diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 17eee2724..82d4d2199 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -355,27 +355,6 @@ AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList) } -/* - * ShouldConvertLocalTableJoinsToSubqueries returns true if we should - * convert local-dist table joins to subqueries. - */ -bool -ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList) -{ - if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) - { - /* user doesn't want Citus to enable local table joins */ - return false; - } - - if (!ContainsLocalTableDistributedTableJoin(rangeTableList)) - { - return false; - } - return true; -} - - /* * HasConstantFilterOnUniqueColumn returns true if the given rangeTableEntry has a constant * filter on a unique column. diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 768e9b171..2d49543fb 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -920,7 +920,7 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer ExtractRangeTableEntryWalker((Node *) originalQuery, &rangeTableList); } bool containsLocalTableDistributedTableJoin = - ContainsLocalTableDistributedTableJoin(queryTree->rtable); + ContainsLocalTableDistributedTableJoin(queryTree->rtable, NULL, NULL); RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index a6761a7f4..04757a29b 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -74,6 +74,7 @@ #include "distributed/relation_restriction_equivalence.h" #include "distributed/log_utils.h" #include "distributed/shard_pruning.h" +#include "distributed/var_utils.h" #include "distributed/version_compat.h" #include "lib/stringinfo.h" #include "optimizer/clauses.h" @@ -111,6 +112,7 @@ struct RecursivePlanningContextInternal uint64 planId; bool allDistributionKeysInQueryAreEqual; /* used for some optimizations */ List *subPlanList; + List *rtableList; /* list of rtables */ PlannerRestrictionContext *plannerRestrictionContext; }; @@ -144,6 +146,9 @@ static DeferredErrorMessage * RecursivelyPlanSubqueriesAndCTEs(Query *query, static bool ShouldRecursivelyPlanNonColocatedSubqueries(Query *subquery, RecursivePlanningContext * context); +static bool ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, + List *tableList, List *rtableList); + static bool ContainsSubquery(Query *query); static void RecursivelyPlanNonColocatedSubqueries(Query *subquery, RecursivePlanningContext *context); @@ -195,6 +200,9 @@ static Query * CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *outerSubqueryTargetList); static List * GenerateRequiredColNamesFromTargetList(List *targetList); static char * GetRelationNameAndAliasName(RangeTblEntry *rangeTablentry); +static void ContainsLocalTableDistributedTableVars(List *tableList, List *rtableList, + bool *containsLocalTable, + bool *containsDistributedTable); /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. @@ -219,6 +227,7 @@ GenerateSubplansForSubqueriesAndCTEs(uint64 planId, Query *originalQuery, context.planId = planId; context.subPlanList = NIL; context.plannerRestrictionContext = plannerRestrictionContext; + context.rtableList = NIL; /* * Calculating the distribution key equality upfront is a trade-off for us. @@ -276,6 +285,8 @@ GenerateSubplansForSubqueriesAndCTEs(uint64 planId, Query *originalQuery, static DeferredErrorMessage * RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context) { + context->rtableList = lcons(query->rtable, context->rtableList); + DeferredErrorMessage *error = RecursivelyPlanCTEs(query, context); if (error != NULL) { @@ -350,8 +361,9 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context RecursivelyPlanNonColocatedSubqueries(query, context); } - - if (ShouldConvertLocalTableJoinsToSubqueries(query->rtable)) + List *tableList = PullAllRangeTablesEntries(query, context->rtableList); + if (ShouldConvertLocalTableJoinsToSubqueries(query->rtable, tableList, + context->rtableList)) { /* * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or @@ -361,11 +373,64 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context RecursivelyPlanLocalTableJoins(query, context); } - + context->rtableList = list_delete_first(context->rtableList); return NULL; } +/* + * ShouldConvertLocalTableJoinsToSubqueries returns true if we should + * convert local-dist table joins to subqueries. + */ +static bool +ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, List *tableList, + List *rtableList) +{ + if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) + { + /* user doesn't want Citus to enable local table joins */ + return false; + } + + bool containsDistributedTable = false; + bool containsLocalTable = false; + + if (ContainsLocalTableDistributedTableJoin(rangeTableList, &containsLocalTable, + &containsDistributedTable)) + { + return true; + } + + /* if we have vars that references local or distributed tables, it means we need to do subquery-conversion */ + ContainsLocalTableDistributedTableVars(tableList, rtableList, &containsLocalTable, + &containsDistributedTable); + + return containsDistributedTable && containsLocalTable; +} + + +static void +ContainsLocalTableDistributedTableVars(List *tableList, List *rtableList, + bool *containsLocalTable, + bool *containsDistributedTable) +{ + RangeTblEntry *rte = NULL; + foreach_ptr(rte, tableList) + { + if (IsDistributedOrReferenceTableRTE((Node *) rte)) + { + *containsDistributedTable = true; + } + else if (IsRecursivelyPlannableRelation(rte) && + IsLocalTableRteOrMatView((Node *) rte)) + { + /* we consider citus local tables as local table */ + *containsLocalTable = true; + } + } +} + + /* * GetPlannerRestrictionContext returns the planner restriction context * from the given context. @@ -1576,7 +1641,8 @@ IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry) * or reference table. */ bool -ContainsLocalTableDistributedTableJoin(List *rangeTableList) +ContainsLocalTableDistributedTableJoin(List *rangeTableList, bool *containsLocalTableOut, + bool *containsDistributedTableOut) { bool containsLocalTable = false; bool containsDistributedTable = false; @@ -1596,7 +1662,14 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) containsLocalTable = true; } } - + if (containsLocalTableOut) + { + *containsLocalTableOut = containsLocalTable; + } + if (containsDistributedTableOut) + { + *containsDistributedTableOut = containsDistributedTable; + } return containsLocalTable && containsDistributedTable; } diff --git a/src/backend/distributed/utils/var_utils.c b/src/backend/distributed/utils/var_utils.c new file mode 100644 index 000000000..759b9293c --- /dev/null +++ b/src/backend/distributed/utils/var_utils.c @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- + * + * var_utils.c + * Utilities regarding vars + * + * Copyright (c) Citus Data, Inc. + *------------------------------------------------------------------------- + */ + +#include "distributed/pg_version_constants.h" + +#include "postgres.h" + +#include "distributed/var_utils.h" + +#include "parser/parsetree.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "nodes/nodes.h" +#include "nodes/nodeFuncs.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" +#include "nodes/primnodes.h" +#if PG_VERSION_NUM >= PG_VERSION_12 +#include "nodes/pathnodes.h" +#else +#include "nodes/relation.h" +#endif + +typedef struct PullTableContext +{ + List *rteList; + List *rtableList; +}PullTableContext; + + +static bool PullAllRangeTablesEntriesWalker(Node *node, + PullTableContext *pullTableContext); + + +/* + * PullAllRangeTablesEntries collects all the range table entries that are referenced + * in the given query. The range table entry could be outside of the given query but a var + * could exist that points to it. + * rtableList should contain list of rtables up to this query from the top query. + */ +List * +PullAllRangeTablesEntries(Query *query, List *rtableList) +{ + PullTableContext p; + p.rtableList = rtableList; + p.rteList = NIL; + + query_or_expression_tree_walker((Node *) query, + PullAllRangeTablesEntriesWalker, + (void *) &p, + 0); + + return p.rteList; +} + + +/* + * PullAllRangeTablesEntriesWalker descends into the given node and collects + * all range table entries that are referenced by a Var. + */ +static bool +PullAllRangeTablesEntriesWalker(Node *node, PullTableContext *pullTableContext) +{ + if (node == NULL) + { + return false; + } + if (IsA(node, Var)) + { + Var *var = (Var *) node; + + List *rtableList = pullTableContext->rtableList; + int index = var->varlevelsup; + if (index >= list_length(rtableList) || index < 0) + { + ereport(ERROR, (errmsg("unexpected state: %d is not between 0-%d", index, + list_length(rtableList)))); + } + List *rtable = (List *) list_nth(rtableList, index); + RangeTblEntry *rte = (RangeTblEntry *) list_nth(rtable, var->varno - 1); + pullTableContext->rteList = lappend(pullTableContext->rteList, rte); + return false; + } + if (IsA(node, PlaceHolderVar)) + { + /* PlaceHolderVar *phv = (PlaceHolderVar *) node; */ + + /* we don't want to look into the contained expression */ + return false; + } + if (IsA(node, Query)) + { + /* Recurse into RTE subquery or not-yet-planned sublink subquery */ + + Query *query = (Query *) node; + pullTableContext->rtableList = lcons(query->rtable, pullTableContext->rtableList); + bool result = query_tree_walker(query, PullAllRangeTablesEntriesWalker, + (void *) pullTableContext, 0); + pullTableContext->rtableList = list_delete_first(pullTableContext->rtableList); + return result; + } + return expression_tree_walker(node, PullAllRangeTablesEntriesWalker, + (void *) pullTableContext); +} diff --git a/src/include/distributed/local_distributed_join_planner.h b/src/include/distributed/local_distributed_join_planner.h index dd74c8fb1..690999bb2 100644 --- a/src/include/distributed/local_distributed_join_planner.h +++ b/src/include/distributed/local_distributed_join_planner.h @@ -27,7 +27,6 @@ typedef enum extern int LocalTableJoinPolicy; -extern bool ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList); extern void RecursivelyPlanLocalTableJoins(Query *query, RecursivePlanningContext *context); diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 98d230cb2..6c01125b9 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -43,7 +43,9 @@ extern Query * BuildReadIntermediateResultsArrayQuery(List *targetEntryList, List *resultIdList, bool useBinaryCopyFormat); extern bool GeneratingSubplans(void); -extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); +extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList, + bool *containsLocalTableOut, + bool *containsDistributedTableOut); extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, RecursivePlanningContext *context); diff --git a/src/include/distributed/var_utils.h b/src/include/distributed/var_utils.h new file mode 100644 index 000000000..04b448093 --- /dev/null +++ b/src/include/distributed/var_utils.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + * + * var_utils.h + * Utilities regarding vars + * + * Copyright (c) Citus Data, Inc. + *------------------------------------------------------------------------- + */ + + +#ifndef VAR_UTILS +#define VAR_UTILS +#include "nodes/pg_list.h" +#include "nodes/parsenodes.h" + +List * PullAllRangeTablesEntries(Query *query, List *rtableList); +#endif diff --git a/src/test/regress/expected/local_table_join_vars.out b/src/test/regress/expected/local_table_join_vars.out new file mode 100644 index 000000000..c03ba8267 --- /dev/null +++ b/src/test/regress/expected/local_table_join_vars.out @@ -0,0 +1,285 @@ +CREATE SCHEMA local_table_join_vars; +SET search_path TO local_table_join_vars; +SET client_min_messages to ERROR; +SELECT master_add_node('localhost', :master_port, groupId => 0) AS coordinator_nodeid \gset +SET client_min_messages TO DEBUG1; +CREATE TABLE postgres_table (key int, value text, value_2 jsonb); +CREATE TABLE reference_table (key int, value text, value_2 jsonb); +SELECT create_reference_table('reference_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_table (key int, value text, value_2 jsonb); +SELECT create_distributed_table('distributed_table', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_table_pkey (key int primary key, value text, value_2 jsonb); +DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "distributed_table_pkey_pkey" for table "distributed_table_pkey" +SELECT create_distributed_table('distributed_table_pkey', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_table_windex (key int primary key, value text, value_2 jsonb); +DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "distributed_table_windex_pkey" for table "distributed_table_windex" +SELECT create_distributed_table('distributed_table_windex', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE UNIQUE INDEX key_index ON distributed_table_windex (key); +CREATE TABLE citus_local(key int, value text); +SELECT create_citus_local_table('citus_local'); + create_citus_local_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_partitioned_table(key int, value text) PARTITION BY RANGE (key); +CREATE TABLE distributed_partitioned_table_1 PARTITION OF distributed_partitioned_table FOR VALUES FROM (0) TO (50); +CREATE TABLE distributed_partitioned_table_2 PARTITION OF distributed_partitioned_table FOR VALUES FROM (50) TO (200); +SELECT create_distributed_table('distributed_partitioned_table', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE local_partitioned_table(key int, value text) PARTITION BY RANGE (key); +CREATE TABLE local_partitioned_table_1 PARTITION OF local_partitioned_table FOR VALUES FROM (0) TO (50); +CREATE TABLE local_partitioned_table_2 PARTITION OF local_partitioned_table FOR VALUES FROM (50) TO (200); +CREATE TABLE distributed_table_composite (key int, value text, value_2 jsonb, primary key (key, value)); +DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "distributed_table_composite_pkey" for table "distributed_table_composite" +SELECT create_distributed_table('distributed_table_composite', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO postgres_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO reference_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +INSERT INTO distributed_table_windex SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +INSERT INTO distributed_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +INSERT INTO distributed_table_pkey SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +INSERT INTO distributed_partitioned_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +INSERT INTO distributed_table_composite SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +INSERT INTO local_partitioned_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +-- vars referencing outer queries should work in SELECT +SELECT (SELECT COUNT(*) FROM postgres_table WHERE postgres_table.key = distributed_table.key) FROM distributed_table ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) distributed_table.key)) AS count FROM local_table_join_vars.distributed_table ORDER BY (SELECT count(*) AS count FROM (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) distributed_table.key)) LIMIT 1 +DEBUG: push down of limit count: 1 + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT (SELECT COUNT(*) FROM postgres_table WHERE distributed_table.key = 5) FROM distributed_table ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) postgres_table_1) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) 5)) AS count FROM local_table_join_vars.distributed_table ORDER BY (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) postgres_table_1) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) 5)) LIMIT 1 +DEBUG: push down of limit count: 1 + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT (SELECT COUNT(*) FROM distributed_table WHERE postgres_table.key = 5) FROM postgres_table ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) distributed_table_1) distributed_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) 5)) AS count FROM local_table_join_vars.postgres_table ORDER BY (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) distributed_table_1) distributed_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) 5)) LIMIT 1 + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT (SELECT COUNT(*) FROM distributed_table WHERE postgres_table.key = distributed_table.key) FROM postgres_table ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) distributed_table.key)) AS count FROM local_table_join_vars.postgres_table ORDER BY (SELECT count(*) AS count FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) distributed_table.key)) LIMIT 1 + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- vars referencing outer queries should work in SELECT with citus local tables +SELECT (SELECT COUNT(*) FROM citus_local WHERE citus_local.key = distributed_table.key) FROM distributed_table ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local WHERE (citus_local.key OPERATOR(pg_catalog.=) distributed_table.key)) AS count FROM local_table_join_vars.distributed_table ORDER BY (SELECT count(*) AS count FROM (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local WHERE (citus_local.key OPERATOR(pg_catalog.=) distributed_table.key)) LIMIT 1 +DEBUG: push down of limit count: 1 + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT (SELECT COUNT(*) FROM citus_local WHERE distributed_table.key = 5) FROM distributed_table ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join_vars.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) citus_local_1) citus_local WHERE (distributed_table.key OPERATOR(pg_catalog.=) 5)) AS count FROM local_table_join_vars.distributed_table ORDER BY (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) citus_local_1) citus_local WHERE (distributed_table.key OPERATOR(pg_catalog.=) 5)) LIMIT 1 +DEBUG: push down of limit count: 1 + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT (SELECT COUNT(*) FROM distributed_table WHERE citus_local.key = 5) FROM citus_local ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) distributed_table_1) distributed_table WHERE (citus_local.key OPERATOR(pg_catalog.=) 5)) AS count FROM local_table_join_vars.citus_local ORDER BY (SELECT count(*) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) distributed_table_1) distributed_table WHERE (citus_local.key OPERATOR(pg_catalog.=) 5)) LIMIT 1 + count +--------------------------------------------------------------------- +(0 rows) + +SELECT (SELECT COUNT(*) FROM distributed_table WHERE citus_local.key = distributed_table.key) FROM citus_local ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT count(*) AS count FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (citus_local.key OPERATOR(pg_catalog.=) distributed_table.key)) AS count FROM local_table_join_vars.citus_local ORDER BY (SELECT count(*) AS count FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (citus_local.key OPERATOR(pg_catalog.=) distributed_table.key)) LIMIT 1 + count +--------------------------------------------------------------------- +(0 rows) + +-- vars referencing outer queries should work in WHERE +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM postgres_table WHERE key > distributed_table.key); +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.distributed_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT postgres_table.key FROM (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.>) distributed_table.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM postgres_table WHERE key in (SELECT key FROM distributed_table WHERE key > postgres_table.key); +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.postgres_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table.key FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.>) postgres_table.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM postgres_table WHERE key in (SELECT key FROM distributed_table WHERE postgres_table.key > 5); +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.postgres_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table.key FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (postgres_table.key OPERATOR(pg_catalog.>) 5))) + count +--------------------------------------------------------------------- + 95 +(1 row) + +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM postgres_table WHERE distributed_table.key > 5); +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.distributed_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT postgres_table.key FROM (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.>) 5))) + count +--------------------------------------------------------------------- + 95 +(1 row) + +-- vars referencing outer queries should work in WHERE with citus local tables +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local WHERE key > distributed_table.key); +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.distributed_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT citus_local.key FROM (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local WHERE (citus_local.key OPERATOR(pg_catalog.>) distributed_table.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table WHERE key > citus_local.key); +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.citus_local WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table.key FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.>) citus_local.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table WHERE citus_local.key > 5); +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.citus_local WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table.key FROM (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table WHERE (citus_local.key OPERATOR(pg_catalog.>) 5))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local WHERE distributed_table.key > 5); +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.distributed_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT citus_local.key FROM (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local WHERE (distributed_table.key OPERATOR(pg_catalog.>) 5))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- citus-local, local and dist should work +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local JOIN postgres_table USING(key) WHERE key > distributed_table.key); +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.citus_local WHERE true +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.distributed_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT citus_local.key FROM ((SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local JOIN (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table USING (key)) WHERE (citus_local.key OPERATOR(pg_catalog.>) distributed_table.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- Will work when we fix "correlated subqueries are not supported when the FROM clause contains a CTE or subquery" +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table JOIN postgres_table USING(key) WHERE key > citus_local.key); +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join_vars.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table.key FROM (local_table_join_vars.distributed_table JOIN (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table USING (key)) WHERE (distributed_table.key OPERATOR(pg_catalog.>) citus_local.key))) +ERROR: correlated subqueries are not supported when the FROM clause contains a CTE or subquery +-- Will work when we fix "correlated subqueries are not supported when the FROM clause contains a CTE or subquery" +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table JOIN postgres_table USING(key) WHERE citus_local.key > 5); +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join_vars.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table.key FROM (local_table_join_vars.distributed_table JOIN (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table USING (key)) WHERE (citus_local.key OPERATOR(pg_catalog.>) 5))) +ERROR: correlated subqueries are not supported when the FROM clause contains a CTE or subquery +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local JOIN postgres_table USING(key) WHERE distributed_table.key > 5); +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.citus_local WHERE true +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_table_join_vars.distributed_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT citus_local.key FROM ((SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local JOIN (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table USING (key)) WHERE (distributed_table.key OPERATOR(pg_catalog.>) 5))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- Will work when we fix "correlated subqueries are not supported when the FROM clause contains a CTE or subquery" +SELECT (SELECT (SELECT COUNT(*) FROM postgres_table WHERE postgres_table.key = distributed_table.key) FROM postgres_table p2) FROM distributed_table; +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join_vars.postgres_table WHERE true +DEBUG: Wrapping relation "postgres_table" "p2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join_vars.postgres_table p2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT (SELECT count(*) AS count FROM (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) distributed_table.key)) AS count FROM (SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) p2_1) p2) AS count FROM local_table_join_vars.distributed_table +ERROR: correlated subqueries are not supported when the FROM clause contains a CTE or subquery +RESET client_min_messages; +\set VERBOSITY terse +DROP SCHEMA local_table_join_vars CASCADE; +NOTICE: drop cascades to 11 other objects diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 015135a1d..331eedf2d 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -231,6 +231,7 @@ test: local_dist_join_modifications test: local_table_join test: local_dist_join_mixed test: citus_local_dist_joins +test: local_table_join_vars # --------- # multi_copy creates hash and range-partitioned tables and performs COPY diff --git a/src/test/regress/sql/local_table_join_vars.sql b/src/test/regress/sql/local_table_join_vars.sql new file mode 100644 index 000000000..358e75681 --- /dev/null +++ b/src/test/regress/sql/local_table_join_vars.sql @@ -0,0 +1,84 @@ +CREATE SCHEMA local_table_join_vars; +SET search_path TO local_table_join_vars; + +SET client_min_messages to ERROR; +SELECT master_add_node('localhost', :master_port, groupId => 0) AS coordinator_nodeid \gset + +SET client_min_messages TO DEBUG1; + +CREATE TABLE postgres_table (key int, value text, value_2 jsonb); +CREATE TABLE reference_table (key int, value text, value_2 jsonb); +SELECT create_reference_table('reference_table'); +CREATE TABLE distributed_table (key int, value text, value_2 jsonb); +SELECT create_distributed_table('distributed_table', 'key'); + +CREATE TABLE distributed_table_pkey (key int primary key, value text, value_2 jsonb); +SELECT create_distributed_table('distributed_table_pkey', 'key'); + +CREATE TABLE distributed_table_windex (key int primary key, value text, value_2 jsonb); +SELECT create_distributed_table('distributed_table_windex', 'key'); +CREATE UNIQUE INDEX key_index ON distributed_table_windex (key); + +CREATE TABLE citus_local(key int, value text); +SELECT create_citus_local_table('citus_local'); + +CREATE TABLE distributed_partitioned_table(key int, value text) PARTITION BY RANGE (key); +CREATE TABLE distributed_partitioned_table_1 PARTITION OF distributed_partitioned_table FOR VALUES FROM (0) TO (50); +CREATE TABLE distributed_partitioned_table_2 PARTITION OF distributed_partitioned_table FOR VALUES FROM (50) TO (200); +SELECT create_distributed_table('distributed_partitioned_table', 'key'); + +CREATE TABLE local_partitioned_table(key int, value text) PARTITION BY RANGE (key); +CREATE TABLE local_partitioned_table_1 PARTITION OF local_partitioned_table FOR VALUES FROM (0) TO (50); +CREATE TABLE local_partitioned_table_2 PARTITION OF local_partitioned_table FOR VALUES FROM (50) TO (200); + +CREATE TABLE distributed_table_composite (key int, value text, value_2 jsonb, primary key (key, value)); +SELECT create_distributed_table('distributed_table_composite', 'key'); + +INSERT INTO postgres_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO reference_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO distributed_table_windex SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO distributed_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO distributed_table_pkey SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO distributed_partitioned_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO distributed_table_composite SELECT i, i::varchar(256) FROM generate_series(1, 100) i; +INSERT INTO local_partitioned_table SELECT i, i::varchar(256) FROM generate_series(1, 100) i; + +-- vars referencing outer queries should work in SELECT +SELECT (SELECT COUNT(*) FROM postgres_table WHERE postgres_table.key = distributed_table.key) FROM distributed_table ORDER BY 1 LIMIT 1; +SELECT (SELECT COUNT(*) FROM postgres_table WHERE distributed_table.key = 5) FROM distributed_table ORDER BY 1 LIMIT 1; +SELECT (SELECT COUNT(*) FROM distributed_table WHERE postgres_table.key = 5) FROM postgres_table ORDER BY 1 LIMIT 1; +SELECT (SELECT COUNT(*) FROM distributed_table WHERE postgres_table.key = distributed_table.key) FROM postgres_table ORDER BY 1 LIMIT 1; + +-- vars referencing outer queries should work in SELECT with citus local tables +SELECT (SELECT COUNT(*) FROM citus_local WHERE citus_local.key = distributed_table.key) FROM distributed_table ORDER BY 1 LIMIT 1; +SELECT (SELECT COUNT(*) FROM citus_local WHERE distributed_table.key = 5) FROM distributed_table ORDER BY 1 LIMIT 1; +SELECT (SELECT COUNT(*) FROM distributed_table WHERE citus_local.key = 5) FROM citus_local ORDER BY 1 LIMIT 1; +SELECT (SELECT COUNT(*) FROM distributed_table WHERE citus_local.key = distributed_table.key) FROM citus_local ORDER BY 1 LIMIT 1; + +-- vars referencing outer queries should work in WHERE +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM postgres_table WHERE key > distributed_table.key); +SELECT COUNT(*) FROM postgres_table WHERE key in (SELECT key FROM distributed_table WHERE key > postgres_table.key); +SELECT COUNT(*) FROM postgres_table WHERE key in (SELECT key FROM distributed_table WHERE postgres_table.key > 5); +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM postgres_table WHERE distributed_table.key > 5); + +-- vars referencing outer queries should work in WHERE with citus local tables +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local WHERE key > distributed_table.key); +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table WHERE key > citus_local.key); +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table WHERE citus_local.key > 5); +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local WHERE distributed_table.key > 5); + +-- citus-local, local and dist should work +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local JOIN postgres_table USING(key) WHERE key > distributed_table.key); +-- Will work when we fix "correlated subqueries are not supported when the FROM clause contains a CTE or subquery" +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table JOIN postgres_table USING(key) WHERE key > citus_local.key); +-- Will work when we fix "correlated subqueries are not supported when the FROM clause contains a CTE or subquery" +SELECT COUNT(*) FROM citus_local WHERE key in (SELECT key FROM distributed_table JOIN postgres_table USING(key) WHERE citus_local.key > 5); +SELECT COUNT(*) FROM distributed_table WHERE key in (SELECT key FROM citus_local JOIN postgres_table USING(key) WHERE distributed_table.key > 5); + +-- Will work when we fix "correlated subqueries are not supported when the FROM clause contains a CTE or subquery" +SELECT (SELECT (SELECT COUNT(*) FROM postgres_table WHERE postgres_table.key = distributed_table.key) FROM postgres_table p2) FROM distributed_table; + + +RESET client_min_messages; +\set VERBOSITY terse +DROP SCHEMA local_table_join_vars CASCADE;