From 6a0db2cb34b9cfa06fcb28bb525cc46cab2dbde7 Mon Sep 17 00:00:00 2001 From: zhaosen Date: Fri, 10 May 2024 11:43:46 +0800 Subject: [PATCH] =?UTF-8?q?ustore=E5=AD=98=E5=82=A8=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E7=9A=84regression=E7=94=A8=E4=BE=8B12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/regress/expected/copy2_ustore.out | 323 +++++++++++++++++++++ src/test/regress/sql/copy2_ustore.sql | 230 +++++++++++++++ 2 files changed, 553 insertions(+) create mode 100644 src/test/regress/expected/copy2_ustore.out create mode 100644 src/test/regress/sql/copy2_ustore.sql diff --git a/src/test/regress/expected/copy2_ustore.out b/src/test/regress/expected/copy2_ustore.out new file mode 100644 index 000000000..9a78b64dd --- /dev/null +++ b/src/test/regress/expected/copy2_ustore.out @@ -0,0 +1,323 @@ +-- Enforce use of COMMIT instead of 2PC for temporary objects +CREATE TABLE x ( + a int, + b int, + c text not null default 'stuff', + d text, + e text +) with (storage_type = ustore); +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; +COPY x (b, d) from stdin; +COPY x (b, d) from stdin; +COPY x (a, b, c, d, e) from stdin; +-- non-existent column in column list: should fail +COPY x (xyz) from stdin; +ERROR: column "xyz" of relation "x" does not exist +-- too many columns in column list: should fail +COPY x (a, b, c, d, e, d, c) from stdin; +ERROR: column "d" specified more than once +-- missing data: should fail +COPY x from stdin; +ERROR: missing data for column "b" +CONTEXT: COPY x, line 1: "" +COPY x from stdin; +ERROR: missing data for column "e" +CONTEXT: COPY x, line 1: "2000 230 23 23" +COPY x from stdin; +ERROR: missing data for column "e" +CONTEXT: COPY x, line 1: "2001 231 \N \N" +-- extra data: should fail +COPY x from stdin; +ERROR: extra data after last expected column +CONTEXT: COPY x, line 1: "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'; +ERROR: table "x" does not have OIDs +500000,x,45,80,90 +500001,x,\x,\\x,\\\x +invalid command \x, +500002,x,\,,\\\,,\\ +invalid command \,, +\. +invalid command \. +COPY x from stdin WITH DELIMITER AS ';' NULL AS ''; +ERROR: syntax error at or near "500000" +LINE 1: 500000,x,45,80,90 + ^ +3000;;c;; +ERROR: syntax error at or near "3000" +LINE 1: 3000; + ^ +ERROR: syntax error at or near "c" +LINE 1: c; + ^ +\. +invalid command \. +COPY x from stdin WITH DELIMITER AS ':' NULL AS E'\\X' ENCODING 'sql_ascii'; +-- check results of copy in +SELECT * FROM x ORDER BY a, b; + a | b | c | d | e +-------+----+------------+--------+---------------------- + 4000 | | C | | before trigger fired + 4001 | 1 | empty | | before trigger fired + 4002 | 2 | null | | before trigger fired + 4003 | 3 | Backslash | \ | before trigger fired + 4004 | 4 | BackslashX | \X | before trigger fired + 4005 | 5 | N | N | before trigger fired + 4006 | 6 | BackslashN | \N | before trigger fired + 4007 | 7 | XX | XX | before trigger fired + 4008 | 8 | Delimiter | : | before trigger fired + 9999 | | \N | NN | before trigger fired + 10000 | 21 | 31 | 41 | before trigger fired + 10001 | 22 | 32 | 42 | before trigger fired + 10002 | 23 | 33 | 43 | before trigger fired + 10003 | 24 | 34 | 44 | before trigger fired + 10004 | 25 | 35 | 45 | before trigger fired + 10005 | 26 | 36 | 46 | before trigger fired + | 1 | stuff | test_1 | after trigger fired + | 2 | stuff | test_2 | after trigger fired + | 3 | stuff | test_3 | after trigger fired + | 4 | stuff | test_4 | after trigger fired + | 5 | stuff | test_5 | after trigger fired +(21 rows) + +-- 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; +ERROR: table "no_oids" does not have OIDs +COPY no_oids TO stdout WITH OIDS; +ERROR: table "no_oids" does not have OIDs +-- check copy out +COPY (select * from x order by 1,2,3,4,5) TO stdout; +4000 \N C \N before trigger fired +4001 1 empty \N before trigger fired +4002 2 null \N before trigger fired +4003 3 Backslash \\ before trigger fired +4004 4 BackslashX \\X before trigger fired +4005 5 N N before trigger fired +4006 6 BackslashN \\N before trigger fired +4007 7 XX XX before trigger fired +4008 8 Delimiter : before trigger fired +9999 \N \\N NN before trigger fired +10000 21 31 41 before trigger fired +10001 22 32 42 before trigger fired +10002 23 33 43 before trigger fired +10003 24 34 44 before trigger fired +10004 25 35 45 before trigger fired +10005 26 36 46 before trigger fired +\N 1 stuff test_1 after trigger fired +\N 2 stuff test_2 after trigger fired +\N 3 stuff test_3 after trigger fired +\N 4 stuff test_4 after trigger fired +\N 5 stuff test_5 after trigger fired +COPY (select c,e from x where c != 'N' order by 1,2) TO stdout; +31 before trigger fired +32 before trigger fired +33 before trigger fired +34 before trigger fired +35 before trigger fired +36 before trigger fired +Backslash before trigger fired +BackslashN before trigger fired +BackslashX before trigger fired +C before trigger fired +Delimiter before trigger fired +empty before trigger fired +\\N before trigger fired +null before trigger fired +stuff after trigger fired +stuff after trigger fired +stuff after trigger fired +stuff after trigger fired +stuff after trigger fired +XX before trigger fired +COPY (select b,e from x order by 1,2) TO stdout WITH NULL 'I''m null'; +1 after trigger fired +1 before trigger fired +2 after trigger fired +2 before trigger fired +3 after trigger fired +3 before trigger fired +4 after trigger fired +4 before trigger fired +5 after trigger fired +5 before trigger fired +6 before trigger fired +7 before trigger fired +8 before trigger fired +21 before trigger fired +22 before trigger fired +23 before trigger fired +24 before trigger fired +25 before trigger fired +26 before trigger fired +I'm null before trigger fired +I'm null before trigger fired +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; +"Jackson, Sam",\h +"It is ""perfect"".", +, +COPY y TO stdout WITH CSV QUOTE '''' DELIMITER '|'; +Jackson, Sam|\h +It is "perfect".| +| +COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE E'\\' ENCODING 'sql_ascii'; +"Jackson, Sam","\\h" +"It is \"perfect\"."," " +, +COPY y TO stdout WITH CSV FORCE QUOTE *; +"Jackson, Sam","\h" +"It is ""perfect""."," " +, +-- Repeat above tests with new 9.0 option syntax +COPY y TO stdout (FORMAT CSV); +"Jackson, Sam",\h +"It is ""perfect"".", +, +COPY y TO stdout (FORMAT CSV, QUOTE '''', DELIMITER '|'); +Jackson, Sam|\h +It is "perfect".| +| +COPY y TO stdout (FORMAT CSV, FORCE_QUOTE (col2), ESCAPE E'\\'); +"Jackson, Sam","\\h" +"It is \"perfect\"."," " +, +COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *); +"Jackson, Sam","\h" +"It is ""perfect""."," " +, +\copy y TO stdout (FORMAT CSV) +"Jackson, Sam",\h +"It is ""perfect"".", +, +\copy y TO stdout (FORMAT CSV, QUOTE '''', DELIMITER '|') +Jackson, Sam|\h +It is "perfect".| +| +\copy y TO stdout (FORMAT CSV, FORCE_QUOTE (col2), ESCAPE E'\\') +"Jackson, Sam","\\h" +"It is \"perfect\"."," " +, +\copy y TO stdout (FORMAT CSV, FORCE_QUOTE *) +"Jackson, Sam","\h" +"It is ""perfect""."," " +, +--test that we read consecutive LFs properly +CREATE TEMP TABLE testnl (a int, b text, c int); +COPY testnl FROM stdin CSV; +-- test end of copy marker +CREATE TABLE testeoc (a text) with (storage_type = ustore); +COPY testeoc FROM stdin CSV; +COPY (select * from testeoc order by a using ~<~) TO stdout CSV; +"\." +\.b +a\. +c\.d +-- 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 (select * from testnull order by 1,2) TO stdout WITH NULL AS E'\\0'; +1 \\0 +\0 \0 +COPY testnull FROM stdin WITH NULL AS E'\\0'; +SELECT * FROM testnull ORDER BY 1,2; + a | b +----+---- + 1 | \0 + 42 | \0 + | + | +(4 rows) + +START TRANSACTION; +CREATE TABLE vistest (LIKE testeoc) with (storage_type = ustore); +COPY vistest FROM stdin CSV; +COMMIT; +SELECT * FROM vistest order by 1; + a +---- + a0 + b +(2 rows) + +START TRANSACTION; +TRUNCATE vistest; +COPY vistest FROM stdin CSV FREEZE; +SELECT * FROM vistest order by 1; + a +--- + x + y +(2 rows) + +COMMIT; +TRUNCATE vistest; +COPY vistest FROM stdin CSV FREEZE; +CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS +$$ +BEGIN + TRUNCATE vistest; +--EXCEPTION +-- WHEN OTHERS THEN +-- INSERT INTO vistest VALUES ('subxact failure'); +END; +$$ language plpgsql; +START TRANSACTION; +INSERT INTO vistest VALUES ('z'); +SELECT truncate_in_subxact(); + truncate_in_subxact +--------------------- + +(1 row) + +COPY vistest FROM stdin CSV FREEZE; +SELECT * FROM vistest order by 1; + a +---- + d4 + e +(2 rows) + +COMMIT; +SELECT * FROM vistest order by 1; + a +---- + d4 + e +(2 rows) + +DROP TABLE vistest; +DROP FUNCTION truncate_in_subxact(); +DROP TABLE x; +DROP TABLE y; +DROP FUNCTION fn_x_before(); +DROP FUNCTION fn_x_after(); diff --git a/src/test/regress/sql/copy2_ustore.sql b/src/test/regress/sql/copy2_ustore.sql new file mode 100644 index 000000000..39e55aae9 --- /dev/null +++ b/src/test/regress/sql/copy2_ustore.sql @@ -0,0 +1,230 @@ +-- Enforce use of COMMIT instead of 2PC for temporary objects + +CREATE TABLE x ( + a int, + b int, + c text not null default 'stuff', + d text, + e text +) with (storage_type = ustore); + +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 ORDER BY a, b; + +-- 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 (select * from x order by 1,2,3,4,5) TO stdout; +COPY (select c,e from x where c != 'N' order by 1,2) TO stdout; +COPY (select b,e from x order by 1,2) 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 TABLE testeoc (a text) with (storage_type = ustore); + +COPY testeoc FROM stdin CSV; +a\. +\.b +c\.d +"\." +\. + +COPY (select * from testeoc order by a using ~<~) 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 (select * from testnull order by 1,2) TO stdout WITH NULL AS E'\\0'; + +COPY testnull FROM stdin WITH NULL AS E'\\0'; +42 \\0 +\0 \0 +\. + +SELECT * FROM testnull ORDER BY 1,2; + +START TRANSACTION; +CREATE TABLE vistest (LIKE testeoc) with (storage_type = ustore); +COPY vistest FROM stdin CSV; +a0 +b +\. +COMMIT; +SELECT * FROM vistest order by 1; + +START TRANSACTION; +TRUNCATE vistest; +COPY vistest FROM stdin CSV FREEZE; +x +y +\. +SELECT * FROM vistest order by 1; +COMMIT; +TRUNCATE vistest; +COPY vistest FROM stdin CSV FREEZE; +p +g +\. + +CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS +$$ +BEGIN + TRUNCATE vistest; +--EXCEPTION +-- WHEN OTHERS THEN +-- INSERT INTO vistest VALUES ('subxact failure'); +END; +$$ language plpgsql; +START TRANSACTION; +INSERT INTO vistest VALUES ('z'); +SELECT truncate_in_subxact(); +COPY vistest FROM stdin CSV FREEZE; +d4 +e +\. +SELECT * FROM vistest order by 1; +COMMIT; +SELECT * FROM vistest order by 1; +DROP TABLE vistest; +DROP FUNCTION truncate_in_subxact(); +DROP TABLE x; +DROP TABLE y; +DROP FUNCTION fn_x_before(); +DROP FUNCTION fn_x_after();