From e579e6f455a48a25aca916b7e48b9b002aa20577 Mon Sep 17 00:00:00 2001 From: naisila Date: Tue, 9 Aug 2022 08:59:19 +0300 Subject: [PATCH] Add alternative test outputs for change in Insert Select display pt3 citus_local_tables_queries.sql cte_inline.sql insert_select_repartition.sql intermediate_result_pruning.sql local_shard_execution.sql local_shard_execution_replicated.sql multi_mx_insert_select_repartition.sql mx_coordinator_shouldhaveshards.sql Relevant PG commit: a8d8445a7b2f80f6d0bfe97b19f90bd2cbef8759 --- .../expected/citus_local_tables_queries.out | 13 +- .../expected/citus_local_tables_queries_0.out | 1160 ++++++ src/test/regress/expected/cte_inline.out | 25 +- src/test/regress/expected/cte_inline_0.out | 1536 ++++++++ .../expected/insert_select_repartition.out | 71 +- .../expected/insert_select_repartition_0.out | 1304 +++++++ .../expected/intermediate_result_pruning.out | 11 +- .../intermediate_result_pruning_0.out | 1068 ++++++ .../expected/local_shard_execution.out | 13 +- .../expected/local_shard_execution_0.out | 3292 +++++++++++++++++ .../local_shard_execution_replicated.out | 15 +- .../local_shard_execution_replicated_0.out | 2456 ++++++++++++ .../multi_mx_insert_select_repartition.out | 13 +- .../multi_mx_insert_select_repartition_0.out | 160 + .../mx_coordinator_shouldhaveshards.out | 17 +- .../mx_coordinator_shouldhaveshards_0.out | 326 ++ .../sql/citus_local_tables_queries.sql | 9 + src/test/regress/sql/cte_inline.sql | 9 + .../regress/sql/insert_select_repartition.sql | 9 + .../sql/intermediate_result_pruning.sql | 10 + .../regress/sql/local_shard_execution.sql | 9 + .../sql/local_shard_execution_replicated.sql | 9 + .../multi_mx_insert_select_repartition.sql | 9 + .../sql/mx_coordinator_shouldhaveshards.sql | 9 + 24 files changed, 11500 insertions(+), 53 deletions(-) create mode 100644 src/test/regress/expected/citus_local_tables_queries_0.out create mode 100644 src/test/regress/expected/cte_inline_0.out create mode 100644 src/test/regress/expected/insert_select_repartition_0.out create mode 100644 src/test/regress/expected/intermediate_result_pruning_0.out create mode 100644 src/test/regress/expected/local_shard_execution_0.out create mode 100644 src/test/regress/expected/local_shard_execution_replicated_0.out create mode 100644 src/test/regress/expected/multi_mx_insert_select_repartition_0.out create mode 100644 src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 4399062aa..e6a6ff11c 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -1,3 +1,12 @@ +-- +-- CITUS_LOCAL_TABLES_QUERIES +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- \set VERBOSITY terse SET citus.next_shard_id TO 1509000; SET citus.shard_replication_factor TO 1; @@ -570,7 +579,7 @@ SELECT clear_and_init_test_tables(); INSERT INTO citus_local_table SELECT * from reference_table; -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT a, b FROM citus_local_table_queries.reference_table_1509003 reference_table +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509003 reference_table INSERT INTO reference_table SELECT * from citus_local_table; NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table @@ -583,7 +592,7 @@ SELECT * from citus_local_table; NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table INSERT INTO citus_local_table SELECT * from citus_local_table_2; -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT a, b FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT citus_local_table_2.a, citus_local_table_2.b FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 INSERT INTO citus_local_table SELECT * from citus_local_table_2 ORDER BY 1,2 diff --git a/src/test/regress/expected/citus_local_tables_queries_0.out b/src/test/regress/expected/citus_local_tables_queries_0.out new file mode 100644 index 000000000..308ac0610 --- /dev/null +++ b/src/test/regress/expected/citus_local_tables_queries_0.out @@ -0,0 +1,1160 @@ +-- +-- CITUS_LOCAL_TABLES_QUERIES +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +\set VERBOSITY terse +SET citus.next_shard_id TO 1509000; +SET citus.shard_replication_factor TO 1; +SET citus.enable_local_execution TO ON; +SET citus.log_local_commands TO ON; +CREATE SCHEMA citus_local_table_queries; +SET search_path TO citus_local_table_queries; +-- ensure that coordinator is added to pg_dist_node +SET client_min_messages to ERROR; +SELECT 1 FROM master_add_node('localhost', :master_port, groupId => 0); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +RESET client_min_messages; +CREATE TABLE dummy_reference_table(a int unique, b int); +SELECT create_reference_table('dummy_reference_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE citus_local_table(a int, b int); +ALTER TABLE citus_local_table ADD CONSTRAINT fkey_to_dummy_1 FOREIGN KEY (a) REFERENCES dummy_reference_table(a); +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509001, 'citus_local_table_queries', 1509000, 'citus_local_table_queries', 'ALTER TABLE citus_local_table ADD CONSTRAINT fkey_to_dummy_1 FOREIGN KEY (a) REFERENCES dummy_reference_table(a);') +CREATE TABLE citus_local_table_2(a int, b int); +ALTER TABLE citus_local_table_2 ADD CONSTRAINT fkey_to_dummy_2 FOREIGN KEY (a) REFERENCES dummy_reference_table(a); +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509002, 'citus_local_table_queries', 1509000, 'citus_local_table_queries', 'ALTER TABLE citus_local_table_2 ADD CONSTRAINT fkey_to_dummy_2 FOREIGN KEY (a) REFERENCES dummy_reference_table(a);') +CREATE TABLE reference_table(a int, b int); +SELECT create_reference_table('reference_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_table(a int, b int); +SELECT create_distributed_table('distributed_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE postgres_local_table(a int, b int); +-- Define a helper function to truncate & insert some data into our test tables +-- We should call this function at some places in this test file to prevent +-- test to take a long time. +-- We shouldn't use LIMIT in INSERT SELECT queries to make the test faster as +-- LIMIT would force planner to wrap SELECT query in an intermediate result and +-- this might reduce the coverage of the test cases. +CREATE FUNCTION clear_and_init_test_tables() RETURNS void AS $$ + BEGIN + SET client_min_messages to ERROR; + + TRUNCATE postgres_local_table, citus_local_table, reference_table, distributed_table, dummy_reference_table, citus_local_table_2; + + INSERT INTO dummy_reference_table SELECT i, i FROM generate_series(0, 5) i; + INSERT INTO citus_local_table SELECT i, i FROM generate_series(0, 5) i; + INSERT INTO citus_local_table_2 SELECT i, i FROM generate_series(0, 5) i; + INSERT INTO postgres_local_table SELECT i, i FROM generate_series(0, 5) i; + INSERT INTO distributed_table SELECT i, i FROM generate_series(0, 5) i; + INSERT INTO reference_table SELECT i, i FROM generate_series(0, 5) i; + + RESET client_min_messages; + END; +$$ LANGUAGE plpgsql; +--------------------------------------------------------------------- +---- SELECT ---- +--------------------------------------------------------------------- +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +-- join between citus local tables and reference tables would succeed +SELECT count(*) FROM citus_local_table, reference_table WHERE citus_local_table.a = reference_table.a; +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.reference_table_1509003 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) + count +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT * FROM citus_local_table, reference_table WHERE citus_local_table.a = reference_table.a ORDER BY 1,2,3,4 FOR UPDATE; +NOTICE: executing the command locally: SELECT citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.reference_table_1509003 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) ORDER BY citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FOR UPDATE OF citus_local_table FOR UPDATE OF reference_table + a | b | a | b +--------------------------------------------------------------------- + 0 | 0 | 0 | 0 + 1 | 1 | 1 | 1 + 2 | 2 | 2 | 2 + 3 | 3 | 3 | 3 + 4 | 4 | 4 | 4 + 5 | 5 | 5 | 5 +(6 rows) + +-- should work +WITH cte_1 AS + (SELECT * FROM citus_local_table, reference_table WHERE citus_local_table.a = reference_table.a ORDER BY 1,2,3,4 FOR UPDATE) +SELECT count(*) FROM cte_1; +NOTICE: executing the command locally: WITH cte_1 AS (SELECT citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.reference_table_1509003 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) ORDER BY citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FOR UPDATE OF citus_local_table FOR UPDATE OF reference_table) SELECT count(*) AS count FROM cte_1 cte_1(a, b, a_1, b_1) + count +--------------------------------------------------------------------- + 6 +(1 row) + +-- should work as joins are between ctes +WITH cte_citus_local_table AS + (SELECT * FROM citus_local_table), +cte_postgres_local_table AS + (SELECT * FROM postgres_local_table), +cte_distributed_table AS + (SELECT * FROM distributed_table) +SELECT count(*) FROM cte_distributed_table, cte_citus_local_table, cte_postgres_local_table +WHERE cte_citus_local_table.a = 1 AND cte_distributed_table.a = 1; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +-- should fail as we don't support direct joins between distributed/local tables +SELECT count(*) FROM distributed_table d1, distributed_table d2, citus_local_table; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +-- local table inside subquery should just work +SELECT count(*) FROM +( + SELECT * FROM (SELECT * FROM citus_local_table) as subquery_inner +) as subquery_top; +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.a, subquery_inner.b FROM (SELECT citus_local_table.a, citus_local_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table) subquery_inner) subquery_top + count +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +-- join between citus/postgres local tables should just work +SELECT count(*) FROM +( + SELECT * FROM (SELECT count(*) FROM citus_local_table, postgres_local_table) as subquery_inner +) as subquery_top; +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.count FROM (SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.postgres_local_table) subquery_inner) subquery_top + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- should fail as we don't support direct joins between distributed/local tables +SELECT count(*) FROM +( + SELECT *, random() FROM (SELECT *, random() FROM citus_local_table, distributed_table) as subquery_inner +) as subquery_top; +NOTICE: executing the command locally: SELECT NULL::integer AS "dummy-1" FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true + count +--------------------------------------------------------------------- + 36 +(1 row) + +-- should fail as we don't support direct joins between distributed/local tables +SELECT count(*) FROM +( + SELECT *, random() + FROM ( + WITH cte_1 AS (SELECT *, random() FROM citus_local_table, distributed_table) SELECT * FROM cte_1) as subquery_inner +) as subquery_top; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.a, subquery_inner.b, subquery_inner.a_1 AS a, subquery_inner.b_1 AS b, subquery_inner.random, random() AS random FROM (SELECT cte_1.a, cte_1.b, cte_1.a_1 AS a, cte_1.b_1 AS b, cte_1.random FROM (SELECT intermediate_result.a, intermediate_result.b, intermediate_result.a_1 AS a, intermediate_result.b_1 AS b, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer, a_1 integer, b_1 integer, random double precision)) cte_1(a, b, a_1, b_1, random)) subquery_inner(a, b, a_1, b_1, random)) subquery_top(a, b, a_1, b_1, random, random_1) + count +--------------------------------------------------------------------- + 36 +(1 row) + +-- should be fine +SELECT count(*) FROM +( + SELECT *, random() + FROM ( + WITH cte_1 AS (SELECT *, random() FROM citus_local_table), cte_2 AS (SELECT * FROM distributed_table) SELECT count(*) FROM cte_1, cte_2 + ) as subquery_inner +) as subquery_top; +NOTICE: executing the command locally: SELECT a, b, random() AS random FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.count, random() AS random FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) subquery_inner) subquery_top + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +-- prepared statement +PREPARE citus_local_only AS SELECT count(*) FROM citus_local_table; +-- execute 6 times, local tables without params +EXECUTE citus_local_only; +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +EXECUTE citus_local_only; +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +EXECUTE citus_local_only; +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +EXECUTE citus_local_only; +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +EXECUTE citus_local_only; +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +EXECUTE citus_local_only; +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +-- execute 6 times, with param +PREPARE citus_local_only_p(int) AS SELECT count(*) FROM citus_local_table WHERE a = $1; +EXECUTE citus_local_only_p(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE citus_local_only_p(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE citus_local_only_p(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE citus_local_only_p(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE citus_local_only_p(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE citus_local_only_p(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- do not evalute the function +-- show the logs +EXECUTE citus_local_only_p(random()); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE citus_local_only_p(random()); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +PREPARE mixed_query(int, int, int) AS + WITH cte_citus_local_table AS + (SELECT * FROM citus_local_table WHERE a = $1), + cte_postgres_local_table AS + (SELECT * FROM postgres_local_table WHERE a = $2), + cte_distributed_table AS + (SELECT * FROM distributed_table WHERE a = $3), + cte_mixes AS (SELECT * FROM cte_distributed_table, cte_citus_local_table, cte_postgres_local_table) + SELECT count(*) FROM cte_mixes; +EXECUTE mixed_query(1,2,3); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE mixed_query(1,2,3); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE mixed_query(1,2,3); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE mixed_query(1,2,3); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE mixed_query(1,2,3); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE mixed_query(1,2,3); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE mixed_query(1,2,3); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +-- anonymous columns +WITH a AS (SELECT a, '' FROM citus_local_table GROUP BY a) SELECT a.a FROM a ORDER BY 1 LIMIT 5; +NOTICE: executing the command locally: SELECT a FROM (SELECT citus_local_table.a, ''::text FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table GROUP BY citus_local_table.a) a(a, "?column?") ORDER BY a LIMIT 5 + a +--------------------------------------------------------------------- + 0 + 1 + 2 + 3 + 4 +(5 rows) + +WITH a AS (SELECT b, '' FROM citus_local_table WHERE a = 1) SELECT * FROM a, a b ORDER BY 1 LIMIT 5; +NOTICE: executing the command locally: WITH a AS (SELECT citus_local_table.b, ''::text FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) 1)) SELECT a.b, a."?column?", b.b, b."?column?" FROM a a(b, "?column?"), a b(b, "?column?") ORDER BY a.b LIMIT 5 + b | ?column? | b | ?column? +--------------------------------------------------------------------- + 1 | | 1 | +(1 row) + +-- weird expression on citus/pg table joins should be fine +SELECT * FROM citus_local_table, postgres_local_table +WHERE citus_local_table.a - postgres_local_table.a = 0 +ORDER BY 1,2,3,4 +LIMIT 10; +NOTICE: executing the command locally: SELECT citus_local_table.a, citus_local_table.b, postgres_local_table.a, postgres_local_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.postgres_local_table WHERE ((citus_local_table.a OPERATOR(pg_catalog.-) postgres_local_table.a) OPERATOR(pg_catalog.=) 0) ORDER BY citus_local_table.a, citus_local_table.b, postgres_local_table.a, postgres_local_table.b LIMIT 10 + a | b | a | b +--------------------------------------------------------------------- + 0 | 0 | 0 | 0 + 1 | 1 | 1 | 1 + 2 | 2 | 2 | 2 + 3 | 3 | 3 | 3 + 4 | 4 | 4 | 4 + 5 | 5 | 5 | 5 +(6 rows) + +-- set operations should just work +SELECT * FROM citus_local_table UNION SELECT * FROM postgres_local_table UNION SELECT * FROM distributed_table ORDER BY 1,2; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +NOTICE: executing the command locally: SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer) UNION SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer) UNION SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer) ORDER BY 1, 2 + a | b +--------------------------------------------------------------------- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 +(6 rows) + +(SELECT * FROM citus_local_table ORDER BY 1,2 LIMIT 5) INTERSECT (SELECT i, i FROM generate_series(0, 100) i) ORDER BY 1, 2; +NOTICE: executing the command locally: (SELECT citus_local_table.a, citus_local_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY citus_local_table.a, citus_local_table.b LIMIT 5) INTERSECT SELECT i.i, i.i FROM generate_series(0, 100) i(i) ORDER BY 1, 2 + a | b +--------------------------------------------------------------------- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 +(5 rows) + +-- should just work as recursive planner kicks in +SELECT count(*) FROM distributed_table WHERE a IN (SELECT a FROM citus_local_table); +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + count +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT count(*) FROM citus_local_table WHERE a IN (SELECT a FROM distributed_table); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) + count +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT count(*) FROM reference_table WHERE a IN (SELECT a FROM citus_local_table); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.reference_table_1509003 reference_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT citus_local_table.a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table)) + count +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT count(*) FROM citus_local_table WHERE a IN (SELECT a FROM reference_table); +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT reference_table.a FROM citus_local_table_queries.reference_table_1509003 reference_table)) + count +--------------------------------------------------------------------- + 6 +(1 row) + +-- nested recursive queries should just work +SELECT count(*) FROM citus_local_table + WHERE a IN + (SELECT a FROM distributed_table WHERE a IN + (SELECT b FROM citus_local_table WHERE b IN (SELECT b FROM postgres_local_table))); +NOTICE: executing the command locally: SELECT b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (b OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(b integer))) +NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) + count +--------------------------------------------------------------------- + 6 +(1 row) + +-- local outer joins +SELECT count(*) FROM citus_local_table LEFT JOIN reference_table ON (true); +NOTICE: executing the command locally: SELECT count(*) AS count FROM (citus_local_table_queries.citus_local_table_1509001 citus_local_table LEFT JOIN citus_local_table_queries.reference_table_1509003 reference_table ON (true)) + count +--------------------------------------------------------------------- + 36 +(1 row) + +SELECT count(*) FROM reference_table + LEFT JOIN citus_local_table ON (true) + LEFT JOIN postgres_local_table ON (true) + LEFT JOIN reference_table r2 ON (true); +NOTICE: executing the command locally: SELECT count(*) AS count FROM (((citus_local_table_queries.reference_table_1509003 reference_table LEFT JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) LEFT JOIN citus_local_table_queries.postgres_local_table ON (true)) LEFT JOIN citus_local_table_queries.reference_table_1509003 r2 ON (true)) + count +--------------------------------------------------------------------- + 1296 +(1 row) + +-- not supported direct outer join +SELECT count(*) FROM citus_local_table LEFT JOIN distributed_table ON (true); +ERROR: cannot pushdown the subquery +-- distinct in subquery on CTE +WITH one_row AS ( + SELECT a from citus_local_table WHERE b = 1 +) +SELECT + * +FROM + distributed_table +WHERE + b IN (SELECT DISTINCT a FROM one_row) +ORDER BY + 1, 2 +LIMIT + 1; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (b OPERATOR(pg_catalog.=) 1) + a | b +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +WITH one_row_2 AS ( + SELECT a from distributed_table WHERE b = 1 +) +SELECT + * +FROM + citus_local_table +WHERE + b IN (SELECT DISTINCT a FROM one_row_2) +ORDER BY + 1 ,2 +LIMIT + 1; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (b OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) ORDER BY a, b LIMIT 1 + a | b +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +-- join between citus local tables and distributed tables would fail +SELECT count(*) FROM citus_local_table, distributed_table; +NOTICE: executing the command locally: SELECT NULL::integer AS "dummy-1" FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true + count +--------------------------------------------------------------------- + 36 +(1 row) + +SELECT * FROM citus_local_table, distributed_table ORDER BY 1,2,3,4 FOR UPDATE; +ERROR: could not run distributed query with FOR UPDATE/SHARE commands +-- join between citus local tables and postgres local tables are okey +SELECT count(citus_local_table.b), count(postgres_local_table.a) +FROM citus_local_table, postgres_local_table +WHERE citus_local_table.a = postgres_local_table.b; +NOTICE: executing the command locally: SELECT count(citus_local_table.b) AS count, count(postgres_local_table.a) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.postgres_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) postgres_local_table.b) + count | count +--------------------------------------------------------------------- + 6 | 6 +(1 row) + +-- select for update is just OK +SELECT * FROM citus_local_table ORDER BY 1,2 FOR UPDATE; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b FOR UPDATE OF citus_local_table + a | b +--------------------------------------------------------------------- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 +(6 rows) + +--------------------------------------------------------------------- +----- INSERT SELECT ----- +--------------------------------------------------------------------- +-- simple INSERT SELECT is OK +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO citus_local_table +SELECT * from reference_table; +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT a, b FROM citus_local_table_queries.reference_table_1509003 reference_table +INSERT INTO reference_table +SELECT * from citus_local_table; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO citus_local_table +SELECT * from distributed_table; +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO distributed_table +SELECT * from citus_local_table; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +INSERT INTO citus_local_table +SELECT * from citus_local_table_2; +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT a, b FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 +INSERT INTO citus_local_table +SELECT * from citus_local_table_2 +ORDER BY 1,2 +LIMIT 10; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 ORDER BY a, b LIMIT 10 +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO citus_local_table +SELECT * from postgres_local_table; +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO postgres_local_table +SELECT * from citus_local_table; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +-- INSERT SELECT with local joins are OK +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO citus_local_table +SELECT reference_table.* FROM reference_table +JOIN citus_local_table ON (true); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) +INSERT INTO reference_table +SELECT reference_table.* FROM reference_table +JOIN citus_local_table ON (true); +NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO reference_table +SELECT reference_table.* FROM reference_table, postgres_local_table +JOIN citus_local_table ON (true); +NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509003 reference_table, (citus_local_table_queries.postgres_local_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) +NOTICE: executing the copy locally for shard xxxxx +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO distributed_table +SELECT reference_table.* FROM reference_table +JOIN citus_local_table ON (true); +NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) +INSERT INTO distributed_table +SELECT reference_table.* FROM reference_table, postgres_local_table +JOIN citus_local_table ON (true); +NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509003 reference_table, (citus_local_table_queries.postgres_local_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) +INSERT INTO postgres_local_table +SELECT reference_table.* FROM reference_table +JOIN citus_local_table ON (true); +NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) +-- INSERT SELECT that joins reference and distributed tables is also OK +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO citus_local_table +SELECT reference_table.* FROM reference_table +JOIN distributed_table ON (true); +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO citus_local_table +SELECT reference_table.* +FROM reference_table, distributed_table; +NOTICE: executing the copy locally for shard xxxxx +-- INSERT SELECT that joins citus local and distributed table directly will fail .. +INSERT INTO citus_local_table +SELECT distributed_table.* FROM distributed_table +JOIN citus_local_table ON (true); +NOTICE: executing the command locally: SELECT NULL::integer AS "dummy-1" FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true +NOTICE: executing the copy locally for shard xxxxx +-- .. but when wrapped into a CTE, join works fine +INSERT INTO citus_local_table +SELECT distributed_table.* FROM distributed_table +JOIN (WITH cte AS (SELECT * FROM citus_local_table) SELECT * FROM cte) as foo ON (true); +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +NOTICE: executing the copy locally for shard xxxxx +-- multi row insert is OK +INSERT INTO citus_local_table VALUES (1, 2), (3, 4); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) VALUES (1,2), (3,4) +--------------------------------------------------------------------- +----- DELETE / UPDATE ----- +--------------------------------------------------------------------- +-- modifications using citus local tables and postgres local tables +-- are not supported, see below four tests +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +DELETE FROM citus_local_table +USING postgres_local_table +WHERE citus_local_table.b = postgres_local_table.b; +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table USING citus_local_table_queries.postgres_local_table WHERE (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b) +UPDATE citus_local_table +SET b = 5 +FROM postgres_local_table +WHERE citus_local_table.a = 3 AND citus_local_table.b = postgres_local_table.b; +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 5 FROM citus_local_table_queries.postgres_local_table WHERE ((citus_local_table.a OPERATOR(pg_catalog.=) 3) AND (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b)) +DELETE FROM postgres_local_table +USING citus_local_table +WHERE citus_local_table.b = postgres_local_table.b; +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.postgres_local_table USING citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b) +UPDATE postgres_local_table +SET b = 5 +FROM citus_local_table +WHERE citus_local_table.a = 3 AND citus_local_table.b = postgres_local_table.b; +NOTICE: executing the command locally: UPDATE citus_local_table_queries.postgres_local_table SET b = 5 FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE ((citus_local_table.a OPERATOR(pg_catalog.=) 3) AND (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b)) +-- no direct joins supported +UPDATE distributed_table +SET b = 6 +FROM citus_local_table +WHERE citus_local_table.a = distributed_table.a; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true +UPDATE reference_table +SET b = 6 +FROM citus_local_table +WHERE citus_local_table.a = reference_table.a; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true +NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509003 reference_table SET b = 6 FROM (SELECT citus_local_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table_1) citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +-- should not work, add HINT use CTEs +UPDATE citus_local_table +SET b = 6 +FROM distributed_table +WHERE citus_local_table.a = distributed_table.a; +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 6 FROM (SELECT distributed_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) distributed_table_1) distributed_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table.a) +-- should work, add HINT use CTEs +UPDATE citus_local_table +SET b = 6 +FROM reference_table +WHERE citus_local_table.a = reference_table.a; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509003 reference_table WHERE true +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 6 FROM (SELECT reference_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) reference_table_1) reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +-- should not work, add HINT use CTEs +DELETE FROM distributed_table +USING citus_local_table +WHERE citus_local_table.a = distributed_table.a; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true +-- should not work, add HINT use CTEs +DELETE FROM citus_local_table +USING distributed_table +WHERE citus_local_table.a = distributed_table.a; +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table USING (SELECT distributed_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) distributed_table_1) distributed_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table.a) +DELETE FROM reference_table +USING citus_local_table +WHERE citus_local_table.a = reference_table.a; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509003 reference_table USING (SELECT citus_local_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table_1) citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +-- should work, add HINT use CTEs +DELETE FROM citus_local_table +USING reference_table +WHERE citus_local_table.a = reference_table.a; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509003 reference_table WHERE true +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table USING (SELECT reference_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) reference_table_1) reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +-- just works +DELETE FROM citus_local_table +WHERE citus_local_table.a IN (SELECT a FROM distributed_table); +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) +-- just works +DELETE FROM citus_local_table +WHERE citus_local_table.a IN (SELECT a FROM reference_table); +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509003 reference_table +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) +-- just works +WITH distributed_table_cte AS (SELECT * FROM distributed_table) +UPDATE citus_local_table +SET b = 6 +FROM distributed_table_cte +WHERE citus_local_table.a = distributed_table_cte.a; +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 6 FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) distributed_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table_cte.a) +SET citus.log_local_commands to off; +-- just works +WITH reference_table_cte AS (SELECT * FROM reference_table) +UPDATE citus_local_table +SET b = 6 +FROM reference_table_cte +WHERE citus_local_table.a = reference_table_cte.a; +set citus.log_local_commands to on; +--------------------------------------------------------------------- +----- VIEW QUERIES ----- +--------------------------------------------------------------------- +CREATE MATERIALIZED VIEW mat_view_4 AS +SELECT count(*) +FROM citus_local_table +JOIN reference_table +USING (a); +NOTICE: executing the command locally: SELECT count(*) AS count FROM (citus_local_table_queries.citus_local_table_1509001 citus_local_table(a, b) JOIN citus_local_table_queries.reference_table_1509003 reference_table(a, b) USING (a)) +-- ok +SELECT count(*) FROM mat_view_4; + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- should work +SELECT count(*) FROM distributed_table WHERE b in +(SELECT count FROM mat_view_4); + count +--------------------------------------------------------------------- + 1 +(1 row) + +CREATE VIEW view_2 AS +SELECT count(*) +FROM citus_local_table +JOIN citus_local_table_2 USING (a) +JOIN distributed_table USING (a); +-- should fail as view contains direct local dist join +SELECT count(*) FROM view_2; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) view_2 + count +--------------------------------------------------------------------- + 1 +(1 row) + +CREATE VIEW view_3 +AS SELECT count(*) +FROM citus_local_table_2 +JOIN reference_table +USING (a); +-- ok +SELECT count(*) FROM view_3; +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT count(*) AS count FROM (citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2(a, b) JOIN citus_local_table_queries.reference_table_1509003 reference_table(a, b) USING (a))) view_3 + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- view treated as subquery, so should work +SELECT count(*) FROM view_3, distributed_table; +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((SELECT citus_local_table_2_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table_2_1) citus_local_table_2 JOIN citus_local_table_queries.reference_table_1509003 reference_table(a, b) USING (a)) + count +--------------------------------------------------------------------- + 6 +(1 row) + +--------------------------------------------------------------------- +-- Some other tests with subqueries & CTE's -- +--------------------------------------------------------------------- +SELECT clear_and_init_test_tables(); + clear_and_init_test_tables +--------------------------------------------------------------------- + +(1 row) + +SELECT count(*) AS a, count(*) AS b +FROM reference_table +JOIN (SELECT count(*) as a, count(*) as b + FROM citus_local_table_2 + JOIN (SELECT count(*) as a, count(*) as b + FROM postgres_local_table + JOIN (SELECT count(*) as a, count(*) as b + FROM reference_table as table_4677) subquery5108 + USING (a)) subquery7132 + USING (b)) subquery7294 +USING (a); +NOTICE: executing the command locally: SELECT count(*) AS a, count(*) AS b FROM (citus_local_table_queries.reference_table_1509003 reference_table(a, b) JOIN (SELECT count(*) AS a, count(*) AS b FROM (citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2(a, b) JOIN (SELECT count(*) AS a, count(*) AS b FROM (citus_local_table_queries.postgres_local_table JOIN (SELECT count(*) AS a, count(*) AS b FROM citus_local_table_queries.reference_table_1509003 table_4677) subquery5108 USING (a))) subquery7132 USING (b))) subquery7294 USING (a)) + a | b +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +-- direct join inside CTE not supported +WITH cte AS ( +UPDATE citus_local_table lt SET a = mt.a +FROM distributed_table mt WHERE mt.b = lt.b +RETURNING lt.b, lt.a +) SELECT * FROM cte JOIN distributed_table mt ON mt.b = cte.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 lt SET a = mt.a FROM (SELECT mt_1.a, mt_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) mt_1) mt WHERE (mt.b OPERATOR(pg_catalog.=) lt.b) RETURNING lt.b, lt.a + b | a | a | b +--------------------------------------------------------------------- + 0 | 0 | 0 | 0 + 1 | 1 | 1 | 1 + 2 | 2 | 2 | 2 + 3 | 3 | 3 | 3 + 4 | 4 | 4 | 4 + 5 | 5 | 5 | 5 +(6 rows) + +-- join with CTE just works +UPDATE citus_local_table +SET a=5 +FROM (SELECT avg(distributed_table.b) as avg_b + FROM distributed_table) as foo +WHERE +foo.avg_b = citus_local_table.b; +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET a = 5 FROM (SELECT intermediate_result.avg_b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg_b numeric)) foo WHERE (foo.avg_b OPERATOR(pg_catalog.=) (citus_local_table.b)::numeric) +-- should work +UPDATE distributed_table +SET b = avg_a +FROM (SELECT avg(citus_local_table.a) as avg_a FROM citus_local_table) as foo +WHERE foo.avg_a = distributed_table.a +RETURNING distributed_table.*; +NOTICE: executing the command locally: SELECT avg(a) AS avg_a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table + a | b +--------------------------------------------------------------------- +(0 rows) + +-- it is unfortunate that recursive planner cannot detect this +-- but expected to not work +UPDATE citus_local_table +SET a=5 +FROM (SELECT b FROM distributed_table) AS foo +WHERE foo.b = citus_local_table.b; +ERROR: local table citus_local_table cannot be joined with these distributed tables +--------------------------------------------------------------------- +-- test different execution paths -- +--------------------------------------------------------------------- +-- a bit different explain output than for postgres local tables +EXPLAIN (COSTS FALSE) +INSERT INTO citus_local_table +SELECT * FROM distributed_table +ORDER BY distributed_table.* +LIMIT 10; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Limit + -> Sort + Sort Key: remote_scan.worker_column_3 + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Limit + -> Sort + Sort Key: distributed_table.* + -> Seq Scan on distributed_table_1509004 distributed_table +(14 rows) + +-- show that we do not pull to coordinator +EXPLAIN (COSTS FALSE) +INSERT INTO citus_local_table +SELECT * FROM citus_local_table; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Insert on citus_local_table_1509001 citus_table_alias + -> Seq Scan on citus_local_table_1509001 citus_local_table +(7 rows) + +EXPLAIN (COSTS FALSE) +INSERT INTO citus_local_table +SELECT reference_table.* FROM reference_table; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Insert on citus_local_table_1509001 citus_table_alias + -> Seq Scan on reference_table_1509003 reference_table +(7 rows) + +EXPLAIN (COSTS FALSE) +INSERT INTO citus_local_table +SELECT reference_table.* FROM reference_table, postgres_local_table; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Nested Loop + -> Seq Scan on reference_table_1509003 reference_table + -> Materialize + -> Seq Scan on postgres_local_table +(11 rows) + +-- show that we pull to coordinator when a distributed table is involved +EXPLAIN (COSTS FALSE) +INSERT INTO citus_local_table +SELECT reference_table.* FROM reference_table, distributed_table; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Nested Loop + -> Seq Scan on distributed_table_1509004 distributed_table + -> Materialize + -> Seq Scan on reference_table_1509003 reference_table +(11 rows) + +-- truncate tables & add unique constraints to be able to define foreign keys +TRUNCATE reference_table, citus_local_table, distributed_table; +NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.reference_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE +ALTER TABLE reference_table ADD CONSTRAINT pkey_ref PRIMARY KEY (a); +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1509003, 'citus_local_table_queries', 'ALTER TABLE reference_table ADD CONSTRAINT pkey_ref PRIMARY KEY (a);') +ALTER TABLE citus_local_table ADD CONSTRAINT pkey_c PRIMARY KEY (a); +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1509001, 'citus_local_table_queries', 'ALTER TABLE citus_local_table ADD CONSTRAINT pkey_c PRIMARY KEY (a);') +-- define a foreign key chain distributed table -> reference table -> citus local table +-- to test sequential execution +ALTER TABLE distributed_table ADD CONSTRAINT fkey_dist_to_ref FOREIGN KEY(a) REFERENCES reference_table(a) ON DELETE RESTRICT; +ALTER TABLE reference_table ADD CONSTRAINT fkey_ref_to_local FOREIGN KEY(a) REFERENCES citus_local_table(a) ON DELETE RESTRICT; +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509003, 'citus_local_table_queries', 1509001, 'citus_local_table_queries', 'ALTER TABLE reference_table ADD CONSTRAINT fkey_ref_to_local FOREIGN KEY(a) REFERENCES citus_local_table(a) ON DELETE RESTRICT;') +INSERT INTO citus_local_table VALUES (1); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 (a) VALUES (1) +INSERT INTO reference_table VALUES (1); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.reference_table_1509003 (a) VALUES (1) +BEGIN; + INSERT INTO citus_local_table VALUES (1) ON CONFLICT (a) DO NOTHING; +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (1) ON CONFLICT(a) DO NOTHING + INSERT INTO distributed_table VALUES (1); + -- should show sequential as first inserting into citus local table + -- would force the xact block to use sequential execution + show citus.multi_shard_modify_mode; + citus.multi_shard_modify_mode +--------------------------------------------------------------------- + sequential +(1 row) + +ROLLBACK; +BEGIN; + TRUNCATE distributed_table; + -- should error out as we truncated distributed_table via parallel execution + TRUNCATE citus_local_table CASCADE; +NOTICE: truncate cascades to table "reference_table" +NOTICE: truncate cascades to table "distributed_table" +NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE +ERROR: cannot execute DDL on table "citus_local_table" because there was a parallel DDL access to distributed table "distributed_table" in the same transaction +ROLLBACK; +BEGIN; + SET LOCAL citus.multi_shard_modify_mode TO 'sequential'; + TRUNCATE distributed_table; + -- should work fine as we already switched to sequential execution + -- before parallel truncate + TRUNCATE citus_local_table CASCADE; +NOTICE: truncate cascades to table "reference_table" +NOTICE: truncate cascades to table "distributed_table" +NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE +NOTICE: truncate cascades to table "reference_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.reference_table_xxxxx CASCADE +ROLLBACK; +ALTER TABLE distributed_table DROP CONSTRAINT fkey_dist_to_ref; +BEGIN; + INSERT INTO citus_local_table VALUES (1) ON CONFLICT (a) DO NOTHING; +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (1) ON CONFLICT(a) DO NOTHING + show citus.multi_shard_modify_mode; + citus.multi_shard_modify_mode +--------------------------------------------------------------------- + sequential +(1 row) + +ROLLBACK; +-- remove uniqueness constraint and dependent foreign key constraint for next tests +ALTER TABLE reference_table DROP CONSTRAINT fkey_ref_to_local; +NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509003, 'citus_local_table_queries', 1509001, 'citus_local_table_queries', 'ALTER TABLE reference_table DROP CONSTRAINT fkey_ref_to_local;') +ALTER TABLE citus_local_table DROP CONSTRAINT pkey_c; +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1509001, 'citus_local_table_queries', 'ALTER TABLE citus_local_table DROP CONSTRAINT pkey_c;') +COPY citus_local_table(a) FROM PROGRAM 'seq 1'; +-- should use local execution +BEGIN; + COPY citus_local_table(a) FROM PROGRAM 'seq 1'; +NOTICE: executing the copy locally for shard xxxxx + COPY citus_local_table(a) FROM PROGRAM 'seq 1'; +NOTICE: executing the copy locally for shard xxxxx +COMMIT; +COPY citus_local_table TO STDOUT; +1 \N +1 \N +1 \N +1 \N +COPY (SELECT * FROM citus_local_table) TO STDOUT; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +1 \N +1 \N +1 \N +1 \N +BEGIN; + COPY citus_local_table TO STDOUT; +1 \N +1 \N +1 \N +1 \N +COMMIT; +BEGIN; + COPY (SELECT * FROM citus_local_table) TO STDOUT; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table +1 \N +1 \N +1 \N +1 \N +COMMIT; +-- truncate test tables for next test +TRUNCATE citus_local_table, reference_table, distributed_table; +NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.reference_table_xxxxx CASCADE +BEGIN; + INSERT INTO citus_local_table VALUES (1), (2); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (1), (2) + SAVEPOINT sp1; + INSERT INTO citus_local_table VALUES (3), (4); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (3), (4) + ROLLBACK TO SAVEPOINT sp1; + SELECT * FROM citus_local_table ORDER BY 1,2; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b + a | b +--------------------------------------------------------------------- + 1 | + 2 | +(2 rows) + + SAVEPOINT sp2; + INSERT INTO citus_local_table VALUES (3), (4); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (3), (4) + INSERT INTO distributed_table VALUES (3), (4); + ROLLBACK TO SAVEPOINT sp2; + SELECT * FROM citus_local_table ORDER BY 1,2; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b + a | b +--------------------------------------------------------------------- + 1 | + 2 | +(2 rows) + + SELECT * FROM distributed_table ORDER BY 1,2; + a | b +--------------------------------------------------------------------- +(0 rows) + + SAVEPOINT sp3; + INSERT INTO citus_local_table VALUES (3), (2); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (3), (2) + INSERT INTO reference_table VALUES (3), (2); +NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.reference_table_1509003 AS citus_table_alias (a) VALUES (3), (2) + ROLLBACK TO SAVEPOINT sp3; + SELECT * FROM citus_local_table ORDER BY 1,2; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b + a | b +--------------------------------------------------------------------- + 1 | + 2 | +(2 rows) + + SELECT * FROM reference_table ORDER BY 1,2; +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.reference_table_1509003 reference_table ORDER BY a, b + a | b +--------------------------------------------------------------------- +(0 rows) + +COMMIT; +-- cleanup at exit +DROP SCHEMA citus_local_table_queries CASCADE; +NOTICE: drop cascades to 14 other objects diff --git a/src/test/regress/expected/cte_inline.out b/src/test/regress/expected/cte_inline.out index a534a7ac9..18cee5b1c 100644 --- a/src/test/regress/expected/cte_inline.out +++ b/src/test/regress/expected/cte_inline.out @@ -1,3 +1,12 @@ +-- +-- CTE_INLINE +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA cte_inline; SET search_path TO cte_inline; SET citus.next_shard_id TO 1960000; @@ -857,10 +866,10 @@ DEBUG: CTE fist_table_cte is going to be inlined via distributed planning DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'key' -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960000_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960001_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960002_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960000_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960001_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960002_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) -- the following INSERT..SELECT is even more interesting -- the CTE becomes pushdownable INSERT INTO test_table @@ -871,10 +880,10 @@ WITH fist_table_cte AS FROM fist_table_cte; DEBUG: CTE fist_table_cte is going to be inlined via distributed planning -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960000 test_table) fist_table_cte WHERE (key IS NOT NULL) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960001 test_table) fist_table_cte WHERE (key IS NOT NULL) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960002 test_table) fist_table_cte WHERE (key IS NOT NULL) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960003 test_table) fist_table_cte WHERE (key IS NOT NULL) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT fist_table_cte.key, fist_table_cte.value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960000 test_table) fist_table_cte WHERE (fist_table_cte.key IS NOT NULL) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT fist_table_cte.key, fist_table_cte.value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960001 test_table) fist_table_cte WHERE (fist_table_cte.key IS NOT NULL) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT fist_table_cte.key, fist_table_cte.value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960002 test_table) fist_table_cte WHERE (fist_table_cte.key IS NOT NULL) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT fist_table_cte.key, fist_table_cte.value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960003 test_table) fist_table_cte WHERE (fist_table_cte.key IS NOT NULL) -- update/delete/modifying ctes -- we don't support any cte inlining in modifications -- queries and modifying CTEs diff --git a/src/test/regress/expected/cte_inline_0.out b/src/test/regress/expected/cte_inline_0.out new file mode 100644 index 000000000..bb4869674 --- /dev/null +++ b/src/test/regress/expected/cte_inline_0.out @@ -0,0 +1,1536 @@ +-- +-- CTE_INLINE +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +CREATE SCHEMA cte_inline; +SET search_path TO cte_inline; +SET citus.next_shard_id TO 1960000; +CREATE TABLE test_table (key int, value text, other_value jsonb); +SELECT create_distributed_table ('test_table', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO test_table SELECT i % 10, 'test' || i, row_to_json(row(i, i*18, 'test' || i)) FROM generate_series (0, 100) i; +SET client_min_messages TO DEBUG; +-- Citus should not inline this CTE because otherwise it cannot +-- plan the query +WITH cte_1 AS (SELECT * FROM test_table) +SELECT + * +FROM + test_table LEFT JOIN cte_1 USING (value) +ORDER BY 1 DESC LIMIT 3; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test99 | 9 | {"f1": 99, "f2": 1782, "f3": "test99"} | 9 | {"f1": 99, "f2": 1782, "f3": "test99"} + test98 | 8 | {"f1": 98, "f2": 1764, "f3": "test98"} | 8 | {"f1": 98, "f2": 1764, "f3": "test98"} + test97 | 7 | {"f1": 97, "f2": 1746, "f3": "test97"} | 7 | {"f1": 97, "f2": 1746, "f3": "test97"} +(3 rows) + +-- Should still not be inlined even if NOT MATERIALIZED is passed +WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) +SELECT + * +FROM + test_table LEFT JOIN cte_1 USING (value) +ORDER BY 2 DESC LIMIT 1; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.key DESC LIMIT 1 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 1 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test9 | 9 | {"f1": 9, "f2": 162, "f3": "test9"} | 9 | {"f1": 9, "f2": 162, "f3": "test9"} +(1 row) + +-- the cte can be inlined because the unsupported +-- part of the query (subquery in WHERE clause) +-- doesn't access the cte +WITH cte_1 AS (SELECT * FROM test_table) +SELECT + count(*) +FROM + cte_1 +WHERE + key IN ( + SELECT + (SELECT 1) + FROM + test_table WHERE key = 1 + ); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT (SELECT 1) FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer))) +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 10 +(1 row) + +-- a similar query as the above, and this time the planning +-- fails, but it fails because the subquery in WHERE clause +-- cannot be planned by Citus +WITH cte_1 AS (SELECT * FROM test_table) +SELECT + count(*) +FROM + cte_1 +WHERE + key IN ( + SELECT + key + FROM + test_table + FOR UPDATE + ); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: SELECT FOR UPDATE with table replication factor > 1 not supported for non-reference tables. +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: SELECT FOR UPDATE with table replication factor > 1 not supported for non-reference tables. +ERROR: could not run distributed query with FOR UPDATE/SHARE commands +HINT: Consider using an equality filter on the distributed table's partition column. +-- Citus does the inlining, the planning fails +-- and retries without inlining, which works +-- fine later via recursive planning +WITH cte_1 AS + (SELECT * + FROM test_table) +SELECT *, (SELECT 1) +FROM + (SELECT * + FROM cte_1) AS foo +ORDER BY 2 DESC LIMIT 1; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 1 + key | value | other_value | ?column? +--------------------------------------------------------------------- + 9 | test99 | {"f1": 99, "f2": 1782, "f3": "test99"} | 1 +(1 row) + +-- a little more complicated query tree +-- Citus does the inlining, the planning fails +-- and retries without inlining, which works +WITH top_cte AS + (SELECT * + FROM test_table) +SELECT count(*) +FROM top_cte, + (WITH cte_1 AS + (SELECT * + FROM test_table) SELECT *, (SELECT 1) + FROM + (SELECT * + FROM cte_1) AS foo) AS bar; +DEBUG: CTE top_cte is going to be inlined via distributed planning +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value, (SELECT 1) FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) top_cte, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) bar(key, value, other_value, "?column?") +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 10201 +(1 row) + +-- CTE is used inside a subquery in WHERE clause +-- the query wouldn't work by inlining, so Citus +-- retries again via recursive planning, which +-- works fine +WITH cte_1 AS + (SELECT * + FROM test_table) +SELECT count(*) +FROM test_table +WHERE KEY IN + (SELECT (SELECT 1) + FROM + (SELECT *, + random() + FROM + (SELECT * + FROM cte_1) AS foo) AS bar); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT (SELECT 1) FROM (SELECT foo.key, foo.value, foo.other_value, random() AS random FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo) bar +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer))) +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 10 +(1 row) + +-- cte_1 is used inside another CTE, but still +-- doesn't work when inlined because it is finally +-- used in an unsupported query +-- but still works fine because recursive planning +-- kicks in +WITH cte_1 AS + (SELECT * + FROM test_table) +SELECT (SELECT 1) AS KEY FROM ( + WITH cte_2 AS (SELECT *, random() + FROM (SELECT *,random() FROM cte_1) as foo) +SELECT *, random() FROM cte_2) as bar ORDER BY 1 DESC LIMIT 3; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_2: SELECT key, value, other_value, random, random() AS random FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value, random() AS random FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT 1) AS key FROM (SELECT cte_2.key, cte_2.value, cte_2.other_value, cte_2.random, cte_2.random_1 AS random, random() AS random FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.random, intermediate_result.random_1 AS random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, random double precision, random_1 double precision)) cte_2(key, value, other_value, random, random_1)) bar(key, value, other_value, random, random_1, random_2) ORDER BY (SELECT 1) DESC LIMIT 3 +DEBUG: Creating router plan + key +--------------------------------------------------------------------- + 1 + 1 + 1 +(3 rows) + +-- in this example, cte_2 can be inlined, because it is not used +-- on any query that Citus cannot plan. However, cte_1 should not be +-- inlined, because it is used with a subquery in target list +WITH cte_1 AS (SELECT * FROM test_table), + cte_2 AS (select * from test_table) +SELECT + count(*) +FROM + (SELECT *, (SELECT 1) FROM cte_1) as foo + JOIN + cte_2 + ON (true); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT cte_1.key, cte_1.value, cte_1.other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo(key, value, other_value, "?column?") JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON (true)) +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 10201 +(1 row) + +-- unreferenced CTEs are just ignored +-- by Citus/Postgres +WITH a AS (SELECT * FROM test_table) +SELECT + *, row_number() OVER () +FROM + test_table +WHERE + key = 1 +ORDER BY 3 DESC +LIMIT 5; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 + key | value | other_value | row_number +--------------------------------------------------------------------- + 1 | test91 | {"f1": 91, "f2": 1638, "f3": "test91"} | 10 + 1 | test81 | {"f1": 81, "f2": 1458, "f3": "test81"} | 9 + 1 | test71 | {"f1": 71, "f2": 1278, "f3": "test71"} | 8 + 1 | test61 | {"f1": 61, "f2": 1098, "f3": "test61"} | 7 + 1 | test51 | {"f1": 51, "f2": 918, "f3": "test51"} | 6 +(5 rows) + +-- router queries are affected by the distributed +-- cte inlining +WITH a AS (SELECT * FROM test_table WHERE key = 1) +SELECT + *, (SELECT 1) +FROM + a +WHERE + key = 1 +ORDER BY 1 DESC +LIMIT 5; +DEBUG: CTE a is going to be inlined via distributed planning +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 + key | value | other_value | ?column? +--------------------------------------------------------------------- + 1 | test1 | {"f1": 1, "f2": 18, "f3": "test1"} | 1 + 1 | test11 | {"f1": 11, "f2": 198, "f3": "test11"} | 1 + 1 | test21 | {"f1": 21, "f2": 378, "f3": "test21"} | 1 + 1 | test31 | {"f1": 31, "f2": 558, "f3": "test31"} | 1 + 1 | test41 | {"f1": 41, "f2": 738, "f3": "test41"} | 1 +(5 rows) + +-- non router queries are affected by the distributed +-- cte inlining as well +WITH a AS (SELECT * FROM test_table) +SELECT + count(*) +FROM + a +WHERE + key = 1; +DEBUG: CTE a is going to be inlined via distributed planning +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 + count +--------------------------------------------------------------------- + 10 +(1 row) + +-- explicitely using NOT MATERIALIZED should result in the same +WITH a AS NOT MATERIALIZED (SELECT * FROM test_table) +SELECT + count(*) +FROM + a +WHERE + key = 1; +DEBUG: CTE a is going to be inlined via distributed planning +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 + count +--------------------------------------------------------------------- + 10 +(1 row) + +-- using MATERIALIZED should cause inlining not to happen +WITH a AS MATERIALIZED (SELECT * FROM test_table) +SELECT + count(*) +FROM + a +WHERE + key = 1; +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) a WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: Creating router plan + count +--------------------------------------------------------------------- + 10 +(1 row) + +-- EXPLAIN should show the difference between materialized an not materialized +EXPLAIN (COSTS OFF) WITH a AS (SELECT * FROM test_table) +SELECT + count(*) +FROM + a +WHERE + key = 1; +DEBUG: CTE a is going to be inlined via distributed planning +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Aggregate + -> Seq Scan on test_table_1960000 test_table + Filter: (key = 1) +(8 rows) + +EXPLAIN (COSTS OFF) WITH a AS MATERIALIZED (SELECT * FROM test_table) +SELECT + count(*) +FROM + a +WHERE + key = 1; +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) a WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: Creating router plan + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + -> Distributed Subplan XXX_1 + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on test_table_1960000 test_table + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Aggregate + -> Function Scan on read_intermediate_result intermediate_result + Filter: (key = 1) +(15 rows) + +-- citus should not inline the CTE because it is used multiple times +WITH cte_1 AS (SELECT * FROM test_table) +SELECT + count(*) +FROM + cte_1 as first_entry + JOIN + cte_1 as second_entry + USING (key); +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) first_entry JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) second_entry USING (key)) +DEBUG: Creating router plan + count +--------------------------------------------------------------------- + 1021 +(1 row) + +-- NOT MATERIALIZED should cause the query to be inlined twice +WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) +SELECT + count(*) +FROM + cte_1 as first_entry + JOIN + cte_1 as second_entry + USING (key); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] +DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] +DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] +DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] +DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] +DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] +DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] + count +--------------------------------------------------------------------- + 1021 +(1 row) + +-- EXPLAIN should show the differences between MATERIALIZED and NOT MATERIALIZED +\set VERBOSITY terse +SELECT public.coordinator_plan_with_subplans($Q$ +EXPLAIN (COSTS OFF) WITH cte_1 AS (SELECT * FROM test_table) +SELECT + count(*) +FROM + cte_1 as first_entry + JOIN + cte_1 as second_entry + USING (key); +$Q$); +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) first_entry JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) second_entry USING (key)) +DEBUG: Creating router plan + coordinator_plan_with_subplans +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + -> Distributed Subplan XXX_1 + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Task Count: 1 +(5 rows) + +\set VERBOSITY default +-- enable_group_by_reordering is a new GUC introduced in PG15 +-- it does some optimization of the order of group by keys which results +-- in a different explain output plan between PG13/14 and PG15 +-- Hence we set that GUC to off. +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int > 14 AS server_version_above_fourteen +\gset +\if :server_version_above_fourteen +SET enable_group_by_reordering TO off; +\endif +SELECT DISTINCT 1 FROM run_command_on_workers($$ALTER SYSTEM SET enable_group_by_reordering TO off;$$); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT run_command_on_workers($$SELECT pg_reload_conf()$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,t) + (localhost,57638,t,t) +(2 rows) + +EXPLAIN (COSTS OFF) WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) +SELECT + count(*) +FROM + cte_1 as first_entry + JOIN + cte_1 as second_entry + USING (key); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] +DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] +DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] +DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] +DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] +DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] +DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] + QUERY PLAN +--------------------------------------------------------------------- + Aggregate + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Aggregate + -> Hash Join + Hash Cond: (test_table.key = test_table_1.key) + -> Seq Scan on test_table_1960000 test_table + -> Hash + -> Seq Scan on test_table_1960000 test_table_1 +(12 rows) + +\if :server_version_above_fourteen +RESET enable_group_by_reordering; +\endif +SELECT DISTINCT 1 FROM run_command_on_workers($$ALTER SYSTEM RESET enable_group_by_reordering;$$); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT run_command_on_workers($$SELECT pg_reload_conf()$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,t) + (localhost,57638,t,t) +(2 rows) + +-- ctes with volatile functions are not +-- inlined +WITH cte_1 AS (SELECT *, random() FROM test_table) +SELECT + key, value +FROM + cte_1 +ORDER BY 2 DESC LIMIT 1; +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value, random() AS random FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, random double precision)) cte_1 ORDER BY value DESC LIMIT 1 +DEBUG: Creating router plan + key | value +--------------------------------------------------------------------- + 9 | test99 +(1 row) + +-- even with NOT MATERIALIZED volatile functions should not be inlined +WITH cte_1 AS NOT MATERIALIZED (SELECT *, random() FROM test_table) +SELECT + count(*) +FROM + cte_1; +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value, random() AS random FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, random double precision)) cte_1 +DEBUG: Creating router plan + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- cte_1 should be able to inlined even if +-- it is used one level below +WITH cte_1 AS (SELECT * FROM test_table) +SELECT + count(*) +FROM +( + WITH ct2 AS (SELECT * FROM cte_1) + SELECT * FROM ct2 +) as foo; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE ct2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- a similar query, but there is also +-- one more cte, which relies on the previous +-- CTE +WITH cte_1 AS (SELECT * FROM test_table) +SELECT + count(DISTINCT key) +FROM +( + WITH cte_2 AS (SELECT * FROM cte_1), + cte_3 AS (SELECT * FROM cte_2) + SELECT * FROM cte_3 +) as foo; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: CTE cte_3 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 10 +(1 row) + +-- inlined CTE contains a reference to outer query +-- should be fine (because we pushdown the whole query) +SELECT count(*) + FROM + (SELECT * + FROM test_table) AS test_table_cte + JOIN LATERAL + (WITH bar AS (SELECT * + FROM test_table + WHERE key = test_table_cte.key) + SELECT * + FROM + bar + LEFT JOIN test_table u2 ON u2.key = bar.key) AS foo ON TRUE; +DEBUG: CTE bar is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 10331 +(1 row) + +-- inlined CTE contains a reference to outer query +-- should be fine (even if the recursive planning fails +-- to recursively plan the query) +SELECT count(*) + FROM + (SELECT * + FROM test_table) AS test_table_cte + JOIN LATERAL + (WITH bar AS (SELECT * + FROM test_table + WHERE key = test_table_cte.key) + SELECT * + FROM + bar + LEFT JOIN test_table u2 ON u2.key = bar.value::int) AS foo ON TRUE; +DEBUG: CTE bar is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: skipping recursive planning for the subquery since it contains references to outer queries +DEBUG: skipping recursive planning for the subquery since it contains references to outer queries +DEBUG: skipping recursive planning for the subquery since it contains references to outer queries +DEBUG: Router planner cannot handle multi-shard select queries +ERROR: CTEs that refer to other subqueries are not supported in multi-shard queries +-- inlined CTE can recursively planned later, that's the decision +-- recursive planning makes +-- LIMIT 5 in cte2 triggers recusrive planning, after cte inlining +WITH cte_1 AS (SELECT * FROM test_table) +SELECT + * +FROM +( + WITH ct2 AS (SELECT * FROM cte_1 ORDER BY 1, 2, 3 LIMIT 5) + SELECT * FROM ct2 +) as foo ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 5; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE ct2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 5 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 ORDER BY key, value, other_value LIMIT 5 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value, other_value FROM (SELECT ct2.key, ct2.value, ct2.other_value FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) ct2) foo ORDER BY key DESC, value DESC, other_value DESC LIMIT 5 +DEBUG: Creating router plan + key | value | other_value +--------------------------------------------------------------------- + 0 | test30 | {"f1": 30, "f2": 540, "f3": "test30"} + 0 | test20 | {"f1": 20, "f2": 360, "f3": "test20"} + 0 | test100 | {"f1": 100, "f2": 1800, "f3": "test100"} + 0 | test10 | {"f1": 10, "f2": 180, "f3": "test10"} + 0 | test0 | {"f1": 0, "f2": 0, "f3": "test0"} +(5 rows) + +-- all nested CTEs can be inlinied +WITH cte_1 AS ( + WITH cte_1 AS ( + WITH cte_1 AS ( + WITH cte_1 AS ( + WITH cte_1 AS ( + WITH cte_1 AS ( + WITH cte_1 AS (SELECT count(*), key FROM test_table GROUP BY key) + SELECT * FROM cte_1) + SELECT * FROM cte_1 WHERE key = 1) + SELECT * FROM cte_1 WHERE key = 2) + SELECT * FROM cte_1 WHERE key = 3) + SELECT * FROM cte_1 WHERE key = 4) + SELECT * FROM cte_1 WHERE key = 5) +SELECT * FROM cte_1 WHERE key = 6; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 + count | key +--------------------------------------------------------------------- +(0 rows) + +-- ctes can be inlined even if they are used +-- in set operations +WITH cte_1 AS (SELECT * FROM test_table), + cte_2 AS (SELECT * FROM test_table) +SELECT count(*) FROM ( +(SELECT * FROM cte_1 EXCEPT SELECT * FROM test_table) +UNION +(SELECT * FROM cte_2)) as foo; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_2 +DEBUG: Creating router plan +DEBUG: generating subplan XXX_4 for subquery (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb) EXCEPT SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) UNION SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) foo +DEBUG: Creating router plan + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- cte_1 is going to be inlined even inside another set operation +WITH cte_1 AS (SELECT * FROM test_table), + cte_2 AS (SELECT * FROM test_table ORDER BY 1 DESC LIMIT 3) +(SELECT *, (SELECT 1) FROM cte_1 EXCEPT SELECT *, 1 FROM test_table) +UNION +(SELECT *, 1 FROM cte_2) +ORDER BY 1,2; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table ORDER BY key DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value, 1 FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer) EXCEPT SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) UNION SELECT cte_2.key, cte_2.value, cte_2.other_value, 1 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ORDER BY 1, 2 +DEBUG: Creating router plan + key | value | other_value | ?column? +--------------------------------------------------------------------- + 9 | test19 | {"f1": 19, "f2": 342, "f3": "test19"} | 1 + 9 | test29 | {"f1": 29, "f2": 522, "f3": "test29"} | 1 + 9 | test9 | {"f1": 9, "f2": 162, "f3": "test9"} | 1 +(3 rows) + +-- cte_1 is safe to inline, even if because after inlining +-- it'd be in a query tree where there is a query that is +-- not supported by Citus unless recursively planned +-- cte_2 is on another queryTree, should be fine +WITH cte_1 AS (SELECT * FROM test_table), + cte_2 AS (SELECT * FROM test_table) +(SELECT *, (SELECT key FROM cte_1) FROM test_table) +UNION +(SELECT *, 1 FROM cte_2); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value, (SELECT cte_1.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1) AS key FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.key_1 AS key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, key_1 integer) UNION SELECT cte_2.key, cte_2.value, cte_2.other_value, 1 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 +DEBUG: Creating router plan +ERROR: more than one row returned by a subquery used as an expression +CONTEXT: while executing command on localhost:xxxxx +-- after inlining CTEs, the query becomes +-- subquery pushdown with set operations +WITH cte_1 AS (SELECT * FROM test_table), + cte_2 AS (SELECT * FROM test_table) +SELECT max(key) FROM +( + SELECT * FROM cte_1 + UNION + SELECT * FROM cte_2 +) as bar; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + max +--------------------------------------------------------------------- + 9 +(1 row) + +-- cte LEFT JOIN subquery should only work +-- when CTE is inlined, as Citus currently +-- doesn't know how to handle intermediate +-- results in the outer parts of outer +-- queries +WITH cte AS (SELECT * FROM test_table) +SELECT + count(*) +FROM + cte LEFT JOIN test_table USING (key); +DEBUG: CTE cte is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 1021 +(1 row) + +-- the CTEs are very simple, so postgres +-- can pull-up the subqueries after inlining +-- the CTEs, and the query that we send to workers +-- becomes a join between two tables +WITH cte_1 AS (SELECT key FROM test_table), + cte_2 AS (SELECT key FROM test_table) +SELECT + count(*) +FROM + cte_1 JOIN cte_2 USING (key); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] +DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] +DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] +DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] +DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] +DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] +DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] +DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] +DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] + count +--------------------------------------------------------------------- + 1021 +(1 row) + +-- the following query is kind of interesting +-- During INSERT .. SELECT via coordinator, +-- Citus moves the CTEs into SELECT part, and plans/execute +-- the SELECT separately. Thus, fist_table_cte can be inlined +-- by Citus -- but not by Postgres +WITH fist_table_cte AS + (SELECT * FROM test_table) +INSERT INTO test_table + (key, value) + SELECT + key, value + FROM + fist_table_cte; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: CTE fist_table_cte is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'key' +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960000_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960001_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960002_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) +-- the following INSERT..SELECT is even more interesting +-- the CTE becomes pushdownable +INSERT INTO test_table +WITH fist_table_cte AS + (SELECT * FROM test_table) + SELECT + key, value + FROM + fist_table_cte; +DEBUG: CTE fist_table_cte is going to be inlined via distributed planning +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960000 test_table) fist_table_cte WHERE (key IS NOT NULL) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960001 test_table) fist_table_cte WHERE (key IS NOT NULL) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960002 test_table) fist_table_cte WHERE (key IS NOT NULL) +DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960003 test_table) fist_table_cte WHERE (key IS NOT NULL) +-- update/delete/modifying ctes +-- we don't support any cte inlining in modifications +-- queries and modifying CTEs +WITH cte_1 AS (SELECT * FROM test_table) + DELETE FROM test_table WHERE key NOT IN (SELECT key FROM cte_1); +DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM cte_inline.test_table WHERE (NOT (key OPERATOR(pg_catalog.=) ANY (SELECT cte_1.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1))) +DEBUG: Creating router plan +-- NOT MATERIALIZED should not CTEs that are used in a modifying query, because +-- we de still don't support it +WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) + DELETE FROM test_table WHERE key NOT IN (SELECT key FROM cte_1); +DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM cte_inline.test_table WHERE (NOT (key OPERATOR(pg_catalog.=) ANY (SELECT cte_1.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1))) +DEBUG: Creating router plan +-- we don't inline CTEs if they are modifying CTEs +WITH cte_1 AS (DELETE FROM test_table WHERE key % 3 = 1 RETURNING key) +SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: DELETE FROM cte_inline.test_table WHERE ((key OPERATOR(pg_catalog.%) 3) OPERATOR(pg_catalog.=) 1) RETURNING key +DEBUG: Creating router plan +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 ORDER BY key DESC LIMIT 3 +DEBUG: Creating router plan + key +--------------------------------------------------------------------- + 7 + 7 + 7 +(3 rows) + +-- NOT MATERIALIZED should not affect modifying CTEs +WITH cte_1 AS NOT MATERIALIZED (DELETE FROM test_table WHERE key % 3 = 0 RETURNING key) +SELECT count(*) FROM cte_1; +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: DELETE FROM cte_inline.test_table WHERE ((key OPERATOR(pg_catalog.%) 3) OPERATOR(pg_catalog.=) 0) RETURNING key +DEBUG: Creating router plan +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 +DEBUG: Creating router plan + count +--------------------------------------------------------------------- + 164 +(1 row) + +-- cte with column aliases +SELECT * FROM test_table, +(WITH cte_1 (x,y) AS (SELECT * FROM test_table), + cte_2 (z,y) AS (SELECT value, other_value, key FROM test_table), + cte_3 (t,m) AS (SELECT z, y, key as cte_2_key FROM cte_2) + SELECT * FROM cte_2, cte_3) as bar +ORDER BY value, other_value, z, y, t, m, cte_2_key +LIMIT 5; +DEBUG: CTE cte_3 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_2: SELECT value, other_value, key FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.key, test_table.value, test_table.other_value, bar.z, bar.y, bar.key, bar.t, bar.m, bar.cte_2_key FROM cte_inline.test_table, (SELECT cte_2.z, cte_2.y, cte_2.key, cte_3.t, cte_3.m, cte_3.cte_2_key FROM (SELECT intermediate_result.value AS z, intermediate_result.other_value AS y, intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text, other_value jsonb, key integer)) cte_2, (SELECT cte_2_1.z AS t, cte_2_1.y AS m, cte_2_1.key AS cte_2_key FROM (SELECT intermediate_result.value AS z, intermediate_result.other_value AS y, intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text, other_value jsonb, key integer)) cte_2_1) cte_3) bar ORDER BY test_table.value, test_table.other_value, bar.z, bar.y, bar.t, bar.m, bar.cte_2_key LIMIT 5 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 5 + key | value | other_value | z | y | key | t | m | cte_2_key +--------------------------------------------------------------------- + 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 + 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | | 2 + 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | | 2 + 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | | 2 + 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test15 | {"f1": 15, "f2": 270, "f3": "test15"} | 5 +(5 rows) + +-- cte used in HAVING subquery just works fine +-- even if it is inlined +WITH cte_1 AS (SELECT max(key) as max FROM test_table) +SELECT + key, count(*) +FROM + test_table +GROUP BY + key +HAVING + (count(*) > (SELECT max FROM cte_1)) +ORDER BY 2 DESC, 1 DESC +LIMIT 5; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT max(key) AS max FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, count(*) AS count FROM cte_inline.test_table GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.>) (SELECT cte_1.max FROM (SELECT intermediate_result.max FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(max integer)) cte_1)) ORDER BY (count(*)) DESC, key DESC LIMIT 5 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 5 + key | count +--------------------------------------------------------------------- + 8 | 40 + 5 | 40 + 2 | 40 +(3 rows) + +-- cte used in ORDER BY just works fine +-- even if it is inlined +WITH cte_1 AS (SELECT max(key) as max FROM test_table) +SELECT + key +FROM + test_table JOIN cte_1 ON (key = max) +ORDER BY + cte_1.max +LIMIT 3; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT max(key) AS max FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.key FROM (cte_inline.test_table JOIN (SELECT intermediate_result.max FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(max integer)) cte_1 ON ((test_table.key OPERATOR(pg_catalog.=) cte_1.max))) ORDER BY cte_1.max LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + key +--------------------------------------------------------------------- + 8 + 8 + 8 +(3 rows) + +PREPARE inlined_cte_without_params AS + WITH cte_1 AS (SELECT count(*) FROM test_table GROUP BY key) + SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; +PREPARE non_inlined_cte_without_params AS + WITH cte_1 AS (SELECT * FROM test_table) + SELECT + * + FROM + test_table LEFT JOIN cte_1 USING (value) ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 3; +PREPARE inlined_cte_has_parameter_on_non_dist_key(text) AS + WITH cte_1 AS (SELECT count(*) FROM test_table WHERE value = $1 GROUP BY key) + SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; +PREPARE inlined_cte_has_parameter_on_dist_key(int) AS + WITH cte_1 AS (SELECT count(*) FROM test_table WHERE key > $1 GROUP BY key) + SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; +PREPARE non_inlined_cte_has_parameter_on_dist_key(int) AS + WITH cte_1 AS (SELECT * FROM test_table where key > $1) + SELECT + * + FROM + test_table LEFT JOIN cte_1 USING (value) ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 3; +PREPARE retry_planning(int) AS + WITH cte_1 AS (SELECT * FROM test_table WHERE key > $1) + SELECT json_object_agg(DISTINCT key, value) FROM cte_1 ORDER BY max(key), min(value) DESC LIMIT 3; +EXECUTE inlined_cte_without_params; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 40 + 40 + 40 +(3 rows) + +EXECUTE inlined_cte_without_params; + count +--------------------------------------------------------------------- + 40 + 40 + 40 +(3 rows) + +EXECUTE inlined_cte_without_params; + count +--------------------------------------------------------------------- + 40 + 40 + 40 +(3 rows) + +EXECUTE inlined_cte_without_params; + count +--------------------------------------------------------------------- + 40 + 40 + 40 +(3 rows) + +EXECUTE inlined_cte_without_params; + count +--------------------------------------------------------------------- + 40 + 40 + 40 +(3 rows) + +EXECUTE inlined_cte_without_params; + count +--------------------------------------------------------------------- + 40 + 40 + 40 +(3 rows) + +EXECUTE non_inlined_cte_without_params; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_without_params; + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_without_params; + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_without_params; + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_without_params; + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_without_params; + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE inlined_cte_has_parameter_on_non_dist_key('test1'); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- +(0 rows) + +EXECUTE inlined_cte_has_parameter_on_non_dist_key('test2'); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 4 +(1 row) + +EXECUTE inlined_cte_has_parameter_on_non_dist_key('test3'); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- +(0 rows) + +EXECUTE inlined_cte_has_parameter_on_non_dist_key('test4'); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- +(0 rows) + +EXECUTE inlined_cte_has_parameter_on_non_dist_key('test5'); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 4 +(1 row) + +EXECUTE inlined_cte_has_parameter_on_non_dist_key('test6'); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- +(0 rows) + +EXECUTE inlined_cte_has_parameter_on_dist_key(1); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 40 + 40 + 40 +(3 rows) + +EXECUTE inlined_cte_has_parameter_on_dist_key(2); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 40 + 40 +(2 rows) + +EXECUTE inlined_cte_has_parameter_on_dist_key(3); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 40 + 40 +(2 rows) + +EXECUTE inlined_cte_has_parameter_on_dist_key(4); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 40 + 40 +(2 rows) + +EXECUTE inlined_cte_has_parameter_on_dist_key(5); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 40 +(1 row) + +EXECUTE inlined_cte_has_parameter_on_dist_key(6); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + count +--------------------------------------------------------------------- + 40 +(1 row) + +EXECUTE non_inlined_cte_has_parameter_on_dist_key(1); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_has_parameter_on_dist_key(2); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 2) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_has_parameter_on_dist_key(3); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 3) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_has_parameter_on_dist_key(4); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 4) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_has_parameter_on_dist_key(5); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE non_inlined_cte_has_parameter_on_dist_key(6); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 6) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + value | key | other_value | key | other_value +--------------------------------------------------------------------- + test98 | 8 | | 8 | + test98 | 8 | | 8 | + test98 | 8 | | 8 | +(3 rows) + +EXECUTE retry_planning(1); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + json_object_agg +--------------------------------------------------------------------- + { "2" : "test12", "2" : "test2", "2" : "test22", "2" : "test32", "2" : "test42", "2" : "test52", "2" : "test62", "2" : "test72", "2" : "test82", "2" : "test92", "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } +(1 row) + +EXECUTE retry_planning(2); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + json_object_agg +--------------------------------------------------------------------- + { "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } +(1 row) + +EXECUTE retry_planning(3); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + json_object_agg +--------------------------------------------------------------------- + { "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } +(1 row) + +EXECUTE retry_planning(4); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + json_object_agg +--------------------------------------------------------------------- + { "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } +(1 row) + +EXECUTE retry_planning(5); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + json_object_agg +--------------------------------------------------------------------- + { "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } +(1 row) + +EXECUTE retry_planning(6); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + json_object_agg +--------------------------------------------------------------------- + { "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } +(1 row) + +-- this test can only work if the CTE is recursively +-- planned +WITH b AS (SELECT * FROM test_table) +SELECT count(*) FROM (SELECT key as x FROM test_table OFFSET 0) as ref LEFT JOIN b ON (ref.x = b.key); +DEBUG: CTE b is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key AS x FROM cte_inline.test_table OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.x FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) ref LEFT JOIN (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) b ON ((ref.x OPERATOR(pg_catalog.=) b.key))) +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE b: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_2 for subquery SELECT key AS x FROM cte_inline.test_table OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.x FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) ref LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) b ON ((ref.x OPERATOR(pg_catalog.=) b.key))) +DEBUG: Creating router plan + count +--------------------------------------------------------------------- + 4800 +(1 row) + +-- this becomes a non-colocated subquery join +-- because after the CTEs are inlined the joins +-- become a non-colocated subquery join +WITH a AS (SELECT * FROM test_table), +b AS (SELECT * FROM test_table) +SELECT count(*) FROM a LEFT JOIN b ON (a.value = b.value); +DEBUG: CTE a is going to be inlined via distributed planning +DEBUG: CTE b is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) a LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) b ON ((a.value OPERATOR(pg_catalog.=) b.value))) +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 480 +(1 row) + +-- cte a has to be recursively planned because of OFFSET 0 +-- after that, cte b also requires recursive planning +WITH a AS (SELECT * FROM test_table OFFSET 0), +b AS (SELECT * FROM test_table) +SELECT min(a.key) FROM a LEFT JOIN b ON (a.value = b.value); +DEBUG: CTE a is going to be inlined via distributed planning +DEBUG: CTE b is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT min(a.key) AS min FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) a LEFT JOIN (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) b ON ((a.value OPERATOR(pg_catalog.=) b.value))) +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value, other_value FROM cte_inline.test_table OFFSET 0 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_2 for CTE b: SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT min(a.key) AS min FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) a LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) b ON ((a.value OPERATOR(pg_catalog.=) b.value))) +DEBUG: Creating router plan + min +--------------------------------------------------------------------- + 2 +(1 row) + +-- after both CTEs are inlined, this becomes non-colocated subquery join +WITH cte_1 AS (SELECT * FROM test_table), +cte_2 AS (SELECT * FROM test_table) +SELECT * FROM cte_1 JOIN cte_2 ON (cte_1.value > cte_2.value) ORDER BY 1,2,3,4,5,6 DESC LIMIT 3;; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT cte_1.key, cte_1.value, cte_1.other_value, cte_2.key, cte_2.value, cte_2.other_value FROM ((SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON ((cte_1.value OPERATOR(pg_catalog.>) cte_2.value))) ORDER BY cte_1.key, cte_1.value, cte_1.other_value, cte_2.key, cte_2.value, cte_2.other_value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: push down of limit count: 3 + key | value | other_value | key | value | other_value +--------------------------------------------------------------------- + 2 | test2 | {"f1": 2, "f2": 36, "f3": "test2"} | 2 | test12 | + 2 | test2 | {"f1": 2, "f2": 36, "f3": "test2"} | 2 | test12 | + 2 | test2 | {"f1": 2, "f2": 36, "f3": "test2"} | 2 | test12 | +(3 rows) + +-- full join is only supported when both sides are +-- recursively planned +WITH cte_1 AS (SELECT value FROM test_table WHERE key > 1), + cte_2 AS (SELECT value FROM test_table WHERE key > 3) +SELECT * FROM cte_1 FULL JOIN cte_2 USING (value) ORDER BY 1 DESC LIMIT 3;; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 3) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT value FROM ((SELECT test_table.value FROM cte_inline.test_table WHERE (test_table.key OPERATOR(pg_catalog.>) 1)) cte_1 FULL JOIN (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) cte_2 USING (value)) ORDER BY value DESC LIMIT 3 +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 1) +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 3) +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT value FROM ((SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) cte_1 FULL JOIN (SELECT intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(value text)) cte_2 USING (value)) ORDER BY value DESC LIMIT 3 +DEBUG: Creating router plan + value +--------------------------------------------------------------------- + test98 + test98 + test98 +(3 rows) + +-- an unsupported agg. for multi-shard queries +-- so CTE has to be recursively planned +WITH cte_1 AS (SELECT * FROM test_table WHERE key > 1) +SELECT json_object_agg(DISTINCT key, value) FROM cte_1; +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries + json_object_agg +--------------------------------------------------------------------- + { "2" : "test12", "2" : "test2", "2" : "test22", "2" : "test32", "2" : "test42", "2" : "test52", "2" : "test62", "2" : "test72", "2" : "test82", "2" : "test92", "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } +(1 row) + +-- both cte_1 and cte_2 are going to be inlined. +-- later, cte_2 is recursively planned since it doesn't have +-- GROUP BY but aggragate in a subquery. +-- this is an important example of being able to recursively plan +-- "some" of the CTEs +WITH cte_1 AS (SELECT value FROM test_table WHERE key > 1), + cte_2 AS (SELECT max(value) as value FROM test_table WHERE key > 3) +SELECT count(*) FROM cte_1 JOIN cte_2 USING (value); +DEBUG: CTE cte_1 is going to be inlined via distributed planning +DEBUG: CTE cte_2 is going to be inlined via distributed planning +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: generating subplan XXX_1 for subquery SELECT max(value) AS value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 3) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT test_table.value FROM cte_inline.test_table WHERE (test_table.key OPERATOR(pg_catalog.>) 1)) cte_1 JOIN (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) cte_2 USING (value)) +DEBUG: Router planner cannot handle multi-shard select queries + count +--------------------------------------------------------------------- + 4 +(1 row) + +-- prevent DROP CASCADE to give notices +SET client_min_messages TO ERROR; +DROP SCHEMA cte_inline CASCADE; diff --git a/src/test/regress/expected/insert_select_repartition.out b/src/test/regress/expected/insert_select_repartition.out index f6cc3db97..39accdd79 100644 --- a/src/test/regress/expected/insert_select_repartition.out +++ b/src/test/regress/expected/insert_select_repartition.out @@ -1,3 +1,12 @@ +-- +-- INSERT_SELECT_REPARTITION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- -- tests behaviour of INSERT INTO ... SELECT with repartitioning CREATE SCHEMA insert_select_repartition; SET search_path TO 'insert_select_repartition'; @@ -29,10 +38,10 @@ HINT: Ensure the target table's partition column has a corresponding simple col DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213585 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213583_to_0,repartitioned_results_xxxxx_from_4213584_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213586 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213582_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213587 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_2,repartitioned_results_xxxxx_from_4213582_to_2,repartitioned_results_xxxxx_from_4213584_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213588 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213585 AS citus_table_alias (a) SELECT intermediate_result.a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213583_to_0,repartitioned_results_xxxxx_from_4213584_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213586 AS citus_table_alias (a) SELECT intermediate_result.a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213582_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213587 AS citus_table_alias (a) SELECT intermediate_result.a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_2,repartitioned_results_xxxxx_from_4213582_to_2,repartitioned_results_xxxxx_from_4213584_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213588 AS citus_table_alias (a) SELECT intermediate_result.a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) RESET client_min_messages; SELECT * FROM target_table WHERE a=-1 OR a=-3 OR a=-7 ORDER BY a; a @@ -79,8 +88,8 @@ DETAIL: The target table's partition column should correspond to a partition co DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 2 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT intermediate_result.f1, intermediate_result.value, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT intermediate_result.f1, intermediate_result.value, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) RESET client_min_messages; SELECT * FROM target_table ORDER BY key; f1 | value | key @@ -109,8 +118,8 @@ DETAIL: The target table's partition column should correspond to a partition co DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 2 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT intermediate_result.f1, intermediate_result.value, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT intermediate_result.f1, intermediate_result.value, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) RESET client_min_messages; SELECT * FROM target_table ORDER BY key; f1 | value | key @@ -133,8 +142,8 @@ DETAIL: The target table's partition column should correspond to a partition co DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 1 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT intermediate_result.f1, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT intermediate_result.f1, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) RESET client_min_messages; SELECT * FROM target_table ORDER BY key; f1 | value | key @@ -159,8 +168,8 @@ DETAIL: The target table's partition column should correspond to a partition co DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 1 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT intermediate_result.f1, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT intermediate_result.f1, intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 RESET client_min_messages; SELECT * FROM target_table ORDER BY key; f1 | value | key @@ -209,8 +218,8 @@ DETAIL: The data type of the target table's partition column should exactly mat DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'col_1' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213593 AS citus_table_alias (col_1, col_2) SELECT col_1, col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213597_to_0,repartitioned_results_xxxxx_from_4213600_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213594 AS citus_table_alias (col_1, col_2) SELECT col_1, col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213599_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213593 AS citus_table_alias (col_1, col_2) SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213597_to_0,repartitioned_results_xxxxx_from_4213600_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213594 AS citus_table_alias (col_1, col_2) SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213599_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 RESET client_min_messages; SELECT * FROM target_table ORDER BY 1; col_1 | col_2 @@ -474,7 +483,7 @@ WITH c AS ( SELECT mapped_key, c FROM source_table RETURNING *) SELECT * FROM c ORDER by a; -DEBUG: generating subplan XXX_1 for CTE c: INSERT INTO insert_select_repartition.target_table (a, b) SELECT mapped_key, c FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b +DEBUG: generating subplan XXX_1 for CTE c: INSERT INTO insert_select_repartition.target_table (a, b) SELECT source_table.mapped_key, source_table.c FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT a, b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer[])) c ORDER BY a DEBUG: performing repartitioned INSERT ... SELECT @@ -583,9 +592,9 @@ DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1,repartitioned_results_xxxxx_from_4213609_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_2,repartitioned_results_xxxxx_from_4213607_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1,repartitioned_results_xxxxx_from_4213609_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_2,repartitioned_results_xxxxx_from_4213607_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RESET client_min_messages; SELECT * FROM target_table ORDER BY a; a | b @@ -748,7 +757,7 @@ WITH r AS ( INSERT INTO target_table SELECT source_table.a, max(source_table.b) FROM source_table NATURAL JOIN r GROUP BY source_table.a; DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT DEBUG: only SELECT, UPDATE, or DELETE common table expressions may be router planned -DEBUG: generating subplan XXX_1 for CTE r: INSERT INTO insert_select_repartition.target_table (a, b) SELECT a, b FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b +DEBUG: generating subplan XXX_1 for CTE r: INSERT INTO insert_select_repartition.target_table (a, b) SELECT source_table.a, source_table.b FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT DEBUG: Router planner cannot handle multi-shard select queries DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT a, max AS b FROM (SELECT source_table.a, max(source_table.b) AS max FROM (insert_select_repartition.source_table JOIN (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) r USING (a, b)) GROUP BY source_table.a) citus_insert_select_subquery @@ -756,13 +765,13 @@ DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RESET client_min_messages; SELECT * FROM target_table ORDER BY a, b; a | b @@ -892,7 +901,7 @@ DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213617 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213613_to_0,repartitioned_results_xxxxx_from_4213614_to_0,repartitioned_results_xxxxx_from_4213615_to_0,repartitioned_results_xxxxx_from_4213616_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213617 AS citus_table_alias (a, b) SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213613_to_0,repartitioned_results_xxxxx_from_4213614_to_0,repartitioned_results_xxxxx_from_4213615_to_0,repartitioned_results_xxxxx_from_4213616_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RESET client_min_messages; SELECT * FROM target_table ORDER BY a, b; a | b @@ -1003,9 +1012,9 @@ DEBUG: INSERT target table and the source relation of the SELECT partition colu DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213633 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213629_to_0,repartitioned_results_xxxxx_from_4213630_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213634 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213630_to_1,repartitioned_results_xxxxx_from_4213631_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213635 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213632_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213633 AS citus_table_alias (a, b, c, d) SELECT intermediate_result.a, intermediate_result.b, intermediate_result.c, intermediate_result.d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213629_to_0,repartitioned_results_xxxxx_from_4213630_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213634 AS citus_table_alias (a, b, c, d) SELECT intermediate_result.a, intermediate_result.b, intermediate_result.c, intermediate_result.d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213630_to_1,repartitioned_results_xxxxx_from_4213631_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213635 AS citus_table_alias (a, b, c, d) SELECT intermediate_result.a, intermediate_result.b, intermediate_result.c, intermediate_result.d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213632_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) RESET client_min_messages; SELECT count(*) FROM target_table; count @@ -1207,8 +1216,8 @@ DEBUG: INSERT target table and the source relation of the SELECT partition colu DEBUG: Router planner cannot handle multi-shard select queries DEBUG: performing repartitioned INSERT ... SELECT DEBUG: partitioning SELECT query by column index 0 with name 'c1' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213639 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT c1, c2, c3, c4, c5, c6, cardinality, sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213644_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213641 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT c1, c2, c3, c4, c5, c6, cardinality, sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213645_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213639 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT intermediate_result.c1, intermediate_result.c2, intermediate_result.c3, intermediate_result.c4, intermediate_result.c5, intermediate_result.c6, intermediate_result.cardinality, intermediate_result.sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213644_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213641 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT intermediate_result.c1, intermediate_result.c2, intermediate_result.c3, intermediate_result.c4, intermediate_result.c5, intermediate_result.c6, intermediate_result.cardinality, intermediate_result.sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213645_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) RESET client_min_messages; EXPLAIN (COSTS OFF) INSERT INTO target_table AS enriched(c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT c1, c2, c3, c4, -1::float AS c5, diff --git a/src/test/regress/expected/insert_select_repartition_0.out b/src/test/regress/expected/insert_select_repartition_0.out new file mode 100644 index 000000000..eff0df02e --- /dev/null +++ b/src/test/regress/expected/insert_select_repartition_0.out @@ -0,0 +1,1304 @@ +-- +-- INSERT_SELECT_REPARTITION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +-- tests behaviour of INSERT INTO ... SELECT with repartitioning +CREATE SCHEMA insert_select_repartition; +SET search_path TO 'insert_select_repartition'; +SET citus.next_shard_id TO 4213581; +SET citus.shard_replication_factor TO 1; +-- 4 shards, hash distributed. +-- Negate distribution column value. +SET citus.shard_count TO 4; +CREATE TABLE source_table(a int); +SELECT create_distributed_table('source_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table SELECT * FROM generate_series(1, 10); +CREATE TABLE target_table(a int); +SELECT create_distributed_table('target_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SET client_min_messages TO DEBUG2; +INSERT INTO target_table SELECT -a FROM source_table; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DETAIL: Subquery contains an operator in the same position as the target table's partition column. +HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'a' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213585 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213583_to_0,repartitioned_results_xxxxx_from_4213584_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213586 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213582_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213587 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_2,repartitioned_results_xxxxx_from_4213582_to_2,repartitioned_results_xxxxx_from_4213584_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213588 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) +RESET client_min_messages; +SELECT * FROM target_table WHERE a=-1 OR a=-3 OR a=-7 ORDER BY a; + a +--------------------------------------------------------------------- + -7 + -3 + -1 +(3 rows) + +DROP TABLE source_table, target_table; +-- +-- range partitioning, composite distribution column +-- +CREATE TYPE composite_key_type AS (f1 int, f2 text); +-- source +CREATE TABLE source_table(f1 int, key composite_key_type, value int, mapped_key composite_key_type); +SELECT create_distributed_table('source_table', 'key', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CALL public.create_range_partitioned_shards('source_table', '{"(0,a)","(25,a)"}','{"(24,z)","(49,z)"}'); +INSERT INTO source_table VALUES (0, (0, 'a'), 1, (0, 'a')); +INSERT INTO source_table VALUES (1, (1, 'b'), 2, (26, 'b')); +INSERT INTO source_table VALUES (2, (2, 'c'), 3, (3, 'c')); +INSERT INTO source_table VALUES (3, (4, 'd'), 4, (27, 'd')); +INSERT INTO source_table VALUES (4, (30, 'e'), 5, (30, 'e')); +INSERT INTO source_table VALUES (5, (31, 'f'), 6, (31, 'f')); +INSERT INTO source_table VALUES (6, (32, 'g'), 50, (8, 'g')); +-- target +CREATE TABLE target_table(f1 int DEFAULT 0, value int, key composite_key_type PRIMARY KEY); +SELECT create_distributed_table('target_table', 'key', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CALL public.create_range_partitioned_shards('target_table', '{"(0,a)","(25,a)"}','{"(24,z)","(49,z)"}'); +SET client_min_messages TO DEBUG2; +INSERT INTO target_table SELECT f1, value, mapped_key FROM source_table; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DETAIL: The target table's partition column should correspond to a partition column in the subquery. +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 2 with name 'key' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +RESET client_min_messages; +SELECT * FROM target_table ORDER BY key; + f1 | value | key +--------------------------------------------------------------------- + 0 | 1 | (0,a) + 2 | 3 | (3,c) + 6 | 50 | (8,g) + 1 | 2 | (26,b) + 3 | 4 | (27,d) + 4 | 5 | (30,e) + 5 | 6 | (31,f) +(7 rows) + +SELECT * FROM target_table WHERE key = (26, 'b')::composite_key_type; + f1 | value | key +--------------------------------------------------------------------- + 1 | 2 | (26,b) +(1 row) + +-- with explicit column names +TRUNCATE target_table; +SET client_min_messages TO DEBUG2; +INSERT INTO target_table(value, key) SELECT value, mapped_key FROM source_table; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DETAIL: The target table's partition column should correspond to a partition column in the subquery. +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 2 with name 'key' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) +RESET client_min_messages; +SELECT * FROM target_table ORDER BY key; + f1 | value | key +--------------------------------------------------------------------- + 0 | 1 | (0,a) + 0 | 3 | (3,c) + 0 | 50 | (8,g) + 0 | 2 | (26,b) + 0 | 4 | (27,d) + 0 | 5 | (30,e) + 0 | 6 | (31,f) +(7 rows) + +-- missing value for a column +TRUNCATE target_table; +SET client_min_messages TO DEBUG2; +INSERT INTO target_table(key) SELECT mapped_key AS key_renamed FROM source_table; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DETAIL: The target table's partition column should correspond to a partition column in the subquery. +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 1 with name 'key' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) +RESET client_min_messages; +SELECT * FROM target_table ORDER BY key; + f1 | value | key +--------------------------------------------------------------------- + 0 | | (0,a) + 0 | | (3,c) + 0 | | (8,g) + 0 | | (26,b) + 0 | | (27,d) + 0 | | (30,e) + 0 | | (31,f) +(7 rows) + +-- ON CONFLICT +SET client_min_messages TO DEBUG2; +INSERT INTO target_table(key) +SELECT mapped_key AS key_renamed FROM source_table +WHERE (mapped_key).f1 % 2 = 1 +ON CONFLICT (key) DO UPDATE SET f1=1; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DETAIL: The target table's partition column should correspond to a partition column in the subquery. +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 1 with name 'key' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 +RESET client_min_messages; +SELECT * FROM target_table ORDER BY key; + f1 | value | key +--------------------------------------------------------------------- + 0 | | (0,a) + 1 | | (3,c) + 0 | | (8,g) + 0 | | (26,b) + 1 | | (27,d) + 0 | | (30,e) + 1 | | (31,f) +(7 rows) + +-- missing value for distribution column +INSERT INTO target_table(value) SELECT value FROM source_table; +ERROR: the partition column of table insert_select_repartition.target_table should have a value +DROP TABLE source_table, target_table; +-- different column types +-- verifies that we add necessary casts, otherwise even shard routing won't +-- work correctly and we will see 2 values for the same primary key. +CREATE TABLE target_table(col_1 int primary key, col_2 int); +SELECT create_distributed_table('target_table','col_1'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO target_table VALUES (1,2), (2,3), (3,4), (4,5), (5,6); +CREATE TABLE source_table(col_1 numeric, col_2 numeric, col_3 numeric); +SELECT create_distributed_table('source_table','col_1'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table VALUES (1,1,1), (3,3,3), (5,5,5); +SET client_min_messages TO DEBUG2; +INSERT INTO target_table +SELECT + col_1, col_2 +FROM + source_table +ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DETAIL: The data type of the target table's partition column should exactly match the data type of the corresponding simple column reference in the subquery. +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'col_1' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213593 AS citus_table_alias (col_1, col_2) SELECT col_1, col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213597_to_0,repartitioned_results_xxxxx_from_4213600_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213594 AS citus_table_alias (col_1, col_2) SELECT col_1, col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213599_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 +RESET client_min_messages; +SELECT * FROM target_table ORDER BY 1; + col_1 | col_2 +--------------------------------------------------------------------- + 1 | 1 + 2 | 3 + 3 | 3 + 4 | 5 + 5 | 5 +(5 rows) + +DROP TABLE source_table, target_table; +-- +-- array coercion +-- +SET citus.shard_count TO 3; +CREATE TABLE source_table(a int, mapped_key int, c float[]); +SELECT create_distributed_table('source_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table VALUES (1, -1, ARRAY[1.1, 2.2, 3.3]), (2, -2, ARRAY[4.5, 5.8]), + (3, -3, ARRAY[]::float[]), (4, -4, ARRAY[3.3]); +SET citus.shard_count TO 2; +CREATE TABLE target_table(a int, b int[]); +SELECT create_distributed_table('target_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SET client_min_messages TO DEBUG1; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DETAIL: The target table's partition column should correspond to a partition column in the subquery. +DEBUG: performing repartitioned INSERT ... SELECT +RESET client_min_messages; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +-- +-- worker queries can have more columns than necessary. ExpandWorkerTargetEntry() +-- might add additional columns to the target list. +-- +TRUNCATE target_table; +\set VERBOSITY TERSE +-- first verify that the SELECT query below fetches 3 projected columns from workers +SET citus.log_remote_commands TO true; SET client_min_messages TO DEBUG; + CREATE TABLE results AS SELECT max(-a), array_agg(mapped_key) FROM source_table GROUP BY a; +DEBUG: Router planner cannot handle multi-shard select queries +NOTICE: issuing SELECT max((OPERATOR(pg_catalog.-) a)) AS max, array_agg(mapped_key) AS array_agg, a AS worker_column_3 FROM insert_select_repartition.source_table_4213601 source_table WHERE true GROUP BY a +NOTICE: issuing SELECT max((OPERATOR(pg_catalog.-) a)) AS max, array_agg(mapped_key) AS array_agg, a AS worker_column_3 FROM insert_select_repartition.source_table_4213602 source_table WHERE true GROUP BY a +NOTICE: issuing SELECT max((OPERATOR(pg_catalog.-) a)) AS max, array_agg(mapped_key) AS array_agg, a AS worker_column_3 FROM insert_select_repartition.source_table_4213603 source_table WHERE true GROUP BY a +RESET citus.log_remote_commands; RESET client_min_messages; +DROP TABLE results; +-- now verify that we don't write the extra columns to the intermediate result files and +-- insertion to the target works fine. +SET client_min_messages TO DEBUG1; +INSERT INTO target_table SELECT max(-a), array_agg(mapped_key) FROM source_table GROUP BY a; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DEBUG: performing repartitioned INSERT ... SELECT +RESET client_min_messages; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {-4} + -3 | {-3} + -2 | {-2} + -1 | {-1} +(4 rows) + +-- +-- repartitioned INSERT/SELECT followed/preceded by other DML in same transaction +-- +-- case 1. followed by DELETE +TRUNCATE target_table; +BEGIN; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +DELETE FROM target_table; +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- +(0 rows) + +-- case 2. followed by UPDATE +TRUNCATE target_table; +BEGIN; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +UPDATE target_table SET b=array_append(b, a); +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3,-4} + -3 | {-3} + -2 | {4,6,-2} + -1 | {1,2,3,-1} +(4 rows) + +-- case 3. followed by multi-row INSERT +TRUNCATE target_table; +BEGIN; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +INSERT INTO target_table VALUES (-5, ARRAY[10,11]), (-6, ARRAY[11,12]), (-7, ARRAY[999]); +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -7 | {999} + -6 | {11,12} + -5 | {10,11} + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(7 rows) + +-- case 4. followed by distributed INSERT/SELECT +TRUNCATE target_table; +BEGIN; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +INSERT INTO target_table SELECT * FROM target_table; +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -4 | {3} + -3 | {} + -3 | {} + -2 | {4,6} + -2 | {4,6} + -1 | {1,2,3} + -1 | {1,2,3} +(8 rows) + +-- case 5. preceded by DELETE +TRUNCATE target_table; +BEGIN; +DELETE FROM target_table; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +-- case 6. preceded by UPDATE +TRUNCATE target_table; +BEGIN; +UPDATE target_table SET b=array_append(b, a); +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +-- case 7. preceded by multi-row INSERT +TRUNCATE target_table; +BEGIN; +INSERT INTO target_table VALUES (-5, ARRAY[10,11]), (-6, ARRAY[11,12]), (-7, ARRAY[999]); +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -7 | {999} + -6 | {11,12} + -5 | {10,11} + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(7 rows) + +-- case 8. preceded by distributed INSERT/SELECT +TRUNCATE target_table; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +BEGIN; +INSERT INTO target_table SELECT * FROM target_table; +INSERT INTO target_table SELECT mapped_key, c FROM source_table; +END; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -4 | {3} + -4 | {3} + -3 | {} + -3 | {} + -3 | {} + -2 | {4,6} + -2 | {4,6} + -2 | {4,6} + -1 | {1,2,3} + -1 | {1,2,3} + -1 | {1,2,3} +(12 rows) + +-- +-- repartitioned INSERT/SELECT with RETURNING +-- +TRUNCATE target_table; +SET client_min_messages TO DEBUG1; +WITH c AS ( + INSERT INTO target_table + SELECT mapped_key, c FROM source_table + RETURNING *) +SELECT * FROM c ORDER by a; +DEBUG: generating subplan XXX_1 for CTE c: INSERT INTO insert_select_repartition.target_table (a, b) SELECT mapped_key, c FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT a, b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer[])) c ORDER BY a +DEBUG: performing repartitioned INSERT ... SELECT + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +RESET client_min_messages; +-- +-- in combination with CTEs +-- +TRUNCATE target_table; +SET client_min_messages TO DEBUG1; +WITH t AS ( + SELECT mapped_key, a, c FROM source_table + WHERE a > floor(random()) +) +INSERT INTO target_table +SELECT mapped_key, c FROM t NATURAL JOIN source_table; +DEBUG: volatile functions are not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for CTE t: SELECT mapped_key, a, c FROM insert_select_repartition.source_table WHERE ((a)::double precision OPERATOR(pg_catalog.>) floor(random())) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT mapped_key AS a, auto_coerced_by_citus_1 AS b FROM (SELECT t.mapped_key, (t.c)::integer[] AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.mapped_key, intermediate_result.a, intermediate_result.c FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(mapped_key integer, a integer, c double precision[])) t JOIN insert_select_repartition.source_table USING (mapped_key, a, c))) citus_insert_select_subquery +DEBUG: performing repartitioned INSERT ... SELECT +RESET client_min_messages; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + -4 | {3} + -3 | {} + -2 | {4,6} + -1 | {1,2,3} +(4 rows) + +DROP TABLE source_table, target_table; +-- +-- The case where select query has a GROUP BY ... +-- +SET citus.shard_count TO 4; +CREATE TABLE source_table(a int, b int); +SELECT create_distributed_table('source_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SET citus.shard_count TO 3; +CREATE TABLE target_table(a int, b int); +SELECT create_distributed_table('target_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table SELECT floor(i/4), i*i FROM generate_series(1, 20) i; +SET client_min_messages TO DEBUG1; +INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +RESET client_min_messages; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + 0 | 9 + 1 | 49 + 2 | 121 + 3 | 225 + 4 | 361 + 5 | 400 +(6 rows) + +-- +-- EXPLAIN output should specify repartitioned INSERT/SELECT +-- +EXPLAIN INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) (cost=0.00..0.00 rows=0 width=0) + INSERT/SELECT method: repartition + -> Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=100000 width=8) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> HashAggregate (cost=43.90..45.90 rows=200 width=8) + Group Key: a + -> Seq Scan on source_table_4213606 source_table (cost=0.00..32.60 rows=2260 width=8) +(10 rows) + +-- +-- EXPLAIN ANALYZE is currently not supported +-- +EXPLAIN ANALYZE INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; +ERROR: EXPLAIN ANALYZE is currently not supported for INSERT ... SELECT commands with repartitioning +-- +-- Duplicate names in target list +-- +TRUNCATE target_table; +SET client_min_messages TO DEBUG2; +INSERT INTO target_table + SELECT max(b), max(b) FROM source_table GROUP BY a; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'a' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1,repartitioned_results_xxxxx_from_4213609_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_2,repartitioned_results_xxxxx_from_4213607_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +RESET client_min_messages; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + 9 | 9 + 49 | 49 + 121 | 121 + 225 | 225 + 361 | 361 + 400 | 400 +(6 rows) + +-- +-- Prepared INSERT/SELECT +-- +TRUNCATE target_table; +PREPARE insert_plan(int, int) AS +INSERT INTO target_table + SELECT a, max(b) FROM source_table + WHERE a BETWEEN $1 AND $2 GROUP BY a; +SET client_min_messages TO DEBUG1; +EXECUTE insert_plan(0, 2); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(0, 2); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(0, 2); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(0, 2); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(0, 2); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(0, 2); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(2, 4); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(2, 4); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(2, 4); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(2, 4); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(2, 4); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan(2, 4); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +RESET client_min_messages; +SELECT a, count(*), count(distinct b) distinct_values FROM target_table GROUP BY a ORDER BY a; + a | count | distinct_values +--------------------------------------------------------------------- + 0 | 6 | 1 + 1 | 6 | 1 + 2 | 12 | 1 + 3 | 6 | 1 + 4 | 6 | 1 +(5 rows) + +DEALLOCATE insert_plan; +-- +-- Prepared router INSERT/SELECT. We currently use pull to coordinator when the +-- distributed query has a single task. +-- +TRUNCATE target_table; +PREPARE insert_plan(int) AS +INSERT INTO target_table + SELECT a, max(b) FROM source_table + WHERE a=$1 GROUP BY a; +SET client_min_messages TO DEBUG1; +EXECUTE insert_plan(0); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Collecting INSERT ... SELECT results on coordinator +EXECUTE insert_plan(0); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Collecting INSERT ... SELECT results on coordinator +EXECUTE insert_plan(0); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Collecting INSERT ... SELECT results on coordinator +EXECUTE insert_plan(0); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Collecting INSERT ... SELECT results on coordinator +EXECUTE insert_plan(0); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Collecting INSERT ... SELECT results on coordinator +EXECUTE insert_plan(0); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Collecting INSERT ... SELECT results on coordinator +EXECUTE insert_plan(0); +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Collecting INSERT ... SELECT results on coordinator +RESET client_min_messages; +SELECT a, count(*), count(distinct b) distinct_values FROM target_table GROUP BY a ORDER BY a; + a | count | distinct_values +--------------------------------------------------------------------- + 0 | 7 | 1 +(1 row) + +DEALLOCATE insert_plan; +-- +-- Prepared INSERT/SELECT with no parameters. +-- +TRUNCATE target_table; +PREPARE insert_plan AS +INSERT INTO target_table + SELECT a, max(b) FROM source_table + WHERE a BETWEEN 1 AND 2 GROUP BY a; +SELECT public.coordinator_plan($Q$ +EXPLAIN EXECUTE insert_plan; +$Q$); + coordinator_plan +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) (cost=0.00..0.00 rows=0 width=0) + INSERT/SELECT method: repartition + -> Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=100000 width=8) + Task Count: 4 +(4 rows) + +SET client_min_messages TO DEBUG1; +EXECUTE insert_plan; +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan; +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan; +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan; +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan; +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan; +DEBUG: performing repartitioned INSERT ... SELECT +EXECUTE insert_plan; +DEBUG: performing repartitioned INSERT ... SELECT +RESET client_min_messages; +SELECT a, count(*), count(distinct b) distinct_values FROM target_table GROUP BY a ORDER BY a; + a | count | distinct_values +--------------------------------------------------------------------- + 1 | 7 | 1 + 2 | 7 | 1 +(2 rows) + +DEALLOCATE insert_plan; +-- +-- INSERT/SELECT in CTE +-- +TRUNCATE target_table; +SET client_min_messages TO DEBUG2; +WITH r AS ( + INSERT INTO target_table SELECT * FROM source_table RETURNING * +) +INSERT INTO target_table SELECT source_table.a, max(source_table.b) FROM source_table NATURAL JOIN r GROUP BY source_table.a; +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: only SELECT, UPDATE, or DELETE common table expressions may be router planned +DEBUG: generating subplan XXX_1 for CTE r: INSERT INTO insert_select_repartition.target_table (a, b) SELECT a, b FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT a, max AS b FROM (SELECT source_table.a, max(source_table.b) AS max FROM (insert_select_repartition.source_table JOIN (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) r USING (a, b)) GROUP BY source_table.a) citus_insert_select_subquery +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'a' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b +DEBUG: partitioning SELECT query by column index 0 with name 'a' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +RESET client_min_messages; +SELECT * FROM target_table ORDER BY a, b; + a | b +--------------------------------------------------------------------- + 0 | 1 + 0 | 4 + 0 | 9 + 0 | 9 + 1 | 16 + 1 | 25 + 1 | 36 + 1 | 49 + 1 | 49 + 2 | 64 + 2 | 81 + 2 | 100 + 2 | 121 + 2 | 121 + 3 | 144 + 3 | 169 + 3 | 196 + 3 | 225 + 3 | 225 + 4 | 256 + 4 | 289 + 4 | 324 + 4 | 361 + 4 | 361 + 5 | 400 + 5 | 400 +(26 rows) + +DROP TABLE source_table, target_table; +-- +-- Constraint failure and rollback +-- +SET citus.shard_count TO 4; +CREATE TABLE source_table(a int, b int); +SELECT create_distributed_table('source_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table SELECT i, i * i FROM generate_series(1, 10) i; +UPDATE source_table SET b = NULL where b IN (9, 4); +SET citus.shard_replication_factor TO 2; +CREATE TABLE target_table(a int, b int not null); +SELECT create_distributed_table('target_table', 'a', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CALL public.create_range_partitioned_shards('target_table', '{0,3,6,9}','{2,5,8,50}'); +INSERT INTO target_table VALUES (11,9), (22,4); +EXPLAIN (costs off) INSERT INTO target_table SELECT * FROM source_table; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: repartition + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on source_table_4213613 source_table +(8 rows) + +EXPLAIN (costs off) INSERT INTO target_table SELECT * FROM source_table WHERE b IS NOT NULL; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: repartition + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on source_table_4213613 source_table + Filter: (b IS NOT NULL) +(9 rows) + +BEGIN; +SAVEPOINT s1; +INSERT INTO target_table SELECT * FROM source_table; +ERROR: null value in column "b" violates not-null constraint +ROLLBACK TO SAVEPOINT s1; +INSERT INTO target_table SELECT * FROM source_table WHERE b IS NOT NULL; +END; +SELECT * FROM target_table ORDER BY b; + a | b +--------------------------------------------------------------------- + 1 | 1 + 22 | 4 + 11 | 9 + 4 | 16 + 5 | 25 + 6 | 36 + 7 | 49 + 8 | 64 + 9 | 81 + 10 | 100 +(10 rows) + +-- verify that values have been replicated to both replicas +SELECT * FROM run_command_on_placements('target_table', 'select count(*) from %s') ORDER BY shardid, nodeport; + nodename | nodeport | shardid | success | result +--------------------------------------------------------------------- + localhost | 57637 | 4213617 | t | 1 + localhost | 57638 | 4213617 | t | 1 + localhost | 57637 | 4213618 | t | 2 + localhost | 57638 | 4213618 | t | 2 + localhost | 57637 | 4213619 | t | 3 + localhost | 57638 | 4213619 | t | 3 + localhost | 57637 | 4213620 | t | 4 + localhost | 57638 | 4213620 | t | 4 +(8 rows) + +-- +-- Multiple casts in the SELECT query +-- +TRUNCATE target_table; +SET client_min_messages TO DEBUG2; +INSERT INTO target_table SELECT 1.12, b::bigint FROM source_table WHERE b IS NOT NULL; +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'a' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213617 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213613_to_0,repartitioned_results_xxxxx_from_4213614_to_0,repartitioned_results_xxxxx_from_4213615_to_0,repartitioned_results_xxxxx_from_4213616_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) +RESET client_min_messages; +SELECT * FROM target_table ORDER BY a, b; + a | b +--------------------------------------------------------------------- + 1 | 1 + 1 | 16 + 1 | 25 + 1 | 36 + 1 | 49 + 1 | 64 + 1 | 81 + 1 | 100 +(8 rows) + +-- +-- ROLLBACK after out of range error +-- +TRUNCATE target_table; +BEGIN; +INSERT INTO target_table SELECT a * 10, b FROM source_table WHERE b IS NOT NULL; +ERROR: could not find shard for partition column value +END; +SELECT max(result) FROM run_command_on_placements('target_table', 'select count(*) from %s'); + max +--------------------------------------------------------------------- + 0 +(1 row) + +DROP TABLE source_table, target_table; +-- +-- Range partitioned target's ranges doesn't cover the whole range +-- +SET citus.shard_replication_factor TO 2; +SET citus.shard_count TO 4; +CREATE TABLE source_table(a int, b int); +SELECT create_distributed_table('source_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table SELECT i, i * i FROM generate_series(1, 10) i; +SET citus.shard_replication_factor TO 2; +CREATE TABLE target_table(b int not null, a float); +SELECT create_distributed_table('target_table', 'a', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CALL public.create_range_partitioned_shards('target_table', '{0.0,3.5,6.5,9.5}','{2.9,5.9,8.9,50.0}'); +INSERT INTO target_table SELECT b, a+0.6 FROM source_table; +SELECT * FROM target_table ORDER BY a; + b | a +--------------------------------------------------------------------- + 1 | 1.6 + 4 | 2.6 + 9 | 3.6 + 16 | 4.6 + 25 | 5.6 + 36 | 6.6 + 49 | 7.6 + 64 | 8.6 + 81 | 9.6 + 100 | 10.6 +(10 rows) + +-- verify that values have been replicated to both replicas, and that each +-- replica has received correct number of rows +SELECT * FROM run_command_on_placements('target_table', 'select count(*) from %s') ORDER BY shardid, nodeport; + nodename | nodeport | shardid | success | result +--------------------------------------------------------------------- + localhost | 57637 | 4213625 | t | 2 + localhost | 57638 | 4213625 | t | 2 + localhost | 57637 | 4213626 | t | 3 + localhost | 57638 | 4213626 | t | 3 + localhost | 57637 | 4213627 | t | 3 + localhost | 57638 | 4213627 | t | 3 + localhost | 57637 | 4213628 | t | 2 + localhost | 57638 | 4213628 | t | 2 +(8 rows) + +DROP TABLE source_table, target_table; +-- +-- Select column names should be unique +-- +SET citus.shard_replication_factor TO 1; +SET citus.shard_count TO 4; +CREATE TABLE source_table(a int, b int); +SELECT create_distributed_table('source_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SET citus.shard_count TO 3; +CREATE TABLE target_table(a int, b int, c int, d int, e int, f int); +SELECT create_distributed_table('target_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table SELECT i, i * i FROM generate_series(1, 10) i; +SET client_min_messages TO DEBUG2; +INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'a' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213633 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213629_to_0,repartitioned_results_xxxxx_from_4213630_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213634 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213630_to_1,repartitioned_results_xxxxx_from_4213631_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213635 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213632_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) +RESET client_min_messages; +SELECT count(*) FROM target_table; + count +--------------------------------------------------------------------- + 10 +(1 row) + +-- +-- Disable repartitioned insert/select +-- +TRUNCATE target_table; +SET citus.enable_repartitioned_insert_select TO OFF; +EXPLAIN (costs off) INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on source_table_4213629 source_table +(8 rows) + +SET client_min_messages TO DEBUG2; +INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Collecting INSERT ... SELECT results on coordinator +RESET client_min_messages; +SELECT count(*) FROM target_table; + count +--------------------------------------------------------------------- + 10 +(1 row) + +SET citus.enable_repartitioned_insert_select TO ON; +EXPLAIN (costs off) INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: repartition + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on source_table_4213629 source_table +(8 rows) + +DROP TABLE source_table, target_table; +-- +-- Don't use INSERT/SELECT repartition with repartition joins +-- +create table test(x int, y int); +select create_distributed_table('test', 'x'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +set citus.enable_repartition_joins to true; +INSERT INTO test SELECT i, i FROM generate_series(1, 10) i; +EXPLAIN (costs off) INSERT INTO test(y, x) SELECT a.x, b.y FROM test a JOIN test b USING (y); + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: None, not supported for re-partition queries + -> MapMergeJob + Map Task Count: 3 + Merge Task Count: 4 + -> MapMergeJob + Map Task Count: 3 + Merge Task Count: 4 +(11 rows) + +SET client_min_messages TO DEBUG1; +INSERT INTO test(y, x) SELECT a.x, b.y FROM test a JOIN test b USING (y); +DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match +DEBUG: Collecting INSERT ... SELECT results on coordinator +RESET client_min_messages; +SELECT count(*) FROM test; + count +--------------------------------------------------------------------- + 20 +(1 row) + +TRUNCATE test; +INSERT INTO test SELECT i, i FROM generate_series(1, 10) i; +EXPLAIN (costs off) INSERT INTO test SELECT a.* FROM test a JOIN test b USING (y); + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: None, not supported for re-partition queries + -> MapMergeJob + Map Task Count: 3 + Merge Task Count: 4 + -> MapMergeJob + Map Task Count: 3 + Merge Task Count: 4 +(11 rows) + +SET client_min_messages TO DEBUG1; +INSERT INTO test SELECT a.* FROM test a JOIN test b USING (y); +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: Collecting INSERT ... SELECT results on coordinator +RESET client_min_messages; +SELECT count(*) FROM test; + count +--------------------------------------------------------------------- + 20 +(1 row) + +-- +-- In the following case we coerce some columns and move uncoerced versions to the +-- end of SELECT list. The following case verifies that we rename those columns so +-- we don't get "column reference is ambiguous" errors. +-- +CREATE TABLE target_table( + c1 int, + c2 int, + c3 timestamp, + a int, + b int, + c int, + c4 int, + c5 int, + c6 int[], + cardinality int, + sum int, + PRIMARY KEY (c1, c2, c3, c4, c5, c6) +); +SET citus.shard_count TO 5; +SELECT create_distributed_table('target_table', 'c1'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE source_table( + c1 int, + c2 int, + c3 date, + c4 int, + cardinality int, + sum int +); +SET citus.shard_count TO 4; +SELECT create_distributed_table('source_table', 'c1'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE OR REPLACE FUNCTION dist_func(a int, b int) RETURNS int[] +AS $$ +BEGIN + RETURN array_fill(a, ARRAY[b]); +END; +$$ +LANGUAGE plpgsql STABLE; +SELECT create_distributed_function('dist_func(int, int)'); +NOTICE: procedure insert_select_repartition.dist_func is already distributed + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SET client_min_messages TO DEBUG; +SET citus.enable_unique_job_ids TO off; +INSERT INTO source_table VALUES (1,2, '2020-02-02', 3, 4, 5); +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 +INSERT INTO source_table VALUES (1,2, '2020-02-02', 3, 4, 5); +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 +INSERT INTO source_table VALUES (3,4, '2020-02-02', 3, 4, 5); +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 3 +INSERT INTO target_table AS enriched(c1, c2, c3, c4, c5, c6, cardinality, sum) +SELECT c1, c2, c3, c4, -1::float AS c5, + dist_func(c1, 4) c6, + sum(cardinality), + sum(sum) +FROM source_table +GROUP BY c1, c2, c3, c4, c5, c6 +ON CONFLICT(c1, c2, c3, c4, c5, c6) +DO UPDATE SET + cardinality = enriched.cardinality + excluded.cardinality, + sum = enriched.sum + excluded.sum; +DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT +DEBUG: Router planner cannot handle multi-shard select queries +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: partitioning SELECT query by column index 0 with name 'c1' +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213639 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT c1, c2, c3, c4, c5, c6, cardinality, sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213644_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) +DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213641 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT c1, c2, c3, c4, c5, c6, cardinality, sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213645_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) +RESET client_min_messages; +EXPLAIN (COSTS OFF) INSERT INTO target_table AS enriched(c1, c2, c3, c4, c5, c6, cardinality, sum) +SELECT c1, c2, c3, c4, -1::float AS c5, + dist_func(c1, 4) c6, + sum(cardinality), + sum(sum) +FROM source_table +GROUP BY c1, c2, c3, c4, c5, c6 +ON CONFLICT(c1, c2, c3, c4, c5, c6) +DO UPDATE SET + cardinality = enriched.cardinality + excluded.cardinality, + sum = enriched.sum + excluded.sum; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: repartition + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> HashAggregate + Group Key: c1, c2, c3, c4, '-1'::double precision, insert_select_repartition.dist_func(c1, 4) + -> Seq Scan on source_table_4213644 source_table +(10 rows) + +-- verify that we don't report repartitioned insert/select for tables +-- with sequences. See https://github.com/citusdata/citus/issues/3936 +create table table_with_sequences (x int, y int, z bigserial); +insert into table_with_sequences values (1,1); +select create_distributed_table('table_with_sequences','x'); +NOTICE: Copying data from local table... +NOTICE: copying the data has completed + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT public.plan_without_result_lines($Q$ +explain (costs off) insert into table_with_sequences select y, x from table_with_sequences; +$Q$); + plan_without_result_lines +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on table_with_sequences_4213648 table_with_sequences +(8 rows) + +-- verify that we don't report repartitioned insert/select for tables +-- with user-defined sequences. +CREATE SEQUENCE user_defined_sequence; +create table table_with_user_sequences (x int, y int, z bigint default nextval('user_defined_sequence')); +insert into table_with_user_sequences values (1,1); +select create_distributed_table('table_with_user_sequences','x'); +NOTICE: Copying data from local table... +NOTICE: copying the data has completed + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT public.plan_without_result_lines($Q$ +explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences; +$Q$); + plan_without_result_lines +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on table_with_user_sequences_4213652 table_with_user_sequences +(8 rows) + +-- clean-up +SET client_min_messages TO WARNING; +DROP SCHEMA insert_select_repartition CASCADE; diff --git a/src/test/regress/expected/intermediate_result_pruning.out b/src/test/regress/expected/intermediate_result_pruning.out index 2670c48a6..593253140 100644 --- a/src/test/regress/expected/intermediate_result_pruning.out +++ b/src/test/regress/expected/intermediate_result_pruning.out @@ -1,3 +1,12 @@ +-- +-- INTERMEDIATE_RESULT_PRUNING +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA intermediate_result_pruning; SET search_path TO intermediate_result_pruning; SET citus.log_intermediate_results TO TRUE; @@ -1039,7 +1048,7 @@ inserts AS MATERIALIZED ( RETURNING * ) SELECT count(*) FROM inserts; DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM intermediate_result_pruning.table_3 -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO intermediate_result_pruning.table_2 (key, value) SELECT key, count(*) AS count FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.>) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO intermediate_result_pruning.table_2 (key, value) SELECT table_1.key, count(*) AS count FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.>) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY table_1.key HAVING (count(*) OPERATOR(pg_catalog.<) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries DEBUG: push down of limit count: 1 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts diff --git a/src/test/regress/expected/intermediate_result_pruning_0.out b/src/test/regress/expected/intermediate_result_pruning_0.out new file mode 100644 index 000000000..e7bf75a27 --- /dev/null +++ b/src/test/regress/expected/intermediate_result_pruning_0.out @@ -0,0 +1,1068 @@ +-- +-- INTERMEDIATE_RESULT_PRUNING +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +CREATE SCHEMA intermediate_result_pruning; +SET search_path TO intermediate_result_pruning; +SET citus.log_intermediate_results TO TRUE; +SET citus.shard_count TO 4; +SET citus.next_shard_id TO 1480000; +SET citus.shard_replication_factor = 1; +CREATE TABLE table_1 (key int, value text); +SELECT create_distributed_table('table_1', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE table_2 (key int, value text); +SELECT create_distributed_table('table_2', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE table_3 (key int, value text); +SELECT create_distributed_table('table_3', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE ref_table (key int, value text); +SELECT create_reference_table('ref_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +-- load some data +INSERT INTO table_1 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'); +INSERT INTO table_2 VALUES (3, '3'), (4, '4'), (5, '5'), (6, '6'); +INSERT INTO table_3 VALUES (3, '3'), (4, '4'), (5, '5'), (6, '6'); +INSERT INTO ref_table VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'); +-- see which workers are hit for intermediate results +SET client_min_messages TO DEBUG1; +-- a very basic case, where the intermediate result +-- should go to both workers +WITH some_values_1 AS MATERIALIZED + (SELECT key FROM table_1 WHERE value IN ('3', '4')) +SELECT + count(*) +FROM + some_values_1 JOIN table_2 USING (key); +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 2 +(1 row) + +-- a very basic case, where the intermediate result +-- should only go to one worker because the final query is a router +-- we use random() to prevent postgres inline the CTE(s) +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')) +SELECT + count(*) +FROM + some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 1; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- a similar query, but with a reference table now +-- given that reference tables are replicated to all nodes +-- we have to broadcast to all nodes +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')) +SELECT + count(*) +FROM + some_values_1 JOIN ref_table USING (key); +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.ref_table USING (key)) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 2 +(1 row) + +-- a similar query as above, but this time use the CTE inside +-- another CTE +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1) +SELECT + count(*) +FROM + some_values_2 JOIN table_2 USING (key) WHERE table_2.key = 1; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT key, random() AS random FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- the second CTE does a join with a distributed table +-- and the final query is a router query +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key)) +SELECT + count(*) +FROM + some_values_2 JOIN table_2 USING (key) WHERE table_2.key = 3; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- the first CTE is used both within second CTE and the final query +-- the second CTE does a join with a distributed table +-- and the final query is a router query +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key)) +SELECT + count(*) +FROM + (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key = 3; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- the first CTE is used both within second CTE and the final query +-- the second CTE does a join with a distributed table but a router query on a worker +-- and the final query is another router query on another worker +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 1) +SELECT + count(*) +FROM + (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key = 3; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- the first CTE is used both within second CTE and the final query +-- the second CTE does a join with a distributed table but a router query on a worker +-- and the final query is a router query on the same worker, so the first result is only +-- broadcasted to a single node +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 1) +SELECT + count(*) +FROM + (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key = 1; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- the same query with the above, but the final query is hitting all shards +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key)) +SELECT + count(*) +FROM + (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key != 3; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.<>) 3) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- even if we add a filter on the first query and make it a router query, +-- the first intermediate result still hits all workers because of the final +-- join is hitting all workers +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 3) +SELECT + count(*) +FROM + (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key != 3; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.<>) 3) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- the reference table is joined with a distributed table and an intermediate +-- result, but the distributed table hits all shards, so the intermediate +-- result is sent to all nodes +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM ref_table WHERE value IN ('3', '4')) +SELECT + count(*) +FROM + (some_values_1 JOIN ref_table USING (key)) JOIN table_2 USING (key); +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.ref_table WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.ref_table USING (key)) JOIN intermediate_result_pruning.table_2 USING (key)) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 2 +(1 row) + +-- similar query as above, but this time the whole query is a router +-- query, so no intermediate results +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM ref_table WHERE value IN ('3', '4')) +SELECT + count(*) +FROM + (some_values_1 JOIN ref_table USING (key)) JOIN table_2 USING (key) WHERE table_2.key = 1; + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- now, the second CTE has a single shard join with a distributed table +-- so the first CTE should only be broadcasted to that node +-- since the final query doesn't have a join, it should simply be broadcasted +-- to one node +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1) +SELECT + count(*) +FROM + some_values_2; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- the same query inlined inside a CTE, and the final query has a +-- join with a distributed table +WITH top_cte as MATERIALIZED ( + WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1) + SELECT + DISTINCT key + FROM + some_values_2 +) +SELECT + count(*) +FROM + top_cte JOIN table_2 USING (key); +DEBUG: generating subplan XXX_1 for CTE top_cte: WITH some_values_1 AS MATERIALIZED (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (table_1.value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text]))), some_values_2 AS MATERIALIZED (SELECT some_values_1.key, random() AS random FROM (some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1)) SELECT DISTINCT key FROM some_values_2 +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT DISTINCT key FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) top_cte JOIN intermediate_result_pruning.table_2 USING (key)) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- very much the same query, but this time the top query is also a router query +-- on a single worker, so all intermediate results only hit a single node +WITH top_cte as MATERIALIZED ( + WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1) + SELECT + DISTINCT key + FROM + some_values_2 +) +SELECT + count(*) +FROM + top_cte JOIN table_2 USING (key) WHERE table_2.key = 2; +DEBUG: generating subplan XXX_1 for CTE top_cte: WITH some_values_1 AS MATERIALIZED (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (table_1.value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text]))), some_values_2 AS MATERIALIZED (SELECT some_values_1.key, random() AS random FROM (some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1)) SELECT DISTINCT key FROM some_values_2 +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT DISTINCT key FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) top_cte JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 2) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- some_values_1 is first used by a single shard-query, and than with a multi-shard +-- CTE, finally a cartesian product join +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1), + some_values_3 AS MATERIALIZED + (SELECT key FROM (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key)) +SELECT * FROM some_values_3 JOIN ref_table ON (true); +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_3 for CTE some_values_3: SELECT some_values_2.key FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT some_values_3.key, ref_table.key, ref_table.value FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) some_values_3 JOIN intermediate_result_pruning.ref_table ON (true)) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx + key | key | value +--------------------------------------------------------------------- +(0 rows) + +-- join on intermediate results, so should only +-- go to a single node +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM table_2 WHERE value IN ('3', '4')) +SELECT count(*) FROM some_values_2 JOIN some_values_1 USING (key); +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT key, random() AS random FROM intermediate_result_pruning.table_2 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file + count +--------------------------------------------------------------------- + 2 +(1 row) + +-- same query with WHERE false make sure that we're not broken +-- for such edge cases +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM table_2 WHERE value IN ('3', '4')) +SELECT count(*) FROM some_values_2 JOIN some_values_1 USING (key) WHERE false; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT key, random() AS random FROM intermediate_result_pruning.table_2 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE false +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- do not use some_values_2 at all, so only 2 intermediate results are +-- broadcasted +WITH some_values_1 AS MATERIALIZED + (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), + some_values_2 AS MATERIALIZED + (SELECT key, random() FROM some_values_1), + some_values_3 AS MATERIALIZED + (SELECT key, random() FROM some_values_1) +SELECT + count(*) +FROM + some_values_3; +DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) +DEBUG: generating subplan XXX_2 for CTE some_values_3: SELECT key, random() AS random FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_3 +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file + count +--------------------------------------------------------------------- + 2 +(1 row) + +-- lets have some deeper intermediate results +-- the inner most two results and the final query (which contains only intermediate results) +-- hitting single worker, others hitting all workers +-- (see below query where all intermediate results hit a single node) +SELECT count(*) FROM +( + SELECT avg(min::int) FROM + ( + SELECT min(table_1.value) FROM + ( + SELECT avg(value::int) as avg_ev_type FROM + ( + SELECT max(value) as mx_val_1 FROM + ( + SELECT avg(value::int) as avg FROM + ( + SELECT cnt FROM + ( + SELECT count(*) as cnt, value + FROM table_1 + WHERE key = 1 + GROUP BY value + ) as level_1, table_1 + WHERE table_1.key = level_1.cnt AND key = 3 + ) as level_2, table_2 + WHERE table_2.key = level_2.cnt AND key = 5 + GROUP BY level_2.cnt + ) as level_3, table_1 + WHERE value::numeric = level_3.avg AND key = 6 + GROUP BY level_3.avg + ) as level_4, table_2 + WHERE level_4.mx_val_1::int = table_2.key + GROUP BY level_4.mx_val_1 + ) as level_5, table_1 + WHERE level_5.avg_ev_type = table_1.key AND key > 111 + GROUP BY level_5.avg_ev_type + ) as level_6, table_1 WHERE table_1.key::int = level_6.min::int + GROUP BY table_1.value +) as bar; +DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS cnt, value FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) GROUP BY value +DEBUG: generating subplan XXX_2 for subquery SELECT avg((table_2.value)::integer) AS avg FROM (SELECT level_1.cnt FROM (SELECT intermediate_result.cnt, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(cnt bigint, value text)) level_1, intermediate_result_pruning.table_1 WHERE ((table_1.key OPERATOR(pg_catalog.=) level_1.cnt) AND (table_1.key OPERATOR(pg_catalog.=) 3))) level_2, intermediate_result_pruning.table_2 WHERE ((table_2.key OPERATOR(pg_catalog.=) level_2.cnt) AND (table_2.key OPERATOR(pg_catalog.=) 5)) GROUP BY level_2.cnt +DEBUG: generating subplan XXX_3 for subquery SELECT max(table_1.value) AS mx_val_1 FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) level_3, intermediate_result_pruning.table_1 WHERE (((table_1.value)::numeric OPERATOR(pg_catalog.=) level_3.avg) AND (table_1.key OPERATOR(pg_catalog.=) 6)) GROUP BY level_3.avg +DEBUG: generating subplan XXX_4 for subquery SELECT avg((table_2.value)::integer) AS avg_ev_type FROM (SELECT intermediate_result.mx_val_1 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(mx_val_1 text)) level_4, intermediate_result_pruning.table_2 WHERE ((level_4.mx_val_1)::integer OPERATOR(pg_catalog.=) table_2.key) GROUP BY level_4.mx_val_1 +DEBUG: generating subplan XXX_5 for subquery SELECT min(table_1.value) AS min FROM (SELECT intermediate_result.avg_ev_type FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(avg_ev_type numeric)) level_5, intermediate_result_pruning.table_1 WHERE ((level_5.avg_ev_type OPERATOR(pg_catalog.=) (table_1.key)::numeric) AND (table_1.key OPERATOR(pg_catalog.>) 111)) GROUP BY level_5.avg_ev_type +DEBUG: generating subplan XXX_6 for subquery SELECT avg((level_6.min)::integer) AS avg FROM (SELECT intermediate_result.min FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(min text)) level_6, intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) (level_6.min)::integer) GROUP BY table_1.value +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) bar +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_4 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_4 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_5 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_5 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_6 will be written to local file + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- the same query where all intermediate results hits one +-- worker because each and every query is a router query -- but on different nodes +SELECT count(*) FROM +( + SELECT avg(min::int) FROM + ( + SELECT min(table_1.value) FROM + ( + SELECT avg(value::int) as avg_ev_type FROM + ( + SELECT max(value) as mx_val_1 FROM + ( + SELECT avg(value::int) as avg FROM + ( + SELECT cnt FROM + ( + SELECT count(*) as cnt, value + FROM table_1 + WHERE key = 1 + GROUP BY value + ) as level_1, table_1 + WHERE table_1.key = level_1.cnt AND key = 3 + ) as level_2, table_2 + WHERE table_2.key = level_2.cnt AND key = 5 + GROUP BY level_2.cnt + ) as level_3, table_1 + WHERE value::numeric = level_3.avg AND key = 6 + GROUP BY level_3.avg + ) as level_4, table_2 + WHERE level_4.mx_val_1::int = table_2.key AND table_2.key = 1 + GROUP BY level_4.mx_val_1 + ) as level_5, table_1 + WHERE level_5.avg_ev_type = table_1.key AND key = 111 + GROUP BY level_5.avg_ev_type + ) as level_6, table_1 + WHERE table_1.key::int = level_6.min::int AND table_1.key = 4 + GROUP BY table_1.value +) as bar; +DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS cnt, value FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) GROUP BY value +DEBUG: generating subplan XXX_2 for subquery SELECT avg((table_2.value)::integer) AS avg FROM (SELECT level_1.cnt FROM (SELECT intermediate_result.cnt, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(cnt bigint, value text)) level_1, intermediate_result_pruning.table_1 WHERE ((table_1.key OPERATOR(pg_catalog.=) level_1.cnt) AND (table_1.key OPERATOR(pg_catalog.=) 3))) level_2, intermediate_result_pruning.table_2 WHERE ((table_2.key OPERATOR(pg_catalog.=) level_2.cnt) AND (table_2.key OPERATOR(pg_catalog.=) 5)) GROUP BY level_2.cnt +DEBUG: generating subplan XXX_3 for subquery SELECT max(table_1.value) AS mx_val_1 FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) level_3, intermediate_result_pruning.table_1 WHERE (((table_1.value)::numeric OPERATOR(pg_catalog.=) level_3.avg) AND (table_1.key OPERATOR(pg_catalog.=) 6)) GROUP BY level_3.avg +DEBUG: generating subplan XXX_4 for subquery SELECT avg((table_2.value)::integer) AS avg_ev_type FROM (SELECT intermediate_result.mx_val_1 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(mx_val_1 text)) level_4, intermediate_result_pruning.table_2 WHERE (((level_4.mx_val_1)::integer OPERATOR(pg_catalog.=) table_2.key) AND (table_2.key OPERATOR(pg_catalog.=) 1)) GROUP BY level_4.mx_val_1 +DEBUG: generating subplan XXX_5 for subquery SELECT min(table_1.value) AS min FROM (SELECT intermediate_result.avg_ev_type FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(avg_ev_type numeric)) level_5, intermediate_result_pruning.table_1 WHERE ((level_5.avg_ev_type OPERATOR(pg_catalog.=) (table_1.key)::numeric) AND (table_1.key OPERATOR(pg_catalog.=) 111)) GROUP BY level_5.avg_ev_type +DEBUG: generating subplan XXX_6 for subquery SELECT avg((level_6.min)::integer) AS avg FROM (SELECT intermediate_result.min FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(min text)) level_6, intermediate_result_pruning.table_1 WHERE ((table_1.key OPERATOR(pg_catalog.=) (level_6.min)::integer) AND (table_1.key OPERATOR(pg_catalog.=) 4)) GROUP BY table_1.value +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) bar +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_4 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_5 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_6 will be written to local file + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- sanity checks for set operations +-- the intermediate results should just hit a single worker +(SELECT key FROM table_1 WHERE key = 1) +INTERSECT +(SELECT key FROM table_1 WHERE key = 2); +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file + key +--------------------------------------------------------------------- +(0 rows) + +-- the intermediate results should just hit a single worker +WITH cte_1 AS MATERIALIZED +( + (SELECT key FROM table_1 WHERE key = 1) + INTERSECT + (SELECT key FROM table_1 WHERE key = 2) +), +cte_2 AS MATERIALIZED +( + (SELECT key FROM table_1 WHERE key = 3) + INTERSECT + (SELECT key FROM table_1 WHERE key = 4) +) +SELECT * FROM cte_1 + UNION +SELECT * FROM cte_2; +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) +DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 3) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 4) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT cte_1.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 UNION SELECT cte_2.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_2 +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file + key +--------------------------------------------------------------------- +(0 rows) + +-- one final test with SET operations, where +-- we join the results with distributed tables +-- so cte_1 should hit all workers, but still the +-- others should hit single worker each +WITH cte_1 AS MATERIALIZED +( + (SELECT key FROM table_1 WHERE key = 1) + INTERSECT + (SELECT key FROM table_1 WHERE key = 2) +), +cte_2 AS MATERIALIZED +( + SELECT count(*) FROM table_1 JOIN cte_1 USING (key) +) +SELECT * FROM cte_2; +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) +DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT count(*) AS count FROM (intermediate_result_pruning.table_1 JOIN (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 USING (key)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) cte_2 +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- sanity checks for non-colocated subquery joins +-- the recursively planned subquery (bar) should hit all +-- nodes +SELECT + count(*) +FROM + (SELECT key, random() FROM table_1) as foo, + (SELECT key, random() FROM table_2) as bar +WHERE + foo.key != bar.key; +DEBUG: generating subplan XXX_1 for subquery SELECT key, random() AS random FROM intermediate_result_pruning.table_2 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1) foo, (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) bar WHERE (foo.key OPERATOR(pg_catalog.<>) bar.key) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 14 +(1 row) + +-- the recursively planned subquery (bar) should hit one +-- node because foo goes to a single node +SELECT + count(*) +FROM + (SELECT key, random() FROM table_1 WHERE key = 1) as foo, + (SELECT key, random() FROM table_2) as bar +WHERE + foo.key != bar.key; +DEBUG: generating subplan XXX_1 for subquery SELECT key, random() AS random FROM intermediate_result_pruning.table_2 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1)) foo, (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) bar WHERE (foo.key OPERATOR(pg_catalog.<>) bar.key) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 4 +(1 row) + +-- sanity checks for modification queries +-- select_data goes to a single node, because it is used in another subquery +-- raw_data is also the final router query, so hits a single shard +-- however, the subquery in WHERE clause of the DELETE query is broadcasted to all +-- nodes +BEGIN; +WITH select_data AS MATERIALIZED ( + SELECT * FROM table_1 +), +raw_data AS MATERIALIZED ( + DELETE FROM table_2 WHERE key >= (SELECT min(key) FROM select_data WHERE key > 1) RETURNING * +) +SELECT * FROM raw_data; +DEBUG: generating subplan XXX_1 for CTE select_data: SELECT key, value FROM intermediate_result_pruning.table_1 +DEBUG: generating subplan XXX_2 for CTE raw_data: DELETE FROM intermediate_result_pruning.table_2 WHERE (key OPERATOR(pg_catalog.>=) (SELECT min(select_data.key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE (select_data.key OPERATOR(pg_catalog.>) 1))) RETURNING key, value +DEBUG: generating subplan XXX_1 for subquery SELECT min(key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE (key OPERATOR(pg_catalog.>) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM intermediate_result_pruning.table_2 WHERE (key OPERATOR(pg_catalog.>=) (SELECT intermediate_result.min FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(min integer))) RETURNING key, value +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) raw_data +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + key | value +--------------------------------------------------------------------- + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 +(4 rows) + +ROLLBACK; +-- select_data goes to a single node, because it is used in another subquery +-- raw_data is also the final router query, so hits a single shard +-- however, the subquery in WHERE clause of the DELETE query is broadcasted to all +-- nodes +BEGIN; +WITH select_data AS MATERIALIZED ( + SELECT * FROM table_1 +), +raw_data AS MATERIALIZED ( + DELETE FROM table_2 WHERE value::int >= (SELECT min(key) FROM select_data WHERE key > 1 + random()) RETURNING * +) +SELECT * FROM raw_data; +DEBUG: generating subplan XXX_1 for CTE select_data: SELECT key, value FROM intermediate_result_pruning.table_1 +DEBUG: generating subplan XXX_2 for CTE raw_data: DELETE FROM intermediate_result_pruning.table_2 WHERE ((value)::integer OPERATOR(pg_catalog.>=) (SELECT min(select_data.key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE ((select_data.key)::double precision OPERATOR(pg_catalog.>) ((1)::double precision OPERATOR(pg_catalog.+) random())))) RETURNING key, value +DEBUG: generating subplan XXX_1 for subquery SELECT min(key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE ((key)::double precision OPERATOR(pg_catalog.>) ((1)::double precision OPERATOR(pg_catalog.+) random())) +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM intermediate_result_pruning.table_2 WHERE ((value)::integer OPERATOR(pg_catalog.>=) (SELECT intermediate_result.min FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(min integer))) RETURNING key, value +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) raw_data +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + key | value +--------------------------------------------------------------------- + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 +(4 rows) + +ROLLBACK; +-- now, we need only two intermediate results as the subquery in WHERE clause is +-- router plannable +BEGIN; +WITH select_data AS MATERIALIZED ( + SELECT * FROM table_1 +), +raw_data AS MATERIALIZED ( + DELETE FROM table_2 WHERE value::int >= (SELECT min(key) FROM table_1 WHERE key > random()) AND key = 6 RETURNING * +) +SELECT * FROM raw_data; +DEBUG: generating subplan XXX_1 for CTE raw_data: DELETE FROM intermediate_result_pruning.table_2 WHERE (((value)::integer OPERATOR(pg_catalog.>=) (SELECT min(table_1.key) AS min FROM intermediate_result_pruning.table_1 WHERE ((table_1.key)::double precision OPERATOR(pg_catalog.>) random()))) AND (key OPERATOR(pg_catalog.=) 6)) RETURNING key, value +DEBUG: generating subplan XXX_1 for subquery SELECT min(key) AS min FROM intermediate_result_pruning.table_1 WHERE ((key)::double precision OPERATOR(pg_catalog.>) random()) +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM intermediate_result_pruning.table_2 WHERE (((value)::integer OPERATOR(pg_catalog.>=) (SELECT intermediate_result.min FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(min integer))) AND (key OPERATOR(pg_catalog.=) 6)) RETURNING key, value +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) raw_data +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + key | value +--------------------------------------------------------------------- + 6 | 6 +(1 row) + +ROLLBACK; +-- test with INSERT SELECT via coordinator +-- INSERT .. SELECT via coordinator that doesn't have any intermediate results +-- We use offset 1 to make sure the result needs to be pulled to the coordinator, offset 0 would be optimized away +INSERT INTO table_1 + SELECT * FROM table_2 OFFSET 1; +DEBUG: OFFSET clauses are not allowed in distributed INSERT ... SELECT queries +DEBUG: Collecting INSERT ... SELECT results on coordinator +-- INSERT .. SELECT via coordinator which has intermediate result, +-- and can be pruned to a single worker because the final query is on +-- single shard via filter in key +INSERT INTO table_1 + SELECT * FROM table_2 where value IN (SELECT value FROM table_1 WHERE random() > 1) AND key = 1; +DEBUG: volatile functions are not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM intermediate_result_pruning.table_1 WHERE (random() OPERATOR(pg_catalog.>) (1)::double precision) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM intermediate_result_pruning.table_2 WHERE ((value OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text))) AND (key OPERATOR(pg_catalog.=) 1)) +DEBUG: Collecting INSERT ... SELECT results on coordinator +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +-- a similar query, with more complex subquery +INSERT INTO table_1 + SELECT * FROM table_2 where key = 1 AND + value::int IN + (WITH cte_1 AS MATERIALIZED + ( + (SELECT key FROM table_1 WHERE key = 1) + INTERSECT + (SELECT key FROM table_1 WHERE key = 2) + ), + cte_2 AS MATERIALIZED + ( + (SELECT key FROM table_1 WHERE key = 3) + INTERSECT + (SELECT key FROM table_1 WHERE key = 4) + ) + SELECT * FROM cte_1 + UNION + SELECT * FROM cte_2); +DEBUG: Set operations are not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) +DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 3) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 4) +DEBUG: generating subplan XXX_3 for subquery SELECT cte_1.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 UNION SELECT cte_2.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_2 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM intermediate_result_pruning.table_2 WHERE ((key OPERATOR(pg_catalog.=) 1) AND ((value)::integer OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)))) +DEBUG: Collecting INSERT ... SELECT results on coordinator +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx +-- same query, cte is on the FROM clause +-- and this time the final query (and top-level intermediate result) +-- hits all the shards because table_2.key != 1 +INSERT INTO table_1 + SELECT table_2.* FROM table_2, + (WITH cte_1 AS MATERIALIZED + ( + (SELECT key FROM table_1 WHERE key = 1) + INTERSECT + (SELECT key FROM table_1 WHERE key = 2) + ), + cte_2 AS MATERIALIZED + ( + (SELECT key FROM table_1 WHERE key = 3) + INTERSECT + (SELECT key FROM table_1 WHERE key = 4) + ) + SELECT * FROM cte_1 + UNION + SELECT * FROM cte_2 + ) foo + where table_2.key != 1 AND + foo.key = table_2.value::int; +DEBUG: Set operations are not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) +DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 3) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 4) +DEBUG: generating subplan XXX_3 for subquery SELECT cte_1.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 UNION SELECT cte_2.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_2 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT table_2.key, table_2.value FROM intermediate_result_pruning.table_2, (SELECT intermediate_result.key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) foo WHERE ((table_2.key OPERATOR(pg_catalog.<>) 1) AND (foo.key OPERATOR(pg_catalog.=) (table_2.value)::integer)) +DEBUG: performing repartitioned INSERT ... SELECT +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx +-- append partitioned/heap-type +-- do not print out 'building index pg_toast_xxxxx_index' messages +SET client_min_messages TO DEFAULT; +CREATE TABLE range_partitioned(range_column text, data int); +SET client_min_messages TO DEBUG1; +SELECT create_distributed_table('range_partitioned', 'range_column', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT master_create_empty_shard('range_partitioned'); + master_create_empty_shard +--------------------------------------------------------------------- + 1480013 +(1 row) + +SELECT master_create_empty_shard('range_partitioned'); + master_create_empty_shard +--------------------------------------------------------------------- + 1480014 +(1 row) + +SELECT master_create_empty_shard('range_partitioned'); + master_create_empty_shard +--------------------------------------------------------------------- + 1480015 +(1 row) + +SELECT master_create_empty_shard('range_partitioned'); + master_create_empty_shard +--------------------------------------------------------------------- + 1480016 +(1 row) + +SELECT master_create_empty_shard('range_partitioned'); + master_create_empty_shard +--------------------------------------------------------------------- + 1480017 +(1 row) + +UPDATE pg_dist_shard SET shardminvalue = 'A', shardmaxvalue = 'D' WHERE shardid = 1480013; +UPDATE pg_dist_shard SET shardminvalue = 'D', shardmaxvalue = 'G' WHERE shardid = 1480014; +UPDATE pg_dist_shard SET shardminvalue = 'G', shardmaxvalue = 'K' WHERE shardid = 1480015; +UPDATE pg_dist_shard SET shardminvalue = 'K', shardmaxvalue = 'O' WHERE shardid = 1480016; +UPDATE pg_dist_shard SET shardminvalue = 'O', shardmaxvalue = 'Z' WHERE shardid = 1480017; +-- final query goes to a single shard +SELECT + count(*) +FROM + range_partitioned +WHERE + range_column = 'A' AND + data IN (SELECT data FROM range_partitioned); +DEBUG: generating subplan XXX_1 for subquery SELECT data FROM intermediate_result_pruning.range_partitioned +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM intermediate_result_pruning.range_partitioned WHERE ((range_column OPERATOR(pg_catalog.=) 'A'::text) AND (data OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.data FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(data integer)))) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- final query goes to three shards, so multiple workers +SELECT + count(*) +FROM + range_partitioned +WHERE + range_column >= 'A' AND range_column <= 'K' AND + data IN (SELECT data FROM range_partitioned); +DEBUG: generating subplan XXX_1 for subquery SELECT data FROM intermediate_result_pruning.range_partitioned +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM intermediate_result_pruning.range_partitioned WHERE ((range_column OPERATOR(pg_catalog.>=) 'A'::text) AND (range_column OPERATOR(pg_catalog.<=) 'K'::text) AND (data OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.data FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(data integer)))) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- two shards, both of which are on the first node +WITH some_data AS ( + SELECT data FROM range_partitioned +) +SELECT + count(*) +FROM + range_partitioned +WHERE + range_column IN ('A', 'E') AND + range_partitioned.data IN (SELECT data FROM some_data); +DEBUG: CTE some_data is going to be inlined via distributed planning +DEBUG: generating subplan XXX_1 for subquery SELECT data FROM (SELECT range_partitioned.data FROM intermediate_result_pruning.range_partitioned) some_data +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM intermediate_result_pruning.range_partitioned WHERE ((range_column OPERATOR(pg_catalog.=) ANY (ARRAY['A'::text, 'E'::text])) AND (data OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.data FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(data integer)))) +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- test case for issue #3556 +CREATE TABLE accounts (id text PRIMARY KEY); +DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "accounts_pkey" for table "accounts" +CREATE TABLE stats (account_id text PRIMARY KEY, spent int); +DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "stats_pkey" for table "stats" +SELECT create_distributed_table('accounts', 'id', colocate_with => 'none'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_table('stats', 'account_id', colocate_with => 'accounts'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO accounts (id) VALUES ('foo'); +INSERT INTO stats (account_id, spent) VALUES ('foo', 100); +SELECT * +FROM +( + WITH accounts_cte AS MATERIALIZED ( + SELECT id AS account_id + FROM accounts + ), + joined_stats_cte_1 AS MATERIALIZED ( + SELECT spent, account_id + FROM stats + INNER JOIN accounts_cte USING (account_id) + ), + joined_stats_cte_2 AS MATERIALIZED ( + SELECT spent, account_id + FROM joined_stats_cte_1 + INNER JOIN accounts_cte USING (account_id) + ) + SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) + FROM accounts_cte + INNER JOIN joined_stats_cte_2 USING (account_id) +) inner_query; +DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM intermediate_result_pruning.accounts +DEBUG: generating subplan XXX_2 for CTE joined_stats_cte_1: SELECT stats.spent, stats.account_id FROM (intermediate_result_pruning.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) +DEBUG: generating subplan XXX_3 for CTE joined_stats_cte_2: SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_2 USING (account_id))) inner_query +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Subplan XXX_3 will be written to local file + sum +--------------------------------------------------------------------- + 100 +(1 row) + +-- confirm that the pruning works well when using round-robin as well +SET citus.task_assignment_policy to 'round-robin'; +SELECT * +FROM +( + WITH accounts_cte AS MATERIALIZED ( + SELECT id AS account_id + FROM accounts + ), + joined_stats_cte_1 AS MATERIALIZED ( + SELECT spent, account_id + FROM stats + INNER JOIN accounts_cte USING (account_id) + ), + joined_stats_cte_2 AS MATERIALIZED ( + SELECT spent, account_id + FROM joined_stats_cte_1 + INNER JOIN accounts_cte USING (account_id) + ) + SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) + FROM accounts_cte + INNER JOIN joined_stats_cte_2 USING (account_id) +) inner_query; +DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM intermediate_result_pruning.accounts +DEBUG: generating subplan XXX_2 for CTE joined_stats_cte_1: SELECT stats.spent, stats.account_id FROM (intermediate_result_pruning.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) +DEBUG: generating subplan XXX_3 for CTE joined_stats_cte_2: SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_2 USING (account_id))) inner_query +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx + sum +--------------------------------------------------------------------- + 100 +(1 row) + +RESET citus.task_assignment_policy; +-- Insert..select is planned differently, make sure we have results everywhere. +-- We put the insert..select in a CTE here to prevent the CTE from being moved +-- into the select, which would follow the regular code path for select. +WITH stats AS MATERIALIZED ( + SELECT count(key) m FROM table_3 +), +inserts AS MATERIALIZED ( + INSERT INTO table_2 + SELECT key, count(*) + FROM table_1 + WHERE key > (SELECT m FROM stats) + GROUP BY key + HAVING count(*) < (SELECT m FROM stats) + LIMIT 1 + RETURNING * +) SELECT count(*) FROM inserts; +DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM intermediate_result_pruning.table_3 +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO intermediate_result_pruning.table_2 (key, value) SELECT key, count(*) AS count FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.>) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value +DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Collecting INSERT ... SELECT results on coordinator + count +--------------------------------------------------------------------- + 1 +(1 row) + +SET citus.task_assignment_policy to DEFAULT; +SET client_min_messages TO DEFAULT; +DROP TABLE table_1, table_2, table_3, ref_table, accounts, stats, range_partitioned; +DROP SCHEMA intermediate_result_pruning; diff --git a/src/test/regress/expected/local_shard_execution.out b/src/test/regress/expected/local_shard_execution.out index 1f7e3e80c..b7049b3bf 100644 --- a/src/test/regress/expected/local_shard_execution.out +++ b/src/test/regress/expected/local_shard_execution.out @@ -1,3 +1,12 @@ +-- +-- LOCAL_SHARD_EXECUTION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA local_shard_execution; SET search_path TO local_shard_execution; SET citus.shard_count TO 4; @@ -288,7 +297,7 @@ RETURNING *; INSERT INTO distributed_table SELECT * FROM distributed_table WHERE key = 1 OFFSET 0 ON CONFLICT DO NOTHING; NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 NOTICE: executing the copy locally for colocated file with shard xxxxx -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) SELECT key, value, age FROM read_intermediate_result('insert_select_XXX_1470001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint) ON CONFLICT DO NOTHING +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('insert_select_XXX_1470001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint) ON CONFLICT DO NOTHING INSERT INTO distributed_table SELECT 1, '1',15 FROM distributed_table WHERE key = 2 LIMIT 1 ON CONFLICT DO NOTHING; -- sanity check: multi-shard INSERT..SELECT pushdown goes through distributed execution INSERT INTO distributed_table SELECT * FROM distributed_table ON CONFLICT DO NOTHING; @@ -800,7 +809,7 @@ NOTICE: executing the copy locally for shard xxxxx INSERT INTO distributed_table (key) SELECT -key FROM distributed_table; NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1470001_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1470001_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1470003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1470003_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1470003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key) SELECT intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1470003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) SELECT count(*) FROM distributed_table WHERE key = -6; NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) '-6'::integer) count diff --git a/src/test/regress/expected/local_shard_execution_0.out b/src/test/regress/expected/local_shard_execution_0.out new file mode 100644 index 000000000..db1e8d7d3 --- /dev/null +++ b/src/test/regress/expected/local_shard_execution_0.out @@ -0,0 +1,3292 @@ +-- +-- LOCAL_SHARD_EXECUTION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +CREATE SCHEMA local_shard_execution; +SET search_path TO local_shard_execution; +SET citus.shard_count TO 4; +SET citus.shard_replication_factor TO 1; +SET citus.next_shard_id TO 1470000; +CREATE TABLE reference_table (key int PRIMARY KEY); +SELECT create_reference_table('reference_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_table (key int PRIMARY KEY , value text, age bigint CHECK (age > 10), FOREIGN KEY (key) REFERENCES reference_table(key) ON DELETE CASCADE); +SELECT create_distributed_table('distributed_table','key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE second_distributed_table (key int PRIMARY KEY , value text, FOREIGN KEY (key) REFERENCES distributed_table(key) ON DELETE CASCADE); +SELECT create_distributed_table('second_distributed_table','key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- ingest some data to enable some tests with data +INSERT INTO reference_table VALUES (1); +INSERT INTO distributed_table VALUES (1, '1', 20); +INSERT INTO second_distributed_table VALUES (1, '1'); +-- a simple test for +CREATE TABLE collections_list ( + key bigserial, + ser bigserial, + ts timestamptz, + collection_id integer, + value numeric, + PRIMARY KEY(key, collection_id) +) PARTITION BY LIST (collection_id ); +SELECT create_distributed_table('collections_list', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE collections_list_0 + PARTITION OF collections_list (key, ser, ts, collection_id, value) + FOR VALUES IN ( 0 ); +-- create a volatile function that returns the local node id +CREATE OR REPLACE FUNCTION get_local_node_id_volatile() +RETURNS INT AS $$ +DECLARE localGroupId int; +BEGIN + SELECT groupid INTO localGroupId FROM pg_dist_local_group; + RETURN localGroupId; +END; $$ language plpgsql VOLATILE; +SELECT create_distributed_function('get_local_node_id_volatile()'); +NOTICE: procedure local_shard_execution.get_local_node_id_volatile is already distributed +DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- test case for issue #3556 +CREATE TABLE accounts (id text PRIMARY KEY); +CREATE TABLE stats (account_id text PRIMARY KEY, spent int); +SELECT create_distributed_table('accounts', 'id', colocate_with => 'none'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_table('stats', 'account_id', colocate_with => 'accounts'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO accounts (id) VALUES ('foo'); +INSERT INTO stats (account_id, spent) VALUES ('foo', 100); +CREATE TABLE abcd(a int, b int, c int, d int); +SELECT create_distributed_table('abcd', 'b'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO abcd VALUES (1,2,3,4); +INSERT INTO abcd VALUES (2,3,4,5); +INSERT INTO abcd VALUES (3,4,5,6); +ALTER TABLE abcd DROP COLUMN a; +-- connection worker and get ready for the tests +\c - - - :worker_1_port +SET search_path TO local_shard_execution; +SET citus.enable_unique_job_ids TO off; +-- returns true of the distribution key filter +-- on the distributed tables (e.g., WHERE key = 1), we'll hit a shard +-- placement which is local to this not +SET citus.enable_metadata_sync TO OFF; +CREATE OR REPLACE FUNCTION shard_of_distribution_column_is_local(dist_key int) RETURNS bool AS $$ + + DECLARE shard_is_local BOOLEAN := FALSE; + + BEGIN + + WITH local_shard_ids AS (SELECT get_shard_id_for_distribution_column('local_shard_execution.distributed_table', dist_key)), + all_local_shard_ids_on_node AS (SELECT shardid FROM pg_dist_placement WHERE groupid IN (SELECT groupid FROM pg_dist_local_group)) + SELECT + true INTO shard_is_local + FROM + local_shard_ids + WHERE + get_shard_id_for_distribution_column IN (SELECT * FROM all_local_shard_ids_on_node); + + IF shard_is_local IS NULL THEN + shard_is_local = FALSE; + END IF; + + RETURN shard_is_local; + END; +$$ LANGUAGE plpgsql; +RESET citus.enable_metadata_sync; +-- test case for issue #3556 +SET citus.log_intermediate_results TO TRUE; +SET client_min_messages TO DEBUG1; +SELECT * +FROM +( + WITH accounts_cte AS ( + SELECT id AS account_id + FROM accounts + ), + joined_stats_cte_1 AS ( + SELECT spent, account_id + FROM stats + INNER JOIN accounts_cte USING (account_id) + ), + joined_stats_cte_2 AS ( + SELECT spent, account_id + FROM joined_stats_cte_1 + INNER JOIN accounts_cte USING (account_id) + ) + SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) + FROM accounts_cte + INNER JOIN joined_stats_cte_2 USING (account_id) +) inner_query; +DEBUG: CTE joined_stats_cte_1 is going to be inlined via distributed planning +DEBUG: CTE joined_stats_cte_2 is going to be inlined via distributed planning +DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM local_shard_execution.accounts +DEBUG: generating subplan XXX_2 for subquery SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT stats.spent, stats.account_id FROM (local_shard_execution.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_2 USING (account_id))) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_1 USING (account_id))) joined_stats_cte_2 USING (account_id)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT intermediate_result.sum FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(sum bigint)) inner_query +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file + sum +--------------------------------------------------------------------- + 100 +(1 row) + +SET citus.log_intermediate_results TO DEFAULT; +SET client_min_messages TO DEFAULT; +-- pick some example values that reside on the shards locally and remote +-- distribution key values of 1,6, 500 and 701 are LOCAL to shards, +-- we'll use these values in the tests +SELECT shard_of_distribution_column_is_local(1); + shard_of_distribution_column_is_local +--------------------------------------------------------------------- + t +(1 row) + +SELECT shard_of_distribution_column_is_local(6); + shard_of_distribution_column_is_local +--------------------------------------------------------------------- + t +(1 row) + +SELECT shard_of_distribution_column_is_local(500); + shard_of_distribution_column_is_local +--------------------------------------------------------------------- + t +(1 row) + +SELECT shard_of_distribution_column_is_local(701); + shard_of_distribution_column_is_local +--------------------------------------------------------------------- + t +(1 row) + +-- distribution key values of 11 and 12 are REMOTE to shards +SELECT shard_of_distribution_column_is_local(11); + shard_of_distribution_column_is_local +--------------------------------------------------------------------- + f +(1 row) + +SELECT shard_of_distribution_column_is_local(12); + shard_of_distribution_column_is_local +--------------------------------------------------------------------- + f +(1 row) + +--- enable logging to see which tasks are executed locally +SET citus.log_local_commands TO ON; +-- first, make sure that local execution works fine +-- with simple queries that are not in transcation blocks +SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- multiple tasks both of which are local should NOT use local execution +-- because local execution means executing the tasks locally, so the executor +-- favors parallel execution even if everyting is local to node +SELECT count(*) FROM distributed_table WHERE key IN (1,6); + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- queries that hit any remote shards should NOT use local execution +SELECT count(*) FROM distributed_table WHERE key IN (1,11); + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM distributed_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- modifications also follow the same rules +INSERT INTO reference_table VALUES (1) ON CONFLICT DO NOTHING; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1) ON CONFLICT DO NOTHING +INSERT INTO distributed_table VALUES (1, '1', 21) ON CONFLICT DO NOTHING; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '1'::text, 21) ON CONFLICT DO NOTHING +-- local query +DELETE FROM distributed_table WHERE key = 1 AND age = 21; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 21)) +-- hitting multiple shards, so should be a distributed execution +DELETE FROM distributed_table WHERE age = 21; +-- although both shards are local, the executor choose the parallel execution +-- over the wire because as noted above local execution is sequential +DELETE FROM second_distributed_table WHERE key IN (1,6); +-- similarly, any multi-shard query just follows distributed execution +DELETE FROM second_distributed_table; +-- load some more data for the following tests +INSERT INTO second_distributed_table VALUES (1, '1'); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (1, '1'::text) +-- INSERT .. SELECT hitting a single single (co-located) shard(s) should +-- be executed locally +INSERT INTO distributed_table +SELECT + distributed_table.* +FROM + distributed_table, second_distributed_table +WHERE + distributed_table.key = 1 and distributed_table.key=second_distributed_table.key +ON CONFLICT(key) DO UPDATE SET value = '22' +RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470001 distributed_table, local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) second_distributed_table.key)) AND (distributed_table.key IS NOT NULL)) ON CONFLICT(key) DO UPDATE SET value = '22'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 22 | 20 +(1 row) + +-- INSERT .. SELECT hitting multi-shards should go thourgh distributed execution +INSERT INTO distributed_table +SELECT + distributed_table.* +FROM + distributed_table, second_distributed_table +WHERE + distributed_table.key != 1 and distributed_table.key=second_distributed_table.key +ON CONFLICT(key) DO UPDATE SET value = '22' +RETURNING *; + key | value | age +--------------------------------------------------------------------- +(0 rows) + +-- INSERT..SELECT via coordinator consists of two steps, select + COPY +-- that's why it is disallowed to use local execution even if the SELECT +-- can be executed locally +INSERT INTO distributed_table SELECT * FROM distributed_table WHERE key = 1 OFFSET 0 ON CONFLICT DO NOTHING; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +NOTICE: executing the copy locally for colocated file with shard xxxxx +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) SELECT key, value, age FROM read_intermediate_result('insert_select_XXX_1470001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint) ON CONFLICT DO NOTHING +INSERT INTO distributed_table SELECT 1, '1',15 FROM distributed_table WHERE key = 2 LIMIT 1 ON CONFLICT DO NOTHING; +-- sanity check: multi-shard INSERT..SELECT pushdown goes through distributed execution +INSERT INTO distributed_table SELECT * FROM distributed_table ON CONFLICT DO NOTHING; +-- Ensure tuple data in explain analyze output is the same on all PG versions +SET citus.enable_binary_protocol = TRUE; +-- EXPLAIN for local execution just works fine +-- though going through distributed execution +EXPLAIN (COSTS OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table + Index Cond: (key = 1) + Filter: (age = 20) +(8 rows) + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 1 + Tuple data received from nodes: 14 bytes + Tasks Shown: All + -> Task + Tuple data received from node: 14 bytes + Node: host=localhost port=xxxxx dbname=regression + -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table (actual rows=1 loops=1) + Index Cond: (key = 1) + Filter: (age = 20) +(10 rows) + +EXPLAIN (ANALYZE ON, COSTS OFF, SUMMARY OFF, TIMING OFF) +WITH r AS ( SELECT GREATEST(random(), 2) z,* FROM distributed_table) +SELECT 1 FROM r WHERE z < 3; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + -> Distributed Subplan XXX_1 + Intermediate Data Size: 40 bytes + Result destination: Write locally + -> Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 4 + Tuple data received from nodes: 22 bytes + Tasks Shown: One of 4 + -> Task + Tuple data received from node: 22 bytes + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on distributed_table_1470001 distributed_table (actual rows=1 loops=1) + Task Count: 1 + Tuple data received from nodes: 4 bytes + Tasks Shown: All + -> Task + Tuple data received from node: 4 bytes + Node: host=localhost port=xxxxx dbname=regression + -> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1) + Filter: (z < '3'::double precision) +(20 rows) + +EXPLAIN (COSTS OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Delete on distributed_table_1470001 distributed_table + -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table + Index Cond: (key = 1) + Filter: (age = 20) +(9 rows) + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) (actual rows=0 loops=1) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Delete on distributed_table_1470001 distributed_table (actual rows=0 loops=1) + -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table (actual rows=1 loops=1) + Index Cond: (key = 1) + Filter: (age = 20) + Trigger for constraint second_distributed_table_key_fkey_1470005: calls=1 +(10 rows) + +-- show that EXPLAIN ANALYZE deleted the row and cascades deletes +SELECT * FROM distributed_table WHERE key = 1 AND age = 20 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 20)) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- +(0 rows) + +SELECT * FROM second_distributed_table WHERE key = 1 ORDER BY 1,2; +NOTICE: executing the command locally: SELECT key, value FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value + key | value +--------------------------------------------------------------------- +(0 rows) + +-- Put rows back for other tests +INSERT INTO distributed_table VALUES (1, '22', 20); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key, value, age) VALUES (1, '22'::text, 20) +INSERT INTO second_distributed_table VALUES (1, '1'); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (1, '1'::text) +SET citus.enable_ddl_propagation TO OFF; +CREATE VIEW abcd_view AS SELECT * FROM abcd; +RESET citus.enable_ddl_propagation; +SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +BEGIN; +SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution.abcd_1470025 first JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution.abcd_1470027 first JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd_view first join abcd_view second on first.b = second.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution.abcd_1470025 abcd JOIN local_shard_execution.abcd_1470025 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true +NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution.abcd_1470027 abcd JOIN local_shard_execution.abcd_1470027 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd first full join abcd second on first.b = second.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution.abcd_1470025 first FULL JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution.abcd_1470027 first FULL JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd first join abcd second USING(b) ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution.abcd_1470025 first JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution.abcd_1470027 first JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true + b | c | d | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 3 | 4 + 3 | 4 | 5 | 4 | 5 + 4 | 5 | 6 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd first join abcd second USING(b) join abcd third on first.b=third.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution.abcd_1470025 first JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution.abcd_1470025 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution.abcd_1470027 first JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution.abcd_1470027 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true + b | c | d | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +-- copy always happens via distributed execution irrespective of the +-- shards that are accessed +COPY reference_table FROM STDIN; +COPY distributed_table FROM STDIN WITH CSV; +COPY second_distributed_table FROM STDIN WITH CSV; +-- the behaviour in transaction blocks is the following: + -- (a) Unless the first query is a local query, always use distributed execution. + -- (b) If the executor has used local execution, it has to use local execution + -- for the remaining of the transaction block. If that's not possible, the + -- executor has to error out +-- rollback should be able to rollback local execution +BEGIN; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 29 | 20 +(1 row) + + SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 29 | 20 +(1 row) + +ROLLBACK; +-- make sure that the value is rollbacked +SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 22 | 20 +(1 row) + +-- rollback should be able to rollback both the local and distributed executions +BEGIN; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 29 | 20 +(1 row) + + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table + -- DELETE should cascade, and we should not see any rows + SELECT count(*) FROM second_distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470007 second_distributed_table WHERE true + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +-- make sure that everything is rollbacked +SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 22 | 20 +(1 row) + +SELECT count(*) FROM second_distributed_table; + count +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT * FROM second_distributed_table; + key | value +--------------------------------------------------------------------- + 1 | 1 + 6 | '6' +(2 rows) + +-- very simple examples, an SELECTs should see the modifications +-- that has done before +BEGIN; + -- INSERT is executed locally + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '23' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '23'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 23 | 20 +(1 row) + + -- since the INSERT is executed locally, the SELECT should also be + -- executed locally and see the changes + SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 23 | 20 +(1 row) + + -- multi-shard SELECTs are now forced to use local execution on + -- the shards that reside on this node + SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) + key | value | age +--------------------------------------------------------------------- + 1 | 23 | 20 +(1 row) + + -- similarly, multi-shard modifications should use local exection + -- on the shards that reside on this node + DELETE FROM distributed_table WHERE value = '23'; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) + -- make sure that the value is deleted + SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) + key | value | age +--------------------------------------------------------------------- +(0 rows) + +COMMIT; +-- make sure that we've committed everything +SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- +(0 rows) + +-- if we start with a distributed execution, we should keep +-- using that and never switch back to local execution +BEGIN; + DELETE FROM distributed_table WHERE value = '11'; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) + -- although this command could have been executed + -- locally, it is not going to be executed locally + SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- +(0 rows) + + -- but we can still execute parallel queries, even if + -- they are utility commands + TRUNCATE distributed_table CASCADE; +NOTICE: truncate cascades to table "second_distributed_table" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE + -- TRUNCATE cascaded into second_distributed_table + SELECT count(*) FROM second_distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470007 second_distributed_table WHERE true + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +-- load some data so that foreign keys won't complain with the next tests +INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; +NOTICE: executing the copy locally for shard xxxxx +-- show that cascading foreign keys just works fine with local execution +BEGIN; + INSERT INTO reference_table VALUES (701); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (701) + INSERT INTO distributed_table VALUES (701, '701', 701); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key, value, age) VALUES (701, '701'::text, 701) + INSERT INTO second_distributed_table VALUES (701, '701'); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (701, '701'::text) + DELETE FROM reference_table WHERE key = 701; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 701) + SELECT count(*) FROM distributed_table WHERE key = 701; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) + count +--------------------------------------------------------------------- + 0 +(1 row) + + SELECT count(*) FROM second_distributed_table WHERE key = 701; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) + count +--------------------------------------------------------------------- + 0 +(1 row) + + -- multi-shard commands should also see the changes + SELECT count(*) FROM distributed_table WHERE key > 700; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) + count +--------------------------------------------------------------------- + 0 +(1 row) + + -- we can still do multi-shard commands + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table +ROLLBACK; +-- multiple queries hitting different shards can be executed locally +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + + SELECT count(*) FROM distributed_table WHERE key = 6; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 1 +(1 row) + + SELECT count(*) FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +-- a local query followed by TRUNCATE command can be executed locally +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + + TRUNCATE distributed_table CASCADE; +NOTICE: truncate cascades to table "second_distributed_table" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +ROLLBACK; +-- a local query is followed by an INSERT..SELECT via the coordinator +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + + INSERT INTO distributed_table (key) SELECT i FROM generate_series(1,1) i; +NOTICE: executing the copy locally for shard xxxxx +ROLLBACK; +BEGIN; +SET citus.enable_repartition_joins TO ON; +SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT count(*) FROM distributed_table d1 join distributed_table d2 using(age); +NOTICE: executing the command locally: SELECT partition_index, 'repartition_65_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_65_1','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470001 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartition_65_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_65_3','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470003 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartition_66_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_66_1','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470001 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartition_66_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_66_3','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470003 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_1_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_2_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_3_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_4_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_1_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_2_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_3_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_4_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_1_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_2_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_3_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_4_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_1_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_2_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_3_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_66_4_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_65_1_0,repartition_65_2_0,repartition_65_3_0,repartition_65_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_66_1_0,repartition_66_2_0,repartition_66_3_0,repartition_66_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_65_1_1,repartition_65_2_1,repartition_65_3_1,repartition_65_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_66_1_1,repartition_66_2_1,repartition_66_3_1,repartition_66_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_65_1_2,repartition_65_2_2,repartition_65_3_2,repartition_65_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_66_1_2,repartition_66_2_2,repartition_66_3_2,repartition_66_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_65_1_3,repartition_65_2_3,repartition_65_3_3,repartition_65_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_66_1_3,repartition_66_2_3,repartition_66_3_3,repartition_66_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + +ROLLBACK; +-- a local query is followed by an INSERT..SELECT with re-partitioning +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 6; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 1 +(1 row) + + INSERT INTO reference_table (key) SELECT -key FROM distributed_table; +NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true +NOTICE: executing the copy locally for shard xxxxx + INSERT INTO distributed_table (key) SELECT -key FROM distributed_table; +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1470001_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1470001_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1470003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1470003_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1470003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) + SELECT count(*) FROM distributed_table WHERE key = -6; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) '-6'::integer) + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 11 | 21 +(1 row) + +BEGIN; + DELETE FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + EXPLAIN ANALYZE DELETE FROM distributed_table WHERE key = 1; +ERROR: cannot execute command because a local execution has accessed a placement in the transaction +DETAIL: Some parallel commands cannot be executed if a previous command has already been executed locally +HINT: Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;" +ROLLBACK; +BEGIN; + INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; + key | value | age +--------------------------------------------------------------------- + 11 | 29 | 121 +(1 row) + + -- this is already disallowed on the nodes, adding it in case we + -- support DDLs from the worker nodes in the future + ALTER TABLE distributed_table ADD COLUMN x INT; +ERROR: operation is not allowed on this node +HINT: Connect to the coordinator and run it again. +ROLLBACK; +BEGIN; + INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; + key | value | age +--------------------------------------------------------------------- + 11 | 29 | 121 +(1 row) + + -- this is already disallowed because VACUUM cannot be executed in tx block + -- adding in case this is supported some day + VACUUM second_distributed_table; +ERROR: VACUUM cannot run inside a transaction block +ROLLBACK; +-- make sure that functions can use local execution +SET citus.enable_metadata_sync TO OFF; +CREATE OR REPLACE PROCEDURE only_local_execution() AS $$ + DECLARE cnt INT; + BEGIN + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; + SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; + DELETE FROM distributed_table WHERE key = 1; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution(); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text +CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" +PL/pgSQL function only_local_execution() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" +PL/pgSQL function only_local_execution() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = 1" +PL/pgSQL function only_local_execution() line XX at SQL statement +-- insert a row that we need in the next tests +INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text +-- make sure that functions can use local execution +CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation() AS $$ + DECLARE nodeId INT; + BEGIN + -- fast path router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = 1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + + -- regular router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution_with_function_evaluation(); +NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = 1" +PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement +NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution.distributed_table_1470001 d1(key, value, age) JOIN local_shard_execution.distributed_table_1470001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1" +PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement +CREATE OR REPLACE PROCEDURE only_local_execution_with_params(int) AS $$ + DECLARE cnt INT; + BEGIN + INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; + SELECT count(*) INTO cnt FROM distributed_table WHERE key = $1; + DELETE FROM distributed_table WHERE key = $1; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution_with_params(1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '29'::text +CONTEXT: SQL statement "INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" +PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = $1" +PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = $1" +PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement +CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation_param(int) AS $$ + DECLARE nodeId INT; + BEGIN + -- fast path router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = $1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + + -- regular router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution_with_function_evaluation_param(1); +NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = $1" +PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement +NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution.distributed_table_1470001 d1(key, value, age) JOIN local_shard_execution.distributed_table_1470001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) $1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1" +PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement +CREATE OR REPLACE PROCEDURE local_execution_followed_by_dist() AS $$ + DECLARE cnt INT; + BEGIN + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; + SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; + DELETE FROM distributed_table; + SELECT count(*) INTO cnt FROM distributed_table; + END; +$$ LANGUAGE plpgsql; +RESET citus.enable_metadata_sync; +CALL local_execution_followed_by_dist(); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text +CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table +CONTEXT: SQL statement "DELETE FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table +CONTEXT: SQL statement "DELETE FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +-- test CTEs, including modifying CTEs +WITH local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *), +distributed_local_mixed AS (SELECT * FROM reference_table WHERE key IN (SELECT key FROM local_insert)) +SELECT * FROM local_insert, distributed_local_mixed; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age +NOTICE: executing the command locally: SELECT key FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT local_insert.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert)) +NOTICE: executing the command locally: SELECT local_insert.key, local_insert.value, local_insert.age, distributed_local_mixed.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed + key | value | age | key +--------------------------------------------------------------------- + 1 | 11 | 21 | 1 +(1 row) + +-- since we start with parallel execution, we do not switch back to local execution in the +-- latter CTEs +WITH distributed_local_mixed AS (SELECT * FROM distributed_table), +local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *) +SELECT * FROM local_insert, distributed_local_mixed ORDER BY 1,2,3,4,5; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age +NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470001 distributed_table) distributed_local_mixed) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table) distributed_local_mixed) worker_subquery + key | value | age | key | value | age +--------------------------------------------------------------------- + 1 | 29 | 21 | 1 | 11 | 21 +(1 row) + +-- router CTE pushdown +WITH all_data AS (SELECT * FROM distributed_table WHERE key = 1) +SELECT + count(*) +FROM + distributed_table, all_data +WHERE + distributed_table.key = all_data.key AND distributed_table.key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) + count +--------------------------------------------------------------------- + 1 +(1 row) + +INSERT INTO reference_table VALUES (2); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (2) +INSERT INTO distributed_table VALUES (2, '29', 29); +INSERT INTO second_distributed_table VALUES (2, '29'); +-- single shard that is not a local query followed by a local query +WITH all_data AS (SELECT * FROM second_distributed_table WHERE key = 2) +SELECT + distributed_table.key +FROM + distributed_table, all_data +WHERE + distributed_table.value = all_data.value AND distributed_table.key = 1 +ORDER BY + 1 DESC; +NOTICE: executing the command locally: SELECT distributed_table.key FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) all_data WHERE ((distributed_table.value OPERATOR(pg_catalog.=) all_data.value) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) ORDER BY distributed_table.key DESC + key +--------------------------------------------------------------------- + 1 +(1 row) + +-- multi-shard CTE is followed by a query which could be executed locally, but +-- since the query started with a parallel query, it doesn't use local execution +-- note that if we allow Postgres to inline the CTE (e.g., not have the EXISTS +-- subquery), then it'd pushdown the filters and the query becomes single-shard, +-- locally executable query +WITH all_data AS (SELECT * FROM distributed_table) +SELECT + count(*) +FROM + distributed_table, all_data +WHERE + distributed_table.key = all_data.key AND distributed_table.key = 1 + AND EXISTS (SELECT * FROM all_data); +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1) AND (EXISTS (SELECT all_data_1.key, all_data_1.value, all_data_1.age FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data_1))) + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- in pg12, the following CTE can be inlined, still the query becomes +-- a subquery that needs to be recursively planned and a parallel +-- query, so do not use local execution +WITH all_data AS (SELECT age FROM distributed_table) +SELECT + count(*) +FROM + distributed_table, all_data +WHERE + distributed_table.key = all_data.age AND distributed_table.key = 1; +NOTICE: executing the command locally: SELECT age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.age) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- get ready for the next commands +TRUNCATE reference_table, distributed_table, second_distributed_table; +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.reference_table_xxxxx CASCADE +NOTICE: truncate cascades to table "distributed_table_xxxxx" +NOTICE: truncate cascades to table "distributed_table_xxxxx" +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +-- local execution of returning of reference tables +INSERT INTO reference_table VALUES (1),(2),(3),(4),(5),(6) RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1), (2), (3), (4), (5), (6) RETURNING citus_table_alias.key + key +--------------------------------------------------------------------- + 1 + 2 + 3 + 4 + 5 + 6 +(6 rows) + +-- local execution of multi-row INSERTs +INSERT INTO distributed_table VALUES (1, '11',21), (5,'55',22) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'22'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 11 | 21 + 5 | 55 | 22 +(2 rows) + +-- distributed execution of multi-rows INSERTs, where executor +-- is smart enough to execute local tasks via local execution +INSERT INTO distributed_table VALUES (1, '11',21), (2,'22',22), (3,'33',33), (4,'44',44),(5,'55',55) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'55'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 12 | 21 + 2 | 22 | 22 + 3 | 33 | 33 + 4 | 44 | 44 + 5 | 56 | 22 +(5 rows) + +PREPARE local_prepare_no_param AS SELECT count(*) FROM distributed_table WHERE key = 1; +PREPARE local_prepare_no_param_subquery AS +SELECT DISTINCT trim(value) FROM ( + SELECT value FROM distributed_table + WHERE + key IN (1, 6, 500, 701) + AND (select 2) > random() + order by 1 + limit 2 + ) t; +PREPARE local_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key = $1; +PREPARE remote_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key != $1; +BEGIN; + -- 8 local execution without params + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + -- 8 local execution without params and some subqueries + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + -- 8 local executions with params + EXECUTE local_prepare_param(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(5); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + EXECUTE local_prepare_param(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(5); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + -- followed by a non-local execution + EXECUTE remote_prepare_param(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) + count +--------------------------------------------------------------------- + 4 +(1 row) + +COMMIT; +PREPARE local_insert_prepare_no_param AS INSERT INTO distributed_table VALUES (1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; +PREPARE local_insert_prepare_param (int) AS INSERT INTO distributed_table VALUES ($1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; +BEGIN; + -- 8 local execution without params + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + -- 8 local executions with params + EXECUTE local_insert_prepare_param(1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 5 | 2928 | 22 | 6 | 292830 | 330 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 11 | 21 | 7 | 1130 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 5 | 2928 | 22 | 6 | 292830 | 330 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 2928 | 21 | 7 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 2928 | 21 | 7 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 2928 | 21 | 7 | 292830 | 315 +(1 row) + + -- followed by a non-local execution + EXECUTE remote_prepare_param(2); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) + count +--------------------------------------------------------------------- + 5 +(1 row) + +COMMIT; +PREPARE local_multi_row_insert_prepare_no_param AS + INSERT INTO distributed_table VALUES (1,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value; +PREPARE local_multi_row_insert_prepare_no_param_multi_shard AS + INSERT INTO distributed_table VALUES (6,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 AND key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; +PREPARE local_multi_row_insert_prepare_params(int,int) AS + INSERT INTO distributed_table VALUES ($1,'55', 21), ($2,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; +INSERT INTO reference_table VALUES (11); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (11) +BEGIN; + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(6,5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(5,1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(5,6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(5,1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + -- one task is remote + EXECUTE local_multi_row_insert_prepare_params(5,11); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +ROLLBACK; +-- make sure that we still get results if we switch off local execution +PREPARE ref_count_prepare AS SELECT count(*) FROM reference_table; +EXECUTE ref_count_prepare; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table + count +--------------------------------------------------------------------- + 7 +(1 row) + +EXECUTE ref_count_prepare; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table + count +--------------------------------------------------------------------- + 7 +(1 row) + +EXECUTE ref_count_prepare; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table + count +--------------------------------------------------------------------- + 7 +(1 row) + +EXECUTE ref_count_prepare; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table + count +--------------------------------------------------------------------- + 7 +(1 row) + +EXECUTE ref_count_prepare; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table + count +--------------------------------------------------------------------- + 7 +(1 row) + +SET citus.enable_local_execution TO off; +EXECUTE ref_count_prepare; + count +--------------------------------------------------------------------- + 7 +(1 row) + +RESET citus.enable_local_execution; +-- failures of local execution should rollback both the +-- local execution and remote executions +-- fail on a local execution +BEGIN; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 100 | 21 +(1 row) + + UPDATE distributed_table SET value = '200'; +NOTICE: executing the command locally: UPDATE local_shard_execution.distributed_table_1470001 distributed_table SET value = '200'::text +NOTICE: executing the command locally: UPDATE local_shard_execution.distributed_table_1470003 distributed_table SET value = '200'::text + INSERT INTO distributed_table VALUES (1, '100',21) ON CONFLICT(key) DO UPDATE SET value = (1 / (100.0 - EXCLUDED.value::int))::text RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '100'::text, 21) ON CONFLICT(key) DO UPDATE SET value = (((1)::numeric OPERATOR(pg_catalog./) (100.0 OPERATOR(pg_catalog.-) ((excluded.value)::integer)::numeric)))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age +ERROR: division by zero +ROLLBACK; +-- we've rollbacked everything +SELECT count(*) FROM distributed_table WHERE value = '200'; + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- RETURNING should just work fine for reference tables +INSERT INTO reference_table VALUES (500) RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (500) RETURNING key + key +--------------------------------------------------------------------- + 500 +(1 row) + +DELETE FROM reference_table WHERE key = 500 RETURNING *; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key + key +--------------------------------------------------------------------- + 500 +(1 row) + +-- should be able to skip local execution even if in a sequential mode of execution +BEGIN; + SET LOCAL citus.multi_shard_modify_mode TO sequential ; + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 11 | 21 +(1 row) + +ROLLBACK; +-- sequential execution should just work fine after a local execution +BEGIN; + SET citus.multi_shard_modify_mode TO sequential ; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 100 | 21 +(1 row) + + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table +ROLLBACK; +-- load some data so that foreign keys won't complain with the next tests +TRUNCATE reference_table CASCADE; +NOTICE: truncate cascades to table "distributed_table" +NOTICE: truncate cascades to table "second_distributed_table" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.reference_table_xxxxx CASCADE +NOTICE: truncate cascades to table "distributed_table_xxxxx" +NOTICE: truncate cascades to table "distributed_table_xxxxx" +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO distributed_table SELECT i, i::text, i % 10 + 25 FROM generate_series(500, 600) i; +NOTICE: executing the copy locally for shard xxxxx +NOTICE: executing the copy locally for shard xxxxx +-- show that both local, and mixed local-distributed executions +-- calculate rows processed correctly +BEGIN; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + DELETE FROM distributed_table WHERE value != '123123213123213'; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) +ROLLBACK; +BEGIN; + DELETE FROM reference_table WHERE key = 500 RETURNING *; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key + key +--------------------------------------------------------------------- + 500 +(1 row) + + DELETE FROM reference_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table +ROLLBACK; +BEGIN; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true + count +--------------------------------------------------------------------- + 100 +(1 row) + +ROLLBACK; +BEGIN; + SET LOCAL client_min_messages TO INFO; + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true + count +--------------------------------------------------------------------- + 101 +(1 row) + + SET LOCAL client_min_messages TO LOG; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) +ROLLBACK; +-- probably not a realistic case since views are not very +-- well supported with MX +SET citus.enable_ddl_propagation TO OFF; +CREATE VIEW v_local_query_execution AS +SELECT * FROM distributed_table WHERE key = 500; +RESET citus.enable_ddl_propagation; +SELECT * FROM v_local_query_execution; +NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) 500)) v_local_query_execution + key | value | age +--------------------------------------------------------------------- + 500 | 500 | 25 +(1 row) + +-- similar test, but this time the view itself is a non-local +-- query, but the query on the view is local +SET citus.enable_ddl_propagation TO OFF; +CREATE VIEW v_local_query_execution_2 AS +SELECT * FROM distributed_table; +RESET citus.enable_ddl_propagation; +SELECT * FROM v_local_query_execution_2 WHERE key = 500; +NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table) v_local_query_execution_2 WHERE (key OPERATOR(pg_catalog.=) 500) + key | value | age +--------------------------------------------------------------------- + 500 | 500 | 25 +(1 row) + +-- even if we switch from remote execution -> local execution, +-- we are able to use remote execution after rollback +BEGIN; + SAVEPOINT my_savepoint; + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true + count +--------------------------------------------------------------------- + 101 +(1 row) + + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + ROLLBACK TO SAVEPOINT my_savepoint; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) +COMMIT; +-- even if we switch from local execution -> remote execution, +-- we are able to use local execution after rollback +BEGIN; + SAVEPOINT my_savepoint; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true + count +--------------------------------------------------------------------- + 100 +(1 row) + + ROLLBACK TO SAVEPOINT my_savepoint; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) +COMMIT; +-- sanity check: local execution on partitions +INSERT INTO collections_list (collection_id) VALUES (0) RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('3940649673949185'::bigint, '3940649673949185'::bigint, 0) RETURNING key, ser, ts, collection_id, value + key | ser | ts | collection_id | value +--------------------------------------------------------------------- + 3940649673949185 | 3940649673949185 | | 0 | +(1 row) + +BEGIN; + INSERT INTO collections_list (key, collection_id) VALUES (1,0); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('1'::bigint, '3940649673949186'::bigint, 0) + SELECT count(*) FROM collections_list_0 WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_0_1470013 collections_list_0 WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + SELECT count(*) FROM collections_list; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_1470009 collections_list WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_1470011 collections_list WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + + SELECT * FROM collections_list ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution.collections_list_1470009 collections_list WHERE true +NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution.collections_list_1470011 collections_list WHERE true + key | ser | ts | collection_id | value +--------------------------------------------------------------------- + 1 | 3940649673949186 | | 0 | + 3940649673949185 | 3940649673949185 | | 0 | +(2 rows) + +COMMIT; +TRUNCATE collections_list; +-- make sure that even if local execution is used, the sequence values +-- are generated locally +SET citus.enable_ddl_propagation TO OFF; +ALTER SEQUENCE collections_list_key_seq NO MINVALUE NO MAXVALUE; +RESET citus.enable_ddl_propagation; +PREPARE serial_prepared_local AS INSERT INTO collections_list (collection_id) VALUES (0) RETURNING key, ser; +SELECT setval('collections_list_key_seq', 4); + setval +--------------------------------------------------------------------- + 4 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949187'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 5 | 3940649673949187 +(1 row) + +SELECT setval('collections_list_key_seq', 5); + setval +--------------------------------------------------------------------- + 5 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949188'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 6 | 3940649673949188 +(1 row) + +SELECT setval('collections_list_key_seq', 499); + setval +--------------------------------------------------------------------- + 499 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('500'::bigint, '3940649673949189'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 500 | 3940649673949189 +(1 row) + +SELECT setval('collections_list_key_seq', 700); + setval +--------------------------------------------------------------------- + 700 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('701'::bigint, '3940649673949190'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 701 | 3940649673949190 +(1 row) + +SELECT setval('collections_list_key_seq', 708); + setval +--------------------------------------------------------------------- + 708 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('709'::bigint, '3940649673949191'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 709 | 3940649673949191 +(1 row) + +SELECT setval('collections_list_key_seq', 709); + setval +--------------------------------------------------------------------- + 709 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('710'::bigint, '3940649673949192'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 710 | 3940649673949192 +(1 row) + +-- get ready for the next executions +DELETE FROM collections_list WHERE key IN (5,6); +SELECT setval('collections_list_key_seq', 4); + setval +--------------------------------------------------------------------- + 4 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949193'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 5 | 3940649673949193 +(1 row) + +SELECT setval('collections_list_key_seq', 5); + setval +--------------------------------------------------------------------- + 5 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949194'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 6 | 3940649673949194 +(1 row) + +-- and, one remote test +SELECT setval('collections_list_key_seq', 10); + setval +--------------------------------------------------------------------- + 10 +(1 row) + +EXECUTE serial_prepared_local; + key | ser +--------------------------------------------------------------------- + 11 | 3940649673949195 +(1 row) + +-- the final queries for the following CTEs are going to happen on the intermediate results only +-- one of them will be executed remotely, and the other is locally +-- Citus currently doesn't allow using task_assignment_policy for intermediate results +WITH distributed_local_mixed AS (INSERT INTO reference_table VALUES (1000) RETURNING *) SELECT * FROM distributed_local_mixed; +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (1000) RETURNING key +NOTICE: executing the command locally: SELECT key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed + key +--------------------------------------------------------------------- + 1000 +(1 row) + +-- clean the table for the next tests +SET search_path TO local_shard_execution; +TRUNCATE distributed_table CASCADE; +NOTICE: truncate cascades to table "second_distributed_table" +-- load some data on a remote shard +INSERT INTO reference_table (key) VALUES (1), (2); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1), (2) +INSERT INTO distributed_table (key) VALUES (2); +BEGIN; + -- local execution followed by a distributed query + INSERT INTO distributed_table (key) VALUES (1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key) VALUES (1) + DELETE FROM distributed_table RETURNING key; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table RETURNING key +NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table RETURNING key + key +--------------------------------------------------------------------- + 1 + 2 +(2 rows) + +COMMIT; +-- a similar test with a reference table +TRUNCATE reference_table CASCADE; +NOTICE: truncate cascades to table "distributed_table" +NOTICE: truncate cascades to table "second_distributed_table" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.reference_table_xxxxx CASCADE +NOTICE: truncate cascades to table "distributed_table_xxxxx" +NOTICE: truncate cascades to table "distributed_table_xxxxx" +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE +NOTICE: truncate cascades to table "second_distributed_table_xxxxx" +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE +-- load some data on a remote shard +INSERT INTO reference_table (key) VALUES (2); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (2) +BEGIN; + -- local execution followed by a distributed query + INSERT INTO reference_table (key) VALUES (1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (1) + DELETE FROM reference_table RETURNING key; +NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table RETURNING key + key +--------------------------------------------------------------------- + 1 + 2 +(2 rows) + +COMMIT; +-- however complex the query, local execution can handle +SET client_min_messages TO LOG; +SET citus.log_local_commands TO ON; +WITH cte_1 AS + (SELECT * + FROM + (WITH cte_1 AS + (SELECT * + FROM distributed_table + WHERE key = 1) SELECT * + FROM cte_1) AS foo) +SELECT count(*) +FROM cte_1 +JOIN distributed_table USING (key) +WHERE distributed_table.key = 1 + AND distributed_table.key IN + (SELECT key + FROM distributed_table + WHERE key = 1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((SELECT foo.key, foo.value, foo.age FROM (SELECT cte_1_1.key, cte_1_1.value, cte_1_1.age FROM (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) cte_1_1) foo) cte_1 JOIN local_shard_execution.distributed_table_1470001 distributed_table(key, value, age) USING (key)) WHERE ((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table_1.key FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +RESET client_min_messages; +RESET citus.log_local_commands; +\c - - - :master_port +SET citus.next_shard_id TO 1480000; +-- test both local and remote execution with custom type +SET citus.shard_replication_factor TO 1; +CREATE TYPE invite_resp AS ENUM ('yes', 'no', 'maybe'); +CREATE TABLE event_responses ( + event_id int, + user_id int, + response invite_resp, + primary key (event_id, user_id) +); +SELECT create_distributed_table('event_responses', 'event_id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO event_responses VALUES (1, 1, 'yes'), (2, 2, 'yes'), (3, 3, 'no'), (4, 4, 'no'); +CREATE TABLE event_responses_no_pkey ( + event_id int, + user_id int, + response invite_resp +); +SELECT create_distributed_table('event_responses_no_pkey', 'event_id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE OR REPLACE FUNCTION regular_func(p invite_resp) +RETURNS int AS $$ +DECLARE + q1Result INT; + q2Result INT; + q3Result INT; +BEGIN +SELECT count(*) INTO q1Result FROM event_responses WHERE response = $1; +SELECT count(*) INTO q2Result FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1; +SELECT count(*) INTO q3Result FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo; +RETURN q3Result+q2Result+q1Result; +END; +$$ LANGUAGE plpgsql; +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +CREATE OR REPLACE PROCEDURE regular_procedure(p invite_resp) +AS $$ +BEGIN +PERFORM * FROM event_responses WHERE response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC; +PERFORM * FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC; +PERFORM * FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo ORDER BY 1 DESC, 2 DESC, 3 DESC; +END; +$$ LANGUAGE plpgsql; +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +PREPARE multi_shard_no_dist_key(invite_resp) AS select * from event_responses where response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +PREPARE multi_shard_with_dist_key(int, invite_resp) AS select * from event_responses where event_id > $1 AND response = $2::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +PREPARE query_pushdown_no_dist_key(invite_resp) AS select * from event_responses e1 LEFT JOIN event_responses e2 USING(event_id) where e1.response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC LIMIT 1; +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +PREPARE insert_select_via_coord(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp LIMIT 1 ON CONFLICT (event_id, user_id) DO NOTHING ; +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +PREPARE insert_select_pushdown(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp ON CONFLICT (event_id, user_id) DO NOTHING; +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +PREPARE router_select_with_no_dist_key_filter(invite_resp) AS select * from event_responses where event_id = 1 AND response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +-- rest of the tests assume the table is empty +TRUNCATE event_responses; +CREATE OR REPLACE PROCEDURE register_for_event(p_event_id int, p_user_id int, p_choice invite_resp) +LANGUAGE plpgsql AS $fn$ +BEGIN + INSERT INTO event_responses VALUES (p_event_id, p_user_id, p_choice) + ON CONFLICT (event_id, user_id) + DO UPDATE SET response = EXCLUDED.response; + + PERFORM count(*) FROM event_responses WHERE event_id = p_event_id; + + PERFORM count(*) FROM event_responses WHERE event_id = p_event_id AND false; + + UPDATE event_responses SET response = p_choice WHERE event_id = p_event_id; + +END; +$fn$; +SELECT create_distributed_function('register_for_event(int,int,invite_resp)', 'p_event_id', 'event_responses'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- call 8 times to make sure it works after the 5th time(postgres binds values after the 5th time and Citus 2nd time) +-- after 6th, the local execution caches the local plans and uses it +-- execute it both locally and remotely +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +\c - - - :worker_2_port +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +-- values 16, 17 and 19 hits the same +-- shard, so we're re-using the same cached +-- plans per statement across different distribution +-- key values +CALL register_for_event(17, 1, 'yes'); +CALL register_for_event(19, 1, 'yes'); +CALL register_for_event(17, 1, 'yes'); +CALL register_for_event(19, 1, 'yes'); +-- should work fine if the logs are enabled +\set VERBOSITY terse +SET citus.log_local_commands TO ON; +SET client_min_messages TO DEBUG2; +CALL register_for_event(19, 1, 'yes'); +DEBUG: not pushing down procedure to the same node +NOTICE: executing the command locally: INSERT INTO public.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (19, 1, 'yes'::public.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response +NOTICE: executing the command locally: SELECT count(*) AS count FROM public.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 19) +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT NULL::integer AS event_id, NULL::integer AS user_id, NULL::public.invite_resp AS response WHERE false) event_responses(event_id, user_id, response) WHERE ((event_id OPERATOR(pg_catalog.=) 19) AND false) +NOTICE: executing the command locally: UPDATE public.event_responses_1480001 event_responses SET response = 'yes'::public.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 19) +-- should be fine even if no parameters exists in the query +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: SELECT count(*) AS count FROM public.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: SELECT count(*) AS count FROM public.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) + count +--------------------------------------------------------------------- + 1 +(1 row) + +UPDATE event_responses SET response = 'no' WHERE event_id = 16; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: UPDATE public.event_responses_1480001 event_responses SET response = 'no'::public.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 16) +INSERT INTO event_responses VALUES (16, 666, 'maybe') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: INSERT INTO public.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (16, 666, 'maybe'::public.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe +(1 row) + +-- multi row INSERTs hitting the same shard +INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan +NOTICE: executing the command locally: INSERT INTO public.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (16,666,'maybe'::public.invite_resp), (17,777,'no'::public.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe + 17 | 777 | no +(2 rows) + +-- now, similar tests with some settings changed +SET citus.enable_local_execution TO false; +SET citus.enable_fast_path_router_planner TO false; +CALL register_for_event(19, 1, 'yes'); +DEBUG: not pushing down procedure to the same node +-- should be fine even if no parameters exists in the query +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 + count +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 + count +--------------------------------------------------------------------- + 2 +(1 row) + +UPDATE event_responses SET response = 'no' WHERE event_id = 16; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +INSERT INTO event_responses VALUES (16, 666, 'maybe') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe +(1 row) + +-- multi row INSERTs hitting the same shard +INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe + 17 | 777 | no +(2 rows) + +-- set back to sane settings +RESET citus.enable_local_execution; +RESET citus.enable_fast_path_router_planner; +-- we'll test some 2PC states +SET citus.enable_metadata_sync TO OFF; +-- coordinated_transaction_should_use_2PC prints the internal +-- state for 2PC decision on Citus. However, even if 2PC is decided, +-- we may not necessarily use 2PC over a connection unless it does +-- a modification +CREATE OR REPLACE FUNCTION coordinated_transaction_should_use_2PC() +RETURNS BOOL LANGUAGE C STRICT VOLATILE AS 'citus', +$$coordinated_transaction_should_use_2PC$$; +-- make tests consistent +SET citus.max_adaptive_executor_pool_size TO 1; +RESET citus.enable_metadata_sync; +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +SET citus.log_remote_commands TO ON; +-- we use event_id = 2 for local execution and event_id = 1 for reemote execution +--show it here, if anything changes here, all the tests below might be broken +-- we prefer this to avoid excessive logging below +SELECT * FROM event_responses_no_pkey WHERE event_id = 2; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 2 +NOTICE: executing the command locally: SELECT event_id, user_id, response FROM public.event_responses_no_pkey_1480007 event_responses_no_pkey WHERE (event_id OPERATOR(pg_catalog.=) 2) + event_id | user_id | response +--------------------------------------------------------------------- +(0 rows) + +SELECT * FROM event_responses_no_pkey WHERE event_id = 1; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 1 +NOTICE: issuing SELECT event_id, user_id, response FROM public.event_responses_no_pkey_1480004 event_responses_no_pkey WHERE (event_id OPERATOR(pg_catalog.=) 1) + event_id | user_id | response +--------------------------------------------------------------------- +(0 rows) + +RESET citus.log_remote_commands; +RESET citus.log_local_commands; +RESET client_min_messages; +-- single shard local command without transaction block does set the +-- internal state for 2PC, but does not require any actual entries +WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *) +SELECT coordinated_transaction_should_use_2PC() FROM cte_1; + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + t +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- two local commands without transaction block set the internal 2PC state +-- but does not use remotely +WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *), + cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + t +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard local modification followed by another single shard +-- local modification sets the 2PC state, but does not use remotely +BEGIN; + INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + + INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + t +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard local modification followed by a single shard +-- remote modification uses 2PC because multiple nodes involved +-- in the modification +BEGIN; + INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + + INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 2 | yes +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + t +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard local modification followed by a single shard +-- remote modification uses 2PC even if it is not in an explicit +-- tx block as multiple nodes involved in the modification +WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *), + cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + t +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard remote modification followed by a single shard +-- local modification uses 2PC as multiple nodes involved +-- in the modification +BEGIN; + INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 2 | yes +(1 row) + + INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + t +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard remote modification followed by a single shard +-- local modification uses 2PC even if it is not in an explicit +-- tx block +WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *), + cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + t +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard local SELECT command without transaction block does not set the +-- internal state for 2PC +WITH cte_1 AS (SELECT * FROM event_responses_no_pkey WHERE event_id = 2) +SELECT coordinated_transaction_should_use_2PC() FROM cte_1; +ERROR: The transaction is not a coordinated transaction +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- two local SELECT commands without transaction block does not set the internal 2PC state +-- and does not use remotely +WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2), + cte_2 AS (SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2) +SELECT count(*) FROM cte_1, cte_2; + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- two local SELECT commands without transaction block does not set the internal 2PC state +-- and does not use remotely +BEGIN; + SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; + count +--------------------------------------------------------------------- + 9 +(1 row) + + SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; + count +--------------------------------------------------------------------- + 9 +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + f +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- a local SELECT followed by a remote SELECT does not require to +-- use actual 2PC +BEGIN; + SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; + count +--------------------------------------------------------------------- + 9 +(1 row) + + SELECT count(*) FROM event_responses_no_pkey; + count +--------------------------------------------------------------------- + 13 +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard local SELECT followed by a single shard +-- remote modification does not use 2PC, because only a single +-- machine involved in the modification +BEGIN; + SELECT * FROM event_responses_no_pkey WHERE event_id = 2; + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes + 2 | 2 | yes + 2 | 2 | yes + 2 | 2 | yes + 2 | 2 | yes + 2 | 2 | yes + 2 | 2 | yes + 2 | 2 | yes + 2 | 2 | yes +(9 rows) + + INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 2 | yes +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + f +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard local SELECT followed by a single shard +-- remote modification does not use 2PC, because only a single +-- machine involved in the modification +WITH cte_1 AS (SELECT * FROM event_responses_no_pkey WHERE event_id = 2), + cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + f +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard remote modification followed by a single shard +-- local SELECT does not use 2PC, because only a single +-- machine involved in the modification +BEGIN; + INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 2 | yes +(1 row) + + SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; + count +--------------------------------------------------------------------- + 9 +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + f +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard remote modification followed by a single shard +-- local SELECT does not use 2PC, because only a single +-- machine involved in the modification +WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *), + cte_2 AS (SELECT * FROM event_responses_no_pkey WHERE event_id = 2) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + f +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- multi shard local SELECT command without transaction block does not set the +-- internal state for 2PC +WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey) +SELECT coordinated_transaction_should_use_2PC() FROM cte_1; + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + f +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- two multi-shard SELECT commands without transaction block does not set the internal 2PC state +-- and does not use remotely +WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey), + cte_2 AS (SELECT count(*) FROM event_responses_no_pkey) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + f +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- two multi-shard SELECT commands without transaction block does not set the internal 2PC state +-- and does not use remotely +BEGIN; + SELECT count(*) FROM event_responses_no_pkey; + count +--------------------------------------------------------------------- + 17 +(1 row) + + SELECT count(*) FROM event_responses_no_pkey; + count +--------------------------------------------------------------------- + 17 +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + f +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- multi-shard shard SELECT followed by a single shard +-- remote modification does not use 2PC, because only a single +-- machine involved in the modification +BEGIN; + SELECT count(*) FROM event_responses_no_pkey; + count +--------------------------------------------------------------------- + 17 +(1 row) + + INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 2 | yes +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + f +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- multi shard SELECT followed by a single shard +-- remote single shard modification does not use 2PC, because only a single +-- machine involved in the modification +WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey), + cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + f +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard remote modification followed by a multi shard +-- SELECT does not use 2PC, because only a single +-- machine involved in the modification +BEGIN; + INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 2 | yes +(1 row) + + SELECT count(*) FROM event_responses_no_pkey; + count +--------------------------------------------------------------------- + 20 +(1 row) + + SELECT coordinated_transaction_should_use_2PC(); + coordinated_transaction_should_use_2pc +--------------------------------------------------------------------- + f +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard remote modification followed by a multi shard +-- SELECT does not use 2PC, because only a single +-- machine involved in the modification +WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *), + cte_2 AS (SELECT count(*) FROM event_responses_no_pkey) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + f +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- single shard local modification followed by remote multi-shard +-- modification uses 2PC as multiple nodes are involved in modifications +WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *), + cte_2 AS (UPDATE event_responses_no_pkey SET user_id = 1000 RETURNING *) +SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; + bool_or +--------------------------------------------------------------------- + t +(1 row) + +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- a local SELECT followed by a remote multi-shard UPDATE requires to +-- use actual 2PC as multiple nodes are involved in modifications +BEGIN; + SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; + count +--------------------------------------------------------------------- + 10 +(1 row) + + UPDATE event_responses_no_pkey SET user_id = 1; +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- a local SELECT followed by a remote single-shard UPDATE does not require to +-- use actual 2PC. This is because a single node is involved in modification +BEGIN; + SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; + count +--------------------------------------------------------------------- + 10 +(1 row) + + UPDATE event_responses_no_pkey SET user_id = 1 WHERE event_id = 1; +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +-- a remote single-shard UPDATE followed by a local single shard SELECT +-- does not require to use actual 2PC. This is because a single node +-- is involved in modification +BEGIN; + UPDATE event_responses_no_pkey SET user_id = 1 WHERE event_id = 1; + SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; + count +--------------------------------------------------------------------- + 10 +(1 row) + +COMMIT; +SELECT count(*) FROM pg_dist_transaction; + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT recover_prepared_transactions(); + recover_prepared_transactions +--------------------------------------------------------------------- + 0 +(1 row) + +\c - - - :master_port +-- verify the local_hostname guc is used for local executions that should connect to the +-- local host +ALTER SYSTEM SET citus.local_hostname TO 'foobar'; +SELECT pg_reload_conf(); + pg_reload_conf +--------------------------------------------------------------------- + t +(1 row) + +SELECT pg_sleep(0.1); -- wait to make sure the config has changed before running the GUC + pg_sleep +--------------------------------------------------------------------- + +(1 row) + +SET citus.enable_local_execution TO false; -- force a connection to the dummy placements +-- run queries that use dummy placements for local execution +SELECT * FROM event_responses WHERE FALSE; +ERROR: connection to the remote node foobar:57636 failed with the following error: could not translate host name "foobar" to address: +WITH cte_1 AS (SELECT * FROM event_responses LIMIT 1) SELECT count(*) FROM cte_1; +ERROR: connection to the remote node foobar:57636 failed with the following error: could not translate host name "foobar" to address: +ALTER SYSTEM RESET citus.local_hostname; +SELECT pg_reload_conf(); + pg_reload_conf +--------------------------------------------------------------------- + t +(1 row) + +SELECT pg_sleep(.1); -- wait to make sure the config has changed before running the GUC + pg_sleep +--------------------------------------------------------------------- + +(1 row) + +SET client_min_messages TO ERROR; +SET search_path TO public; +DROP SCHEMA local_shard_execution CASCADE; diff --git a/src/test/regress/expected/local_shard_execution_replicated.out b/src/test/regress/expected/local_shard_execution_replicated.out index 200b99872..5bc734cfb 100644 --- a/src/test/regress/expected/local_shard_execution_replicated.out +++ b/src/test/regress/expected/local_shard_execution_replicated.out @@ -1,3 +1,12 @@ +-- +-- LOCAL_SHARD_EXECUTION_REPLICATED +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA local_shard_execution_replicated; SET search_path TO local_shard_execution_replicated; SET citus.shard_count TO 4; @@ -225,7 +234,7 @@ RETURNING *; INSERT INTO distributed_table SELECT * FROM distributed_table WHERE key = 1 OFFSET 0 ON CONFLICT DO NOTHING; NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 NOTICE: executing the copy locally for colocated file with shard xxxxx -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) SELECT key, value, age FROM read_intermediate_result('insert_select_XXX_1500001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint) ON CONFLICT DO NOTHING +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('insert_select_XXX_1500001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint) ON CONFLICT DO NOTHING INSERT INTO distributed_table SELECT 1, '1',15 FROM distributed_table WHERE key = 2 LIMIT 1 ON CONFLICT DO NOTHING; NOTICE: executing the command locally: SELECT 1 AS key, '1'::text AS value, int8(15) AS age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.=) 2) LIMIT 1 -- sanity check: multi-shard INSERT..SELECT pushdown goes through distributed execution @@ -764,8 +773,8 @@ NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_r NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500002_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500002_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500003_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500004_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500004_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500004_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key) SELECT intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key) SELECT intermediate_result.key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500004_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) SELECT count(*) FROM distributed_table WHERE key = -6; NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) '-6'::integer) count diff --git a/src/test/regress/expected/local_shard_execution_replicated_0.out b/src/test/regress/expected/local_shard_execution_replicated_0.out new file mode 100644 index 000000000..09e4278bf --- /dev/null +++ b/src/test/regress/expected/local_shard_execution_replicated_0.out @@ -0,0 +1,2456 @@ +-- +-- LOCAL_SHARD_EXECUTION_REPLICATED +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +CREATE SCHEMA local_shard_execution_replicated; +SET search_path TO local_shard_execution_replicated; +SET citus.shard_count TO 4; +SET citus.shard_replication_factor TO 2; +SET citus.next_shard_id TO 1500000; +CREATE TABLE reference_table (key int PRIMARY KEY); +SELECT create_reference_table('reference_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_table (key int PRIMARY KEY , value text, age bigint CHECK (age > 10)); +SELECT create_distributed_table('distributed_table','key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE second_distributed_table (key int PRIMARY KEY , value text); +SELECT create_distributed_table('second_distributed_table','key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- ingest some data to enable some tests with data +INSERT INTO distributed_table VALUES (1, '1', 20); +-- This GUC prevents to acquire the remote lock for replicated +-- tables +BEGIN; + SET LOCAL citus.allow_modifications_from_workers_to_replicated_tables TO false; + INSERT INTO second_distributed_table VALUES (1, '1'); + INSERT INTO reference_table VALUES (1); +COMMIT; +-- a simple test for +CREATE TABLE collections_list ( + key bigserial, + ser bigserial, + ts timestamptz, + collection_id integer, + value numeric, + PRIMARY KEY(key, collection_id) +) PARTITION BY LIST (collection_id ); +SELECT create_distributed_table('collections_list', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE collections_list_0 + PARTITION OF collections_list (key, ser, ts, collection_id, value) + FOR VALUES IN ( 0 ); +-- create a volatile function that returns the local node id +CREATE OR REPLACE FUNCTION get_local_node_id_volatile() +RETURNS INT AS $$ +DECLARE localGroupId int; +BEGIN + SELECT groupid INTO localGroupId FROM pg_dist_local_group; + RETURN localGroupId; +END; $$ language plpgsql VOLATILE; +SELECT create_distributed_function('get_local_node_id_volatile()'); +NOTICE: procedure local_shard_execution_replicated.get_local_node_id_volatile is already distributed +DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- test case for issue #3556 +CREATE TABLE accounts (id text PRIMARY KEY); +CREATE TABLE stats (account_id text PRIMARY KEY, spent int); +SELECT create_distributed_table('accounts', 'id', colocate_with => 'none'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_table('stats', 'account_id', colocate_with => 'accounts'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO accounts (id) VALUES ('foo'); +INSERT INTO stats (account_id, spent) VALUES ('foo', 100); +CREATE TABLE abcd(a int, b int, c int, d int); +SELECT create_distributed_table('abcd', 'b'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO abcd VALUES (1,2,3,4); +INSERT INTO abcd VALUES (2,3,4,5); +INSERT INTO abcd VALUES (3,4,5,6); +ALTER TABLE abcd DROP COLUMN a; +-- connection worker and get ready for the tests +\c - - - :worker_1_port +SET search_path TO local_shard_execution_replicated; +-- test case for issue #3556 +SET citus.log_intermediate_results TO TRUE; +SET client_min_messages TO DEBUG1; +SELECT * +FROM +( + WITH accounts_cte AS ( + SELECT id AS account_id + FROM accounts + ), + joined_stats_cte_1 AS ( + SELECT spent, account_id + FROM stats + INNER JOIN accounts_cte USING (account_id) + ), + joined_stats_cte_2 AS ( + SELECT spent, account_id + FROM joined_stats_cte_1 + INNER JOIN accounts_cte USING (account_id) + ) + SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) + FROM accounts_cte + INNER JOIN joined_stats_cte_2 USING (account_id) +) inner_query; +DEBUG: CTE joined_stats_cte_1 is going to be inlined via distributed planning +DEBUG: CTE joined_stats_cte_2 is going to be inlined via distributed planning +DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM local_shard_execution_replicated.accounts +DEBUG: generating subplan XXX_2 for subquery SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT stats.spent, stats.account_id FROM (local_shard_execution_replicated.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_2 USING (account_id))) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_1 USING (account_id))) joined_stats_cte_2 USING (account_id)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT intermediate_result.sum FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(sum bigint)) inner_query +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file + sum +--------------------------------------------------------------------- + 100 +(1 row) + +SET citus.log_intermediate_results TO DEFAULT; +SET client_min_messages TO DEFAULT; +--- enable logging to see which tasks are executed locally +SET citus.log_local_commands TO ON; +-- first, make sure that local execution works fine +-- with simple queries that are not in transcation blocks +SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- multiple tasks both of which are local should NOT use local execution +-- because local execution means executing the tasks locally, so the executor +-- favors parallel execution even if everyting is local to node +SELECT count(*) FROM distributed_table WHERE key IN (1,6); + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- queries that hit any remote shards should NOT use local execution +SELECT count(*) FROM distributed_table WHERE key IN (1,11); + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM distributed_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- modifications also follow the same rules +INSERT INTO reference_table VALUES (1) ON CONFLICT DO NOTHING; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 AS citus_table_alias (key) VALUES (1) ON CONFLICT DO NOTHING +INSERT INTO distributed_table VALUES (1, '1', 21) ON CONFLICT DO NOTHING; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '1'::text, 21) ON CONFLICT DO NOTHING +-- local query +DELETE FROM distributed_table WHERE key = 1 AND age = 21; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 21)) +-- hitting multiple shards, so should be a distributed execution +DELETE FROM distributed_table WHERE age = 21; +-- although both shards are local, the executor choose the parallel execution +-- over the wire because as noted above local execution is sequential +DELETE FROM second_distributed_table WHERE key IN (1,6); +-- similarly, any multi-shard query just follows distributed execution +DELETE FROM second_distributed_table; +-- load some more data for the following tests +INSERT INTO second_distributed_table VALUES (1, '1'); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.second_distributed_table_1500005 (key, value) VALUES (1, '1'::text) +-- INSERT .. SELECT hitting a single single (co-located) shard(s) should +-- be executed locally +INSERT INTO distributed_table +SELECT + distributed_table.* +FROM + distributed_table, second_distributed_table +WHERE + distributed_table.key = 1 and distributed_table.key=second_distributed_table.key +ON CONFLICT(key) DO UPDATE SET value = '22' +RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE (((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) second_distributed_table.key)) AND (distributed_table.key IS NOT NULL)) ON CONFLICT(key) DO UPDATE SET value = '22'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 22 | 20 +(1 row) + +-- INSERT .. SELECT hitting multi-shards should go thourgh distributed execution +INSERT INTO distributed_table +SELECT + distributed_table.* +FROM + distributed_table, second_distributed_table +WHERE + distributed_table.key != 1 and distributed_table.key=second_distributed_table.key +ON CONFLICT(key) DO UPDATE SET value = '22' +RETURNING *; + key | value | age +--------------------------------------------------------------------- +(0 rows) + +-- INSERT..SELECT via coordinator consists of two steps, select + COPY +-- that's why it is disallowed to use local execution even if the SELECT +-- can be executed locally +INSERT INTO distributed_table SELECT * FROM distributed_table WHERE key = 1 OFFSET 0 ON CONFLICT DO NOTHING; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +NOTICE: executing the copy locally for colocated file with shard xxxxx +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) SELECT key, value, age FROM read_intermediate_result('insert_select_XXX_1500001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint) ON CONFLICT DO NOTHING +INSERT INTO distributed_table SELECT 1, '1',15 FROM distributed_table WHERE key = 2 LIMIT 1 ON CONFLICT DO NOTHING; +NOTICE: executing the command locally: SELECT 1 AS key, '1'::text AS value, int8(15) AS age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.=) 2) LIMIT 1 +-- sanity check: multi-shard INSERT..SELECT pushdown goes through distributed execution +INSERT INTO distributed_table SELECT * FROM distributed_table ON CONFLICT DO NOTHING; +-- Ensure tuple data in explain analyze output is the same on all PG versions +SET citus.enable_binary_protocol = TRUE; +-- EXPLAIN for local execution just works fine +-- though going through distributed execution +EXPLAIN (COSTS OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table + Index Cond: (key = 1) + Filter: (age = 20) +(8 rows) + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 1 + Tuple data received from nodes: 14 bytes + Tasks Shown: All + -> Task + Tuple data received from node: 14 bytes + Node: host=localhost port=xxxxx dbname=regression + -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table (actual rows=1 loops=1) + Index Cond: (key = 1) + Filter: (age = 20) +(10 rows) + +EXPLAIN (ANALYZE ON, COSTS OFF, SUMMARY OFF, TIMING OFF) +WITH r AS ( SELECT GREATEST(random(), 2) z,* FROM distributed_table) +SELECT 1 FROM r WHERE z < 3; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + -> Distributed Subplan XXX_1 + Intermediate Data Size: 40 bytes + Result destination: Write locally + -> Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 4 + Tuple data received from nodes: 22 bytes + Tasks Shown: One of 4 + -> Task + Tuple data received from node: 22 bytes + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on distributed_table_1500001 distributed_table (actual rows=1 loops=1) + Task Count: 1 + Tuple data received from nodes: 4 bytes + Tasks Shown: All + -> Task + Tuple data received from node: 4 bytes + Node: host=localhost port=xxxxx dbname=regression + -> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1) + Filter: (z < '3'::double precision) +(20 rows) + +EXPLAIN (COSTS OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Delete on distributed_table_1500001 distributed_table + -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table + Index Cond: (key = 1) + Filter: (age = 20) +(9 rows) + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus Adaptive) (actual rows=0 loops=1) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Delete on distributed_table_1500001 distributed_table (actual rows=0 loops=1) + -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table (actual rows=1 loops=1) + Index Cond: (key = 1) + Filter: (age = 20) +(9 rows) + +-- show that EXPLAIN ANALYZE deleted the row +SELECT * FROM distributed_table WHERE key = 1 AND age = 20 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 20)) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- +(0 rows) + +SELECT * FROM second_distributed_table WHERE key = 1 ORDER BY 1,2; +NOTICE: executing the command locally: SELECT key, value FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value + key | value +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +-- Put row back for other tests +INSERT INTO distributed_table VALUES (1, '22', 20); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 (key, value, age) VALUES (1, '22'::text, 20) +SET citus.enable_ddl_propagation TO OFF; +CREATE VIEW abcd_view AS SELECT * FROM abcd; +RESET citus.enable_ddl_propagation; +SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +BEGIN; +SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500025 first JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500026 first JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500027 first JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500028 first JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd_view first join abcd_view second on first.b = second.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500025 abcd JOIN local_shard_execution_replicated.abcd_1500025 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true +NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500026 abcd JOIN local_shard_execution_replicated.abcd_1500026 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true +NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500027 abcd JOIN local_shard_execution_replicated.abcd_1500027 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true +NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500028 abcd JOIN local_shard_execution_replicated.abcd_1500028 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd first full join abcd second on first.b = second.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500025 first FULL JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500026 first FULL JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500027 first FULL JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500028 first FULL JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery + b | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd first join abcd second USING(b) ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500025 first JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500026 first JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500027 first JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500028 first JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true + b | c | d | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 3 | 4 + 3 | 4 | 5 | 4 | 5 + 4 | 5 | 6 | 5 | 6 +(3 rows) + +END; +BEGIN; +SELECT * FROM abcd first join abcd second USING(b) join abcd third on first.b=third.b ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500025 first JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500025 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500026 first JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500026 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500027 first JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500027 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true +NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500028 first JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500028 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true + b | c | d | c | d | b | c | d +--------------------------------------------------------------------- + 2 | 3 | 4 | 3 | 4 | 2 | 3 | 4 + 3 | 4 | 5 | 4 | 5 | 3 | 4 | 5 + 4 | 5 | 6 | 5 | 6 | 4 | 5 | 6 +(3 rows) + +END; +-- copy always happens via distributed execution irrespective of the +-- shards that are accessed +COPY reference_table FROM STDIN; +COPY distributed_table FROM STDIN WITH CSV; +COPY second_distributed_table FROM STDIN WITH CSV; +-- the behaviour in transaction blocks is the following: + -- (a) Unless the first query is a local query, always use distributed execution. + -- (b) If the executor has used local execution, it has to use local execution + -- for the remaining of the transaction block. If that's not possible, the + -- executor has to error out +-- rollback should be able to rollback local execution +BEGIN; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 29 | 20 +(1 row) + + SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 29 | 20 +(1 row) + +ROLLBACK; +-- make sure that the value is rollbacked +SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 22 | 20 +(1 row) + +-- rollback should be able to rollback both the local and distributed executions +BEGIN; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 29 | 20 +(1 row) + + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table + SELECT count(*) FROM second_distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500006 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500007 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500008 second_distributed_table WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + +ROLLBACK; +-- make sure that everything is rollbacked +SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 22 | 20 +(1 row) + +SELECT count(*) FROM second_distributed_table; + count +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT * FROM second_distributed_table; + key | value +--------------------------------------------------------------------- + 1 | 1 + 6 | '6' +(2 rows) + +-- very simple examples, an SELECTs should see the modifications +-- that has done before +BEGIN; + -- INSERT is executed locally + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '23' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '23'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 23 | 20 +(1 row) + + -- since the INSERT is executed locally, the SELECT should also be + -- executed locally and see the changes + SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- + 1 | 23 | 20 +(1 row) + + -- multi-shard SELECTs are now forced to use local execution on + -- the shards that reside on this node + SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) + key | value | age +--------------------------------------------------------------------- + 1 | 23 | 20 +(1 row) + + -- similarly, multi-shard modifications should use local exection + -- on the shards that reside on this node + DELETE FROM distributed_table WHERE value = '23'; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) + -- make sure that the value is deleted + SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) + key | value | age +--------------------------------------------------------------------- +(0 rows) + +COMMIT; +-- make sure that we've committed everything +SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- +(0 rows) + +-- if we start with a distributed execution, we should keep +-- using that and never switch back to local execution +BEGIN; + DELETE FROM distributed_table WHERE value = '11'; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) + -- although this command could have been executed + -- locally, it is not going to be executed locally + SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age + key | value | age +--------------------------------------------------------------------- +(0 rows) + + -- but we can still execute parallel queries, even if + -- they are utility commands + TRUNCATE distributed_table CASCADE; +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE + -- TRUNCATE didn't cascade into second_distributed_table + SELECT count(*) FROM second_distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500006 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500007 second_distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500008 second_distributed_table WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + +ROLLBACK; +-- load some data +INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; +NOTICE: executing the copy locally for shard xxxxx +-- show that complex tx blocks work fine +BEGIN; + INSERT INTO reference_table VALUES (701); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (701) + INSERT INTO distributed_table VALUES (701, '701', 701); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 (key, value, age) VALUES (701, '701'::text, 701) + INSERT INTO second_distributed_table VALUES (701, '701'); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.second_distributed_table_1500005 (key, value) VALUES (701, '701'::text) + DELETE FROM reference_table WHERE key = 701; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) 701) + SELECT count(*) FROM distributed_table WHERE key = 701; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) + count +--------------------------------------------------------------------- + 1 +(1 row) + + SELECT count(*) FROM second_distributed_table WHERE key = 701; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) + count +--------------------------------------------------------------------- + 1 +(1 row) + + -- multi-shard commands should also see the changes + SELECT count(*) FROM distributed_table WHERE key > 700; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) + count +--------------------------------------------------------------------- + 1 +(1 row) + + -- we can still do multi-shard commands + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table +ROLLBACK; +-- multiple queries hitting different shards can be executed locally +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + + SELECT count(*) FROM distributed_table WHERE key = 6; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 1 +(1 row) + + SELECT count(*) FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +-- a local query followed by TRUNCATE command can be executed locally +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + + TRUNCATE distributed_table CASCADE; +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +ROLLBACK; +-- a local query is followed by an INSERT..SELECT via the coordinator +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + + INSERT INTO distributed_table (key) SELECT i FROM generate_series(1,1) i; +NOTICE: executing the copy locally for shard xxxxx +ROLLBACK; +BEGIN; +SET citus.enable_repartition_joins TO ON; +SET citus.enable_unique_job_ids TO off; +SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT count(*) FROM distributed_table d1 join distributed_table d2 using(age); +NOTICE: executing the command locally: SELECT partition_index, 'repartition_64_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_64_1','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500001 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartition_64_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_64_3','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500003 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartition_65_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_65_1','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500001 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartition_65_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_65_3','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500003 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_1_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_2_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_3_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_4_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_0']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_1_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_2_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_3_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_4_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_1']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_1']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_1_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_2_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_3_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_4_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_2']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_2']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_1_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_2_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_3_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_64_4_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_1_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_2_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_3_3']::text[],'localhost',57637) bytes +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_65_4_3']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_64_1_0,repartition_64_2_0,repartition_64_3_0,repartition_64_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_65_1_0,repartition_65_2_0,repartition_65_3_0,repartition_65_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_64_1_1,repartition_64_2_1,repartition_64_3_1,repartition_64_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_65_1_1,repartition_65_2_1,repartition_65_3_1,repartition_65_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_64_1_2,repartition_64_2_2,repartition_64_3_2,repartition_64_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_65_1_2,repartition_65_2_2,repartition_65_3_2,repartition_65_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_64_1_3,repartition_64_2_3,repartition_64_3_3,repartition_64_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_65_1_3,repartition_65_2_3,repartition_65_3_3,repartition_65_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + +ROLLBACK; +-- a local query is followed by an INSERT..SELECT with re-partitioning +BEGIN; + SELECT count(*) FROM distributed_table WHERE key = 6; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 1 +(1 row) + + INSERT INTO reference_table (key) SELECT -key FROM distributed_table; +NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true +NOTICE: executing the copy locally for shard xxxxx + INSERT INTO distributed_table (key) SELECT -key FROM distributed_table; +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500001_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500001_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500002_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500002_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500003_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500004_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500004_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500004_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) + SELECT count(*) FROM distributed_table WHERE key = -6; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) '-6'::integer) + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 11 | 21 +(1 row) + +BEGIN; + DELETE FROM distributed_table WHERE key = 1; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + EXPLAIN ANALYZE DELETE FROM distributed_table WHERE key = 1; +ERROR: cannot execute command because a local execution has accessed a placement in the transaction +DETAIL: Some parallel commands cannot be executed if a previous command has already been executed locally +HINT: Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;" +ROLLBACK; +BEGIN; + INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (11, '111'::text, 29) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 11 | 29 | 121 +(1 row) + + -- this is already disallowed on the nodes, adding it in case we + -- support DDLs from the worker nodes in the future + ALTER TABLE distributed_table ADD COLUMN x INT; +ERROR: operation is not allowed on this node +HINT: Connect to the coordinator and run it again. +ROLLBACK; +BEGIN; + INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (11, '111'::text, 29) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 11 | 29 | 121 +(1 row) + + -- this is already disallowed because VACUUM cannot be executed in tx block + -- adding in case this is supported some day + VACUUM second_distributed_table; +ERROR: VACUUM cannot run inside a transaction block +ROLLBACK; +-- make sure that functions can use local execution +SET citus.enable_metadata_sync TO OFF; +CREATE OR REPLACE PROCEDURE only_local_execution() AS $$ + DECLARE cnt INT; + BEGIN + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; + SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; + DELETE FROM distributed_table WHERE key = 1; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution(); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text +CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" +PL/pgSQL function only_local_execution() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" +PL/pgSQL function only_local_execution() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = 1" +PL/pgSQL function only_local_execution() line XX at SQL statement +-- insert a row that we need in the next tests +INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text +-- make sure that functions can use local execution +CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation() AS $$ + DECLARE nodeId INT; + BEGIN + -- fast path router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = 1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + + -- regular router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution_with_function_evaluation(); +NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = 1" +PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement +NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution_replicated.distributed_table_1500001 d1(key, value, age) JOIN local_shard_execution_replicated.distributed_table_1500001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1" +PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement +CREATE OR REPLACE PROCEDURE only_local_execution_with_params(int) AS $$ + DECLARE cnt INT; + BEGIN + INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; + SELECT count(*) INTO cnt FROM distributed_table WHERE key = $1; + DELETE FROM distributed_table WHERE key = $1; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution_with_params(1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '29'::text +CONTEXT: SQL statement "INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" +PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = $1" +PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = $1" +PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement +CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation_param(int) AS $$ + DECLARE nodeId INT; + BEGIN + -- fast path router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = $1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + + -- regular router + SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1; + IF nodeId <= 0 THEN + RAISE NOTICE 'unexpected node id'; + END IF; + END; +$$ LANGUAGE plpgsql; +CALL only_local_execution_with_function_evaluation_param(1); +NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = $1" +PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement +NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution_replicated.distributed_table_1500001 d1(key, value, age) JOIN local_shard_execution_replicated.distributed_table_1500001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) $1) +CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1" +PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement +CREATE OR REPLACE PROCEDURE local_execution_followed_by_dist() AS $$ + DECLARE cnt INT; + BEGIN + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; + SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; + DELETE FROM distributed_table; + SELECT count(*) INTO cnt FROM distributed_table; + END; +$$ LANGUAGE plpgsql; +RESET citus.enable_metadata_sync; +CALL local_execution_followed_by_dist(); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text +CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table +CONTEXT: SQL statement "DELETE FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table +CONTEXT: SQL statement "DELETE FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table +CONTEXT: SQL statement "DELETE FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table +CONTEXT: SQL statement "DELETE FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true +CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" +PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement +-- test CTEs, including modifying CTEs +WITH local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *), +distributed_local_mixed AS (SELECT * FROM reference_table WHERE key IN (SELECT key FROM local_insert)) +SELECT * FROM local_insert, distributed_local_mixed; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age +NOTICE: executing the command locally: SELECT key FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT local_insert.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert)) +NOTICE: executing the command locally: SELECT local_insert.key, local_insert.value, local_insert.age, distributed_local_mixed.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed + key | value | age | key +--------------------------------------------------------------------- + 1 | 11 | 21 | 1 +(1 row) + +-- since we start with parallel execution, we do not switch back to local execution in the +-- latter CTEs +WITH distributed_local_mixed AS (SELECT * FROM distributed_table), +local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *) +SELECT * FROM local_insert, distributed_local_mixed ORDER BY 1,2,3,4,5; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age +NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table) distributed_local_mixed) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table) distributed_local_mixed) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table) distributed_local_mixed) worker_subquery +NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table) distributed_local_mixed) worker_subquery + key | value | age | key | value | age +--------------------------------------------------------------------- + 1 | 29 | 21 | 1 | 11 | 21 +(1 row) + +-- router CTE pushdown +WITH all_data AS (SELECT * FROM distributed_table WHERE key = 1) +SELECT + count(*) +FROM + distributed_table, all_data +WHERE + distributed_table.key = all_data.key AND distributed_table.key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) + count +--------------------------------------------------------------------- + 1 +(1 row) + +INSERT INTO reference_table VALUES (2); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (2) +INSERT INTO distributed_table VALUES (2, '29', 29); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 (key, value, age) VALUES (2, '29'::text, 29) +INSERT INTO second_distributed_table VALUES (2, '29'); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.second_distributed_table_1500008 (key, value) VALUES (2, '29'::text) +-- single shard that is not a local query followed by a local query +WITH all_data AS (SELECT * FROM second_distributed_table WHERE key = 2) +SELECT + distributed_table.key +FROM + distributed_table, all_data +WHERE + distributed_table.value = all_data.value AND distributed_table.key = 1 +ORDER BY + 1 DESC; +NOTICE: executing the command locally: SELECT distributed_table.key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT second_distributed_table.key, second_distributed_table.value FROM local_shard_execution_replicated.second_distributed_table_1500008 second_distributed_table WHERE (second_distributed_table.key OPERATOR(pg_catalog.=) 2)) all_data WHERE ((distributed_table.value OPERATOR(pg_catalog.=) all_data.value) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) ORDER BY distributed_table.key DESC + key +--------------------------------------------------------------------- + 1 +(1 row) + +-- multi-shard CTE is followed by a query which could be executed locally, but +-- since the query started with a parallel query, it doesn't use local execution +-- note that if we allow Postgres to inline the CTE (e.g., not have the EXISTS +-- subquery), then it'd pushdown the filters and the query becomes single-shard, +-- locally executable query +WITH all_data AS (SELECT * FROM distributed_table) +SELECT + count(*) +FROM + distributed_table, all_data +WHERE + distributed_table.key = all_data.key AND distributed_table.key = 1 + AND EXISTS (SELECT * FROM all_data); +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1) AND (EXISTS (SELECT all_data_1.key, all_data_1.value, all_data_1.age FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data_1))) + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- in pg12, the following CTE can be inlined, still the query becomes +-- a subquery that needs to be recursively planned and a parallel +-- query, so do not use local execution +WITH all_data AS (SELECT age FROM distributed_table) +SELECT + count(*) +FROM + distributed_table, all_data +WHERE + distributed_table.key = all_data.age AND distributed_table.key = 1; +NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.age) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- get ready for the next commands +TRUNCATE reference_table, distributed_table, second_distributed_table; +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.reference_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE +-- local execution of returning of reference tables +INSERT INTO reference_table VALUES (1),(2),(3),(4),(5),(6) RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 AS citus_table_alias (key) VALUES (1), (2), (3), (4), (5), (6) RETURNING citus_table_alias.key + key +--------------------------------------------------------------------- + 1 + 2 + 3 + 4 + 5 + 6 +(6 rows) + +-- local execution of multi-row INSERTs +INSERT INTO distributed_table VALUES (1, '11',21), (5,'55',22) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'22'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 11 | 21 + 5 | 55 | 22 +(2 rows) + +-- distributed execution of multi-rows INSERTs, where executor +-- is smart enough to execute local tasks via local execution +INSERT INTO distributed_table VALUES (1, '11',21), (2,'22',22), (3,'33',33), (4,'44',44),(5,'55',55) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'55'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500002 AS citus_table_alias (key, value, age) VALUES (3,'33'::text,'33'::bigint), (4,'44'::text,'44'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (2,'22'::text,'22'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 12 | 21 + 2 | 22 | 22 + 3 | 33 | 33 + 4 | 44 | 44 + 5 | 56 | 22 +(5 rows) + +PREPARE local_prepare_no_param AS SELECT count(*) FROM distributed_table WHERE key = 1; +PREPARE local_prepare_no_param_subquery AS +SELECT DISTINCT trim(value) FROM ( + SELECT value FROM distributed_table + WHERE + key IN (1, 6, 500, 701) + AND (select 2) > random() + order by 1 + limit 2 + ) t; +PREPARE local_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key = $1; +PREPARE remote_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key != $1; +BEGIN; + -- 8 local execution without params + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_no_param; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + -- 8 local execution without params and some subqueries + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + EXECUTE local_prepare_no_param_subquery; +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint +NOTICE: executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t + btrim +--------------------------------------------------------------------- + 12 +(1 row) + + -- 8 local executions with params + EXECUTE local_prepare_param(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(5); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + EXECUTE local_prepare_param(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(5); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 1 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + EXECUTE local_prepare_param(6); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) + count +--------------------------------------------------------------------- + 0 +(1 row) + + -- followed by a non-local execution + EXECUTE remote_prepare_param(1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) + count +--------------------------------------------------------------------- + 4 +(1 row) + +COMMIT; +PREPARE local_insert_prepare_no_param AS INSERT INTO distributed_table VALUES (1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; +PREPARE local_insert_prepare_param (int) AS INSERT INTO distributed_table VALUES ($1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; +BEGIN; + -- 8 local execution without params + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + -- 8 local executions with params + EXECUTE local_insert_prepare_param(1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 5 | 2928 | 22 | 6 | 292830 | 330 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 11 | 21 | 7 | 1130 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 1 | 2928 | 21 | 2 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 5 | 2928 | 22 | 6 | 292830 | 330 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 2928 | 21 | 7 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 2928 | 21 | 7 | 292830 | 315 +(1 row) + + EXECUTE local_insert_prepare_param(6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) + key | value | age | ?column? | ?column? | ?column? +--------------------------------------------------------------------- + 6 | 2928 | 21 | 7 | 292830 | 315 +(1 row) + + -- followed by a non-local execution + EXECUTE remote_prepare_param(2); +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) + count +--------------------------------------------------------------------- + 5 +(1 row) + +COMMIT; +PREPARE local_multi_row_insert_prepare_no_param AS + INSERT INTO distributed_table VALUES (1,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value; +PREPARE local_multi_row_insert_prepare_no_param_multi_shard AS + INSERT INTO distributed_table VALUES (6,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 AND key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; +PREPARE local_multi_row_insert_prepare_params(int,int) AS + INSERT INTO distributed_table VALUES ($1,'55', 21), ($2,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; +INSERT INTO reference_table VALUES (11); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (11) +BEGIN; + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(6,5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(5,1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(5,6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(5,1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,6); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + EXECUTE local_multi_row_insert_prepare_params(1,5); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) + -- one task is remote + EXECUTE local_multi_row_insert_prepare_params(5,11); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (11,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) +ROLLBACK; +-- failures of local execution should rollback both the +-- local execution and remote executions +-- fail on a local execution +BEGIN; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 100 | 21 +(1 row) + + UPDATE distributed_table SET value = '200'; +NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500001 distributed_table SET value = '200'::text +NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500002 distributed_table SET value = '200'::text +NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500003 distributed_table SET value = '200'::text +NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500004 distributed_table SET value = '200'::text + INSERT INTO distributed_table VALUES (1, '100',21) ON CONFLICT(key) DO UPDATE SET value = (1 / (100.0 - EXCLUDED.value::int))::text RETURNING *; +ERROR: division by zero +CONTEXT: while executing command on localhost:xxxxx +ROLLBACK; +-- we've rollbacked everything +SELECT count(*) FROM distributed_table WHERE value = '200'; + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- RETURNING should just work fine for reference tables +INSERT INTO reference_table VALUES (500) RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (500) RETURNING key + key +--------------------------------------------------------------------- + 500 +(1 row) + +DELETE FROM reference_table WHERE key = 500 RETURNING *; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key + key +--------------------------------------------------------------------- + 500 +(1 row) + +-- should be able to skip local execution even if in a sequential mode of execution +BEGIN; + SET LOCAL citus.multi_shard_modify_mode TO sequential ; + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 11 | 21 +(1 row) + +ROLLBACK; +-- sequential execution should just work fine after a local execution +BEGIN; + SET citus.multi_shard_modify_mode TO sequential ; + INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age + key | value | age +--------------------------------------------------------------------- + 1 | 100 | 21 +(1 row) + + DELETE FROM distributed_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table +ROLLBACK; +-- load some data so that foreign keys won't complain with the next tests +TRUNCATE reference_table CASCADE; +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.reference_table_xxxxx CASCADE +INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; +NOTICE: executing the copy locally for shard xxxxx +INSERT INTO distributed_table SELECT i, i::text, i % 10 + 25 FROM generate_series(500, 600) i; +NOTICE: executing the copy locally for shard xxxxx +NOTICE: executing the copy locally for shard xxxxx +NOTICE: executing the copy locally for shard xxxxx +NOTICE: executing the copy locally for shard xxxxx +-- show that both local, and mixed local-distributed executions +-- calculate rows processed correctly +BEGIN; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + DELETE FROM distributed_table WHERE value != '123123213123213'; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) +ROLLBACK; +BEGIN; + DELETE FROM reference_table WHERE key = 500 RETURNING *; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key + key +--------------------------------------------------------------------- + 500 +(1 row) + + DELETE FROM reference_table; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table +ROLLBACK; +BEGIN; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true + count +--------------------------------------------------------------------- + 106 +(1 row) + +ROLLBACK; +BEGIN; + SET LOCAL client_min_messages TO INFO; + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true + count +--------------------------------------------------------------------- + 107 +(1 row) + + SET LOCAL client_min_messages TO LOG; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) +ROLLBACK; +-- probably not a realistic case since views are not very +-- well supported with MX +SET citus.enable_ddl_propagation TO OFF; +CREATE VIEW v_local_query_execution AS +SELECT * FROM distributed_table WHERE key = 500; +RESET citus.enable_ddl_propagation; +SELECT * FROM v_local_query_execution; +NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) 500)) v_local_query_execution + key | value | age +--------------------------------------------------------------------- + 500 | 500 | 25 +(1 row) + +-- similar test, but this time the view itself is a non-local +-- query, but the query on the view is local +SET citus.enable_ddl_propagation TO OFF; +CREATE VIEW v_local_query_execution_2 AS +SELECT * FROM distributed_table; +RESET citus.enable_ddl_propagation; +SELECT * FROM v_local_query_execution_2 WHERE key = 500; +NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table) v_local_query_execution_2 WHERE (key OPERATOR(pg_catalog.=) 500) + key | value | age +--------------------------------------------------------------------- + 500 | 500 | 25 +(1 row) + +-- even if we switch from remote execution -> local execution, +-- we are able to use remote execution after rollback +BEGIN; + SAVEPOINT my_savepoint; + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true + count +--------------------------------------------------------------------- + 107 +(1 row) + + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + ROLLBACK TO SAVEPOINT my_savepoint; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) +COMMIT; +-- even if we switch from local execution -> remote execution, +-- we are able to use local execution after rollback +BEGIN; + SAVEPOINT my_savepoint; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) + SELECT count(*) FROM distributed_table; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true + count +--------------------------------------------------------------------- + 106 +(1 row) + + ROLLBACK TO SAVEPOINT my_savepoint; + DELETE FROM distributed_table WHERE key = 500; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) +COMMIT; +-- sanity check: local execution on partitions +INSERT INTO collections_list (collection_id) VALUES (0) RETURNING *; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('3940649673949185'::bigint, '3940649673949185'::bigint, 0) RETURNING key, ser, ts, collection_id, value + key | ser | ts | collection_id | value +--------------------------------------------------------------------- + 3940649673949185 | 3940649673949185 | | 0 | +(1 row) + +BEGIN; + INSERT INTO collections_list (key, collection_id) VALUES (1,0); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('1'::bigint, '3940649673949186'::bigint, 0) + SELECT count(*) FROM collections_list_0 WHERE key = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_0_1500013 collections_list_0 WHERE (key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 1 +(1 row) + + SELECT count(*) FROM collections_list; +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500009 collections_list WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500010 collections_list WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500011 collections_list WHERE true +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500012 collections_list WHERE true + count +--------------------------------------------------------------------- + 2 +(1 row) + + SELECT * FROM collections_list ORDER BY 1,2,3,4; +NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500009 collections_list WHERE true +NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500010 collections_list WHERE true +NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500011 collections_list WHERE true +NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500012 collections_list WHERE true + key | ser | ts | collection_id | value +--------------------------------------------------------------------- + 1 | 3940649673949186 | | 0 | + 3940649673949185 | 3940649673949185 | | 0 | +(2 rows) + +COMMIT; +TRUNCATE collections_list; +-- make sure that even if local execution is used, the sequence values +-- are generated locally +SET citus.enable_ddl_propagation TO OFF; +ALTER SEQUENCE collections_list_key_seq NO MINVALUE NO MAXVALUE; +RESET citus.enable_ddl_propagation; +PREPARE serial_prepared_local AS INSERT INTO collections_list (collection_id) VALUES (0) RETURNING key, ser; +SELECT setval('collections_list_key_seq', 4); + setval +--------------------------------------------------------------------- + 4 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949187'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 5 | 3940649673949187 +(1 row) + +SELECT setval('collections_list_key_seq', 5); + setval +--------------------------------------------------------------------- + 5 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949188'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 6 | 3940649673949188 +(1 row) + +SELECT setval('collections_list_key_seq', 499); + setval +--------------------------------------------------------------------- + 499 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('500'::bigint, '3940649673949189'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 500 | 3940649673949189 +(1 row) + +SELECT setval('collections_list_key_seq', 700); + setval +--------------------------------------------------------------------- + 700 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('701'::bigint, '3940649673949190'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 701 | 3940649673949190 +(1 row) + +SELECT setval('collections_list_key_seq', 708); + setval +--------------------------------------------------------------------- + 708 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('709'::bigint, '3940649673949191'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 709 | 3940649673949191 +(1 row) + +SELECT setval('collections_list_key_seq', 709); + setval +--------------------------------------------------------------------- + 709 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('710'::bigint, '3940649673949192'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 710 | 3940649673949192 +(1 row) + +-- get ready for the next executions +DELETE FROM collections_list WHERE key IN (5,6); +SELECT setval('collections_list_key_seq', 4); + setval +--------------------------------------------------------------------- + 4 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949193'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 5 | 3940649673949193 +(1 row) + +SELECT setval('collections_list_key_seq', 5); + setval +--------------------------------------------------------------------- + 5 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949194'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 6 | 3940649673949194 +(1 row) + +-- and, one remote test +SELECT setval('collections_list_key_seq', 10); + setval +--------------------------------------------------------------------- + 10 +(1 row) + +EXECUTE serial_prepared_local; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500012 (key, ser, collection_id) VALUES ('11'::bigint, '3940649673949195'::bigint, 0) RETURNING key, ser + key | ser +--------------------------------------------------------------------- + 11 | 3940649673949195 +(1 row) + +-- the final queries for the following CTEs are going to happen on the intermediate results only +-- one of them will be executed remotely, and the other is locally +-- Citus currently doesn't allow using task_assignment_policy for intermediate results +WITH distributed_local_mixed AS (INSERT INTO reference_table VALUES (1000) RETURNING *) SELECT * FROM distributed_local_mixed; +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (1000) RETURNING key +NOTICE: executing the command locally: SELECT key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed + key +--------------------------------------------------------------------- + 1000 +(1 row) + +-- clean the table for the next tests +SET search_path TO local_shard_execution_replicated; +TRUNCATE distributed_table CASCADE; +-- load some data on a remote shard +INSERT INTO reference_table (key) VALUES (1), (2); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 AS citus_table_alias (key) VALUES (1), (2) +INSERT INTO distributed_table (key) VALUES (2); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 (key) VALUES (2) +BEGIN; + -- local execution followed by a distributed query + INSERT INTO distributed_table (key) VALUES (1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 (key) VALUES (1) + DELETE FROM distributed_table RETURNING key; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table RETURNING key +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table RETURNING key +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table RETURNING key +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table RETURNING key + key +--------------------------------------------------------------------- + 1 + 2 +(2 rows) + +COMMIT; +-- a similar test with a reference table +TRUNCATE reference_table CASCADE; +NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.reference_table_xxxxx CASCADE +-- load some data on a remote shard +INSERT INTO reference_table (key) VALUES (2); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (2) +BEGIN; + -- local execution followed by a distributed query + INSERT INTO reference_table (key) VALUES (1); +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (1) + DELETE FROM reference_table RETURNING key; +NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table RETURNING key + key +--------------------------------------------------------------------- + 1 + 2 +(2 rows) + +COMMIT; +-- however complex the query, local execution can handle +SET client_min_messages TO LOG; +SET citus.log_local_commands TO ON; +WITH cte_1 AS + (SELECT * + FROM + (WITH cte_1 AS + (SELECT * + FROM distributed_table + WHERE key = 1) SELECT * + FROM cte_1) AS foo) +SELECT count(*) +FROM cte_1 +JOIN distributed_table USING (key) +WHERE distributed_table.key = 1 + AND distributed_table.key IN + (SELECT key + FROM distributed_table + WHERE key = 1); +NOTICE: executing the command locally: SELECT count(*) AS count FROM ((SELECT foo.key, foo.value, foo.age FROM (SELECT cte_1_1.key, cte_1_1.value, cte_1_1.age FROM (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) cte_1_1) foo) cte_1 JOIN local_shard_execution_replicated.distributed_table_1500001 distributed_table(key, value, age) USING (key)) WHERE ((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table_1.key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +RESET client_min_messages; +RESET citus.log_local_commands; +\c - - - :master_port +SET citus.next_shard_id TO 1501000; +-- test both local and remote execution with custom type +SET citus.shard_replication_factor TO 2; +SET search_path TO local_shard_execution_replicated; +CREATE TYPE invite_resp AS ENUM ('yes', 'no', 'maybe'); +CREATE TABLE event_responses ( + event_id int, + user_id int, + response invite_resp, + primary key (event_id, user_id) +); +SELECT create_distributed_table('event_responses', 'event_id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO event_responses VALUES (1, 1, 'yes'), (2, 2, 'yes'), (3, 3, 'no'), (4, 4, 'no'); +CREATE OR REPLACE FUNCTION regular_func(p invite_resp) +RETURNS int AS $$ +DECLARE + q1Result INT; + q2Result INT; + q3Result INT; +BEGIN +SELECT count(*) INTO q1Result FROM event_responses WHERE response = $1; +SELECT count(*) INTO q2Result FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1; +SELECT count(*) INTO q3Result FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo; +RETURN q3Result+q2Result+q1Result; +END; +$$ LANGUAGE plpgsql; +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +SELECT regular_func('yes'); + regular_func +--------------------------------------------------------------------- + 6 +(1 row) + +CREATE OR REPLACE PROCEDURE regular_procedure(p invite_resp) +AS $$ +BEGIN +PERFORM * FROM event_responses WHERE response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC; +PERFORM * FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC; +PERFORM * FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo ORDER BY 1 DESC, 2 DESC, 3 DESC; +END; +$$ LANGUAGE plpgsql; +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +CALL regular_procedure('no'); +PREPARE multi_shard_no_dist_key(invite_resp) AS select * from event_responses where response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_no_dist_key('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +PREPARE multi_shard_with_dist_key(int, invite_resp) AS select * from event_responses where event_id > $1 AND response = $2::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +EXECUTE multi_shard_with_dist_key(1, 'yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes +(1 row) + +PREPARE query_pushdown_no_dist_key(invite_resp) AS select * from event_responses e1 LEFT JOIN event_responses e2 USING(event_id) where e1.response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC LIMIT 1; +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +EXECUTE query_pushdown_no_dist_key('yes'); + event_id | user_id | response | user_id | response +--------------------------------------------------------------------- + 2 | 2 | yes | 2 | yes +(1 row) + +PREPARE insert_select_via_coord(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp LIMIT 1 ON CONFLICT (event_id, user_id) DO NOTHING ; +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +EXECUTE insert_select_via_coord('yes'); +PREPARE insert_select_pushdown(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp ON CONFLICT (event_id, user_id) DO NOTHING; +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +EXECUTE insert_select_pushdown('yes'); +PREPARE router_select_with_no_dist_key_filter(invite_resp) AS select * from event_responses where event_id = 1 AND response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +EXECUTE router_select_with_no_dist_key_filter('yes'); + event_id | user_id | response +--------------------------------------------------------------------- + 1 | 1 | yes +(1 row) + +-- rest of the tests assume the table is empty +TRUNCATE event_responses; +CREATE OR REPLACE PROCEDURE register_for_event(p_event_id int, p_user_id int, p_choice invite_resp) +LANGUAGE plpgsql AS $fn$ +BEGIN + INSERT INTO local_shard_execution_replicated.event_responses VALUES (p_event_id, p_user_id, p_choice) + ON CONFLICT (event_id, user_id) + DO UPDATE SET response = EXCLUDED.response; + + PERFORM count(*) FROM local_shard_execution_replicated.event_responses WHERE event_id = p_event_id; + + PERFORM count(*) FROM local_shard_execution_replicated.event_responses WHERE event_id = p_event_id AND false; + + UPDATE local_shard_execution_replicated.event_responses SET response = p_choice WHERE event_id = p_event_id; + +END; +$fn$; +SELECT create_distributed_function('register_for_event(int,int,invite_resp)'); +NOTICE: procedure local_shard_execution_replicated.register_for_event is already distributed +DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- call 8 times to make sure it works after the 5th time(postgres binds values after the 5th time and Citus 2nd time) +-- after 6th, the local execution caches the local plans and uses it +-- execute it both locally and remotely +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +\c - - - :worker_2_port +SET search_path TO local_shard_execution_replicated; +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +CALL register_for_event(16, 1, 'yes'); +-- values 16, 17 and 19 hits the same +-- shard, so we're re-using the same cached +-- plans per statement across different distribution +-- key values +CALL register_for_event(17, 1, 'yes'); +CALL register_for_event(19, 1, 'yes'); +CALL register_for_event(17, 1, 'yes'); +CALL register_for_event(19, 1, 'yes'); +-- should work fine if the logs are enabled +\set VERBOSITY terse +SET citus.log_local_commands TO ON; +SET client_min_messages TO DEBUG2; +CALL register_for_event(19, 1, 'yes'); +DEBUG: stored procedure does not have co-located tables +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.event_responses_1501001 AS citus_table_alias (event_id, user_id, response) VALUES (19, 1, 'yes'::local_shard_execution_replicated.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.event_responses_1501001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 19) +NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT NULL::integer AS event_id, NULL::integer AS user_id, NULL::local_shard_execution_replicated.invite_resp AS response WHERE false) event_responses(event_id, user_id, response) WHERE ((event_id OPERATOR(pg_catalog.=) 19) AND false) +NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.event_responses_1501001 event_responses SET response = 'yes'::local_shard_execution_replicated.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 19) +-- should be fine even if no parameters exists in the query +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.event_responses_1501001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.event_responses_1501001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) + count +--------------------------------------------------------------------- + 1 +(1 row) + +UPDATE event_responses SET response = 'no' WHERE event_id = 16; +DEBUG: Distributed planning for a fast-path router query +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.event_responses_1501001 event_responses SET response = 'no'::local_shard_execution_replicated.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 16) +INSERT INTO event_responses VALUES (16, 666, 'maybe') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.event_responses_1501001 AS citus_table_alias (event_id, user_id, response) VALUES (16, 666, 'maybe'::local_shard_execution_replicated.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe +(1 row) + +-- multi row INSERTs hitting the same shard +INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan +NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.event_responses_1501001 AS citus_table_alias (event_id, user_id, response) VALUES (16,666,'maybe'::local_shard_execution_replicated.invite_resp), (17,777,'no'::local_shard_execution_replicated.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe + 17 | 777 | no +(2 rows) + +-- now, similar tests with some settings changed +SET citus.enable_local_execution TO false; +SET citus.enable_fast_path_router_planner TO false; +CALL register_for_event(19, 1, 'yes'); +DEBUG: stored procedure does not have co-located tables +-- should be fine even if no parameters exists in the query +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 + count +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT count(*) FROM event_responses WHERE event_id = 16; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 + count +--------------------------------------------------------------------- + 2 +(1 row) + +UPDATE event_responses SET response = 'no' WHERE event_id = 16; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 +INSERT INTO event_responses VALUES (16, 666, 'maybe') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan +DEBUG: query has a single distribution column value: 16 + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe +(1 row) + +-- multi row INSERTs hitting the same shard +INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +DEBUG: Creating router plan + event_id | user_id | response +--------------------------------------------------------------------- + 16 | 666 | maybe + 17 | 777 | no +(2 rows) + +-- not allow commands over the workers when user disables +SET citus.allow_modifications_from_workers_to_replicated_tables TO false; +INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') +ON CONFLICT (event_id, user_id) +DO UPDATE SET response = EXCLUDED.response RETURNING *; +ERROR: modifications via the worker nodes are not allowed for replicated tables such as reference tables or hash distributed tables with replication factor greater than 1. +\c - - - :master_port +SET client_min_messages TO ERROR; +SET search_path TO public; +DROP SCHEMA local_shard_execution_replicated CASCADE; diff --git a/src/test/regress/expected/multi_mx_insert_select_repartition.out b/src/test/regress/expected/multi_mx_insert_select_repartition.out index 47fd8d18f..066350cba 100644 --- a/src/test/regress/expected/multi_mx_insert_select_repartition.out +++ b/src/test/regress/expected/multi_mx_insert_select_repartition.out @@ -1,3 +1,12 @@ +-- +-- MULTI_MX_INSERT_SELECT_REPARTITION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- -- Test behaviour of repartitioned INSERT ... SELECT in MX setup CREATE SCHEMA multi_mx_insert_select_repartition; SET search_path TO multi_mx_insert_select_repartition; @@ -92,8 +101,8 @@ NOTICE: executing the command locally: SELECT count(*) AS count FROM multi_mx_i NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_4213581_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_4213581_to','SELECT (a OPERATOR(pg_catalog.*) 2) AS a FROM multi_mx_insert_select_repartition.source_table_4213581 source_table WHERE true',0,'hash','{-2147483648,-715827883,715827882}'::text[],'{-715827884,715827881,2147483647}'::text[],true) WHERE rows_written > 0 NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_4213583_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_4213583_to','SELECT (a OPERATOR(pg_catalog.*) 2) AS a FROM multi_mx_insert_select_repartition.source_table_4213583 source_table WHERE true',0,'hash','{-2147483648,-715827883,715827882}'::text[],'{-715827884,715827881,2147483647}'::text[],true) WHERE rows_written > 0 NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartitioned_results_xxxxx_from_4213582_to_0','repartitioned_results_xxxxx_from_4213584_to_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: INSERT INTO multi_mx_insert_select_repartition.target_table_4213585 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_0,repartitioned_results_xxxxx_from_4213582_to_0,repartitioned_results_xxxxx_from_4213584_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) RETURNING citus_table_alias.a -NOTICE: executing the command locally: INSERT INTO multi_mx_insert_select_repartition.target_table_4213587 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) RETURNING citus_table_alias.a +NOTICE: executing the command locally: INSERT INTO multi_mx_insert_select_repartition.target_table_4213585 AS citus_table_alias (a) SELECT intermediate_result.a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_0,repartitioned_results_xxxxx_from_4213582_to_0,repartitioned_results_xxxxx_from_4213584_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) RETURNING citus_table_alias.a +NOTICE: executing the command locally: INSERT INTO multi_mx_insert_select_repartition.target_table_4213587 AS citus_table_alias (a) SELECT intermediate_result.a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) RETURNING citus_table_alias.a a --------------------------------------------------------------------- 0 diff --git a/src/test/regress/expected/multi_mx_insert_select_repartition_0.out b/src/test/regress/expected/multi_mx_insert_select_repartition_0.out new file mode 100644 index 000000000..44a4b7300 --- /dev/null +++ b/src/test/regress/expected/multi_mx_insert_select_repartition_0.out @@ -0,0 +1,160 @@ +-- +-- MULTI_MX_INSERT_SELECT_REPARTITION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +-- Test behaviour of repartitioned INSERT ... SELECT in MX setup +CREATE SCHEMA multi_mx_insert_select_repartition; +SET search_path TO multi_mx_insert_select_repartition; +SET citus.next_shard_id TO 4213581; +SET citus.shard_replication_factor TO 1; +SET citus.shard_count TO 4; +CREATE TABLE source_table(a int, b int); +SELECT create_distributed_table('source_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO source_table SELECT floor(i/4), i*i FROM generate_series(1, 20) i; +SET citus.shard_count TO 3; +CREATE TABLE target_table(a int, b int); +SELECT create_distributed_table('target_table', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE FUNCTION square(int) RETURNS INT + AS $$ SELECT $1 * $1 $$ + LANGUAGE SQL; +select create_distributed_function('square(int)'); +NOTICE: procedure multi_mx_insert_select_repartition.square is already distributed +DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +select public.colocate_proc_with_table('square', 'source_table'::regclass, 0); + colocate_proc_with_table +--------------------------------------------------------------------- + +(1 row) + +-- Test along with function delegation +-- function delegation only happens for "SELECT f()", and we don't use +-- repartitioned INSERT/SELECT when task count is 1, so the following +-- should go via coordinator +EXPLAIN (costs off) INSERT INTO target_table(a) SELECT square(4); + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: pull to coordinator + -> Result +(3 rows) + +INSERT INTO target_table(a) SELECT square(4); +SELECT * FROM target_table; + a | b +--------------------------------------------------------------------- + 16 | +(1 row) + +TRUNCATE target_table; +-- +-- Test repartitioned INSERT/SELECT from MX worker +-- +\c - - - :worker_1_port +SET search_path TO multi_mx_insert_select_repartition; +EXPLAIN (costs off) INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (Citus INSERT ... SELECT) + INSERT/SELECT method: repartition + -> Custom Scan (Citus Adaptive) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> HashAggregate + Group Key: a + -> Seq Scan on source_table_4213581 source_table +(10 rows) + +INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; +SET citus.log_local_commands to on; +-- INSERT .. SELECT via repartitioning with local execution +BEGIN; + select count(*) from source_table WHERE a = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM multi_mx_insert_select_repartition.source_table_4213581 source_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 4 +(1 row) + + insert into target_table SELECT a*2 FROM source_table RETURNING a; +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_4213581_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_4213581_to','SELECT (a OPERATOR(pg_catalog.*) 2) AS a FROM multi_mx_insert_select_repartition.source_table_4213581 source_table WHERE true',0,'hash','{-2147483648,-715827883,715827882}'::text[],'{-715827884,715827881,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_4213583_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_4213583_to','SELECT (a OPERATOR(pg_catalog.*) 2) AS a FROM multi_mx_insert_select_repartition.source_table_4213583 source_table WHERE true',0,'hash','{-2147483648,-715827883,715827882}'::text[],'{-715827884,715827881,2147483647}'::text[],true) WHERE rows_written > 0 +NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartitioned_results_xxxxx_from_4213582_to_0','repartitioned_results_xxxxx_from_4213584_to_0']::text[],'localhost',57638) bytes +NOTICE: executing the command locally: INSERT INTO multi_mx_insert_select_repartition.target_table_4213585 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_0,repartitioned_results_xxxxx_from_4213582_to_0,repartitioned_results_xxxxx_from_4213584_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) RETURNING citus_table_alias.a +NOTICE: executing the command locally: INSERT INTO multi_mx_insert_select_repartition.target_table_4213587 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) RETURNING citus_table_alias.a + a +--------------------------------------------------------------------- + 0 + 0 + 0 + 2 + 2 + 2 + 2 + 4 + 4 + 4 + 4 + 6 + 6 + 6 + 6 + 8 + 8 + 8 + 8 + 10 +(20 rows) + +ROLLBACK; +BEGIN; + select count(*) from source_table WHERE a = 1; +NOTICE: executing the command locally: SELECT count(*) AS count FROM multi_mx_insert_select_repartition.source_table_4213581 source_table WHERE (a OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 4 +(1 row) + + insert into target_table SELECT a FROM source_table LIMIT 10; +NOTICE: executing the command locally: SELECT a FROM multi_mx_insert_select_repartition.source_table_4213581 source_table WHERE true LIMIT '10'::bigint +NOTICE: executing the command locally: SELECT a FROM multi_mx_insert_select_repartition.source_table_4213583 source_table WHERE true LIMIT '10'::bigint +NOTICE: executing the copy locally for shard xxxxx +ROLLBACK; +\c - - - :master_port +SET search_path TO multi_mx_insert_select_repartition; +SELECT * FROM target_table ORDER BY a; + a | b +--------------------------------------------------------------------- + 0 | 9 + 1 | 49 + 2 | 121 + 3 | 225 + 4 | 361 + 5 | 400 +(6 rows) + +RESET client_min_messages; +\set VERBOSITY terse +DROP SCHEMA multi_mx_insert_select_repartition CASCADE; +NOTICE: drop cascades to 3 other objects diff --git a/src/test/regress/expected/mx_coordinator_shouldhaveshards.out b/src/test/regress/expected/mx_coordinator_shouldhaveshards.out index cbfe25281..892b0e83b 100644 --- a/src/test/regress/expected/mx_coordinator_shouldhaveshards.out +++ b/src/test/regress/expected/mx_coordinator_shouldhaveshards.out @@ -1,3 +1,12 @@ +-- +-- MX_COORDINATOR_SHOULDHAVESHARDS +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA mx_coordinator_shouldhaveshards; SET search_path TO mx_coordinator_shouldhaveshards; SET citus.shard_replication_factor to 1; @@ -99,7 +108,7 @@ inserts AS ( RETURNING * ) SELECT count(*) FROM inserts; DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1 -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT table_1.key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (table_1.key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY table_1.key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries DEBUG: push down of limit count: 1 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts @@ -160,7 +169,7 @@ inserts AS ( RETURNING * ) SELECT count(*) FROM inserts; DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1_rep -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT table_1_rep.key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (table_1_rep.key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY table_1_rep.key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries DEBUG: push down of limit count: 1 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts @@ -225,7 +234,7 @@ inserts AS ( RETURNING * ) SELECT count(*) FROM inserts; DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1 -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT table_1.key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (table_1.key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY table_1.key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries DEBUG: push down of limit count: 1 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts @@ -286,7 +295,7 @@ inserts AS ( RETURNING * ) SELECT count(*) FROM inserts; DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1_rep -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT table_1_rep.key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (table_1_rep.key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY table_1_rep.key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries DEBUG: push down of limit count: 1 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts diff --git a/src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out b/src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out new file mode 100644 index 000000000..26f454b48 --- /dev/null +++ b/src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out @@ -0,0 +1,326 @@ +-- +-- MX_COORDINATOR_SHOULDHAVESHARDS +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- +CREATE SCHEMA mx_coordinator_shouldhaveshards; +SET search_path TO mx_coordinator_shouldhaveshards; +SET citus.shard_replication_factor to 1; +SET client_min_messages TO WARNING; +SELECT 1 FROM master_add_node('localhost', :master_port, groupid => 0); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +RESET client_min_messages; +SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', true); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +-- issue 4508 table_1 and table_2 are used to test some edge cases +-- around intermediate result pruning +CREATE TABLE table_1 (key int, value text); +SELECT create_distributed_table('table_1', 'key', colocate_with := 'none'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE table_2 (key int, value text); +SELECT create_distributed_table('table_2', 'key', colocate_with := 'none'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO table_1 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'); +INSERT INTO table_2 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'); +SET citus.shard_replication_factor to 2; +CREATE TABLE table_1_rep (key int, value text); +SELECT create_distributed_table('table_1_rep', 'key', colocate_with := 'none'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE table_2_rep (key int, value text); +SELECT create_distributed_table('table_2_rep', 'key', colocate_with := 'none'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO table_1_rep VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'); +INSERT INTO table_2_rep VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'); +set citus.log_intermediate_results TO ON; +set client_min_messages to debug1; +WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) +SELECT count(*), +key +FROM a JOIN table_2 USING (key) +GROUP BY key +HAVING (max(table_2.value) >= (SELECT value FROM a)); +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count | key +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) +INSERT INTO table_1 SELECT count(*), +key +FROM a JOIN table_2 USING (key) +GROUP BY key +HAVING (max(table_2.value) >= (SELECT value FROM a)); +DEBUG: Group by list without distribution column is not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery +DEBUG: Collecting INSERT ... SELECT results on coordinator +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +WITH stats AS ( + SELECT count(key) m FROM table_1 +), +inserts AS ( + INSERT INTO table_2 + SELECT key, count(*) + FROM table_1 + WHERE key >= (SELECT m FROM stats) + GROUP BY key + HAVING count(*) <= (SELECT m FROM stats) + LIMIT 1 + RETURNING * +) SELECT count(*) FROM inserts; +DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1 +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value +DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Collecting INSERT ... SELECT results on coordinator + count +--------------------------------------------------------------------- + 0 +(1 row) + +WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) +SELECT count(*), +key +FROM a JOIN table_2_rep USING (key) +GROUP BY key +HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count | key +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) +INSERT INTO table_1_rep SELECT count(*), +key +FROM a JOIN table_2_rep USING (key) +GROUP BY key +HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); +DEBUG: Group by list without distribution column is not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery +DEBUG: Collecting INSERT ... SELECT results on coordinator +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +WITH stats AS ( + SELECT count(key) m FROM table_1_rep +), +inserts AS ( + INSERT INTO table_2_rep + SELECT key, count(*) + FROM table_1_rep + WHERE key >= (SELECT m FROM stats) + GROUP BY key + HAVING count(*) <= (SELECT m FROM stats) + LIMIT 1 + RETURNING * +) SELECT count(*) FROM inserts; +DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1_rep +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value +DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Collecting INSERT ... SELECT results on coordinator + count +--------------------------------------------------------------------- + 0 +(1 row) + +\c - - - :worker_1_port +SET search_path TO mx_coordinator_shouldhaveshards; +set citus.log_intermediate_results TO ON; +set client_min_messages to debug1; +WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) +SELECT count(*), +key +FROM a JOIN table_2 USING (key) +GROUP BY key +HAVING (max(table_2.value) >= (SELECT value FROM a)); +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count | key +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) +INSERT INTO table_1 SELECT count(*), +key +FROM a JOIN table_2 USING (key) +GROUP BY key +HAVING (max(table_2.value) >= (SELECT value FROM a)); +DEBUG: Group by list without distribution column is not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery +DEBUG: Collecting INSERT ... SELECT results on coordinator +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +WITH stats AS ( + SELECT count(key) m FROM table_1 +), +inserts AS ( + INSERT INTO table_2 + SELECT key, count(*) + FROM table_1 + WHERE key >= (SELECT m FROM stats) + GROUP BY key + HAVING count(*) <= (SELECT m FROM stats) + LIMIT 1 + RETURNING * +) SELECT count(*) FROM inserts; +DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1 +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value +DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Collecting INSERT ... SELECT results on coordinator + count +--------------------------------------------------------------------- + 0 +(1 row) + +WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) +SELECT count(*), +key +FROM a JOIN table_2_rep USING (key) +GROUP BY key +HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx + count | key +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) +INSERT INTO table_1_rep SELECT count(*), +key +FROM a JOIN table_2_rep USING (key) +GROUP BY key +HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); +DEBUG: Group by list without distribution column is not allowed in distributed INSERT ... SELECT queries +DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery +DEBUG: Collecting INSERT ... SELECT results on coordinator +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +WITH stats AS ( + SELECT count(key) m FROM table_1_rep +), +inserts AS ( + INSERT INTO table_2_rep + SELECT key, count(*) + FROM table_1_rep + WHERE key >= (SELECT m FROM stats) + GROUP BY key + HAVING count(*) <= (SELECT m FROM stats) + LIMIT 1 + RETURNING * +) SELECT count(*) FROM inserts; +DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1_rep +DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value +DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries +DEBUG: push down of limit count: 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts +DEBUG: Subplan XXX_1 will be written to local file +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx +DEBUG: Subplan XXX_2 will be written to local file +DEBUG: Collecting INSERT ... SELECT results on coordinator + count +--------------------------------------------------------------------- + 0 +(1 row) + +\c - - - :master_port +SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', false); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +SET client_min_messages TO ERROR; +DROP SCHEMA mx_coordinator_shouldhaveshards CASCADE; +SELECT master_remove_node('localhost', :master_port); + master_remove_node +--------------------------------------------------------------------- + +(1 row) + diff --git a/src/test/regress/sql/citus_local_tables_queries.sql b/src/test/regress/sql/citus_local_tables_queries.sql index a4f8b6e00..50d9a5e40 100644 --- a/src/test/regress/sql/citus_local_tables_queries.sql +++ b/src/test/regress/sql/citus_local_tables_queries.sql @@ -1,3 +1,12 @@ +-- +-- CITUS_LOCAL_TABLES_QUERIES +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- \set VERBOSITY terse SET citus.next_shard_id TO 1509000; diff --git a/src/test/regress/sql/cte_inline.sql b/src/test/regress/sql/cte_inline.sql index c554d5df9..7c3e7c73f 100644 --- a/src/test/regress/sql/cte_inline.sql +++ b/src/test/regress/sql/cte_inline.sql @@ -1,3 +1,12 @@ +-- +-- CTE_INLINE +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA cte_inline; SET search_path TO cte_inline; SET citus.next_shard_id TO 1960000; diff --git a/src/test/regress/sql/insert_select_repartition.sql b/src/test/regress/sql/insert_select_repartition.sql index f88c67f50..6620b9295 100644 --- a/src/test/regress/sql/insert_select_repartition.sql +++ b/src/test/regress/sql/insert_select_repartition.sql @@ -1,3 +1,12 @@ +-- +-- INSERT_SELECT_REPARTITION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- -- tests behaviour of INSERT INTO ... SELECT with repartitioning CREATE SCHEMA insert_select_repartition; SET search_path TO 'insert_select_repartition'; diff --git a/src/test/regress/sql/intermediate_result_pruning.sql b/src/test/regress/sql/intermediate_result_pruning.sql index 58beb8df0..c6d1d35e1 100644 --- a/src/test/regress/sql/intermediate_result_pruning.sql +++ b/src/test/regress/sql/intermediate_result_pruning.sql @@ -1,3 +1,13 @@ +-- +-- INTERMEDIATE_RESULT_PRUNING +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- + CREATE SCHEMA intermediate_result_pruning; SET search_path TO intermediate_result_pruning; SET citus.log_intermediate_results TO TRUE; diff --git a/src/test/regress/sql/local_shard_execution.sql b/src/test/regress/sql/local_shard_execution.sql index b289f6bed..c4f1971b5 100644 --- a/src/test/regress/sql/local_shard_execution.sql +++ b/src/test/regress/sql/local_shard_execution.sql @@ -1,3 +1,12 @@ +-- +-- LOCAL_SHARD_EXECUTION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA local_shard_execution; SET search_path TO local_shard_execution; diff --git a/src/test/regress/sql/local_shard_execution_replicated.sql b/src/test/regress/sql/local_shard_execution_replicated.sql index a8fe72b98..1c239d612 100644 --- a/src/test/regress/sql/local_shard_execution_replicated.sql +++ b/src/test/regress/sql/local_shard_execution_replicated.sql @@ -1,3 +1,12 @@ +-- +-- LOCAL_SHARD_EXECUTION_REPLICATED +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA local_shard_execution_replicated; SET search_path TO local_shard_execution_replicated; diff --git a/src/test/regress/sql/multi_mx_insert_select_repartition.sql b/src/test/regress/sql/multi_mx_insert_select_repartition.sql index e086444cf..c62b7bfe2 100644 --- a/src/test/regress/sql/multi_mx_insert_select_repartition.sql +++ b/src/test/regress/sql/multi_mx_insert_select_repartition.sql @@ -1,3 +1,12 @@ +-- +-- MULTI_MX_INSERT_SELECT_REPARTITION +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- -- Test behaviour of repartitioned INSERT ... SELECT in MX setup CREATE SCHEMA multi_mx_insert_select_repartition; diff --git a/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql b/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql index 2b2d9b118..fb539fada 100644 --- a/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql +++ b/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql @@ -1,3 +1,12 @@ +-- +-- MX_COORDINATOR_SHOULDHAVESHARDS +-- +-- Test queries on a distributed table with shards on the coordinator +-- +-- This test file has an alternative output because of the change in the +-- display of SQL-standard function's arguments in INSERT/SELECT in PG15. +-- The alternative output can be deleted when we drop support for PG14 +-- CREATE SCHEMA mx_coordinator_shouldhaveshards; SET search_path TO mx_coordinator_shouldhaveshards;