From a008fc611cdab360907de4c45b8aa651dea2582a Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Tue, 1 Dec 2020 22:48:21 +0300 Subject: [PATCH] Support materialized view joins as well --- .../distributed/planner/recursive_planning.c | 8 +- .../regress/expected/local_table_join.out | 77 ++++++++++++++++++- src/test/regress/sql/local_table_join.sql | 14 ++++ 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index bd372d01b..cac80f824 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1476,7 +1476,8 @@ IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry) return false; } return rangeTableEntry->relkind == RELKIND_PARTITIONED_TABLE || - rangeTableEntry->relkind == RELKIND_RELATION; + rangeTableEntry->relkind == RELKIND_RELATION || + rangeTableEntry->relkind == RELKIND_MATVIEW; } @@ -1505,8 +1506,7 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) { containsDistributedTable = true; } - else if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE) || - !IsCitusTable(rangeTableEntry->relid)) + else if (IsLocalTableRteOrMatView((Node*) rangeTableEntry)) { /* we consider citus local tables as local table */ containsLocalTable = true; @@ -1542,7 +1542,7 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) continue; } - if (!IsCitusTable(rangeTableEntry->relid) && rangeTableEntry->relid != resultRelationId) + if (IsLocalTableRteOrMatView((Node*) rangeTableEntry) && rangeTableEntry->relid != resultRelationId) { containsLocalTable = true; } diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 790f79c77..b9a6018e0 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -49,6 +49,8 @@ SELECT create_distributed_table('distributed_table_composite', 'key'); (1 row) +CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; +CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; SET client_min_messages TO DEBUG1; -- the user doesn't allow local / distributed table joinn SET citus.local_table_join_policy TO 'never'; @@ -159,6 +161,79 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +-- materialized views should work too +SELECT count(*) FROM distributed_table JOIN mv1 USING(key); +DEBUG: Wrapping local relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv1 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv1 USING(key); +DEBUG: Wrapping local relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv1 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM reference_table JOIN mv1 USING(key); +DEBUG: Wrapping local relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv1 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table JOIN mv1 USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping local relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv1 USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table JOIN mv2 USING(key); +DEBUG: Wrapping local relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv2 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv2 USING(key); +DEBUG: Wrapping local relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv2 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM reference_table JOIN mv2 USING(key); +DEBUG: Wrapping local relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv2 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table JOIN mv2 USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping local relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) mv2 USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- partitioned tables should work as well SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key); DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 @@ -936,4 +1011,4 @@ SELECT master_remove_node('localhost', :master_port); \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 9 other objects +NOTICE: drop cascades to 11 other objects diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 59b4b543a..788d053bb 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -26,6 +26,10 @@ CREATE TABLE local_partitioned_table_2 PARTITION OF local_partitioned_table FOR CREATE TABLE distributed_table_composite (key int, value text, value_2 jsonb, primary key (key, value)); SELECT create_distributed_table('distributed_table_composite', 'key'); +CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; +CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; + + SET client_min_messages TO DEBUG1; @@ -62,6 +66,16 @@ SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key); SELECT count(*) FROM reference_table JOIN local_partitioned_table USING(key); SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); +-- materialized views should work too +SELECT count(*) FROM distributed_table JOIN mv1 USING(key); +SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv1 USING(key); +SELECT count(*) FROM reference_table JOIN mv1 USING(key); +SELECT count(*) FROM distributed_table JOIN mv1 USING(key) JOIN reference_table USING (key); +SELECT count(*) FROM distributed_table JOIN mv2 USING(key); +SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv2 USING(key); +SELECT count(*) FROM reference_table JOIN mv2 USING(key); +SELECT count(*) FROM distributed_table JOIN mv2 USING(key) JOIN reference_table USING (key); + -- partitioned tables should work as well SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key); SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) WHERE distributed_partitioned_table.key = 10;