CREATE TEMP TABLE x ( a serial, b int, c text not null default 'stuff', d text, e text ) WITH OIDS; CREATE FUNCTION fn_x_before () RETURNS TRIGGER AS ' BEGIN NEW.e := ''before trigger fired''::text; return NEW; END; ' LANGUAGE plpgsql; CREATE FUNCTION fn_x_after () RETURNS TRIGGER AS ' BEGIN UPDATE x set e=''after trigger fired'' where c=''stuff''; return NULL; END; ' LANGUAGE plpgsql; CREATE TRIGGER trg_x_after AFTER INSERT ON x FOR EACH ROW EXECUTE PROCEDURE fn_x_after(); CREATE TRIGGER trg_x_before BEFORE INSERT ON x FOR EACH ROW EXECUTE PROCEDURE fn_x_before(); COPY x (a, b, c, d, e) from stdin; 9999 \N \\N \NN \N 10000 21 31 41 51 \. COPY x (b, d) from stdin; 1 test_1 \. COPY x (b, d) from stdin; 2 test_2 3 test_3 4 test_4 5 test_5 \. COPY x (a, b, c, d, e) from stdin; 10001 22 32 42 52 10002 23 33 43 53 10003 24 34 44 54 10004 25 35 45 55 10005 26 36 46 56 \. -- non-existent column in column list: should fail COPY x (xyz) from stdin; -- too many columns in column list: should fail COPY x (a, b, c, d, e, d, c) from stdin; -- missing data: should fail COPY x from stdin; \. COPY x from stdin; 2000 230 23 23 \. COPY x from stdin; 2001 231 \N \N \. -- extra data: should fail COPY x from stdin; 2002 232 40 50 60 70 80 \. -- various COPY options: delimiters, oids, NULL string, encoding COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x'; 500000,x,45,80,90 500001,x,\x,\\x,\\\x 500002,x,\,,\\\,,\\ \. COPY x from stdin WITH DELIMITER AS ';' NULL AS ''; 3000;;c;; \. COPY x from stdin WITH DELIMITER AS ':' NULL AS E'\\X' ENCODING 'sql_ascii'; 4000:\X:C:\X:\X 4001:1:empty:: 4002:2:null:\X:\X 4003:3:Backslash:\\:\\ 4004:4:BackslashX:\\X:\\X 4005:5:N:\N:\N 4006:6:BackslashN:\\N:\\N 4007:7:XX:\XX:\XX 4008:8:Delimiter:\::\: \. -- check results of copy in SELECT * FROM x; -- COPY w/ oids on a table w/o oids should fail CREATE TABLE no_oids ( a int, b int ) WITHOUT OIDS; INSERT INTO no_oids (a, b) VALUES (5, 10); INSERT INTO no_oids (a, b) VALUES (20, 30); -- should fail COPY no_oids FROM stdin WITH OIDS; COPY no_oids TO stdout WITH OIDS; -- check copy out COPY x TO stdout; COPY x (c, e) TO stdout; COPY x (b, e) TO stdout WITH NULL 'I''m null'; CREATE TEMP TABLE y ( col1 text, col2 text ); INSERT INTO y VALUES ('Jackson, Sam', E'\\h'); INSERT INTO y VALUES ('It is "perfect".',E'\t'); INSERT INTO y VALUES ('', NULL); COPY y TO stdout WITH CSV; COPY y TO stdout WITH CSV QUOTE '''' DELIMITER '|'; COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE E'\\' ENCODING 'sql_ascii'; COPY y TO stdout WITH CSV FORCE QUOTE *; -- Repeat above tests with new 9.0 option syntax COPY y TO stdout (FORMAT CSV); COPY y TO stdout (FORMAT CSV, QUOTE '''', DELIMITER '|'); COPY y TO stdout (FORMAT CSV, FORCE_QUOTE (col2), ESCAPE E'\\'); COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *); \copy y TO stdout (FORMAT CSV) \copy y TO stdout (FORMAT CSV, QUOTE '''', DELIMITER '|') \copy y TO stdout (FORMAT CSV, FORCE_QUOTE (col2), ESCAPE E'\\') \copy y TO stdout (FORMAT CSV, FORCE_QUOTE *) --test that we read consecutive LFs properly CREATE TEMP TABLE testnl (a int, b text, c int); COPY testnl FROM stdin CSV; 1,"a field with two LFs inside",2 \. -- test end of copy marker CREATE TEMP TABLE testeoc (a text); COPY testeoc FROM stdin CSV; a\. \.b c\.d "\." \. COPY testeoc TO stdout CSV; -- test handling of nonstandard null marker that violates escaping rules CREATE TEMP TABLE testnull(a int, b text); INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL); COPY testnull TO stdout WITH NULL AS E'\\0'; COPY testnull FROM stdin WITH NULL AS E'\\0'; 42 \\0 \0 \0 \. SELECT * FROM testnull; BEGIN; CREATE TABLE vistest (LIKE testeoc); COPY vistest FROM stdin CSV; a0 b \. COMMIT; SELECT * FROM vistest; BEGIN; TRUNCATE vistest; COPY vistest FROM stdin CSV; a1 b \. SELECT * FROM vistest; SAVEPOINT s1; TRUNCATE vistest; COPY vistest FROM stdin CSV; d1 e \. SELECT * FROM vistest; COMMIT; SELECT * FROM vistest; BEGIN; TRUNCATE vistest; COPY vistest FROM stdin CSV FREEZE; a2 b \. SELECT * FROM vistest; SAVEPOINT s1; TRUNCATE vistest; COPY vistest FROM stdin CSV FREEZE; d2 e \. SELECT * FROM vistest; COMMIT; SELECT * FROM vistest; BEGIN; TRUNCATE vistest; COPY vistest FROM stdin CSV FREEZE; x y \. SELECT * FROM vistest; COMMIT; TRUNCATE vistest; COPY vistest FROM stdin CSV FREEZE; p g \. BEGIN; TRUNCATE vistest; SAVEPOINT s1; COPY vistest FROM stdin CSV FREEZE; m k \. COMMIT; BEGIN; INSERT INTO vistest VALUES ('z'); SAVEPOINT s1; TRUNCATE vistest; ROLLBACK TO SAVEPOINT s1; COPY vistest FROM stdin CSV FREEZE; d3 e \. COMMIT; CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS $$ BEGIN TRUNCATE vistest; EXCEPTION WHEN OTHERS THEN INSERT INTO vistest VALUES ('subxact failure'); END; $$ language plpgsql; BEGIN; INSERT INTO vistest VALUES ('z'); SELECT truncate_in_subxact(); COPY vistest FROM stdin CSV FREEZE; d4 e \. SELECT * FROM vistest; COMMIT; SELECT * FROM vistest; -- Test FORCE_NOT_NULL and FORCE_NULL options CREATE TEMP TABLE forcetest ( a INT NOT NULL, b TEXT NOT NULL, c TEXT, d TEXT, e TEXT ); \pset null NULL -- should succeed with no effect ("b" remains an empty string, "c" remains NULL) BEGIN; COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c)); 1,,"" \. COMMIT; SELECT b, c FROM forcetest WHERE a = 1; -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified BEGIN; COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d)); 2,'a',,"" \. COMMIT; SELECT c, d FROM forcetest WHERE a = 2; -- should fail with not-null constraint violation BEGIN; COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NULL(b), FORCE_NOT_NULL(c)); 3,,"" \. ROLLBACK; -- should fail with "not referenced by COPY" error BEGIN; COPY forcetest (d, e) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b)); ROLLBACK; -- should fail with "not referenced by COPY" error BEGIN; COPY forcetest (d, e) FROM STDIN WITH (FORMAT csv, FORCE_NULL(b)); ROLLBACK; \pset null '' -- test case with whole-row Var in a check constraint create table check_con_tbl (f1 int); create function check_con_function(check_con_tbl) returns bool as $$ begin raise notice 'input = %', row_to_json($1); return $1.f1 > 0; end $$ language plpgsql immutable; alter table check_con_tbl add check (check_con_function(check_con_tbl.*)); \d+ check_con_tbl copy check_con_tbl from stdin; 1 \N \. copy check_con_tbl from stdin; 0 \. select * from check_con_tbl; DROP TABLE forcetest; DROP TABLE vistest; DROP FUNCTION truncate_in_subxact(); DROP TABLE x, y; DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_after();