diff --git a/src/test/regress/expected/multi_explain.out b/src/test/regress/expected/multi_explain.out index 9670abbf4..e78b1b1eb 100644 --- a/src/test/regress/expected/multi_explain.out +++ b/src/test/regress/expected/multi_explain.out @@ -299,14 +299,14 @@ Limit Filter: (l_quantity < 5.0) -- Test insert EXPLAIN (COSTS FALSE) - INSERT INTO lineitem VALUES(1,0); + INSERT INTO lineitem VALUES (1,0), (2, 0), (3, 0), (4, 0); Custom Scan (Citus Router) Task Count: 1 Tasks Shown: All -> Task Node: host=localhost port=57638 dbname=regression -> Insert on lineitem_290000 - -> Result + -> Values Scan on "*VALUES*" -- Test update EXPLAIN (COSTS FALSE) UPDATE lineitem diff --git a/src/test/regress/expected/multi_explain_0.out b/src/test/regress/expected/multi_explain_0.out index 7e0d6e490..998b97578 100644 --- a/src/test/regress/expected/multi_explain_0.out +++ b/src/test/regress/expected/multi_explain_0.out @@ -299,14 +299,14 @@ Limit Filter: (l_quantity < 5.0) -- Test insert EXPLAIN (COSTS FALSE) - INSERT INTO lineitem VALUES(1,0); + INSERT INTO lineitem VALUES (1,0), (2, 0), (3, 0), (4, 0); Custom Scan (Citus Router) Task Count: 1 Tasks Shown: All -> Task Node: host=localhost port=57638 dbname=regression -> Insert on lineitem_290000 - -> Result + -> Values Scan on "*VALUES*" -- Test update EXPLAIN (COSTS FALSE) UPDATE lineitem diff --git a/src/test/regress/expected/multi_modifications.out b/src/test/regress/expected/multi_modifications.out index 608c23609..606d329da 100644 --- a/src/test/regress/expected/multi_modifications.out +++ b/src/test/regress/expected/multi_modifications.out @@ -201,10 +201,36 @@ ERROR: functions used in the WHERE clause of modification queries on distribute -- commands with mutable but non-volatile functions(ie: stable func.) in their quals -- (the cast to timestamp is because the timestamp_eq_timestamptz operator is stable) DELETE FROM limit_orders WHERE id = 246 AND placed_at = current_timestamp::timestamp; --- commands with multiple rows are supported -INSERT INTO limit_orders VALUES (2037, 'GOOG', 5634, now(), 'buy', random()), - (2038, 'GOOG', 5634, now(), 'buy', random()), - (2039, 'GOOG', 5634, now(), 'buy', random()); +-- multi-row inserts are supported +INSERT INTO limit_orders VALUES (12037, 'GOOG', 5634, '2001-04-16 03:37:28', 'buy', 0.50), + (12038, 'GOOG', 5634, '2001-04-17 03:37:28', 'buy', 2.50), + (12039, 'GOOG', 5634, '2001-04-18 03:37:28', 'buy', 1.50); +SELECT COUNT(*) FROM limit_orders WHERE id BETWEEN 12037 AND 12039; + count +------- + 3 +(1 row) + +-- even those with functions +INSERT INTO limit_orders VALUES (22037, 'GOOG', 5634, now(), 'buy', 0.50), + (22038, 'GOOG', 5634, now(), 'buy', 2.50), + (22039, 'GOOG', 5634, now(), 'buy', 1.50); +SELECT COUNT(*) FROM limit_orders WHERE id BETWEEN 22037 AND 22039; + count +------- + 3 +(1 row) + +-- even those with functions in their partition columns +INSERT INTO limit_orders VALUES (random() * 10 + 70000, 'GOOG', 5634, now(), 'buy', 0.50), + (random() * 10 + 80000, 'GOOG', 5634, now(), 'buy', 2.50), + (random() * 10 + 80090, 'GOOG', 5634, now(), 'buy', 1.50); +SELECT COUNT(*) FROM limit_orders WHERE id BETWEEN 70000 AND 90000; + count +------- + 3 +(1 row) + -- Who says that? :) -- INSERT ... SELECT ... FROM commands are unsupported -- INSERT INTO limit_orders SELECT * FROM limit_orders; diff --git a/src/test/regress/expected/multi_modifying_xacts.out b/src/test/regress/expected/multi_modifying_xacts.out index 940aeae55..1262e0ec8 100644 --- a/src/test/regress/expected/multi_modifying_xacts.out +++ b/src/test/regress/expected/multi_modifying_xacts.out @@ -45,16 +45,28 @@ INSERT INTO researchers VALUES (1, 1, 'Donald Knuth'); INSERT INTO researchers VALUES (2, 1, 'Niklaus Wirth'); INSERT INTO researchers VALUES (3, 2, 'Tony Hoare'); INSERT INTO researchers VALUES (4, 2, 'Kenneth Iverson'); --- replace a researcher, reusing their id +-- replace a researcher, reusing their id in a multi-row INSERT BEGIN; DELETE FROM researchers WHERE lab_id = 1 AND id = 2; -INSERT INTO researchers VALUES (2, 1, 'John Backus'); +INSERT INTO researchers VALUES (2, 1, 'John Backus'), (12, 1, 'Frances E. Allen'); COMMIT; -SELECT name FROM researchers WHERE lab_id = 1 AND id = 2; - name -------------- +SELECT name FROM researchers WHERE lab_id = 1 AND id % 10 = 2; + name +------------------ John Backus -(1 row) + Frances E. Allen +(2 rows) + +-- and the other way around +BEGIN; +INSERT INTO researchers VALUES (14, 2, 'Alan Kay'), (15, 2, 'Barbara Liskov'); +DELETE FROM researchers WHERE id = 14 AND lab_id = 2; +ROLLBACK; +-- should have rolled everything back +SELECT * FROM researchers WHERE id = 15 AND lab_id = 2; + id | lab_id | name +----+--------+------ +(0 rows) -- abort a modification BEGIN; @@ -209,6 +221,11 @@ INSERT INTO researchers VALUES (10, 6, 'Lamport Leslie'); ERROR: cannot establish a new connection for placement 1200003, since DML has been executed on a connection that is in use CONTEXT: COPY researchers, line 2: "10,6,Lesport Lampie" ROLLBACK; +-- but it is allowed after a multi-row insert +BEGIN; +INSERT INTO researchers VALUES (2, 1, 'Knuth Donald'), (10, 6, 'Lamport Leslie'); +\copy researchers from stdin delimiter ',' +ROLLBACK; -- after a COPY you can modify multiple shards, since they'll use different connections BEGIN; \copy researchers from stdin delimiter ',' diff --git a/src/test/regress/expected/multi_prepare_sql.out b/src/test/regress/expected/multi_prepare_sql.out index fbc951413..4da5dfa45 100644 --- a/src/test/regress/expected/multi_prepare_sql.out +++ b/src/test/regress/expected/multi_prepare_sql.out @@ -383,6 +383,15 @@ EXECUTE prepared_double_parameter_insert(3, 30); EXECUTE prepared_double_parameter_insert(4, 40); EXECUTE prepared_double_parameter_insert(5, 50); EXECUTE prepared_double_parameter_insert(6, 60); +PREPARE prepared_multi_insert(int, int) AS + INSERT INTO prepare_table (key, value) VALUES ($1, $2), ($1 + 1, $2 + 10); +-- execute 6 times to trigger prepared statement usage +EXECUTE prepared_multi_insert( 7, 70); +EXECUTE prepared_multi_insert( 9, 90); +EXECUTE prepared_multi_insert(11, 110); +EXECUTE prepared_multi_insert(13, 130); +EXECUTE prepared_multi_insert(15, 150); +EXECUTE prepared_multi_insert(17, 170); PREPARE prepared_non_partition_parameter_insert(int) AS INSERT INTO prepare_table (key, value) VALUES (0, $1); -- execute 6 times to trigger prepared statement usage @@ -420,7 +429,25 @@ SELECT * FROM prepare_table ORDER BY key, value; 5 | 6 | 60 6 | -(24 rows) + 7 | 70 + 8 | 80 + 9 | 90 + 10 | 100 + 11 | 110 + 12 | 120 + 13 | 130 + 14 | 140 + 15 | 150 + 16 | 160 + 17 | 170 + 18 | 180 +(36 rows) + +SELECT master_modify_multiple_shards('DELETE FROM prepare_table WHERE value >= 70'); + master_modify_multiple_shards +------------------------------- + 12 +(1 row) -- check router executor select PREPARE prepared_router_partition_column_select(int) AS diff --git a/src/test/regress/expected/multi_upsert.out b/src/test/regress/expected/multi_upsert.out index 62cd90bd2..d41abe94a 100644 --- a/src/test/regress/expected/multi_upsert.out +++ b/src/test/regress/expected/multi_upsert.out @@ -20,7 +20,7 @@ SELECT master_create_worker_shards('upsert_test', '4', '2'); (1 row) -- do a regular insert -INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1); +INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1), (2, 2); -- observe that there is a conflict and the following query does nothing INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1) ON CONFLICT DO NOTHING; -- same as the above with different syntax @@ -35,8 +35,27 @@ SELECT * FROM upsert_test; part_key | other_col | third_col ----------+-----------+----------- 1 | 2 | 4 -(1 row) + 2 | 2 | +(2 rows) +-- do a multi-row DO NOTHING insert +INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1), (2, 2) +ON CONFLICT DO NOTHING; +-- do a multi-row DO UPDATE insert +INSERT INTO upsert_test (part_key, other_col) VALUES (1, 10), (2, 20), (3, 30) +ON CONFLICT (part_key) DO +UPDATE SET other_col = EXCLUDED.other_col WHERE upsert_test.part_key != 1; +-- see the results +SELECT * FROM upsert_test ORDER BY part_key ASC; + part_key | other_col | third_col +----------+-----------+----------- + 1 | 2 | 4 + 2 | 20 | + 3 | 30 | +(3 rows) + +DELETE FROM upsert_test WHERE part_key = 2; +DELETE FROM upsert_test WHERE part_key = 3; -- use a WHERE clause, so that SET doesn't have an affect INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1) ON CONFLICT (part_key) DO UPDATE SET other_col = 30 WHERE upsert_test.other_col = 3; diff --git a/src/test/regress/sql/multi_explain.sql b/src/test/regress/sql/multi_explain.sql index 9f3035d0d..07aefa97b 100644 --- a/src/test/regress/sql/multi_explain.sql +++ b/src/test/regress/sql/multi_explain.sql @@ -87,7 +87,7 @@ EXPLAIN (COSTS FALSE) -- Test insert EXPLAIN (COSTS FALSE) - INSERT INTO lineitem VALUES(1,0); + INSERT INTO lineitem VALUES (1,0), (2, 0), (3, 0), (4, 0); -- Test update EXPLAIN (COSTS FALSE) diff --git a/src/test/regress/sql/multi_modifications.sql b/src/test/regress/sql/multi_modifications.sql index c3c1becf7..cfe2df393 100644 --- a/src/test/regress/sql/multi_modifications.sql +++ b/src/test/regress/sql/multi_modifications.sql @@ -146,10 +146,26 @@ DELETE FROM limit_orders WHERE id = 246 AND bidder_id = (random() * 1000); -- (the cast to timestamp is because the timestamp_eq_timestamptz operator is stable) DELETE FROM limit_orders WHERE id = 246 AND placed_at = current_timestamp::timestamp; --- commands with multiple rows are supported -INSERT INTO limit_orders VALUES (2037, 'GOOG', 5634, now(), 'buy', random()), - (2038, 'GOOG', 5634, now(), 'buy', random()), - (2039, 'GOOG', 5634, now(), 'buy', random()); +-- multi-row inserts are supported +INSERT INTO limit_orders VALUES (12037, 'GOOG', 5634, '2001-04-16 03:37:28', 'buy', 0.50), + (12038, 'GOOG', 5634, '2001-04-17 03:37:28', 'buy', 2.50), + (12039, 'GOOG', 5634, '2001-04-18 03:37:28', 'buy', 1.50); + +SELECT COUNT(*) FROM limit_orders WHERE id BETWEEN 12037 AND 12039; + +-- even those with functions +INSERT INTO limit_orders VALUES (22037, 'GOOG', 5634, now(), 'buy', 0.50), + (22038, 'GOOG', 5634, now(), 'buy', 2.50), + (22039, 'GOOG', 5634, now(), 'buy', 1.50); + +SELECT COUNT(*) FROM limit_orders WHERE id BETWEEN 22037 AND 22039; + +-- even those with functions in their partition columns +INSERT INTO limit_orders VALUES (random() * 10 + 70000, 'GOOG', 5634, now(), 'buy', 0.50), + (random() * 10 + 80000, 'GOOG', 5634, now(), 'buy', 2.50), + (random() * 10 + 80090, 'GOOG', 5634, now(), 'buy', 1.50); + +SELECT COUNT(*) FROM limit_orders WHERE id BETWEEN 70000 AND 90000; -- Who says that? :) -- INSERT ... SELECT ... FROM commands are unsupported diff --git a/src/test/regress/sql/multi_modifying_xacts.sql b/src/test/regress/sql/multi_modifying_xacts.sql index 883b6feda..395a1ed98 100644 --- a/src/test/regress/sql/multi_modifying_xacts.sql +++ b/src/test/regress/sql/multi_modifying_xacts.sql @@ -32,13 +32,22 @@ INSERT INTO researchers VALUES (2, 1, 'Niklaus Wirth'); INSERT INTO researchers VALUES (3, 2, 'Tony Hoare'); INSERT INTO researchers VALUES (4, 2, 'Kenneth Iverson'); --- replace a researcher, reusing their id +-- replace a researcher, reusing their id in a multi-row INSERT BEGIN; DELETE FROM researchers WHERE lab_id = 1 AND id = 2; -INSERT INTO researchers VALUES (2, 1, 'John Backus'); +INSERT INTO researchers VALUES (2, 1, 'John Backus'), (12, 1, 'Frances E. Allen'); COMMIT; -SELECT name FROM researchers WHERE lab_id = 1 AND id = 2; +SELECT name FROM researchers WHERE lab_id = 1 AND id % 10 = 2; + +-- and the other way around +BEGIN; +INSERT INTO researchers VALUES (14, 2, 'Alan Kay'), (15, 2, 'Barbara Liskov'); +DELETE FROM researchers WHERE id = 14 AND lab_id = 2; +ROLLBACK; + +-- should have rolled everything back +SELECT * FROM researchers WHERE id = 15 AND lab_id = 2; -- abort a modification BEGIN; @@ -172,6 +181,15 @@ INSERT INTO researchers VALUES (10, 6, 'Lamport Leslie'); \. ROLLBACK; +-- but it is allowed after a multi-row insert +BEGIN; +INSERT INTO researchers VALUES (2, 1, 'Knuth Donald'), (10, 6, 'Lamport Leslie'); +\copy researchers from stdin delimiter ',' +3,1,Duth Knonald +10,6,Lesport Lampie +\. +ROLLBACK; + -- after a COPY you can modify multiple shards, since they'll use different connections BEGIN; \copy researchers from stdin delimiter ',' diff --git a/src/test/regress/sql/multi_prepare_sql.sql b/src/test/regress/sql/multi_prepare_sql.sql index bde59efbf..e67d783a9 100644 --- a/src/test/regress/sql/multi_prepare_sql.sql +++ b/src/test/regress/sql/multi_prepare_sql.sql @@ -245,6 +245,17 @@ EXECUTE prepared_double_parameter_insert(4, 40); EXECUTE prepared_double_parameter_insert(5, 50); EXECUTE prepared_double_parameter_insert(6, 60); +PREPARE prepared_multi_insert(int, int) AS + INSERT INTO prepare_table (key, value) VALUES ($1, $2), ($1 + 1, $2 + 10); + +-- execute 6 times to trigger prepared statement usage +EXECUTE prepared_multi_insert( 7, 70); +EXECUTE prepared_multi_insert( 9, 90); +EXECUTE prepared_multi_insert(11, 110); +EXECUTE prepared_multi_insert(13, 130); +EXECUTE prepared_multi_insert(15, 150); +EXECUTE prepared_multi_insert(17, 170); + PREPARE prepared_non_partition_parameter_insert(int) AS INSERT INTO prepare_table (key, value) VALUES (0, $1); @@ -259,6 +270,8 @@ EXECUTE prepared_non_partition_parameter_insert(60); -- check inserted values SELECT * FROM prepare_table ORDER BY key, value; +SELECT master_modify_multiple_shards('DELETE FROM prepare_table WHERE value >= 70'); + -- check router executor select PREPARE prepared_router_partition_column_select(int) AS SELECT diff --git a/src/test/regress/sql/multi_upsert.sql b/src/test/regress/sql/multi_upsert.sql index 72e0b9a92..9795fc116 100644 --- a/src/test/regress/sql/multi_upsert.sql +++ b/src/test/regress/sql/multi_upsert.sql @@ -16,7 +16,7 @@ SELECT master_create_distributed_table('upsert_test', 'part_key', 'hash'); SELECT master_create_worker_shards('upsert_test', '4', '2'); -- do a regular insert -INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1); +INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1), (2, 2); -- observe that there is a conflict and the following query does nothing INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1) ON CONFLICT DO NOTHING; @@ -34,6 +34,21 @@ INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1) -- see the results SELECT * FROM upsert_test; +-- do a multi-row DO NOTHING insert +INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1), (2, 2) +ON CONFLICT DO NOTHING; + +-- do a multi-row DO UPDATE insert +INSERT INTO upsert_test (part_key, other_col) VALUES (1, 10), (2, 20), (3, 30) +ON CONFLICT (part_key) DO +UPDATE SET other_col = EXCLUDED.other_col WHERE upsert_test.part_key != 1; + +-- see the results +SELECT * FROM upsert_test ORDER BY part_key ASC; + +DELETE FROM upsert_test WHERE part_key = 2; +DELETE FROM upsert_test WHERE part_key = 3; + -- use a WHERE clause, so that SET doesn't have an affect INSERT INTO upsert_test (part_key, other_col) VALUES (1, 1) ON CONFLICT (part_key) DO UPDATE SET other_col = 30 WHERE upsert_test.other_col = 3;