From 7cc25c9125cf5bb66d50f6dac58b33dc7953c229 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Tue, 7 Jul 2020 16:54:58 +0200 Subject: [PATCH 01/37] Add ability to fetch the restrictions per relation With this commit, we add the ability to add restrictions per relation. We simply rely on the restrictions that Postgres keeps per relation. --- .../relation_restriction_equivalence.c | 100 ++++++++++++++++++ .../relation_restriction_equivalence.h | 6 ++ 2 files changed, 106 insertions(+) diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index 565e17c11..e9d30ade4 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -26,9 +26,13 @@ #include "nodes/primnodes.h" #if PG_VERSION_NUM >= PG_VERSION_12 #include "nodes/pathnodes.h" +#include "optimizer/optimizer.h" #else +#include "optimizer/cost.h" #include "nodes/relation.h" #endif +#include "optimizer/paths.h" +#include "optimizer/var.h" #include "parser/parsetree.h" #include "optimizer/pathnode.h" @@ -139,6 +143,7 @@ static Index RelationRestrictionPartitionKeyIndex(RelationRestriction * relationRestriction); static bool AllRelationsInRestrictionContextColocated(RelationRestrictionContext * restrictionContext); +static bool IsParam(Node *node); static RelationRestrictionContext * FilterRelationRestrictionContext( RelationRestrictionContext *relationRestrictionContext, Relids @@ -1832,6 +1837,101 @@ FilterPlannerRestrictionForQuery(PlannerRestrictionContext *plannerRestrictionCo } +/* + * GetRestrictInfoListForRelation gets a range table entry and planner + * restriction context. The function returns a list of expressions that + * appear in the restriction context for only the given relation. And, + * all the varnos are set to 1. + */ +List * +GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, + PlannerRestrictionContext *plannerRestrictionContext) +{ + int rteIdentity = GetRTEIdentity(rangeTblEntry); + RelationRestrictionContext *relationRestrictionContext = + plannerRestrictionContext->relationRestrictionContext; + Relids queryRteIdentities = bms_make_singleton(rteIdentity); + RelationRestrictionContext *filteredRelationRestrictionContext = + FilterRelationRestrictionContext(relationRestrictionContext, queryRteIdentities); + List *filteredRelationRestrictionList = + filteredRelationRestrictionContext->relationRestrictionList; + + if (list_length(filteredRelationRestrictionList) != 1) + { + return NIL; + } + + RelationRestriction *relationRestriction = + (RelationRestriction *) linitial(filteredRelationRestrictionList); + + RelOptInfo *relOptInfo = relationRestriction->relOptInfo; + List *baseRestrictInfo = relOptInfo->baserestrictinfo; + + List *restrictExprList = NIL; + ListCell *restrictCell = NULL; + foreach(restrictCell, baseRestrictInfo) + { + RestrictInfo *restrictInfo = (RestrictInfo *) lfirst(restrictCell); + Expr *restrictionClause = restrictInfo->clause; + List *varClauses = NIL; + ListCell *varClauseCell = NULL; + Relids varnos = NULL; + + Expr *copyOfRestrictClause = NULL; + + /* we cannot process Params beacuse they are not known at this point */ + if (FindNodeCheck((Node *) restrictionClause, IsParam)) + { + continue; + } + + /* + * If the restriction involves multiple tables, we cannot add it to + * input relation's expression list. + */ + varnos = pull_varnos((Node *) restrictionClause); + if (bms_num_members(varnos) != 1) + { + continue; + } + + /* + * We're going to add this restriction expression to a subquery + * which consists of only one relation in its jointree. Thus, + * simply set the varnos accordingly. + */ + copyOfRestrictClause = (Expr *) copyObject((Node *) restrictionClause); + varClauses = pull_var_clause_default((Node *) copyOfRestrictClause); + foreach(varClauseCell, varClauses) + { + Var *column = (Var *) lfirst(varClauseCell); + + column->varno = 1; + column->varnoold = 1; + } + + restrictExprList = lappend(restrictExprList, copyOfRestrictClause); + } + + return restrictExprList; +} + + +/* + * IsParam determines whether the given node is a param. + */ +static bool +IsParam(Node *node) +{ + if (IsA(node, Param)) + { + return true; + } + + return false; +} + + /* * FilterRelationRestrictionContext gets a relation restriction context and * set of rte identities. It returns the relation restrictions that that appear diff --git a/src/include/distributed/relation_restriction_equivalence.h b/src/include/distributed/relation_restriction_equivalence.h index 028b0587a..ba89ec972 100644 --- a/src/include/distributed/relation_restriction_equivalence.h +++ b/src/include/distributed/relation_restriction_equivalence.h @@ -36,6 +36,12 @@ extern List * DistributedRelationIdList(Query *query); extern PlannerRestrictionContext * FilterPlannerRestrictionForQuery( PlannerRestrictionContext *plannerRestrictionContext, Query *query); +extern List * GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, + PlannerRestrictionContext * + plannerRestrictionContext); +extern JoinRestrictionContext * RemoveDuplicateJoinRestrictions(JoinRestrictionContext * + joinRestrictionContext); + extern bool EquivalenceListContainsRelationsEquality(List *attributeEquivalenceList, RelationRestrictionContext * restrictionContext); From 8f8390ed6ee3820dd0658d929a4b1c3c39f8ea6a Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Thu, 9 Jul 2020 12:10:43 +0200 Subject: [PATCH 02/37] Recursively plan local table joins The logical planner cannot handle joins between local and distributed table. Instead, we can recursively plan one side of the join and let the logical planner handle the rest. Our algorithm is a little smart, trying not to recursively plan distributed tables, but favors local tables. --- .../planner/multi_logical_optimizer.c | 3 +- .../planner/query_colocation_checker.c | 29 +- .../distributed/planner/recursive_planning.c | 254 ++++++++++++++++++ .../relation_restriction_equivalence.c | 16 +- src/backend/distributed/shared_library_init.c | 23 ++ .../distributed/multi_logical_optimizer.h | 1 + .../distributed/query_colocation_checker.h | 1 + src/include/distributed/recursive_planning.h | 12 + .../relation_restriction_equivalence.h | 2 +- 9 files changed, 324 insertions(+), 17 deletions(-) diff --git a/src/backend/distributed/planner/multi_logical_optimizer.c b/src/backend/distributed/planner/multi_logical_optimizer.c index 6e36c0f9f..27509e8e1 100644 --- a/src/backend/distributed/planner/multi_logical_optimizer.c +++ b/src/backend/distributed/planner/multi_logical_optimizer.c @@ -291,7 +291,6 @@ static SortGroupClause * CreateSortGroupClause(Var *column); /* Local functions forward declarations for count(distinct) approximations */ static const char * CountDistinctHashFunctionName(Oid argumentType); static int CountDistinctStorageSize(double approximationErrorRate); -static Const * MakeIntegerConst(int32 integerValue); static Const * MakeIntegerConstInt64(int64 integerValue); /* Local functions forward declarations for aggregate expression checks */ @@ -3790,7 +3789,7 @@ CountDistinctStorageSize(double approximationErrorRate) /* Makes an integer constant node from the given value, and returns that node. */ -static Const * +Const * MakeIntegerConst(int32 integerValue) { const int typeCollationId = get_typcollation(INT4OID); diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index 0a84ea49e..5016cf34e 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -33,10 +33,10 @@ #include "parser/parse_relation.h" #include "optimizer/planner.h" #include "optimizer/prep.h" +#include "utils/rel.h" static RangeTblEntry * AnchorRte(Query *subquery); -static Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation); static List * UnionRelationRestrictionLists(List *firstRelationList, List *secondRelationList); @@ -252,7 +252,7 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker) * projections. The returned query should be used cautiosly and it is mostly * designed for generating a stub query. */ -static Query * +Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation) { Query *subquery = makeNode(Query); @@ -269,15 +269,26 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation) newRangeTableRef->rtindex = 1; subquery->jointree = makeFromExpr(list_make1(newRangeTableRef), NULL); - /* Need the whole row as a junk var */ - Var *targetColumn = makeWholeRowVar(newRangeTableEntry, newRangeTableRef->rtindex, 0, - false); - /* create a dummy target entry */ - TargetEntry *targetEntry = makeTargetEntry((Expr *) targetColumn, 1, "wholerow", - true); + Relation relation = relation_open(rteRelation->relid, AccessShareLock); + int numberOfAttributes = RelationGetNumberOfAttributes(relation); - subquery->targetList = lappend(subquery->targetList, targetEntry); + int attributeNumber = 1; + for (; attributeNumber <= numberOfAttributes; attributeNumber++) + { + Form_pg_attribute attributeTuple = + TupleDescAttr(relation->rd_att, attributeNumber - 1); + Var *targetColumn = + makeVar(newRangeTableRef->rtindex, attributeNumber, attributeTuple->atttypid, + attributeTuple->atttypmod, attributeTuple->attcollation, 0); + TargetEntry *targetEntry = + makeTargetEntry((Expr *) targetColumn, attributeNumber, + strdup(attributeTuple->attname.data), false); + + subquery->targetList = lappend(subquery->targetList, targetEntry); + } + + relation_close(relation, NoLock); return subquery; } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index c6dce836e..e68052a5f 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -63,6 +63,7 @@ #include "distributed/log_utils.h" #include "distributed/metadata_cache.h" #include "distributed/multi_logical_planner.h" +#include "distributed/multi_logical_optimizer.h" #include "distributed/multi_router_planner.h" #include "distributed/multi_physical_planner.h" #include "distributed/multi_server_executor.h" @@ -73,12 +74,14 @@ #include "distributed/log_utils.h" #include "distributed/version_compat.h" #include "lib/stringinfo.h" +#include "optimizer/clauses.h" #include "optimizer/planner.h" #include "optimizer/prep.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 "nodes/primnodes.h" #if PG_VERSION_NUM >= PG_VERSION_12 @@ -88,6 +91,13 @@ #endif #include "utils/builtins.h" #include "utils/guc.h" +#include "utils/lsyscache.h" + + +/* + * Managed via a GUC + */ +int LocalTableJoinPolicy = LOCAL_JOIN_POLICY_AUTO; /* track depth of current recursive planner query */ @@ -175,6 +185,16 @@ static bool ContainsReferencesToOuterQuery(Query *query); static bool ContainsReferencesToOuterQueryWalker(Node *node, VarLevelsUpWalkerContext *context); static bool NodeContainsSubqueryReferencingOuterQuery(Node *node); +static void ConvertLocalTableJoinsToSubqueries(Query *query, + PlannerRestrictionContext * + plannerRestrictionContext); +static RangeTblEntry * MostFilteredRte(PlannerRestrictionContext * + plannerRestrictionContext, + List *rangeTableList, List **restrictionList, + bool localTable); +static void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, + List *restrictionList); +static bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); static void WrapFunctionsInSubqueries(Query *query); static void TransformFunctionRTE(RangeTblEntry *rangeTblEntry); static bool ShouldTransformRTE(RangeTblEntry *rangeTableEntry); @@ -287,6 +307,12 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context /* make sure function calls in joins are executed in the coordinator */ WrapFunctionsInSubqueries(query); + /* + * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", so we + * recursively plan one side of the join so that the logical planner can plan. + */ + ConvertLocalTableJoinsToSubqueries(query, context->plannerRestrictionContext); + /* descend into subqueries */ query_tree_walker(query, RecursivelyPlanSubqueryWalker, context, 0); @@ -1125,6 +1151,7 @@ RecursivelyPlanSubquery(Query *subquery, RecursivePlanningContext *planningConte debugQuery = copyObject(subquery); } + /* * Create the subplan and append it to the list in the planning context. */ @@ -1337,6 +1364,233 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) } +/* + * ConvertLocalTableJoinsToSubqueries gets a query and the planner + * restrictions. As long as there is a join between a local table + * and distributed table, the function wraps one table in a + * subquery (by also pushing the filters on the table down + * to the subquery). + * + * Once this function returns, there are no direct joins between + * local and distributed tables. + */ +static void +ConvertLocalTableJoinsToSubqueries(Query *query, + PlannerRestrictionContext *plannerRestrictionContext) +{ + List *rangeTableList = query->rtable; + + if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) + { + /* user doesn't want Citus to enable local table joins */ + return; + } + + if (!ContainsLocalTableDistributedTableJoin(rangeTableList)) + { + /* nothing to do as there are no relevant joins */ + return; + } + + { + /* TODO: if all tables are local, skip */ + } + + while (ContainsLocalTableDistributedTableJoin(rangeTableList)) + { + List *localTableRestrictList = NIL; + List *distributedTableRestrictList = NIL; + + bool localTable = true; + + RangeTblEntry *mostFilteredLocalRte = + MostFilteredRte(plannerRestrictionContext, rangeTableList, + &localTableRestrictList, localTable); + RangeTblEntry *mostFilteredDistributedRte = + MostFilteredRte(plannerRestrictionContext, rangeTableList, + &distributedTableRestrictList, !localTable); + + if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PULL_LOCAL) + { + ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, + localTableRestrictList); + } + else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PULL_DISTRIBUTED) + { + ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, + distributedTableRestrictList); + } + else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_AUTO) + { + bool localTableHasFilter = list_length(localTableRestrictList) > 0; + bool distributedTableHasFilter = + list_length(distributedTableRestrictList) > 0; + + /* TODO: for modifications, either skip or do not plan target table */ + + /* + * First, favor recursively planning local table when it has a filter. + * The rationale is that local tables are small, and at least one filter + * they become even smaller. On each iteration, we pick the local table + * with the most filters (e.g., WHERE clause entries). Note that the filters + * don't need to be directly on the table in the query tree, instead we use + * Postgres' filters where filters can be pushed down tables via filters. + * + * Second, if a distributed table doesn't have a filter, we do not ever + * prefer recursively planning that. Instead, we recursively plan the + * local table, assuming that it is smaller. + * + * TODO: If we have better statistics on how many tuples each table returns + * considering the filters on them, we should pick the table with least + * tuples. Today, we do not have such an infrastructure. + */ + if (localTableHasFilter || !distributedTableHasFilter) + { + ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, + localTableRestrictList); + } + else + { + ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, + distributedTableRestrictList); + } + } + else + { + elog(ERROR, "unexpected local table join policy: %d", LocalTableJoinPolicy); + } + } +} + + +/* + * MostFilteredRte returns a range table entry which has the most filters + * on it along with the restrictions (e.g., fills **restrictionList). + * + * The function also gets a boolean localTable parameter, so the caller + * can choose to run the function for only local tables or distributed tables. + */ +static RangeTblEntry * +MostFilteredRte(PlannerRestrictionContext *plannerRestrictionContext, + List *rangeTableList, List **restrictionList, + bool localTable) +{ + RangeTblEntry *mostFilteredLocalRte = NULL; + + ListCell *rangeTableCell = NULL; + + foreach(rangeTableCell, rangeTableList) + { + RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); + + /* we're only interested in tables */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) + { + continue; + } + + if (IsCitusTable(rangeTableEntry->relid) && localTable) + { + continue; + } + + List *currentRestrictionList = + GetRestrictInfoListForRelation(rangeTableEntry, + plannerRestrictionContext, 1); + + if (mostFilteredLocalRte == NULL || + list_length(*restrictionList) < list_length(currentRestrictionList)) + { + mostFilteredLocalRte = rangeTableEntry; + *restrictionList = currentRestrictionList; + } + } + + return mostFilteredLocalRte; +} + + +/* + * ReplaceRTERelationWithRteSubquery replaces the input rte relation target entry + * with a subquery. The function also pushes down the filters to the subquery. + */ +static void +ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList) +{ + Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry); + Expr *andedBoundExpressions = make_ands_explicit(restrictionList); + subquery->jointree->quals = (Node *) andedBoundExpressions; + + /* force recursively planning of the newly created subquery */ + subquery->limitOffset = (Node *) MakeIntegerConst(0); + + /* replace the function with the constructed subquery */ + rangeTableEntry->rtekind = RTE_SUBQUERY; + rangeTableEntry->subquery = subquery; + + /* + * If the relation is inherited, it'll still be inherited as + * we've copied it earlier. This is to prevent the newly created + * subquery being treated as inherited. + */ + rangeTableEntry->inh = false; + + if (IsLoggableLevel(DEBUG1)) + { + StringInfo subqueryString = makeStringInfo(); + + pg_get_query_def(subquery, subqueryString); + + ereport(DEBUG1, (errmsg("Wrapping local relation \"%s\" to a subquery: %s ", + get_rel_name(rangeTableEntry->relid), + ApplyLogRedaction(subqueryString->data)))); + } +} + + +/* + * ContainsLocalTableDistributedTableJoin returns true if the input range table list + * contains a direct join between local and distributed tables. + */ +static bool +ContainsLocalTableDistributedTableJoin(List *rangeTableList) +{ + bool containsLocalTable = false; + bool containsDistributedTable = false; + + ListCell *rangeTableCell = NULL; + foreach(rangeTableCell, rangeTableList) + { + RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); + + /* we're only interested in tables */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) + { + continue; + } + + /* TODO: do NOT forget Citus local tables */ + if (IsCitusTable(rangeTableEntry->relid)) + { + containsDistributedTable = true; + } + else + { + containsLocalTable = true; + } + + if (containsLocalTable && containsDistributedTable) + { + return true; + } + } + + return false; +} + + /* * WrapFunctionsInSubqueries iterates over all the immediate Range Table Entries * of a query and wraps the functions inside (SELECT * FROM fnc() f) diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index e9d30ade4..e1c480336 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -488,9 +488,13 @@ FindUnionAllVar(PlannerInfo *root, List *appendRelList, Oid relationOid, bool RestrictionEquivalenceForPartitionKeys(PlannerRestrictionContext *restrictionContext) { - /* there is a single distributed relation, no need to continue */ - if (!ContainsMultipleDistributedRelations(restrictionContext)) + if (ContextContainsLocalRelation(restrictionContext->relationRestrictionContext)) { + return false; + } + else if (!ContainsMultipleDistributedRelations(restrictionContext)) + { + /* there is a single distributed relation, no need to continue */ return true; } @@ -1845,7 +1849,8 @@ FilterPlannerRestrictionForQuery(PlannerRestrictionContext *plannerRestrictionCo */ List * GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, - PlannerRestrictionContext *plannerRestrictionContext) + PlannerRestrictionContext *plannerRestrictionContext, + int rteIndex) { int rteIdentity = GetRTEIdentity(rangeTblEntry); RelationRestrictionContext *relationRestrictionContext = @@ -1867,6 +1872,7 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, RelOptInfo *relOptInfo = relationRestriction->relOptInfo; List *baseRestrictInfo = relOptInfo->baserestrictinfo; + List *restrictExprList = NIL; ListCell *restrictCell = NULL; foreach(restrictCell, baseRestrictInfo) @@ -1906,8 +1912,8 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, { Var *column = (Var *) lfirst(varClauseCell); - column->varno = 1; - column->varnoold = 1; + column->varno = rteIndex; + column->varnoold = rteIndex; } restrictExprList = lappend(restrictExprList, copyOfRestrictClause); diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 6c4de8fe5..fbf9c14ab 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -55,6 +55,7 @@ #include "distributed/multi_server_executor.h" #include "distributed/pg_dist_partition.h" #include "distributed/placement_connection.h" +#include "distributed/recursive_planning.h" #include "distributed/reference_table_utils.h" #include "distributed/relation_access_tracking.h" #include "distributed/run_from_same_connection.h" @@ -196,6 +197,16 @@ static const struct config_enum_entry log_level_options[] = { { NULL, 0, false} }; + +static const struct config_enum_entry local_table_join_policies[] = { + { "never", LOCAL_JOIN_POLICY_NEVER, false}, + { "pull-local", LOCAL_JOIN_POLICY_PULL_LOCAL, false}, + { "pull-distributed", LOCAL_JOIN_POLICY_PULL_DISTRIBUTED, false}, + { "auto", LOCAL_JOIN_POLICY_AUTO, false}, + { NULL, 0, false} +}; + + static const struct config_enum_entry multi_shard_modify_connection_options[] = { { "parallel", PARALLEL_CONNECTION, false }, { "sequential", SEQUENTIAL_CONNECTION, false }, @@ -708,6 +719,18 @@ RegisterCitusConfigVariables(void) PGC_SIGHUP, GUC_SUPERUSER_ONLY, NULL, NULL, LocalPoolSizeGucShowHook); + + DefineCustomEnumVariable( + "citus.local_table_join_policy", + gettext_noop("defines the behaviour when a distributed table " + "is joined with a local table"), + gettext_noop("TODO: fill"), + &LocalTableJoinPolicy, + LOCAL_JOIN_POLICY_AUTO, + local_table_join_policies, + PGC_USERSET, + GUC_STANDARD, + NULL, NULL, NULL); DefineCustomBoolVariable( "citus.log_multi_join_order", diff --git a/src/include/distributed/multi_logical_optimizer.h b/src/include/distributed/multi_logical_optimizer.h index 9e6167959..ddfaae315 100644 --- a/src/include/distributed/multi_logical_optimizer.h +++ b/src/include/distributed/multi_logical_optimizer.h @@ -177,5 +177,6 @@ extern void FindReferencedTableColumn(Expr *columnExpression, List *parentQueryL extern char * WorkerColumnName(AttrNumber resno); extern bool IsGroupBySubsetOfDistinct(List *groupClauses, List *distinctClauses); extern bool TargetListHasAggregates(List *targetEntryList); +extern Const * MakeIntegerConst(int32 integerValue); #endif /* MULTI_LOGICAL_OPTIMIZER_H */ diff --git a/src/include/distributed/query_colocation_checker.h b/src/include/distributed/query_colocation_checker.h index 0c8c7292b..2a27fa9f1 100644 --- a/src/include/distributed/query_colocation_checker.h +++ b/src/include/distributed/query_colocation_checker.h @@ -34,6 +34,7 @@ extern ColocatedJoinChecker CreateColocatedJoinChecker(Query *subquery, PlannerRestrictionContext * restrictionContext); extern bool SubqueryColocated(Query *subquery, ColocatedJoinChecker *context); +extern Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation); #endif /* QUERY_COLOCATION_CHECKER_H */ diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index e1017bd70..1da704dff 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -22,6 +22,18 @@ #include "nodes/relation.h" #endif +/* managed via guc.c */ +typedef enum +{ + LOCAL_JOIN_POLICY_NEVER = 0, + LOCAL_JOIN_POLICY_PULL_LOCAL = 1, + LOCAL_JOIN_POLICY_PULL_DISTRIBUTED = 2, + LOCAL_JOIN_POLICY_AUTO = 3, +} LocalJoinPolicy; + +extern int LocalTableJoinPolicy; + + extern List * GenerateSubplansForSubqueriesAndCTEs(uint64 planId, Query *originalQuery, PlannerRestrictionContext * plannerRestrictionContext); diff --git a/src/include/distributed/relation_restriction_equivalence.h b/src/include/distributed/relation_restriction_equivalence.h index ba89ec972..4c1406f8e 100644 --- a/src/include/distributed/relation_restriction_equivalence.h +++ b/src/include/distributed/relation_restriction_equivalence.h @@ -38,7 +38,7 @@ extern PlannerRestrictionContext * FilterPlannerRestrictionForQuery( Query *query); extern List * GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, PlannerRestrictionContext * - plannerRestrictionContext); + plannerRestrictionContext, int rteIndex); extern JoinRestrictionContext * RemoveDuplicateJoinRestrictions(JoinRestrictionContext * joinRestrictionContext); From 7a4d6b2984a740f8783859a988767d877870cca0 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Tue, 14 Jul 2020 13:56:11 +0200 Subject: [PATCH 03/37] Handle modifications as well --- .../distributed/metadata/metadata_utility.c | 3 +- .../planner/multi_router_planner.c | 28 +++- .../distributed/planner/recursive_planning.c | 121 ++++++++++++++---- src/include/distributed/metadata_utility.h | 5 + src/include/distributed/recursive_planning.h | 2 + 5 files changed, 130 insertions(+), 29 deletions(-) diff --git a/src/backend/distributed/metadata/metadata_utility.c b/src/backend/distributed/metadata/metadata_utility.c index 35dc01cf4..af1563129 100644 --- a/src/backend/distributed/metadata/metadata_utility.c +++ b/src/backend/distributed/metadata/metadata_utility.c @@ -78,7 +78,6 @@ static bool DistributedTableSizeOnWorker(WorkerNode *workerNode, Oid relationId, uint64 *tableSize); static List * ShardIntervalsOnWorkerGroup(WorkerNode *workerNode, Oid relationId); static void ErrorIfNotSuitableToGetSize(Oid relationId); -static ShardPlacement * ShardPlacementOnGroup(uint64 shardId, int groupId); /* exports for SQL callable functions */ @@ -1295,7 +1294,7 @@ UpdatePartitionShardPlacementStates(ShardPlacement *parentShardPlacement, char s * of the shard on the given group. If no such placement exists, the function * return NULL. */ -static ShardPlacement * +ShardPlacement * ShardPlacementOnGroup(uint64 shardId, int groupId) { List *placementList = ShardPlacementList(shardId); diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index eaba0ff02..0062e4534 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -512,6 +512,8 @@ IsTidColumn(Node *node) } +#include "distributed/recursive_planning.h" + /* * ModifyPartialQuerySupported implements a subset of what ModifyQuerySupported checks, * that subset being what's necessary to check modifying CTEs for. @@ -521,7 +523,15 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, Oid *distributedTableIdOutput) { DeferredErrorMessage *deferredError = DeferErrorIfModifyView(queryTree); - if (deferredError != NULL) + if (deferredError != NULL) { + return deferredError; + } + uint32 rangeTableId = 1; + CmdType commandType = queryTree->commandType; + + Oid distributedTableId = ModifyQueryResultRelationId(queryTree); + *distributedTableIdOutput = distributedTableId; + if (ContainsLocalTableDistributedTableJoin(queryTree->rtable)) { return deferredError; } @@ -531,6 +541,18 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, { return deferredError; } + Var *partitionColumn = NULL; + + if (IsCitusTable(distributedTableId)) + { + partitionColumn = PartitionColumn(distributedTableId, rangeTableId); + } + + deferredError = DeferErrorIfModifyView(queryTree); + if (deferredError != NULL) + { + return deferredError; + } /* * Reject subqueries which are in SELECT or WHERE clause. @@ -939,9 +961,7 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer /* for other kinds of relations, check if its distributed */ else { - Oid relationId = rangeTableEntry->relid; - - if (!IsCitusTable(relationId)) + if (ContainsLocalTableDistributedTableJoin(queryTree->rtable)) { StringInfo errorMessage = makeStringInfo(); char *relationName = get_rel_name(rangeTableEntry->relid); diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index e68052a5f..898f00280 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -194,7 +194,7 @@ static RangeTblEntry * MostFilteredRte(PlannerRestrictionContext * bool localTable); static void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList); -static bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); +static bool AllDataLocallyAccessible(List *rangeTableList); static void WrapFunctionsInSubqueries(Query *query); static void TransformFunctionRTE(RangeTblEntry *rangeTblEntry); static bool ShouldTransformRTE(RangeTblEntry *rangeTableEntry); @@ -1392,10 +1392,14 @@ ConvertLocalTableJoinsToSubqueries(Query *query, return; } + if (AllDataLocallyAccessible(rangeTableList)) { - /* TODO: if all tables are local, skip */ + /* recursively planning is overkill, router planner can already handle this */ + return; } + RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); + while (ContainsLocalTableDistributedTableJoin(rangeTableList)) { List *localTableRestrictList = NIL; @@ -1410,6 +1414,11 @@ ConvertLocalTableJoinsToSubqueries(Query *query, MostFilteredRte(plannerRestrictionContext, rangeTableList, &distributedTableRestrictList, !localTable); + elog(DEBUG4, "Local relation with the most number of filters " + "on it: \"%s\"", get_rel_name(mostFilteredLocalRte->relid)); + elog(DEBUG4, "Distributed relation with the most number of filters " + "on it: \"%s\"", get_rel_name(mostFilteredDistributedRte->relid)); + if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PULL_LOCAL) { ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, @@ -1426,26 +1435,37 @@ ConvertLocalTableJoinsToSubqueries(Query *query, bool distributedTableHasFilter = list_length(distributedTableRestrictList) > 0; - /* TODO: for modifications, either skip or do not plan target table */ - - /* - * First, favor recursively planning local table when it has a filter. - * The rationale is that local tables are small, and at least one filter - * they become even smaller. On each iteration, we pick the local table - * with the most filters (e.g., WHERE clause entries). Note that the filters - * don't need to be directly on the table in the query tree, instead we use - * Postgres' filters where filters can be pushed down tables via filters. - * - * Second, if a distributed table doesn't have a filter, we do not ever - * prefer recursively planning that. Instead, we recursively plan the - * local table, assuming that it is smaller. - * - * TODO: If we have better statistics on how many tuples each table returns - * considering the filters on them, we should pick the table with least - * tuples. Today, we do not have such an infrastructure. - */ - if (localTableHasFilter || !distributedTableHasFilter) + if (resultRelation && resultRelation->relid == mostFilteredLocalRte->relid && + !mostFilteredLocalRte->inFromCl) { + /* + * We cannot recursively plan result relation, we have to + * recursively plan the distributed table. + * + * TODO: A future improvement could be to pick the next most filtered + * local relation, if exists. + */ + ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, + distributedTableRestrictList); + } + else if (localTableHasFilter || !distributedTableHasFilter) + { + /* + * First, favor recursively planning local table when it has a filter. + * The rationale is that local tables are small, and at least one filter + * they become even smaller. On each iteration, we pick the local table + * with the most filters (e.g., WHERE clause entries). Note that the filters + * don't need to be directly on the table in the query tree, instead we use + * Postgres' filters where filters can be pushed down tables via filters. + * + * Second, if a distributed table doesn't have a filter, we do not ever + * prefer recursively planning that. Instead, we recursively plan the + * local table, assuming that it is smaller. + * + * TODO: If we have better statistics on how many tuples each table returns + * considering the filters on them, we should pick the table with least + * tuples. Today, we do not have such an infrastructure. + */ ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, localTableRestrictList); } @@ -1490,7 +1510,12 @@ MostFilteredRte(PlannerRestrictionContext *plannerRestrictionContext, continue; } - if (IsCitusTable(rangeTableEntry->relid) && localTable) + if (localTable && IsCitusTable(rangeTableEntry->relid)) + { + continue; + } + + if (!localTable && !IsCitusTable(rangeTableEntry->relid)) { continue; } @@ -1549,11 +1574,61 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict } +/* + * AllDataLocallyAccessible return true if all data for the relations in the + * rangeTableList is locally accessible. + */ +static bool +AllDataLocallyAccessible(List *rangeTableList) +{ + ListCell *rangeTableCell = NULL; + foreach(rangeTableCell, rangeTableList) + { + RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); + + /* we're only interested in tables */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) + { + continue; + } + + + Oid relationId = rangeTableEntry->relid; + + if (!IsCitusTable(relationId)) + { + /* local tables are locally accessible */ + continue; + } + + List *shardIntervalList = LoadShardIntervalList(relationId); + if (list_length(shardIntervalList) > 1) + { + /* we currently only consider single placement tables */ + return false; + } + + ShardInterval *shardInterval = linitial(shardIntervalList); + uint64 shardId = shardInterval->shardId; + ShardPlacement *localShardPlacement = + ShardPlacementOnGroup(shardId, GetLocalGroupId()); + if (localShardPlacement == NULL) + { + /* the table doesn't have a placement on this node */ + return false; + } + } + + return true; +} + + /* * ContainsLocalTableDistributedTableJoin returns true if the input range table list * contains a direct join between local and distributed tables. */ -static bool +bool ContainsLocalTableDistributedTableJoin(List *rangeTableList) { bool containsLocalTable = false; diff --git a/src/include/distributed/metadata_utility.h b/src/include/distributed/metadata_utility.h index 5db5b0b69..d41a1c53a 100644 --- a/src/include/distributed/metadata_utility.h +++ b/src/include/distributed/metadata_utility.h @@ -113,7 +113,12 @@ extern List * AllShardPlacementsOnNodeGroup(int32 groupId); extern List * GroupShardPlacementsForTableOnGroup(Oid relationId, int32 groupId); extern StringInfo GenerateSizeQueryOnMultiplePlacements(List *shardIntervalList, char *sizeQuery); +<<<<<<< HEAD extern List * RemoveCoordinatorPlacementIfNotSingleNode(List *placementList); +======= +extern ShardPlacement * ShardPlacementOnGroup(uint64 shardId, int groupId); + +>>>>>>> Handle modifications as well /* Function declarations to modify shard and shard placement data */ extern void InsertShardRow(Oid relationId, uint64 shardId, char storageType, diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 1da704dff..28f9f6e5d 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -45,5 +45,7 @@ extern Query * BuildReadIntermediateResultsArrayQuery(List *targetEntryList, List *resultIdList, bool useBinaryCopyFormat); extern bool GeneratingSubplans(void); +extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); + #endif /* RECURSIVE_PLANNING_H */ From 82a4830c7de9220296d27d2b3f60332f30010163 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Thu, 16 Jul 2020 18:45:19 +0200 Subject: [PATCH 04/37] Adjust the existing regression tests --- .../planner/query_colocation_checker.c | 8 ++++++- .../relation_restriction_equivalence.c | 18 ++++++--------- .../expected/coordinator_shouldhaveshards.out | 22 ++++++++++++++----- src/test/regress/expected/dml_recursive.out | 11 ++++++---- .../regress/expected/multi_modifications.out | 9 +++----- .../expected/multi_mx_modifications.out | 2 -- .../regress/expected/multi_shard_modify.out | 7 ++++-- .../expected/multi_shard_update_delete.out | 6 +---- .../regress/expected/multi_simple_queries.out | 19 ++++++++++------ .../expected/multi_simple_queries_0.out | 8 +++---- src/test/regress/expected/with_executors.out | 20 +++++++++++------ src/test/regress/expected/with_modifying.out | 11 +++++----- .../sql/coordinator_shouldhaveshards.sql | 4 ++-- src/test/regress/sql/dml_recursive.sql | 6 +++-- src/test/regress/sql/multi_modifications.sql | 2 +- .../regress/sql/multi_shard_update_delete.sql | 2 +- src/test/regress/sql/multi_simple_queries.sql | 4 ++-- src/test/regress/sql/with_executors.sql | 6 ++--- src/test/regress/sql/with_modifying.sql | 3 ++- 19 files changed, 96 insertions(+), 72 deletions(-) diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index 5016cf34e..f0c11cbc0 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -21,6 +21,13 @@ #include "postgres.h" +#include "distributed/pg_version_constants.h" + +#if PG_VERSION_NUM >= PG_VERSION_12 +#include "access/relation.h" +#else +#include "access/heapam.h" +#endif #include "distributed/multi_logical_planner.h" #include "distributed/query_colocation_checker.h" #include "distributed/pg_dist_partition.h" @@ -269,7 +276,6 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation) newRangeTableRef->rtindex = 1; subquery->jointree = makeFromExpr(list_make1(newRangeTableRef), NULL); - Relation relation = relation_open(rteRelation->relid, AccessShareLock); int numberOfAttributes = RelationGetNumberOfAttributes(relation); diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index e1c480336..782005abb 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -30,9 +30,9 @@ #else #include "optimizer/cost.h" #include "nodes/relation.h" +#include "optimizer/var.h" #endif #include "optimizer/paths.h" -#include "optimizer/var.h" #include "parser/parsetree.h" #include "optimizer/pathnode.h" @@ -1879,14 +1879,9 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, { RestrictInfo *restrictInfo = (RestrictInfo *) lfirst(restrictCell); Expr *restrictionClause = restrictInfo->clause; - List *varClauses = NIL; - ListCell *varClauseCell = NULL; - Relids varnos = NULL; - - Expr *copyOfRestrictClause = NULL; /* we cannot process Params beacuse they are not known at this point */ - if (FindNodeCheck((Node *) restrictionClause, IsParam)) + if (FindNodeMatchingCheckFunction((Node *) restrictionClause, IsParam)) { continue; } @@ -1895,7 +1890,7 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, * If the restriction involves multiple tables, we cannot add it to * input relation's expression list. */ - varnos = pull_varnos((Node *) restrictionClause); + Relids varnos = pull_varnos((Node *) restrictionClause); if (bms_num_members(varnos) != 1) { continue; @@ -1906,14 +1901,15 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, * which consists of only one relation in its jointree. Thus, * simply set the varnos accordingly. */ - copyOfRestrictClause = (Expr *) copyObject((Node *) restrictionClause); - varClauses = pull_var_clause_default((Node *) copyOfRestrictClause); + Expr *copyOfRestrictClause = (Expr *) copyObject((Node *) restrictionClause); + List *varClauses = pull_var_clause_default((Node *) copyOfRestrictClause); + ListCell *varClauseCell = NULL; foreach(varClauseCell, varClauses) { Var *column = (Var *) lfirst(varClauseCell); column->varno = rteIndex; - column->varnoold = rteIndex; + column->varnosyn = rteIndex; } restrictExprList = lappend(restrictExprList, copyOfRestrictClause); diff --git a/src/test/regress/expected/coordinator_shouldhaveshards.out b/src/test/regress/expected/coordinator_shouldhaveshards.out index 300c390d0..78597ecce 100644 --- a/src/test/regress/expected/coordinator_shouldhaveshards.out +++ b/src/test/regress/expected/coordinator_shouldhaveshards.out @@ -417,12 +417,22 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut INSERT INTO dist_table VALUES(1); NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.dist_table_1503017 (a) VALUES (1) -SELECT * FROM local JOIN dist_table ON (a = x); -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins -SELECT * FROM local JOIN dist_table ON (a = x) WHERE a = 1;; -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins +SELECT * FROM local JOIN dist_table ON (a = x) ORDER BY 1,2,3; + x | y | a +--------------------------------------------------------------------- + 1 | 2 | 1 + 1 | 2 | 1 + 3 | 2 | 3 +(3 rows) + +SELECT * FROM local JOIN dist_table ON (a = x) WHERE a = 1 ORDER BY 1,2,3; +NOTICE: executing the command locally: SELECT local.x, local.y, dist_table.a FROM ((SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) local JOIN coordinator_shouldhaveshards.dist_table_1503017 dist_table ON ((dist_table.a OPERATOR(pg_catalog.=) local.x))) WHERE (dist_table.a OPERATOR(pg_catalog.=) 1) ORDER BY local.x, local.y, dist_table.a + x | y | a +--------------------------------------------------------------------- + 1 | 2 | 1 + 1 | 2 | 1 +(2 rows) + -- intermediate results are allowed WITH cte_1 AS (SELECT * FROM dist_table ORDER BY 1 LIMIT 1) SELECT * FROM ref JOIN local ON (a = x) JOIN cte_1 ON (local.x = cte_1.a); diff --git a/src/test/regress/expected/dml_recursive.out b/src/test/regress/expected/dml_recursive.out index e5a720618..f14baaeb5 100644 --- a/src/test/regress/expected/dml_recursive.out +++ b/src/test/regress/expected/dml_recursive.out @@ -340,8 +340,10 @@ FROM cte_1 WHERE distributed_table.tenant_id < cte_1.tenant_id; DEBUG: generating subplan XXX_1 for CTE cte_1: WITH cte_2 AS (SELECT second_distributed_table.tenant_id AS cte2_id FROM recursive_dml_queries.second_distributed_table WHERE (second_distributed_table.dept OPERATOR(pg_catalog.>=) 2)) UPDATE recursive_dml_queries.distributed_table SET dept = 10 RETURNING tenant_id, dept, info DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE recursive_dml_queries.distributed_table SET dept = 5 FROM (SELECT intermediate_result.tenant_id, intermediate_result.dept, intermediate_result.info FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(tenant_id text, dept integer, info jsonb)) cte_1 WHERE (distributed_table.tenant_id OPERATOR(pg_catalog.<) cte_1.tenant_id) --- we don't support updating local table with a join with --- distributed tables +-- we support updating local table with a join with +-- distributed tables, though as the local table +-- is target here, distributed table is recursively +-- planned UPDATE local_table SET @@ -350,8 +352,9 @@ FROM distributed_table WHERE distributed_table.tenant_id = local_table.id; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT tenant_id, dept, info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id, dept, info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE recursive_dml_queries.local_table SET id = 'citus_test'::text FROM (SELECT intermediate_result.tenant_id, intermediate_result.dept, intermediate_result.info FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(tenant_id text, dept integer, info jsonb)) distributed_table WHERE (distributed_table.tenant_id OPERATOR(pg_catalog.=) local_table.id) RESET client_min_messages; DROP SCHEMA recursive_dml_queries CASCADE; NOTICE: drop cascades to 5 other objects diff --git a/src/test/regress/expected/multi_modifications.out b/src/test/regress/expected/multi_modifications.out index 05ba0a3d7..ee24d4c99 100644 --- a/src/test/regress/expected/multi_modifications.out +++ b/src/test/regress/expected/multi_modifications.out @@ -270,8 +270,6 @@ CREATE TABLE bidders ( name text, id bigint ); DELETE FROM limit_orders USING bidders WHERE limit_orders.id = 246 AND limit_orders.bidder_id = bidders.id AND bidders.name = 'Bernie Madoff'; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins -- commands containing a CTE are supported WITH new_orders AS (INSERT INTO limit_orders VALUES (411, 'FLO', 12, '2017-07-02 16:32:15', 'buy', 66)) DELETE FROM limit_orders WHERE id < 0; @@ -429,13 +427,11 @@ ERROR: modifying the partition value of rows is not allowed UPDATE limit_orders SET id = 246 WHERE id = 246; UPDATE limit_orders SET id = 246 WHERE id = 246 AND symbol = 'GM'; UPDATE limit_orders SET id = limit_orders.id WHERE id = 246; --- UPDATEs with a FROM clause are unsupported +-- UPDATEs with a FROM clause are supported even with local tables UPDATE limit_orders SET limit_price = 0.00 FROM bidders WHERE limit_orders.id = 246 AND limit_orders.bidder_id = bidders.id AND bidders.name = 'Bernie Madoff'; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins -- should succeed with a CTE WITH deleted_orders AS (INSERT INTO limit_orders VALUES (399, 'PDR', 14, '2017-07-02 16:32:15', 'sell', 43)) UPDATE limit_orders SET symbol = 'GM'; @@ -1306,7 +1302,8 @@ DELETE FROM summary_table WHERE id < ( ); CREATE TABLE multi_modifications.local (a int default 1, b int); INSERT INTO multi_modifications.local VALUES (default, (SELECT min(id) FROM summary_table)); -ERROR: cannot plan modifications of local tables involving distributed tables +ERROR: subqueries are not supported within INSERT queries +HINT: Try rewriting your queries with 'INSERT INTO ... SELECT' syntax. DROP TABLE raw_table; DROP TABLE summary_table; DROP TABLE reference_raw_table; diff --git a/src/test/regress/expected/multi_mx_modifications.out b/src/test/regress/expected/multi_mx_modifications.out index c78b1d98f..14468b95a 100644 --- a/src/test/regress/expected/multi_mx_modifications.out +++ b/src/test/regress/expected/multi_mx_modifications.out @@ -158,7 +158,6 @@ CREATE TABLE bidders ( name text, id bigint ); DELETE FROM limit_orders_mx USING bidders WHERE limit_orders_mx.id = 246 AND limit_orders_mx.bidder_id = bidders.id AND bidders.name = 'Bernie Madoff'; -ERROR: cannot plan modifications with local tables involving citus tables -- commands containing a CTE are supported WITH new_orders AS (INSERT INTO limit_orders_mx VALUES (411, 'FLO', 12, '2017-07-02 16:32:15', 'buy', 66)) DELETE FROM limit_orders_mx WHERE id < 0; @@ -225,7 +224,6 @@ UPDATE limit_orders_mx SET limit_price = 0.00 FROM bidders WHERE limit_orders_mx.id = 246 AND limit_orders_mx.bidder_id = bidders.id AND bidders.name = 'Bernie Madoff'; -ERROR: cannot plan modifications with local tables involving citus tables -- commands containing a CTE are supported WITH deleted_orders AS (INSERT INTO limit_orders_mx VALUES (399, 'PDR', 14, '2017-07-02 16:32:15', 'sell', 43)) UPDATE limit_orders_mx SET symbol = 'GM'; diff --git a/src/test/regress/expected/multi_shard_modify.out b/src/test/regress/expected/multi_shard_modify.out index 0b1fe4ce7..70a12381d 100644 --- a/src/test/regress/expected/multi_shard_modify.out +++ b/src/test/regress/expected/multi_shard_modify.out @@ -72,8 +72,11 @@ CREATE TABLE temp_nations(name text, key integer); SELECT master_modify_multiple_shards('DELETE FROM multi_shard_modify_test USING temp_nations WHERE multi_shard_modify_test.t_value = temp_nations.key AND temp_nations.name = ''foobar'' '); WARNING: master_modify_multiple_shards is deprecated and will be removed in a future release. HINT: Run the command directly -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins + master_modify_multiple_shards +--------------------------------------------------------------------- + 0 +(1 row) + -- commands with a USING clause are unsupported SELECT create_distributed_table('temp_nations', 'name', 'hash'); create_distributed_table diff --git a/src/test/regress/expected/multi_shard_update_delete.out b/src/test/regress/expected/multi_shard_update_delete.out index f5d845597..8fe0a5aec 100644 --- a/src/test/regress/expected/multi_shard_update_delete.out +++ b/src/test/regress/expected/multi_shard_update_delete.out @@ -730,19 +730,15 @@ SET value_2 = subquery.random FROM (SELECT user_id, random() WHERE users_test_table.user_id = subquery.user_id; -- Make following tests consistent UPDATE users_test_table SET value_2 = 0; --- Local tables are not supported +-- Joins with tables not supported UPDATE users_test_table SET value_2 = 5 FROM events_test_table_local WHERE users_test_table.user_id = events_test_table_local.user_id; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins UPDATE events_test_table_local SET value_2 = 5 FROM users_test_table WHERE events_test_table_local.user_id = users_test_table.user_id; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins -- Local tables in a subquery are supported through recursive planning UPDATE users_test_table SET value_2 = 5 diff --git a/src/test/regress/expected/multi_simple_queries.out b/src/test/regress/expected/multi_simple_queries.out index a5d95abd3..7cba49921 100644 --- a/src/test/regress/expected/multi_simple_queries.out +++ b/src/test/regress/expected/multi_simple_queries.out @@ -280,15 +280,20 @@ ORDER BY articles.id; -- subqueries are not supported in SELECT clause SELECT a.title AS name, (SELECT a2.id FROM articles_single_shard a2 WHERE a.id = a2.id LIMIT 1) AS special_price FROM articles a; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns --- joins are not supported between local and distributed tables +ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses +HINT: Consider using an equality filter on the distributed table's partition column. +-- joins are supported between local and distributed tables SELECT title, authors.name FROM authors, articles WHERE authors.id = articles.author_id; -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins --- inner joins are not supported (I think) + title | name +--------------------------------------------------------------------- +(0 rows) + +-- inner joins are supported SELECT * FROM (articles INNER JOIN authors ON articles.id = authors.id); -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins + id | author_id | title | word_count | name | id +--------------------------------------------------------------------- +(0 rows) + -- test use of EXECUTE statements within plpgsql DO $sharded_execute$ BEGIN diff --git a/src/test/regress/expected/multi_simple_queries_0.out b/src/test/regress/expected/multi_simple_queries_0.out index 1f64bba84..461d7db0a 100644 --- a/src/test/regress/expected/multi_simple_queries_0.out +++ b/src/test/regress/expected/multi_simple_queries_0.out @@ -226,12 +226,12 @@ SELECT a.title AS name, (SELECT a2.id FROM articles_single_shard a2 WHERE a.id = AS special_price FROM articles a; ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses HINT: Consider using an equality filter on the distributed table's partition column. --- joins are not supported between local and distributed tables +-- joins are supported between local and distributed tables SELECT title, authors.name FROM authors, articles WHERE authors.id = articles.author_id; -ERROR: relation authors is not distributed --- inner joins are not supported (I think) +ERROR: Complex subqueries and CTEs are not supported when task_executor_type is set to 'task-tracker' +-- inner joins are supported SELECT * FROM (articles INNER JOIN authors ON articles.id = authors.id); -ERROR: relation authors is not distributed +ERROR: Complex subqueries and CTEs are not supported when task_executor_type is set to 'task-tracker' -- test use of EXECUTE statements within plpgsql DO $sharded_execute$ BEGIN diff --git a/src/test/regress/expected/with_executors.out b/src/test/regress/expected/with_executors.out index 519ec9ddd..df1c80625 100644 --- a/src/test/regress/expected/with_executors.out +++ b/src/test/regress/expected/with_executors.out @@ -302,13 +302,16 @@ SELECT min(user_id) FROM cte JOIN local_table ON (user_id = id); 1 (1 row) --- not if there are no distributed tables +-- even if there are no distributed tables WITH cte AS ( SELECT user_id FROM users_table ) SELECT min(user_id) FROM cte JOIN local_table ON (user_id = id) JOIN events_table USING (user_id); -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins + min +--------------------------------------------------------------------- + 1 +(1 row) + -- unless the distributed table is part of a recursively planned subquery WITH cte AS ( SELECT user_id FROM users_table @@ -319,15 +322,18 @@ SELECT min(user_id) FROM cte JOIN local_table ON (user_id = id) JOIN (SELECT * F 1 (1 row) --- joins between local and reference tables not allowed --- since the coordinator is not in the metadata at this stage +-- joins between local and reference tables are allowed +-- even when the coordinator is not in the metadata at this stage WITH cte AS ( SELECT user_id FROM users_table ) SELECT count(*) FROM local_table JOIN ref_table USING (id) WHERE id IN (SELECT * FROM cte); -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins + count +--------------------------------------------------------------------- + 6 +(1 row) + -- CTEs should be able to terminate a router query WITH cte AS ( WITH cte_1 AS ( diff --git a/src/test/regress/expected/with_modifying.out b/src/test/regress/expected/with_modifying.out index 4704c31a3..e7e81a08a 100644 --- a/src/test/regress/expected/with_modifying.out +++ b/src/test/regress/expected/with_modifying.out @@ -668,19 +668,20 @@ SELECT * FROM raw_data ORDER BY val; --------------------------------------------------------------------- (0 rows) --- Test that local tables are barred +-- Test that local tables are can be updated +-- selecting from distributed tables UPDATE local_table lt SET val = mt.val FROM modify_table mt WHERE mt.id = lt.id; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins -- Including inside CTEs WITH cte AS ( UPDATE local_table lt SET val = mt.val FROM modify_table mt WHERE mt.id = lt.id RETURNING lt.id, lt.val ) SELECT * FROM cte JOIN modify_table mt ON mt.id = cte.id ORDER BY 1,2; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins + id | val | id | val +--------------------------------------------------------------------- +(0 rows) + -- Make sure checks for volatile functions apply to CTEs too WITH cte AS (UPDATE modify_table SET val = random() WHERE id = 3 RETURNING *) SELECT * FROM cte JOIN modify_table mt ON mt.id = 3 AND mt.id = cte.id ORDER BY 1,2; diff --git a/src/test/regress/sql/coordinator_shouldhaveshards.sql b/src/test/regress/sql/coordinator_shouldhaveshards.sql index 2c2e6231f..7c1157610 100644 --- a/src/test/regress/sql/coordinator_shouldhaveshards.sql +++ b/src/test/regress/sql/coordinator_shouldhaveshards.sql @@ -169,8 +169,8 @@ CREATE TABLE dist_table(a int); SELECT create_distributed_table('dist_table', 'a'); INSERT INTO dist_table VALUES(1); -SELECT * FROM local JOIN dist_table ON (a = x); -SELECT * FROM local JOIN dist_table ON (a = x) WHERE a = 1;; +SELECT * FROM local JOIN dist_table ON (a = x) ORDER BY 1,2,3; +SELECT * FROM local JOIN dist_table ON (a = x) WHERE a = 1 ORDER BY 1,2,3; -- intermediate results are allowed WITH cte_1 AS (SELECT * FROM dist_table ORDER BY 1 LIMIT 1) diff --git a/src/test/regress/sql/dml_recursive.sql b/src/test/regress/sql/dml_recursive.sql index 33c1b057e..cf456410b 100644 --- a/src/test/regress/sql/dml_recursive.sql +++ b/src/test/regress/sql/dml_recursive.sql @@ -281,8 +281,10 @@ SET dept = 5 FROM cte_1 WHERE distributed_table.tenant_id < cte_1.tenant_id; --- we don't support updating local table with a join with --- distributed tables +-- we support updating local table with a join with +-- distributed tables, though as the local table +-- is target here, distributed table is recursively +-- planned UPDATE local_table SET diff --git a/src/test/regress/sql/multi_modifications.sql b/src/test/regress/sql/multi_modifications.sql index 3076aeeeb..0b272ca01 100644 --- a/src/test/regress/sql/multi_modifications.sql +++ b/src/test/regress/sql/multi_modifications.sql @@ -327,7 +327,7 @@ UPDATE limit_orders SET id = 246 WHERE id = 246; UPDATE limit_orders SET id = 246 WHERE id = 246 AND symbol = 'GM'; UPDATE limit_orders SET id = limit_orders.id WHERE id = 246; --- UPDATEs with a FROM clause are unsupported +-- UPDATEs with a FROM clause are supported even with local tables UPDATE limit_orders SET limit_price = 0.00 FROM bidders WHERE limit_orders.id = 246 AND limit_orders.bidder_id = bidders.id AND diff --git a/src/test/regress/sql/multi_shard_update_delete.sql b/src/test/regress/sql/multi_shard_update_delete.sql index c0cbdd791..41a102829 100644 --- a/src/test/regress/sql/multi_shard_update_delete.sql +++ b/src/test/regress/sql/multi_shard_update_delete.sql @@ -609,7 +609,7 @@ WHERE users_test_table.user_id = subquery.user_id; -- Make following tests consistent UPDATE users_test_table SET value_2 = 0; --- Local tables are not supported +-- Joins with tables not supported UPDATE users_test_table SET value_2 = 5 FROM events_test_table_local diff --git a/src/test/regress/sql/multi_simple_queries.sql b/src/test/regress/sql/multi_simple_queries.sql index a95f93f68..f987518e1 100644 --- a/src/test/regress/sql/multi_simple_queries.sql +++ b/src/test/regress/sql/multi_simple_queries.sql @@ -146,10 +146,10 @@ ORDER BY articles.id; SELECT a.title AS name, (SELECT a2.id FROM articles_single_shard a2 WHERE a.id = a2.id LIMIT 1) AS special_price FROM articles a; --- joins are not supported between local and distributed tables +-- joins are supported between local and distributed tables SELECT title, authors.name FROM authors, articles WHERE authors.id = articles.author_id; --- inner joins are not supported (I think) +-- inner joins are supported SELECT * FROM (articles INNER JOIN authors ON articles.id = authors.id); -- test use of EXECUTE statements within plpgsql diff --git a/src/test/regress/sql/with_executors.sql b/src/test/regress/sql/with_executors.sql index 231df8e0c..dec5fcd9b 100644 --- a/src/test/regress/sql/with_executors.sql +++ b/src/test/regress/sql/with_executors.sql @@ -231,7 +231,7 @@ WITH cte AS ( ) SELECT min(user_id) FROM cte JOIN local_table ON (user_id = id); --- not if there are no distributed tables +-- even if there are no distributed tables WITH cte AS ( SELECT user_id FROM users_table ) @@ -243,8 +243,8 @@ WITH cte AS ( ) SELECT min(user_id) FROM cte JOIN local_table ON (user_id = id) JOIN (SELECT * FROM events_table OFFSET 0) e USING (user_id); --- joins between local and reference tables not allowed --- since the coordinator is not in the metadata at this stage +-- joins between local and reference tables are allowed +-- even when the coordinator is not in the metadata at this stage WITH cte AS ( SELECT user_id FROM users_table ) diff --git a/src/test/regress/sql/with_modifying.sql b/src/test/regress/sql/with_modifying.sql index 5d6999264..058ff8e41 100644 --- a/src/test/regress/sql/with_modifying.sql +++ b/src/test/regress/sql/with_modifying.sql @@ -412,7 +412,8 @@ raw_data AS ( ) SELECT * FROM raw_data ORDER BY val; --- Test that local tables are barred +-- Test that local tables are can be updated +-- selecting from distributed tables UPDATE local_table lt SET val = mt.val FROM modify_table mt WHERE mt.id = lt.id; From 594e001f3bbf9bca48f4d0bbed7c277def58ad18 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Fri, 17 Jul 2020 18:25:33 +0200 Subject: [PATCH 05/37] Add filter pushdown regression tests Also handle WHERE false --- .../planner/multi_router_planner.c | 3 +- .../distributed/planner/recursive_planning.c | 4 +- .../relation_restriction_equivalence.c | 8 + src/include/distributed/shard_pruning.h | 1 + ...relation_planning_restirction_pushdown.out | 428 ++++++++++++++++++ src/test/regress/multi_schedule | 2 +- ...relation_planning_restirction_pushdown.sql | 242 ++++++++++ 7 files changed, 684 insertions(+), 4 deletions(-) create mode 100644 src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out create mode 100644 src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 0062e4534..1a23fd090 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -171,7 +171,6 @@ static DeferredErrorMessage * ErrorIfQueryHasUnroutableModifyingCTE(Query *query static bool SelectsFromDistributedTable(List *rangeTableList, Query *query); static ShardPlacement * CreateDummyPlacement(bool hasLocalRelation); static ShardPlacement * CreateLocalDummyPlacement(); -static List * get_all_actual_clauses(List *restrictinfo_list); static int CompareInsertValuesByShardId(const void *leftElement, const void *rightElement); static List * SingleShardTaskList(Query *query, uint64 jobId, @@ -3699,7 +3698,7 @@ ErrorIfQueryHasUnroutableModifyingCTE(Query *queryTree) * This loses the distinction between regular and pseudoconstant clauses, * so be careful what you use it for. */ -static List * +List * get_all_actual_clauses(List *restrictinfo_list) { List *result = NIL; diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 898f00280..c9744e575 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -72,6 +72,7 @@ #include "distributed/recursive_planning.h" #include "distributed/relation_restriction_equivalence.h" #include "distributed/log_utils.h" +#include "distributed/shard_pruning.h" #include "distributed/version_compat.h" #include "lib/stringinfo.h" #include "optimizer/clauses.h" @@ -1525,7 +1526,8 @@ MostFilteredRte(PlannerRestrictionContext *plannerRestrictionContext, plannerRestrictionContext, 1); if (mostFilteredLocalRte == NULL || - list_length(*restrictionList) < list_length(currentRestrictionList)) + list_length(*restrictionList) < list_length(currentRestrictionList) || + ContainsFalseClause(currentRestrictionList)) { mostFilteredLocalRte = rangeTableEntry; *restrictionList = currentRestrictionList; diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index 782005abb..e138d9389 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -21,6 +21,7 @@ #include "distributed/pg_dist_partition.h" #include "distributed/query_utils.h" #include "distributed/relation_restriction_equivalence.h" +#include "distributed/shard_pruning.h" #include "nodes/nodeFuncs.h" #include "nodes/pg_list.h" #include "nodes/primnodes.h" @@ -1871,7 +1872,14 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, RelOptInfo *relOptInfo = relationRestriction->relOptInfo; List *baseRestrictInfo = relOptInfo->baserestrictinfo; + List *joinRestrictInfo = relOptInfo->joininfo; + List *joinRrestrictClauseList = get_all_actual_clauses(joinRestrictInfo); + if (ContainsFalseClause(joinRrestrictClauseList)) + { + /* found WHERE false, no need to continue */ + return copyObject((List *) joinRrestrictClauseList); + } List *restrictExprList = NIL; ListCell *restrictCell = NULL; diff --git a/src/include/distributed/shard_pruning.h b/src/include/distributed/shard_pruning.h index a780a7336..8f8ca69e7 100644 --- a/src/include/distributed/shard_pruning.h +++ b/src/include/distributed/shard_pruning.h @@ -20,6 +20,7 @@ extern List * PruneShards(Oid relationId, Index rangeTableId, List *whereClauseList, Const **partitionValueConst); extern bool ContainsFalseClause(List *whereClauseList); +extern List * get_all_actual_clauses(List *restrictinfo_list); extern Const * TransformPartitionRestrictionValue(Var *partitionColumn, Const *restrictionValue, bool missingOk); diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out new file mode 100644 index 000000000..d58fa9fb6 --- /dev/null +++ b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out @@ -0,0 +1,428 @@ +--------------------------------------------------------------------- +-- recursive_relation_planning_restirction_pushdown +-- In this test file, we mosly test whether Citus +-- can successfully pushdown filters to the subquery +-- that is being recursively planned. This is done +-- for all types of JOINs +--------------------------------------------------------------------- +-- all the queries in this file have the +-- same tables/subqueries combination as below +-- because this test aims to hold the query planning +-- steady, but mostly ensure that filters are handled +-- properly. Note that local is the relation that is +-- recursively planned throughout the file +CREATE SCHEMA push_down_filters; +SET search_path TO push_down_filters; +CREATE TABLE local_table (key int, value int, time timestamptz); +CREATE TABLE distributed_table (key int, value int, metadata jsonb); +SELECT create_distributed_table('distributed_table', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- Setting the debug level so that filters can be observed +SET client_min_messages TO DEBUG1; +-- for the purposes of these tests, we always want to recursively +-- plan local tables. +SET citus.local_table_join_policy TO "pull-local"; +-- there are no filters, hence cannot pushdown any filters +SELECT count(*) +FROM distributed_table u1 +JOIN distributed_table u2 USING(key) +JOIN local_table USING (key); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN push_down_filters.distributed_table u2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) local_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- scalar array expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING (key) +WHERE u2.key > ANY(ARRAY[2, 1, 6]); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (u2.key OPERATOR(pg_catalog.>) ANY (ARRAY[2, 1, 6])) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- array operators on the table can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(key) +WHERE ARRAY[u2.key, u2.value] @> (ARRAY[2, 3]); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (ARRAY[u2.key, u2.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- array operators on different tables cannot be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE ARRAY[u2.value, u1.value] @> (ARRAY[2, 3]); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ARRAY[u2.value, u1.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- coerced expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value/2.0 > 2)::int::bool::text::bool; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) (2)::numeric))::integer)::boolean)::text)::boolean + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- case expression on a single table can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (CASE WHEN u2.value > 3 THEN u2.value > 2 ELSE false END); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u2.value OPERATOR(pg_catalog.>) 3) THEN (u2.value OPERATOR(pg_catalog.>) 2) ELSE false END + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- case expression multiple tables cannot be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (CASE WHEN u1.value > 4000 THEN u2.value / 100 > 1 ELSE false END); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u1.value OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- coalesce expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE COALESCE((u2.key/5.0)::int::bool, false); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE COALESCE(((((u2.key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- nullif expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE NULLIF((u2.value/5.0)::int::bool, false); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE NULLIF(((((u2.value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- null test can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value IS NOT NULL; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value IS NOT NULL) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- functions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE isfinite(u2.time); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE isfinite(u2."time") + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- functions with multiple tables cannot be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE int4smaller(u2.value, u1.value) = 55; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.value, u1.value) OPERATOR(pg_catalog.=) 55) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- functions with multiple columns from the same tables can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE int4smaller(u2.key, u2.value) = u2.key; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.key, u2.value) OPERATOR(pg_catalog.=) u2.key) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- row expressions can be pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE row(u2.value, 2, 3) > row(u2.value, 2, 3); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(u2.value, 2, 3)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- multiple expression from the same table can be pushed down together +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) + WHERE + (u2.key/1.0)::int::bool::text::bool AND + CASE WHEN u2.key > 4000 THEN u2.value / 100 > 1 ELSE false END AND + COALESCE((u2.key/50000)::bool, false) AND + NULLIF((u2.value/50000)::int::bool, false) AND + isfinite(u2.time) AND + u2.value IS DISTINCT FROM 50040 AND + row(u2.value, 2, 3) > row(2000, 2, 3); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (u2.key OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((u2.key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((u2.value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite(u2."time") AND (u2.value IS DISTINCT FROM 50040) AND (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- subqueries filters are not pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > + (SELECT avg(key) + FROM distributed_table); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT avg(key) AS avg FROM push_down_filters.distributed_table +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value)::numeric OPERATOR(pg_catalog.>) (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- even subqueries with constant values are not pushdowned +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > (SELECT 5); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value OPERATOR(pg_catalog.>) (SELECT 5)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- filters involving multiple tables aren't pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value * u1.key > 25; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.*) u1.key) OPERATOR(pg_catalog.>) 25) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- filter on other tables can only be pushdown +-- as long as they are equality filters on the +-- joining column +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u1.value = 3; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.=) 3) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- but not when the filter is gt, lt or any other thing +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u1.value > 3; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.>) 3) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- when the filter is on another column than the +-- join column, that's obviously not pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u1.key = 3; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.key OPERATOR(pg_catalog.=) 3) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- or filters on the same table is pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > 4 OR u2.value = 4; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 4) OR (u2.value OPERATOR(pg_catalog.=) 4)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- and filters on the same table is pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > 2 and u2.time IS NULL; +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND (u2."time" IS NULL)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- filters on different tables are pushdown +-- only the ones that are not ANDed +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- filters on different tables are pushdown +-- only the ones that are not ANDed +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u2.value IS NULL) OR (u2.key > 4 OR u1.key > 3); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL) OR ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- filters on different tables are pushdown +-- only the ones that are not ANDed +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- but volatile functions are not pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u1.value IS NULL) AND (u2.key = 10000 * random() OR u1.key > 3); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u1.value IS NULL)) AND (((u2.key)::double precision OPERATOR(pg_catalog.=) ((10000)::double precision OPERATOR(pg_catalog.*) random())) OR (u1.key OPERATOR(pg_catalog.>) 3))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- constant results should be pushed down, but not supported yet +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 AND false); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- we can still pushdown WHERE false +-- even if it is a LATERAL join +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +JOIN LATERAL + (SELECT value, + random() + FROM distributed_table + WHERE u2.value = 15) AS u3 USING (value) +WHERE (u2.value > 2 + AND FALSE); +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) JOIN LATERAL (SELECT distributed_table.value, random() AS random FROM push_down_filters.distributed_table WHERE (u2.value OPERATOR(pg_catalog.=) 15)) u3 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +\set VERBOSITY terse +RESET client_min_messages; +DROP SCHEMA push_down_filters CASCADE; +NOTICE: drop cascades to 2 other objects diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 95434bf38..39329b2d7 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -110,7 +110,7 @@ test: multi_average_expression multi_working_columns multi_having_pushdown havin test: multi_array_agg multi_limit_clause multi_orderby_limit_pushdown test: multi_jsonb_agg multi_jsonb_object_agg multi_json_agg multi_json_object_agg bool_agg ch_bench_having chbenchmark_all_queries expression_reference_join anonymous_columns test: ch_bench_subquery_repartition -test: multi_agg_type_conversion multi_count_type_conversion +test: multi_agg_type_conversion multi_count_type_conversion recursive_relation_planning_restirction_pushdown test: multi_partition_pruning single_hash_repartition_join test: multi_join_pruning multi_hash_pruning intermediate_result_pruning test: multi_null_minmax_value_pruning cursors diff --git a/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql b/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql new file mode 100644 index 000000000..ecd148b91 --- /dev/null +++ b/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql @@ -0,0 +1,242 @@ +---------------------------------------------------- +-- recursive_relation_planning_restirction_pushdown +-- In this test file, we mosly test whether Citus +-- can successfully pushdown filters to the subquery +-- that is being recursively planned. This is done +-- for all types of JOINs +---------------------------------------------------- + +-- all the queries in this file have the +-- same tables/subqueries combination as below +-- because this test aims to hold the query planning +-- steady, but mostly ensure that filters are handled +-- properly. Note that local is the relation that is +-- recursively planned throughout the file + +CREATE SCHEMA push_down_filters; +SET search_path TO push_down_filters; + +CREATE TABLE local_table (key int, value int, time timestamptz); + +CREATE TABLE distributed_table (key int, value int, metadata jsonb); +SELECT create_distributed_table('distributed_table', 'key'); + +-- Setting the debug level so that filters can be observed +SET client_min_messages TO DEBUG1; + +-- for the purposes of these tests, we always want to recursively +-- plan local tables. +SET citus.local_table_join_policy TO "pull-local"; + + +-- there are no filters, hence cannot pushdown any filters +SELECT count(*) +FROM distributed_table u1 +JOIN distributed_table u2 USING(key) +JOIN local_table USING (key); + +-- scalar array expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING (key) +WHERE u2.key > ANY(ARRAY[2, 1, 6]); + +-- array operators on the table can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(key) +WHERE ARRAY[u2.key, u2.value] @> (ARRAY[2, 3]); + + +-- array operators on different tables cannot be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE ARRAY[u2.value, u1.value] @> (ARRAY[2, 3]); + +-- coerced expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value/2.0 > 2)::int::bool::text::bool; + + +-- case expression on a single table can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (CASE WHEN u2.value > 3 THEN u2.value > 2 ELSE false END); + +-- case expression multiple tables cannot be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (CASE WHEN u1.value > 4000 THEN u2.value / 100 > 1 ELSE false END); + +-- coalesce expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE COALESCE((u2.key/5.0)::int::bool, false); + +-- nullif expressions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE NULLIF((u2.value/5.0)::int::bool, false); + +-- null test can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value IS NOT NULL; + +-- functions can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE isfinite(u2.time); + +-- functions with multiple tables cannot be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE int4smaller(u2.value, u1.value) = 55; + +-- functions with multiple columns from the same tables can be pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE int4smaller(u2.key, u2.value) = u2.key; + +-- row expressions can be pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE row(u2.value, 2, 3) > row(u2.value, 2, 3); + + + +-- multiple expression from the same table can be pushed down together +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) + WHERE + (u2.key/1.0)::int::bool::text::bool AND + CASE WHEN u2.key > 4000 THEN u2.value / 100 > 1 ELSE false END AND + COALESCE((u2.key/50000)::bool, false) AND + NULLIF((u2.value/50000)::int::bool, false) AND + isfinite(u2.time) AND + u2.value IS DISTINCT FROM 50040 AND + row(u2.value, 2, 3) > row(2000, 2, 3); + + +-- subqueries filters are not pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > + (SELECT avg(key) + FROM distributed_table); + +-- even subqueries with constant values are not pushdowned +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > (SELECT 5); + +-- filters involving multiple tables aren't pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value * u1.key > 25; + + +-- filter on other tables can only be pushdown +-- as long as they are equality filters on the +-- joining column +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u1.value = 3; + + +-- but not when the filter is gt, lt or any other thing +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u1.value > 3; + + +-- when the filter is on another column than the +-- join column, that's obviously not pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u1.key = 3; + + +-- or filters on the same table is pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > 4 OR u2.value = 4; + +-- and filters on the same table is pushdown +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE u2.value > 2 and u2.time IS NULL; + + +-- filters on different tables are pushdown +-- only the ones that are not ANDed +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); + +-- filters on different tables are pushdown +-- only the ones that are not ANDed +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u2.value IS NULL) OR (u2.key > 4 OR u1.key > 3); + + +-- filters on different tables are pushdown +-- only the ones that are not ANDed +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); + +-- but volatile functions are not pushed down +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 OR u1.value IS NULL) AND (u2.key = 10000 * random() OR u1.key > 3); + +-- constant results should be pushed down, but not supported yet +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +WHERE (u2.value > 2 AND false); + +-- we can still pushdown WHERE false +-- even if it is a LATERAL join +SELECT count(*) +FROM distributed_table u1 +JOIN local_table u2 USING(value) +JOIN LATERAL + (SELECT value, + random() + FROM distributed_table + WHERE u2.value = 15) AS u3 USING (value) +WHERE (u2.value > 2 + AND FALSE); + +\set VERBOSITY terse +RESET client_min_messages; +DROP SCHEMA push_down_filters CASCADE; + From 945193555b533669c6ea7e8954b22c0a95988e8d Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Wed, 26 Aug 2020 10:06:32 +0200 Subject: [PATCH 06/37] add basic regression tests --- .../regress/expected/local_table_join.out | 257 ++++++++++++++++++ src/test/regress/multi_schedule | 2 +- src/test/regress/sql/local_table_join.sql | 138 ++++++++++ 3 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 src/test/regress/expected/local_table_join.out create mode 100644 src/test/regress/sql/local_table_join.sql diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out new file mode 100644 index 000000000..38f6f9cb2 --- /dev/null +++ b/src/test/regress/expected/local_table_join.out @@ -0,0 +1,257 @@ +CREATE SCHEMA local_table_join; +SET search_path TO local_table_join; +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) + +SET client_min_messages TO DEBUG1; +-- the user doesn't allow local / distributed table joinn +SET citus.local_table_join_policy TO 'never'; +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); +ERROR: relation postgres_table is not distributed +SELECT count(*) FROM postgres_table JOIN reference_table USING(key); +ERROR: relation postgres_table is not distributed +-- the user prefers local table recursively planned +SET citus.local_table_join_policy TO 'pull-local'; +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN reference_table USING(key); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- the user prefers distributed table recursively planned +SET citus.local_table_join_policy TO 'pull-distributed'; +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN reference_table USING(key); +DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- update/delete +-- auto tests +-- switch back to the default policy, which is auto +RESET citus.local_table_join_policy; +-- on the default mode, the local tables should be recursively planned +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM reference_table JOIN postgres_table USING(key); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- this is a contreversial part that we should discuss further +-- if the distributed table has at least one filter, we prefer +-- recursively planning of the distributed table +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- but if the filters can be pushed downn to the local table via the join +-- we are smart about recursively planning the local table +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) 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)) postgres_table USING (key)) WHERE (distributed_table.key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- if both local and distributed tables have a filter, we prefer local +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) AND (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) OR (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- multiple local/distributed tables +-- only local tables are recursively planned +SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- if one of the distributed tables have a filter, we'll prefer recursive planning of it as well +-- it actually leads to a poor plan as we need to recursively plan local tables anyway as it is +-- joined with another distributed table +SELECT + count(*) +FROM + distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) +WHERE + d1.value = '1'; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_3 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) d1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- if the filter is on the JOIN key, we can recursively plan the local +-- tables as filters are pushded down to the local tables +SELECT + count(*) +FROM + distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) +WHERE + d1.key = 1; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- we can support modification queries as well +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +-- modifications with multiple tables +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, postgres_table p2 +WHERE + distributed_table.key = p1.key AND p1.key = p2.key; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, distributed_table d2 +WHERE + distributed_table.key = p1.key AND p1.key = d2.key; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, local_table_join.distributed_table d2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) d2.key)) +-- pretty inefficient plan as it requires +-- recursive planninng of 2 distributed tables +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table d1, distributed_table d2 +WHERE + postgres_table.key = d1.key AND d1.key = d2.key; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) +\set VERBOSITY terse +RESET client_min_messages; +DROP SCHEMA local_table_join CASCADE; +NOTICE: drop cascades to 3 other objects diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 39329b2d7..4da3a305d 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -282,7 +282,7 @@ test: multi_colocated_shard_transfer # ---------- # multi_citus_tools tests utility functions written for citus tools # ---------- -test: multi_citus_tools +test: multi_citus_tools local_table_join # ---------- # node_conninfo_reload tests that node_conninfo changes take effect diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql new file mode 100644 index 000000000..0b0285af9 --- /dev/null +++ b/src/test/regress/sql/local_table_join.sql @@ -0,0 +1,138 @@ +CREATE SCHEMA local_table_join; +SET search_path TO local_table_join; + + +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'); + +SET client_min_messages TO DEBUG1; + + +-- the user doesn't allow local / distributed table joinn +SET citus.local_table_join_policy TO 'never'; +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); +SELECT count(*) FROM postgres_table JOIN reference_table USING(key); + +-- the user prefers local table recursively planned +SET citus.local_table_join_policy TO 'pull-local'; +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); +SELECT count(*) FROM postgres_table JOIN reference_table USING(key); + + +-- the user prefers distributed table recursively planned +SET citus.local_table_join_policy TO 'pull-distributed'; +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); +SELECT count(*) FROM postgres_table JOIN reference_table USING(key); + + +-- update/delete +-- auto tests + +-- switch back to the default policy, which is auto +RESET citus.local_table_join_policy; + +-- on the default mode, the local tables should be recursively planned +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); +SELECT count(*) FROM reference_table JOIN postgres_table USING(key); +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_table USING (key); + + + +-- this is a contreversial part that we should discuss further +-- if the distributed table has at least one filter, we prefer +-- recursively planning of the distributed table +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; + +-- but if the filters can be pushed downn to the local table via the join +-- we are smart about recursively planning the local table +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; + + +-- if both local and distributed tables have a filter, we prefer local +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; + + +-- multiple local/distributed tables +-- only local tables are recursively planned +SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key); + + +-- if one of the distributed tables have a filter, we'll prefer recursive planning of it as well +-- it actually leads to a poor plan as we need to recursively plan local tables anyway as it is +-- joined with another distributed table +SELECT + count(*) +FROM + distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) +WHERE + d1.value = '1'; + +-- if the filter is on the JOIN key, we can recursively plan the local +-- tables as filters are pushded down to the local tables +SELECT + count(*) +FROM + distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) +WHERE + d1.key = 1; + + +-- we can support modification queries as well +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; + + +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; + +-- modifications with multiple tables +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, postgres_table p2 +WHERE + distributed_table.key = p1.key AND p1.key = p2.key; + + +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, distributed_table d2 +WHERE + distributed_table.key = p1.key AND p1.key = d2.key; + +-- pretty inefficient plan as it requires +-- recursive planninng of 2 distributed tables +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table d1, distributed_table d2 +WHERE + postgres_table.key = d1.key AND d1.key = d2.key; + + +\set VERBOSITY terse +RESET client_min_messages; +DROP SCHEMA local_table_join CASCADE; From 3f4952cc2b5f931f2cf2aa603a72f9178de03073 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Thu, 27 Aug 2020 08:42:47 +0200 Subject: [PATCH 07/37] Pushdown projections when relations are recursively planned This is important to limit the data transfer size. --- .../planner/query_colocation_checker.c | 12 ++- .../distributed/planner/recursive_planning.c | 96 ++++++++++++++--- .../distributed/query_colocation_checker.h | 3 +- .../regress/expected/local_table_join.out | 100 +++++++++--------- 4 files changed, 146 insertions(+), 65 deletions(-) diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index f0c11cbc0..62905396d 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -76,7 +76,7 @@ CreateColocatedJoinChecker(Query *subquery, PlannerRestrictionContext *restricti * functions (i.e., FilterPlannerRestrictionForQuery()) rely on queries * not relations. */ - anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry); + anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry, NIL); } else if (anchorRangeTblEntry->rtekind == RTE_SUBQUERY) { @@ -260,7 +260,7 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker) * designed for generating a stub query. */ Query * -WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation) +WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes) { Query *subquery = makeNode(Query); RangeTblRef *newRangeTableRef = makeNode(RangeTblRef); @@ -291,6 +291,14 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation) makeTargetEntry((Expr *) targetColumn, attributeNumber, strdup(attributeTuple->attname.data), false); + if (!list_member_int(requiredAttributes, attributeNumber)) + { + targetEntry->expr = + (Expr *) makeNullConst(attributeTuple->atttypid, + attributeTuple->atttypmod, + attributeTuple->attcollation); + } + subquery->targetList = lappend(subquery->targetList, targetEntry); } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index c9744e575..d71e0dab8 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -76,6 +76,11 @@ #include "distributed/version_compat.h" #include "lib/stringinfo.h" #include "optimizer/clauses.h" +#if PG_VERSION_NUM >= PG_VERSION_12 +#include "optimizer/optimizer.h" +#else +#include "optimizer/var.h" +#endif #include "optimizer/planner.h" #include "optimizer/prep.h" #include "parser/parsetree.h" @@ -187,14 +192,16 @@ static bool ContainsReferencesToOuterQueryWalker(Node *node, VarLevelsUpWalkerContext *context); static bool NodeContainsSubqueryReferencingOuterQuery(Node *node); static void ConvertLocalTableJoinsToSubqueries(Query *query, - PlannerRestrictionContext * - plannerRestrictionContext); + RecursivePlanningContext *planningContext); +static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, + RecursivePlanningContext *planningContext); static RangeTblEntry * MostFilteredRte(PlannerRestrictionContext * plannerRestrictionContext, List *rangeTableList, List **restrictionList, bool localTable); static void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, - List *restrictionList); + List *restrictionList, + List *requiredAttrNumbers); static bool AllDataLocallyAccessible(List *rangeTableList); static void WrapFunctionsInSubqueries(Query *query); static void TransformFunctionRTE(RangeTblEntry *rangeTblEntry); @@ -312,7 +319,7 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", so we * recursively plan one side of the join so that the logical planner can plan. */ - ConvertLocalTableJoinsToSubqueries(query, context->plannerRestrictionContext); + ConvertLocalTableJoinsToSubqueries(query, context); /* descend into subqueries */ query_tree_walker(query, RecursivelyPlanSubqueryWalker, context, 0); @@ -1377,7 +1384,7 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) */ static void ConvertLocalTableJoinsToSubqueries(Query *query, - PlannerRestrictionContext *plannerRestrictionContext) + RecursivePlanningContext *context) { List *rangeTableList = query->rtable; @@ -1408,6 +1415,8 @@ ConvertLocalTableJoinsToSubqueries(Query *query, bool localTable = true; + PlannerRestrictionContext *plannerRestrictionContext = + context->plannerRestrictionContext; RangeTblEntry *mostFilteredLocalRte = MostFilteredRte(plannerRestrictionContext, rangeTableList, &localTableRestrictList, localTable); @@ -1415,6 +1424,12 @@ ConvertLocalTableJoinsToSubqueries(Query *query, MostFilteredRte(plannerRestrictionContext, rangeTableList, &distributedTableRestrictList, !localTable); + List *requiredAttrNumbersForLocalRte = + RequiredAttrNumbersForRelation(mostFilteredLocalRte, context); + List *requiredAttrNumbersForDistriutedRte = + RequiredAttrNumbersForRelation(mostFilteredDistributedRte, context); + + elog(DEBUG4, "Local relation with the most number of filters " "on it: \"%s\"", get_rel_name(mostFilteredLocalRte->relid)); elog(DEBUG4, "Distributed relation with the most number of filters " @@ -1423,12 +1438,14 @@ ConvertLocalTableJoinsToSubqueries(Query *query, if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PULL_LOCAL) { ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, - localTableRestrictList); + localTableRestrictList, + requiredAttrNumbersForLocalRte); } else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PULL_DISTRIBUTED) { ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, - distributedTableRestrictList); + distributedTableRestrictList, + requiredAttrNumbersForDistriutedRte); } else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_AUTO) { @@ -1447,7 +1464,8 @@ ConvertLocalTableJoinsToSubqueries(Query *query, * local relation, if exists. */ ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, - distributedTableRestrictList); + distributedTableRestrictList, + requiredAttrNumbersForDistriutedRte); } else if (localTableHasFilter || !distributedTableHasFilter) { @@ -1468,12 +1486,14 @@ ConvertLocalTableJoinsToSubqueries(Query *query, * tuples. Today, we do not have such an infrastructure. */ ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, - localTableRestrictList); + localTableRestrictList, + requiredAttrNumbersForLocalRte); } else { ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, - distributedTableRestrictList); + distributedTableRestrictList, + requiredAttrNumbersForDistriutedRte); } } else @@ -1484,6 +1504,56 @@ ConvertLocalTableJoinsToSubqueries(Query *query, } +/* + * RequiredAttrNumbersForRelation returns the required attribute numbers for + * the input RTE relation in order for the planning to succeed. + * + * The function could be optimized by not adding the columns that only appear + * WHERE clause as a filter (e.g., not a join clause). + */ +static List * +RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, + RecursivePlanningContext *planningContext) +{ + PlannerRestrictionContext *plannerRestrictionContext = + planningContext->plannerRestrictionContext; + + /* TODO: Get rid of this hack, find relation restriction information directly */ + PlannerRestrictionContext *filteredPlannerRestrictionContext = + FilterPlannerRestrictionForQuery(plannerRestrictionContext, + WrapRteRelationIntoSubquery(relationRte, NIL)); + + RelationRestrictionContext *relationRestrictionContext = + filteredPlannerRestrictionContext->relationRestrictionContext; + List *filteredRelationRestrictionList = + relationRestrictionContext->relationRestrictionList; + RelationRestriction *relationRestriction = + (RelationRestriction *) linitial(filteredRelationRestrictionList); + + PlannerInfo *plannerInfo = relationRestriction->plannerInfo; + Query *queryToProcess = plannerInfo->parse; + int rteIndex = relationRestriction->index; + + List *allVarsInQuery = pull_vars_of_level((Node *) queryToProcess, 0); + ListCell *varCell = NULL; + + List *requiredAttrNumbers = NIL; + + foreach(varCell, allVarsInQuery) + { + Var *var = (Var *) lfirst(varCell); + + if (var->varno == rteIndex) + { + requiredAttrNumbers = list_append_unique_int(requiredAttrNumbers, + var->varattno); + } + } + + return requiredAttrNumbers; +} + + /* * MostFilteredRte returns a range table entry which has the most filters * on it along with the restrictions (e.g., fills **restrictionList). @@ -1543,9 +1613,10 @@ MostFilteredRte(PlannerRestrictionContext *plannerRestrictionContext, * with a subquery. The function also pushes down the filters to the subquery. */ static void -ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList) +ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, + List *requiredAttrNumbers) { - Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry); + Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); Expr *andedBoundExpressions = make_ands_explicit(restrictionList); subquery->jointree->quals = (Node *) andedBoundExpressions; @@ -1556,6 +1627,7 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict rangeTableEntry->rtekind = RTE_SUBQUERY; rangeTableEntry->subquery = subquery; + /* * If the relation is inherited, it'll still be inherited as * we've copied it earlier. This is to prevent the newly created diff --git a/src/include/distributed/query_colocation_checker.h b/src/include/distributed/query_colocation_checker.h index 2a27fa9f1..fc63522b2 100644 --- a/src/include/distributed/query_colocation_checker.h +++ b/src/include/distributed/query_colocation_checker.h @@ -34,7 +34,8 @@ extern ColocatedJoinChecker CreateColocatedJoinChecker(Query *subquery, PlannerRestrictionContext * restrictionContext); extern bool SubqueryColocated(Query *subquery, ColocatedJoinChecker *context); -extern Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation); +extern Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, + List *requiredAttributes); #endif /* QUERY_COLOCATION_CHECKER_H */ diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 38f6f9cb2..489d4be0f 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -25,8 +25,8 @@ ERROR: relation postgres_table is not distributed -- the user prefers local table recursively planned SET citus.local_table_join_policy TO 'pull-local'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) count --------------------------------------------------------------------- @@ -34,8 +34,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- @@ -45,8 +45,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- the user prefers distributed table recursively planned SET citus.local_table_join_policy TO 'pull-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table USING (key)) count --------------------------------------------------------------------- @@ -54,8 +54,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table 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.reference_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) reference_table USING (key)) count --------------------------------------------------------------------- @@ -68,8 +68,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c RESET citus.local_table_join_policy; -- on the default mode, the local tables should be recursively planned SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) count --------------------------------------------------------------------- @@ -77,8 +77,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM reference_table JOIN postgres_table USING(key); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) count --------------------------------------------------------------------- @@ -86,8 +86,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- @@ -98,8 +98,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- if the distributed table has at least one filter, we prefer -- recursively planning of the distributed table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) count --------------------------------------------------------------------- @@ -109,8 +109,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- but if the filters can be pushed downn to the local table via the join -- we are smart about recursively planning the local table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +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 (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) 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)) postgres_table USING (key)) WHERE (distributed_table.key OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- @@ -119,8 +119,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- if both local and distributed tables have a filter, we prefer local SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) AND (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count --------------------------------------------------------------------- @@ -128,8 +128,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) OR (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count --------------------------------------------------------------------- @@ -139,10 +139,10 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- multiple local/distributed tables -- only local tables are recursively planned SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +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 p1 WHERE true OFFSET 0 +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 p2 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.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) count --------------------------------------------------------------------- @@ -158,12 +158,12 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.value = '1'; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_3 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 +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 p1 WHERE true OFFSET 0 +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 p2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_3 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) d1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) count --------------------------------------------------------------------- @@ -178,10 +178,10 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.key = 1; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +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 p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +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 p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- @@ -197,8 +197,8 @@ FROM distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE distributed_table @@ -208,8 +208,8 @@ FROM postgres_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) -- modifications with multiple tables UPDATE @@ -220,10 +220,10 @@ FROM postgres_table p1, postgres_table p2 WHERE distributed_table.key = p1.key AND p1.key = p2.key; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +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 p1 WHERE true OFFSET 0 +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 p2 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.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) UPDATE distributed_table @@ -233,8 +233,8 @@ FROM postgres_table p1, distributed_table d2 WHERE distributed_table.key = p1.key AND p1.key = d2.key; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +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 p1 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.postgres_table p1 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, local_table_join.distributed_table d2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) d2.key)) -- pretty inefficient plan as it requires -- recursive planninng of 2 distributed tables @@ -246,10 +246,10 @@ FROM distributed_table d1, distributed_table d2 WHERE postgres_table.key = d1.key AND d1.key = d2.key; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 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.distributed_table d1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) \set VERBOSITY terse RESET client_min_messages; From f0aef67ed215f82684d842a58d55cc7b9a1ae7ae Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Fri, 28 Aug 2020 17:28:14 +0200 Subject: [PATCH 08/37] Update existing regression tests --- src/test/regress/expected/dml_recursive.out | 4 +- ...relation_planning_restirction_pushdown.out | 112 +++++++++--------- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/test/regress/expected/dml_recursive.out b/src/test/regress/expected/dml_recursive.out index f14baaeb5..4c6243b88 100644 --- a/src/test/regress/expected/dml_recursive.out +++ b/src/test/regress/expected/dml_recursive.out @@ -352,8 +352,8 @@ FROM distributed_table WHERE distributed_table.tenant_id = local_table.id; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT tenant_id, dept, info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id, dept, info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE recursive_dml_queries.local_table SET id = 'citus_test'::text FROM (SELECT intermediate_result.tenant_id, intermediate_result.dept, intermediate_result.info FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(tenant_id text, dept integer, info jsonb)) distributed_table WHERE (distributed_table.tenant_id OPERATOR(pg_catalog.=) local_table.id) RESET client_min_messages; DROP SCHEMA recursive_dml_queries CASCADE; diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out index d58fa9fb6..2df77f1af 100644 --- a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out +++ b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out @@ -31,8 +31,8 @@ SELECT count(*) FROM distributed_table u1 JOIN distributed_table u2 USING(key) JOIN local_table USING (key); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN push_down_filters.distributed_table u2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) local_table USING (key)) count --------------------------------------------------------------------- @@ -44,8 +44,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING (key) WHERE u2.key > ANY(ARRAY[2, 1, 6]); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (u2.key OPERATOR(pg_catalog.>) ANY (ARRAY[2, 1, 6])) count --------------------------------------------------------------------- @@ -57,8 +57,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(key) WHERE ARRAY[u2.key, u2.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (ARRAY[u2.key, u2.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count --------------------------------------------------------------------- @@ -70,8 +70,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE ARRAY[u2.value, u1.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ARRAY[u2.value, u1.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count --------------------------------------------------------------------- @@ -83,8 +83,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value/2.0 > 2)::int::bool::text::bool; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) (2)::numeric))::integer)::boolean)::text)::boolean count --------------------------------------------------------------------- @@ -96,8 +96,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u2.value > 3 THEN u2.value > 2 ELSE false END); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u2.value OPERATOR(pg_catalog.>) 3) THEN (u2.value OPERATOR(pg_catalog.>) 2) ELSE false END count --------------------------------------------------------------------- @@ -109,8 +109,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u1.value > 4000 THEN u2.value / 100 > 1 ELSE false END); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u1.value OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END count --------------------------------------------------------------------- @@ -122,8 +122,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE COALESCE((u2.key/5.0)::int::bool, false); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE COALESCE(((((u2.key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count --------------------------------------------------------------------- @@ -135,8 +135,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE NULLIF((u2.value/5.0)::int::bool, false); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE NULLIF(((((u2.value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count --------------------------------------------------------------------- @@ -148,8 +148,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value IS NOT NULL; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value IS NOT NULL) count --------------------------------------------------------------------- @@ -161,8 +161,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE isfinite(u2.time); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE isfinite(u2."time") count --------------------------------------------------------------------- @@ -174,8 +174,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.value, u1.value) = 55; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.value, u1.value) OPERATOR(pg_catalog.=) 55) count --------------------------------------------------------------------- @@ -187,8 +187,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.key, u2.value) = u2.key; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.key, u2.value) OPERATOR(pg_catalog.=) u2.key) count --------------------------------------------------------------------- @@ -200,8 +200,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE row(u2.value, 2, 3) > row(u2.value, 2, 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(u2.value, 2, 3)) count --------------------------------------------------------------------- @@ -235,9 +235,9 @@ JOIN local_table u2 USING(value) WHERE u2.value > (SELECT avg(key) FROM distributed_table); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT avg(key) AS avg FROM push_down_filters.distributed_table -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value)::numeric OPERATOR(pg_catalog.>) (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric))) count --------------------------------------------------------------------- @@ -249,8 +249,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > (SELECT 5); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value OPERATOR(pg_catalog.>) (SELECT 5)) count --------------------------------------------------------------------- @@ -262,8 +262,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value * u1.key > 25; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.*) u1.key) OPERATOR(pg_catalog.>) 25) count --------------------------------------------------------------------- @@ -277,8 +277,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value = 3; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.=) 3) count --------------------------------------------------------------------- @@ -290,8 +290,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value > 3; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.>) 3) count --------------------------------------------------------------------- @@ -304,8 +304,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.key = 3; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.key OPERATOR(pg_catalog.=) 3) count --------------------------------------------------------------------- @@ -317,8 +317,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 4 OR u2.value = 4; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 4) OR (u2.value OPERATOR(pg_catalog.=) 4)) count --------------------------------------------------------------------- @@ -330,8 +330,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 2 and u2.time IS NULL; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND (u2."time" IS NULL)) count --------------------------------------------------------------------- @@ -344,8 +344,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -358,8 +358,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) OR (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL) OR ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -372,8 +372,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -385,8 +385,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u1.value IS NULL) AND (u2.key = 10000 * random() OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u1.value IS NULL)) AND (((u2.key)::double precision OPERATOR(pg_catalog.=) ((10000)::double precision OPERATOR(pg_catalog.*) random())) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -398,8 +398,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 AND false); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) count --------------------------------------------------------------------- @@ -418,8 +418,8 @@ JOIN LATERAL WHERE u2.value = 15) AS u3 USING (value) WHERE (u2.value > 2 AND FALSE); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) JOIN LATERAL (SELECT distributed_table.value, random() AS random FROM push_down_filters.distributed_table WHERE (u2.value OPERATOR(pg_catalog.=) 15)) u3 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns \set VERBOSITY terse From f3d55448b3191a47d8dd1befe4c7c96ff54ab4a7 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 18 Nov 2020 17:38:42 +0300 Subject: [PATCH 09/37] Choose distributed table if it has a unique index in filter When doing local-distributed table joins we convert one of them to subquery. The current policy is that we convert distributed tables to subquery if it has a unique index on a column that has unique index(primary key also has a unique index). --- src/backend/distributed/commands/index.c | 35 ++ .../distributed/operations/node_protocol.c | 1 - .../planner/local_distributed_join_planner.c | 361 ++++++++++++++++++ .../planner/multi_router_planner.c | 18 +- .../distributed/planner/recursive_planning.c | 329 +--------------- src/backend/distributed/shared_library_init.c | 4 +- src/include/distributed/commands.h | 1 + .../local_distributed_join_planner.h | 24 ++ src/include/distributed/metadata_utility.h | 3 - src/include/distributed/recursive_planning.h | 21 +- .../regress/expected/local_table_join.out | 250 ++++++++++-- ...relation_planning_restirction_pushdown.out | 2 +- src/test/regress/sql/local_table_join.sql | 142 ++++++- ...relation_planning_restirction_pushdown.sql | 2 +- 14 files changed, 809 insertions(+), 384 deletions(-) create mode 100644 src/backend/distributed/planner/local_distributed_join_planner.c create mode 100644 src/include/distributed/local_distributed_join_planner.h diff --git a/src/backend/distributed/commands/index.c b/src/backend/distributed/commands/index.c index a44cde0cc..7a9c5c9ad 100644 --- a/src/backend/distributed/commands/index.c +++ b/src/backend/distributed/commands/index.c @@ -249,6 +249,41 @@ CreateIndexStmtGetSchemaId(IndexStmt *createIndexStatement) return namespaceId; } +List* ExecuteFunctionOnEachTableIndex(Oid relationId, IndexProcesor indexProcessor) { + List *result = NIL; + ScanKeyData scanKey[1]; + int scanKeyCount = 1; + + PushOverrideEmptySearchPath(CurrentMemoryContext); + + /* open system catalog and scan all indexes that belong to this table */ + Relation pgIndex = table_open(IndexRelationId, AccessShareLock); + + ScanKeyInit(&scanKey[0], Anum_pg_index_indrelid, + BTEqualStrategyNumber, F_OIDEQ, relationId); + + SysScanDesc scanDescriptor = systable_beginscan(pgIndex, + IndexIndrelidIndexId, true, /* indexOK */ + NULL, scanKeyCount, scanKey); + + HeapTuple heapTuple = systable_getnext(scanDescriptor); + while (HeapTupleIsValid(heapTuple)) + { + Form_pg_index indexForm = (Form_pg_index) GETSTRUCT(heapTuple); + indexProcessor(indexForm, &result); + + heapTuple = systable_getnext(scanDescriptor); + } + + /* clean up scan and close system catalog */ + systable_endscan(scanDescriptor); + table_close(pgIndex, AccessShareLock); + + /* revert back to original search_path */ + PopOverrideSearchPath(); + + return result; +} /* * ExecuteFunctionOnEachTableIndex executes the given pgIndexProcessor function on each diff --git a/src/backend/distributed/operations/node_protocol.c b/src/backend/distributed/operations/node_protocol.c index 4a23a5052..0eb23f6a5 100644 --- a/src/backend/distributed/operations/node_protocol.c +++ b/src/backend/distributed/operations/node_protocol.c @@ -729,7 +729,6 @@ GatherIndexAndConstraintDefinitionList(Form_pg_index indexForm, List **indexDDLE } } - /* * IndexImpliedByAConstraint is a helper function to be used while scanning * pg_index. It returns true if the index identified by the given indexForm is diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c new file mode 100644 index 000000000..4a31aa543 --- /dev/null +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -0,0 +1,361 @@ +#include "postgres.h" + +#include "distributed/pg_version_constants.h" + +#include "funcapi.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_class.h" +#include "catalog/pg_index.h" +#include "distributed/citus_nodes.h" +#include "distributed/citus_ruleutils.h" +#include "distributed/commands.h" +#include "distributed/commands/multi_copy.h" +#include "distributed/distributed_planner.h" +#include "distributed/errormessage.h" +#include "distributed/local_distributed_join_planner.h" +#include "distributed/listutils.h" +#include "distributed/log_utils.h" +#include "distributed/metadata_cache.h" +#include "distributed/multi_logical_planner.h" +#include "distributed/multi_logical_optimizer.h" +#include "distributed/multi_router_planner.h" +#include "distributed/multi_physical_planner.h" +#include "distributed/multi_server_executor.h" +#include "distributed/query_colocation_checker.h" +#include "distributed/query_pushdown_planning.h" +#include "distributed/recursive_planning.h" +#include "distributed/relation_restriction_equivalence.h" +#include "distributed/log_utils.h" +#include "distributed/shard_pruning.h" +#include "distributed/version_compat.h" +#include "lib/stringinfo.h" +#include "optimizer/clauses.h" +#if PG_VERSION_NUM >= PG_VERSION_12 +#include "optimizer/optimizer.h" +#else +#include "optimizer/var.h" +#endif +#include "optimizer/planner.h" +#include "optimizer/prep.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 "nodes/primnodes.h" +#if PG_VERSION_NUM >= PG_VERSION_12 +#include "nodes/pathnodes.h" +#else +#include "nodes/relation.h" +#endif +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" + +static bool ShouldConvertLocalTableJoinsToSubqueries(List* rangeTableList); +static bool HasUniqueFilter(RangeTblEntry* distRTE, List* distRTERestrictionList, List* requiredAttrNumbersForDistRTE); +static void AutoConvertLocalTableJoinToSubquery(RangeTblEntry* localRTE, RangeTblEntry* distRTE, + List* localRTERestrictionList, List* distRTERestrictionList, + List *requiredAttrNumbersForLocalRTE, List *requiredAttrNumbersForDistRTE); +static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, + RecursivePlanningContext *planningContext); +static RangeTblEntry * FindNextRTECandidate(PlannerRestrictionContext * + plannerRestrictionContext, + List *rangeTableList, List **restrictionList, + bool localTable); +static bool AllDataLocallyAccessible(List *rangeTableList); +static void GetAllUniqueIndexes(Form_pg_index indexForm, List** uniqueIndexes); + +/* + * ConvertLocalTableJoinsToSubqueries gets a query and the planner + * restrictions. As long as there is a join between a local table + * and distributed table, the function wraps one table in a + * subquery (by also pushing the filters on the table down + * to the subquery). + * + * Once this function returns, there are no direct joins between + * local and distributed tables. + */ +void +ConvertLocalTableJoinsToSubqueries(Query *query, + RecursivePlanningContext *context) +{ + List *rangeTableList = query->rtable; + if(!ShouldConvertLocalTableJoinsToSubqueries(rangeTableList)) { + return; + } + + RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); + + while (ContainsLocalTableDistributedTableJoin(rangeTableList)) + { + List *localTableRestrictList = NIL; + List *distributedTableRestrictList = NIL; + + bool localTable = true; + + PlannerRestrictionContext *plannerRestrictionContext = + context->plannerRestrictionContext; + RangeTblEntry *localRTECandidate = + FindNextRTECandidate(plannerRestrictionContext, rangeTableList, + &localTableRestrictList, localTable); + RangeTblEntry *distributedRTECandidate = + FindNextRTECandidate(plannerRestrictionContext, rangeTableList, + &distributedTableRestrictList, !localTable); + + List *requiredAttrNumbersForLocalRte = + RequiredAttrNumbersForRelation(localRTECandidate, context); + List *requiredAttrNumbersForDistributedRte = + RequiredAttrNumbersForRelation(distributedRTECandidate, context); + + if (resultRelation) { + + if (resultRelation->relid == localRTECandidate->relid) { + ReplaceRTERelationWithRteSubquery(distributedRTECandidate, + distributedTableRestrictList, + requiredAttrNumbersForDistributedRte); + continue; + }else if (resultRelation->relid == distributedRTECandidate->relid) { + ReplaceRTERelationWithRteSubquery(localRTECandidate, + localTableRestrictList, + requiredAttrNumbersForLocalRte); + continue; + } + } + + if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) + { + ReplaceRTERelationWithRteSubquery(localRTECandidate, + localTableRestrictList, + requiredAttrNumbersForLocalRte); + } + else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) + { + ReplaceRTERelationWithRteSubquery(distributedRTECandidate, + distributedTableRestrictList, + requiredAttrNumbersForDistributedRte); + } + else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_AUTO) + { + AutoConvertLocalTableJoinToSubquery(localRTECandidate, distributedRTECandidate, + localTableRestrictList, distributedTableRestrictList, + requiredAttrNumbersForLocalRte, requiredAttrNumbersForDistributedRte); + } + else + { + elog(ERROR, "unexpected local table join policy: %d", LocalTableJoinPolicy); + } + } +} + +/* + * ShouldConvertLocalTableJoinsToSubqueries returns true if we should + * convert local-dist table joins to subqueries. + */ +static 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)) + { + /* nothing to do as there are no relevant joins */ + return false; + } + + if (AllDataLocallyAccessible(rangeTableList)) + { + /* recursively planning is overkill, router planner can already handle this */ + return false; + } + return true; +} + +static void AutoConvertLocalTableJoinToSubquery(RangeTblEntry* localRTE, RangeTblEntry* distRTE, + List* localRTERestrictionList, List* distRTERestrictionList, + List *requiredAttrNumbersForLocalRTE, List *requiredAttrNumbersForDistRTE) { + + bool hasUniqueFilter = HasUniqueFilter(distRTE, distRTERestrictionList, requiredAttrNumbersForDistRTE); + if (hasUniqueFilter) { + ReplaceRTERelationWithRteSubquery(distRTE, + distRTERestrictionList, + requiredAttrNumbersForDistRTE); + }else { + ReplaceRTERelationWithRteSubquery(localRTE, + localRTERestrictionList, + requiredAttrNumbersForLocalRTE); + } + +} + +// TODO:: This function should only consider equality, +// currently it will return true for dist.a > 5. We should check this from join->quals. +static bool HasUniqueFilter(RangeTblEntry* distRTE, List* distRTERestrictionList, List* requiredAttrNumbersForDistRTE) { + List* uniqueIndexes = ExecuteFunctionOnEachTableIndex(distRTE->relid, GetAllUniqueIndexes); + int columnNumber = 0; + foreach_int(columnNumber, uniqueIndexes) { + if (list_member_int(requiredAttrNumbersForDistRTE, columnNumber)) { + return true; + } + } + return false; +} + +static void GetAllUniqueIndexes(Form_pg_index indexForm, List** uniqueIndexes) { + if (indexForm->indisunique || indexForm->indisprimary) { + for(int i = 0; i < indexForm->indkey.dim1; i++) { + *uniqueIndexes = list_append_unique_int(*uniqueIndexes, indexForm->indkey.values[i]); + } + } +} + + +/* + * RequiredAttrNumbersForRelation returns the required attribute numbers for + * the input RTE relation in order for the planning to succeed. + * + * The function could be optimized by not adding the columns that only appear + * WHERE clause as a filter (e.g., not a join clause). + */ +static List * +RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, + RecursivePlanningContext *planningContext) +{ + PlannerRestrictionContext *plannerRestrictionContext = + planningContext->plannerRestrictionContext; + + /* TODO: Get rid of this hack, find relation restriction information directly */ + PlannerRestrictionContext *filteredPlannerRestrictionContext = + FilterPlannerRestrictionForQuery(plannerRestrictionContext, + WrapRteRelationIntoSubquery(relationRte, NIL)); + + RelationRestrictionContext *relationRestrictionContext = + filteredPlannerRestrictionContext->relationRestrictionContext; + List *filteredRelationRestrictionList = + relationRestrictionContext->relationRestrictionList; + RelationRestriction *relationRestriction = + (RelationRestriction *) linitial(filteredRelationRestrictionList); + + PlannerInfo *plannerInfo = relationRestriction->plannerInfo; + Query *queryToProcess = plannerInfo->parse; + int rteIndex = relationRestriction->index; + + List *allVarsInQuery = pull_vars_of_level((Node *) queryToProcess, 0); + ListCell *varCell = NULL; + + List *requiredAttrNumbers = NIL; + + foreach(varCell, allVarsInQuery) + { + Var *var = (Var *) lfirst(varCell); + + if (var->varno == rteIndex) + { + requiredAttrNumbers = list_append_unique_int(requiredAttrNumbers, + var->varattno); + } + } + + return requiredAttrNumbers; +} + + +/* + * FindNextRTECandidate returns a range table entry which has the most filters + * on it along with the restrictions (e.g., fills **restrictionList). + * + * The function also gets a boolean localTable parameter, so the caller + * can choose to run the function for only local tables or distributed tables. + */ +static RangeTblEntry * +FindNextRTECandidate(PlannerRestrictionContext *plannerRestrictionContext, + List *rangeTableList, List **restrictionList, + bool localTable) +{ + ListCell *rangeTableCell = NULL; + + foreach(rangeTableCell, rangeTableList) + { + RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); + + /* we're only interested in tables */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) + { + continue; + } + + if (localTable && IsCitusTable(rangeTableEntry->relid)) + { + continue; + } + + if (!localTable && !IsCitusTable(rangeTableEntry->relid)) + { + continue; + } + + List *currentRestrictionList = + GetRestrictInfoListForRelation(rangeTableEntry, + plannerRestrictionContext, 1); + + *restrictionList = currentRestrictionList; + return rangeTableEntry; + } + // TODO:: Put Illegal state error code + ereport(ERROR, (errmsg("unexpected state: could not find any RTE to convert to subquery in range table list"))); + return NULL; +} + +/* + * AllDataLocallyAccessible return true if all data for the relations in the + * rangeTableList is locally accessible. + */ +static bool +AllDataLocallyAccessible(List *rangeTableList) +{ + ListCell *rangeTableCell = NULL; + foreach(rangeTableCell, rangeTableList) + { + RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); + + /* we're only interested in tables */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) + { + continue; + } + + + Oid relationId = rangeTableEntry->relid; + + if (!IsCitusTable(relationId)) + { + /* local tables are locally accessible */ + continue; + } + + List *shardIntervalList = LoadShardIntervalList(relationId); + if (list_length(shardIntervalList) > 1) + { + /* we currently only consider single placement tables */ + return false; + } + + ShardInterval *shardInterval = linitial(shardIntervalList); + uint64 shardId = shardInterval->shardId; + ShardPlacement *localShardPlacement = + ShardPlacementOnGroup(shardId, GetLocalGroupId()); + if (localShardPlacement == NULL) + { + /* the table doesn't have a placement on this node */ + return false; + } + } + + return true; +} \ No newline at end of file diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 1a23fd090..24414fa90 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -534,12 +534,7 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, { return deferredError; } - - deferredError = DeferErrorIfUnsupportedModifyQueryWithLocalTable(queryTree); - if (deferredError != NULL) - { - return deferredError; - } + Var *partitionColumn = NULL; if (IsCitusTable(distributedTableId)) @@ -638,11 +633,14 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, } } - Oid distributedTableId = ModifyQueryResultRelationId(queryTree); - uint32 rangeTableId = 1; - Var *partitionColumn = PartitionColumn(distributedTableId, rangeTableId); + distributedTableId = ModifyQueryResultRelationId(queryTree); + rangeTableId = 1; - CmdType commandType = queryTree->commandType; + if (IsCitusTable(distributedTableId)) + { + partitionColumn = PartitionColumn(distributedTableId, rangeTableId); + } + commandType = queryTree->commandType; if (commandType == CMD_INSERT || commandType == CMD_UPDATE || commandType == CMD_DELETE) { diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index d71e0dab8..96cd55845 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -59,6 +59,7 @@ #include "distributed/commands/multi_copy.h" #include "distributed/distributed_planner.h" #include "distributed/errormessage.h" +#include "distributed/local_distributed_join_planner.h" #include "distributed/listutils.h" #include "distributed/log_utils.h" #include "distributed/metadata_cache.h" @@ -109,21 +110,6 @@ int LocalTableJoinPolicy = LOCAL_JOIN_POLICY_AUTO; /* track depth of current recursive planner query */ static int recursivePlanningDepth = 0; -/* - * RecursivePlanningContext is used to recursively plan subqueries - * and CTEs, pull results to the coordinator, and push it back into - * the workers. - */ -typedef struct RecursivePlanningContext -{ - int level; - uint64 planId; - bool allDistributionKeysInQueryAreEqual; /* used for some optimizations */ - List *subPlanList; - PlannerRestrictionContext *plannerRestrictionContext; -} RecursivePlanningContext; - - /* * CteReferenceWalkerContext is used to collect CTE references in * CteReferenceListWalker. @@ -191,18 +177,6 @@ static bool ContainsReferencesToOuterQuery(Query *query); static bool ContainsReferencesToOuterQueryWalker(Node *node, VarLevelsUpWalkerContext *context); static bool NodeContainsSubqueryReferencingOuterQuery(Node *node); -static void ConvertLocalTableJoinsToSubqueries(Query *query, - RecursivePlanningContext *planningContext); -static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, - RecursivePlanningContext *planningContext); -static RangeTblEntry * MostFilteredRte(PlannerRestrictionContext * - plannerRestrictionContext, - List *rangeTableList, List **restrictionList, - bool localTable); -static void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, - List *restrictionList, - List *requiredAttrNumbers); -static bool AllDataLocallyAccessible(List *rangeTableList); static void WrapFunctionsInSubqueries(Query *query); static void TransformFunctionRTE(RangeTblEntry *rangeTblEntry); static bool ShouldTransformRTE(RangeTblEntry *rangeTableEntry); @@ -210,7 +184,6 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); - /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. * The function returns the subplans if necessary. For the details of when/how subplans are @@ -1371,248 +1344,11 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) return false; } - -/* - * ConvertLocalTableJoinsToSubqueries gets a query and the planner - * restrictions. As long as there is a join between a local table - * and distributed table, the function wraps one table in a - * subquery (by also pushing the filters on the table down - * to the subquery). - * - * Once this function returns, there are no direct joins between - * local and distributed tables. - */ -static void -ConvertLocalTableJoinsToSubqueries(Query *query, - RecursivePlanningContext *context) -{ - List *rangeTableList = query->rtable; - - if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) - { - /* user doesn't want Citus to enable local table joins */ - return; - } - - if (!ContainsLocalTableDistributedTableJoin(rangeTableList)) - { - /* nothing to do as there are no relevant joins */ - return; - } - - if (AllDataLocallyAccessible(rangeTableList)) - { - /* recursively planning is overkill, router planner can already handle this */ - return; - } - - RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); - - while (ContainsLocalTableDistributedTableJoin(rangeTableList)) - { - List *localTableRestrictList = NIL; - List *distributedTableRestrictList = NIL; - - bool localTable = true; - - PlannerRestrictionContext *plannerRestrictionContext = - context->plannerRestrictionContext; - RangeTblEntry *mostFilteredLocalRte = - MostFilteredRte(plannerRestrictionContext, rangeTableList, - &localTableRestrictList, localTable); - RangeTblEntry *mostFilteredDistributedRte = - MostFilteredRte(plannerRestrictionContext, rangeTableList, - &distributedTableRestrictList, !localTable); - - List *requiredAttrNumbersForLocalRte = - RequiredAttrNumbersForRelation(mostFilteredLocalRte, context); - List *requiredAttrNumbersForDistriutedRte = - RequiredAttrNumbersForRelation(mostFilteredDistributedRte, context); - - - elog(DEBUG4, "Local relation with the most number of filters " - "on it: \"%s\"", get_rel_name(mostFilteredLocalRte->relid)); - elog(DEBUG4, "Distributed relation with the most number of filters " - "on it: \"%s\"", get_rel_name(mostFilteredDistributedRte->relid)); - - if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PULL_LOCAL) - { - ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, - localTableRestrictList, - requiredAttrNumbersForLocalRte); - } - else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PULL_DISTRIBUTED) - { - ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, - distributedTableRestrictList, - requiredAttrNumbersForDistriutedRte); - } - else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_AUTO) - { - bool localTableHasFilter = list_length(localTableRestrictList) > 0; - bool distributedTableHasFilter = - list_length(distributedTableRestrictList) > 0; - - if (resultRelation && resultRelation->relid == mostFilteredLocalRte->relid && - !mostFilteredLocalRte->inFromCl) - { - /* - * We cannot recursively plan result relation, we have to - * recursively plan the distributed table. - * - * TODO: A future improvement could be to pick the next most filtered - * local relation, if exists. - */ - ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, - distributedTableRestrictList, - requiredAttrNumbersForDistriutedRte); - } - else if (localTableHasFilter || !distributedTableHasFilter) - { - /* - * First, favor recursively planning local table when it has a filter. - * The rationale is that local tables are small, and at least one filter - * they become even smaller. On each iteration, we pick the local table - * with the most filters (e.g., WHERE clause entries). Note that the filters - * don't need to be directly on the table in the query tree, instead we use - * Postgres' filters where filters can be pushed down tables via filters. - * - * Second, if a distributed table doesn't have a filter, we do not ever - * prefer recursively planning that. Instead, we recursively plan the - * local table, assuming that it is smaller. - * - * TODO: If we have better statistics on how many tuples each table returns - * considering the filters on them, we should pick the table with least - * tuples. Today, we do not have such an infrastructure. - */ - ReplaceRTERelationWithRteSubquery(mostFilteredLocalRte, - localTableRestrictList, - requiredAttrNumbersForLocalRte); - } - else - { - ReplaceRTERelationWithRteSubquery(mostFilteredDistributedRte, - distributedTableRestrictList, - requiredAttrNumbersForDistriutedRte); - } - } - else - { - elog(ERROR, "unexpected local table join policy: %d", LocalTableJoinPolicy); - } - } -} - - -/* - * RequiredAttrNumbersForRelation returns the required attribute numbers for - * the input RTE relation in order for the planning to succeed. - * - * The function could be optimized by not adding the columns that only appear - * WHERE clause as a filter (e.g., not a join clause). - */ -static List * -RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, - RecursivePlanningContext *planningContext) -{ - PlannerRestrictionContext *plannerRestrictionContext = - planningContext->plannerRestrictionContext; - - /* TODO: Get rid of this hack, find relation restriction information directly */ - PlannerRestrictionContext *filteredPlannerRestrictionContext = - FilterPlannerRestrictionForQuery(plannerRestrictionContext, - WrapRteRelationIntoSubquery(relationRte, NIL)); - - RelationRestrictionContext *relationRestrictionContext = - filteredPlannerRestrictionContext->relationRestrictionContext; - List *filteredRelationRestrictionList = - relationRestrictionContext->relationRestrictionList; - RelationRestriction *relationRestriction = - (RelationRestriction *) linitial(filteredRelationRestrictionList); - - PlannerInfo *plannerInfo = relationRestriction->plannerInfo; - Query *queryToProcess = plannerInfo->parse; - int rteIndex = relationRestriction->index; - - List *allVarsInQuery = pull_vars_of_level((Node *) queryToProcess, 0); - ListCell *varCell = NULL; - - List *requiredAttrNumbers = NIL; - - foreach(varCell, allVarsInQuery) - { - Var *var = (Var *) lfirst(varCell); - - if (var->varno == rteIndex) - { - requiredAttrNumbers = list_append_unique_int(requiredAttrNumbers, - var->varattno); - } - } - - return requiredAttrNumbers; -} - - -/* - * MostFilteredRte returns a range table entry which has the most filters - * on it along with the restrictions (e.g., fills **restrictionList). - * - * The function also gets a boolean localTable parameter, so the caller - * can choose to run the function for only local tables or distributed tables. - */ -static RangeTblEntry * -MostFilteredRte(PlannerRestrictionContext *plannerRestrictionContext, - List *rangeTableList, List **restrictionList, - bool localTable) -{ - RangeTblEntry *mostFilteredLocalRte = NULL; - - ListCell *rangeTableCell = NULL; - - foreach(rangeTableCell, rangeTableList) - { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - - /* we're only interested in tables */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) - { - continue; - } - - if (localTable && IsCitusTable(rangeTableEntry->relid)) - { - continue; - } - - if (!localTable && !IsCitusTable(rangeTableEntry->relid)) - { - continue; - } - - List *currentRestrictionList = - GetRestrictInfoListForRelation(rangeTableEntry, - plannerRestrictionContext, 1); - - if (mostFilteredLocalRte == NULL || - list_length(*restrictionList) < list_length(currentRestrictionList) || - ContainsFalseClause(currentRestrictionList)) - { - mostFilteredLocalRte = rangeTableEntry; - *restrictionList = currentRestrictionList; - } - } - - return mostFilteredLocalRte; -} - - /* * ReplaceRTERelationWithRteSubquery replaces the input rte relation target entry * with a subquery. The function also pushes down the filters to the subquery. */ -static void +void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, List *requiredAttrNumbers) { @@ -1648,56 +1384,6 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict } -/* - * AllDataLocallyAccessible return true if all data for the relations in the - * rangeTableList is locally accessible. - */ -static bool -AllDataLocallyAccessible(List *rangeTableList) -{ - ListCell *rangeTableCell = NULL; - foreach(rangeTableCell, rangeTableList) - { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - - /* we're only interested in tables */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) - { - continue; - } - - - Oid relationId = rangeTableEntry->relid; - - if (!IsCitusTable(relationId)) - { - /* local tables are locally accessible */ - continue; - } - - List *shardIntervalList = LoadShardIntervalList(relationId); - if (list_length(shardIntervalList) > 1) - { - /* we currently only consider single placement tables */ - return false; - } - - ShardInterval *shardInterval = linitial(shardIntervalList); - uint64 shardId = shardInterval->shardId; - ShardPlacement *localShardPlacement = - ShardPlacementOnGroup(shardId, GetLocalGroupId()); - if (localShardPlacement == NULL) - { - /* the table doesn't have a placement on this node */ - return false; - } - } - - return true; -} - - /* * ContainsLocalTableDistributedTableJoin returns true if the input range table list * contains a direct join between local and distributed tables. @@ -1714,8 +1400,8 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); /* we're only interested in tables */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) + if (rangeTableEntry->rtekind != RTE_RELATION || + rangeTableEntry->relkind != RELKIND_RELATION) { continue; } @@ -1729,14 +1415,9 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) { containsLocalTable = true; } - - if (containsLocalTable && containsDistributedTable) - { - return true; - } } - return false; + return containsLocalTable && containsDistributedTable; } diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index fbf9c14ab..d93c77962 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -200,8 +200,8 @@ static const struct config_enum_entry log_level_options[] = { static const struct config_enum_entry local_table_join_policies[] = { { "never", LOCAL_JOIN_POLICY_NEVER, false}, - { "pull-local", LOCAL_JOIN_POLICY_PULL_LOCAL, false}, - { "pull-distributed", LOCAL_JOIN_POLICY_PULL_DISTRIBUTED, false}, + { "prefer-local", LOCAL_JOIN_POLICY_PREFER_LOCAL, false}, + { "prefer-distributed", LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED, false}, { "auto", LOCAL_JOIN_POLICY_AUTO, false}, { NULL, 0, false} }; diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index 603b68b81..3461e2246 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -70,6 +70,7 @@ extern List * PreprocessClusterStmt(Node *node, const char *clusterCommand); /* index.c */ typedef void (*PGIndexProcessor)(Form_pg_index, List **); + /* call.c */ extern bool CallDistributedProcedureRemotely(CallStmt *callStmt, DestReceiver *dest); diff --git a/src/include/distributed/local_distributed_join_planner.h b/src/include/distributed/local_distributed_join_planner.h new file mode 100644 index 000000000..85d15b4ea --- /dev/null +++ b/src/include/distributed/local_distributed_join_planner.h @@ -0,0 +1,24 @@ + +/*------------------------------------------------------------------------- + * + * listutils.h + * + * Declarations for public utility functions related to lists. + * + * Copyright (c) Citus Data, Inc. + * + *------------------------------------------------------------------------- + */ + +#ifndef LOCAL_DISTRIBUTED_JOIN_PLANNER_H +#define LOCAL_DISTRIBUTED_JOIN_PLANNER_H + +#include "postgres.h" +#include "distributed/recursive_planning.h" + + +extern void +ConvertLocalTableJoinsToSubqueries(Query *query, + RecursivePlanningContext *context); + +#endif /* LOCAL_DISTRIBUTED_JOIN_PLANNER_H */ diff --git a/src/include/distributed/metadata_utility.h b/src/include/distributed/metadata_utility.h index d41a1c53a..a34a6a9ff 100644 --- a/src/include/distributed/metadata_utility.h +++ b/src/include/distributed/metadata_utility.h @@ -113,12 +113,9 @@ extern List * AllShardPlacementsOnNodeGroup(int32 groupId); extern List * GroupShardPlacementsForTableOnGroup(Oid relationId, int32 groupId); extern StringInfo GenerateSizeQueryOnMultiplePlacements(List *shardIntervalList, char *sizeQuery); -<<<<<<< HEAD extern List * RemoveCoordinatorPlacementIfNotSingleNode(List *placementList); -======= extern ShardPlacement * ShardPlacementOnGroup(uint64 shardId, int groupId); ->>>>>>> Handle modifications as well /* Function declarations to modify shard and shard placement data */ extern void InsertShardRow(Oid relationId, uint64 shardId, char storageType, diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 28f9f6e5d..d6fed178e 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -26,13 +26,27 @@ typedef enum { LOCAL_JOIN_POLICY_NEVER = 0, - LOCAL_JOIN_POLICY_PULL_LOCAL = 1, - LOCAL_JOIN_POLICY_PULL_DISTRIBUTED = 2, + LOCAL_JOIN_POLICY_PREFER_LOCAL = 1, + LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED = 2, LOCAL_JOIN_POLICY_AUTO = 3, } LocalJoinPolicy; extern int LocalTableJoinPolicy; +/* + * RecursivePlanningContext is used to recursively plan subqueries + * and CTEs, pull results to the coordinator, and push it back into + * the workers. + */ +typedef struct RecursivePlanningContext +{ + int level; + uint64 planId; + bool allDistributionKeysInQueryAreEqual; /* used for some optimizations */ + List *subPlanList; + PlannerRestrictionContext *plannerRestrictionContext; +} RecursivePlanningContext; + extern List * GenerateSubplansForSubqueriesAndCTEs(uint64 planId, Query *originalQuery, PlannerRestrictionContext * @@ -46,6 +60,9 @@ extern Query * BuildReadIntermediateResultsArrayQuery(List *targetEntryList, bool useBinaryCopyFormat); extern bool GeneratingSubplans(void); extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); +extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, + List *restrictionList, + List *requiredAttrNumbers); #endif /* RECURSIVE_PLANNING_H */ diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 489d4be0f..be290b200 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -15,15 +15,32 @@ SELECT create_distributed_table('distributed_table', 'key'); (1 row) +CREATE TABLE distributed_table_pkey (key int primary key, value text, value_2 jsonb); +SELECT create_distributed_table('distributed_table_pkey', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE distributed_table_windex (key int, value text, value_2 jsonb); +SELECT create_distributed_table('distributed_table_windex', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE UNIQUE INDEX key_index ON distributed_table_windex (key); SET client_min_messages TO DEBUG1; -- the user doesn't allow local / distributed table joinn SET citus.local_table_join_policy TO 'never'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -ERROR: relation postgres_table is not distributed +ERROR: direct joins between distributed and local tables are not supported +HINT: Use CTE's or subqueries to select from local tables and use them in joins SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -ERROR: relation postgres_table is not distributed +ERROR: direct joins between distributed and local tables are not supported +HINT: Use CTE's or subqueries to select from local tables and use them in joins -- the user prefers local table recursively planned -SET citus.local_table_join_policy TO 'pull-local'; +SET citus.local_table_join_policy TO 'prefer-local'; SELECT count(*) FROM postgres_table JOIN distributed_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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 @@ -43,7 +60,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) -- the user prefers distributed table recursively planned -SET citus.local_table_join_policy TO 'pull-distributed'; +SET citus.local_table_join_policy TO 'prefer-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 @@ -65,8 +82,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- update/delete -- auto tests -- switch back to the default policy, which is auto -RESET citus.local_table_join_policy; --- on the default mode, the local tables should be recursively planned +SET citus.local_table_join_policy to 'auto'; +-- on the auto mode, the local tables should be recursively planned +-- unless a unique index exists in a column for distributed table SELECT count(*) FROM distributed_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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 @@ -94,20 +112,90 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) --- this is a contreversial part that we should discuss further --- if the distributed table has at least one filter, we prefer --- recursively planning of the distributed table -SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey 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.distributed_table_pkey WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (value)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = distributed_table_pkey.key; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey 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.distributed_table_pkey WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_pkey.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(key); +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(value); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (value)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON postgres_table.key = distributed_table_windex.key; +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON distributed_table_windex.key = 10; +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- no unique index on value so local table should be recursively planned. +SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) WHERE (distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) count --------------------------------------------------------------------- 0 (1 row) --- but if the filters can be pushed downn to the local table via the join --- we are smart about recursively planning the local table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; 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 (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 @@ -117,7 +205,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) --- if both local and distributed tables have a filter, we prefer local +-- if both local and distributed tables have a filter, we prefer local unless distributed table has unique indexes on any equality filter SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 @@ -149,29 +237,24 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) --- if one of the distributed tables have a filter, we'll prefer recursive planning of it as well --- it actually leads to a poor plan as we need to recursively plan local tables anyway as it is --- joined with another distributed table SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.value = '1'; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 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 p1 WHERE true OFFSET 0 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 p2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE (value OPERATOR(pg_catalog.=) '1'::text) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_3 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) d1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) count --------------------------------------------------------------------- 0 (1 row) -- if the filter is on the JOIN key, we can recursively plan the local --- tables as filters are pushded down to the local tables +-- tables as filters are pushed down to the local tables SELECT count(*) FROM @@ -188,6 +271,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +SET citus.local_table_join_policy to 'auto'; -- we can support modification queries as well UPDATE postgres_table @@ -211,6 +295,120 @@ WHERE 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +-- in case of update/delete we always recursively plan +-- the tables other than target table no matter what the policy is +SET citus.local_table_join_policy TO 'prefer-local'; +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +SET citus.local_table_join_policy TO 'prefer-distributed'; +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) -- modifications with multiple tables UPDATE distributed_table @@ -254,4 +452,4 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_j \set VERBOSITY terse RESET client_min_messages; DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 3 other objects +NOTICE: drop cascades to 5 other objects diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out index 2df77f1af..87dee53e0 100644 --- a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out +++ b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out @@ -25,7 +25,7 @@ SELECT create_distributed_table('distributed_table', 'key'); SET client_min_messages TO DEBUG1; -- for the purposes of these tests, we always want to recursively -- plan local tables. -SET citus.local_table_join_policy TO "pull-local"; +SET citus.local_table_join_policy TO "prefer-local"; -- there are no filters, hence cannot pushdown any filters SELECT count(*) FROM distributed_table u1 diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 0b0285af9..be1946533 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -8,6 +8,13 @@ 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, value text, value_2 jsonb); +SELECT create_distributed_table('distributed_table_windex', 'key'); +CREATE UNIQUE INDEX key_index ON distributed_table_windex (key); + SET client_min_messages TO DEBUG1; @@ -17,13 +24,13 @@ SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -- the user prefers local table recursively planned -SET citus.local_table_join_policy TO 'pull-local'; +SET citus.local_table_join_policy TO 'prefer-local'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -- the user prefers distributed table recursively planned -SET citus.local_table_join_policy TO 'pull-distributed'; +SET citus.local_table_join_policy TO 'prefer-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); SELECT count(*) FROM postgres_table JOIN reference_table USING(key); @@ -32,26 +39,34 @@ SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -- auto tests -- switch back to the default policy, which is auto -RESET citus.local_table_join_policy; +SET citus.local_table_join_policy to 'auto'; --- on the default mode, the local tables should be recursively planned +-- on the auto mode, the local tables should be recursively planned +-- unless a unique index exists in a column for distributed table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); SELECT count(*) FROM reference_table JOIN postgres_table USING(key); SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_table USING (key); +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = distributed_table_pkey.key; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; --- this is a contreversial part that we should discuss further --- if the distributed table has at least one filter, we prefer --- recursively planning of the distributed table +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(key); +SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(value); +SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON postgres_table.key = distributed_table_windex.key; +SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON distributed_table_windex.key = 10; + +-- no unique index on value so local table should be recursively planned. SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; --- but if the filters can be pushed downn to the local table via the join --- we are smart about recursively planning the local table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; --- if both local and distributed tables have a filter, we prefer local +-- if both local and distributed tables have a filter, we prefer local unless distributed table has unique indexes on any equality filter SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; @@ -61,9 +76,6 @@ SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE dist SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key); --- if one of the distributed tables have a filter, we'll prefer recursive planning of it as well --- it actually leads to a poor plan as we need to recursively plan local tables anyway as it is --- joined with another distributed table SELECT count(*) FROM @@ -72,7 +84,7 @@ WHERE d1.value = '1'; -- if the filter is on the JOIN key, we can recursively plan the local --- tables as filters are pushded down to the local tables +-- tables as filters are pushed down to the local tables SELECT count(*) FROM @@ -81,6 +93,8 @@ WHERE d1.key = 1; +SET citus.local_table_join_policy to 'auto'; + -- we can support modification queries as well UPDATE postgres_table @@ -101,6 +115,106 @@ FROM WHERE distributed_table.key = postgres_table.key; +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; + +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; + +-- in case of update/delete we always recursively plan +-- the tables other than target table no matter what the policy is + +SET citus.local_table_join_policy TO 'prefer-local'; + +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; + + +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; + +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; + +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; + + +SET citus.local_table_join_policy TO 'prefer-distributed'; + +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; + + +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; + +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; + +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; + -- modifications with multiple tables UPDATE distributed_table diff --git a/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql b/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql index ecd148b91..7a1e9923d 100644 --- a/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql +++ b/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql @@ -26,7 +26,7 @@ SET client_min_messages TO DEBUG1; -- for the purposes of these tests, we always want to recursively -- plan local tables. -SET citus.local_table_join_policy TO "pull-local"; +SET citus.local_table_join_policy TO "prefer-local"; -- there are no filters, hence cannot pushdown any filters From 44953579cf4d291072a266712750539c29eb97ce Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Fri, 20 Nov 2020 15:47:42 +0300 Subject: [PATCH 10/37] Enable citus-local distributed table joins Check equality in quals We want to recursively plan distributed tables only if they have an equality filter on a unique column. So '>' and '<' operators will not trigger recursive planning of distributed tables in local-distributed table joins. Recursively plan distributed table only if the filter is constant If the filter is not a constant then the join might return multiple rows and there is a chance that the distributed table will return huge data. Hence if the filter is not constant we choose to recursively plan the local table. --- .../planner/local_distributed_join_planner.c | 333 +++++++++--------- .../planner/multi_physical_planner.c | 50 +++ .../planner/multi_router_planner.c | 34 +- .../distributed/planner/recursive_planning.c | 106 +++++- .../distributed/planner/shard_pruning.c | 2 - .../distributed/multi_physical_planner.h | 1 + src/include/distributed/recursive_planning.h | 4 +- src/include/distributed/shard_pruning.h | 2 + .../regress/expected/local_table_join.out | 308 +++++++++++++++- src/test/regress/sql/local_table_join.sql | 75 +++- .../regress/sql/subqueries_not_supported.sql | 6 +- 11 files changed, 724 insertions(+), 197 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 4a31aa543..2ff2257ec 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -54,20 +54,34 @@ #include "utils/guc.h" #include "utils/lsyscache.h" -static bool ShouldConvertLocalTableJoinsToSubqueries(List* rangeTableList); +typedef struct RTEToSubqueryConverterReference { + RangeTblEntry* rangeTableEntry; + Index rteIndex; + List* restrictionList; + List* requiredAttributeNumbers; +} RTEToSubqueryConverterReference; + +typedef struct RTEToSubqueryConverterContext{ + List* distributedTableList; /* reference or distributed table */ + List* localTableList; + List* citusLocalTableList; + bool hasSubqueryRTE; +}RTEToSubqueryConverterContext; + +static bool ShouldConvertLocalTableJoinsToSubqueries(List* rangeTableList, Oid resultRelationId); static bool HasUniqueFilter(RangeTblEntry* distRTE, List* distRTERestrictionList, List* requiredAttrNumbersForDistRTE); -static void AutoConvertLocalTableJoinToSubquery(RangeTblEntry* localRTE, RangeTblEntry* distRTE, - List* localRTERestrictionList, List* distRTERestrictionList, - List *requiredAttrNumbersForLocalRTE, List *requiredAttrNumbersForDistRTE); +static bool AutoConvertLocalTableJoinToSubquery(FromExpr* joinTree, + RTEToSubqueryConverterReference* distRTEContext); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, RecursivePlanningContext *planningContext); -static RangeTblEntry * FindNextRTECandidate(PlannerRestrictionContext * - plannerRestrictionContext, - List *rangeTableList, List **restrictionList, - bool localTable); -static bool AllDataLocallyAccessible(List *rangeTableList); +static RTEToSubqueryConverterContext * CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, + List *rangeTableList); static void GetAllUniqueIndexes(Form_pg_index indexForm, List** uniqueIndexes); - +static RTEToSubqueryConverterReference* + GetNextRTEToConvertToSubquery(FromExpr* joinTree, RTEToSubqueryConverterContext* rteToSubqueryConverterContext, + PlannerRestrictionContext *plannerRestrictionContext, RangeTblEntry* resultRelation); +static void PopFromRTEToSubqueryConverterContext(RTEToSubqueryConverterContext* rteToSubqueryConverterContext, + bool isCitusLocalTable); /* * ConvertLocalTableJoinsToSubqueries gets a query and the planner * restrictions. As long as there is a join between a local table @@ -83,70 +97,109 @@ ConvertLocalTableJoinsToSubqueries(Query *query, RecursivePlanningContext *context) { List *rangeTableList = query->rtable; - if(!ShouldConvertLocalTableJoinsToSubqueries(rangeTableList)) { + RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); + Oid resultRelationId = InvalidOid; + if (resultRelation) { + resultRelationId = resultRelation->relid; + } + if (!ShouldConvertLocalTableJoinsToSubqueries(rangeTableList, resultRelationId)) { return; } + RTEToSubqueryConverterContext* rteToSubqueryConverterContext = CreateRTEToSubqueryConverterContext( + context, rangeTableList); - RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); - while (ContainsLocalTableDistributedTableJoin(rangeTableList)) + RTEToSubqueryConverterReference* rteToSubqueryConverterReference = + GetNextRTEToConvertToSubquery(query->jointree, rteToSubqueryConverterContext, + context->plannerRestrictionContext, resultRelation); + while (rteToSubqueryConverterReference) { - List *localTableRestrictList = NIL; - List *distributedTableRestrictList = NIL; + ReplaceRTERelationWithRteSubquery(rteToSubqueryConverterReference->rangeTableEntry, + rteToSubqueryConverterReference->restrictionList, + rteToSubqueryConverterReference->requiredAttributeNumbers); + rteToSubqueryConverterReference = + GetNextRTEToConvertToSubquery(query->jointree, rteToSubqueryConverterContext, + context->plannerRestrictionContext, resultRelation); + } +} - bool localTable = true; +static RTEToSubqueryConverterReference* + GetNextRTEToConvertToSubquery(FromExpr* joinTree, RTEToSubqueryConverterContext* rteToSubqueryConverterContext, + PlannerRestrictionContext *plannerRestrictionContext, RangeTblEntry* resultRelation) { - PlannerRestrictionContext *plannerRestrictionContext = - context->plannerRestrictionContext; - RangeTblEntry *localRTECandidate = - FindNextRTECandidate(plannerRestrictionContext, rangeTableList, - &localTableRestrictList, localTable); - RangeTblEntry *distributedRTECandidate = - FindNextRTECandidate(plannerRestrictionContext, rangeTableList, - &distributedTableRestrictList, !localTable); + RTEToSubqueryConverterReference* localRTECandidate = NULL; + RTEToSubqueryConverterReference* nonLocalRTECandidate = NULL; + bool citusLocalTableChosen = false; - List *requiredAttrNumbersForLocalRte = - RequiredAttrNumbersForRelation(localRTECandidate, context); - List *requiredAttrNumbersForDistributedRte = - RequiredAttrNumbersForRelation(distributedRTECandidate, context); + if (list_length(rteToSubqueryConverterContext->localTableList) > 0) { + localRTECandidate = linitial(rteToSubqueryConverterContext->localTableList); + }else if (list_length(rteToSubqueryConverterContext->citusLocalTableList) > 0) { + localRTECandidate = linitial(rteToSubqueryConverterContext->citusLocalTableList); + citusLocalTableChosen = true; + } + if (localRTECandidate == NULL) { + return NULL; + } - if (resultRelation) { + if (list_length(rteToSubqueryConverterContext->distributedTableList) > 0) { + nonLocalRTECandidate = linitial(rteToSubqueryConverterContext->distributedTableList); + } + if (nonLocalRTECandidate == NULL && !rteToSubqueryConverterContext->hasSubqueryRTE) { + return NULL; + } - if (resultRelation->relid == localRTECandidate->relid) { - ReplaceRTERelationWithRteSubquery(distributedRTECandidate, - distributedTableRestrictList, - requiredAttrNumbersForDistributedRte); - continue; - }else if (resultRelation->relid == distributedRTECandidate->relid) { - ReplaceRTERelationWithRteSubquery(localRTECandidate, - localTableRestrictList, - requiredAttrNumbersForLocalRte); - continue; - } + if (resultRelation) { + if(resultRelation == localRTECandidate->rangeTableEntry) { + rteToSubqueryConverterContext->distributedTableList = list_delete_first( + rteToSubqueryConverterContext->distributedTableList + ); + return nonLocalRTECandidate; + } + if (resultRelation == nonLocalRTECandidate->rangeTableEntry) { + PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); + return localRTECandidate; + } + } + + if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) { + PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); + return localRTECandidate; + }else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) { + if (nonLocalRTECandidate) { + rteToSubqueryConverterContext->distributedTableList = list_delete_first( + rteToSubqueryConverterContext->distributedTableList + ); + return nonLocalRTECandidate; + }else { + PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); + return localRTECandidate; } - if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) - { - ReplaceRTERelationWithRteSubquery(localRTECandidate, - localTableRestrictList, - requiredAttrNumbersForLocalRte); - } - else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) - { - ReplaceRTERelationWithRteSubquery(distributedRTECandidate, - distributedTableRestrictList, - requiredAttrNumbersForDistributedRte); - } - else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_AUTO) - { - AutoConvertLocalTableJoinToSubquery(localRTECandidate, distributedRTECandidate, - localTableRestrictList, distributedTableRestrictList, - requiredAttrNumbersForLocalRte, requiredAttrNumbersForDistributedRte); - } - else - { - elog(ERROR, "unexpected local table join policy: %d", LocalTableJoinPolicy); + }else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_AUTO) { + bool shouldConvertNonLocalTable = AutoConvertLocalTableJoinToSubquery(joinTree, nonLocalRTECandidate); + if (shouldConvertNonLocalTable) { + rteToSubqueryConverterContext->distributedTableList = list_delete_first( + rteToSubqueryConverterContext->distributedTableList + ); + return nonLocalRTECandidate; + }else { + PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); + return localRTECandidate; } + }else { + elog(ERROR, "unexpected local table join policy: %d", LocalTableJoinPolicy); + } + return NULL; +} + +static void PopFromRTEToSubqueryConverterContext(RTEToSubqueryConverterContext* rteToSubqueryConverterContext, + bool isCitusLocalTable) { + if (isCitusLocalTable) { + rteToSubqueryConverterContext->citusLocalTableList = + list_delete_first(rteToSubqueryConverterContext->citusLocalTableList); + }else { + rteToSubqueryConverterContext->localTableList = + list_delete_first(rteToSubqueryConverterContext->localTableList); } } @@ -154,46 +207,42 @@ ConvertLocalTableJoinsToSubqueries(Query *query, * ShouldConvertLocalTableJoinsToSubqueries returns true if we should * convert local-dist table joins to subqueries. */ -static bool ShouldConvertLocalTableJoinsToSubqueries(List* rangeTableList) { +static bool ShouldConvertLocalTableJoinsToSubqueries(List* rangeTableList, Oid resultRelationId) { if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) { /* user doesn't want Citus to enable local table joins */ return false; } - - if (!ContainsLocalTableDistributedTableJoin(rangeTableList)) - { - /* nothing to do as there are no relevant joins */ - return false; - } - - if (AllDataLocallyAccessible(rangeTableList)) - { - /* recursively planning is overkill, router planner can already handle this */ + if (!ContainsTableToBeConvertedToSubquery(rangeTableList, resultRelationId)) { return false; } return true; } -static void AutoConvertLocalTableJoinToSubquery(RangeTblEntry* localRTE, RangeTblEntry* distRTE, - List* localRTERestrictionList, List* distRTERestrictionList, - List *requiredAttrNumbersForLocalRTE, List *requiredAttrNumbersForDistRTE) { - - bool hasUniqueFilter = HasUniqueFilter(distRTE, distRTERestrictionList, requiredAttrNumbersForDistRTE); - if (hasUniqueFilter) { - ReplaceRTERelationWithRteSubquery(distRTE, - distRTERestrictionList, - requiredAttrNumbersForDistRTE); - }else { - ReplaceRTERelationWithRteSubquery(localRTE, - localRTERestrictionList, - requiredAttrNumbersForLocalRTE); +static bool AutoConvertLocalTableJoinToSubquery(FromExpr* joinTree, + RTEToSubqueryConverterReference* rteToSubqueryConverterReference) { + if (rteToSubqueryConverterReference == NULL) { + return false; } + List* distRTEEqualityQuals = + FetchAttributeNumsForRTEFromQuals(joinTree->quals, rteToSubqueryConverterReference->rteIndex); + + Node* join = NULL; + foreach_ptr(join, joinTree->fromlist) { + if (IsA(join, JoinExpr)) { + JoinExpr* joinExpr = (JoinExpr*) join; + distRTEEqualityQuals = list_concat(distRTEEqualityQuals, + FetchAttributeNumsForRTEFromQuals(joinExpr->quals, rteToSubqueryConverterReference->rteIndex) + ); + } + } + + bool hasUniqueFilter = HasUniqueFilter(rteToSubqueryConverterReference->rangeTableEntry, + rteToSubqueryConverterReference->restrictionList, distRTEEqualityQuals); + return hasUniqueFilter; } -// TODO:: This function should only consider equality, -// currently it will return true for dist.a > 5. We should check this from join->quals. static bool HasUniqueFilter(RangeTblEntry* distRTE, List* distRTERestrictionList, List* requiredAttrNumbersForDistRTE) { List* uniqueIndexes = ExecuteFunctionOnEachTableIndex(distRTE->relid, GetAllUniqueIndexes); int columnNumber = 0; @@ -237,6 +286,10 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, filteredPlannerRestrictionContext->relationRestrictionContext; List *filteredRelationRestrictionList = relationRestrictionContext->relationRestrictionList; + + if (list_length(filteredRelationRestrictionList) == 0) { + return NIL; + } RelationRestriction *relationRestriction = (RelationRestriction *) linitial(filteredRelationRestrictionList); @@ -265,23 +318,27 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, /* - * FindNextRTECandidate returns a range table entry which has the most filters + * CreateRTEToSubqueryConverterContext returns a range table entry which has the most filters * on it along with the restrictions (e.g., fills **restrictionList). * * The function also gets a boolean localTable parameter, so the caller * can choose to run the function for only local tables or distributed tables. */ -static RangeTblEntry * -FindNextRTECandidate(PlannerRestrictionContext *plannerRestrictionContext, - List *rangeTableList, List **restrictionList, - bool localTable) +static RTEToSubqueryConverterContext* +CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, + List *rangeTableList) { - ListCell *rangeTableCell = NULL; + + RTEToSubqueryConverterContext* rteToSubqueryConverterContext = palloc0(sizeof(RTEToSubqueryConverterContext)); - foreach(rangeTableCell, rangeTableList) + int rteIndex = 0; + RangeTblEntry* rangeTableEntry = NULL; + foreach_ptr(rangeTableEntry, rangeTableList) { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - + rteIndex++; + if (rangeTableEntry->rtekind == RTE_SUBQUERY) { + rteToSubqueryConverterContext->hasSubqueryRTE = true; + } /* we're only interested in tables */ if (!(rangeTableEntry->rtekind == RTE_RELATION && rangeTableEntry->relkind == RELKIND_RELATION)) @@ -289,73 +346,25 @@ FindNextRTECandidate(PlannerRestrictionContext *plannerRestrictionContext, continue; } - if (localTable && IsCitusTable(rangeTableEntry->relid)) - { - continue; - } + RTEToSubqueryConverterReference* rteToSubqueryConverter = palloc(sizeof(RTEToSubqueryConverterReference)); + rteToSubqueryConverter->rangeTableEntry = rangeTableEntry; + rteToSubqueryConverter->rteIndex = rteIndex; + rteToSubqueryConverter->restrictionList = GetRestrictInfoListForRelation(rangeTableEntry, + context->plannerRestrictionContext, 1); + rteToSubqueryConverter->requiredAttributeNumbers = RequiredAttrNumbersForRelation(rangeTableEntry, context); - if (!localTable && !IsCitusTable(rangeTableEntry->relid)) - { - continue; - } - - List *currentRestrictionList = - GetRestrictInfoListForRelation(rangeTableEntry, - plannerRestrictionContext, 1); - - *restrictionList = currentRestrictionList; - return rangeTableEntry; - } - // TODO:: Put Illegal state error code - ereport(ERROR, (errmsg("unexpected state: could not find any RTE to convert to subquery in range table list"))); - return NULL; -} - -/* - * AllDataLocallyAccessible return true if all data for the relations in the - * rangeTableList is locally accessible. - */ -static bool -AllDataLocallyAccessible(List *rangeTableList) -{ - ListCell *rangeTableCell = NULL; - foreach(rangeTableCell, rangeTableList) - { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - - /* we're only interested in tables */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) - { - continue; - } - - - Oid relationId = rangeTableEntry->relid; - - if (!IsCitusTable(relationId)) - { - /* local tables are locally accessible */ - continue; - } - - List *shardIntervalList = LoadShardIntervalList(relationId); - if (list_length(shardIntervalList) > 1) - { - /* we currently only consider single placement tables */ - return false; - } - - ShardInterval *shardInterval = linitial(shardIntervalList); - uint64 shardId = shardInterval->shardId; - ShardPlacement *localShardPlacement = - ShardPlacementOnGroup(shardId, GetLocalGroupId()); - if (localShardPlacement == NULL) - { - /* the table doesn't have a placement on this node */ - return false; + bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE) || + IsCitusTableType(rangeTableEntry->relid, DISTRIBUTED_TABLE); + if (referenceOrDistributedTable) { + rteToSubqueryConverterContext->distributedTableList = + lappend(rteToSubqueryConverterContext->distributedTableList, rteToSubqueryConverter); + }else if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE)) { + rteToSubqueryConverterContext->citusLocalTableList = + lappend(rteToSubqueryConverterContext->citusLocalTableList, rteToSubqueryConverter); + }else { + rteToSubqueryConverterContext->localTableList = + lappend(rteToSubqueryConverterContext->localTableList, rteToSubqueryConverter); } } - - return true; + return rteToSubqueryConverterContext; } \ No newline at end of file diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 1dd5c661a..6e05268f9 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -3588,6 +3588,56 @@ NodeIsRangeTblRefReferenceTable(Node *node, List *rangeTableList) return IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE); } +List* FetchAttributeNumsForRTEFromQuals(Node* quals, Index rteIndex) { + List* attributeNums = NIL; + if (quals == NULL) + { + return NIL; + } + + if (IsA(quals, OpExpr)) + { + if (!NodeIsEqualsOpExpr(quals)) + { + return NIL; + } + OpExpr *nextJoinClauseOpExpr = castNode(OpExpr, quals); + + Var* var = NULL; + if (VarConstOpExprClause(nextJoinClauseOpExpr, &var, NULL)) { + attributeNums = lappend_int(attributeNums, var->varattno); + return attributeNums; + } + + } + else if (IsA(quals, BoolExpr)) + { + BoolExpr *boolExpr = (BoolExpr *) quals; + + if (boolExpr->boolop != AND_EXPR && boolExpr->boolop != OR_EXPR) { + return attributeNums; + } + + bool hasEquality = true; + Node* arg = NULL; + foreach_ptr(arg, boolExpr->args) + { + List* attributeNumsInSubExpression = FetchAttributeNumsForRTEFromQuals(arg, rteIndex); + if (boolExpr->boolop == AND_EXPR) + { + hasEquality |= list_length(attributeNumsInSubExpression) > 0; + }else if (boolExpr->boolop == OR_EXPR){ + hasEquality &= list_length(attributeNumsInSubExpression) > 0; + } + attributeNums = list_concat(attributeNums, attributeNumsInSubExpression); + + } + if (hasEquality) { + return attributeNums; + } + } + return NIL; +} /* * JoinSequenceArray walks over the join nodes in the job query and constructs a join diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 24414fa90..6b9858e23 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -181,7 +181,7 @@ static void ReorderTaskPlacementsByTaskAssignmentPolicy(Job *job, TaskAssignmentPolicyType taskAssignmentPolicy, List *placementList); - +static bool IsLocalOrCitusLocalTable(Oid relationId); /* * CreateRouterPlan attempts to create a router executor plan for the given @@ -530,11 +530,11 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, Oid distributedTableId = ModifyQueryResultRelationId(queryTree); *distributedTableIdOutput = distributedTableId; - if (ContainsLocalTableDistributedTableJoin(queryTree->rtable)) + if (ContainsTableToBeConvertedToSubquery(queryTree->rtable, distributedTableId)) { return deferredError; } - + Var *partitionColumn = NULL; if (IsCitusTable(distributedTableId)) @@ -773,6 +773,13 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, return NULL; } +static bool IsLocalOrCitusLocalTable(Oid relationId) { + if (!IsCitusTable(relationId)) { + return true; + } + return IsCitusTableType(relationId, CITUS_LOCAL_TABLE); +} + /* * NodeIsFieldStore returns true if given Node is a FieldStore object. @@ -896,7 +903,7 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer List *rangeTableList = NIL; uint32 queryTableCount = 0; CmdType commandType = queryTree->commandType; - bool fastPathRouterQuery = +bool fastPathRouterQuery = plannerRestrictionContext->fastPathRestrictionContext->fastPathRouterQuery; /* @@ -958,13 +965,24 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer /* for other kinds of relations, check if its distributed */ else { - if (ContainsLocalTableDistributedTableJoin(queryTree->rtable)) - { + RangeTblEntry *resultRte = ExtractResultRelationRTE(queryTree); + Oid resultRelationId = InvalidOid; + if (resultRte) { + resultRelationId = resultRte->relid; + } + if (IsLocalOrCitusLocalTable(rangeTableEntry->relid) && + ContainsTableToBeConvertedToSubquery(queryTree->rtable, resultRelationId) + ) + { StringInfo errorMessage = makeStringInfo(); char *relationName = get_rel_name(rangeTableEntry->relid); - - appendStringInfo(errorMessage, "relation %s is not distributed", + if (IsCitusTable(rangeTableEntry->relid)) { + appendStringInfo(errorMessage, "citus local table %s cannot be used in this join", relationName); + }else { + appendStringInfo(errorMessage, "relation %s is not distributed", + relationName); + } return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, errorMessage->data, NULL, NULL); diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 96cd55845..2213f92d5 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -163,6 +163,7 @@ static bool ShouldRecursivelyPlanSubquery(Query *subquery, static bool AllDistributionKeysInSubqueryAreEqual(Query *subquery, PlannerRestrictionContext * restrictionContext); +static bool AllDataLocallyAccessible(List *rangeTableList); static bool ShouldRecursivelyPlanSetOperation(Query *query, RecursivePlanningContext *context); static void RecursivelyPlanSetOperations(Query *query, Node *node, @@ -184,6 +185,7 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); + /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. * The function returns the subplans if necessary. For the details of when/how subplans are @@ -1383,6 +1385,64 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict } } +bool ContainsTableToBeConvertedToSubquery(List* rangeTableList, Oid resultRelationId) { + if (AllDataLocallyAccessible(rangeTableList)) { + return false; + } + return ContainsLocalTableDistributedTableJoin(rangeTableList) || + ContainsLocalTableSubqueryJoin(rangeTableList, resultRelationId); +} + +/* + * AllDataLocallyAccessible return true if all data for the relations in the + * rangeTableList is locally accessible. + */ +static bool +AllDataLocallyAccessible(List *rangeTableList) +{ + RangeTblEntry* rangeTableEntry = NULL; + foreach_ptr(rangeTableEntry, rangeTableList) + { + if (rangeTableEntry->rtekind == RTE_SUBQUERY) { + // TODO:: check if it has distributed table + return false; + } + /* we're only interested in tables */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) + { + continue; + } + + + Oid relationId = rangeTableEntry->relid; + + if (!IsCitusTable(relationId)) + { + /* local tables are locally accessible */ + continue; + } + + List *shardIntervalList = LoadShardIntervalList(relationId); + if (list_length(shardIntervalList) != 1) + { + /* we currently only consider single placement tables */ + return false; + } + + ShardInterval *shardInterval = linitial(shardIntervalList); + uint64 shardId = shardInterval->shardId; + ShardPlacement *localShardPlacement = + ShardPlacementOnGroup(shardId, GetLocalGroupId()); + if (localShardPlacement == NULL) + { + /* the table doesn't have a placement on this node */ + return false; + } + } + + return true; +} /* * ContainsLocalTableDistributedTableJoin returns true if the input range table list @@ -1400,19 +1460,20 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); /* we're only interested in tables */ - if (rangeTableEntry->rtekind != RTE_RELATION || - rangeTableEntry->relkind != RELKIND_RELATION) + /* TODO:: What about partitioned tables? */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) { continue; } - /* TODO: do NOT forget Citus local tables */ - if (IsCitusTable(rangeTableEntry->relid)) + if (IsCitusTableType(rangeTableEntry->relid, DISTRIBUTED_TABLE) || IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE)) { containsDistributedTable = true; } - else + else if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE) || !IsCitusTable(rangeTableEntry->relid)) { + /* we consider citus local tables as local table */ containsLocalTable = true; } } @@ -1421,6 +1482,41 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) } +/* + * ContainsLocalTableSubqueryJoin returns true if the input range table list + * contains a direct join between local table/citus local table and subquery. + */ +bool +ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) +{ + bool containsLocalTable = false; + bool containsSubquery = false; + + ListCell *rangeTableCell = NULL; + foreach(rangeTableCell, rangeTableList) + { + RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); + + if (rangeTableEntry->rtekind == RTE_SUBQUERY) { + containsSubquery = true; + } + /* we're only interested in tables */ + /* TODO:: What about partitioned tables? */ + if (!(rangeTableEntry->rtekind == RTE_RELATION && + rangeTableEntry->relkind == RELKIND_RELATION)) + { + continue; + } + + if (!IsCitusTable(rangeTableEntry->relid) && rangeTableEntry->relid != resultRelationId) + { + containsLocalTable = true; + } + } + + return containsLocalTable && containsSubquery; +} + /* * WrapFunctionsInSubqueries iterates over all the immediate Range Table Entries * of a query and wraps the functions inside (SELECT * FROM fnc() f) diff --git a/src/backend/distributed/planner/shard_pruning.c b/src/backend/distributed/planner/shard_pruning.c index b7133561d..26b84d9ee 100644 --- a/src/backend/distributed/planner/shard_pruning.c +++ b/src/backend/distributed/planner/shard_pruning.c @@ -254,8 +254,6 @@ static bool IsValidPartitionKeyRestriction(OpExpr *opClause); static void AddPartitionKeyRestrictionToInstance(ClauseWalkerContext *context, OpExpr *opClause, Var *varClause, Const *constantClause); -static bool VarConstOpExprClause(OpExpr *opClause, Var **varClause, - Const **constantClause); static void AddSAOPartitionKeyRestrictionToInstance(ClauseWalkerContext *context, ScalarArrayOpExpr * arrayOperatorExpression); diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index 9f90798da..2f0abb26b 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -589,5 +589,6 @@ extern RangeTblEntry * DerivedRangeTableEntry(MultiNode *multiNode, List *column List *funcColumnTypeMods, List *funcCollations); +extern List* FetchAttributeNumsForRTEFromQuals(Node* quals, Index rteIndex); #endif /* MULTI_PHYSICAL_PLANNER_H */ diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index d6fed178e..d48a20f13 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -63,6 +63,8 @@ extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, List *requiredAttrNumbers); - +extern bool +ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId); +extern bool ContainsTableToBeConvertedToSubquery(List* rangeTableList, Oid resultRelationId); #endif /* RECURSIVE_PLANNING_H */ diff --git a/src/include/distributed/shard_pruning.h b/src/include/distributed/shard_pruning.h index 8f8ca69e7..04176314e 100644 --- a/src/include/distributed/shard_pruning.h +++ b/src/include/distributed/shard_pruning.h @@ -24,4 +24,6 @@ extern List * get_all_actual_clauses(List *restrictinfo_list); extern Const * TransformPartitionRestrictionValue(Var *partitionColumn, Const *restrictionValue, bool missingOk); +bool VarConstOpExprClause(OpExpr *opClause, Var **varClause, Const **constantClause); + #endif /* SHARD_PRUNING_H_ */ diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index be290b200..eac5a5087 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -114,9 +114,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey 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.distributed_table_pkey WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) count --------------------------------------------------------------------- 0 @@ -132,9 +132,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = distributed_table_pkey.key; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey 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.distributed_table_pkey WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_pkey.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_pkey.key))) count --------------------------------------------------------------------- 0 @@ -149,11 +149,141 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +-- it should favor distributed table only if it has equality on the unique column +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key > 10; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key < 10; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.<) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 AND postgres_table.key = 5; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (postgres_table.key OPERATOR(pg_catalog.=) 5)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key > 10; +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20 OR distributed_table_pkey.key = 30; +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 30)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = ( + SELECT count(*) FROM distributed_table_pkey +); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM local_table_join.distributed_table_pkey +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)))))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 5 and distributed_table_pkey.key > 15); +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.key > 15); +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.value = 'notext'); +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 10 and distributed_table_pkey.value = 'notext'); +DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(key); -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (key)) count --------------------------------------------------------------------- 0 @@ -169,9 +299,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON postgres_table.key = distributed_table_windex.key; -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_windex.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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) count --------------------------------------------------------------------- 0 @@ -449,7 +579,157 @@ DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, N DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) -\set VERBOSITY terse +-- currently can't plan subquery-local table join +SELECT count(*) +FROM + (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 +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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT d1.key, d1.value, d1.value_2 FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1) d2 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)) postgres_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +--------------------------------------------------------------------- +SET client_min_messages to ERROR; +SELECT master_add_node('localhost', :master_port, groupId => 0); + master_add_node +--------------------------------------------------------------------- + 30 +(1 row) + +CREATE TABLE citus_local(key int, value text); +SELECT create_citus_local_table('citus_local'); + create_citus_local_table +--------------------------------------------------------------------- + +(1 row) + +SET client_min_messages TO DEBUG1; +-- same for citus local table - distributed table joins +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex USING (value)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- no unique index, citus local table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table USING(key); +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table USING(value); +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table USING (value)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table.key))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table 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.distributed_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.citus_local 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)) distributed_table USING (key)) JOIN local_table_join.postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- update +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table_windex.key = citus_local.key; +DEBUG: Wrapping local relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text 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)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) +UPDATE + citus_local +SET + value = 'test' +FROM + distributed_table_windex +WHERE + distributed_table_windex.key = citus_local.key; +DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.citus_local SET value = 'test'::text FROM (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)) distributed_table_windex WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) +DROP TABLE citus_local; +CONTEXT: SQL statement "SELECT master_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name)" +PL/pgSQL function citus_drop_trigger() line 15 at PERFORM +CONTEXT: SQL statement "SELECT master_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name)" +PL/pgSQL function citus_drop_trigger() line 15 at PERFORM RESET client_min_messages; +SELECT master_remove_node('localhost', :master_port); + master_remove_node +--------------------------------------------------------------------- + +(1 row) + +\set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 5 other objects +NOTICE: drop cascades to 6 other objects diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index be1946533..7805e9dda 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -1,7 +1,6 @@ CREATE SCHEMA local_table_join; SET search_path TO local_table_join; - 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'); @@ -52,6 +51,24 @@ SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = distributed_table_pkey.key; SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; +-- it should favor distributed table only if it has equality on the unique column +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key > 10; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key < 10; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 AND postgres_table.key = 5; + +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key > 10; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20 OR distributed_table_pkey.key = 30; +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = ( + SELECT count(*) FROM distributed_table_pkey +); +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 5 and distributed_table_pkey.key > 15); +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.key > 15); +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.value = 'notext'); +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 10 and distributed_table_pkey.value = 'notext'); -- a unique index on key so dist table should be recursively planned @@ -246,7 +263,61 @@ FROM WHERE postgres_table.key = d1.key AND d1.key = d2.key; +-- currently can't plan subquery-local table join +SELECT count(*) +FROM + (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 +JOIN postgres_table +USING(key); -\set VERBOSITY terse + + +--------------------------------------------------------- + +SET client_min_messages to ERROR; +SELECT master_add_node('localhost', :master_port, groupId => 0); + + +CREATE TABLE citus_local(key int, value text); +SELECT create_citus_local_table('citus_local'); +SET client_min_messages TO DEBUG1; + +-- same for citus local table - distributed table joins +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; + +-- no unique index, citus local table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table USING(key); +SELECT count(*) FROM citus_local JOIN distributed_table USING(value); +SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; +SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; + +SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); + +-- update +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table_windex.key = citus_local.key; + +UPDATE + citus_local +SET + value = 'test' +FROM + distributed_table_windex +WHERE + distributed_table_windex.key = citus_local.key; + +DROP TABLE citus_local; RESET client_min_messages; +SELECT master_remove_node('localhost', :master_port); +\set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; diff --git a/src/test/regress/sql/subqueries_not_supported.sql b/src/test/regress/sql/subqueries_not_supported.sql index a91c9a097..1ece06c34 100644 --- a/src/test/regress/sql/subqueries_not_supported.sql +++ b/src/test/regress/sql/subqueries_not_supported.sql @@ -9,9 +9,9 @@ SET client_min_messages TO DEBUG1; CREATE TABLE users_table_local AS SELECT * FROM users_table; --- we don't support subqueries with local tables when they are not leaf queries +-- TODO:: Move this out of this file SELECT - * + COUNT(*) FROM ( SELECT @@ -23,7 +23,7 @@ FROM RESET client_min_messages; -- we don't support subqueries with local tables when they are not leaf queries -SELECT user_id FROM users_table WHERE user_id IN +SELECT COUNT(user_id) FROM users_table WHERE user_id IN (SELECT user_id FROM From 2ff65f363098841971de6e65fbb9147d97502236 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 25 Nov 2020 20:52:44 +0300 Subject: [PATCH 11/37] Enable partitioned distributed tables in local-dist table joins --- .../planner/local_distributed_join_planner.c | 3 +- .../distributed/planner/recursive_planning.c | 27 ++++++---- src/include/distributed/recursive_planning.h | 1 + .../regress/expected/local_table_join.out | 53 ++++++++++++++++++- src/test/regress/sql/local_table_join.sql | 17 +++++- 5 files changed, 84 insertions(+), 17 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 2ff2257ec..72499a93c 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -340,8 +340,7 @@ CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, rteToSubqueryConverterContext->hasSubqueryRTE = true; } /* we're only interested in tables */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) + if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) { continue; } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 2213f92d5..390209fc0 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1407,9 +1407,7 @@ AllDataLocallyAccessible(List *rangeTableList) // TODO:: check if it has distributed table return false; } - /* we're only interested in tables */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) + if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) { continue; } @@ -1444,6 +1442,18 @@ AllDataLocallyAccessible(List *rangeTableList) return true; } +/* + * SubqueryConvertableRelationForJoin returns true if the given range table entry + * is a relation type that can be converted to a subquery. + */ +bool SubqueryConvertableRelationForJoin(RangeTblEntry* rangeTableEntry) { + if (rangeTableEntry->rtekind != RTE_RELATION) { + return false; + } + return rangeTableEntry->relkind == RELKIND_PARTITIONED_TABLE || + rangeTableEntry->relkind == RELKIND_RELATION; +} + /* * ContainsLocalTableDistributedTableJoin returns true if the input range table list * contains a direct join between local and distributed tables. @@ -1459,10 +1469,7 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) { RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - /* we're only interested in tables */ - /* TODO:: What about partitioned tables? */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) + if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) { continue; } @@ -1500,10 +1507,8 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) if (rangeTableEntry->rtekind == RTE_SUBQUERY) { containsSubquery = true; } - /* we're only interested in tables */ - /* TODO:: What about partitioned tables? */ - if (!(rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind == RELKIND_RELATION)) + + if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) { continue; } diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index d48a20f13..e4b46745f 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -66,5 +66,6 @@ extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, extern bool ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId); extern bool ContainsTableToBeConvertedToSubquery(List* rangeTableList, Oid resultRelationId); +extern bool SubqueryConvertableRelationForJoin(RangeTblEntry* rangeTableEntry); #endif /* RECURSIVE_PLANNING_H */ diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index eac5a5087..95af74534 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -22,7 +22,7 @@ SELECT create_distributed_table('distributed_table_pkey', 'key'); (1 row) -CREATE TABLE distributed_table_windex (key int, value text, value_2 jsonb); +CREATE TABLE distributed_table_windex (key int primary key, value text, value_2 jsonb); SELECT create_distributed_table('distributed_table_windex', 'key'); create_distributed_table --------------------------------------------------------------------- @@ -30,6 +30,15 @@ SELECT create_distributed_table('distributed_table_windex', 'key'); (1 row) CREATE UNIQUE INDEX key_index ON distributed_table_windex (key); +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 (10); +CREATE TABLE distributed_partitioned_table_2 PARTITION OF distributed_partitioned_table FOR VALUES FROM (10) TO (20); +SELECT create_distributed_table('distributed_partitioned_table', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + SET client_min_messages TO DEBUG1; -- the user doesn't allow local / distributed table joinn SET citus.local_table_join_policy TO 'never'; @@ -112,6 +121,34 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) WHERE distributed_partitioned_table.key = 10; +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 (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey 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 @@ -695,6 +732,18 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) + JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; +DEBUG: Wrapping local relation "distributed_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) distributed_partitioned_table JOIN local_table_join.postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- update UPDATE distributed_table_windex @@ -732,4 +781,4 @@ SELECT master_remove_node('localhost', :master_port); \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 6 other objects +NOTICE: drop cascades to 7 other objects diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 7805e9dda..517a529cf 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -10,10 +10,16 @@ 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, value text, value_2 jsonb); +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 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 (10); +CREATE TABLE distributed_partitioned_table_2 PARTITION OF distributed_partitioned_table FOR VALUES FROM (10) TO (20); +SELECT create_distributed_table('distributed_partitioned_table', 'key'); + + SET client_min_messages TO DEBUG1; @@ -33,7 +39,6 @@ SET citus.local_table_join_policy TO 'prefer-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); SELECT count(*) FROM postgres_table JOIN reference_table USING(key); - -- update/delete -- auto tests @@ -46,6 +51,11 @@ SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); SELECT count(*) FROM reference_table JOIN postgres_table USING(key); SELECT count(*) FROM distributed_table JOIN postgres_table 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; +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key); + -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); @@ -297,6 +307,9 @@ SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) + JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; + -- update UPDATE distributed_table_windex From 5693cabc41b81d342b440eac50554eedc1b18001 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Thu, 26 Nov 2020 09:39:54 +0300 Subject: [PATCH 12/37] Not convert an already routable plannable query We should not recursively plan an already routable plannable query. An example of this is (SELECT * FROM local JOIN (SELECT * FROM dist) d1 USING(a)); So we let the recursive planner do all of its work and at the end we convert the final query to to handle unsupported joins. While doing each conversion, we check if it is router plannable, if so we stop. Only consider range table entries that are in jointree If a range table is not in jointree then there is no point in considering that because we are trying to convert range table entries to subqueries for join use case. --- src/backend/distributed/commands/index.c | 11 +- .../distributed/metadata/metadata_cache.c | 15 + .../distributed/operations/node_protocol.c | 1 + .../planner/local_distributed_join_planner.c | 529 ++++++++++++------ .../planner/multi_physical_planner.c | 116 ++-- .../planner/multi_router_planner.c | 95 ++-- .../distributed/planner/recursive_planning.c | 75 ++- .../relation_restriction_equivalence.c | 14 +- src/include/distributed/commands.h | 5 + .../local_distributed_join_planner.h | 5 +- src/include/distributed/metadata_cache.h | 2 + .../distributed/multi_physical_planner.h | 2 +- .../distributed/multi_router_planner.h | 2 + src/include/distributed/recursive_planning.h | 11 +- .../regress/expected/local_table_join.out | 64 ++- src/test/regress/sql/local_table_join.sql | 43 +- 16 files changed, 688 insertions(+), 302 deletions(-) diff --git a/src/backend/distributed/commands/index.c b/src/backend/distributed/commands/index.c index 7a9c5c9ad..cf68b90f6 100644 --- a/src/backend/distributed/commands/index.c +++ b/src/backend/distributed/commands/index.c @@ -249,7 +249,15 @@ CreateIndexStmtGetSchemaId(IndexStmt *createIndexStatement) return namespaceId; } -List* ExecuteFunctionOnEachTableIndex(Oid relationId, IndexProcesor indexProcessor) { + +/* + * ExecuteFunctionOnEachTableIndex executes the given indexProcessor function on each + * index of the given relation. + * It returns a list that is filled by the indexProcessor. + */ +List * +ExecuteFunctionOnEachTableIndex(Oid relationId, IndexProcesor indexProcessor) +{ List *result = NIL; ScanKeyData scanKey[1]; int scanKeyCount = 1; @@ -285,6 +293,7 @@ List* ExecuteFunctionOnEachTableIndex(Oid relationId, IndexProcesor indexProcess return result; } + /* * ExecuteFunctionOnEachTableIndex executes the given pgIndexProcessor function on each * index of the given relation. diff --git a/src/backend/distributed/metadata/metadata_cache.c b/src/backend/distributed/metadata/metadata_cache.c index 1e5ebac6a..83fbad1bc 100644 --- a/src/backend/distributed/metadata/metadata_cache.c +++ b/src/backend/distributed/metadata/metadata_cache.c @@ -293,6 +293,21 @@ EnsureModificationsCanRun(void) } +/* + * IsLocalOrCitusLocalTable returns true if the given relation + * is either a local or citus local table. + */ +bool +IsLocalOrCitusLocalTable(Oid relationId) +{ + if (!IsCitusTable(relationId)) + { + return true; + } + return IsCitusTableType(relationId, CITUS_LOCAL_TABLE); +} + + /* * IsCitusTableType returns true if the given table with relationId * belongs to a citus table that matches the given table type. If cache diff --git a/src/backend/distributed/operations/node_protocol.c b/src/backend/distributed/operations/node_protocol.c index 0eb23f6a5..4a23a5052 100644 --- a/src/backend/distributed/operations/node_protocol.c +++ b/src/backend/distributed/operations/node_protocol.c @@ -729,6 +729,7 @@ GatherIndexAndConstraintDefinitionList(Form_pg_index indexForm, List **indexDDLE } } + /* * IndexImpliedByAConstraint is a helper function to be used while scanning * pg_index. It returns true if the index identified by the given indexForm is diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 72499a93c..680fb7b3a 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -54,212 +54,398 @@ #include "utils/guc.h" #include "utils/lsyscache.h" -typedef struct RTEToSubqueryConverterReference { - RangeTblEntry* rangeTableEntry; +typedef struct RTEToSubqueryConverterReference +{ + RangeTblEntry *rangeTableEntry; Index rteIndex; - List* restrictionList; - List* requiredAttributeNumbers; + List *restrictionList; + List *requiredAttributeNumbers; } RTEToSubqueryConverterReference; -typedef struct RTEToSubqueryConverterContext{ - List* distributedTableList; /* reference or distributed table */ - List* localTableList; - List* citusLocalTableList; +typedef struct RTEToSubqueryConverterContext +{ + List *distributedTableList; /* reference or distributed table */ + List *localTableList; /* local or citus local table */ bool hasSubqueryRTE; }RTEToSubqueryConverterContext; -static bool ShouldConvertLocalTableJoinsToSubqueries(List* rangeTableList, Oid resultRelationId); -static bool HasUniqueFilter(RangeTblEntry* distRTE, List* distRTERestrictionList, List* requiredAttrNumbersForDistRTE); -static bool AutoConvertLocalTableJoinToSubquery(FromExpr* joinTree, - RTEToSubqueryConverterReference* distRTEContext); +static Oid GetResultRelationId(Query *query); +static Oid GetRTEToSubqueryConverterReferenceRelId( + RTEToSubqueryConverterReference *rteToSubqueryConverterReference); +static bool ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, Oid + resultRelationId); +static bool HasUniqueFilter(RangeTblEntry *distRTE, List *distRTERestrictionList, + List *requiredAttrNumbersForDistRTE); +static bool ShouldConvertDistributedTable(FromExpr *joinTree, + RTEToSubqueryConverterReference *distRTEContext); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, RecursivePlanningContext *planningContext); -static RTEToSubqueryConverterContext * CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, - List *rangeTableList); -static void GetAllUniqueIndexes(Form_pg_index indexForm, List** uniqueIndexes); -static RTEToSubqueryConverterReference* - GetNextRTEToConvertToSubquery(FromExpr* joinTree, RTEToSubqueryConverterContext* rteToSubqueryConverterContext, - PlannerRestrictionContext *plannerRestrictionContext, RangeTblEntry* resultRelation); -static void PopFromRTEToSubqueryConverterContext(RTEToSubqueryConverterContext* rteToSubqueryConverterContext, - bool isCitusLocalTable); +static RTEToSubqueryConverterContext * CreateRTEToSubqueryConverterContext( + RecursivePlanningContext *context, + List * + rangeTableList); +static void GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes); +static RTEToSubqueryConverterReference * GetNextRTEToConvertToSubquery(FromExpr *joinTree, + RTEToSubqueryConverterContext + * + rteToSubqueryConverterContext, + PlannerRestrictionContext + * + plannerRestrictionContext, + Oid + resultRelationId); +static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, + List **joinRangeTableEntries); +static void RemoveFromRTEToSubqueryConverterContext( + RTEToSubqueryConverterContext *rteToSubqueryConverterContext, Oid relationId); +static bool FillLocalAndDistributedRTECandidates( + RTEToSubqueryConverterContext *rteToSubqueryConverterContext, + RTEToSubqueryConverterReference ** + localRTECandidate, + RTEToSubqueryConverterReference ** + distributedRTECandidate); + /* - * ConvertLocalTableJoinsToSubqueries gets a query and the planner - * restrictions. As long as there is a join between a local table - * and distributed table, the function wraps one table in a - * subquery (by also pushing the filters on the table down - * to the subquery). - * - * Once this function returns, there are no direct joins between - * local and distributed tables. + * ConvertUnplannableTableJoinsToSubqueries gets a query and the planner + * restrictions. As long as the query is not plannable by router planner, + * it converts either a local or distributed table to a subquery. */ void -ConvertLocalTableJoinsToSubqueries(Query *query, - RecursivePlanningContext *context) +ConvertUnplannableTableJoinsToSubqueries(Query *query, + RecursivePlanningContext *context) { - List *rangeTableList = query->rtable; - RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); - Oid resultRelationId = InvalidOid; - if (resultRelation) { - resultRelationId = resultRelation->relid; - } - if (!ShouldConvertLocalTableJoinsToSubqueries(rangeTableList, resultRelationId)) { + List *rangeTableList = NIL; + GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, + &rangeTableList); + Oid resultRelationId = GetResultRelationId(query); + if (!ShouldConvertLocalTableJoinsToSubqueries(rangeTableList, resultRelationId)) + { return; } - RTEToSubqueryConverterContext* rteToSubqueryConverterContext = CreateRTEToSubqueryConverterContext( - context, rangeTableList); + RTEToSubqueryConverterContext *rteToSubqueryConverterContext = + CreateRTEToSubqueryConverterContext( + context, rangeTableList); - RTEToSubqueryConverterReference* rteToSubqueryConverterReference = - GetNextRTEToConvertToSubquery(query->jointree, rteToSubqueryConverterContext, - context->plannerRestrictionContext, resultRelation); - while (rteToSubqueryConverterReference) + RTEToSubqueryConverterReference *rteToSubqueryConverterReference = + GetNextRTEToConvertToSubquery(query->jointree, rteToSubqueryConverterContext, + context->plannerRestrictionContext, + resultRelationId); + + PlannerRestrictionContext *plannerRestrictionContext = + FilterPlannerRestrictionForQuery(context->plannerRestrictionContext, query); + while (rteToSubqueryConverterReference && !IsRouterPlannable(query, + plannerRestrictionContext)) { - ReplaceRTERelationWithRteSubquery(rteToSubqueryConverterReference->rangeTableEntry, - rteToSubqueryConverterReference->restrictionList, - rteToSubqueryConverterReference->requiredAttributeNumbers); - rteToSubqueryConverterReference = + ReplaceRTERelationWithRteSubquery( + rteToSubqueryConverterReference->rangeTableEntry, + rteToSubqueryConverterReference->restrictionList, + rteToSubqueryConverterReference-> + requiredAttributeNumbers, + context); + RemoveFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext, + rteToSubqueryConverterReference-> + rangeTableEntry->relid); + rteToSubqueryConverterReference = GetNextRTEToConvertToSubquery(query->jointree, rteToSubqueryConverterContext, - context->plannerRestrictionContext, resultRelation); + context->plannerRestrictionContext, + resultRelationId); } } -static RTEToSubqueryConverterReference* - GetNextRTEToConvertToSubquery(FromExpr* joinTree, RTEToSubqueryConverterContext* rteToSubqueryConverterContext, - PlannerRestrictionContext *plannerRestrictionContext, RangeTblEntry* resultRelation) { - RTEToSubqueryConverterReference* localRTECandidate = NULL; - RTEToSubqueryConverterReference* nonLocalRTECandidate = NULL; - bool citusLocalTableChosen = false; +/* + * GetResultRelationId gets the result relation id from query + * if it exists. + */ +static Oid +GetResultRelationId(Query *query) +{ + RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); + Oid resultRelationId = InvalidOid; + if (resultRelation) + { + resultRelationId = resultRelation->relid; + } + return resultRelationId; +} - if (list_length(rteToSubqueryConverterContext->localTableList) > 0) { - localRTECandidate = linitial(rteToSubqueryConverterContext->localTableList); - }else if (list_length(rteToSubqueryConverterContext->citusLocalTableList) > 0) { - localRTECandidate = linitial(rteToSubqueryConverterContext->citusLocalTableList); - citusLocalTableChosen = true; - } - if (localRTECandidate == NULL) { - return NULL; - } - if (list_length(rteToSubqueryConverterContext->distributedTableList) > 0) { - nonLocalRTECandidate = linitial(rteToSubqueryConverterContext->distributedTableList); - } - if (nonLocalRTECandidate == NULL && !rteToSubqueryConverterContext->hasSubqueryRTE) { - return NULL; +/* + * GetRangeTableEntriesFromJoinTree gets the range table entries that are + * on the given join tree. + */ +static void +GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, + List **joinRangeTableEntries) +{ + if (joinNode == NULL) + { + return; } + else if (IsA(joinNode, FromExpr)) + { + FromExpr *fromExpr = (FromExpr *) joinNode; + Node *fromElement; - if (resultRelation) { - if(resultRelation == localRTECandidate->rangeTableEntry) { - rteToSubqueryConverterContext->distributedTableList = list_delete_first( - rteToSubqueryConverterContext->distributedTableList - ); - return nonLocalRTECandidate; + foreach_ptr(fromElement, fromExpr->fromlist) + { + GetRangeTableEntriesFromJoinTree(fromElement, rangeTableList, + joinRangeTableEntries); } - if (resultRelation == nonLocalRTECandidate->rangeTableEntry) { - PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); + } + else if (IsA(joinNode, JoinExpr)) + { + JoinExpr *joinExpr = (JoinExpr *) joinNode; + GetRangeTableEntriesFromJoinTree(joinExpr->larg, rangeTableList, + joinRangeTableEntries); + GetRangeTableEntriesFromJoinTree(joinExpr->rarg, rangeTableList, + joinRangeTableEntries); + } + else if (IsA(joinNode, RangeTblRef)) + { + int rangeTableIndex = ((RangeTblRef *) joinNode)->rtindex; + RangeTblEntry *rte = rt_fetch(rangeTableIndex, rangeTableList); + *joinRangeTableEntries = lappend(*joinRangeTableEntries, rte); + } + else + { + pg_unreachable(); + } +} + + +/* + * GetNextRTEToConvertToSubquery returns the range table entry + * which should be converted to a subquery. It considers the local join policy + * and result relation. + */ +static RTEToSubqueryConverterReference * +GetNextRTEToConvertToSubquery(FromExpr *joinTree, + RTEToSubqueryConverterContext *rteToSubqueryConverterContext, + PlannerRestrictionContext *plannerRestrictionContext, Oid + resultRelationId) +{ + RTEToSubqueryConverterReference *localRTECandidate = NULL; + RTEToSubqueryConverterReference *distributedRTECandidate = NULL; + if (!FillLocalAndDistributedRTECandidates(rteToSubqueryConverterContext, + &localRTECandidate, + &distributedRTECandidate)) + { + return NULL; + } + + if (OidIsValid(resultRelationId)) + { + if (resultRelationId == GetRTEToSubqueryConverterReferenceRelId( + localRTECandidate)) + { + return distributedRTECandidate; + } + if (resultRelationId == GetRTEToSubqueryConverterReferenceRelId( + distributedRTECandidate)) + { return localRTECandidate; } } - if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) { - PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); + if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) + { return localRTECandidate; - }else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) { - if (nonLocalRTECandidate) { - rteToSubqueryConverterContext->distributedTableList = list_delete_first( - rteToSubqueryConverterContext->distributedTableList - ); - return nonLocalRTECandidate; - }else { - PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); - return localRTECandidate; - } - - }else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_AUTO) { - bool shouldConvertNonLocalTable = AutoConvertLocalTableJoinToSubquery(joinTree, nonLocalRTECandidate); - if (shouldConvertNonLocalTable) { - rteToSubqueryConverterContext->distributedTableList = list_delete_first( - rteToSubqueryConverterContext->distributedTableList - ); - return nonLocalRTECandidate; - }else { - PopFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext,citusLocalTableChosen); - return localRTECandidate; - } - }else { - elog(ERROR, "unexpected local table join policy: %d", LocalTableJoinPolicy); } - return NULL; + else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) + { + if (distributedRTECandidate) + { + return distributedRTECandidate; + } + else + { + return localRTECandidate; + } + } + else + { + if (ShouldConvertDistributedTable(joinTree, distributedRTECandidate)) + { + return distributedRTECandidate; + } + else + { + return localRTECandidate; + } + } } -static void PopFromRTEToSubqueryConverterContext(RTEToSubqueryConverterContext* rteToSubqueryConverterContext, - bool isCitusLocalTable) { - if (isCitusLocalTable) { - rteToSubqueryConverterContext->citusLocalTableList = - list_delete_first(rteToSubqueryConverterContext->citusLocalTableList); - }else { - rteToSubqueryConverterContext->localTableList = + +/* + * FillLocalAndDistributedRTECandidates fills the local and distributed RTE candidates. + * It returns true if we should continue converting tables to subqueries. + */ +static bool +FillLocalAndDistributedRTECandidates( + RTEToSubqueryConverterContext *rteToSubqueryConverterContext, + RTEToSubqueryConverterReference **localRTECandidate, + RTEToSubqueryConverterReference ** + distributedRTECandidate) +{ + if (list_length(rteToSubqueryConverterContext->localTableList) > 0) + { + *localRTECandidate = linitial(rteToSubqueryConverterContext->localTableList); + } + if (*localRTECandidate == NULL) + { + return false; + } + + if (list_length(rteToSubqueryConverterContext->distributedTableList) > 0) + { + *distributedRTECandidate = linitial( + rteToSubqueryConverterContext->distributedTableList); + } + return *distributedRTECandidate != NULL || + rteToSubqueryConverterContext->hasSubqueryRTE; +} + + +/* + * GetRTEToSubqueryConverterReferenceRelId returns the underlying relation id + * if it is a valid one. + */ +static Oid +GetRTEToSubqueryConverterReferenceRelId( + RTEToSubqueryConverterReference *rteToSubqueryConverterReference) +{ + if (rteToSubqueryConverterReference && + rteToSubqueryConverterReference->rangeTableEntry) + { + return rteToSubqueryConverterReference->rangeTableEntry->relid; + } + return InvalidOid; +} + + +/* + * RemoveFromRTEToSubqueryConverterContext removes an element from + * the relevant list based on the relation id. + */ +static void +RemoveFromRTEToSubqueryConverterContext( + RTEToSubqueryConverterContext *rteToSubqueryConverterContext, Oid relationId) +{ + if (IsLocalOrCitusLocalTable(relationId)) + { + rteToSubqueryConverterContext->localTableList = list_delete_first(rteToSubqueryConverterContext->localTableList); } + else + { + rteToSubqueryConverterContext->distributedTableList = + list_delete_first(rteToSubqueryConverterContext->distributedTableList); + } } + /* * ShouldConvertLocalTableJoinsToSubqueries returns true if we should * convert local-dist table joins to subqueries. */ -static bool ShouldConvertLocalTableJoinsToSubqueries(List* rangeTableList, Oid resultRelationId) { +static bool +ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, Oid resultRelationId) +{ if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) { /* user doesn't want Citus to enable local table joins */ return false; } - if (!ContainsTableToBeConvertedToSubquery(rangeTableList, resultRelationId)) { + if (!ContainsTableToBeConvertedToSubquery(rangeTableList, resultRelationId)) + { return false; } return true; } -static bool AutoConvertLocalTableJoinToSubquery(FromExpr* joinTree, - RTEToSubqueryConverterReference* rteToSubqueryConverterReference) { - if (rteToSubqueryConverterReference == NULL) { + +/* + * ShouldConvertDistributedTable returns true if we should convert the + * distributed table rte to a subquery. This will be the case if the distributed + * table has a unique index on a column that appears in filter. + */ +static bool +ShouldConvertDistributedTable(FromExpr *joinTree, + RTEToSubqueryConverterReference * + rteToSubqueryConverterReference) +{ + if (rteToSubqueryConverterReference == NULL) + { return false; } - List* distRTEEqualityQuals = - FetchAttributeNumsForRTEFromQuals(joinTree->quals, rteToSubqueryConverterReference->rteIndex); + List *distRTEEqualityQuals = + FetchEqualityAttrNumsForRTEFromQuals(joinTree->quals, + rteToSubqueryConverterReference->rteIndex); - Node* join = NULL; - foreach_ptr(join, joinTree->fromlist) { - if (IsA(join, JoinExpr)) { - JoinExpr* joinExpr = (JoinExpr*) join; - distRTEEqualityQuals = list_concat(distRTEEqualityQuals, - FetchAttributeNumsForRTEFromQuals(joinExpr->quals, rteToSubqueryConverterReference->rteIndex) - ); + Node *join = NULL; + foreach_ptr(join, joinTree->fromlist) + { + if (IsA(join, JoinExpr)) + { + JoinExpr *joinExpr = (JoinExpr *) join; + distRTEEqualityQuals = list_concat(distRTEEqualityQuals, + FetchEqualityAttrNumsForRTEFromQuals( + joinExpr->quals, + rteToSubqueryConverterReference-> + rteIndex) + ); } } - bool hasUniqueFilter = HasUniqueFilter(rteToSubqueryConverterReference->rangeTableEntry, - rteToSubqueryConverterReference->restrictionList, distRTEEqualityQuals); - return hasUniqueFilter; - + bool hasUniqueFilter = HasUniqueFilter( + rteToSubqueryConverterReference->rangeTableEntry, + rteToSubqueryConverterReference-> + restrictionList, distRTEEqualityQuals); + return hasUniqueFilter; } -static bool HasUniqueFilter(RangeTblEntry* distRTE, List* distRTERestrictionList, List* requiredAttrNumbersForDistRTE) { - List* uniqueIndexes = ExecuteFunctionOnEachTableIndex(distRTE->relid, GetAllUniqueIndexes); - int columnNumber = 0; - foreach_int(columnNumber, uniqueIndexes) { - if (list_member_int(requiredAttrNumbersForDistRTE, columnNumber)) { - return true; - } - } - return false; + +/* + * HasUniqueFilter returns true if the given RTE has a unique filter + * on a column, which is a member of the given requiredAttrNumbersForDistRTE. + */ +static bool +HasUniqueFilter(RangeTblEntry *distRTE, List *distRTERestrictionList, + List *requiredAttrNumbersForDistRTE) +{ + List *uniqueIndexes = ExecuteFunctionOnEachTableIndex(distRTE->relid, + GetAllUniqueIndexes); + int columnNumber = 0; + foreach_int(columnNumber, uniqueIndexes) + { + if (list_member_int(requiredAttrNumbersForDistRTE, columnNumber)) + { + return true; + } + } + return false; } -static void GetAllUniqueIndexes(Form_pg_index indexForm, List** uniqueIndexes) { - if (indexForm->indisunique || indexForm->indisprimary) { - for(int i = 0; i < indexForm->indkey.dim1; i++) { - *uniqueIndexes = list_append_unique_int(*uniqueIndexes, indexForm->indkey.values[i]); - } - } + +/* + * GetAllUniqueIndexes adds the given index's column numbers if it is a + * unique index. + * TODO:: if there is a unique index on a multiple column, then we should + * probably return true only if all the columns in the index exist in the filter. + */ +static void +GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes) +{ + if (indexForm->indisunique || indexForm->indisprimary) + { + for (int i = 0; i < indexForm->indkey.dim1; i++) + { + *uniqueIndexes = list_append_unique_int(*uniqueIndexes, + indexForm->indkey.values[i]); + } + } } @@ -287,7 +473,8 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, List *filteredRelationRestrictionList = relationRestrictionContext->relationRestrictionList; - if (list_length(filteredRelationRestrictionList) == 0) { + if (list_length(filteredRelationRestrictionList) == 0) + { return NIL; } RelationRestriction *relationRestriction = @@ -324,46 +511,56 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, * The function also gets a boolean localTable parameter, so the caller * can choose to run the function for only local tables or distributed tables. */ -static RTEToSubqueryConverterContext* +static RTEToSubqueryConverterContext * CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, - List *rangeTableList) + List *rangeTableList) { - - RTEToSubqueryConverterContext* rteToSubqueryConverterContext = palloc0(sizeof(RTEToSubqueryConverterContext)); + RTEToSubqueryConverterContext *rteToSubqueryConverterContext = palloc0( + sizeof(RTEToSubqueryConverterContext)); int rteIndex = 0; - RangeTblEntry* rangeTableEntry = NULL; + RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) { rteIndex++; - if (rangeTableEntry->rtekind == RTE_SUBQUERY) { + if (rangeTableEntry->rtekind == RTE_SUBQUERY) + { rteToSubqueryConverterContext->hasSubqueryRTE = true; } + /* we're only interested in tables */ if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) { continue; } - RTEToSubqueryConverterReference* rteToSubqueryConverter = palloc(sizeof(RTEToSubqueryConverterReference)); + RTEToSubqueryConverterReference *rteToSubqueryConverter = palloc( + sizeof(RTEToSubqueryConverterReference)); rteToSubqueryConverter->rangeTableEntry = rangeTableEntry; rteToSubqueryConverter->rteIndex = rteIndex; - rteToSubqueryConverter->restrictionList = GetRestrictInfoListForRelation(rangeTableEntry, - context->plannerRestrictionContext, 1); - rteToSubqueryConverter->requiredAttributeNumbers = RequiredAttrNumbersForRelation(rangeTableEntry, context); + rteToSubqueryConverter->restrictionList = GetRestrictInfoListForRelation( + rangeTableEntry, + context-> + plannerRestrictionContext, 1); + rteToSubqueryConverter->requiredAttributeNumbers = RequiredAttrNumbersForRelation( + rangeTableEntry, context); - bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE) || - IsCitusTableType(rangeTableEntry->relid, DISTRIBUTED_TABLE); - if (referenceOrDistributedTable) { - rteToSubqueryConverterContext->distributedTableList = - lappend(rteToSubqueryConverterContext->distributedTableList, rteToSubqueryConverter); - }else if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE)) { - rteToSubqueryConverterContext->citusLocalTableList = - lappend(rteToSubqueryConverterContext->citusLocalTableList, rteToSubqueryConverter); - }else { - rteToSubqueryConverterContext->localTableList = - lappend(rteToSubqueryConverterContext->localTableList, rteToSubqueryConverter); + bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, + REFERENCE_TABLE) || + IsCitusTableType(rangeTableEntry->relid, + DISTRIBUTED_TABLE); + if (referenceOrDistributedTable) + { + rteToSubqueryConverterContext->distributedTableList = + lappend(rteToSubqueryConverterContext->distributedTableList, + rteToSubqueryConverter); + } + else + { + rteToSubqueryConverterContext->localTableList = + lappend(rteToSubqueryConverterContext->localTableList, + rteToSubqueryConverter); } } return rteToSubqueryConverterContext; -} \ No newline at end of file +} diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 6e05268f9..0bc31a9f5 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -233,6 +233,9 @@ static StringInfo ColumnTypeArrayString(List *targetEntryList); static bool CoPlacedShardIntervals(ShardInterval *firstInterval, ShardInterval *secondInterval); +static List * FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr, Index rteIndex); +static List * FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr, Index rteIndex); + #if PG_VERSION_NUM >= PG_VERSION_13 static List * GetColumnOriginalIndexes(Oid relationId); #endif @@ -3588,8 +3591,16 @@ NodeIsRangeTblRefReferenceTable(Node *node, List *rangeTableList) return IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE); } -List* FetchAttributeNumsForRTEFromQuals(Node* quals, Index rteIndex) { - List* attributeNums = NIL; + +/* + * FetchEqualityAttrNumsForRTEFromQuals fetches the attribute numbers from quals + * which: + * - has equality operator + * - belongs to rangeTableEntry with rteIndex + */ +List * +FetchEqualityAttrNumsForRTEFromQuals(Node *quals, Index rteIndex) +{ if (quals == NULL) { return NIL; @@ -3597,48 +3608,79 @@ List* FetchAttributeNumsForRTEFromQuals(Node* quals, Index rteIndex) { if (IsA(quals, OpExpr)) { - if (!NodeIsEqualsOpExpr(quals)) - { - return NIL; - } - OpExpr *nextJoinClauseOpExpr = castNode(OpExpr, quals); - - Var* var = NULL; - if (VarConstOpExprClause(nextJoinClauseOpExpr, &var, NULL)) { - attributeNums = lappend_int(attributeNums, var->varattno); - return attributeNums; - } - + return FetchEqualityAttrNumsForRTEOpExpr((OpExpr *) quals, rteIndex); } else if (IsA(quals, BoolExpr)) { - BoolExpr *boolExpr = (BoolExpr *) quals; - - if (boolExpr->boolop != AND_EXPR && boolExpr->boolop != OR_EXPR) { - return attributeNums; - } - - bool hasEquality = true; - Node* arg = NULL; - foreach_ptr(arg, boolExpr->args) - { - List* attributeNumsInSubExpression = FetchAttributeNumsForRTEFromQuals(arg, rteIndex); - if (boolExpr->boolop == AND_EXPR) - { - hasEquality |= list_length(attributeNumsInSubExpression) > 0; - }else if (boolExpr->boolop == OR_EXPR){ - hasEquality &= list_length(attributeNumsInSubExpression) > 0; - } - attributeNums = list_concat(attributeNums, attributeNumsInSubExpression); - - } - if (hasEquality) { - return attributeNums; - } + return FetchEqualityAttrNumsForRTEBoolExpr((BoolExpr *) quals, rteIndex); } return NIL; } + +/* + * FetchEqualityAttrNumsForRTEOpExpr fetches the attribute numbers from opExpr + * which: + * - has equality operator + * - belongs to rangeTableEntry with rteIndex + */ +static List * +FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr, Index rteIndex) +{ + if (!OperatorImplementsEquality(opExpr->opno)) + { + return NIL; + } + + List *attributeNums = NIL; + Var *var = NULL; + if (VarConstOpExprClause(opExpr, &var, NULL) && var->varno == rteIndex) + { + attributeNums = lappend_int(attributeNums, var->varattno); + } + return attributeNums; +} + + +/* + * FetchEqualityAttrNumsForRTEBoolExpr fetches the attribute numbers from boolExpr + * which: + * - has equality operator + * - belongs to rangeTableEntry with rteIndex + */ +static List * +FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr, Index rteIndex) +{ + if (boolExpr->boolop != AND_EXPR && boolExpr->boolop != OR_EXPR) + { + return NIL; + } + + List *attributeNums = NIL; + bool hasEquality = true; + Node *arg = NULL; + foreach_ptr(arg, boolExpr->args) + { + List *attributeNumsInSubExpression = FetchEqualityAttrNumsForRTEFromQuals(arg, + rteIndex); + if (boolExpr->boolop == AND_EXPR) + { + hasEquality |= list_length(attributeNumsInSubExpression) > 0; + } + else if (boolExpr->boolop == OR_EXPR) + { + hasEquality &= list_length(attributeNumsInSubExpression) > 0; + } + attributeNums = list_concat(attributeNums, attributeNumsInSubExpression); + } + if (hasEquality) + { + return attributeNums; + } + return NIL; +} + + /* * JoinSequenceArray walks over the join nodes in the job query and constructs a join * sequence containing an entry for each joined table. The function then returns an diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 6b9858e23..4869ef7cf 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -49,6 +49,7 @@ #include "distributed/reference_table_utils.h" #include "distributed/relation_restriction_equivalence.h" #include "distributed/relay_utility.h" +#include "distributed/recursive_planning.h" #include "distributed/resource_lock.h" #include "distributed/shardinterval_utils.h" #include "distributed/shard_pruning.h" @@ -181,7 +182,6 @@ static void ReorderTaskPlacementsByTaskAssignmentPolicy(Job *job, TaskAssignmentPolicyType taskAssignmentPolicy, List *placementList); -static bool IsLocalOrCitusLocalTable(Oid relationId); /* * CreateRouterPlan attempts to create a router executor plan for the given @@ -295,6 +295,32 @@ CreateSingleTaskRouterSelectPlan(DistributedPlan *distributedPlan, Query *origin } +/* + * IsRouterPlannable returns true if the given query can be planned by + * router planner. + */ +bool +IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionContext) +{ + /* copy the query as the following methods can change the underlying query */ + Query *copyQuery = copyObject(query); + DeferredErrorMessage *deferredErrorMessage = NULL; + if (copyQuery->commandType == CMD_SELECT) + { + deferredErrorMessage = MultiRouterPlannableQuery(copyQuery); + } + if (deferredErrorMessage) + { + return false; + } + + /* TODO:: we might not need this copy*/ + copyQuery = copyObject(query); + RouterJob(copyQuery, plannerRestrictionContext, &deferredErrorMessage); + return deferredErrorMessage == NULL; +} + + /* * ShardIntervalOpExpressions returns a list of OpExprs with exactly two * items in it. The list consists of shard interval ranges with partition columns @@ -511,8 +537,6 @@ IsTidColumn(Node *node) } -#include "distributed/recursive_planning.h" - /* * ModifyPartialQuerySupported implements a subset of what ModifyQuerySupported checks, * that subset being what's necessary to check modifying CTEs for. @@ -522,24 +546,25 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, Oid *distributedTableIdOutput) { DeferredErrorMessage *deferredError = DeferErrorIfModifyView(queryTree); - if (deferredError != NULL) { + if (deferredError != NULL) + { return deferredError; } uint32 rangeTableId = 1; CmdType commandType = queryTree->commandType; - Oid distributedTableId = ModifyQueryResultRelationId(queryTree); - *distributedTableIdOutput = distributedTableId; - if (ContainsTableToBeConvertedToSubquery(queryTree->rtable, distributedTableId)) + Oid resultRelationId = ModifyQueryResultRelationId(queryTree); + *distributedTableIdOutput = resultRelationId; + if (ContainsTableToBeConvertedToSubquery(queryTree->rtable, resultRelationId)) { return deferredError; } Var *partitionColumn = NULL; - if (IsCitusTable(distributedTableId)) + if (IsCitusTable(resultRelationId)) { - partitionColumn = PartitionColumn(distributedTableId, rangeTableId); + partitionColumn = PartitionColumn(resultRelationId, rangeTableId); } deferredError = DeferErrorIfModifyView(queryTree); @@ -633,12 +658,12 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, } } - distributedTableId = ModifyQueryResultRelationId(queryTree); + resultRelationId = ModifyQueryResultRelationId(queryTree); rangeTableId = 1; - if (IsCitusTable(distributedTableId)) + if (IsCitusTable(resultRelationId)) { - partitionColumn = PartitionColumn(distributedTableId, rangeTableId); + partitionColumn = PartitionColumn(resultRelationId, rangeTableId); } commandType = queryTree->commandType; if (commandType == CMD_INSERT || commandType == CMD_UPDATE || @@ -768,18 +793,11 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, /* set it for caller to use when we don't return any errors */ - *distributedTableIdOutput = distributedTableId; + *distributedTableIdOutput = resultRelationId; return NULL; } -static bool IsLocalOrCitusLocalTable(Oid relationId) { - if (!IsCitusTable(relationId)) { - return true; - } - return IsCitusTableType(relationId, CITUS_LOCAL_TABLE); -} - /* * NodeIsFieldStore returns true if given Node is a FieldStore object. @@ -903,7 +921,7 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer List *rangeTableList = NIL; uint32 queryTableCount = 0; CmdType commandType = queryTree->commandType; -bool fastPathRouterQuery = + bool fastPathRouterQuery = plannerRestrictionContext->fastPathRestrictionContext->fastPathRouterQuery; /* @@ -941,6 +959,14 @@ bool fastPathRouterQuery = { ExtractRangeTableEntryWalker((Node *) originalQuery, &rangeTableList); } + RangeTblEntry *resultRte = ExtractResultRelationRTE(queryTree); + Oid resultRelationId = InvalidOid; + if (resultRte) + { + resultRelationId = resultRte->relid; + } + bool containsTableToBeConvertedToSubquery = + ContainsTableToBeConvertedToSubquery(queryTree->rtable, resultRelationId); RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) @@ -965,25 +991,22 @@ bool fastPathRouterQuery = /* for other kinds of relations, check if its distributed */ else { - RangeTblEntry *resultRte = ExtractResultRelationRTE(queryTree); - Oid resultRelationId = InvalidOid; - if (resultRte) { - resultRelationId = resultRte->relid; - } if (IsLocalOrCitusLocalTable(rangeTableEntry->relid) && - ContainsTableToBeConvertedToSubquery(queryTree->rtable, resultRelationId) - ) - { + containsTableToBeConvertedToSubquery) + { StringInfo errorMessage = makeStringInfo(); char *relationName = get_rel_name(rangeTableEntry->relid); - if (IsCitusTable(rangeTableEntry->relid)) { - appendStringInfo(errorMessage, "citus local table %s cannot be used in this join", - relationName); - }else { - appendStringInfo(errorMessage, "relation %s is not distributed", - relationName); + if (IsCitusTable(rangeTableEntry->relid)) + { + appendStringInfo(errorMessage, + "citus local table %s cannot be joined with these distributed tables", + relationName); + } + else + { + appendStringInfo(errorMessage, "relation %s is not distributed", + relationName); } - return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, errorMessage->data, NULL, NULL); } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 390209fc0..f1c821690 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -163,14 +163,14 @@ static bool ShouldRecursivelyPlanSubquery(Query *subquery, static bool AllDistributionKeysInSubqueryAreEqual(Query *subquery, PlannerRestrictionContext * restrictionContext); -static bool AllDataLocallyAccessible(List *rangeTableList); +static bool AllDataLocallyAccessible(List *rangeTableList); static bool ShouldRecursivelyPlanSetOperation(Query *query, RecursivePlanningContext *context); +static void RecursivelyPlanSubquery(Query *subquery, + RecursivePlanningContext *planningContext); static void RecursivelyPlanSetOperations(Query *query, Node *node, RecursivePlanningContext *context); static bool IsLocalTableRteOrMatView(Node *node); -static void RecursivelyPlanSubquery(Query *subquery, - RecursivePlanningContext *planningContext); static DistributedSubPlan * CreateDistributedSubPlan(uint32 subPlanId, Query *subPlanQuery); static bool CteReferenceListWalker(Node *node, CteReferenceWalkerContext *context); @@ -290,12 +290,6 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context /* make sure function calls in joins are executed in the coordinator */ WrapFunctionsInSubqueries(query); - /* - * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", so we - * recursively plan one side of the join so that the logical planner can plan. - */ - ConvertLocalTableJoinsToSubqueries(query, context); - /* descend into subqueries */ query_tree_walker(query, RecursivelyPlanSubqueryWalker, context, 0); @@ -346,6 +340,13 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context RecursivelyPlanNonColocatedSubqueries(query, context); } + /* + * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or + * a query with local table/citus local table and subquery. We convert local/citus local + * tables to a subquery until they can be planned + */ + ConvertUnplannableTableJoinsToSubqueries(query, context); + return NULL; } @@ -1346,13 +1347,15 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) return false; } + /* * ReplaceRTERelationWithRteSubquery replaces the input rte relation target entry * with a subquery. The function also pushes down the filters to the subquery. */ void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, - List *requiredAttrNumbers) + List *requiredAttrNumbers, + RecursivePlanningContext *context) { Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); Expr *andedBoundExpressions = make_ands_explicit(restrictionList); @@ -1365,7 +1368,6 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict rangeTableEntry->rtekind = RTE_SUBQUERY; rangeTableEntry->subquery = subquery; - /* * If the relation is inherited, it'll still be inherited as * we've copied it earlier. This is to prevent the newly created @@ -1383,16 +1385,26 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict get_rel_name(rangeTableEntry->relid), ApplyLogRedaction(subqueryString->data)))); } + RecursivelyPlanSubquery(rangeTableEntry->subquery, context); } -bool ContainsTableToBeConvertedToSubquery(List* rangeTableList, Oid resultRelationId) { - if (AllDataLocallyAccessible(rangeTableList)) { + +/* + * ContainsTableToBeConvertedToSubquery checks if the given range table list contains + * any table that should be converted to a subquery, which otherwise is not plannable. + */ +bool +ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) +{ + if (AllDataLocallyAccessible(rangeTableList)) + { return false; } - return ContainsLocalTableDistributedTableJoin(rangeTableList) || - ContainsLocalTableSubqueryJoin(rangeTableList, resultRelationId); + return ContainsLocalTableDistributedTableJoin(rangeTableList) || + ContainsLocalTableSubqueryJoin(rangeTableList, resultRelationId); } + /* * AllDataLocallyAccessible return true if all data for the relations in the * rangeTableList is locally accessible. @@ -1400,11 +1412,12 @@ bool ContainsTableToBeConvertedToSubquery(List* rangeTableList, Oid resultRelati static bool AllDataLocallyAccessible(List *rangeTableList) { - RangeTblEntry* rangeTableEntry = NULL; + RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) { - if (rangeTableEntry->rtekind == RTE_SUBQUERY) { - // TODO:: check if it has distributed table + if (rangeTableEntry->rtekind == RTE_SUBQUERY) + { + /* TODO:: check if it has distributed table */ return false; } if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) @@ -1442,18 +1455,23 @@ AllDataLocallyAccessible(List *rangeTableList) return true; } + /* * SubqueryConvertableRelationForJoin returns true if the given range table entry * is a relation type that can be converted to a subquery. */ -bool SubqueryConvertableRelationForJoin(RangeTblEntry* rangeTableEntry) { - if (rangeTableEntry->rtekind != RTE_RELATION) { +bool +SubqueryConvertableRelationForJoin(RangeTblEntry *rangeTableEntry) +{ + if (rangeTableEntry->rtekind != RTE_RELATION) + { return false; } return rangeTableEntry->relkind == RELKIND_PARTITIONED_TABLE || - rangeTableEntry->relkind == RELKIND_RELATION; + rangeTableEntry->relkind == RELKIND_RELATION; } + /* * ContainsLocalTableDistributedTableJoin returns true if the input range table list * contains a direct join between local and distributed tables. @@ -1474,11 +1492,13 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) continue; } - if (IsCitusTableType(rangeTableEntry->relid, DISTRIBUTED_TABLE) || IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE)) + if (IsCitusTableType(rangeTableEntry->relid, DISTRIBUTED_TABLE) || + IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE)) { containsDistributedTable = true; } - else if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE) || !IsCitusTable(rangeTableEntry->relid)) + else if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE) || + !IsCitusTable(rangeTableEntry->relid)) { /* we consider citus local tables as local table */ containsLocalTable = true; @@ -1504,7 +1524,8 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) { RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - if (rangeTableEntry->rtekind == RTE_SUBQUERY) { + if (rangeTableEntry->rtekind == RTE_SUBQUERY) + { containsSubquery = true; } @@ -1513,7 +1534,8 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) continue; } - if (!IsCitusTable(rangeTableEntry->relid) && rangeTableEntry->relid != resultRelationId) + if (!IsCitusTable(rangeTableEntry->relid) && rangeTableEntry->relid != + resultRelationId) { containsLocalTable = true; } @@ -1522,6 +1544,7 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) return containsLocalTable && containsSubquery; } + /* * WrapFunctionsInSubqueries iterates over all the immediate Range Table Entries * of a query and wraps the functions inside (SELECT * FROM fnc() f) @@ -1645,7 +1668,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) subquery->targetList = lappend(subquery->targetList, targetEntry); } } - /* * If tupleDesc is NULL we have 2 different cases: * @@ -1695,7 +1717,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) columnType = list_nth_oid(rangeTblFunction->funccoltypes, targetColumnIndex); } - /* use the types in the function definition otherwise */ else { diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index e138d9389..a744e80ff 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -1818,8 +1818,8 @@ FilterPlannerRestrictionForQuery(PlannerRestrictionContext *plannerRestrictionCo /* allocate the filtered planner restriction context and set all the fields */ PlannerRestrictionContext *filteredPlannerRestrictionContext = palloc0( sizeof(PlannerRestrictionContext)); - filteredPlannerRestrictionContext->fastPathRestrictionContext = - palloc0(sizeof(FastPathRestrictionContext)); + filteredPlannerRestrictionContext->fastPathRestrictionContext = palloc0( + sizeof(FastPathRestrictionContext)); filteredPlannerRestrictionContext->memoryContext = plannerRestrictionContext->memoryContext; @@ -1882,10 +1882,9 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, } List *restrictExprList = NIL; - ListCell *restrictCell = NULL; - foreach(restrictCell, baseRestrictInfo) + RestrictInfo *restrictInfo = NULL; + foreach_ptr(restrictInfo, baseRestrictInfo) { - RestrictInfo *restrictInfo = (RestrictInfo *) lfirst(restrictCell); Expr *restrictionClause = restrictInfo->clause; /* we cannot process Params beacuse they are not known at this point */ @@ -1912,10 +1911,9 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, Expr *copyOfRestrictClause = (Expr *) copyObject((Node *) restrictionClause); List *varClauses = pull_var_clause_default((Node *) copyOfRestrictClause); ListCell *varClauseCell = NULL; - foreach(varClauseCell, varClauses) + Var *column = NULL; + foreach_ptr(column, varClauses) { - Var *column = (Var *) lfirst(varClauseCell); - column->varno = rteIndex; column->varnosyn = rteIndex; } diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index 3461e2246..e24b47757 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -186,8 +186,13 @@ extern List * PostprocessIndexStmt(Node *node, const char *queryString); extern void ErrorIfUnsupportedAlterIndexStmt(AlterTableStmt *alterTableStatement); extern void MarkIndexValid(IndexStmt *indexStmt); +<<<<<<< HEAD extern List * ExecuteFunctionOnEachTableIndex(Oid relationId, PGIndexProcessor pgIndexProcessor); +======= +extern List * ExecuteFunctionOnEachTableIndex(Oid relationId, IndexProcesor + indexProcessor); +>>>>>>> Increase readability of the current structure /* objectaddress.c - forward declarations */ extern ObjectAddress CreateExtensionStmtObjectAddress(Node *stmt, bool missing_ok); diff --git a/src/include/distributed/local_distributed_join_planner.h b/src/include/distributed/local_distributed_join_planner.h index 85d15b4ea..1fc7269a6 100644 --- a/src/include/distributed/local_distributed_join_planner.h +++ b/src/include/distributed/local_distributed_join_planner.h @@ -17,8 +17,7 @@ #include "distributed/recursive_planning.h" -extern void -ConvertLocalTableJoinsToSubqueries(Query *query, - RecursivePlanningContext *context); +extern void ConvertUnplannableTableJoinsToSubqueries(Query *query, + RecursivePlanningContext *context); #endif /* LOCAL_DISTRIBUTED_JOIN_PLANNER_H */ diff --git a/src/include/distributed/metadata_cache.h b/src/include/distributed/metadata_cache.h index 7303e55fe..50d9bf251 100644 --- a/src/include/distributed/metadata_cache.h +++ b/src/include/distributed/metadata_cache.h @@ -134,6 +134,8 @@ typedef enum ANY_CITUS_TABLE_TYPE } CitusTableType; + +extern bool IsLocalOrCitusLocalTable(Oid relationId); extern bool IsCitusTableType(Oid relationId, CitusTableType tableType); extern bool IsCitusTableTypeCacheEntry(CitusTableCacheEntry *tableEtnry, CitusTableType tableType); diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index 2f0abb26b..24e60facd 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -589,6 +589,6 @@ extern RangeTblEntry * DerivedRangeTableEntry(MultiNode *multiNode, List *column List *funcColumnTypeMods, List *funcCollations); -extern List* FetchAttributeNumsForRTEFromQuals(Node* quals, Index rteIndex); +extern List * FetchEqualityAttrNumsForRTEFromQuals(Node *quals, Index rteIndex); #endif /* MULTI_PHYSICAL_PLANNER_H */ diff --git a/src/include/distributed/multi_router_planner.h b/src/include/distributed/multi_router_planner.h index 18278bda5..7dff1015c 100644 --- a/src/include/distributed/multi_router_planner.h +++ b/src/include/distributed/multi_router_planner.h @@ -85,6 +85,8 @@ extern List * TargetShardIntervalForFastPathQuery(Query *query, extern void GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, List *placementList, uint64 shardId); +extern bool IsRouterPlannable(Query *query, + PlannerRestrictionContext *plannerRestrictionContext); /* * FastPathPlanner is a subset of router planner, that's why we prefer to diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index e4b46745f..6dd146482 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -62,10 +62,11 @@ extern bool GeneratingSubplans(void); extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, - List *requiredAttrNumbers); -extern bool -ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId); -extern bool ContainsTableToBeConvertedToSubquery(List* rangeTableList, Oid resultRelationId); -extern bool SubqueryConvertableRelationForJoin(RangeTblEntry* rangeTableEntry); + List *requiredAttrNumbers, + RecursivePlanningContext *context); +extern bool ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId); +extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid + resultRelationId); +extern bool SubqueryConvertableRelationForJoin(RangeTblEntry *rangeTableEntry); #endif /* RECURSIVE_PLANNING_H */ diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 95af74534..2dacb8db8 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -271,8 +271,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = ( SELECT count(*) FROM distributed_table_pkey ); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM local_table_join.distributed_table_pkey +DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)))))) count @@ -316,6 +316,34 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = 10; +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 (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table) d1 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- since this is already router plannable, we don't recursively plan the postgres table +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table LIMIT 1) d1 USING(key); +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table LIMIT 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) d1 USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_windex 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 @@ -395,8 +423,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- only local tables are recursively planned SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 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 p1 WHERE true OFFSET 0 -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 p2 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.postgres_table p1 WHERE true OFFSET 0 +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 p2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) count @@ -411,8 +439,8 @@ FROM WHERE d1.value = '1'; 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 p1 WHERE true OFFSET 0 -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 p2 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.postgres_table p1 WHERE true OFFSET 0 +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 p2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) count @@ -429,8 +457,8 @@ FROM WHERE d1.key = 1; 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 p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -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 p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +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 p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) count @@ -586,10 +614,30 @@ FROM WHERE distributed_table.key = p1.key AND p1.key = p2.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 p1 WHERE true OFFSET 0 -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 p2 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.postgres_table p1 WHERE true OFFSET 0 +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 p2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table) d1 +WHERE + d1.key = postgres_table.key; +ERROR: relation postgres_table is not distributed +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table LIMIT 1) d1 +WHERE + d1.key = postgres_table.key; +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table LIMIT 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1 WHERE (d1.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE distributed_table SET @@ -612,8 +660,8 @@ FROM WHERE postgres_table.key = d1.key AND d1.key = d2.key; DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 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.distributed_table d1 WHERE true OFFSET 0 +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) -- currently can't plan subquery-local table join @@ -723,8 +771,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 -DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table 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.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.citus_local 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)) distributed_table USING (key)) JOIN local_table_join.postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) reference_table USING (key)) count @@ -735,8 +783,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; DEBUG: Wrapping local relation "distributed_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 -DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) distributed_partitioned_table JOIN local_table_join.postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) count diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 517a529cf..0fb65d824 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -45,7 +45,7 @@ SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -- switch back to the default policy, which is auto SET citus.local_table_join_policy to 'auto'; --- on the auto mode, the local tables should be recursively planned +-- on the auto mode, the local tables should be recursively planned -- unless a unique index exists in a column for distributed table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); SELECT count(*) FROM reference_table JOIN postgres_table USING(key); @@ -80,6 +80,12 @@ SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_t SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.value = 'notext'); SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 10 and distributed_table_pkey.value = 'notext'); +SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = 10; + + +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table) d1 USING(key); +-- since this is already router plannable, we don't recursively plan the postgres table +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table LIMIT 1) d1 USING(key); -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(key); @@ -93,7 +99,7 @@ SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE dist SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; --- if both local and distributed tables have a filter, we prefer local unless distributed table has unique indexes on any equality filter +-- if both local and distributed tables have a filter, we prefer local unless distributed table has unique indexes on any equality filter SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; @@ -158,9 +164,9 @@ SET FROM postgres_table WHERE - distributed_table_windex.key = postgres_table.key; + distributed_table_windex.key = postgres_table.key; --- in case of update/delete we always recursively plan +-- in case of update/delete we always recursively plan -- the tables other than target table no matter what the policy is SET citus.local_table_join_policy TO 'prefer-local'; @@ -200,7 +206,7 @@ SET FROM postgres_table WHERE - distributed_table_windex.key = postgres_table.key; + distributed_table_windex.key = postgres_table.key; SET citus.local_table_join_policy TO 'prefer-distributed'; @@ -240,7 +246,7 @@ SET FROM postgres_table WHERE - distributed_table_windex.key = postgres_table.key; + distributed_table_windex.key = postgres_table.key; -- modifications with multiple tables UPDATE @@ -252,6 +258,23 @@ FROM WHERE distributed_table.key = p1.key AND p1.key = p2.key; +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table) d1 +WHERE + d1.key = postgres_table.key; + +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table LIMIT 1) d1 +WHERE + d1.key = postgres_table.key; UPDATE distributed_table @@ -274,8 +297,8 @@ WHERE postgres_table.key = d1.key AND d1.key = d2.key; -- currently can't plan subquery-local table join -SELECT count(*) -FROM +SELECT count(*) +FROM (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 JOIN postgres_table USING(key); @@ -318,7 +341,7 @@ SET FROM citus_local WHERE - distributed_table_windex.key = citus_local.key; + distributed_table_windex.key = citus_local.key; UPDATE citus_local @@ -327,7 +350,7 @@ SET FROM distributed_table_windex WHERE - distributed_table_windex.key = citus_local.key; + distributed_table_windex.key = citus_local.key; DROP TABLE citus_local; RESET client_min_messages; From eebcd995b3dc75470d55c086eaba2f09528c834e Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Fri, 27 Nov 2020 19:02:51 +0300 Subject: [PATCH 13/37] Add some more tests --- .../planner/local_distributed_join_planner.c | 182 +++++++++--------- .../planner/multi_router_planner.c | 96 +-------- .../distributed/planner/recursive_planning.c | 22 ++- .../relation_restriction_equivalence.c | 1 - .../distributed/planner/shard_pruning.c | 2 +- src/include/distributed/recursive_planning.h | 2 +- .../regress/expected/local_table_join.out | 127 +++++++++++- src/test/regress/sql/local_table_join.sql | 30 +++ 8 files changed, 256 insertions(+), 206 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 680fb7b3a..d9535d1c6 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -54,55 +54,55 @@ #include "utils/guc.h" #include "utils/lsyscache.h" -typedef struct RTEToSubqueryConverterReference +typedef struct RangeTableEntryDetails { RangeTblEntry *rangeTableEntry; Index rteIndex; List *restrictionList; List *requiredAttributeNumbers; -} RTEToSubqueryConverterReference; +} RangeTableEntryDetails; -typedef struct RTEToSubqueryConverterContext +typedef struct ConversionCandidates { List *distributedTableList; /* reference or distributed table */ List *localTableList; /* local or citus local table */ bool hasSubqueryRTE; -}RTEToSubqueryConverterContext; +}ConversionCandidates; static Oid GetResultRelationId(Query *query); static Oid GetRTEToSubqueryConverterReferenceRelId( - RTEToSubqueryConverterReference *rteToSubqueryConverterReference); + RangeTableEntryDetails *rangeTableEntryDetails); static bool ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, Oid resultRelationId); static bool HasUniqueFilter(RangeTblEntry *distRTE, List *distRTERestrictionList, List *requiredAttrNumbersForDistRTE); static bool ShouldConvertDistributedTable(FromExpr *joinTree, - RTEToSubqueryConverterReference *distRTEContext); + RangeTableEntryDetails *distRTEContext); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, RecursivePlanningContext *planningContext); -static RTEToSubqueryConverterContext * CreateRTEToSubqueryConverterContext( +static ConversionCandidates * CreateConversionCandidates( RecursivePlanningContext *context, List * rangeTableList); static void GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes); -static RTEToSubqueryConverterReference * GetNextRTEToConvertToSubquery(FromExpr *joinTree, - RTEToSubqueryConverterContext - * - rteToSubqueryConverterContext, - PlannerRestrictionContext - * - plannerRestrictionContext, - Oid - resultRelationId); +static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree, + ConversionCandidates + * + conversionCandidates, + PlannerRestrictionContext + * + plannerRestrictionContext, + Oid + resultRelationId); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, List **joinRangeTableEntries); -static void RemoveFromRTEToSubqueryConverterContext( - RTEToSubqueryConverterContext *rteToSubqueryConverterContext, Oid relationId); +static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid + relationId); static bool FillLocalAndDistributedRTECandidates( - RTEToSubqueryConverterContext *rteToSubqueryConverterContext, - RTEToSubqueryConverterReference ** + ConversionCandidates *conversionCandidates, + RangeTableEntryDetails ** localRTECandidate, - RTEToSubqueryConverterReference ** + RangeTableEntryDetails ** distributedRTECandidate); /* @@ -123,31 +123,31 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, return; } - RTEToSubqueryConverterContext *rteToSubqueryConverterContext = - CreateRTEToSubqueryConverterContext( + ConversionCandidates *conversionCandidates = + CreateConversionCandidates( context, rangeTableList); - RTEToSubqueryConverterReference *rteToSubqueryConverterReference = - GetNextRTEToConvertToSubquery(query->jointree, rteToSubqueryConverterContext, + RangeTableEntryDetails *rangeTableEntryDetails = + GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, context->plannerRestrictionContext, resultRelationId); PlannerRestrictionContext *plannerRestrictionContext = FilterPlannerRestrictionForQuery(context->plannerRestrictionContext, query); - while (rteToSubqueryConverterReference && !IsRouterPlannable(query, - plannerRestrictionContext)) + while (rangeTableEntryDetails && !IsRouterPlannable(query, + plannerRestrictionContext)) { ReplaceRTERelationWithRteSubquery( - rteToSubqueryConverterReference->rangeTableEntry, - rteToSubqueryConverterReference->restrictionList, - rteToSubqueryConverterReference-> + rangeTableEntryDetails->rangeTableEntry, + rangeTableEntryDetails->restrictionList, + rangeTableEntryDetails-> requiredAttributeNumbers, context); - RemoveFromRTEToSubqueryConverterContext(rteToSubqueryConverterContext, - rteToSubqueryConverterReference-> - rangeTableEntry->relid); - rteToSubqueryConverterReference = - GetNextRTEToConvertToSubquery(query->jointree, rteToSubqueryConverterContext, + RemoveFromConversionCandidates(conversionCandidates, + rangeTableEntryDetails-> + rangeTableEntry->relid); + rangeTableEntryDetails = + GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, context->plannerRestrictionContext, resultRelationId); } @@ -220,15 +220,15 @@ GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, * which should be converted to a subquery. It considers the local join policy * and result relation. */ -static RTEToSubqueryConverterReference * +static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree, - RTEToSubqueryConverterContext *rteToSubqueryConverterContext, + ConversionCandidates *conversionCandidates, PlannerRestrictionContext *plannerRestrictionContext, Oid resultRelationId) { - RTEToSubqueryConverterReference *localRTECandidate = NULL; - RTEToSubqueryConverterReference *distributedRTECandidate = NULL; - if (!FillLocalAndDistributedRTECandidates(rteToSubqueryConverterContext, + RangeTableEntryDetails *localRTECandidate = NULL; + RangeTableEntryDetails *distributedRTECandidate = NULL; + if (!FillLocalAndDistributedRTECandidates(conversionCandidates, &localRTECandidate, &distributedRTECandidate)) { @@ -283,28 +283,27 @@ GetNextRTEToConvertToSubquery(FromExpr *joinTree, * It returns true if we should continue converting tables to subqueries. */ static bool -FillLocalAndDistributedRTECandidates( - RTEToSubqueryConverterContext *rteToSubqueryConverterContext, - RTEToSubqueryConverterReference **localRTECandidate, - RTEToSubqueryConverterReference ** - distributedRTECandidate) +FillLocalAndDistributedRTECandidates(ConversionCandidates *conversionCandidates, + RangeTableEntryDetails **localRTECandidate, + RangeTableEntryDetails ** + distributedRTECandidate) { - if (list_length(rteToSubqueryConverterContext->localTableList) > 0) + if (list_length(conversionCandidates->localTableList) > 0) { - *localRTECandidate = linitial(rteToSubqueryConverterContext->localTableList); + *localRTECandidate = linitial(conversionCandidates->localTableList); } if (*localRTECandidate == NULL) { return false; } - if (list_length(rteToSubqueryConverterContext->distributedTableList) > 0) + if (list_length(conversionCandidates->distributedTableList) > 0) { *distributedRTECandidate = linitial( - rteToSubqueryConverterContext->distributedTableList); + conversionCandidates->distributedTableList); } return *distributedRTECandidate != NULL || - rteToSubqueryConverterContext->hasSubqueryRTE; + conversionCandidates->hasSubqueryRTE; } @@ -313,35 +312,33 @@ FillLocalAndDistributedRTECandidates( * if it is a valid one. */ static Oid -GetRTEToSubqueryConverterReferenceRelId( - RTEToSubqueryConverterReference *rteToSubqueryConverterReference) +GetRTEToSubqueryConverterReferenceRelId(RangeTableEntryDetails *rangeTableEntryDetails) { - if (rteToSubqueryConverterReference && - rteToSubqueryConverterReference->rangeTableEntry) + if (rangeTableEntryDetails && + rangeTableEntryDetails->rangeTableEntry) { - return rteToSubqueryConverterReference->rangeTableEntry->relid; + return rangeTableEntryDetails->rangeTableEntry->relid; } return InvalidOid; } /* - * RemoveFromRTEToSubqueryConverterContext removes an element from + * RemoveFromConversionCandidates removes an element from * the relevant list based on the relation id. */ static void -RemoveFromRTEToSubqueryConverterContext( - RTEToSubqueryConverterContext *rteToSubqueryConverterContext, Oid relationId) +RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid relationId) { if (IsLocalOrCitusLocalTable(relationId)) { - rteToSubqueryConverterContext->localTableList = - list_delete_first(rteToSubqueryConverterContext->localTableList); + conversionCandidates->localTableList = + list_delete_first(conversionCandidates->localTableList); } else { - rteToSubqueryConverterContext->distributedTableList = - list_delete_first(rteToSubqueryConverterContext->distributedTableList); + conversionCandidates->distributedTableList = + list_delete_first(conversionCandidates->distributedTableList); } } @@ -373,16 +370,16 @@ ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, Oid resultRelatio */ static bool ShouldConvertDistributedTable(FromExpr *joinTree, - RTEToSubqueryConverterReference * - rteToSubqueryConverterReference) + RangeTableEntryDetails * + rangeTableEntryDetails) { - if (rteToSubqueryConverterReference == NULL) + if (rangeTableEntryDetails == NULL) { return false; } List *distRTEEqualityQuals = FetchEqualityAttrNumsForRTEFromQuals(joinTree->quals, - rteToSubqueryConverterReference->rteIndex); + rangeTableEntryDetails->rteIndex); Node *join = NULL; foreach_ptr(join, joinTree->fromlist) @@ -393,15 +390,15 @@ ShouldConvertDistributedTable(FromExpr *joinTree, distRTEEqualityQuals = list_concat(distRTEEqualityQuals, FetchEqualityAttrNumsForRTEFromQuals( joinExpr->quals, - rteToSubqueryConverterReference-> + rangeTableEntryDetails-> rteIndex) ); } } bool hasUniqueFilter = HasUniqueFilter( - rteToSubqueryConverterReference->rangeTableEntry, - rteToSubqueryConverterReference-> + rangeTableEntryDetails->rangeTableEntry, + rangeTableEntryDetails-> restrictionList, distRTEEqualityQuals); return hasUniqueFilter; } @@ -505,18 +502,15 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, /* - * CreateRTEToSubqueryConverterContext returns a range table entry which has the most filters - * on it along with the restrictions (e.g., fills **restrictionList). - * - * The function also gets a boolean localTable parameter, so the caller - * can choose to run the function for only local tables or distributed tables. + * CreateConversionCandidates creates the conversion candidates that might + * be converted to a subquery so that citus planners can work. */ -static RTEToSubqueryConverterContext * -CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, - List *rangeTableList) +static ConversionCandidates * +CreateConversionCandidates(RecursivePlanningContext *context, + List *rangeTableList) { - RTEToSubqueryConverterContext *rteToSubqueryConverterContext = palloc0( - sizeof(RTEToSubqueryConverterContext)); + ConversionCandidates *conversionCandidates = palloc0( + sizeof(ConversionCandidates)); int rteIndex = 0; RangeTblEntry *rangeTableEntry = NULL; @@ -525,24 +519,24 @@ CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, rteIndex++; if (rangeTableEntry->rtekind == RTE_SUBQUERY) { - rteToSubqueryConverterContext->hasSubqueryRTE = true; + conversionCandidates->hasSubqueryRTE = true; } /* we're only interested in tables */ - if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) + if (!IsRecursivelyPlannableRelation(rangeTableEntry)) { continue; } - RTEToSubqueryConverterReference *rteToSubqueryConverter = palloc( - sizeof(RTEToSubqueryConverterReference)); - rteToSubqueryConverter->rangeTableEntry = rangeTableEntry; - rteToSubqueryConverter->rteIndex = rteIndex; - rteToSubqueryConverter->restrictionList = GetRestrictInfoListForRelation( + RangeTableEntryDetails *rangeTableEntryDetails = palloc0( + sizeof(RangeTableEntryDetails)); + rangeTableEntryDetails->rangeTableEntry = rangeTableEntry; + rangeTableEntryDetails->rteIndex = rteIndex; + rangeTableEntryDetails->restrictionList = GetRestrictInfoListForRelation( rangeTableEntry, context-> plannerRestrictionContext, 1); - rteToSubqueryConverter->requiredAttributeNumbers = RequiredAttrNumbersForRelation( + rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation( rangeTableEntry, context); bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, @@ -551,16 +545,16 @@ CreateRTEToSubqueryConverterContext(RecursivePlanningContext *context, DISTRIBUTED_TABLE); if (referenceOrDistributedTable) { - rteToSubqueryConverterContext->distributedTableList = - lappend(rteToSubqueryConverterContext->distributedTableList, - rteToSubqueryConverter); + conversionCandidates->distributedTableList = + lappend(conversionCandidates->distributedTableList, + rangeTableEntryDetails); } else { - rteToSubqueryConverterContext->localTableList = - lappend(rteToSubqueryConverterContext->localTableList, - rteToSubqueryConverter); + conversionCandidates->localTableList = + lappend(conversionCandidates->localTableList, + rangeTableEntryDetails); } } - return rteToSubqueryConverterContext; + return conversionCandidates; } diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 4869ef7cf..c8d71619e 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -132,12 +132,6 @@ static DeferredErrorMessage * ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, Oid *distributedTableId); static bool NodeIsFieldStore(Node *node); -static DeferredErrorMessage * DeferErrorIfUnsupportedModifyQueryWithLocalTable( - Query *query); -static DeferredErrorMessage * DeferErrorIfUnsupportedModifyQueryWithCitusLocalTable( - RTEListProperties *rteListProperties, Oid targetRelationId); -static DeferredErrorMessage * DeferErrorIfUnsupportedModifyQueryWithPostgresLocalTable( - RTEListProperties *rteListProperties, Oid targetRelationId); static DeferredErrorMessage * MultiShardUpdateDeleteSupported(Query *originalQuery, PlannerRestrictionContext * plannerRestrictionContext); @@ -307,7 +301,8 @@ IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionCon DeferredErrorMessage *deferredErrorMessage = NULL; if (copyQuery->commandType == CMD_SELECT) { - deferredErrorMessage = MultiRouterPlannableQuery(copyQuery); + deferredErrorMessage = DeferErrorIfUnsupportedRouterPlannableSelectQuery( + copyQuery); } if (deferredErrorMessage) { @@ -809,93 +804,6 @@ NodeIsFieldStore(Node *node) } -/* - * DeferErrorIfUnsupportedModifyQueryWithLocalTable returns DeferredErrorMessage - * for unsupported modify queries that cannot be planned by router planner due to - * unsupported usage of postgres local or citus local tables. - */ -static DeferredErrorMessage * -DeferErrorIfUnsupportedModifyQueryWithLocalTable(Query *query) -{ - RTEListProperties *rteListProperties = GetRTEListPropertiesForQuery(query); - Oid targetRelationId = ModifyQueryResultRelationId(query); - - DeferredErrorMessage *deferredErrorMessage = - DeferErrorIfUnsupportedModifyQueryWithCitusLocalTable(rteListProperties, - targetRelationId); - if (deferredErrorMessage) - { - return deferredErrorMessage; - } - - deferredErrorMessage = DeferErrorIfUnsupportedModifyQueryWithPostgresLocalTable( - rteListProperties, - targetRelationId); - return deferredErrorMessage; -} - - -/* - * DeferErrorIfUnsupportedModifyQueryWithCitusLocalTable is a helper function - * that takes RTEListProperties & targetRelationId and returns deferred error - * if query is not supported due to unsupported usage of citus local tables. - */ -static DeferredErrorMessage * -DeferErrorIfUnsupportedModifyQueryWithCitusLocalTable( - RTEListProperties *rteListProperties, Oid targetRelationId) -{ - if (rteListProperties->hasDistributedTable && rteListProperties->hasCitusLocalTable) - { - return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "cannot plan modifications with citus local tables and " - "distributed tables", NULL, - LOCAL_TABLE_SUBQUERY_CTE_HINT); - } - - if (IsCitusTableType(targetRelationId, REFERENCE_TABLE) && - rteListProperties->hasCitusLocalTable) - { - return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "cannot plan modifications of reference tables with citus " - "local tables", NULL, - LOCAL_TABLE_SUBQUERY_CTE_HINT); - } - - return NULL; -} - - -/* - * DeferErrorIfUnsupportedModifyQueryWithPostgresLocalTable is a helper - * function that takes RTEListProperties & targetRelationId and returns - * deferred error if query is not supported due to unsupported usage of - * postgres local tables. - */ -static DeferredErrorMessage * -DeferErrorIfUnsupportedModifyQueryWithPostgresLocalTable( - RTEListProperties *rteListProperties, Oid targetRelationId) -{ - if (rteListProperties->hasPostgresLocalTable && - rteListProperties->hasCitusTable) - { - return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "cannot plan modifications with local tables involving " - "citus tables", NULL, - LOCAL_TABLE_SUBQUERY_CTE_HINT); - } - - if (!IsCitusTable(targetRelationId)) - { - return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "cannot plan modifications of local tables involving " - "distributed tables", - NULL, NULL); - } - - return NULL; -} - - /* * ModifyQuerySupported returns NULL if the query only contains supported * features, otherwise it returns an error description. diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index f1c821690..63c9d85e0 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1400,8 +1400,16 @@ ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) { return false; } - return ContainsLocalTableDistributedTableJoin(rangeTableList) || - ContainsLocalTableSubqueryJoin(rangeTableList, resultRelationId); + if (ContainsLocalTableDistributedTableJoin(rangeTableList)) + { + return true; + } + if (ContainsLocalTableSubqueryJoin(rangeTableList, resultRelationId)) + { + return true; + } + + return false; } @@ -1420,7 +1428,7 @@ AllDataLocallyAccessible(List *rangeTableList) /* TODO:: check if it has distributed table */ return false; } - if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) + if (!IsRecursivelyPlannableRelation(rangeTableEntry)) { continue; } @@ -1457,11 +1465,11 @@ AllDataLocallyAccessible(List *rangeTableList) /* - * SubqueryConvertableRelationForJoin returns true if the given range table entry + * IsRecursivelyPlannableRelation returns true if the given range table entry * is a relation type that can be converted to a subquery. */ bool -SubqueryConvertableRelationForJoin(RangeTblEntry *rangeTableEntry) +IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry) { if (rangeTableEntry->rtekind != RTE_RELATION) { @@ -1487,7 +1495,7 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) { RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) + if (!IsRecursivelyPlannableRelation(rangeTableEntry)) { continue; } @@ -1529,7 +1537,7 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) containsSubquery = true; } - if (!SubqueryConvertableRelationForJoin(rangeTableEntry)) + if (!IsRecursivelyPlannableRelation(rangeTableEntry)) { continue; } diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index a744e80ff..64620ef4f 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -1910,7 +1910,6 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, */ Expr *copyOfRestrictClause = (Expr *) copyObject((Node *) restrictionClause); List *varClauses = pull_var_clause_default((Node *) copyOfRestrictClause); - ListCell *varClauseCell = NULL; Var *column = NULL; foreach_ptr(column, varClauses) { diff --git a/src/backend/distributed/planner/shard_pruning.c b/src/backend/distributed/planner/shard_pruning.c index 26b84d9ee..8d606cc14 100644 --- a/src/backend/distributed/planner/shard_pruning.c +++ b/src/backend/distributed/planner/shard_pruning.c @@ -894,7 +894,7 @@ PrunableExpressionsWalker(PruningTreeNode *node, ClauseWalkerContext *context) * VarConstOpExprClause check whether an expression is a valid comparison of a Var to a Const. * Also obtaining the var with constant when valid. */ -static bool +bool VarConstOpExprClause(OpExpr *opClause, Var **varClause, Const **constantClause) { Var *foundVarClause = NULL; diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 6dd146482..a88e14bc2 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -67,6 +67,6 @@ extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, extern bool ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId); extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId); -extern bool SubqueryConvertableRelationForJoin(RangeTblEntry *rangeTableEntry); +extern bool IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry); #endif /* RECURSIVE_PLANNING_H */ diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 2dacb8db8..9d2ebb12a 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -39,6 +39,16 @@ SELECT create_distributed_table('distributed_partitioned_table', 'key'); (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 (10); +CREATE TABLE local_partitioned_table_2 PARTITION OF local_partitioned_table FOR VALUES FROM (10) TO (20); +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_distributed_table +--------------------------------------------------------------------- + +(1 row) + SET client_min_messages TO DEBUG1; -- the user doesn't allow local / distributed table joinn SET citus.local_table_join_policy TO 'never'; @@ -121,6 +131,34 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +-- partititoned local tables should work as well +SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key); +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM reference_table JOIN local_partitioned_table USING(key); +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table 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 @@ -149,6 +187,43 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; +DEBUG: Wrapping local relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_composite.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey 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 @@ -508,7 +583,7 @@ SET FROM postgres_table WHERE - distributed_table_windex.key = postgres_table.key; + distributed_table_windex.key = postgres_table.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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) @@ -555,7 +630,7 @@ SET FROM postgres_table WHERE - distributed_table_windex.key = postgres_table.key; + distributed_table_windex.key = postgres_table.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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) @@ -600,7 +675,7 @@ SET FROM postgres_table WHERE - distributed_table_windex.key = postgres_table.key; + distributed_table_windex.key = postgres_table.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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) @@ -800,7 +875,7 @@ SET FROM citus_local WHERE - distributed_table_windex.key = citus_local.key; + distributed_table_windex.key = citus_local.key; DEBUG: Wrapping local relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text 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)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) @@ -811,15 +886,51 @@ SET FROM distributed_table_windex WHERE - distributed_table_windex.key = citus_local.key; + distributed_table_windex.key = citus_local.key; DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.citus_local SET value = 'test'::text FROM (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)) distributed_table_windex WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) +-- complex queries +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table LIMIT 1 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM local_table_join.citus_local +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((local_table_join.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table LIMIT 1 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM local_table_join.citus_local +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((local_table_join.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- TODO:: we should support this? +UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; +ERROR: relation postgres_table is not distributed +UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) l WHERE (l.key OPERATOR(pg_catalog.=) 10) +-- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? +-- though then the planner could give an error +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; +DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE false OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE false OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table USING (key)) WHERE false + count +--------------------------------------------------------------------- + 0 +(1 row) + DROP TABLE citus_local; CONTEXT: SQL statement "SELECT master_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name)" PL/pgSQL function citus_drop_trigger() line 15 at PERFORM -CONTEXT: SQL statement "SELECT master_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name)" -PL/pgSQL function citus_drop_trigger() line 15 at PERFORM RESET client_min_messages; SELECT master_remove_node('localhost', :master_port); master_remove_node @@ -829,4 +940,4 @@ SELECT master_remove_node('localhost', :master_port); \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 7 other objects +NOTICE: drop cascades to 9 other objects diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 0fb65d824..59b4b543a 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -19,6 +19,12 @@ CREATE TABLE distributed_partitioned_table_1 PARTITION OF distributed_partitione CREATE TABLE distributed_partitioned_table_2 PARTITION OF distributed_partitioned_table FOR VALUES FROM (10) TO (20); 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 (10); +CREATE TABLE local_partitioned_table_2 PARTITION OF local_partitioned_table FOR VALUES FROM (10) TO (20); + +CREATE TABLE distributed_table_composite (key int, value text, value_2 jsonb, primary key (key, value)); +SELECT create_distributed_table('distributed_table_composite', 'key'); SET client_min_messages TO DEBUG1; @@ -51,11 +57,23 @@ SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); SELECT count(*) FROM reference_table JOIN postgres_table USING(key); SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_table USING (key); +-- partititoned local tables should work as well +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); + -- 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; SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key); +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); + +-- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; + -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); @@ -352,6 +370,18 @@ FROM WHERE distributed_table_windex.key = citus_local.key; +-- complex queries +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; + +-- TODO:: we should support this? +UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; +UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; + +-- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? +-- though then the planner could give an error +SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; + DROP TABLE citus_local; RESET client_min_messages; SELECT master_remove_node('localhost', :master_port); From 3fe3c5502312ec844826a3ff3819a26b4fd3bf99 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Tue, 1 Dec 2020 18:09:50 +0300 Subject: [PATCH 14/37] Use ShouldConvertLocalTableJoinsToSubqueries Remove FillLocalAndDistributedRTECandidates and use ShouldConvertLocalTableJoinsToSubqueries, which simplifies things as we rely on a single function to decide whether we should continue converting RTE to subquery. --- .../planner/local_distributed_join_planner.c | 143 ++++++------------ .../regress/expected/local_table_join.out | 8 +- 2 files changed, 49 insertions(+), 102 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index d9535d1c6..c5206d0a8 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -66,14 +66,12 @@ typedef struct ConversionCandidates { List *distributedTableList; /* reference or distributed table */ List *localTableList; /* local or citus local table */ - bool hasSubqueryRTE; }ConversionCandidates; static Oid GetResultRelationId(Query *query); -static Oid GetRTEToSubqueryConverterReferenceRelId( - RangeTableEntryDetails *rangeTableEntryDetails); -static bool ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, Oid - resultRelationId); +static bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, + Oid resultRelationId, + RecursivePlanningContext *context); static bool HasUniqueFilter(RangeTblEntry *distRTE, List *distRTERestrictionList, List *requiredAttrNumbersForDistRTE); static bool ShouldConvertDistributedTable(FromExpr *joinTree, @@ -82,8 +80,8 @@ static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, RecursivePlanningContext *planningContext); static ConversionCandidates * CreateConversionCandidates( RecursivePlanningContext *context, - List * - rangeTableList); + List *rangeTableList, + Oid resultRelationId); static void GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes); static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree, ConversionCandidates @@ -98,12 +96,6 @@ static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableLis List **joinRangeTableEntries); static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid relationId); -static bool FillLocalAndDistributedRTECandidates( - ConversionCandidates *conversionCandidates, - RangeTableEntryDetails ** - localRTECandidate, - RangeTableEntryDetails ** - distributedRTECandidate); /* * ConvertUnplannableTableJoinsToSubqueries gets a query and the planner @@ -117,25 +109,18 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, List *rangeTableList = NIL; GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, &rangeTableList); - Oid resultRelationId = GetResultRelationId(query); - if (!ShouldConvertLocalTableJoinsToSubqueries(rangeTableList, resultRelationId)) - { - return; - } + Oid resultRelationId = GetResultRelationId(query); ConversionCandidates *conversionCandidates = - CreateConversionCandidates( - context, rangeTableList); + CreateConversionCandidates(context, rangeTableList, resultRelationId); RangeTableEntryDetails *rangeTableEntryDetails = GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, context->plannerRestrictionContext, resultRelationId); - PlannerRestrictionContext *plannerRestrictionContext = - FilterPlannerRestrictionForQuery(context->plannerRestrictionContext, query); - while (rangeTableEntryDetails && !IsRouterPlannable(query, - plannerRestrictionContext)) + while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, + resultRelationId, context)) { ReplaceRTERelationWithRteSubquery( rangeTableEntryDetails->rangeTableEntry, @@ -146,6 +131,7 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, RemoveFromConversionCandidates(conversionCandidates, rangeTableEntryDetails-> rangeTableEntry->relid); + rangeTableEntryDetails = GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, context->plannerRestrictionContext, @@ -228,30 +214,27 @@ GetNextRTEToConvertToSubquery(FromExpr *joinTree, { RangeTableEntryDetails *localRTECandidate = NULL; RangeTableEntryDetails *distributedRTECandidate = NULL; - if (!FillLocalAndDistributedRTECandidates(conversionCandidates, - &localRTECandidate, - &distributedRTECandidate)) + + if (list_length(conversionCandidates->localTableList) > 0) { - return NULL; + localRTECandidate = linitial(conversionCandidates->localTableList); } - if (OidIsValid(resultRelationId)) + if (list_length(conversionCandidates->distributedTableList) > 0) { - if (resultRelationId == GetRTEToSubqueryConverterReferenceRelId( - localRTECandidate)) - { - return distributedRTECandidate; - } - if (resultRelationId == GetRTEToSubqueryConverterReferenceRelId( - distributedRTECandidate)) - { - return localRTECandidate; - } + distributedRTECandidate = linitial(conversionCandidates->distributedTableList); } if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) { - return localRTECandidate; + if (localRTECandidate) + { + return localRTECandidate; + } + else + { + return distributedRTECandidate; + } } else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) { @@ -266,7 +249,8 @@ GetNextRTEToConvertToSubquery(FromExpr *joinTree, } else { - if (ShouldConvertDistributedTable(joinTree, distributedRTECandidate)) + if (ShouldConvertDistributedTable(joinTree, distributedRTECandidate) || + localRTECandidate == NULL) { return distributedRTECandidate; } @@ -278,51 +262,6 @@ GetNextRTEToConvertToSubquery(FromExpr *joinTree, } -/* - * FillLocalAndDistributedRTECandidates fills the local and distributed RTE candidates. - * It returns true if we should continue converting tables to subqueries. - */ -static bool -FillLocalAndDistributedRTECandidates(ConversionCandidates *conversionCandidates, - RangeTableEntryDetails **localRTECandidate, - RangeTableEntryDetails ** - distributedRTECandidate) -{ - if (list_length(conversionCandidates->localTableList) > 0) - { - *localRTECandidate = linitial(conversionCandidates->localTableList); - } - if (*localRTECandidate == NULL) - { - return false; - } - - if (list_length(conversionCandidates->distributedTableList) > 0) - { - *distributedRTECandidate = linitial( - conversionCandidates->distributedTableList); - } - return *distributedRTECandidate != NULL || - conversionCandidates->hasSubqueryRTE; -} - - -/* - * GetRTEToSubqueryConverterReferenceRelId returns the underlying relation id - * if it is a valid one. - */ -static Oid -GetRTEToSubqueryConverterReferenceRelId(RangeTableEntryDetails *rangeTableEntryDetails) -{ - if (rangeTableEntryDetails && - rangeTableEntryDetails->rangeTableEntry) - { - return rangeTableEntryDetails->rangeTableEntry->relid; - } - return InvalidOid; -} - - /* * RemoveFromConversionCandidates removes an element from * the relevant list based on the relation id. @@ -348,7 +287,9 @@ RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid r * convert local-dist table joins to subqueries. */ static bool -ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, Oid resultRelationId) +ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, + Oid resultRelationId, + RecursivePlanningContext *context) { if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) { @@ -359,6 +300,13 @@ ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList, Oid resultRelatio { return false; } + + PlannerRestrictionContext *plannerRestrictionContext = + FilterPlannerRestrictionForQuery(context->plannerRestrictionContext, query); + if (IsRouterPlannable(query, plannerRestrictionContext)) + { + return false; + } return true; } @@ -507,7 +455,7 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, */ static ConversionCandidates * CreateConversionCandidates(RecursivePlanningContext *context, - List *rangeTableList) + List *rangeTableList, Oid resultRelationId) { ConversionCandidates *conversionCandidates = palloc0( sizeof(ConversionCandidates)); @@ -517,10 +465,6 @@ CreateConversionCandidates(RecursivePlanningContext *context, foreach_ptr(rangeTableEntry, rangeTableList) { rteIndex++; - if (rangeTableEntry->rtekind == RTE_SUBQUERY) - { - conversionCandidates->hasSubqueryRTE = true; - } /* we're only interested in tables */ if (!IsRecursivelyPlannableRelation(rangeTableEntry)) @@ -528,6 +472,17 @@ CreateConversionCandidates(RecursivePlanningContext *context, continue; } + bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, + REFERENCE_TABLE) || + IsCitusTableType(rangeTableEntry->relid, + DISTRIBUTED_TABLE); + + /* result relation cannot converted to a subquery */ + if (resultRelationId == rangeTableEntry->relid) + { + continue; + } + RangeTableEntryDetails *rangeTableEntryDetails = palloc0( sizeof(RangeTableEntryDetails)); rangeTableEntryDetails->rangeTableEntry = rangeTableEntry; @@ -539,10 +494,6 @@ CreateConversionCandidates(RecursivePlanningContext *context, rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation( rangeTableEntry, context); - bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, - REFERENCE_TABLE) || - IsCitusTableType(rangeTableEntry->relid, - DISTRIBUTED_TABLE); if (referenceOrDistributedTable) { conversionCandidates->distributedTableList = diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 9d2ebb12a..790f79c77 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -847,9 +847,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 -DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.citus_local 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)) distributed_table USING (key)) JOIN local_table_join.postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) reference_table USING (key)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.citus_local 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)) distributed_table USING (key)) JOIN local_table_join.postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 0 @@ -859,9 +857,7 @@ SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; DEBUG: Wrapping local relation "distributed_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 -DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) distributed_partitioned_table JOIN local_table_join.postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) distributed_partitioned_table JOIN local_table_join.postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) count --------------------------------------------------------------------- 0 From ff4f3b2f3cadf76056e10d157a6b601e7c6eaa70 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Tue, 1 Dec 2020 18:53:07 +0300 Subject: [PATCH 15/37] Use PlannerRestrictionContext instead of RecursivePlannerContext --- .../planner/local_distributed_join_planner.c | 44 ++++++++----------- .../planner/multi_router_planner.c | 9 ++-- .../distributed/planner/recursive_planning.c | 3 +- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index c5206d0a8..a9c4b64e6 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -71,27 +71,22 @@ typedef struct ConversionCandidates static Oid GetResultRelationId(Query *query); static bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, Oid resultRelationId, - RecursivePlanningContext *context); + PlannerRestrictionContext *plannerRestrictionContext); static bool HasUniqueFilter(RangeTblEntry *distRTE, List *distRTERestrictionList, List *requiredAttrNumbersForDistRTE); static bool ShouldConvertDistributedTable(FromExpr *joinTree, RangeTableEntryDetails *distRTEContext); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, - RecursivePlanningContext *planningContext); + PlannerRestrictionContext *plannerRestrictionContext); static ConversionCandidates * CreateConversionCandidates( - RecursivePlanningContext *context, + PlannerRestrictionContext *plannerRestrictionContext, List *rangeTableList, Oid resultRelationId); static void GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes); static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree, - ConversionCandidates - * - conversionCandidates, - PlannerRestrictionContext - * - plannerRestrictionContext, - Oid - resultRelationId); + ConversionCandidates *conversionCandidates, + PlannerRestrictionContext* plannerRestrictionContext, + Oid resultRelationId); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, List **joinRangeTableEntries); static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid @@ -106,13 +101,18 @@ void ConvertUnplannableTableJoinsToSubqueries(Query *query, RecursivePlanningContext *context) { + PlannerRestrictionContext* plannerRestrictionContext = context->plannerRestrictionContext; + List *rangeTableList = NIL; GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, &rangeTableList); Oid resultRelationId = GetResultRelationId(query); + if (!ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, resultRelationId, plannerRestrictionContext)) { + return; + } ConversionCandidates *conversionCandidates = - CreateConversionCandidates(context, rangeTableList, resultRelationId); + CreateConversionCandidates(plannerRestrictionContext, rangeTableList, resultRelationId); RangeTableEntryDetails *rangeTableEntryDetails = GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, @@ -120,7 +120,7 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, resultRelationId); while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, - resultRelationId, context)) + resultRelationId, plannerRestrictionContext)) { ReplaceRTERelationWithRteSubquery( rangeTableEntryDetails->rangeTableEntry, @@ -289,7 +289,7 @@ RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid r static bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, Oid resultRelationId, - RecursivePlanningContext *context) + PlannerRestrictionContext *plannerRestrictionContext) { if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) { @@ -301,8 +301,7 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, return false; } - PlannerRestrictionContext *plannerRestrictionContext = - FilterPlannerRestrictionForQuery(context->plannerRestrictionContext, query); + plannerRestrictionContext = FilterPlannerRestrictionForQuery(plannerRestrictionContext, query); if (IsRouterPlannable(query, plannerRestrictionContext)) { return false; @@ -403,11 +402,8 @@ GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes) */ static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, - RecursivePlanningContext *planningContext) + PlannerRestrictionContext *plannerRestrictionContext) { - PlannerRestrictionContext *plannerRestrictionContext = - planningContext->plannerRestrictionContext; - /* TODO: Get rid of this hack, find relation restriction information directly */ PlannerRestrictionContext *filteredPlannerRestrictionContext = FilterPlannerRestrictionForQuery(plannerRestrictionContext, @@ -454,7 +450,7 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, * be converted to a subquery so that citus planners can work. */ static ConversionCandidates * -CreateConversionCandidates(RecursivePlanningContext *context, +CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, List *rangeTableList, Oid resultRelationId) { ConversionCandidates *conversionCandidates = palloc0( @@ -488,11 +484,9 @@ CreateConversionCandidates(RecursivePlanningContext *context, rangeTableEntryDetails->rangeTableEntry = rangeTableEntry; rangeTableEntryDetails->rteIndex = rteIndex; rangeTableEntryDetails->restrictionList = GetRestrictInfoListForRelation( - rangeTableEntry, - context-> - plannerRestrictionContext, 1); + rangeTableEntry, plannerRestrictionContext, 1); rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation( - rangeTableEntry, context); + rangeTableEntry, plannerRestrictionContext); if (referenceOrDistributedTable) { diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index c8d71619e..406333f8e 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -221,8 +221,9 @@ CreateModifyPlan(Query *originalQuery, Query *query, distributedPlan->modLevel = RowModifyLevelForQuery(query); distributedPlan->planningError = ModifyQuerySupported(query, originalQuery, - multiShardQuery, - plannerRestrictionContext); + multiShardQuery, + plannerRestrictionContext); + if (distributedPlan->planningError != NULL) { return distributedPlan; @@ -550,10 +551,6 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, Oid resultRelationId = ModifyQueryResultRelationId(queryTree); *distributedTableIdOutput = resultRelationId; - if (ContainsTableToBeConvertedToSubquery(queryTree->rtable, resultRelationId)) - { - return deferredError; - } Var *partitionColumn = NULL; diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 63c9d85e0..bd372d01b 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1542,8 +1542,7 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) continue; } - if (!IsCitusTable(rangeTableEntry->relid) && rangeTableEntry->relid != - resultRelationId) + if (!IsCitusTable(rangeTableEntry->relid) && rangeTableEntry->relid != resultRelationId) { containsLocalTable = true; } From 5f46abffd9d6ab4075929edaa01e2be3247e309f Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Tue, 1 Dec 2020 22:14:33 +0300 Subject: [PATCH 16/37] Update check multi tests --- .../expected/citus_local_tables_queries.out | 80 ++++++++---- .../regress/expected/mixed_relkind_tests.out | 123 ++++++++++++------ ...relation_planning_restirction_pushdown.out | 2 +- .../expected/subqueries_not_supported.out | 15 +-- src/test/regress/sql/mixed_relkind_tests.sql | 14 +- .../regress/sql/subqueries_not_supported.sql | 12 -- 6 files changed, 151 insertions(+), 95 deletions(-) diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index aabd2fe07..5640fe7ca 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -120,7 +120,7 @@ NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queri -- 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: direct joins between distributed and local tables are not supported +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 ( @@ -154,7 +154,12 @@ SELECT count(*) FROM ( SELECT *, random() FROM (SELECT *, random() FROM citus_local_table, distributed_table) as subquery_inner ) as subquery_top; -ERROR: direct joins between distributed and local tables are not supported +NOTICE: executing the command locally: SELECT NULL::integer AS a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 + count +--------------------------------------------------------------------- + 36 +(1 row) + -- should fail as we don't support direct joins between distributed/local tables SELECT count(*) FROM ( @@ -162,7 +167,13 @@ SELECT count(*) FROM FROM ( WITH cte_1 AS (SELECT *, random() FROM citus_local_table, distributed_table) SELECT * FROM cte_1) as subquery_inner ) as subquery_top; -ERROR: direct joins between distributed and local tables are not supported +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +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 ( @@ -474,7 +485,7 @@ NOTICE: executing the command locally: SELECT count(*) AS count FROM (((citus_l -- not supported direct outer join SELECT count(*) FROM citus_local_table LEFT JOIN distributed_table ON (true); -ERROR: direct joins between distributed and local tables are not supported +ERROR: cannot pushdown the subquery -- distinct in subquery on CTE WITH one_row AS ( SELECT a from citus_local_table WHERE b = 1 @@ -516,9 +527,14 @@ NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queri -- join between citus local tables and distributed tables would fail SELECT count(*) FROM citus_local_table, distributed_table; -ERROR: direct joins between distributed and local tables are not supported +NOTICE: executing the command locally: SELECT NULL::integer AS a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 + count +--------------------------------------------------------------------- + 36 +(1 row) + SELECT * FROM citus_local_table, distributed_table ORDER BY 1,2,3,4 FOR UPDATE; -ERROR: direct joins between distributed and local tables are not supported +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 @@ -638,7 +654,8 @@ NOTICE: executing the copy locally for shard xxxxx INSERT INTO citus_local_table SELECT distributed_table.* FROM distributed_table JOIN citus_local_table ON (true); -ERROR: direct joins between distributed and local tables are not supported +NOTICE: executing the command locally: SELECT NULL::integer AS a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +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 @@ -662,38 +679,38 @@ SELECT clear_and_init_test_tables(); DELETE FROM citus_local_table USING postgres_local_table WHERE citus_local_table.b = postgres_local_table.b; -ERROR: cannot plan modifications with local tables involving citus tables +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 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; -ERROR: cannot plan modifications with local tables involving citus tables +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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; -ERROR: cannot plan modifications with local tables involving citus tables +ERROR: relation postgres_local_table is not distributed 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; -ERROR: cannot plan modifications with local tables involving citus tables +ERROR: relation postgres_local_table is not distributed -- no direct joins supported UPDATE distributed_table SET b = 6 FROM citus_local_table WHERE citus_local_table.a = distributed_table.a; -ERROR: cannot plan modifications with citus local tables and distributed tables +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 UPDATE reference_table SET b = 6 FROM citus_local_table WHERE citus_local_table.a = reference_table.a; -ERROR: cannot plan modifications of reference tables with citus local tables +NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509002 reference_table SET b = 6 FROM citus_local_table_queries.citus_local_table_1509000 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; -ERROR: cannot plan modifications with citus local tables and distributed tables +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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 WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table.a) -- should work, add HINT use CTEs UPDATE citus_local_table SET b = 6 @@ -704,16 +721,16 @@ NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_l DELETE FROM distributed_table USING citus_local_table WHERE citus_local_table.a = distributed_table.a; -ERROR: cannot plan modifications with citus local tables and distributed tables +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 -- should not work, add HINT use CTEs DELETE FROM citus_local_table USING distributed_table WHERE citus_local_table.a = distributed_table.a; -ERROR: cannot plan modifications with citus local tables and distributed tables +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table USING (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 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; -ERROR: cannot plan modifications of reference tables with citus local tables +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509002 reference_table USING citus_local_table_queries.citus_local_table_1509000 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 @@ -726,7 +743,8 @@ NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.ci -- just works DELETE FROM citus_local_table WHERE citus_local_table.a IN (SELECT a FROM reference_table); -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT reference_table.a FROM citus_local_table_queries.reference_table_1509002 reference_table)) +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509002 reference_table +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 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 @@ -740,7 +758,8 @@ UPDATE citus_local_table SET b = 6 FROM reference_table_cte WHERE citus_local_table.a = reference_table_cte.a; -NOTICE: executing the command locally: WITH reference_table_cte AS (SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509002 reference_table) UPDATE citus_local_table_queries.citus_local_table_1509000 citus_local_table SET b = 6 FROM reference_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table_cte.a) +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.reference_table_1509002 reference_table +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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)) reference_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table_cte.a) --------------------------------------------------------------------- ----- VIEW QUERIES ----- --------------------------------------------------------------------- @@ -772,7 +791,14 @@ 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; -ERROR: direct joins between distributed and local tables are not supported +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_2_1509001 citus_local_table_2 WHERE true OFFSET 0 +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 @@ -826,7 +852,17 @@ 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; -ERROR: cannot plan modifications with citus local tables and distributed tables +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 lt SET a = mt.a 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 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 @@ -852,7 +888,7 @@ UPDATE citus_local_table SET a=5 FROM (SELECT b FROM distributed_table) AS foo WHERE foo.b = citus_local_table.b; -ERROR: cannot plan modifications with citus local tables and distributed tables +ERROR: citus local table citus_local_table cannot be joined with these distributed tables --------------------------------------------------------------------- -- test different execution paths -- --------------------------------------------------------------------- diff --git a/src/test/regress/expected/mixed_relkind_tests.out b/src/test/regress/expected/mixed_relkind_tests.out index 1185b0d00..3323bca56 100644 --- a/src/test/regress/expected/mixed_relkind_tests.out +++ b/src/test/regress/expected/mixed_relkind_tests.out @@ -319,28 +319,55 @@ $$); (1 row) SET client_min_messages TO DEBUG1; --- should fail -SELECT * FROM partitioned_postgres_local_table JOIN distributed_table ON (true); -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins -SELECT * FROM partitioned_postgres_local_table JOIN partitioned_distributed_table ON (true); -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins -SELECT * FROM distributed_table JOIN partitioned_postgres_local_table ON (true); -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins -SELECT * FROM reference_table LEFT JOIN partitioned_distributed_table ON true; -ERROR: cannot pushdown the subquery -DETAIL: There exist a reference table in the outer part of the outer join +SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN distributed_table ON (true); +DEBUG: Wrapping local relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.distributed_table ON (true)) + count +--------------------------------------------------------------------- + 36 +(1 row) + +SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN partitioned_distributed_table ON (true); +DEBUG: Wrapping local relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.partitioned_distributed_table ON (true)) + count +--------------------------------------------------------------------- + 36 +(1 row) + +SELECT COUNT(*) FROM distributed_table JOIN partitioned_postgres_local_table ON (true); +DEBUG: Wrapping local relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (mixed_relkind_tests.distributed_table JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table ON (true)) + count +--------------------------------------------------------------------- + 36 +(1 row) + INSERT INTO partitioned_distributed_table SELECT foo.* FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -ERROR: direct joins between distributed and local tables are not supported +DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a, foo.b FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) +DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO partitioned_distributed_table SELECT foo.* FROM distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -ERROR: direct joins between distributed and local tables are not supported +DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) +DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO distributed_table SELECT foo.a FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -ERROR: direct joins between distributed and local tables are not supported +DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) +DEBUG: performing repartitioned INSERT ... SELECT +-- should fail +SELECT COUNT(*) FROM reference_table LEFT JOIN partitioned_distributed_table ON true; +ERROR: cannot pushdown the subquery +DETAIL: There exist a reference table in the outer part of the outer join -- non-colocated subquery should work SELECT COUNT(*) FROM (SELECT *, random() FROM partitioned_distributed_table) AS foo, @@ -350,7 +377,7 @@ DEBUG: generating subplan XXX_1 for subquery SELECT a, b, random() AS random FR DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT partitioned_distributed_table.a, partitioned_distributed_table.b, random() AS random FROM mixed_relkind_tests.partitioned_distributed_table) foo, (SELECT intermediate_result.a, intermediate_result.b, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer, random double precision)) bar WHERE (foo.a OPERATOR(pg_catalog.=) bar.b) count --------------------------------------------------------------------- - 5 + 455 (1 row) SELECT COUNT(*) FROM @@ -364,19 +391,23 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) --- should fail UPDATE partitioned_distributed_table SET b = foo.a FROM citus_local_table AS foo; -ERROR: cannot plan modifications with citus local tables and distributed tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins +DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo UPDATE partitioned_distributed_table SET b = foo.a FROM postgres_local_table AS foo; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins +DEBUG: Wrapping local relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo UPDATE partitioned_distributed_table SET a = foo.a FROM postgres_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -ERROR: cannot plan modifications with local tables involving citus tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins +DEBUG: Wrapping local relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) UPDATE partitioned_distributed_table SET a = foo.a FROM citus_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -ERROR: cannot plan modifications with citus local tables and distributed tables -HINT: Use CTE's or subqueries to select from local tables and use them in joins +DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) +-- should fail UPDATE partitioned_distributed_table SET a = foo.a FROM mat_view_on_part_dist AS foo WHERE foo.a = partitioned_distributed_table.a; ERROR: materialized views in modify queries are not supported UPDATE partitioned_distributed_table SET a = foo.a FROM partitioned_distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; @@ -392,33 +423,33 @@ UPDATE partitioned_distributed_table SET a = foo.a FROM view_on_ref AS foo WHERE SELECT COUNT(*) FROM partitioned_distributed_table p1 JOIN partitioned_distributed_table p2 USING (a); count --------------------------------------------------------------------- - 6 + 1014 (1 row) SELECT COUNT(*) FROM unlogged_distributed_table u1 JOIN partitioned_distributed_table p2 USING (a); count --------------------------------------------------------------------- - 6 + 78 (1 row) SELECT COUNT(*) FROM partitioned_distributed_table p1 LEFT JOIN partitioned_distributed_table p2 USING (a); count --------------------------------------------------------------------- - 6 + 1014 (1 row) -- lateral JOIN SELECT COUNT(*) FROM partitioned_distributed_table p1 JOIN LATERAL (SELECT * FROM partitioned_distributed_table p2 WHERE p1.a = p2.a) AS foo ON (true); count --------------------------------------------------------------------- - 6 + 1014 (1 row) -- router query SELECT COUNT(*) FROM partitioned_distributed_table p1 JOIN partitioned_distributed_table p2 USING (a) WHERE a = 1; count --------------------------------------------------------------------- - 1 + 169 (1 row) -- repartition query @@ -426,13 +457,13 @@ SET citus.enable_repartition_joins TO ON; SELECT COUNT(*) FROM partitioned_distributed_table p1 JOIN partitioned_distributed_table p2 USING (b) WHERE b = 1; count --------------------------------------------------------------------- - 1 + 0 (1 row) SELECT COUNT(*) FROM unlogged_distributed_table u1 JOIN partitioned_distributed_table p2 USING (b) WHERE b = 1; count --------------------------------------------------------------------- - 1 + 0 (1 row) RESET citus.enable_repartition_joins; @@ -443,7 +474,7 @@ DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT a, b FROM mixed_relkind_t DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) cte_1 count --------------------------------------------------------------------- - 6 + 78 (1 row) WITH cte_1 AS (SELECT * FROM partitioned_distributed_table) @@ -452,7 +483,7 @@ DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT a, b FROM mixed_relkind_t DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) cte_1 JOIN mixed_relkind_tests.partitioned_distributed_table USING (a)) count --------------------------------------------------------------------- - 6 + 1014 (1 row) WITH cte_1 AS (SELECT * FROM foreign_distributed_table) @@ -470,7 +501,7 @@ DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT a, b FROM mixed_relkind_t DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) cte_1 JOIN mixed_relkind_tests.partitioned_distributed_table USING (b)) count --------------------------------------------------------------------- - 6 + 6084 (1 row) -- multi shard colocated update @@ -599,13 +630,13 @@ SET client_min_messages TO DEBUG1; SELECT sum(a) FROM partitioned_distributed_table; sum --------------------------------------------------------------------- - 15 + 195 (1 row) SELECT ceil(regr_syy(a, b)) FROM partitioned_distributed_table; ceil --------------------------------------------------------------------- - 18 + 228 (1 row) SELECT ceil(regr_syy(a, b)) FROM unlogged_distributed_table; @@ -674,8 +705,20 @@ $Q$); SELECT * FROM partitioned_distributed_table WHERE a = 1 ORDER BY 1,2 FOR UPDATE; a | b --------------------------------------------------------------------- - 1 | 2 -(1 row) + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 + 1 | 0 +(13 rows) SELECT * FROM unlogged_distributed_table WHERE a = 1 ORDER BY 1,2 FOR UPDATE; a | b diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out index 87dee53e0..c9513f28f 100644 --- a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out +++ b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out @@ -235,8 +235,8 @@ JOIN local_table u2 USING(value) WHERE u2.value > (SELECT avg(key) FROM distributed_table); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT avg(key) AS avg FROM push_down_filters.distributed_table +DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value)::numeric OPERATOR(pg_catalog.>) (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric))) count diff --git a/src/test/regress/expected/subqueries_not_supported.out b/src/test/regress/expected/subqueries_not_supported.out index 13e064d59..0bb5da386 100644 --- a/src/test/regress/expected/subqueries_not_supported.out +++ b/src/test/regress/expected/subqueries_not_supported.out @@ -6,22 +6,9 @@ SET search_path TO not_supported, public; SET citus.coordinator_aggregation_strategy TO 'disabled'; SET client_min_messages TO DEBUG1; CREATE TABLE users_table_local AS SELECT * FROM users_table; --- we don't support subqueries with local tables when they are not leaf queries -SELECT - * -FROM - ( - SELECT - users_table_local.user_id - FROM - users_table_local, (SELECT user_id FROM events_table) as evs - WHERE users_table_local.user_id = evs.user_id - ) as foo; -ERROR: direct joins between distributed and local tables are not supported -HINT: Use CTE's or subqueries to select from local tables and use them in joins RESET client_min_messages; -- we don't support subqueries with local tables when they are not leaf queries -SELECT user_id FROM users_table WHERE user_id IN +SELECT COUNT(user_id) FROM users_table WHERE user_id IN (SELECT user_id FROM diff --git a/src/test/regress/sql/mixed_relkind_tests.sql b/src/test/regress/sql/mixed_relkind_tests.sql index 795307d65..6f935c79d 100644 --- a/src/test/regress/sql/mixed_relkind_tests.sql +++ b/src/test/regress/sql/mixed_relkind_tests.sql @@ -101,15 +101,17 @@ INSERT INTO partitioned_distributed_table SELECT * FROM partitioned_distributed_ $$); SET client_min_messages TO DEBUG1; --- should fail -SELECT * FROM partitioned_postgres_local_table JOIN distributed_table ON (true); -SELECT * FROM partitioned_postgres_local_table JOIN partitioned_distributed_table ON (true); -SELECT * FROM distributed_table JOIN partitioned_postgres_local_table ON (true); -SELECT * FROM reference_table LEFT JOIN partitioned_distributed_table ON true; +SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN distributed_table ON (true); +SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN partitioned_distributed_table ON (true); +SELECT COUNT(*) FROM distributed_table JOIN partitioned_postgres_local_table ON (true); INSERT INTO partitioned_distributed_table SELECT foo.* FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); INSERT INTO partitioned_distributed_table SELECT foo.* FROM distributed_table AS foo JOIN citus_local_table ON (true); INSERT INTO distributed_table SELECT foo.a FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); +-- should fail +SELECT COUNT(*) FROM reference_table LEFT JOIN partitioned_distributed_table ON true; + + -- non-colocated subquery should work SELECT COUNT(*) FROM (SELECT *, random() FROM partitioned_distributed_table) AS foo, @@ -121,11 +123,11 @@ SELECT COUNT(*) FROM (SELECT *, random() FROM foreign_distributed_table) AS bar WHERE foo.a = bar.b; --- should fail UPDATE partitioned_distributed_table SET b = foo.a FROM citus_local_table AS foo; UPDATE partitioned_distributed_table SET b = foo.a FROM postgres_local_table AS foo; UPDATE partitioned_distributed_table SET a = foo.a FROM postgres_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; UPDATE partitioned_distributed_table SET a = foo.a FROM citus_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; +-- should fail UPDATE partitioned_distributed_table SET a = foo.a FROM mat_view_on_part_dist AS foo WHERE foo.a = partitioned_distributed_table.a; UPDATE partitioned_distributed_table SET a = foo.a FROM partitioned_distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; UPDATE partitioned_distributed_table SET a = foo.a FROM distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; diff --git a/src/test/regress/sql/subqueries_not_supported.sql b/src/test/regress/sql/subqueries_not_supported.sql index 1ece06c34..b08fe254c 100644 --- a/src/test/regress/sql/subqueries_not_supported.sql +++ b/src/test/regress/sql/subqueries_not_supported.sql @@ -9,18 +9,6 @@ SET client_min_messages TO DEBUG1; CREATE TABLE users_table_local AS SELECT * FROM users_table; --- TODO:: Move this out of this file -SELECT - COUNT(*) -FROM - ( - SELECT - users_table_local.user_id - FROM - users_table_local, (SELECT user_id FROM events_table) as evs - WHERE users_table_local.user_id = evs.user_id - ) as foo; - RESET client_min_messages; -- we don't support subqueries with local tables when they are not leaf queries SELECT COUNT(user_id) FROM users_table WHERE user_id IN From a008fc611cdab360907de4c45b8aa651dea2582a Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Tue, 1 Dec 2020 22:48:21 +0300 Subject: [PATCH 17/37] 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; From 0689f2ac1adc4ddb9921831f4efd7dbf805f659c Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Tue, 1 Dec 2020 23:44:06 +0300 Subject: [PATCH 18/37] Recursively plan distributed tables only if all have unique filters The previous algorithm was not consistent and it could convert different RTEs based on the table orders in the query. Now we convert local tables if there is a distributed table which doesn't have a unique index. So if there are 4 tables, local1, local2, dist1, dist2_with_pkey then we will convert local1 and local2 in `auto` mode. Converting a distributed table is not that logical because as there is a distributed table without a unique index, we will need to convert the local tables anyway. So converting the distributed table with pkey is redundant. --- .../planner/local_distributed_join_planner.c | 147 +++++++++--------- .../planner/multi_router_planner.c | 4 +- .../distributed/planner/recursive_planning.c | 7 +- .../regress/expected/local_table_join.out | 45 ++++++ src/test/regress/sql/local_table_join.sql | 6 + 5 files changed, 131 insertions(+), 78 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index a9c4b64e6..e0b74b409 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -60,6 +60,7 @@ typedef struct RangeTableEntryDetails Index rteIndex; List *restrictionList; List *requiredAttributeNumbers; + bool hasUniqueIndex; } RangeTableEntryDetails; typedef struct ConversionCandidates @@ -71,26 +72,30 @@ typedef struct ConversionCandidates static Oid GetResultRelationId(Query *query); static bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, Oid resultRelationId, - PlannerRestrictionContext *plannerRestrictionContext); -static bool HasUniqueFilter(RangeTblEntry *distRTE, List *distRTERestrictionList, - List *requiredAttrNumbersForDistRTE); -static bool ShouldConvertDistributedTable(FromExpr *joinTree, - RangeTableEntryDetails *distRTEContext); + PlannerRestrictionContext * + plannerRestrictionContext); +static bool HasUniqueIndex(FromExpr *joinTree, + RangeTblEntry *rangeTableEntry, Index rteIndex); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, - PlannerRestrictionContext *plannerRestrictionContext); -static ConversionCandidates * CreateConversionCandidates( - PlannerRestrictionContext *plannerRestrictionContext, - List *rangeTableList, - Oid resultRelationId); + PlannerRestrictionContext * + plannerRestrictionContext); +static ConversionCandidates * CreateConversionCandidates(FromExpr *joinTree, + PlannerRestrictionContext * + plannerRestrictionContext, + List *rangeTableList, + Oid resultRelationId); static void GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes); static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree, - ConversionCandidates *conversionCandidates, - PlannerRestrictionContext* plannerRestrictionContext, + ConversionCandidates * + conversionCandidates, + PlannerRestrictionContext * + plannerRestrictionContext, Oid resultRelationId); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, List **joinRangeTableEntries); static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid relationId); +static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList); /* * ConvertUnplannableTableJoinsToSubqueries gets a query and the planner @@ -101,18 +106,22 @@ void ConvertUnplannableTableJoinsToSubqueries(Query *query, RecursivePlanningContext *context) { - PlannerRestrictionContext* plannerRestrictionContext = context->plannerRestrictionContext; + PlannerRestrictionContext *plannerRestrictionContext = + context->plannerRestrictionContext; List *rangeTableList = NIL; GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, &rangeTableList); Oid resultRelationId = GetResultRelationId(query); - if (!ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, resultRelationId, plannerRestrictionContext)) { + if (!ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, resultRelationId, + plannerRestrictionContext)) + { return; } ConversionCandidates *conversionCandidates = - CreateConversionCandidates(plannerRestrictionContext, rangeTableList, resultRelationId); + CreateConversionCandidates(query->jointree, plannerRestrictionContext, + rangeTableList, resultRelationId); RangeTableEntryDetails *rangeTableEntryDetails = GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, @@ -120,7 +129,8 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, resultRelationId); while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, - resultRelationId, plannerRestrictionContext)) + resultRelationId, + plannerRestrictionContext)) { ReplaceRTERelationWithRteSubquery( rangeTableEntryDetails->rangeTableEntry, @@ -219,7 +229,6 @@ GetNextRTEToConvertToSubquery(FromExpr *joinTree, { localRTECandidate = linitial(conversionCandidates->localTableList); } - if (list_length(conversionCandidates->distributedTableList) > 0) { distributedRTECandidate = linitial(conversionCandidates->distributedTableList); @@ -227,41 +236,48 @@ GetNextRTEToConvertToSubquery(FromExpr *joinTree, if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) { - if (localRTECandidate) - { - return localRTECandidate; - } - else - { - return distributedRTECandidate; - } + return localRTECandidate ? localRTECandidate : distributedRTECandidate; } else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) { - if (distributedRTECandidate) - { - return distributedRTECandidate; - } - else - { - return localRTECandidate; - } + return distributedRTECandidate ? distributedRTECandidate : localRTECandidate; } else { - if (ShouldConvertDistributedTable(joinTree, distributedRTECandidate) || - localRTECandidate == NULL) + bool allRangeTableEntriesHaveUniqueIndex = AllRangeTableEntriesHaveUniqueIndex( + conversionCandidates->distributedTableList); + + if (allRangeTableEntriesHaveUniqueIndex) { - return distributedRTECandidate; + return distributedRTECandidate ? distributedRTECandidate : localRTECandidate; } else { - return localRTECandidate; + return localRTECandidate ? localRTECandidate : distributedRTECandidate; } } } +/* + * AllRangeTableEntriesHaveUniqueIndex returns true if all of the RTE's in the given + * list have a unique index. + */ +static bool +AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList) +{ + RangeTableEntryDetails *rangeTableEntryDetails = NULL; + foreach_ptr(rangeTableEntryDetails, rangeTableEntryDetailsList) + { + if (!rangeTableEntryDetails->hasUniqueIndex) + { + return false; + } + } + return true; +} + + /* * RemoveFromConversionCandidates removes an element from * the relevant list based on the relation id. @@ -289,7 +305,8 @@ RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid r static bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, Oid resultRelationId, - PlannerRestrictionContext *plannerRestrictionContext) + PlannerRestrictionContext * + plannerRestrictionContext) { if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) { @@ -301,7 +318,8 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, return false; } - plannerRestrictionContext = FilterPlannerRestrictionForQuery(plannerRestrictionContext, query); + plannerRestrictionContext = FilterPlannerRestrictionForQuery( + plannerRestrictionContext, query); if (IsRouterPlannable(query, plannerRestrictionContext)) { return false; @@ -311,22 +329,18 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, /* - * ShouldConvertDistributedTable returns true if we should convert the - * distributed table rte to a subquery. This will be the case if the distributed - * table has a unique index on a column that appears in filter. + * HasUniqueIndex returns true if the given rangeTableEntry has a constant + * filter on a unique column. */ static bool -ShouldConvertDistributedTable(FromExpr *joinTree, - RangeTableEntryDetails * - rangeTableEntryDetails) +HasUniqueIndex(FromExpr *joinTree, RangeTblEntry *rangeTableEntry, Index rteIndex) { - if (rangeTableEntryDetails == NULL) + if (rangeTableEntry == NULL) { return false; } - List *distRTEEqualityQuals = - FetchEqualityAttrNumsForRTEFromQuals(joinTree->quals, - rangeTableEntryDetails->rteIndex); + List *rteEqualityQuals = + FetchEqualityAttrNumsForRTEFromQuals(joinTree->quals, rteIndex); Node *join = NULL; foreach_ptr(join, joinTree->fromlist) @@ -334,37 +348,18 @@ ShouldConvertDistributedTable(FromExpr *joinTree, if (IsA(join, JoinExpr)) { JoinExpr *joinExpr = (JoinExpr *) join; - distRTEEqualityQuals = list_concat(distRTEEqualityQuals, - FetchEqualityAttrNumsForRTEFromQuals( - joinExpr->quals, - rangeTableEntryDetails-> - rteIndex) - ); + List *joinExprEqualityQuals = FetchEqualityAttrNumsForRTEFromQuals( + joinExpr->quals, rteIndex); + rteEqualityQuals = list_concat(rteEqualityQuals, joinExprEqualityQuals); } } - bool hasUniqueFilter = HasUniqueFilter( - rangeTableEntryDetails->rangeTableEntry, - rangeTableEntryDetails-> - restrictionList, distRTEEqualityQuals); - return hasUniqueFilter; -} - - -/* - * HasUniqueFilter returns true if the given RTE has a unique filter - * on a column, which is a member of the given requiredAttrNumbersForDistRTE. - */ -static bool -HasUniqueFilter(RangeTblEntry *distRTE, List *distRTERestrictionList, - List *requiredAttrNumbersForDistRTE) -{ - List *uniqueIndexes = ExecuteFunctionOnEachTableIndex(distRTE->relid, + List *uniqueIndexes = ExecuteFunctionOnEachTableIndex(rangeTableEntry->relid, GetAllUniqueIndexes); int columnNumber = 0; foreach_int(columnNumber, uniqueIndexes) { - if (list_member_int(requiredAttrNumbersForDistRTE, columnNumber)) + if (list_member_int(rteEqualityQuals, columnNumber)) { return true; } @@ -450,7 +445,8 @@ RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, * be converted to a subquery so that citus planners can work. */ static ConversionCandidates * -CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, +CreateConversionCandidates(FromExpr *joinTree, + PlannerRestrictionContext *plannerRestrictionContext, List *rangeTableList, Oid resultRelationId) { ConversionCandidates *conversionCandidates = palloc0( @@ -487,6 +483,9 @@ CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, rangeTableEntry, plannerRestrictionContext, 1); rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation( rangeTableEntry, plannerRestrictionContext); + rangeTableEntryDetails->hasUniqueIndex = HasUniqueIndex(joinTree, + rangeTableEntry, + rteIndex); if (referenceOrDistributedTable) { diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 406333f8e..dec40c41a 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -221,8 +221,8 @@ CreateModifyPlan(Query *originalQuery, Query *query, distributedPlan->modLevel = RowModifyLevelForQuery(query); distributedPlan->planningError = ModifyQuerySupported(query, originalQuery, - multiShardQuery, - plannerRestrictionContext); + multiShardQuery, + plannerRestrictionContext); if (distributedPlan->planningError != NULL) { diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index cac80f824..03c4f1e32 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1506,7 +1506,7 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) { containsDistributedTable = true; } - else if (IsLocalTableRteOrMatView((Node*) rangeTableEntry)) + else if (IsLocalTableRteOrMatView((Node *) rangeTableEntry)) { /* we consider citus local tables as local table */ containsLocalTable = true; @@ -1542,7 +1542,8 @@ ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) continue; } - if (IsLocalTableRteOrMatView((Node*) rangeTableEntry) && rangeTableEntry->relid != resultRelationId) + if (IsLocalTableRteOrMatView((Node *) rangeTableEntry) && + rangeTableEntry->relid != resultRelationId) { containsLocalTable = true; } @@ -1675,6 +1676,7 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) subquery->targetList = lappend(subquery->targetList, targetEntry); } } + /* * If tupleDesc is NULL we have 2 different cases: * @@ -1724,6 +1726,7 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) columnType = list_nth_oid(rangeTblFunction->funccoltypes, targetColumnIndex); } + /* use the types in the function definition otherwise */ else { diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index b9a6018e0..84f19a909 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -289,6 +289,51 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +-- the conversions should be independent from the order of table entries in the query +SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; +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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join distributed_table_pkey using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; +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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM postgres_table join distributed_table using(key) join local_partitioned_table using(key) join distributed_table_pkey using(key) where distributed_table_pkey.key = 5; +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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) join postgres_table using(key) join local_partitioned_table using(key) where distributed_table_pkey.key = 5; +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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table_pkey JOIN local_table_join.distributed_table USING (key)) 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)) postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; DEBUG: Wrapping local relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 788d053bb..422c64f95 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -85,6 +85,12 @@ SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); +-- the conversions should be independent from the order of table entries in the query +SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; +SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join distributed_table_pkey using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; +SELECT COUNT(*) FROM postgres_table join distributed_table using(key) join local_partitioned_table using(key) join distributed_table_pkey using(key) where distributed_table_pkey.key = 5; +SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) join postgres_table using(key) join local_partitioned_table using(key) where distributed_table_pkey.key = 5; + -- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; From 7e9204eba982099ab0f056e7448acdcae8becc90 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 2 Dec 2020 12:28:25 +0300 Subject: [PATCH 19/37] Update vars in quals while wrapping RTE to subquery When we wrap an RTE to subquery we are updating the variables varno's as 1, however we should also update the varno's of vars in quals. Also some other small code quality improvements are done. --- .../planner/local_distributed_join_planner.c | 63 ++++++++----------- .../distributed/planner/recursive_planning.c | 47 +++++++++++++- .../regress/expected/local_table_join.out | 27 ++++++++ src/test/regress/sql/local_table_join.sql | 5 ++ 4 files changed, 104 insertions(+), 38 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index e0b74b409..e36d9f0dc 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -60,7 +60,7 @@ typedef struct RangeTableEntryDetails Index rteIndex; List *restrictionList; List *requiredAttributeNumbers; - bool hasUniqueIndex; + bool hasConstantFilterOnUniqueColumn; } RangeTableEntryDetails; typedef struct ConversionCandidates @@ -69,13 +69,13 @@ typedef struct ConversionCandidates List *localTableList; /* local or citus local table */ }ConversionCandidates; -static Oid GetResultRelationId(Query *query); static bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, Oid resultRelationId, PlannerRestrictionContext * plannerRestrictionContext); -static bool HasUniqueIndex(FromExpr *joinTree, - RangeTblEntry *rangeTableEntry, Index rteIndex); +static bool HasConstantFilterOnUniqueColumn(FromExpr *joinTree, + RangeTblEntry *rangeTableEntry, Index + rteIndex); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, PlannerRestrictionContext * plannerRestrictionContext); @@ -113,7 +113,12 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, &rangeTableList); - Oid resultRelationId = GetResultRelationId(query); + Oid resultRelationId = InvalidOid; + if (IsModifyCommand(query)) + { + resultRelationId = ModifyQueryResultRelationId(query); + } + if (!ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, resultRelationId, plannerRestrictionContext)) { @@ -125,7 +130,7 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, RangeTableEntryDetails *rangeTableEntryDetails = GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, - context->plannerRestrictionContext, + plannerRestrictionContext, resultRelationId); while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, @@ -135,38 +140,20 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, ReplaceRTERelationWithRteSubquery( rangeTableEntryDetails->rangeTableEntry, rangeTableEntryDetails->restrictionList, - rangeTableEntryDetails-> - requiredAttributeNumbers, + rangeTableEntryDetails->requiredAttributeNumbers, context); - RemoveFromConversionCandidates(conversionCandidates, - rangeTableEntryDetails-> - rangeTableEntry->relid); + RemoveFromConversionCandidates( + conversionCandidates, + rangeTableEntryDetails->rangeTableEntry->relid); rangeTableEntryDetails = GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, - context->plannerRestrictionContext, + plannerRestrictionContext, resultRelationId); } } -/* - * GetResultRelationId gets the result relation id from query - * if it exists. - */ -static Oid -GetResultRelationId(Query *query) -{ - RangeTblEntry *resultRelation = ExtractResultRelationRTE(query); - Oid resultRelationId = InvalidOid; - if (resultRelation) - { - resultRelationId = resultRelation->relid; - } - return resultRelationId; -} - - /* * GetRangeTableEntriesFromJoinTree gets the range table entries that are * on the given join tree. @@ -269,7 +256,7 @@ AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList) RangeTableEntryDetails *rangeTableEntryDetails = NULL; foreach_ptr(rangeTableEntryDetails, rangeTableEntryDetailsList) { - if (!rangeTableEntryDetails->hasUniqueIndex) + if (!rangeTableEntryDetails->hasConstantFilterOnUniqueColumn) { return false; } @@ -329,11 +316,12 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, /* - * HasUniqueIndex returns true if the given rangeTableEntry has a constant + * HasConstantFilterOnUniqueColumn returns true if the given rangeTableEntry has a constant * filter on a unique column. */ static bool -HasUniqueIndex(FromExpr *joinTree, RangeTblEntry *rangeTableEntry, Index rteIndex) +HasConstantFilterOnUniqueColumn(FromExpr *joinTree, RangeTblEntry *rangeTableEntry, Index + rteIndex) { if (rangeTableEntry == NULL) { @@ -348,8 +336,8 @@ HasUniqueIndex(FromExpr *joinTree, RangeTblEntry *rangeTableEntry, Index rteInde if (IsA(join, JoinExpr)) { JoinExpr *joinExpr = (JoinExpr *) join; - List *joinExprEqualityQuals = FetchEqualityAttrNumsForRTEFromQuals( - joinExpr->quals, rteIndex); + List *joinExprEqualityQuals = + FetchEqualityAttrNumsForRTEFromQuals(joinExpr->quals, rteIndex); rteEqualityQuals = list_concat(rteEqualityQuals, joinExprEqualityQuals); } } @@ -483,9 +471,10 @@ CreateConversionCandidates(FromExpr *joinTree, rangeTableEntry, plannerRestrictionContext, 1); rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation( rangeTableEntry, plannerRestrictionContext); - rangeTableEntryDetails->hasUniqueIndex = HasUniqueIndex(joinTree, - rangeTableEntry, - rteIndex); + rangeTableEntryDetails->hasConstantFilterOnUniqueColumn = + HasConstantFilterOnUniqueColumn(joinTree, + rangeTableEntry, + rteIndex); if (referenceOrDistributedTable) { diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 03c4f1e32..083eef214 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -185,6 +185,7 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); +static void UpdateVarNosInQualForSubquery(Node *node); /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. @@ -1360,6 +1361,7 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); Expr *andedBoundExpressions = make_ands_explicit(restrictionList); subquery->jointree->quals = (Node *) andedBoundExpressions; + UpdateVarNosInQualForSubquery(subquery->jointree->quals); /* force recursively planning of the newly created subquery */ subquery->limitOffset = (Node *) MakeIntegerConst(0); @@ -1379,7 +1381,8 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict { StringInfo subqueryString = makeStringInfo(); - pg_get_query_def(subquery, subqueryString); + pg_get_query_def(subquery, + subqueryString); ereport(DEBUG1, (errmsg("Wrapping local relation \"%s\" to a subquery: %s ", get_rel_name(rangeTableEntry->relid), @@ -1389,6 +1392,48 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict } +/* + * UpdateVarNosInQualForSubquery iterates the Vars in the + * given quals node and updates the varno's as 1 as there + * will be only one RTE in rtable, which is the subquery. + */ +static void +UpdateVarNosInQualForSubquery(Node *node) +{ + if (node == NULL) + { + return; + } + + if (IsA(node, Var)) + { + Var *var = (Var *) node; + + /* we update the varno as 1 as there is only one subquery */ + var->varno = 1; + } + else if (IsA(node, OpExpr)) + { + OpExpr *opExpr = (OpExpr *) node; + Var *leftColumn = LeftColumnOrNULL(opExpr); + Var *rightColumn = RightColumnOrNULL(opExpr); + UpdateVarNosInQualForSubquery((Node *) leftColumn); + UpdateVarNosInQualForSubquery((Node *) rightColumn); + } + else if (IsA(node, BoolExpr)) + { + BoolExpr *boolExpr = (BoolExpr *) node; + List *argumentList = boolExpr->args; + + Node *arg = NULL; + foreach_ptr(arg, argumentList) + { + UpdateVarNosInQualForSubquery(arg); + } + } +} + + /* * ContainsTableToBeConvertedToSubquery checks if the given range table list contains * any table that should be converted to a subquery, which otherwise is not plannable. diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 84f19a909..ce796af90 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -334,6 +334,33 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +SELECT count(*) FROM (SELECT *, random() FROM distributed_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; +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 ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) 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, random() AS random 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; +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 ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, random() AS random FROM local_table_join.distributed_table_pkey) 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; +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 ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; DEBUG: Wrapping local relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 422c64f95..5d38db1ea 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -91,6 +91,11 @@ SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join SELECT COUNT(*) FROM postgres_table join distributed_table using(key) join local_partitioned_table using(key) join distributed_table_pkey using(key) where distributed_table_pkey.key = 5; SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) join postgres_table using(key) join local_partitioned_table using(key) where distributed_table_pkey.key = 5; +SELECT count(*) FROM (SELECT *, random() FROM distributed_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; +SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; +SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; + + -- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; From 4b6611460a830c1d34b643d1a4c3bd79e09e9eeb Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 2 Dec 2020 14:31:11 +0300 Subject: [PATCH 20/37] Support foreign table joins as well --- .../distributed/planner/recursive_planning.c | 3 ++- .../regress/expected/local_table_join.out | 22 ++++++++++++++++++- src/test/regress/sql/local_table_join.sql | 15 +++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 083eef214..5f85df5cc 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1522,7 +1522,8 @@ IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry) } return rangeTableEntry->relkind == RELKIND_PARTITIONED_TABLE || rangeTableEntry->relkind == RELKIND_RELATION || - rangeTableEntry->relkind == RELKIND_MATVIEW; + rangeTableEntry->relkind == RELKIND_MATVIEW || + rangeTableEntry->relkind == RELKIND_FOREIGN_TABLE; } diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index ce796af90..4f9ae31c8 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -49,6 +49,16 @@ SELECT create_distributed_table('distributed_table_composite', 'key'); (1 row) +CREATE FUNCTION fake_fdw_handler() +RETURNS fdw_handler +AS 'citus' +LANGUAGE C STRICT; +CREATE FOREIGN DATA WRAPPER fake_fdw HANDLER fake_fdw_handler; +CREATE SERVER fake_fdw_server FOREIGN DATA WRAPPER fake_fdw; +CREATE FOREIGN TABLE foreign_table ( + key int, + value text +) SERVER fake_fdw_server OPTIONS (encoding 'utf-8', compression 'true'); CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; SET client_min_messages TO DEBUG1; @@ -234,6 +244,16 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +-- foreign tables should work too +SELECT count(*) FROM foreign_table JOIN distributed_table USING(key); +DEBUG: Wrapping local relation "foreign_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) foreign_table JOIN local_table_join.distributed_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 @@ -1083,4 +1103,4 @@ SELECT master_remove_node('localhost', :master_port); \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 11 other objects +NOTICE: drop cascades to 15 other objects diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 5d38db1ea..1b5593061 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -26,6 +26,18 @@ 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 FUNCTION fake_fdw_handler() +RETURNS fdw_handler +AS 'citus' +LANGUAGE C STRICT; +CREATE FOREIGN DATA WRAPPER fake_fdw HANDLER fake_fdw_handler; +CREATE SERVER fake_fdw_server FOREIGN DATA WRAPPER fake_fdw; + +CREATE FOREIGN TABLE foreign_table ( + key int, + value text +) SERVER fake_fdw_server OPTIONS (encoding 'utf-8', compression 'true'); + CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; @@ -76,6 +88,9 @@ 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); +-- foreign tables should work too +SELECT count(*) FROM foreign_table JOIN distributed_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; From 3bd53a24a329dd1b6cf0aa382f49965fe3fa68b6 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 2 Dec 2020 16:54:15 +0300 Subject: [PATCH 21/37] Support update on postgres table from citus local table --- .../distributed/planner/multi_router_planner.c | 12 ++++++++---- src/backend/distributed/planner/recursive_planning.c | 2 -- src/test/regress/expected/local_table_join.out | 2 ++ src/test/regress/sql/local_table_join.sql | 4 ++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index dec40c41a..257c6d24c 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -1940,10 +1940,12 @@ SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, RangeTblEntry *updateOrDeleteRTE = ExtractResultRelationRTE(query); Assert(updateOrDeleteRTE != NULL); - CitusTableCacheEntry *modificationTableCacheEntry = GetCitusTableCacheEntry( - updateOrDeleteRTE->relid); + CitusTableCacheEntry *modificationTableCacheEntry = NULL; + if (IsCitusTable(updateOrDeleteRTE->relid)) { + modificationTableCacheEntry = GetCitusTableCacheEntry(updateOrDeleteRTE->relid); + } - if (IsCitusTableTypeCacheEntry(modificationTableCacheEntry, REFERENCE_TABLE) && + if (IsCitusTableType(updateOrDeleteRTE->relid, REFERENCE_TABLE) && SelectsFromDistributedTable(rangeTableList, query)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -1952,7 +1954,9 @@ SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, } taskType = MODIFY_TASK; - replicationModel = modificationTableCacheEntry->replicationModel; + if (modificationTableCacheEntry) { + replicationModel = modificationTableCacheEntry->replicationModel; + } } if (taskType == READ_TASK && query->hasModifyingCTE) diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 5f85df5cc..581635576 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1453,11 +1453,9 @@ ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) { return true; } - return false; } - /* * AllDataLocallyAccessible return true if all data for the relations in the * rangeTableList is locally accessible. diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 4f9ae31c8..2deab459c 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -1080,6 +1080,8 @@ ERROR: relation postgres_table is not distributed UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) l WHERE (l.key OPERATOR(pg_catalog.=) 10) +UPDATE citus_local SET key = 1 FROM postgres_table WHERE citus_local.key = 10; +UPDATE postgres_table SET key = 1 FROM citus_local WHERE citus_local.key = 10; -- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? -- though then the planner could give an error SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 1b5593061..10c5fdcd9 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -418,6 +418,10 @@ SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distribut UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; +UPDATE citus_local SET key = 1 FROM postgres_table WHERE citus_local.key = 10; +UPDATE postgres_table SET key = 1 FROM citus_local WHERE citus_local.key = 10; + + -- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? -- though then the planner could give an error SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; From 26d9f0b457992529a03ba842be5194266a12e5d9 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 2 Dec 2020 20:29:27 +0300 Subject: [PATCH 22/37] Use auto mode in tests and fix debug message --- .../distributed/metadata/metadata_cache.c | 15 - .../planner/local_distributed_join_planner.c | 63 ++--- .../planner/multi_router_planner.c | 21 +- .../distributed/planner/recursive_planning.c | 193 ++++++++----- .../relation_restriction_equivalence.c | 7 +- src/backend/distributed/shared_library_init.c | 1 + .../local_distributed_join_planner.h | 18 +- src/include/distributed/metadata_cache.h | 1 - src/include/distributed/recursive_planning.h | 13 +- .../relation_restriction_equivalence.h | 4 +- .../expected/citus_local_tables_queries.out | 10 +- .../citus_local_tables_queries_mx.out | 74 +++-- src/test/regress/expected/dml_recursive.out | 2 +- .../regress/expected/local_table_join.out | 266 +++++++++--------- .../regress/expected/materialized_view.out | 27 +- .../regress/expected/mixed_relkind_tests.out | 24 +- ...relation_planning_restirction_pushdown.out | 58 ++-- src/test/regress/multi_schedule | 4 +- src/test/regress/sql/local_table_join.sql | 12 +- 19 files changed, 460 insertions(+), 353 deletions(-) diff --git a/src/backend/distributed/metadata/metadata_cache.c b/src/backend/distributed/metadata/metadata_cache.c index 83fbad1bc..1e5ebac6a 100644 --- a/src/backend/distributed/metadata/metadata_cache.c +++ b/src/backend/distributed/metadata/metadata_cache.c @@ -293,21 +293,6 @@ EnsureModificationsCanRun(void) } -/* - * IsLocalOrCitusLocalTable returns true if the given relation - * is either a local or citus local table. - */ -bool -IsLocalOrCitusLocalTable(Oid relationId) -{ - if (!IsCitusTable(relationId)) - { - return true; - } - return IsCitusTableType(relationId, CITUS_LOCAL_TABLE); -} - - /* * IsCitusTableType returns true if the given table with relationId * belongs to a citus table that matches the given table type. If cache diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index e36d9f0dc..8e03fd6d8 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -54,6 +54,12 @@ #include "utils/guc.h" #include "utils/lsyscache.h" + +/* + * Managed via a GUC + */ +int LocalTableJoinPolicy = LOCAL_JOIN_POLICY_AUTO; + typedef struct RangeTableEntryDetails { RangeTblEntry *rangeTableEntry; @@ -89,8 +95,7 @@ static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree ConversionCandidates * conversionCandidates, PlannerRestrictionContext * - plannerRestrictionContext, - Oid resultRelationId); + plannerRestrictionContext); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, List **joinRangeTableEntries); static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid @@ -98,13 +103,13 @@ static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandi static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList); /* - * ConvertUnplannableTableJoinsToSubqueries gets a query and the planner + * RecursivelyPlanLocalTableJoins gets a query and the planner * restrictions. As long as the query is not plannable by router planner, * it converts either a local or distributed table to a subquery. */ void -ConvertUnplannableTableJoinsToSubqueries(Query *query, - RecursivePlanningContext *context) +RecursivelyPlanLocalTableJoins(Query *query, + RecursivePlanningContext *context) { PlannerRestrictionContext *plannerRestrictionContext = context->plannerRestrictionContext; @@ -128,28 +133,22 @@ ConvertUnplannableTableJoinsToSubqueries(Query *query, CreateConversionCandidates(query->jointree, plannerRestrictionContext, rangeTableList, resultRelationId); - RangeTableEntryDetails *rangeTableEntryDetails = - GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, - plannerRestrictionContext, - resultRelationId); - while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, resultRelationId, plannerRestrictionContext)) { - ReplaceRTERelationWithRteSubquery( - rangeTableEntryDetails->rangeTableEntry, - rangeTableEntryDetails->restrictionList, - rangeTableEntryDetails->requiredAttributeNumbers, - context); - RemoveFromConversionCandidates( - conversionCandidates, - rangeTableEntryDetails->rangeTableEntry->relid); + FromExpr *joinTree = query->jointree; + RangeTableEntryDetails *rangeTableEntryDetails = + GetNextRTEToConvertToSubquery(joinTree, conversionCandidates, + plannerRestrictionContext); - rangeTableEntryDetails = - GetNextRTEToConvertToSubquery(query->jointree, conversionCandidates, - plannerRestrictionContext, - resultRelationId); + RangeTblEntry *rangeTableEntry = rangeTableEntryDetails->rangeTableEntry; + Oid relId = rangeTableEntryDetails->rangeTableEntry->relid; + List *restrictionList = rangeTableEntryDetails->restrictionList; + List *requiredAttributeNumbers = rangeTableEntryDetails->requiredAttributeNumbers; + ReplaceRTERelationWithRteSubquery(rangeTableEntry, restrictionList, + requiredAttributeNumbers, context); + RemoveFromConversionCandidates(conversionCandidates, relId); } } @@ -206,8 +205,7 @@ GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree, ConversionCandidates *conversionCandidates, - PlannerRestrictionContext *plannerRestrictionContext, Oid - resultRelationId) + PlannerRestrictionContext *plannerRestrictionContext) { RangeTableEntryDetails *localRTECandidate = NULL; RangeTableEntryDetails *distributedRTECandidate = NULL; @@ -272,7 +270,7 @@ AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList) static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid relationId) { - if (IsLocalOrCitusLocalTable(relationId)) + if (IsRelationLocalTableOrMatView(relationId)) { conversionCandidates->localTableList = list_delete_first(conversionCandidates->localTableList); @@ -452,23 +450,18 @@ CreateConversionCandidates(FromExpr *joinTree, continue; } - bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, - REFERENCE_TABLE) || - IsCitusTableType(rangeTableEntry->relid, - DISTRIBUTED_TABLE); - /* result relation cannot converted to a subquery */ if (resultRelationId == rangeTableEntry->relid) { continue; } - RangeTableEntryDetails *rangeTableEntryDetails = palloc0( - sizeof(RangeTableEntryDetails)); + RangeTableEntryDetails *rangeTableEntryDetails = + palloc0(sizeof(RangeTableEntryDetails)); rangeTableEntryDetails->rangeTableEntry = rangeTableEntry; rangeTableEntryDetails->rteIndex = rteIndex; rangeTableEntryDetails->restrictionList = GetRestrictInfoListForRelation( - rangeTableEntry, plannerRestrictionContext, 1); + rangeTableEntry, plannerRestrictionContext); rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation( rangeTableEntry, plannerRestrictionContext); rangeTableEntryDetails->hasConstantFilterOnUniqueColumn = @@ -476,6 +469,10 @@ CreateConversionCandidates(FromExpr *joinTree, rangeTableEntry, rteIndex); + bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, + REFERENCE_TABLE) || + IsCitusTableType(rangeTableEntry->relid, + DISTRIBUTED_TABLE); if (referenceOrDistributedTable) { conversionCandidates->distributedTableList = diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 257c6d24c..8f0ae7fb3 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -310,6 +310,16 @@ IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionCon return false; } + if (IsModifyCommand(query)) + { + deferredErrorMessage = ModifyQuerySupported(copyQuery, copyQuery, false, + plannerRestrictionContext); + if (deferredErrorMessage) + { + return false; + } + } + /* TODO:: we might not need this copy*/ copyQuery = copyObject(query); RouterJob(copyQuery, plannerRestrictionContext, &deferredErrorMessage); @@ -896,7 +906,7 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer /* for other kinds of relations, check if its distributed */ else { - if (IsLocalOrCitusLocalTable(rangeTableEntry->relid) && + if (IsRelationLocalTableOrMatView(rangeTableEntry->relid) && containsTableToBeConvertedToSubquery) { StringInfo errorMessage = makeStringInfo(); @@ -1941,8 +1951,10 @@ SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, Assert(updateOrDeleteRTE != NULL); CitusTableCacheEntry *modificationTableCacheEntry = NULL; - if (IsCitusTable(updateOrDeleteRTE->relid)) { - modificationTableCacheEntry = GetCitusTableCacheEntry(updateOrDeleteRTE->relid); + if (IsCitusTable(updateOrDeleteRTE->relid)) + { + modificationTableCacheEntry = GetCitusTableCacheEntry( + updateOrDeleteRTE->relid); } if (IsCitusTableType(updateOrDeleteRTE->relid, REFERENCE_TABLE) && @@ -1954,7 +1966,8 @@ SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, } taskType = MODIFY_TASK; - if (modificationTableCacheEntry) { + if (modificationTableCacheEntry) + { replicationModel = modificationTableCacheEntry->replicationModel; } } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 581635576..1ef1371a3 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -100,13 +100,6 @@ #include "utils/guc.h" #include "utils/lsyscache.h" - -/* - * Managed via a GUC - */ -int LocalTableJoinPolicy = LOCAL_JOIN_POLICY_AUTO; - - /* track depth of current recursive planner query */ static int recursivePlanningDepth = 0; @@ -164,6 +157,7 @@ static bool AllDistributionKeysInSubqueryAreEqual(Query *subquery, PlannerRestrictionContext * restrictionContext); static bool AllDataLocallyAccessible(List *rangeTableList); +static bool IsTableLocallyAccessible(Oid relationId); static bool ShouldRecursivelyPlanSetOperation(Query *query, RecursivePlanningContext *context); static void RecursivelyPlanSubquery(Query *subquery, @@ -185,7 +179,10 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); -static void UpdateVarNosInQualForSubquery(Node *node); +static void UpdateVarNosInQualForSubquery(Query *query); +static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList, Oid + resultRelationId); +static bool ContainsOnlyReferenceAndCitusLocalRelation(List *rangeTableList); /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. @@ -344,9 +341,11 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context /* * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or * a query with local table/citus local table and subquery. We convert local/citus local - * tables to a subquery until they can be planned + * tables to a subquery until they can be planned. + * This is the last call in this function since we want the other calls to be finished + * so that we can check if the current plan is router plannable at any step within this function. */ - ConvertUnplannableTableJoinsToSubqueries(query, context); + RecursivelyPlanLocalTableJoins(query, context); return NULL; } @@ -1087,6 +1086,17 @@ IsLocalTableRteOrMatView(Node *node) } Oid relationId = rangeTableEntry->relid; + return IsRelationLocalTableOrMatView(relationId); +} + + +/* + * IsRelationLocalTableOrMatView returns true if the given relation + * is a citus local, local, or materialized view. + */ +bool +IsRelationLocalTableOrMatView(Oid relationId) +{ if (!IsCitusTable(relationId)) { /* postgres local table or a materialized view */ @@ -1361,7 +1371,7 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); Expr *andedBoundExpressions = make_ands_explicit(restrictionList); subquery->jointree->quals = (Node *) andedBoundExpressions; - UpdateVarNosInQualForSubquery(subquery->jointree->quals); + UpdateVarNosInQualForSubquery(subquery); /* force recursively planning of the newly created subquery */ subquery->limitOffset = (Node *) MakeIntegerConst(0); @@ -1384,7 +1394,7 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict pg_get_query_def(subquery, subqueryString); - ereport(DEBUG1, (errmsg("Wrapping local relation \"%s\" to a subquery: %s ", + ereport(DEBUG1, (errmsg("Wrapping relation \"%s\" to a subquery: %s ", get_rel_name(rangeTableEntry->relid), ApplyLogRedaction(subqueryString->data)))); } @@ -1398,38 +1408,14 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict * will be only one RTE in rtable, which is the subquery. */ static void -UpdateVarNosInQualForSubquery(Node *node) +UpdateVarNosInQualForSubquery(Query *query) { - if (node == NULL) + List *varList = pull_var_clause(query->jointree->quals, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_PLACEHOLDERS); + Var *var = NULL; + foreach_ptr(var, varList) { - return; - } - - if (IsA(node, Var)) - { - Var *var = (Var *) node; - - /* we update the varno as 1 as there is only one subquery */ - var->varno = 1; - } - else if (IsA(node, OpExpr)) - { - OpExpr *opExpr = (OpExpr *) node; - Var *leftColumn = LeftColumnOrNULL(opExpr); - Var *rightColumn = RightColumnOrNULL(opExpr); - UpdateVarNosInQualForSubquery((Node *) leftColumn); - UpdateVarNosInQualForSubquery((Node *) rightColumn); - } - else if (IsA(node, BoolExpr)) - { - BoolExpr *boolExpr = (BoolExpr *) node; - List *argumentList = boolExpr->args; - - Node *arg = NULL; - foreach_ptr(arg, argumentList) - { - UpdateVarNosInQualForSubquery(arg); - } + var->varno = SINGLE_RTE_INDEX; } } @@ -1445,6 +1431,10 @@ ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) { return false; } + if (ContainsOnlyReferenceAndCitusLocalRelation(rangeTableList)) + { + return false; + } if (ContainsLocalTableDistributedTableJoin(rangeTableList)) { return true; @@ -1453,9 +1443,48 @@ ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) { return true; } + if (ModifiesLocalTableWithRemoteCitusLocalTable(rangeTableList, resultRelationId)) + { + return true; + } return false; } + +/* + * ModifiesLocalTableWithRemoteCitusLocalTable returns true if a local + * table is modified with a remote citus local table. This could be a case with + * MX structure. + */ +static bool +ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList, Oid resultRelationId) +{ + bool containsLocalResultRelation = false; + bool containsRemoteCitusLocalTable = false; + + RangeTblEntry *rangeTableEntry = NULL; + foreach_ptr(rangeTableEntry, rangeTableList) + { + if (!IsRecursivelyPlannableRelation(rangeTableEntry)) + { + continue; + } + if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE)) + { + if (!IsTableLocallyAccessible(rangeTableEntry->relid)) + { + containsRemoteCitusLocalTable = true; + } + } + else if (!IsCitusTable(rangeTableEntry->relid)) + { + containsLocalResultRelation = true; + } + } + return containsLocalResultRelation && containsRemoteCitusLocalTable; +} + + /* * AllDataLocallyAccessible return true if all data for the relations in the * rangeTableList is locally accessible. @@ -1476,29 +1505,9 @@ AllDataLocallyAccessible(List *rangeTableList) continue; } - Oid relationId = rangeTableEntry->relid; - - if (!IsCitusTable(relationId)) + if (!IsTableLocallyAccessible(relationId)) { - /* local tables are locally accessible */ - continue; - } - - List *shardIntervalList = LoadShardIntervalList(relationId); - if (list_length(shardIntervalList) != 1) - { - /* we currently only consider single placement tables */ - return false; - } - - ShardInterval *shardInterval = linitial(shardIntervalList); - uint64 shardId = shardInterval->shardId; - ShardPlacement *localShardPlacement = - ShardPlacementOnGroup(shardId, GetLocalGroupId()); - if (localShardPlacement == NULL) - { - /* the table doesn't have a placement on this node */ return false; } } @@ -1507,6 +1516,38 @@ AllDataLocallyAccessible(List *rangeTableList) } +/* + * IsTableLocallyAccessible returns true if the given table + * can be accessed in local. + */ +static bool +IsTableLocallyAccessible(Oid relationId) +{ + if (!IsCitusTable(relationId)) + { + /* local tables are locally accessible */ + return true; + } + + List *shardIntervalList = LoadShardIntervalList(relationId); + if (list_length(shardIntervalList) != 1) + { + return false; + } + + ShardInterval *shardInterval = linitial(shardIntervalList); + uint64 shardId = shardInterval->shardId; + ShardPlacement *localShardPlacement = + ShardPlacementOnGroup(shardId, GetLocalGroupId()); + if (localShardPlacement != NULL) + { + /* the table has a placement on this node */ + return true; + } + return false; +} + + /* * IsRecursivelyPlannableRelation returns true if the given range table entry * is a relation type that can be converted to a subquery. @@ -1561,6 +1602,32 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) } +/* + * ContainsOnlyReferenceAndCitusLocalRelation returns true if there is no + * relation other than citus local and reference tables + */ +static bool +ContainsOnlyReferenceAndCitusLocalRelation(List *rangeTableList) +{ + RangeTblEntry *rangeTableEntry = NULL; + foreach_ptr(rangeTableEntry, rangeTableList) + { + if (!IsRecursivelyPlannableRelation(rangeTableEntry)) + { + continue; + } + + if (!IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE) && + !IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE)) + { + return false; + } + } + + return true; +} + + /* * ContainsLocalTableSubqueryJoin returns true if the input range table list * contains a direct join between local table/citus local table and subquery. diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index 64620ef4f..c9b86163f 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -1850,8 +1850,7 @@ FilterPlannerRestrictionForQuery(PlannerRestrictionContext *plannerRestrictionCo */ List * GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, - PlannerRestrictionContext *plannerRestrictionContext, - int rteIndex) + PlannerRestrictionContext *plannerRestrictionContext) { int rteIdentity = GetRTEIdentity(rangeTblEntry); RelationRestrictionContext *relationRestrictionContext = @@ -1913,8 +1912,8 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, Var *column = NULL; foreach_ptr(column, varClauses) { - column->varno = rteIndex; - column->varnosyn = rteIndex; + column->varno = SINGLE_RTE_INDEX; + column->varnosyn = SINGLE_RTE_INDEX; } restrictExprList = lappend(restrictExprList, copyOfRestrictClause); diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index d93c77962..c1b4a7b0b 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -38,6 +38,7 @@ #include "distributed/insert_select_executor.h" #include "distributed/intermediate_result_pruning.h" #include "distributed/local_executor.h" +#include "distributed/local_distributed_join_planner.h" #include "distributed/locally_reserved_shared_connections.h" #include "distributed/maintenanced.h" #include "distributed/metadata_utility.h" diff --git a/src/include/distributed/local_distributed_join_planner.h b/src/include/distributed/local_distributed_join_planner.h index 1fc7269a6..690999bb2 100644 --- a/src/include/distributed/local_distributed_join_planner.h +++ b/src/include/distributed/local_distributed_join_planner.h @@ -1,9 +1,9 @@ /*------------------------------------------------------------------------- * - * listutils.h + * local_distributed_join_planner.h * - * Declarations for public utility functions related to lists. + * Declarations for functions to handle local-distributed table joins. * * Copyright (c) Citus Data, Inc. * @@ -16,8 +16,18 @@ #include "postgres.h" #include "distributed/recursive_planning.h" +/* managed via guc.c */ +typedef enum +{ + LOCAL_JOIN_POLICY_NEVER = 0, + LOCAL_JOIN_POLICY_PREFER_LOCAL = 1, + LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED = 2, + LOCAL_JOIN_POLICY_AUTO = 3, +} LocalJoinPolicy; -extern void ConvertUnplannableTableJoinsToSubqueries(Query *query, - RecursivePlanningContext *context); +extern int LocalTableJoinPolicy; + +extern void RecursivelyPlanLocalTableJoins(Query *query, + RecursivePlanningContext *context); #endif /* LOCAL_DISTRIBUTED_JOIN_PLANNER_H */ diff --git a/src/include/distributed/metadata_cache.h b/src/include/distributed/metadata_cache.h index 50d9bf251..36a0a5d23 100644 --- a/src/include/distributed/metadata_cache.h +++ b/src/include/distributed/metadata_cache.h @@ -135,7 +135,6 @@ typedef enum } CitusTableType; -extern bool IsLocalOrCitusLocalTable(Oid relationId); extern bool IsCitusTableType(Oid relationId, CitusTableType tableType); extern bool IsCitusTableTypeCacheEntry(CitusTableCacheEntry *tableEtnry, CitusTableType tableType); diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index a88e14bc2..f58fa48f5 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -22,17 +22,6 @@ #include "nodes/relation.h" #endif -/* managed via guc.c */ -typedef enum -{ - LOCAL_JOIN_POLICY_NEVER = 0, - LOCAL_JOIN_POLICY_PREFER_LOCAL = 1, - LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED = 2, - LOCAL_JOIN_POLICY_AUTO = 3, -} LocalJoinPolicy; - -extern int LocalTableJoinPolicy; - /* * RecursivePlanningContext is used to recursively plan subqueries * and CTEs, pull results to the coordinator, and push it back into @@ -68,5 +57,5 @@ extern bool ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelat extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId); extern bool IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry); - +extern bool IsRelationLocalTableOrMatView(Oid relationId); #endif /* RECURSIVE_PLANNING_H */ diff --git a/src/include/distributed/relation_restriction_equivalence.h b/src/include/distributed/relation_restriction_equivalence.h index 4c1406f8e..4aed46a2c 100644 --- a/src/include/distributed/relation_restriction_equivalence.h +++ b/src/include/distributed/relation_restriction_equivalence.h @@ -15,6 +15,8 @@ #include "distributed/distributed_planner.h" #include "distributed/metadata_cache.h" +#define SINGLE_RTE_INDEX 1 + extern bool AllDistributionKeysInQueryAreEqual(Query *originalQuery, PlannerRestrictionContext * plannerRestrictionContext); @@ -38,7 +40,7 @@ extern PlannerRestrictionContext * FilterPlannerRestrictionForQuery( Query *query); extern List * GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, PlannerRestrictionContext * - plannerRestrictionContext, int rteIndex); + plannerRestrictionContext); extern JoinRestrictionContext * RemoveDuplicateJoinRestrictions(JoinRestrictionContext * joinRestrictionContext); diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 5640fe7ca..973237f85 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -688,12 +688,12 @@ NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_l DELETE FROM postgres_local_table USING citus_local_table WHERE citus_local_table.b = postgres_local_table.b; -ERROR: relation postgres_local_table is not distributed +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.postgres_local_table USING citus_local_table_queries.citus_local_table_1509000 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; -ERROR: relation postgres_local_table is not distributed +NOTICE: executing the command locally: UPDATE citus_local_table_queries.postgres_local_table SET b = 5 FROM citus_local_table_queries.citus_local_table_1509000 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 @@ -743,8 +743,7 @@ NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.ci -- 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_1509002 reference_table -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 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))) +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT reference_table.a FROM citus_local_table_queries.reference_table_1509002 reference_table)) -- just works WITH distributed_table_cte AS (SELECT * FROM distributed_table) UPDATE citus_local_table @@ -758,8 +757,7 @@ UPDATE citus_local_table SET b = 6 FROM reference_table_cte WHERE citus_local_table.a = reference_table_cte.a; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.reference_table_1509002 reference_table -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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)) reference_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table_cte.a) +NOTICE: executing the command locally: WITH reference_table_cte AS (SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509002 reference_table) UPDATE citus_local_table_queries.citus_local_table_1509000 citus_local_table SET b = 6 FROM reference_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table_cte.a) --------------------------------------------------------------------- ----- VIEW QUERIES ----- --------------------------------------------------------------------- diff --git a/src/test/regress/expected/citus_local_tables_queries_mx.out b/src/test/regress/expected/citus_local_tables_queries_mx.out index 833699555..7791e57bc 100644 --- a/src/test/regress/expected/citus_local_tables_queries_mx.out +++ b/src/test/regress/expected/citus_local_tables_queries_mx.out @@ -126,7 +126,7 @@ WHERE cte_citus_local_table.a = 1 AND cte_distributed_table.a = 1; -- 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: direct joins between distributed and local tables are not supported +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 ( @@ -148,13 +148,21 @@ SELECT count(*) FROM ( SELECT * FROM (SELECT count(*) FROM citus_local_table, postgres_local_table) as subquery_inner ) as subquery_top; -ERROR: direct joins between distributed and local tables are not supported + 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; -ERROR: direct joins between distributed and local tables are not supported + count +--------------------------------------------------------------------- + 36 +(1 row) + -- should fail as we don't support direct joins between distributed/local tables SELECT count(*) FROM ( @@ -162,7 +170,11 @@ SELECT count(*) FROM FROM ( WITH cte_1 AS (SELECT *, random() FROM citus_local_table, distributed_table) SELECT * FROM cte_1) as subquery_inner ) as subquery_top; -ERROR: direct joins between distributed and local tables are not supported + count +--------------------------------------------------------------------- + 36 +(1 row) + -- should be fine SELECT count(*) FROM ( @@ -415,10 +427,14 @@ 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); -ERROR: direct joins between distributed and local tables are not supported + count +--------------------------------------------------------------------- + 1296 +(1 row) + -- not supported direct outer join SELECT count(*) FROM citus_local_table LEFT JOIN distributed_table ON (true); -ERROR: direct joins between distributed and local tables are not supported +ERROR: cannot pushdown the subquery -- distinct in subquery on CTE WITH one_row AS ( SELECT a from citus_local_table WHERE b = 1 @@ -458,15 +474,23 @@ LIMIT -- join between citus local tables and distributed tables would fail SELECT count(*) FROM citus_local_table, distributed_table; -ERROR: direct joins between distributed and local tables are not supported + count +--------------------------------------------------------------------- + 36 +(1 row) + SELECT * FROM citus_local_table, distributed_table ORDER BY 1,2,3,4 FOR UPDATE; -ERROR: direct joins between distributed and local tables are not supported +ERROR: could not run distributed query with FOR UPDATE/SHARE commands -- join between citus local table and postgres local table would fail -- as citus local table is on the coordinator 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; -ERROR: direct joins between distributed and local tables are not supported + count | count +--------------------------------------------------------------------- + 6 | 6 +(1 row) + -- select for update is just OK SELECT * FROM citus_local_table ORDER BY 1,2 FOR UPDATE; a | b @@ -523,7 +547,6 @@ JOIN citus_local_table ON (true); INSERT INTO reference_table SELECT reference_table.* FROM reference_table, postgres_local_table JOIN citus_local_table ON (true); -ERROR: direct joins between distributed and local tables are not supported SELECT clear_and_init_test_tables(); clear_and_init_test_tables --------------------------------------------------------------------- @@ -536,7 +559,6 @@ JOIN citus_local_table ON (true); INSERT INTO distributed_table SELECT reference_table.* FROM reference_table, postgres_local_table JOIN citus_local_table ON (true); -ERROR: direct joins between distributed and local tables are not supported INSERT INTO postgres_local_table SELECT reference_table.* FROM reference_table JOIN citus_local_table ON (true); @@ -557,7 +579,6 @@ FROM reference_table, distributed_table; INSERT INTO citus_local_table SELECT distributed_table.* FROM distributed_table JOIN citus_local_table ON (true); -ERROR: direct joins between distributed and local tables are not supported -- .. but when wrapped into a CTE, join works fine INSERT INTO citus_local_table SELECT distributed_table.* FROM distributed_table @@ -578,38 +599,31 @@ SELECT clear_and_init_test_tables(); DELETE FROM citus_local_table USING postgres_local_table WHERE citus_local_table.b = postgres_local_table.b; -ERROR: cannot plan modifications with local tables involving citus tables 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; -ERROR: cannot plan modifications with local tables involving citus tables DELETE FROM postgres_local_table USING citus_local_table WHERE citus_local_table.b = postgres_local_table.b; -ERROR: cannot plan modifications with local tables involving citus tables 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; -ERROR: cannot plan modifications with local tables involving citus tables -- no direct joins supported UPDATE distributed_table SET b = 6 FROM citus_local_table WHERE citus_local_table.a = distributed_table.a; -ERROR: cannot plan modifications with citus local tables and distributed tables UPDATE reference_table SET b = 6 FROM citus_local_table WHERE citus_local_table.a = reference_table.a; -ERROR: cannot plan modifications of reference tables with citus local tables -- 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; -ERROR: cannot plan modifications with citus local tables and distributed tables -- should work, add HINT use CTEs UPDATE citus_local_table SET b = 6 @@ -619,16 +633,13 @@ WHERE citus_local_table.a = reference_table.a; DELETE FROM distributed_table USING citus_local_table WHERE citus_local_table.a = distributed_table.a; -ERROR: cannot plan modifications with citus local tables and distributed tables -- should not work, add HINT use CTEs DELETE FROM citus_local_table USING distributed_table WHERE citus_local_table.a = distributed_table.a; -ERROR: cannot plan modifications with citus local tables and distributed tables DELETE FROM reference_table USING citus_local_table WHERE citus_local_table.a = reference_table.a; -ERROR: cannot plan modifications of reference tables with citus local tables -- should work, add HINT use CTEs DELETE FROM citus_local_table USING reference_table @@ -681,7 +692,11 @@ 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; -ERROR: direct joins between distributed and local tables are not supported + count +--------------------------------------------------------------------- + 1 +(1 row) + CREATE VIEW view_3 AS SELECT count(*) FROM citus_local_table_2 @@ -732,7 +747,16 @@ 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; -ERROR: cannot plan modifications with citus local tables and distributed tables + 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 @@ -756,7 +780,7 @@ UPDATE citus_local_table SET a=5 FROM (SELECT b FROM distributed_table) AS foo WHERE foo.b = citus_local_table.b; -ERROR: cannot plan modifications with citus local tables and distributed tables +ERROR: citus local table citus_local_table cannot be joined with these distributed tables --------------------------------------------------------------------- -- test different execution paths -- --------------------------------------------------------------------- diff --git a/src/test/regress/expected/dml_recursive.out b/src/test/regress/expected/dml_recursive.out index 4c6243b88..ff75e6277 100644 --- a/src/test/regress/expected/dml_recursive.out +++ b/src/test/regress/expected/dml_recursive.out @@ -352,7 +352,7 @@ FROM distributed_table WHERE distributed_table.tenant_id = local_table.id; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE recursive_dml_queries.local_table SET id = 'citus_test'::text FROM (SELECT intermediate_result.tenant_id, intermediate_result.dept, intermediate_result.info FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(tenant_id text, dept integer, info jsonb)) distributed_table WHERE (distributed_table.tenant_id OPERATOR(pg_catalog.=) local_table.id) RESET client_min_messages; diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 2deab459c..a52c174f2 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -53,12 +53,12 @@ CREATE FUNCTION fake_fdw_handler() RETURNS fdw_handler AS 'citus' LANGUAGE C STRICT; -CREATE FOREIGN DATA WRAPPER fake_fdw HANDLER fake_fdw_handler; -CREATE SERVER fake_fdw_server FOREIGN DATA WRAPPER fake_fdw; +CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler; +CREATE SERVER fake_fdw_server_1 FOREIGN DATA WRAPPER fake_fdw_1; CREATE FOREIGN TABLE foreign_table ( key int, value text -) SERVER fake_fdw_server OPTIONS (encoding 'utf-8', compression 'true'); +) SERVER fake_fdw_server_1 OPTIONS (encoding 'utf-8', compression 'true'); CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; SET client_min_messages TO DEBUG1; @@ -73,7 +73,7 @@ HINT: Use CTE's or subqueries to select from local tables and use them in joins -- the user prefers local table recursively planned SET citus.local_table_join_policy TO 'prefer-local'; SELECT count(*) FROM postgres_table JOIN distributed_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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) count @@ -82,7 +82,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN reference_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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.reference_table USING (key)) count @@ -93,7 +93,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- the user prefers distributed table recursively planned SET citus.local_table_join_policy TO 'prefer-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table USING (key)) count @@ -102,7 +102,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -DEBUG: Wrapping local relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table 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.reference_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) reference_table USING (key)) count @@ -117,7 +117,7 @@ SET citus.local_table_join_policy to 'auto'; -- on the auto mode, the local tables should be recursively planned -- unless a unique index exists in a column for distributed table SELECT count(*) FROM distributed_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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) count @@ -126,7 +126,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM reference_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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) count @@ -135,7 +135,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) count @@ -145,7 +145,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- partititoned local tables should work as well SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count @@ -154,7 +154,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM reference_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count @@ -163,7 +163,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count @@ -173,7 +173,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- 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: Wrapping 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 @@ -182,7 +182,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (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: Wrapping 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 @@ -191,7 +191,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (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: Wrapping 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 @@ -200,7 +200,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (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: Wrapping 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 @@ -209,7 +209,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (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: Wrapping 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 @@ -218,7 +218,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (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: Wrapping 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 @@ -227,7 +227,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (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: Wrapping 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 @@ -236,7 +236,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (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: Wrapping 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 @@ -246,7 +246,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- foreign tables should work too SELECT count(*) FROM foreign_table JOIN distributed_table USING(key); -DEBUG: Wrapping local relation "foreign_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "foreign_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true OFFSET 0 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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) foreign_table JOIN local_table_join.distributed_table USING (key)) count @@ -256,7 +256,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- 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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) count @@ -265,7 +265,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) WHERE distributed_partitioned_table.key = 10; -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 (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) count @@ -274,7 +274,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) count @@ -283,7 +283,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count @@ -292,7 +292,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) count @@ -301,7 +301,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count @@ -311,9 +311,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- the conversions should be independent from the order of table entries in the query SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; -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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count @@ -322,9 +322,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join distributed_table_pkey using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; -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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count @@ -333,9 +333,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT COUNT(*) FROM postgres_table join distributed_table using(key) join local_partitioned_table using(key) join distributed_table_pkey using(key) where distributed_table_pkey.key = 5; -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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count @@ -344,9 +344,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) join postgres_table using(key) join local_partitioned_table using(key) where distributed_table_pkey.key = 5; -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 (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping local relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table_pkey JOIN local_table_join.distributed_table USING (key)) 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)) postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count @@ -355,7 +355,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -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 ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) 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, random() AS random 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count @@ -364,7 +364,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -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 ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, random() AS random FROM local_table_join.distributed_table_pkey) 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count @@ -373,7 +373,16 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -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 ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key::int = d1.key::int AND d1.key < postgres_table.key) WHERE d1.key::int = 1 AND false; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count @@ -383,7 +392,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; -DEBUG: Wrapping local relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_composite.key OPERATOR(pg_catalog.=) 10) count @@ -393,7 +402,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey 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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) count @@ -402,7 +411,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (value)) count @@ -411,7 +420,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = distributed_table_pkey.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_pkey.key))) count @@ -420,7 +429,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) count @@ -430,7 +439,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- it should favor distributed table only if it has equality on the unique column SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key > 10; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10))) count @@ -439,7 +448,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key < 10; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.<) 10))) count @@ -448,7 +457,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) count @@ -457,7 +466,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count @@ -466,7 +475,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count @@ -475,7 +484,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 AND postgres_table.key = 5; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (postgres_table.key OPERATOR(pg_catalog.=) 5)))) count @@ -484,7 +493,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key > 10; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count @@ -493,7 +502,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20)))) count @@ -502,7 +511,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20 OR distributed_table_pkey.key = 30; -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 30)))) count @@ -514,7 +523,7 @@ SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_t SELECT count(*) FROM distributed_table_pkey ); DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM local_table_join.distributed_table_pkey -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)))))) count @@ -523,7 +532,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 5 and distributed_table_pkey.key > 15); -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) count @@ -532,7 +541,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.key > 15); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) count @@ -541,7 +550,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.value = 'notext'); -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) count @@ -550,7 +559,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 10 and distributed_table_pkey.value = 'notext'); -DEBUG: Wrapping local relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) count @@ -559,7 +568,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = 10; -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 (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) 10))) count @@ -568,7 +577,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table) d1 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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1 USING (key)) count @@ -588,7 +597,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_windex 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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (key)) count @@ -597,7 +606,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(value); -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (value)) count @@ -606,7 +615,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON postgres_table.key = distributed_table_windex.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) count @@ -615,7 +624,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON distributed_table_windex.key = 10; -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) count @@ -625,7 +634,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- no unique index on value so local table should be recursively planned. SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; -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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) WHERE (distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) count @@ -634,7 +643,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; -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 (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) 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)) postgres_table USING (key)) WHERE (distributed_table.key OPERATOR(pg_catalog.=) 1) count @@ -644,7 +653,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- if both local and distributed tables have a filter, we prefer local unless distributed table has unique indexes on any equality filter SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) AND (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count @@ -653,7 +662,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; -DEBUG: Wrapping local relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) OR (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count @@ -664,9 +673,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- multiple local/distributed tables -- only local tables are recursively planned SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 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 p1 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 -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 p2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) count @@ -680,9 +689,9 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.value = '1'; -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 p1 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 -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 p2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) count @@ -698,9 +707,9 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.key = 1; -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 p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -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 p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) count @@ -718,7 +727,7 @@ FROM distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -729,7 +738,7 @@ FROM postgres_table WHERE distributed_table.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -740,7 +749,7 @@ FROM postgres_table WHERE distributed_table_pkey.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -751,7 +760,7 @@ FROM postgres_table WHERE distributed_table_windex.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) -- in case of update/delete we always recursively plan @@ -765,7 +774,7 @@ FROM distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -776,7 +785,7 @@ FROM postgres_table WHERE distributed_table.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -787,7 +796,7 @@ FROM postgres_table WHERE distributed_table_pkey.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -798,7 +807,7 @@ FROM postgres_table WHERE distributed_table_windex.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) SET citus.local_table_join_policy TO 'prefer-distributed'; @@ -810,7 +819,7 @@ FROM distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -821,7 +830,7 @@ FROM postgres_table WHERE distributed_table.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -832,7 +841,7 @@ FROM postgres_table WHERE distributed_table_pkey.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) UPDATE @@ -843,9 +852,10 @@ FROM postgres_table WHERE distributed_table_windex.key = postgres_table.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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +SET citus.local_table_join_policy TO 'auto'; -- modifications with multiple tables UPDATE distributed_table @@ -855,9 +865,9 @@ FROM postgres_table p1, postgres_table p2 WHERE distributed_table.key = p1.key AND p1.key = p2.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 p1 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 -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 p2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) UPDATE @@ -888,7 +898,7 @@ FROM postgres_table p1, distributed_table d2 WHERE distributed_table.key = p1.key AND p1.key = d2.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 p1 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, local_table_join.distributed_table d2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) d2.key)) -- pretty inefficient plan as it requires @@ -901,9 +911,9 @@ FROM distributed_table d1, distributed_table d2 WHERE postgres_table.key = d1.key AND d1.key = d2.key; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 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.distributed_table d1 WHERE true OFFSET 0 -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) -- currently can't plan subquery-local table join @@ -912,7 +922,7 @@ FROM (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 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 +DEBUG: Wrapping 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 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT d1.key, d1.value, d1.value_2 FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1) d2 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)) postgres_table USING (key)) count @@ -925,7 +935,7 @@ SET client_min_messages to ERROR; SELECT master_add_node('localhost', :master_port, groupId => 0); master_add_node --------------------------------------------------------------------- - 30 + 5 (1 row) CREATE TABLE citus_local(key int, value text); @@ -939,34 +949,34 @@ SET client_min_messages TO DEBUG1; -- same for citus local table - distributed table joins -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex USING (key)) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table_windex USING (key)) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex USING (value)) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table_windex USING (value)) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table_windex ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) count @@ -976,45 +986,47 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- no unique index, citus local table should be recursively planned SELECT count(*) FROM citus_local JOIN distributed_table USING(key); -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table USING (key)) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table USING (key)) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table USING(value); -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table USING (value)) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table USING (value)) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table.key))) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table.key))) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) 10))) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.citus_local 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)) distributed_table USING (key)) JOIN local_table_join.postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 0 @@ -1022,9 +1034,11 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; -DEBUG: Wrapping local relation "distributed_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.distributed_partitioned_table WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) distributed_partitioned_table JOIN local_table_join.postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_partitioned_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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) count --------------------------------------------------------------------- 0 @@ -1039,7 +1053,7 @@ FROM citus_local WHERE distributed_table_windex.key = citus_local.key; -DEBUG: Wrapping local relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text 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)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) UPDATE @@ -1050,7 +1064,7 @@ FROM distributed_table_windex WHERE distributed_table_windex.key = citus_local.key; -DEBUG: Wrapping local relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.citus_local SET value = 'test'::text FROM (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)) distributed_table_windex WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) -- complex queries @@ -1085,9 +1099,9 @@ UPDATE postgres_table SET key = 1 FROM citus_local WHERE citus_local.key = 10; -- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? -- though then the planner could give an error SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; -DEBUG: Wrapping local relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE false OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE false OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table USING (key)) WHERE false +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) WHERE false count --------------------------------------------------------------------- 0 diff --git a/src/test/regress/expected/materialized_view.out b/src/test/regress/expected/materialized_view.out index 4ef7818a2..711167c8c 100644 --- a/src/test/regress/expected/materialized_view.out +++ b/src/test/regress/expected/materialized_view.out @@ -49,7 +49,11 @@ SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10; -- materialized views are local, cannot join with distributed tables SELECT count(*) FROM mode_counts JOIN temp_lineitem USING (l_shipmode); -ERROR: relation mode_counts is not distributed + count +--------------------------------------------------------------------- + 1706 +(1 row) + -- new data is not immediately reflected in the view INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems; SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10; @@ -240,26 +244,24 @@ UPDATE small_view SET id = 1; ERROR: cannot change materialized view "small_view" -- for now, using materialized views in modify statements' FROM / WHERE clauses is not supported UPDATE large SET id=20 FROM small_view WHERE small_view.id=large.id; -ERROR: materialized views in modify queries are not supported SELECT * FROM large ORDER BY 1, 2; id | tenant_id --------------------------------------------------------------------- - 1 | 2 2 | 3 5 | 4 - 6 | 5 + 20 | 2 + 20 | 5 (4 rows) -- test on a router executable update statement, this will also fail UPDATE large SET id=28 FROM small_view WHERE small_view.id=large.id and small_view.tenant_id=2 and large.tenant_id=2; -ERROR: materialized views in modify queries are not supported SELECT * FROM large ORDER BY 1, 2; id | tenant_id --------------------------------------------------------------------- - 1 | 2 2 | 3 5 | 4 - 6 | 5 + 20 | 2 + 20 | 5 (4 rows) -- delete statement on large with subquery, this should succeed @@ -267,7 +269,7 @@ DELETE FROM large WHERE tenant_id in (SELECT tenant_id FROM small_view); SELECT * FROM large ORDER BY 1, 2; id | tenant_id --------------------------------------------------------------------- - 6 | 5 + 20 | 5 (1 row) -- INSERT INTO views is already not supported by PostgreSQL @@ -304,14 +306,13 @@ DELETE FROM small_view; ERROR: cannot change materialized view "small_view" -- using mat. view in modify statements' FROM / WHERE clauses is not valid yet UPDATE large_partitioned SET id=20 FROM small_view WHERE small_view.id=large_partitioned.id; -ERROR: materialized views in modify queries are not supported SELECT * FROM large_partitioned ORDER BY 1, 2; id | tenant_id --------------------------------------------------------------------- - 1 | 2 2 | 3 5 | 4 - 6 | 5 + 20 | 2 + 20 | 5 26 | 32 29 | 15 60 | 51 @@ -324,10 +325,12 @@ SELECT * FROM large_partitioned ORDER BY 1, 2; --------------------------------------------------------------------- 2 | 3 5 | 4 + 20 | 2 + 20 | 5 26 | 32 29 | 15 60 | 51 -(5 rows) +(7 rows) -- we should still have identical rows for next test statement, then insert new rows to both tables INSERT INTO large_partitioned VALUES(14, 14); diff --git a/src/test/regress/expected/mixed_relkind_tests.out b/src/test/regress/expected/mixed_relkind_tests.out index 3323bca56..65a6d6045 100644 --- a/src/test/regress/expected/mixed_relkind_tests.out +++ b/src/test/regress/expected/mixed_relkind_tests.out @@ -320,7 +320,7 @@ $$); SET client_min_messages TO DEBUG1; SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN distributed_table ON (true); -DEBUG: Wrapping local relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.distributed_table ON (true)) count @@ -329,7 +329,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN partitioned_distributed_table ON (true); -DEBUG: Wrapping local relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.partitioned_distributed_table ON (true)) count @@ -338,7 +338,7 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT COUNT(*) FROM distributed_table JOIN partitioned_postgres_local_table ON (true); -DEBUG: Wrapping local relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (mixed_relkind_tests.distributed_table JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table ON (true)) count @@ -348,19 +348,19 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c INSERT INTO partitioned_distributed_table SELECT foo.* FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a, foo.b FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO partitioned_distributed_table SELECT foo.* FROM distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO distributed_table SELECT foo.a FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) DEBUG: performing repartitioned INSERT ... SELECT @@ -392,24 +392,26 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) UPDATE partitioned_distributed_table SET b = foo.a FROM citus_local_table AS foo; -DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo UPDATE partitioned_distributed_table SET b = foo.a FROM postgres_local_table AS foo; -DEBUG: Wrapping local relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo UPDATE partitioned_distributed_table SET a = foo.a FROM postgres_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping local relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) UPDATE partitioned_distributed_table SET a = foo.a FROM citus_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping local relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) -- should fail UPDATE partitioned_distributed_table SET a = foo.a FROM mat_view_on_part_dist AS foo WHERE foo.a = partitioned_distributed_table.a; -ERROR: materialized views in modify queries are not supported +DEBUG: Wrapping relation "mat_view_on_part_dist" to a subquery: SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a 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)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) UPDATE partitioned_distributed_table SET a = foo.a FROM partitioned_distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns UPDATE partitioned_distributed_table SET a = foo.a FROM distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out index c9513f28f..20788d6fe 100644 --- a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out +++ b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out @@ -31,7 +31,7 @@ SELECT count(*) FROM distributed_table u1 JOIN distributed_table u2 USING(key) JOIN local_table USING (key); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN push_down_filters.distributed_table u2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) local_table USING (key)) count @@ -44,7 +44,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING (key) WHERE u2.key > ANY(ARRAY[2, 1, 6]); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (u2.key OPERATOR(pg_catalog.>) ANY (ARRAY[2, 1, 6])) count @@ -57,7 +57,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(key) WHERE ARRAY[u2.key, u2.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (ARRAY[u2.key, u2.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count @@ -70,7 +70,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE ARRAY[u2.value, u1.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ARRAY[u2.value, u1.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count @@ -83,7 +83,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value/2.0 > 2)::int::bool::text::bool; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) (2)::numeric))::integer)::boolean)::text)::boolean count @@ -96,7 +96,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u2.value > 3 THEN u2.value > 2 ELSE false END); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u2.value OPERATOR(pg_catalog.>) 3) THEN (u2.value OPERATOR(pg_catalog.>) 2) ELSE false END count @@ -109,7 +109,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u1.value > 4000 THEN u2.value / 100 > 1 ELSE false END); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u1.value OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END count @@ -122,7 +122,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE COALESCE((u2.key/5.0)::int::bool, false); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE COALESCE(((((u2.key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count @@ -135,7 +135,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE NULLIF((u2.value/5.0)::int::bool, false); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE NULLIF(((((u2.value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count @@ -148,7 +148,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value IS NOT NULL; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value IS NOT NULL) count @@ -161,7 +161,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE isfinite(u2.time); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE isfinite(u2."time") count @@ -174,7 +174,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.value, u1.value) = 55; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.value, u1.value) OPERATOR(pg_catalog.=) 55) count @@ -187,7 +187,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.key, u2.value) = u2.key; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.key, u2.value) OPERATOR(pg_catalog.=) u2.key) count @@ -200,7 +200,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE row(u2.value, 2, 3) > row(u2.value, 2, 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(u2.value, 2, 3)) count @@ -220,7 +220,7 @@ JOIN local_table u2 USING(value) isfinite(u2.time) AND u2.value IS DISTINCT FROM 50040 AND row(u2.value, 2, 3) > row(2000, 2, 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (u2.key OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((u2.key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((u2.value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite(u2."time") AND (u2.value IS DISTINCT FROM 50040) AND (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) count @@ -236,7 +236,7 @@ WHERE u2.value > (SELECT avg(key) FROM distributed_table); DEBUG: generating subplan XXX_1 for subquery SELECT avg(key) AS avg FROM push_down_filters.distributed_table -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value)::numeric OPERATOR(pg_catalog.>) (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric))) count @@ -249,7 +249,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > (SELECT 5); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value OPERATOR(pg_catalog.>) (SELECT 5)) count @@ -262,7 +262,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value * u1.key > 25; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.*) u1.key) OPERATOR(pg_catalog.>) 25) count @@ -277,7 +277,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value = 3; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.=) 3) count @@ -290,7 +290,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value > 3; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.>) 3) count @@ -304,7 +304,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.key = 3; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.key OPERATOR(pg_catalog.=) 3) count @@ -317,7 +317,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 4 OR u2.value = 4; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 4) OR (u2.value OPERATOR(pg_catalog.=) 4)) count @@ -330,7 +330,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 2 and u2.time IS NULL; -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND (u2."time" IS NULL)) count @@ -344,7 +344,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count @@ -358,7 +358,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) OR (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL) OR ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count @@ -372,7 +372,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count @@ -385,7 +385,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u1.value IS NULL) AND (u2.key = 10000 * random() OR u1.key > 3); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u1.value IS NULL)) AND (((u2.key)::double precision OPERATOR(pg_catalog.=) ((10000)::double precision OPERATOR(pg_catalog.*) random())) OR (u1.key OPERATOR(pg_catalog.>) 3))) count @@ -398,7 +398,7 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 AND false); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) count @@ -418,7 +418,7 @@ JOIN LATERAL WHERE u2.value = 15) AS u3 USING (value) WHERE (u2.value > 2 AND FALSE); -DEBUG: Wrapping local relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) JOIN LATERAL (SELECT distributed_table.value, random() AS random FROM push_down_filters.distributed_table WHERE (u2.value OPERATOR(pg_catalog.=) 15)) u3 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 4da3a305d..3c5cb0175 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -222,6 +222,8 @@ test: multi_modifying_xacts test: multi_repartition_udt multi_repartitioned_subquery_udf multi_subtransactions test: multi_transaction_recovery +test: local_table_join + # --------- # multi_copy creates hash and range-partitioned tables and performs COPY # multi_router_planner creates hash partitioned tables. @@ -282,7 +284,7 @@ test: multi_colocated_shard_transfer # ---------- # multi_citus_tools tests utility functions written for citus tools # ---------- -test: multi_citus_tools local_table_join +test: multi_citus_tools # ---------- # node_conninfo_reload tests that node_conninfo changes take effect diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 10c5fdcd9..5ae9b6f59 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -30,13 +30,13 @@ CREATE FUNCTION fake_fdw_handler() RETURNS fdw_handler AS 'citus' LANGUAGE C STRICT; -CREATE FOREIGN DATA WRAPPER fake_fdw HANDLER fake_fdw_handler; -CREATE SERVER fake_fdw_server FOREIGN DATA WRAPPER fake_fdw; +CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler; +CREATE SERVER fake_fdw_server_1 FOREIGN DATA WRAPPER fake_fdw_1; CREATE FOREIGN TABLE foreign_table ( key int, value text -) SERVER fake_fdw_server OPTIONS (encoding 'utf-8', compression 'true'); +) SERVER fake_fdw_server_1 OPTIONS (encoding 'utf-8', compression 'true'); CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; @@ -109,7 +109,7 @@ SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) jo SELECT count(*) FROM (SELECT *, random() FROM distributed_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; - +SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key::int = d1.key::int AND d1.key < postgres_table.key) WHERE d1.key::int = 1 AND false; -- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; @@ -306,6 +306,8 @@ FROM WHERE distributed_table_windex.key = postgres_table.key; +SET citus.local_table_join_policy TO 'auto'; + -- modifications with multiple tables UPDATE distributed_table @@ -418,7 +420,7 @@ SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distribut UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; -UPDATE citus_local SET key = 1 FROM postgres_table WHERE citus_local.key = 10; +UPDATE citus_local SET key = 1 FROM postgres_table WHERE citus_local.key = 10; UPDATE postgres_table SET key = 1 FROM citus_local WHERE citus_local.key = 10; From 2a44029aaf78cd6c518b5d2b7c09253c738620b7 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Fri, 4 Dec 2020 12:24:37 +0300 Subject: [PATCH 23/37] Simplify ContainsTableToBeConvertedToSubquery AllDataLocallyAccessible and ContainsLocalTableSubqueryJoin are removed. We can possibly remove ModifiesLocalTableWithRemoteCitusLocalTable as well. Though this removal has a side effect that now when all the data is locally available, we could still wrap a relation into a subquery, I guess that should be resolved in the router planner itself. Add more tests --- .../distributed/planner/distributed_planner.c | 1 - .../planner/local_distributed_join_planner.c | 24 +- .../planner/multi_logical_planner.c | 11 + .../planner/multi_router_planner.c | 12 +- .../distributed/planner/recursive_planning.c | 129 +----- .../relation_restriction_equivalence.c | 6 +- .../distributed/multi_logical_planner.h | 1 + src/include/distributed/recursive_planning.h | 1 - .../relation_restriction_equivalence.h | 4 +- .../expected/citus_local_tables_queries.out | 18 +- .../expected/local_distributed_table_join.out | 0 .../regress/expected/local_table_join.out | 45 ++- .../sql/local_distributed_table_join.sql | 371 ++++++++++++++++++ src/test/regress/sql/local_table_join.sql | 3 + 14 files changed, 451 insertions(+), 175 deletions(-) create mode 100644 src/test/regress/expected/local_distributed_table_join.out create mode 100644 src/test/regress/sql/local_distributed_table_join.sql diff --git a/src/backend/distributed/planner/distributed_planner.c b/src/backend/distributed/planner/distributed_planner.c index 21de545e2..6a11bb352 100644 --- a/src/backend/distributed/planner/distributed_planner.c +++ b/src/backend/distributed/planner/distributed_planner.c @@ -414,7 +414,6 @@ AdjustPartitioningForDistributedPlanning(List *rangeTableList, * value before and after dropping to the standart_planner. */ if (rangeTableEntry->rtekind == RTE_RELATION && - IsCitusTable(rangeTableEntry->relid) && PartitionedTable(rangeTableEntry->relid)) { rangeTableEntry->inh = setPartitionedTablesInherited; diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 8e03fd6d8..877616fa0 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -141,6 +141,10 @@ RecursivelyPlanLocalTableJoins(Query *query, RangeTableEntryDetails *rangeTableEntryDetails = GetNextRTEToConvertToSubquery(joinTree, conversionCandidates, plannerRestrictionContext); + if (rangeTableEntryDetails == NULL) + { + break; + } RangeTblEntry *rangeTableEntry = rangeTableEntryDetails->rangeTableEntry; Oid relId = rangeTableEntryDetails->rangeTableEntry->relid; @@ -298,7 +302,8 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, /* user doesn't want Citus to enable local table joins */ return false; } - if (!ContainsTableToBeConvertedToSubquery(rangeTableList, resultRelationId)) + + if (!ContainsTableToBeConvertedToSubquery(rangeTableList, resultRelationId)) { return false; } @@ -385,23 +390,22 @@ static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, PlannerRestrictionContext *plannerRestrictionContext) { - /* TODO: Get rid of this hack, find relation restriction information directly */ - PlannerRestrictionContext *filteredPlannerRestrictionContext = - FilterPlannerRestrictionForQuery(plannerRestrictionContext, - WrapRteRelationIntoSubquery(relationRte, NIL)); - + int rteIdentity = GetRTEIdentity(relationRte); RelationRestrictionContext *relationRestrictionContext = - filteredPlannerRestrictionContext->relationRestrictionContext; + plannerRestrictionContext->relationRestrictionContext; + Relids queryRteIdentities = bms_make_singleton(rteIdentity); + RelationRestrictionContext *filteredRelationRestrictionContext = + FilterRelationRestrictionContext(relationRestrictionContext, queryRteIdentities); List *filteredRelationRestrictionList = - relationRestrictionContext->relationRestrictionList; + filteredRelationRestrictionContext->relationRestrictionList; - if (list_length(filteredRelationRestrictionList) == 0) + if (list_length(filteredRelationRestrictionList) != 1) { return NIL; } + RelationRestriction *relationRestriction = (RelationRestriction *) linitial(filteredRelationRestrictionList); - PlannerInfo *plannerInfo = relationRestriction->plannerInfo; Query *queryToProcess = plannerInfo->parse; int rteIndex = relationRestriction->index; diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index b74b7a352..02e780aa1 100644 --- a/src/backend/distributed/planner/multi_logical_planner.c +++ b/src/backend/distributed/planner/multi_logical_planner.c @@ -333,6 +333,17 @@ IsCitusTableRTE(Node *node) } +/* + * IsDistributedOrReferenceTableRTE returns true if the given node + * is eeither a distributed(hash/range/append) or reference table. + */ +bool +IsDistributedOrReferenceTableRTE(Node *node) +{ + return IsDistributedTableRTE(node) || IsReferenceTableRTE(node); +} + + /* * IsDistributedTableRTE gets a node and returns true if the node * is a range table relation entry that points to a distributed relation, diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 8f0ae7fb3..2b97da267 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -874,14 +874,8 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer { ExtractRangeTableEntryWalker((Node *) originalQuery, &rangeTableList); } - RangeTblEntry *resultRte = ExtractResultRelationRTE(queryTree); - Oid resultRelationId = InvalidOid; - if (resultRte) - { - resultRelationId = resultRte->relid; - } - bool containsTableToBeConvertedToSubquery = - ContainsTableToBeConvertedToSubquery(queryTree->rtable, resultRelationId); + bool containsLocalTableDistributedTableJoin = + ContainsLocalTableDistributedTableJoin(queryTree->rtable); RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) @@ -907,7 +901,7 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer else { if (IsRelationLocalTableOrMatView(rangeTableEntry->relid) && - containsTableToBeConvertedToSubquery) + containsLocalTableDistributedTableJoin) { StringInfo errorMessage = makeStringInfo(); char *relationName = get_rel_name(rangeTableEntry->relid); diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 1ef1371a3..7fe70a4f3 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -156,7 +156,6 @@ static bool ShouldRecursivelyPlanSubquery(Query *subquery, static bool AllDistributionKeysInSubqueryAreEqual(Query *subquery, PlannerRestrictionContext * restrictionContext); -static bool AllDataLocallyAccessible(List *rangeTableList); static bool IsTableLocallyAccessible(Oid relationId); static bool ShouldRecursivelyPlanSetOperation(Query *query, RecursivePlanningContext *context); @@ -182,7 +181,6 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, static void UpdateVarNosInQualForSubquery(Query *query); static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList, Oid resultRelationId); -static bool ContainsOnlyReferenceAndCitusLocalRelation(List *rangeTableList); /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. @@ -1427,22 +1425,10 @@ UpdateVarNosInQualForSubquery(Query *query) bool ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) { - if (AllDataLocallyAccessible(rangeTableList)) - { - return false; - } - if (ContainsOnlyReferenceAndCitusLocalRelation(rangeTableList)) - { - return false; - } if (ContainsLocalTableDistributedTableJoin(rangeTableList)) { return true; } - if (ContainsLocalTableSubqueryJoin(rangeTableList, resultRelationId)) - { - return true; - } if (ModifiesLocalTableWithRemoteCitusLocalTable(rangeTableList, resultRelationId)) { return true; @@ -1485,37 +1471,6 @@ ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList, Oid resultRela } -/* - * AllDataLocallyAccessible return true if all data for the relations in the - * rangeTableList is locally accessible. - */ -static bool -AllDataLocallyAccessible(List *rangeTableList) -{ - RangeTblEntry *rangeTableEntry = NULL; - foreach_ptr(rangeTableEntry, rangeTableList) - { - if (rangeTableEntry->rtekind == RTE_SUBQUERY) - { - /* TODO:: check if it has distributed table */ - return false; - } - if (!IsRecursivelyPlannableRelation(rangeTableEntry)) - { - continue; - } - - Oid relationId = rangeTableEntry->relid; - if (!IsTableLocallyAccessible(relationId)) - { - return false; - } - } - - return true; -} - - /* * IsTableLocallyAccessible returns true if the given table * can be accessed in local. @@ -1568,7 +1523,8 @@ IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry) /* * ContainsLocalTableDistributedTableJoin returns true if the input range table list - * contains a direct join between local and distributed tables. + * contains a direct join between local RTE and an RTE that contains a distributed + * or reference table. */ bool ContainsLocalTableDistributedTableJoin(List *rangeTableList) @@ -1576,22 +1532,16 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) bool containsLocalTable = false; bool containsDistributedTable = false; - ListCell *rangeTableCell = NULL; - foreach(rangeTableCell, rangeTableList) + RangeTblEntry *rangeTableEntry = NULL; + foreach_ptr(rangeTableEntry, rangeTableList) { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - - if (!IsRecursivelyPlannableRelation(rangeTableEntry)) - { - continue; - } - - if (IsCitusTableType(rangeTableEntry->relid, DISTRIBUTED_TABLE) || - IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE)) + if (FindNodeMatchingCheckFunctionInRangeTableList(list_make1(rangeTableEntry), + IsDistributedOrReferenceTableRTE)) { containsDistributedTable = true; } - else if (IsLocalTableRteOrMatView((Node *) rangeTableEntry)) + else if (IsRecursivelyPlannableRelation(rangeTableEntry) && + IsLocalTableRteOrMatView((Node *) rangeTableEntry)) { /* we consider citus local tables as local table */ containsLocalTable = true; @@ -1601,69 +1551,6 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) return containsLocalTable && containsDistributedTable; } - -/* - * ContainsOnlyReferenceAndCitusLocalRelation returns true if there is no - * relation other than citus local and reference tables - */ -static bool -ContainsOnlyReferenceAndCitusLocalRelation(List *rangeTableList) -{ - RangeTblEntry *rangeTableEntry = NULL; - foreach_ptr(rangeTableEntry, rangeTableList) - { - if (!IsRecursivelyPlannableRelation(rangeTableEntry)) - { - continue; - } - - if (!IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE) && - !IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE)) - { - return false; - } - } - - return true; -} - - -/* - * ContainsLocalTableSubqueryJoin returns true if the input range table list - * contains a direct join between local table/citus local table and subquery. - */ -bool -ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId) -{ - bool containsLocalTable = false; - bool containsSubquery = false; - - ListCell *rangeTableCell = NULL; - foreach(rangeTableCell, rangeTableList) - { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - - if (rangeTableEntry->rtekind == RTE_SUBQUERY) - { - containsSubquery = true; - } - - if (!IsRecursivelyPlannableRelation(rangeTableEntry)) - { - continue; - } - - if (IsLocalTableRteOrMatView((Node *) rangeTableEntry) && - rangeTableEntry->relid != resultRelationId) - { - containsLocalTable = true; - } - } - - return containsLocalTable && containsSubquery; -} - - /* * WrapFunctionsInSubqueries iterates over all the immediate Range Table Entries * of a query and wraps the functions inside (SELECT * FROM fnc() f) diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index c9b86163f..ea4fe336d 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -145,10 +145,6 @@ static Index RelationRestrictionPartitionKeyIndex(RelationRestriction * static bool AllRelationsInRestrictionContextColocated(RelationRestrictionContext * restrictionContext); static bool IsParam(Node *node); -static RelationRestrictionContext * FilterRelationRestrictionContext( - RelationRestrictionContext *relationRestrictionContext, - Relids - queryRteIdentities); static JoinRestrictionContext * FilterJoinRestrictionContext( JoinRestrictionContext *joinRestrictionContext, Relids queryRteIdentities); @@ -1944,7 +1940,7 @@ IsParam(Node *node) * in the queryRteIdentities and returns a newly allocated * RelationRestrictionContext. */ -static RelationRestrictionContext * +RelationRestrictionContext * FilterRelationRestrictionContext(RelationRestrictionContext *relationRestrictionContext, Relids queryRteIdentities) { diff --git a/src/include/distributed/multi_logical_planner.h b/src/include/distributed/multi_logical_planner.h index 993e8b819..f8d1811a2 100644 --- a/src/include/distributed/multi_logical_planner.h +++ b/src/include/distributed/multi_logical_planner.h @@ -195,6 +195,7 @@ extern bool TargetListOnPartitionColumn(Query *query, List *targetEntryList); extern bool FindNodeMatchingCheckFunctionInRangeTableList(List *rtable, bool (*check)( Node *)); extern bool IsCitusTableRTE(Node *node); +extern bool IsDistributedOrReferenceTableRTE(Node *node); extern bool IsDistributedTableRTE(Node *node); extern bool IsReferenceTableRTE(Node *node); extern bool QueryContainsDistributedTableRTE(Query *query); diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index f58fa48f5..5a2484665 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -53,7 +53,6 @@ extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, List *requiredAttrNumbers, RecursivePlanningContext *context); -extern bool ContainsLocalTableSubqueryJoin(List *rangeTableList, Oid resultRelationId); extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId); extern bool IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry); diff --git a/src/include/distributed/relation_restriction_equivalence.h b/src/include/distributed/relation_restriction_equivalence.h index 4aed46a2c..e9bdb9adc 100644 --- a/src/include/distributed/relation_restriction_equivalence.h +++ b/src/include/distributed/relation_restriction_equivalence.h @@ -47,5 +47,7 @@ extern JoinRestrictionContext * RemoveDuplicateJoinRestrictions(JoinRestrictionC extern bool EquivalenceListContainsRelationsEquality(List *attributeEquivalenceList, RelationRestrictionContext * restrictionContext); - +extern RelationRestrictionContext * +FilterRelationRestrictionContext(RelationRestrictionContext *relationRestrictionContext, + Relids queryRteIdentities); #endif /* RELATION_RESTRICTION_EQUIVALENCE_H */ diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 973237f85..0529d6f02 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -704,7 +704,8 @@ UPDATE reference_table SET b = 6 FROM citus_local_table WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509002 reference_table SET b = 6 FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509002 reference_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)) 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 @@ -716,7 +717,8 @@ UPDATE citus_local_table SET b = 6 FROM reference_table WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 citus_local_table SET b = 6 FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true OFFSET 0 +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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)) 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 @@ -730,12 +732,14 @@ NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.ci DELETE FROM reference_table USING citus_local_table WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509002 reference_table USING citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509002 reference_table USING (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) 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: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table USING citus_local_table_queries.reference_table_1509002 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true OFFSET 0 +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table USING (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) 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); @@ -743,7 +747,8 @@ NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.ci -- just works DELETE FROM citus_local_table WHERE citus_local_table.a IN (SELECT a FROM reference_table); -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT reference_table.a FROM citus_local_table_queries.reference_table_1509002 reference_table)) +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509002 reference_table +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 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 @@ -757,7 +762,8 @@ UPDATE citus_local_table SET b = 6 FROM reference_table_cte WHERE citus_local_table.a = reference_table_cte.a; -NOTICE: executing the command locally: WITH reference_table_cte AS (SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509002 reference_table) UPDATE citus_local_table_queries.citus_local_table_1509000 citus_local_table SET b = 6 FROM reference_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table_cte.a) +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.reference_table_1509002 reference_table +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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)) reference_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table_cte.a) --------------------------------------------------------------------- ----- VIEW QUERIES ----- --------------------------------------------------------------------- diff --git a/src/test/regress/expected/local_distributed_table_join.out b/src/test/regress/expected/local_distributed_table_join.out new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index a52c174f2..7710453ed 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -145,8 +145,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- partititoned local tables should work as well SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count --------------------------------------------------------------------- @@ -154,8 +154,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM reference_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count --------------------------------------------------------------------- @@ -163,8 +163,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- @@ -283,8 +283,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count --------------------------------------------------------------------- @@ -292,8 +292,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- @@ -301,8 +301,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- @@ -313,8 +313,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- @@ -324,8 +324,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join distributed_table_pkey using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- @@ -335,8 +335,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT COUNT(*) FROM postgres_table join distributed_table using(key) join local_partitioned_table using(key) join distributed_table_pkey using(key) where distributed_table_pkey.key = 5; DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- @@ -346,8 +346,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) join postgres_table using(key) join local_partitioned_table using(key) where distributed_table_pkey.key = 5; DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table_pkey JOIN local_table_join.distributed_table USING (key)) 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)) postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- @@ -935,7 +935,7 @@ SET client_min_messages to ERROR; SELECT master_add_node('localhost', :master_port, groupId => 0); master_add_node --------------------------------------------------------------------- - 5 + 5 (1 row) CREATE TABLE citus_local(key int, value text); @@ -1090,6 +1090,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- TODO:: we should support this? UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) 10) ERROR: relation postgres_table is not distributed UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table diff --git a/src/test/regress/sql/local_distributed_table_join.sql b/src/test/regress/sql/local_distributed_table_join.sql new file mode 100644 index 000000000..78ff90614 --- /dev/null +++ b/src/test/regress/sql/local_distributed_table_join.sql @@ -0,0 +1,371 @@ +CREATE SCHEMA local_distributed_table_join; +SET search_path TO local_distributed_table_join; + + + +CREATE TABLE distributed (id bigserial PRIMARY KEY, + name text, + created_at timestamptz DEFAULT now()); +CREATE TABLE reference (id bigserial PRIMARY KEY, + title text); + +CREATE TABLE local (id bigserial PRIMARY KEY, + title text); + +-- these above restrictions brought us to the following schema +SELECT create_reference_table('reference'); +SELECT create_distributed_table('distributed', 'id'); + +INSERT INTO distributed SELECT i, i::text, now() FROM generate_series(0,100)i; +INSERT INTO reference SELECT i, i::text FROM generate_series(0,100)i; +INSERT INTO local SELECT i, i::text FROM generate_series(0,100)i; + + +-- very simple 1-1 Joins +SELECT count(*) FROM distributed JOIN local USING (id); +SELECT count(*) FROM distributed JOIN local ON (name = title); +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text); +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +SELECT count(*) FROM distributed JOIN local USING (id) WHERE false; +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR True; +SELECT count(*) FROM distributed d1 JOIN local ON (name::int + local.id > d1.id AND d1.id < local.title::int) WHERE d1.id = 1; +SELECT count(*) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)); +SELECT hashtext(local.id::text) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1 LIMIT 4; +SELECT '' as "xxx", local.*, 'xxx' as "test" FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1,2,3 LIMIT 4; +SELECT local.title, count(*) FROM distributed JOIN local USING (id) GROUP BY 1 ORDER BY 1, 2 DESC LIMIT 5; +SELECT distributed.id as id1, local.id as id2 FROM distributed JOIN local USING(id) ORDER BY distributed.id + local.id LIMIT 5; +SELECT distributed.id as id1, local.id as id2, count(*) FROM distributed JOIN local USING(id) GROUP BY distributed.id, local.id ORDER BY 1,2 LIMIT 5; + + +-- basic subqueries that cannot be pulled up +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local USING (id); +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = title); +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text); +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; + +-- pull up subqueries as they are pretty simple, local table should be recursively planned +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local USING (id); +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = title); +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text); +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; +SELECT count(*) FROM (SELECT * FROM distributed WHERE id = 2) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +SELECT count(*) FROM (SELECT * FROM distributed WHERE false) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; + +-- TEMPORARY table +CREATE TEMPORARY TABLE temp_local AS SELECT * FROM local; +SELECT count(*) FROM distributed JOIN temp_local USING (id); + +-- UNLOGGED table +CREATE UNLOGGED TABLE unlogged_local AS SELECT * FROM local; +SELECT count(*) FROM distributed JOIN unlogged_local USING (id); + +-- mat view +CREATE MATERIALIZED VIEW mat_view AS SELECT * FROM local; +SELECT count(*) FROM distributed JOIN mat_view USING (id); + +CREATE VIEW local_regular_view AS SELECT * FROM local; +CREATE VIEW dist_regular_view AS SELECT * FROM distributed; + +SELECT count(*) FROM distributed JOIN local_regular_view USING (id); +SELECT count(*) FROM local JOIN dist_regular_view USING (id); +SELECT count(*) FROM dist_regular_view JOIN local_regular_view USING (id); + + +-- join alias/table alias +SELECT COUNT(*) FROM (distributed JOIN local USING (id)) AS t(a,b,c,d) ORDER BY d,c,a,b LIMIT 3; +SELECT COUNT(*) FROM (distributed d1(x,y,y1) JOIN local l1(x,t) USING (x)) AS t(a,b,c,d) ORDER BY d,c,a,b LIMIT 3; + +-- final queries are pushdown queries +SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id); +SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; +SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) ORDER BY 1 DESC LIMIT 4; +SELECT count(DISTINCT d1.name::int * local.id) FROM distributed d1 JOIN local USING (id); + +-- final queries are router queries +SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1; +SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1 ORDER BY 1 DESC LIMIT 4; +SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) WHERE d2.id = 1 ORDER BY 1 DESC LIMIT 4; + +-- final queries are pull to coordinator queries +SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id + local.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; + + + +-- nested subqueries +SELECT + count(*) +FROM + (SELECT * FROM (SELECT * FROM distributed) as foo) as bar + JOIN + local + USING(id); + + +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + local + USING(id); + +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + local + USING(id); +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id); + +-- TODO: Unnecessary recursive planning for local +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed LIMIT 1) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id); + +-- subqueries in WHERE clause +-- is not colocated, and the JOIN inside as well. +-- so should be recursively planned twice +SELECT + count(*) +FROM + distributed +WHERE + id > (SELECT + count(*) + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id) + ); + +-- two distributed tables are co-located and JOINed on distribution +-- key, so should be fine to pushdown +SELECT + count(*) +FROM + distributed d_upper +WHERE + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id) + ) IS NOT NULL; + +SELECT + count(*) +FROM + distributed d_upper +WHERE + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + local as foo + USING(id) + ) IS NOT NULL; + +SELECT + count(*) +FROM + distributed d_upper +WHERE d_upper.id > + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + local as foo + USING(id) + ); + +SELECT + count(*) +FROM + distributed d_upper +WHERE + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local WHERE d_upper.id = id) as foo2) as bar2 + USING(id) + ) IS NOT NULL; + + + + +-- subqueries in the target list + +-- router, should work +select (SELECT local.id) FROM local, distributed WHERE distributed.id = 1 LIMIT 1; + +-- should fail +select (SELECT local.id) FROM local, distributed WHERE distributed.id != 1 LIMIT 1; + +-- currently not supported, but should work with https://github.com/citusdata/citus/pull/4360/files +SELECT + name, (SELECT id FROM local WHERE id = e.id) +FROM + distributed e +ORDER BY 1,2 LIMIT 1; + + +-- set operations + +SELECT local.* FROM distributed JOIN local USING (id) + EXCEPT +SELECT local.* FROM distributed JOIN local USING (id); + +SELECT distributed.* FROM distributed JOIN local USING (id) + EXCEPT +SELECT distributed.* FROM distributed JOIN local USING (id); + + +SELECT count(*) FROM +( + (SELECT * FROM (SELECT * FROM local) as f JOIN distributed USING (id)) + UNION ALL + (SELECT * FROM (SELECT * FROM local) as f2 JOIN distributed USING (id)) +) bar; + +SELECT count(*) FROM +( + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as fo) + UNION ALL + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) +) bar; + +select count(DISTINCT id) +FROM +( + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as fo) + UNION ALL + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) +) bar; + +-- 25 Joins +select ' select count(*) from distributed ' || string_Agg('INNER +JOIN local u'|| x::text || ' USING (id)',' ') from +generate_Series(1,25)x; +\gexec + +select ' select count(*) from distributed ' || string_Agg('INNER +JOIN local u'|| x::text || ' ON (false)',' ') from +generate_Series(1,25)x; +\gexec + +select ' select count(*) from local ' || string_Agg('INNER +JOIN distributed u'|| x::text || ' USING (id)',' ') from +generate_Series(1,25)x; +\gexec + +select ' select count(*) from local ' || string_Agg('INNER +JOIN distributed u'|| x::text || ' ON (false)',' ') from +generate_Series(1,25)x; +\gexec + +-- lateral joins + +SELECT COUNT(*) FROM (VALUES (1), (2), (3)) as f(x) LATERAL JOIN (SELECT * FROM local WHERE id = x) as bar; + +SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id = distributed.id) as foo ON (true); +SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id > distributed.id) as foo ON (true); + +SELECT COUNT(*) FROM distributed JOIN LATERAL (SELECT * FROM local WHERE local.id = distributed.id) as foo ON (true); +SELECT COUNT(*) FROM distributed JOIN LATERAL (SELECT * FROM local WHERE local.id > distributed.id) as foo ON (true); + + + + +SELECT count(*) FROM distributed CROSS JOIN local; +SELECT count(*) FROM distributed CROSS JOIN local WHERE distributed.id = 1; + +-- w count(*) it works fine as PG ignores the inner tables +SELECT count(*) FROM distributed LEFT JOIN local USING (id); +SELECT count(*) FROM local LEFT JOIN distributed USING (id); + +SELECT * FROM distributed LEFT JOIN local USING (id) LIMIT 1; +SELECT * FROM local LEFT JOIN distributed USING (id) LIMIT 1; + + SELECT + foo1.id, random() + FROM + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo9, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo8, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo7, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo6, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo5, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo4, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo3, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo2, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo10, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo1 + WHERE + foo1.id = foo9.id AND + foo1.id = foo8.id AND + foo1.id = foo7.id AND + foo1.id = foo6.id AND + foo1.id = foo5.id AND + foo1.id = foo4.id AND + foo1.id = foo3.id AND + foo1.id = foo2.id AND + foo1.id = foo10.id AND + foo1.id = foo1.id ; + + SELECT + foo1.id + FROM + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo1, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo2, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo3, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo4, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo5 + WHERE + foo1.id = foo4.id AND + foo1.id = foo2.id AND + foo1.id = foo3.id AND + foo1.id = foo4.id AND + foo1.id = foo5.id; + + SELECT + foo1.id + FROM + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 1) as foo1, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 2) as foo2, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 3) as foo3, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 4) as foo4, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 5) as foo5 + WHERE + foo1.id = foo4.id AND + foo1.id = foo2.id AND + foo1.id = foo3.id AND + foo1.id = foo4.id AND + foo1.id = foo5.id; + + + +DROP SCHEMA local_distributed_table_join CASCADE; \ No newline at end of file diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 5ae9b6f59..c3786cc4f 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -141,6 +141,9 @@ SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_t SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = 10; +select count(*) FROM postgres_table JOIN (SELECT a.key,random() FROM distributed_table a JOIN distributed_table b USING(key)) as foo USING(key); +select count(*) FROM (SELECT a.key, random() FROM distributed_table a JOIN distributed_table b USING(key)) as foo JOIN postgres_table USING(key); + SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table) d1 USING(key); -- since this is already router plannable, we don't recursively plan the postgres table SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table LIMIT 1) d1 USING(key); From a34504d7bf48af5e3b0710396e217bac40723a97 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Sun, 6 Dec 2020 12:55:43 +0300 Subject: [PATCH 24/37] Move recursive planning related function to recursive_planning --- .../planner/local_distributed_join_planner.c | 72 +----------- .../distributed/planner/recursive_planning.c | 105 ++++++++++++++---- .../local_distributed_join_planner.h | 6 +- src/include/distributed/recursive_planning.h | 3 +- 4 files changed, 93 insertions(+), 93 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 877616fa0..e819ada8b 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -75,10 +75,6 @@ typedef struct ConversionCandidates List *localTableList; /* local or citus local table */ }ConversionCandidates; -static bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, - Oid resultRelationId, - PlannerRestrictionContext * - plannerRestrictionContext); static bool HasConstantFilterOnUniqueColumn(FromExpr *joinTree, RangeTblEntry *rangeTableEntry, Index rteIndex); @@ -96,8 +92,6 @@ static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree conversionCandidates, PlannerRestrictionContext * plannerRestrictionContext); -static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, - List **joinRangeTableEntries); static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid relationId); static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList); @@ -109,32 +103,22 @@ static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList */ void RecursivelyPlanLocalTableJoins(Query *query, - RecursivePlanningContext *context) + RecursivePlanningContext *context, List* rangeTableList) { + PlannerRestrictionContext *plannerRestrictionContext = context->plannerRestrictionContext; - List *rangeTableList = NIL; - GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, - &rangeTableList); - Oid resultRelationId = InvalidOid; if (IsModifyCommand(query)) { resultRelationId = ModifyQueryResultRelationId(query); - } - - if (!ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, resultRelationId, - plannerRestrictionContext)) - { - return; - } + } ConversionCandidates *conversionCandidates = CreateConversionCandidates(query->jointree, plannerRestrictionContext, rangeTableList, resultRelationId); while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, - resultRelationId, plannerRestrictionContext)) { FromExpr *joinTree = query->jointree; @@ -156,51 +140,6 @@ RecursivelyPlanLocalTableJoins(Query *query, } } - -/* - * GetRangeTableEntriesFromJoinTree gets the range table entries that are - * on the given join tree. - */ -static void -GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, - List **joinRangeTableEntries) -{ - if (joinNode == NULL) - { - return; - } - else if (IsA(joinNode, FromExpr)) - { - FromExpr *fromExpr = (FromExpr *) joinNode; - Node *fromElement; - - foreach_ptr(fromElement, fromExpr->fromlist) - { - GetRangeTableEntriesFromJoinTree(fromElement, rangeTableList, - joinRangeTableEntries); - } - } - else if (IsA(joinNode, JoinExpr)) - { - JoinExpr *joinExpr = (JoinExpr *) joinNode; - GetRangeTableEntriesFromJoinTree(joinExpr->larg, rangeTableList, - joinRangeTableEntries); - GetRangeTableEntriesFromJoinTree(joinExpr->rarg, rangeTableList, - joinRangeTableEntries); - } - else if (IsA(joinNode, RangeTblRef)) - { - int rangeTableIndex = ((RangeTblRef *) joinNode)->rtindex; - RangeTblEntry *rte = rt_fetch(rangeTableIndex, rangeTableList); - *joinRangeTableEntries = lappend(*joinRangeTableEntries, rte); - } - else - { - pg_unreachable(); - } -} - - /* * GetNextRTEToConvertToSubquery returns the range table entry * which should be converted to a subquery. It considers the local join policy @@ -291,9 +230,8 @@ RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid r * ShouldConvertLocalTableJoinsToSubqueries returns true if we should * convert local-dist table joins to subqueries. */ -static bool +bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, - Oid resultRelationId, PlannerRestrictionContext * plannerRestrictionContext) { @@ -303,7 +241,7 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, return false; } - if (!ContainsTableToBeConvertedToSubquery(rangeTableList, resultRelationId)) + if (!ContainsTableToBeConvertedToSubquery(rangeTableList)) { return false; } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 7fe70a4f3..a0c0a7b1d 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -178,9 +178,11 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); -static void UpdateVarNosInQualForSubquery(Query *query); -static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList, Oid - resultRelationId); +static void +UpdateVarNosInNode(Query *query, Index newVarNo); +static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList); +static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, + List **joinRangeTableEntries); /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. @@ -336,18 +338,75 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context RecursivelyPlanNonColocatedSubqueries(query, context); } - /* - * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or - * a query with local table/citus local table and subquery. We convert local/citus local - * tables to a subquery until they can be planned. - * This is the last call in this function since we want the other calls to be finished - * so that we can check if the current plan is router plannable at any step within this function. - */ - RecursivelyPlanLocalTableJoins(query, context); + + PlannerRestrictionContext *plannerRestrictionContext = + context->plannerRestrictionContext; + + List *rangeTableList = NIL; + GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, + &rangeTableList); + + if (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, + plannerRestrictionContext)) { + /* + * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or + * a query with local table/citus local table and subquery. We convert local/citus local + * tables to a subquery until they can be planned. + * This is the last call in this function since we want the other calls to be finished + * so that we can check if the current plan is router plannable at any step within this function. + */ + RecursivelyPlanLocalTableJoins(query, context, rangeTableList); + + } + return NULL; } +/* + * GetRangeTableEntriesFromJoinTree gets the range table entries that are + * on the given join tree. + */ +static void +GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, + List **joinRangeTableEntries) +{ + if (joinNode == NULL) + { + return; + } + else if (IsA(joinNode, FromExpr)) + { + FromExpr *fromExpr = (FromExpr *) joinNode; + Node *fromElement; + + foreach_ptr(fromElement, fromExpr->fromlist) + { + GetRangeTableEntriesFromJoinTree(fromElement, rangeTableList, + joinRangeTableEntries); + } + } + else if (IsA(joinNode, JoinExpr)) + { + JoinExpr *joinExpr = (JoinExpr *) joinNode; + GetRangeTableEntriesFromJoinTree(joinExpr->larg, rangeTableList, + joinRangeTableEntries); + GetRangeTableEntriesFromJoinTree(joinExpr->rarg, rangeTableList, + joinRangeTableEntries); + } + else if (IsA(joinNode, RangeTblRef)) + { + int rangeTableIndex = ((RangeTblRef *) joinNode)->rtindex; + RangeTblEntry *rte = rt_fetch(rangeTableIndex, rangeTableList); + *joinRangeTableEntries = lappend(*joinRangeTableEntries, rte); + } + else + { + pg_unreachable(); + } +} + + /* * ShouldRecursivelyPlanNonColocatedSubqueries returns true if the input query contains joins @@ -1360,6 +1419,8 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) /* * ReplaceRTERelationWithRteSubquery replaces the input rte relation target entry * with a subquery. The function also pushes down the filters to the subquery. + * + * It then recursively plans the subquery. */ void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, @@ -1369,10 +1430,7 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); Expr *andedBoundExpressions = make_ands_explicit(restrictionList); subquery->jointree->quals = (Node *) andedBoundExpressions; - UpdateVarNosInQualForSubquery(subquery); - - /* force recursively planning of the newly created subquery */ - subquery->limitOffset = (Node *) MakeIntegerConst(0); + UpdateVarNosInNode(subquery, SINGLE_RTE_INDEX); /* replace the function with the constructed subquery */ rangeTableEntry->rtekind = RTE_SUBQUERY; @@ -1396,24 +1454,25 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict get_rel_name(rangeTableEntry->relid), ApplyLogRedaction(subqueryString->data)))); } + + /* as we created the subquery, now forcefully recursively plan it */ RecursivelyPlanSubquery(rangeTableEntry->subquery, context); } /* - * UpdateVarNosInQualForSubquery iterates the Vars in the - * given quals node and updates the varno's as 1 as there - * will be only one RTE in rtable, which is the subquery. + * UpdateVarNosInNode iterates the Vars in the + * given node and updates the varno's as the newVarNo. */ static void -UpdateVarNosInQualForSubquery(Query *query) +UpdateVarNosInNode(Query *query, Index newVarNo) { List *varList = pull_var_clause(query->jointree->quals, PVC_RECURSE_AGGREGATES | PVC_RECURSE_PLACEHOLDERS); Var *var = NULL; foreach_ptr(var, varList) { - var->varno = SINGLE_RTE_INDEX; + var->varno = newVarNo; } } @@ -1423,13 +1482,13 @@ UpdateVarNosInQualForSubquery(Query *query) * any table that should be converted to a subquery, which otherwise is not plannable. */ bool -ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) +ContainsTableToBeConvertedToSubquery(List *rangeTableList) { if (ContainsLocalTableDistributedTableJoin(rangeTableList)) { return true; } - if (ModifiesLocalTableWithRemoteCitusLocalTable(rangeTableList, resultRelationId)) + if (ModifiesLocalTableWithRemoteCitusLocalTable(rangeTableList)) { return true; } @@ -1443,7 +1502,7 @@ ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid resultRelationId) * MX structure. */ static bool -ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList, Oid resultRelationId) +ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList) { bool containsLocalResultRelation = false; bool containsRemoteCitusLocalTable = false; diff --git a/src/include/distributed/local_distributed_join_planner.h b/src/include/distributed/local_distributed_join_planner.h index 690999bb2..88fa5e1be 100644 --- a/src/include/distributed/local_distributed_join_planner.h +++ b/src/include/distributed/local_distributed_join_planner.h @@ -27,7 +27,11 @@ typedef enum extern int LocalTableJoinPolicy; +extern bool +ShouldConvertLocalTableJoinsToSubqueries(Query *query, + List *rangeTableList, + PlannerRestrictionContext *plannerRestrictionContext); extern void RecursivelyPlanLocalTableJoins(Query *query, - RecursivePlanningContext *context); + RecursivePlanningContext *context, List *rangeTableList); #endif /* LOCAL_DISTRIBUTED_JOIN_PLANNER_H */ diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 5a2484665..ed85f88ed 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -53,8 +53,7 @@ extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, List *requiredAttrNumbers, RecursivePlanningContext *context); -extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList, Oid - resultRelationId); +extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList); extern bool IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry); extern bool IsRelationLocalTableOrMatView(Oid relationId); #endif /* RECURSIVE_PLANNING_H */ From 69992d58f989cd6f82851890a27846823c2cb82b Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Sun, 6 Dec 2020 17:34:31 +0300 Subject: [PATCH 25/37] Add broken local-dist table modifications tests It seems that most of the updates were broken, we weren't aware of it because there wasn't any data in the tables. They are broken mostly because local tables do not have a shard id and some code paths should be updated with that information, currently when there is an invalid shard id, it is assumed to be pruned. Consider local tables in router planner In case there is a local table, the shard id will not be valid and there are some checks that rely on shard id, we should skip these in case of local tables, which is handled with a dummy placement. Add citus local table dist table join tests add local-dist table mixed joins tests --- src/backend/distributed/commands/index.c | 45 - .../distributed/executor/citus_custom_scan.c | 7 + .../planner/local_distributed_join_planner.c | 2 + .../planner/multi_router_planner.c | 3 +- .../distributed/utils/citus_copyfuncs.c | 1 + src/include/distributed/commands.h | 5 - .../distributed/multi_physical_planner.h | 1 + .../expected/citus_local_dist_joins.out | 469 +++++ .../expected/citus_local_tables_queries.out | 24 +- src/test/regress/expected/dml_recursive.out | 4 +- .../expected/local_dist_join_mixed.out | 1532 +++++++++++++++++ .../local_dist_join_modifications.out | 597 +++++++ .../expected/local_distributed_table_join.out | 0 .../regress/expected/local_table_join.out | 818 +++------ .../regress/expected/mixed_relkind_tests.out | 44 +- .../regress/expected/multi_partitioning.out | 34 +- ...relation_planning_restirction_pushdown.out | 116 +- src/test/regress/multi_schedule | 3 + .../regress/sql/citus_local_dist_joins.sql | 232 +++ ...ble_join.sql => local_dist_join_mixed.sql} | 74 +- .../sql/local_dist_join_modifications.sql | 372 ++++ src/test/regress/sql/local_table_join.sql | 248 +-- 22 files changed, 3612 insertions(+), 1019 deletions(-) create mode 100644 src/test/regress/expected/citus_local_dist_joins.out create mode 100644 src/test/regress/expected/local_dist_join_mixed.out create mode 100644 src/test/regress/expected/local_dist_join_modifications.out delete mode 100644 src/test/regress/expected/local_distributed_table_join.out create mode 100644 src/test/regress/sql/citus_local_dist_joins.sql rename src/test/regress/sql/{local_distributed_table_join.sql => local_dist_join_mixed.sql} (88%) create mode 100644 src/test/regress/sql/local_dist_join_modifications.sql diff --git a/src/backend/distributed/commands/index.c b/src/backend/distributed/commands/index.c index cf68b90f6..81a037abc 100644 --- a/src/backend/distributed/commands/index.c +++ b/src/backend/distributed/commands/index.c @@ -249,51 +249,6 @@ CreateIndexStmtGetSchemaId(IndexStmt *createIndexStatement) return namespaceId; } - -/* - * ExecuteFunctionOnEachTableIndex executes the given indexProcessor function on each - * index of the given relation. - * It returns a list that is filled by the indexProcessor. - */ -List * -ExecuteFunctionOnEachTableIndex(Oid relationId, IndexProcesor indexProcessor) -{ - List *result = NIL; - ScanKeyData scanKey[1]; - int scanKeyCount = 1; - - PushOverrideEmptySearchPath(CurrentMemoryContext); - - /* open system catalog and scan all indexes that belong to this table */ - Relation pgIndex = table_open(IndexRelationId, AccessShareLock); - - ScanKeyInit(&scanKey[0], Anum_pg_index_indrelid, - BTEqualStrategyNumber, F_OIDEQ, relationId); - - SysScanDesc scanDescriptor = systable_beginscan(pgIndex, - IndexIndrelidIndexId, true, /* indexOK */ - NULL, scanKeyCount, scanKey); - - HeapTuple heapTuple = systable_getnext(scanDescriptor); - while (HeapTupleIsValid(heapTuple)) - { - Form_pg_index indexForm = (Form_pg_index) GETSTRUCT(heapTuple); - indexProcessor(indexForm, &result); - - heapTuple = systable_getnext(scanDescriptor); - } - - /* clean up scan and close system catalog */ - systable_endscan(scanDescriptor); - table_close(pgIndex, AccessShareLock); - - /* revert back to original search_path */ - PopOverrideSearchPath(); - - return result; -} - - /* * ExecuteFunctionOnEachTableIndex executes the given pgIndexProcessor function on each * index of the given relation. diff --git a/src/backend/distributed/executor/citus_custom_scan.c b/src/backend/distributed/executor/citus_custom_scan.c index 4a59512f2..106f47cbe 100644 --- a/src/backend/distributed/executor/citus_custom_scan.c +++ b/src/backend/distributed/executor/citus_custom_scan.c @@ -326,6 +326,7 @@ CitusBeginModifyScan(CustomScanState *node, EState *estate, int eflags) scanState->distributedPlan = currentPlan; Job *workerJob = currentPlan->workerJob; + Query *jobQuery = workerJob->jobQuery; if (ModifyJobNeedsEvaluation(workerJob)) @@ -367,6 +368,11 @@ CitusBeginModifyScan(CustomScanState *node, EState *estate, int eflags) RebuildQueryStrings(workerJob); } + if (workerJob->onDummyPlacement) { + /* if this job is on a dummy placement, then it doesn't operate on + an actual shard placement */ + return; + } /* * Now that we know the shard ID(s) we can acquire the necessary shard metadata * locks. Once we have the locks it's safe to load the placement metadata. @@ -375,6 +381,7 @@ CitusBeginModifyScan(CustomScanState *node, EState *estate, int eflags) /* prevent concurrent placement changes */ AcquireMetadataLocks(workerJob->taskList); + /* modify tasks are always assigned using first-replica policy */ workerJob->taskList = FirstReplicaAssignTaskList(workerJob->taskList); diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index e819ada8b..7fdf97af6 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -250,6 +250,8 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, plannerRestrictionContext, query); if (IsRouterPlannable(query, plannerRestrictionContext)) { + ereport(DEBUG1, (errmsg("local-distributed table joins will not be converted, " + "as the query is router plannable"))); return false; } return true; diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 2b97da267..537091359 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -1754,6 +1754,7 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon Job *job = CreateJob(originalQuery); job->partitionKeyValue = partitionKeyValue; + job->onDummyPlacement = replacePrunedQueryWithDummy; if (originalQuery->resultRelation > 0) { @@ -1828,7 +1829,7 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, placementList); } } - else if (shardId == INVALID_SHARD_ID) + else if (shardId == INVALID_SHARD_ID && !job->onDummyPlacement) { /* modification that prunes to 0 shards */ job->taskList = NIL; diff --git a/src/backend/distributed/utils/citus_copyfuncs.c b/src/backend/distributed/utils/citus_copyfuncs.c index 24caf6a8d..698e96449 100644 --- a/src/backend/distributed/utils/citus_copyfuncs.c +++ b/src/backend/distributed/utils/citus_copyfuncs.c @@ -101,6 +101,7 @@ copyJobInfo(Job *newnode, Job *from) COPY_NODE_FIELD(partitionKeyValue); COPY_NODE_FIELD(localPlannedStatements); COPY_SCALAR_FIELD(parametersInJobQueryResolved); + COPY_SCALAR_FIELD(onDummyPlacement); } diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index e24b47757..3461e2246 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -186,13 +186,8 @@ extern List * PostprocessIndexStmt(Node *node, const char *queryString); extern void ErrorIfUnsupportedAlterIndexStmt(AlterTableStmt *alterTableStatement); extern void MarkIndexValid(IndexStmt *indexStmt); -<<<<<<< HEAD extern List * ExecuteFunctionOnEachTableIndex(Oid relationId, PGIndexProcessor pgIndexProcessor); -======= -extern List * ExecuteFunctionOnEachTableIndex(Oid relationId, IndexProcesor - indexProcessor); ->>>>>>> Increase readability of the current structure /* objectaddress.c - forward declarations */ extern ObjectAddress CreateExtensionStmtObjectAddress(Node *stmt, bool missing_ok); diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index 24e60facd..c15c6bcf9 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -163,6 +163,7 @@ typedef struct Job * query. */ bool parametersInJobQueryResolved; + bool onDummyPlacement; } Job; diff --git a/src/test/regress/expected/citus_local_dist_joins.out b/src/test/regress/expected/citus_local_dist_joins.out new file mode 100644 index 000000000..dbbf37bfe --- /dev/null +++ b/src/test/regress/expected/citus_local_dist_joins.out @@ -0,0 +1,469 @@ +CREATE SCHEMA citus_local_dist_joins; +SET search_path TO citus_local_dist_joins; +SET client_min_messages to ERROR; +SELECT master_add_node('localhost', :master_port, groupId => 0); + master_add_node +--------------------------------------------------------------------- + 5 +(1 row) + +CREATE TABLE citus_local(key int, value text); +SELECT create_citus_local_table('citus_local'); + create_citus_local_table +--------------------------------------------------------------------- + +(1 row) + +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); +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); +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 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)); +SELECT create_distributed_table('distributed_table_composite', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; +CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; +-- set log messages to debug1 so that we can see which tables are recursively planned. +SET client_min_messages TO DEBUG1; +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; +INSERT INTO citus_local 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 +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table_windex USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table_windex USING (value)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table_windex ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; +DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (citus_local_dist_joins.citus_local 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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 100 +(1 row) + +-- no unique index, citus local table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table USING(key); +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table USING(value); +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table USING (value)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table.key))) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) 10))) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE true +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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) + JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((citus_local_dist_joins.distributed_partitioned_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)) postgres_table USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- update +BEGIN; +SELECT COUNT(DISTINCT value) FROM citus_local; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + citus_local +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = citus_local.key; +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.citus_local SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM citus_local; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table.key = citus_local.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table SET value = 'test'::text 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)) citus_local WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table_pkey.key = citus_local.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table_pkey SET value = 'test'::text 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)) citus_local WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table_windex.key = citus_local.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table_windex SET value = 'test'::text 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)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +UPDATE + mv1 +SET + value = 'test' +FROM + citus_local +WHERE + mv1.key = citus_local.key; +ERROR: materialized views in modify queries are not supported +ROLLBACK; +BEGIN; +UPDATE + citus_local +SET + value = 'test' +FROM + mv1 +WHERE + mv1.key = citus_local.key; +ERROR: materialized views in modify queries are not supported +ROLLBACK; +BEGIN; +UPDATE + citus_local +SET + value = 'test' +FROM + mv2 +WHERE + mv2.key = citus_local.key; +ERROR: materialized views in modify queries are not supported +ROLLBACK; +-- DELETE operations +BEGIN; +SELECT COUNT(DISTINCT value) FROM citus_local; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + citus_local +USING + distributed_table +WHERE + distributed_table.key = citus_local.key; +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.citus_local USING (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM citus_local; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + distributed_table +USING + citus_local +WHERE + distributed_table.key = citus_local.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table USING (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + distributed_table_pkey +USING + citus_local +WHERE + distributed_table_pkey.key = citus_local.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table_pkey USING (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + distributed_table_windex +USING + citus_local +WHERE + distributed_table_windex.key = citus_local.key; +DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table_windex USING (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +DELETE FROM + mv1 +USING + citus_local +WHERE + mv1.key = citus_local.key; +ERROR: materialized views in modify queries are not supported +DELETE FROM + citus_local +USING + mv1 +WHERE + mv1.key = citus_local.key; +ERROR: materialized views in modify queries are not supported +DELETE FROM + citus_local +USING + mv2 +WHERE + mv2.key = citus_local.key; +ERROR: materialized views in modify queries are not supported +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM citus_local_dist_joins.distributed_table LIMIT 1 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM citus_local_dist_joins.citus_local +DEBUG: local-distributed table joins will not be converted, as the query is router plannable +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((citus_local_dist_joins.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN citus_local_dist_joins.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM citus_local_dist_joins.distributed_table LIMIT 1 +DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM citus_local_dist_joins.citus_local +DEBUG: local-distributed table joins will not be converted, as the query is router plannable +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((citus_local_dist_joins.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN citus_local_dist_joins.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SET client_min_messages to ERROR; +DROP TABLE citus_local; +SELECT master_remove_node('localhost', :master_port); + master_remove_node +--------------------------------------------------------------------- + +(1 row) + +\set VERBOSITY terse +DROP SCHEMA citus_local_dist_joins CASCADE; diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 0529d6f02..6ccc25bf9 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -154,7 +154,7 @@ 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 a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT NULL::integer AS a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true count --------------------------------------------------------------------- 36 @@ -167,7 +167,7 @@ SELECT count(*) FROM 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_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509000 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 --------------------------------------------------------------------- @@ -527,7 +527,7 @@ NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queri -- 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 a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT NULL::integer AS a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true count --------------------------------------------------------------------- 36 @@ -654,7 +654,7 @@ NOTICE: executing the copy locally for shard xxxxx 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 a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT NULL::integer AS a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 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 @@ -699,12 +699,12 @@ 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509002 reference_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)) 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 @@ -717,13 +717,13 @@ 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, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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)) 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true -- should not work, add HINT use CTEs DELETE FROM citus_local_table USING distributed_table @@ -732,13 +732,13 @@ NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.ci DELETE FROM reference_table USING citus_local_table WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509002 reference_table USING (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) 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, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table USING (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) -- just works DELETE FROM citus_local_table @@ -795,8 +795,8 @@ 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true OFFSET 0 -NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_2_1509001 citus_local_table_2 WHERE true OFFSET 0 +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_2_1509001 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 --------------------------------------------------------------------- diff --git a/src/test/regress/expected/dml_recursive.out b/src/test/regress/expected/dml_recursive.out index ff75e6277..304e53218 100644 --- a/src/test/regress/expected/dml_recursive.out +++ b/src/test/regress/expected/dml_recursive.out @@ -352,8 +352,8 @@ FROM distributed_table WHERE distributed_table.tenant_id = local_table.id; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE recursive_dml_queries.local_table SET id = 'citus_test'::text FROM (SELECT intermediate_result.tenant_id, intermediate_result.dept, intermediate_result.info FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(tenant_id text, dept integer, info jsonb)) distributed_table WHERE (distributed_table.tenant_id OPERATOR(pg_catalog.=) local_table.id) RESET client_min_messages; DROP SCHEMA recursive_dml_queries CASCADE; diff --git a/src/test/regress/expected/local_dist_join_mixed.out b/src/test/regress/expected/local_dist_join_mixed.out new file mode 100644 index 000000000..95cf94ff9 --- /dev/null +++ b/src/test/regress/expected/local_dist_join_mixed.out @@ -0,0 +1,1532 @@ +CREATE SCHEMA local_dist_join_mixed; +SET search_path TO local_dist_join_mixed; +CREATE TABLE distributed (id bigserial PRIMARY KEY, + name text, + created_at timestamptz DEFAULT now()); +CREATE TABLE reference (id bigserial PRIMARY KEY, + title text); +CREATE TABLE local (id bigserial PRIMARY KEY, + title text); +-- these above restrictions brought us to the following schema +SELECT create_reference_table('reference'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_table('distributed', 'id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO distributed SELECT i, i::text, now() FROM generate_series(0,100)i; +INSERT INTO reference SELECT i, i::text FROM generate_series(0,100)i; +INSERT INTO local SELECT i, i::text FROM generate_series(0,100)i; +SET client_min_messages to DEBUG1; +-- very simple 1-1 Joins +SELECT count(*) FROM distributed JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM distributed JOIN local ON (name = title); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((distributed.name OPERATOR(pg_catalog.=) local.title))) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) + count +--------------------------------------------------------------------- + 10201 +(1 row) + +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) + count +--------------------------------------------------------------------- + 5050 +(1 row) + +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE ((name OPERATOR(pg_catalog.=) (id)::text) AND (id OPERATOR(pg_catalog.=) 1)) +DEBUG: generating subplan XXX_1 for subquery SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE ((name OPERATOR(pg_catalog.=) (id)::text) AND (id OPERATOR(pg_catalog.=) 1)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 99 +(1 row) + +SELECT count(*) FROM distributed JOIN local USING (id) WHERE false; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE false +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE false +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) WHERE false + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR True; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) + count +--------------------------------------------------------------------- + 5050 +(1 row) + +SELECT count(*) FROM distributed d1 JOIN local ON (name::int + local.id > d1.id AND d1.id < local.title::int) WHERE d1.id = 1; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local ON (((((d1.name)::integer OPERATOR(pg_catalog.+) local.id) OPERATOR(pg_catalog.>) d1.id) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 99 +(1 row) + +SELECT count(*) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT hashtext(local.id::text) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1 LIMIT 4; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT hashtext((local.id)::text) AS hashtext FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) ORDER BY (hashtext((local.id)::text)) LIMIT 4 +DEBUG: push down of limit count: 4 + hashtext +--------------------------------------------------------------------- + -2114455578 + -2097988278 + -1997006946 + -1985772843 +(4 rows) + +SELECT '' as "xxx", local.*, 'xxx' as "test" FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1,2,3 LIMIT 4; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT ''::text AS xxx, local.id, local.title, 'xxx'::text AS test FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) ORDER BY ''::text, local.id, local.title LIMIT 4 +DEBUG: push down of limit count: 4 + xxx | id | title | test +--------------------------------------------------------------------- + | 0 | 0 | xxx + | 1 | 1 | xxx + | 2 | 2 | xxx + | 3 | 3 | xxx +(4 rows) + +SELECT local.title, count(*) FROM distributed JOIN local USING (id) GROUP BY 1 ORDER BY 1, 2 DESC LIMIT 5; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.title, count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) GROUP BY local.title ORDER BY local.title, (count(*)) DESC LIMIT 5 + title | count +--------------------------------------------------------------------- + 0 | 1 + 1 | 1 + 10 | 1 + 100 | 1 + 11 | 1 +(5 rows) + +SELECT distributed.id as id1, local.id as id2 FROM distributed JOIN local USING(id) ORDER BY distributed.id + local.id LIMIT 5; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id AS id1, local.id AS id2 FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) ORDER BY (distributed.id OPERATOR(pg_catalog.+) local.id) LIMIT 5 +DEBUG: push down of limit count: 5 + id1 | id2 +--------------------------------------------------------------------- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 +(5 rows) + +SELECT distributed.id as id1, local.id as id2, count(*) FROM distributed JOIN local USING(id) GROUP BY distributed.id, local.id ORDER BY 1,2 LIMIT 5; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id AS id1, local.id AS id2, count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) GROUP BY distributed.id, local.id ORDER BY distributed.id, local.id LIMIT 5 +DEBUG: push down of limit count: 5 + id1 | id2 | count +--------------------------------------------------------------------- + 0 | 0 | 1 + 1 | 1 | 1 + 2 | 2 | 1 + 3 | 3 | 1 + 4 | 4 | 1 +(5 rows) + +-- basic subqueries that cannot be pulled up +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = title); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) local.title))) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) + count +--------------------------------------------------------------------- + 10201 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) + count +--------------------------------------------------------------------- + 5050 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 99 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) AND false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) + count +--------------------------------------------------------------------- + 5050 +(1 row) + +-- pull up subqueries as they are pretty simple, local table should be recursively planned +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = title); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) local.title))) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) + count +--------------------------------------------------------------------- + 10201 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) + count +--------------------------------------------------------------------- + 5050 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 99 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) AND false) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) + count +--------------------------------------------------------------------- + 5050 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed WHERE id = 2) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) 2)) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed WHERE false) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE (false AND (id OPERATOR(pg_catalog.<) (title)::integer)) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE (false AND (id OPERATOR(pg_catalog.<) (title)::integer)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE false) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- TEMPORARY table +CREATE TEMPORARY TABLE temp_local AS SELECT * FROM local; +SELECT count(*) FROM distributed JOIN temp_local USING (id); +DEBUG: Wrapping relation "temp_local" to a subquery: SELECT id, NULL::text AS title FROM temp_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM temp_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) temp_local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- UNLOGGED table +CREATE UNLOGGED TABLE unlogged_local AS SELECT * FROM local; +SELECT count(*) FROM distributed JOIN unlogged_local USING (id); +DEBUG: Wrapping relation "unlogged_local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.unlogged_local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.unlogged_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) unlogged_local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- mat view +CREATE MATERIALIZED VIEW mat_view AS SELECT * FROM local; +SELECT count(*) FROM distributed JOIN mat_view USING (id); +DEBUG: Wrapping relation "mat_view" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.mat_view WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.mat_view WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) mat_view USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +CREATE VIEW local_regular_view AS SELECT * FROM local; +CREATE VIEW dist_regular_view AS SELECT * FROM distributed; +SELECT count(*) FROM distributed JOIN local_regular_view USING (id); +DEBUG: generating subplan XXX_1 for subquery SELECT local.id, local.title FROM local_dist_join_mixed.local +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_regular_view USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM local JOIN dist_regular_view USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) dist_regular_view USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM dist_regular_view JOIN local_regular_view USING (id); +DEBUG: generating subplan XXX_1 for subquery SELECT local.id, local.title FROM local_dist_join_mixed.local +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) dist_regular_view JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_regular_view USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- join alias/table alias +SELECT COUNT(*) FROM (distributed JOIN local USING (id)) AS t(a,b,c,d) ORDER BY d,c,a,b LIMIT 3; +ERROR: column "local.title" must appear in the GROUP BY clause or be used in an aggregate function +SELECT COUNT(*) FROM (distributed d1(x,y,y1) JOIN local l1(x,t) USING (x)) AS t(a,b,c,d) ORDER BY d,c,a,b LIMIT 3; +ERROR: column "l1.t" must appear in the GROUP BY clause or be used in an aggregate function +-- final queries are pushdown queries +SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + sum +--------------------------------------------------------------------- + 10100 +(1 row) + +SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id)) DESC LIMIT 4 +DEBUG: push down of limit count: 4 + sum +--------------------------------------------------------------------- + 200 + 198 + 196 + 194 +(4 rows) + +SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) ORDER BY 1 DESC LIMIT 4; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) LEFT JOIN local_dist_join_mixed.distributed d2 USING (id)) ORDER BY (count(*)) DESC LIMIT 4 +DEBUG: push down of limit count: 4 + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(DISTINCT d1.name::int * local.id) FROM distributed d1 JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(DISTINCT ((d1.name)::integer OPERATOR(pg_catalog.*) local.id)) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- final queries are router queries +SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local USING (id)) WHERE (d1.id OPERATOR(pg_catalog.=) 1) + sum +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1 ORDER BY 1 DESC LIMIT 4; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id) AS sum FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local USING (id)) WHERE (d1.id OPERATOR(pg_catalog.=) 1) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id)) DESC LIMIT 4 + sum +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) WHERE d2.id = 1 ORDER BY 1 DESC LIMIT 4; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) LEFT JOIN local_dist_join_mixed.distributed d2 USING (id)) WHERE (d2.id OPERATOR(pg_catalog.=) 1) ORDER BY (count(*)) DESC LIMIT 4 + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- final queries are pull to coordinator queries +SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id + local.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY (d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY (d1.id OPERATOR(pg_catalog.+) local.id))) DESC LIMIT 4 + sum +--------------------------------------------------------------------- + 200 + 198 + 196 + 194 +(4 rows) + +-- nested subqueries +SELECT + count(*) +FROM + (SELECT * FROM (SELECT * FROM distributed) as foo) as bar + JOIN + local + USING(id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) foo) bar JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + local + USING(id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + local + USING(id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id); +DEBUG: generating subplan XXX_1 for subquery SELECT id, title, random() AS random FROM local_dist_join_mixed.local +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT foo2.id, foo2.title, foo2.random, random() AS random FROM (SELECT intermediate_result.id, intermediate_result.title, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text, random double precision)) foo2) bar2(id, title, random, random_1) USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- TODO: Unnecessary recursive planning for local +SELECT + count(*) +FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed LIMIT 1) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id); +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT id, name, created_at, random() AS random FROM local_dist_join_mixed.distributed LIMIT 1 +DEBUG: generating subplan XXX_2 for subquery SELECT id, title, random() AS random FROM local_dist_join_mixed.local +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone, random double precision)) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT foo2.id, foo2.title, foo2.random, random() AS random FROM (SELECT intermediate_result.id, intermediate_result.title, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text, random double precision)) foo2) bar2(id, title, random, random_1) USING (id)) + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- subqueries in WHERE clause +-- is not colocated, and the JOIN inside as well. +-- so should be recursively planned twice +SELECT + count(*) +FROM + distributed +WHERE + id > (SELECT + count(*) + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id) + ); +DEBUG: generating subplan XXX_1 for subquery SELECT id, title, random() AS random FROM local_dist_join_mixed.local +DEBUG: generating subplan XXX_2 for subquery SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT foo2.id, foo2.title, foo2.random, random() AS random FROM (SELECT intermediate_result.id, intermediate_result.title, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text, random double precision)) foo2) bar2(id, title, random, random_1) USING (id)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.>) (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- two distributed tables are co-located and JOINed on distribution +-- key, so should be fine to pushdown +SELECT + count(*) +FROM + distributed d_upper +WHERE + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 + USING(id) + ) IS NOT NULL; +DEBUG: generating subplan XXX_1 for subquery SELECT id, title, random() AS random FROM local_dist_join_mixed.local +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed d_upper WHERE ((SELECT bar.id FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) d_upper.id)) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT foo2.id, foo2.title, foo2.random, random() AS random FROM (SELECT intermediate_result.id, intermediate_result.title, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text, random double precision)) foo2) bar2(id, title, random, random_1) USING (id))) IS NOT NULL) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT + count(*) +FROM + distributed d_upper +WHERE + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + local as foo + USING(id) + ) IS NOT NULL; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed d_upper WHERE ((SELECT bar.id FROM ((SELECT foo_1.id, foo_1.name, foo_1.created_at, foo_1.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) d_upper.id)) foo_1) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) foo USING (id))) IS NOT NULL) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT + count(*) +FROM + distributed d_upper +WHERE d_upper.id > + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + local as foo + USING(id) + ); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed d_upper WHERE (id OPERATOR(pg_catalog.>) (SELECT bar.id FROM ((SELECT foo_1.id, foo_1.name, foo_1.created_at, foo_1.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) d_upper.id)) foo_1) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) foo USING (id)))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT + count(*) +FROM + distributed d_upper +WHERE + (SELECT + bar.id + FROM + (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar + JOIN + (SELECT *, random() FROM (SELECT *,random() FROM local WHERE d_upper.id = id) as foo2) as bar2 + USING(id) + ) IS NOT NULL; +ERROR: direct joins between distributed and local tables are not supported +HINT: Use CTE's or subqueries to select from local tables and use them in joins +-- subqueries in the target list +-- router, should work +select (SELECT local.id) FROM local, distributed WHERE distributed.id = 1 LIMIT 1; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local.id) AS id FROM local_dist_join_mixed.local, (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed WHERE (distributed.id OPERATOR(pg_catalog.=) 1) LIMIT 1 + id +--------------------------------------------------------------------- + 0 +(1 row) + +-- should fail +select (SELECT local.id) FROM local, distributed WHERE distributed.id != 1 LIMIT 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local.id) AS id FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.<>) 1) LIMIT 1 +ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses +HINT: Consider using an equality filter on the distributed table's partition column. +-- currently not supported, but should work with https://github.com/citusdata/citus/pull/4360/files +SELECT + name, (SELECT id FROM local WHERE id = e.id) +FROM + distributed e +ORDER BY 1,2 LIMIT 1; +ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses +HINT: Consider using an equality filter on the distributed table's partition column. +-- set operations +SELECT local.* FROM distributed JOIN local USING (id) + EXCEPT +SELECT local.* FROM distributed JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT local.id, local.title FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: generating subplan XXX_4 for subquery SELECT local.id, local.title FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text) EXCEPT SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text) + id | title +--------------------------------------------------------------------- +(0 rows) + +SELECT distributed.* FROM distributed JOIN local USING (id) + EXCEPT +SELECT distributed.* FROM distributed JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT distributed.id, distributed.name, distributed.created_at FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: generating subplan XXX_4 for subquery SELECT distributed.id, distributed.name, distributed.created_at FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) EXCEPT SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) + id | name | created_at +--------------------------------------------------------------------- +(0 rows) + +SELECT count(*) FROM +( + (SELECT * FROM (SELECT * FROM local) as f JOIN distributed USING (id)) + UNION ALL + (SELECT * FROM (SELECT * FROM local) as f2 JOIN distributed USING (id)) +) bar; +DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local +DEBUG: generating subplan XXX_2 for subquery SELECT id, title FROM local_dist_join_mixed.local +DEBUG: generating subplan XXX_3 for subquery SELECT f.id, f.title, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) f JOIN local_dist_join_mixed.distributed USING (id)) +DEBUG: generating subplan XXX_4 for subquery SELECT f2.id, f2.title, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) f2 JOIN local_dist_join_mixed.distributed USING (id)) +DEBUG: generating subplan XXX_5 for subquery SELECT intermediate_result.id, intermediate_result.title, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text, name text, created_at timestamp with time zone) UNION ALL SELECT intermediate_result.id, intermediate_result.title, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text, name text, created_at timestamp with time zone) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.id, intermediate_result.title, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text, name text, created_at timestamp with time zone)) bar + count +--------------------------------------------------------------------- + 202 +(1 row) + +SELECT count(*) FROM +( + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as fo) + UNION ALL + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) +) bar; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT id, name, created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) fo +DEBUG: generating subplan XXX_4 for subquery SELECT id, name, created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) ba +DEBUG: generating subplan XXX_5 for subquery SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) UNION ALL SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) bar + count +--------------------------------------------------------------------- + 202 +(1 row) + +select count(DISTINCT id) +FROM +( + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as fo) + UNION ALL + (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) +) bar; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(DISTINCT id) AS count FROM (SELECT fo.id, fo.name, fo.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) fo UNION ALL SELECT ba.id, ba.name, ba.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) ba) bar + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- 25 Joins +select ' select count(*) from distributed ' || string_Agg('INNER +JOIN local u'|| x::text || ' USING (id)',' ') from +generate_Series(1,25)x; + ?column? +--------------------------------------------------------------------- + select count(*) from distributed INNER+ + JOIN local u1 USING (id) INNER + + JOIN local u2 USING (id) INNER + + JOIN local u3 USING (id) INNER + + JOIN local u4 USING (id) INNER + + JOIN local u5 USING (id) INNER + + JOIN local u6 USING (id) INNER + + JOIN local u7 USING (id) INNER + + JOIN local u8 USING (id) INNER + + JOIN local u9 USING (id) INNER + + JOIN local u10 USING (id) INNER + + JOIN local u11 USING (id) INNER + + JOIN local u12 USING (id) INNER + + JOIN local u13 USING (id) INNER + + JOIN local u14 USING (id) INNER + + JOIN local u15 USING (id) INNER + + JOIN local u16 USING (id) INNER + + JOIN local u17 USING (id) INNER + + JOIN local u18 USING (id) INNER + + JOIN local u19 USING (id) INNER + + JOIN local u20 USING (id) INNER + + JOIN local u21 USING (id) INNER + + JOIN local u22 USING (id) INNER + + JOIN local u23 USING (id) INNER + + JOIN local u24 USING (id) INNER + + JOIN local u25 USING (id) +(1 row) + +\gexec + select count(*) from distributed INNER +JOIN local u1 USING (id) INNER +JOIN local u2 USING (id) INNER +JOIN local u3 USING (id) INNER +JOIN local u4 USING (id) INNER +JOIN local u5 USING (id) INNER +JOIN local u6 USING (id) INNER +JOIN local u7 USING (id) INNER +JOIN local u8 USING (id) INNER +JOIN local u9 USING (id) INNER +JOIN local u10 USING (id) INNER +JOIN local u11 USING (id) INNER +JOIN local u12 USING (id) INNER +JOIN local u13 USING (id) INNER +JOIN local u14 USING (id) INNER +JOIN local u15 USING (id) INNER +JOIN local u16 USING (id) INNER +JOIN local u17 USING (id) INNER +JOIN local u18 USING (id) INNER +JOIN local u19 USING (id) INNER +JOIN local u20 USING (id) INNER +JOIN local u21 USING (id) INNER +JOIN local u22 USING (id) INNER +JOIN local u23 USING (id) INNER +JOIN local u24 USING (id) INNER +JOIN local u25 USING (id) +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE true +DEBUG: generating subplan XXX_4 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE true +DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE true +DEBUG: generating subplan XXX_6 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE true +DEBUG: generating subplan XXX_7 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE true +DEBUG: generating subplan XXX_8 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE true +DEBUG: generating subplan XXX_9 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE true +DEBUG: generating subplan XXX_10 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE true +DEBUG: generating subplan XXX_11 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE true +DEBUG: generating subplan XXX_12 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE true +DEBUG: generating subplan XXX_13 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE true +DEBUG: generating subplan XXX_14 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE true +DEBUG: generating subplan XXX_15 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE true +DEBUG: generating subplan XXX_16 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE true +DEBUG: generating subplan XXX_17 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE true +DEBUG: generating subplan XXX_18 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE true +DEBUG: generating subplan XXX_19 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE true +DEBUG: generating subplan XXX_20 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE true +DEBUG: generating subplan XXX_21 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE true +DEBUG: generating subplan XXX_22 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE true +DEBUG: generating subplan XXX_23 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE true +DEBUG: generating subplan XXX_24 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE true +DEBUG: generating subplan XXX_25 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((((((((((((((((((((((((local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u1 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u2 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u3 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u4 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u5 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u6 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u7 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u8 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u9 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u10 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_11'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u11 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_12'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u12 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_13'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u13 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_14'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u14 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u15 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u16 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u17 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_18'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u18 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_19'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u19 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_20'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u20 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_21'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u21 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_22'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u22 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_23'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u23 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_24'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u24 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_25'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u25 USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +select ' select count(*) from distributed ' || string_Agg('INNER +JOIN local u'|| x::text || ' ON (false)',' ') from +generate_Series(1,25)x; + ?column? +--------------------------------------------------------------------- + select count(*) from distributed INNER+ + JOIN local u1 ON (false) INNER + + JOIN local u2 ON (false) INNER + + JOIN local u3 ON (false) INNER + + JOIN local u4 ON (false) INNER + + JOIN local u5 ON (false) INNER + + JOIN local u6 ON (false) INNER + + JOIN local u7 ON (false) INNER + + JOIN local u8 ON (false) INNER + + JOIN local u9 ON (false) INNER + + JOIN local u10 ON (false) INNER + + JOIN local u11 ON (false) INNER + + JOIN local u12 ON (false) INNER + + JOIN local u13 ON (false) INNER + + JOIN local u14 ON (false) INNER + + JOIN local u15 ON (false) INNER + + JOIN local u16 ON (false) INNER + + JOIN local u17 ON (false) INNER + + JOIN local u18 ON (false) INNER + + JOIN local u19 ON (false) INNER + + JOIN local u20 ON (false) INNER + + JOIN local u21 ON (false) INNER + + JOIN local u22 ON (false) INNER + + JOIN local u23 ON (false) INNER + + JOIN local u24 ON (false) INNER + + JOIN local u25 ON (false) +(1 row) + +\gexec + select count(*) from distributed INNER +JOIN local u1 ON (false) INNER +JOIN local u2 ON (false) INNER +JOIN local u3 ON (false) INNER +JOIN local u4 ON (false) INNER +JOIN local u5 ON (false) INNER +JOIN local u6 ON (false) INNER +JOIN local u7 ON (false) INNER +JOIN local u8 ON (false) INNER +JOIN local u9 ON (false) INNER +JOIN local u10 ON (false) INNER +JOIN local u11 ON (false) INNER +JOIN local u12 ON (false) INNER +JOIN local u13 ON (false) INNER +JOIN local u14 ON (false) INNER +JOIN local u15 ON (false) INNER +JOIN local u16 ON (false) INNER +JOIN local u17 ON (false) INNER +JOIN local u18 ON (false) INNER +JOIN local u19 ON (false) INNER +JOIN local u20 ON (false) INNER +JOIN local u21 ON (false) INNER +JOIN local u22 ON (false) INNER +JOIN local u23 ON (false) INNER +JOIN local u24 ON (false) INNER +JOIN local u25 ON (false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_3 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_4 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_5 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_6 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_7 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_8 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_9 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_10 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_11 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_12 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_13 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_14 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_15 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_16 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_17 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_18 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_19 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_20 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_21 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_22 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_23 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_24 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_25 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((((((((((((((((((((((((local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u1 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u2 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u3 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u4 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u5 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u6 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u7 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u8 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u9 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u10 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_11'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u11 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_12'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u12 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_13'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u13 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_14'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u14 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u15 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u16 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u17 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_18'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u18 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_19'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u19 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_20'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u20 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_21'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u21 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_22'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u22 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_23'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u23 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_24'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u24 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_25'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u25 ON (false)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +select ' select count(*) from local ' || string_Agg('INNER +JOIN distributed u'|| x::text || ' USING (id)',' ') from +generate_Series(1,25)x; + ?column? +--------------------------------------------------------------------- + select count(*) from local INNER + + JOIN distributed u1 USING (id) INNER + + JOIN distributed u2 USING (id) INNER + + JOIN distributed u3 USING (id) INNER + + JOIN distributed u4 USING (id) INNER + + JOIN distributed u5 USING (id) INNER + + JOIN distributed u6 USING (id) INNER + + JOIN distributed u7 USING (id) INNER + + JOIN distributed u8 USING (id) INNER + + JOIN distributed u9 USING (id) INNER + + JOIN distributed u10 USING (id) INNER+ + JOIN distributed u11 USING (id) INNER+ + JOIN distributed u12 USING (id) INNER+ + JOIN distributed u13 USING (id) INNER+ + JOIN distributed u14 USING (id) INNER+ + JOIN distributed u15 USING (id) INNER+ + JOIN distributed u16 USING (id) INNER+ + JOIN distributed u17 USING (id) INNER+ + JOIN distributed u18 USING (id) INNER+ + JOIN distributed u19 USING (id) INNER+ + JOIN distributed u20 USING (id) INNER+ + JOIN distributed u21 USING (id) INNER+ + JOIN distributed u22 USING (id) INNER+ + JOIN distributed u23 USING (id) INNER+ + JOIN distributed u24 USING (id) INNER+ + JOIN distributed u25 USING (id) +(1 row) + +\gexec + select count(*) from local INNER +JOIN distributed u1 USING (id) INNER +JOIN distributed u2 USING (id) INNER +JOIN distributed u3 USING (id) INNER +JOIN distributed u4 USING (id) INNER +JOIN distributed u5 USING (id) INNER +JOIN distributed u6 USING (id) INNER +JOIN distributed u7 USING (id) INNER +JOIN distributed u8 USING (id) INNER +JOIN distributed u9 USING (id) INNER +JOIN distributed u10 USING (id) INNER +JOIN distributed u11 USING (id) INNER +JOIN distributed u12 USING (id) INNER +JOIN distributed u13 USING (id) INNER +JOIN distributed u14 USING (id) INNER +JOIN distributed u15 USING (id) INNER +JOIN distributed u16 USING (id) INNER +JOIN distributed u17 USING (id) INNER +JOIN distributed u18 USING (id) INNER +JOIN distributed u19 USING (id) INNER +JOIN distributed u20 USING (id) INNER +JOIN distributed u21 USING (id) INNER +JOIN distributed u22 USING (id) INNER +JOIN distributed u23 USING (id) INNER +JOIN distributed u24 USING (id) INNER +JOIN distributed u25 USING (id) +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((((((((((((((((((((((((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed u1 USING (id)) JOIN local_dist_join_mixed.distributed u2 USING (id)) JOIN local_dist_join_mixed.distributed u3 USING (id)) JOIN local_dist_join_mixed.distributed u4 USING (id)) JOIN local_dist_join_mixed.distributed u5 USING (id)) JOIN local_dist_join_mixed.distributed u6 USING (id)) JOIN local_dist_join_mixed.distributed u7 USING (id)) JOIN local_dist_join_mixed.distributed u8 USING (id)) JOIN local_dist_join_mixed.distributed u9 USING (id)) JOIN local_dist_join_mixed.distributed u10 USING (id)) JOIN local_dist_join_mixed.distributed u11 USING (id)) JOIN local_dist_join_mixed.distributed u12 USING (id)) JOIN local_dist_join_mixed.distributed u13 USING (id)) JOIN local_dist_join_mixed.distributed u14 USING (id)) JOIN local_dist_join_mixed.distributed u15 USING (id)) JOIN local_dist_join_mixed.distributed u16 USING (id)) JOIN local_dist_join_mixed.distributed u17 USING (id)) JOIN local_dist_join_mixed.distributed u18 USING (id)) JOIN local_dist_join_mixed.distributed u19 USING (id)) JOIN local_dist_join_mixed.distributed u20 USING (id)) JOIN local_dist_join_mixed.distributed u21 USING (id)) JOIN local_dist_join_mixed.distributed u22 USING (id)) JOIN local_dist_join_mixed.distributed u23 USING (id)) JOIN local_dist_join_mixed.distributed u24 USING (id)) JOIN local_dist_join_mixed.distributed u25 USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +select ' select count(*) from local ' || string_Agg('INNER +JOIN distributed u'|| x::text || ' ON (false)',' ') from +generate_Series(1,25)x; + ?column? +--------------------------------------------------------------------- + select count(*) from local INNER + + JOIN distributed u1 ON (false) INNER + + JOIN distributed u2 ON (false) INNER + + JOIN distributed u3 ON (false) INNER + + JOIN distributed u4 ON (false) INNER + + JOIN distributed u5 ON (false) INNER + + JOIN distributed u6 ON (false) INNER + + JOIN distributed u7 ON (false) INNER + + JOIN distributed u8 ON (false) INNER + + JOIN distributed u9 ON (false) INNER + + JOIN distributed u10 ON (false) INNER+ + JOIN distributed u11 ON (false) INNER+ + JOIN distributed u12 ON (false) INNER+ + JOIN distributed u13 ON (false) INNER+ + JOIN distributed u14 ON (false) INNER+ + JOIN distributed u15 ON (false) INNER+ + JOIN distributed u16 ON (false) INNER+ + JOIN distributed u17 ON (false) INNER+ + JOIN distributed u18 ON (false) INNER+ + JOIN distributed u19 ON (false) INNER+ + JOIN distributed u20 ON (false) INNER+ + JOIN distributed u21 ON (false) INNER+ + JOIN distributed u22 ON (false) INNER+ + JOIN distributed u23 ON (false) INNER+ + JOIN distributed u24 ON (false) INNER+ + JOIN distributed u25 ON (false) +(1 row) + +\gexec + select count(*) from local INNER +JOIN distributed u1 ON (false) INNER +JOIN distributed u2 ON (false) INNER +JOIN distributed u3 ON (false) INNER +JOIN distributed u4 ON (false) INNER +JOIN distributed u5 ON (false) INNER +JOIN distributed u6 ON (false) INNER +JOIN distributed u7 ON (false) INNER +JOIN distributed u8 ON (false) INNER +JOIN distributed u9 ON (false) INNER +JOIN distributed u10 ON (false) INNER +JOIN distributed u11 ON (false) INNER +JOIN distributed u12 ON (false) INNER +JOIN distributed u13 ON (false) INNER +JOIN distributed u14 ON (false) INNER +JOIN distributed u15 ON (false) INNER +JOIN distributed u16 ON (false) INNER +JOIN distributed u17 ON (false) INNER +JOIN distributed u18 ON (false) INNER +JOIN distributed u19 ON (false) INNER +JOIN distributed u20 ON (false) INNER +JOIN distributed u21 ON (false) INNER +JOIN distributed u22 ON (false) INNER +JOIN distributed u23 ON (false) INNER +JOIN distributed u24 ON (false) INNER +JOIN distributed u25 ON (false) +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((((((((((((((((((((((((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed u1 ON (false)) JOIN local_dist_join_mixed.distributed u2 ON (false)) JOIN local_dist_join_mixed.distributed u3 ON (false)) JOIN local_dist_join_mixed.distributed u4 ON (false)) JOIN local_dist_join_mixed.distributed u5 ON (false)) JOIN local_dist_join_mixed.distributed u6 ON (false)) JOIN local_dist_join_mixed.distributed u7 ON (false)) JOIN local_dist_join_mixed.distributed u8 ON (false)) JOIN local_dist_join_mixed.distributed u9 ON (false)) JOIN local_dist_join_mixed.distributed u10 ON (false)) JOIN local_dist_join_mixed.distributed u11 ON (false)) JOIN local_dist_join_mixed.distributed u12 ON (false)) JOIN local_dist_join_mixed.distributed u13 ON (false)) JOIN local_dist_join_mixed.distributed u14 ON (false)) JOIN local_dist_join_mixed.distributed u15 ON (false)) JOIN local_dist_join_mixed.distributed u16 ON (false)) JOIN local_dist_join_mixed.distributed u17 ON (false)) JOIN local_dist_join_mixed.distributed u18 ON (false)) JOIN local_dist_join_mixed.distributed u19 ON (false)) JOIN local_dist_join_mixed.distributed u20 ON (false)) JOIN local_dist_join_mixed.distributed u21 ON (false)) JOIN local_dist_join_mixed.distributed u22 ON (false)) JOIN local_dist_join_mixed.distributed u23 ON (false)) JOIN local_dist_join_mixed.distributed u24 ON (false)) JOIN local_dist_join_mixed.distributed u25 ON (false)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- lateral joins +SELECT COUNT(*) FROM (VALUES (1), (2), (3)) as f(x) LATERAL JOIN (SELECT * FROM local WHERE id = x) as bar; +ERROR: syntax error at or near "LATERAL" +SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id = distributed.id) as foo ON (true); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN LATERAL (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo ON (true)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id > distributed.id) as foo ON (true); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN LATERAL (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.>) distributed.id)) foo ON (true)) + count +--------------------------------------------------------------------- + 5050 +(1 row) + +SELECT COUNT(*) FROM distributed JOIN LATERAL (SELECT * FROM local WHERE local.id = distributed.id) as foo ON (true); +ERROR: direct joins between distributed and local tables are not supported +HINT: Use CTE's or subqueries to select from local tables and use them in joins +SELECT COUNT(*) FROM distributed JOIN LATERAL (SELECT * FROM local WHERE local.id > distributed.id) as foo ON (true); +ERROR: direct joins between distributed and local tables are not supported +HINT: Use CTE's or subqueries to select from local tables and use them in joins +SELECT count(*) FROM distributed CROSS JOIN local; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed CROSS JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local) + count +--------------------------------------------------------------------- + 10201 +(1 row) + +SELECT count(*) FROM distributed CROSS JOIN local WHERE distributed.id = 1; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed CROSS JOIN local_dist_join_mixed.local) WHERE (distributed.id OPERATOR(pg_catalog.=) 1) + count +--------------------------------------------------------------------- + 101 +(1 row) + +-- w count(*) it works fine as PG ignores the inner tables +SELECT count(*) FROM distributed LEFT JOIN local USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed LEFT JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT count(*) FROM local LEFT JOIN distributed USING (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT id, name FROM distributed LEFT JOIN local USING (id) LIMIT 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id, distributed.name FROM (local_dist_join_mixed.distributed LEFT JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) LIMIT 1 +DEBUG: push down of limit count: 1 + id | name +--------------------------------------------------------------------- + 1 | 1 +(1 row) + +SELECT id, name FROM local LEFT JOIN distributed USING (id) LIMIT 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.id, distributed.name FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) LIMIT 1 +ERROR: cannot pushdown the subquery +DETAIL: Complex subqueries and CTEs cannot be in the outer part of the outer join + SELECT + foo1.id + FROM + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo9, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo8, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo7, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo6, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo5, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo4, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo3, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo2, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo10, + (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo1 + WHERE + foo1.id = foo9.id AND + foo1.id = foo8.id AND + foo1.id = foo7.id AND + foo1.id = foo6.id AND + foo1.id = foo5.id AND + foo1.id = foo4.id AND + foo1.id = foo3.id AND + foo1.id = foo2.id AND + foo1.id = foo10.id AND + foo1.id = foo1.id +ORDER BY 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_4 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_6 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_7 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_8 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_9 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id IS NOT NULL) +DEBUG: generating subplan XXX_10 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id IS NOT NULL) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo9, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo8, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo7, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo6, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo5, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo4, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo3, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo2, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo10, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo1 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo9.id) AND (foo1.id OPERATOR(pg_catalog.=) foo8.id) AND (foo1.id OPERATOR(pg_catalog.=) foo7.id) AND (foo1.id OPERATOR(pg_catalog.=) foo6.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo10.id) AND (foo1.id OPERATOR(pg_catalog.=) foo1.id)) ORDER BY foo1.id + id +--------------------------------------------------------------------- + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 +(101 rows) + +SELECT + foo1.id +FROM + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo1, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo2, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo3, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo4, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo5 +WHERE + foo1.id = foo4.id AND + foo1.id = foo2.id AND + foo1.id = foo3.id AND + foo1.id = foo4.id AND + foo1.id = foo5.id +ORDER BY 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_4 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo1, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo2, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo3, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo4, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo5 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id)) ORDER BY foo1.id + id +--------------------------------------------------------------------- + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 +(101 rows) + +SELECT + foo1.id +FROM + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 1) as foo1, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 2) as foo2, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 3) as foo3, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 4) as foo4, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 5) as foo5 +WHERE + foo1.id = foo4.id AND + foo1.id = foo2.id AND + foo1.id = foo3.id AND + foo1.id = foo4.id AND + foo1.id = foo5.id +ORDER BY 1; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_2 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 1)) +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_4 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 2)) +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_6 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 3)) +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_7 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_8 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 4)) +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_9 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_10 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 5)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo1, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo2, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo3, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo4, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo5 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id)) ORDER BY foo1.id + id +--------------------------------------------------------------------- +(0 rows) + +DROP SCHEMA local_dist_join_mixed CASCADE; +NOTICE: drop cascades to 7 other objects +DETAIL: drop cascades to table distributed +drop cascades to table reference +drop cascades to table local +drop cascades to table unlogged_local +drop cascades to materialized view mat_view +drop cascades to view local_regular_view +drop cascades to view dist_regular_view diff --git a/src/test/regress/expected/local_dist_join_modifications.out b/src/test/regress/expected/local_dist_join_modifications.out new file mode 100644 index 000000000..a42de58bf --- /dev/null +++ b/src/test/regress/expected/local_dist_join_modifications.out @@ -0,0 +1,597 @@ +CREATE SCHEMA local_dist_join_modifications; +SET search_path TO local_dist_join_modifications; +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); +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); +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 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)); +SELECT create_distributed_table('distributed_table_composite', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; +CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; +-- set log messages to debug1 so that we can see which tables are recursively planned. +SET client_min_messages TO DEBUG1; +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; +SET citus.local_table_join_policy to 'auto'; +-- we can support modification queries as well +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +UPDATE + mv1 +SET + value = 'test' +FROM + postgres_table +WHERE + mv1.key = postgres_table.key; +ERROR: cannot change materialized view "mv1" +ROLLBACK; +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + mv1 +WHERE + mv1.key = postgres_table.key; +ROLLBACK; +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + mv2 +WHERE + mv2.key = postgres_table.key; +ROLLBACK; +-- in case of update/delete we always recursively plan +-- the tables other than target table no matter what the policy is +SET citus.local_table_join_policy TO 'prefer-local'; +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +SET citus.local_table_join_policy TO 'prefer-distributed'; +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 100 +(1 row) + +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 1 +(1 row) + +ROLLBACK; +SET citus.local_table_join_policy TO 'auto'; +-- modifications with multiple tables +BEGIN; +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, postgres_table p2 +WHERE + distributed_table.key = p1.key AND p1.key = p2.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p2 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) p1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) +ROLLBACK; +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table) d1 +WHERE + d1.key = postgres_table.key; +ERROR: relation postgres_table is not distributed +ROLLBACK; +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table LIMIT 1) d1 +WHERE + d1.key = postgres_table.key; +DEBUG: push down of limit count: 1 +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_dist_join_modifications.distributed_table LIMIT 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) d1 WHERE (d1.key OPERATOR(pg_catalog.=) postgres_table.key) +ROLLBACK; +BEGIN; +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, distributed_table d2 +WHERE + distributed_table.key = p1.key AND p1.key = d2.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) p1, local_dist_join_modifications.distributed_table d2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) d2.key)) +ROLLBACK; +-- pretty inefficient plan as it requires +-- recursive planninng of 2 distributed tables +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table d1, distributed_table d2 +WHERE + postgres_table.key = d1.key AND d1.key = d2.key; +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d1 WHERE true +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d2 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) +ROLLBACK; +-- DELETE operations +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + postgres_table +USING + distributed_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.postgres_table USING (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM postgres_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + distributed_table +USING + postgres_table +WHERE + distributed_table.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table USING (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + distributed_table_pkey +USING + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table_pkey USING (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 100 +(1 row) + +DELETE FROM + distributed_table_windex +USING + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table_windex USING (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; + count +--------------------------------------------------------------------- + 0 +(1 row) + +ROLLBACK; +DELETE FROM + mv1 +USING + postgres_table +WHERE + mv1.key = postgres_table.key; +ERROR: cannot change materialized view "mv1" +DELETE FROM + postgres_table +USING + mv1 +WHERE + mv1.key = postgres_table.key; +DELETE FROM + postgres_table +USING + mv2 +WHERE + mv2.key = postgres_table.key; +SET client_min_messages to ERROR; +DROP SCHEMA local_dist_join_modifications CASCADE; diff --git a/src/test/regress/expected/local_distributed_table_join.out b/src/test/regress/expected/local_distributed_table_join.out deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 7710453ed..647c1609e 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -31,8 +31,8 @@ SELECT create_distributed_table('distributed_table_windex', 'key'); CREATE UNIQUE INDEX key_index ON distributed_table_windex (key); 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 (10); -CREATE TABLE distributed_partitioned_table_2 PARTITION OF distributed_partitioned_table FOR VALUES FROM (10) TO (20); +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 --------------------------------------------------------------------- @@ -40,8 +40,8 @@ SELECT create_distributed_table('distributed_partitioned_table', 'key'); (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 (10); -CREATE TABLE local_partitioned_table_2 PARTITION OF local_partitioned_table FOR VALUES FROM (10) TO (20); +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'); create_distributed_table @@ -49,6 +49,14 @@ SELECT create_distributed_table('distributed_table_composite', 'key'); (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; +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; CREATE FUNCTION fake_fdw_handler() RETURNS fdw_handler AS 'citus' @@ -73,181 +81,180 @@ HINT: Use CTE's or subqueries to select from local tables and use them in joins -- the user prefers local table recursively planned SET citus.local_table_join_policy TO 'prefer-local'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) -- the user prefers distributed table recursively planned SET citus.local_table_join_policy TO 'prefer-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -DEBUG: Wrapping relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table 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.reference_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) reference_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) --- update/delete -- auto tests -- switch back to the default policy, which is auto SET citus.local_table_join_policy to 'auto'; -- on the auto mode, the local tables should be recursively planned -- unless a unique index exists in a column for distributed table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true 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)) postgres_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM reference_table JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true 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)) postgres_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true 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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) -- partititoned local tables should work as well SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM reference_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true 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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) -- materialized views should work too SELECT count(*) FROM distributed_table JOIN mv1 USING(key); -DEBUG: Wrapping 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: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true +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 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 + 100 (1 row) SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv1 USING(key); -DEBUG: Wrapping 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: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true +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 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 + 100 (1 row) SELECT count(*) FROM reference_table JOIN mv1 USING(key); -DEBUG: Wrapping 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: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true +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 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 + 100 (1 row) SELECT count(*) FROM distributed_table JOIN mv1 USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping 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: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true +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 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 + 100 (1 row) SELECT count(*) FROM distributed_table JOIN mv2 USING(key); -DEBUG: Wrapping 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: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true +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 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 + 100 (1 row) SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv2 USING(key); -DEBUG: Wrapping 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: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true +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 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 + 100 (1 row) SELECT count(*) FROM reference_table JOIN mv2 USING(key); -DEBUG: Wrapping 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: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true +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 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 + 100 (1 row) SELECT count(*) FROM distributed_table JOIN mv2 USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping 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: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true +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 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 + 100 (1 row) -- foreign tables should work too SELECT count(*) FROM foreign_table JOIN distributed_table USING(key); -DEBUG: Wrapping relation "foreign_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "foreign_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true 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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) foreign_table JOIN local_table_join.distributed_table USING (key)) count --------------------------------------------------------------------- @@ -256,107 +263,107 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- partitioned tables should work as well SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) WHERE distributed_partitioned_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- - 0 + 1 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- - 0 + 1 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) -- the conversions should be independent from the order of table entries in the query SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- - 0 + 1 (1 row) SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join distributed_table_pkey using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- - 0 + 1 (1 row) SELECT COUNT(*) FROM postgres_table join distributed_table using(key) join local_partitioned_table using(key) join distributed_table_pkey using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- - 0 + 1 (1 row) SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) join postgres_table using(key) join local_partitioned_table using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table_pkey JOIN local_table_join.distributed_table USING (key)) 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)) postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- - 0 + 1 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) 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, random() AS random 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- @@ -364,8 +371,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, random() AS random FROM local_table_join.distributed_table_pkey) 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- @@ -373,8 +380,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- @@ -382,8 +389,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key::int = d1.key::int AND d1.key < postgres_table.key) WHERE d1.key::int = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- @@ -392,82 +399,82 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_composite.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- - 0 + 1 (1 row) -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (value)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = distributed_table_pkey.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_pkey.key))) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- - 0 + 100 (1 row) -- it should favor distributed table only if it has equality on the unique column SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key > 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10))) count --------------------------------------------------------------------- - 0 + 9000 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key < 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.<) 10))) count --------------------------------------------------------------------- - 0 + 900 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count --------------------------------------------------------------------- @@ -475,8 +482,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count --------------------------------------------------------------------- @@ -484,8 +491,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 AND postgres_table.key = 5; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (postgres_table.key OPERATOR(pg_catalog.=) 5)))) count --------------------------------------------------------------------- @@ -493,96 +500,114 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key > 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count --------------------------------------------------------------------- - 0 + 9100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20)))) count --------------------------------------------------------------------- - 0 + 200 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20 OR distributed_table_pkey.key = 30; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 30)))) count --------------------------------------------------------------------- - 0 + 300 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = ( SELECT count(*) FROM distributed_table_pkey ); DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM local_table_join.distributed_table_pkey -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)))))) count --------------------------------------------------------------------- - 0 + 200 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 5 and distributed_table_pkey.key > 15); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.key > 15); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) count --------------------------------------------------------------------- - 0 + 8600 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.value = 'notext'); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 10 and distributed_table_pkey.value = 'notext'); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- - 0 + 100 +(1 row) + +select count(*) FROM postgres_table JOIN (SELECT a.key,random() FROM distributed_table a JOIN distributed_table b USING(key)) as foo USING(key); +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN (SELECT a.key, random() AS random FROM (local_table_join.distributed_table a JOIN local_table_join.distributed_table b USING (key))) foo USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +select count(*) FROM (SELECT a.key, random() FROM distributed_table a JOIN distributed_table b USING(key)) as foo JOIN postgres_table USING(key); +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT a.key, random() AS random FROM (local_table_join.distributed_table a JOIN local_table_join.distributed_table b USING (key))) foo 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)) postgres_table USING (key)) + count +--------------------------------------------------------------------- + 100 (1 row) SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table) d1 USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1 USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) -- since this is already router plannable, we don't recursively plan the postgres table @@ -592,50 +617,50 @@ DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM lo DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) d1 USING (key)) count --------------------------------------------------------------------- - 0 + 1 (1 row) -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(value); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (value)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON postgres_table.key = distributed_table_windex.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON distributed_table_windex.key = 10; -DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- - 0 + 100 (1 row) -- no unique index on value so local table should be recursively planned. SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true 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)) postgres_table USING (key)) WHERE (distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) count --------------------------------------------------------------------- @@ -643,18 +668,18 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) 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)) postgres_table USING (key)) WHERE (distributed_table.key OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- - 0 + 1 (1 row) -- if both local and distributed tables have a filter, we prefer local unless distributed table has unique indexes on any equality filter SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) AND (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count --------------------------------------------------------------------- @@ -662,8 +687,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true 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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) OR (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count --------------------------------------------------------------------- @@ -673,14 +698,14 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- multiple local/distributed tables -- only local tables are recursively planned SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) count --------------------------------------------------------------------- - 0 + 100 (1 row) SELECT @@ -689,14 +714,14 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.value = '1'; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) count --------------------------------------------------------------------- - 0 + 1 (1 row) -- if the filter is on the JOIN key, we can recursively plan the local @@ -707,419 +732,50 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.key = 1; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- - 0 + 1 (1 row) -SET citus.local_table_join_policy to 'auto'; --- we can support modification queries as well -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table -WHERE - distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table_pkey -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_pkey.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_windex.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) --- in case of update/delete we always recursively plan --- the tables other than target table no matter what the policy is -SET citus.local_table_join_policy TO 'prefer-local'; -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table -WHERE - distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table_pkey -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_pkey.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_windex.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) -SET citus.local_table_join_policy TO 'prefer-distributed'; -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table -WHERE - distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table 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.distributed_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table_pkey -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_pkey.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_windex.key = postgres_table.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) -SET citus.local_table_join_policy TO 'auto'; --- modifications with multiple tables -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table p1, postgres_table p2 -WHERE - distributed_table.key = p1.key AND p1.key = p2.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) -UPDATE - postgres_table -SET - value = 'test' -FROM - (SELECT * FROM distributed_table) d1 -WHERE - d1.key = postgres_table.key; -ERROR: relation postgres_table is not distributed -UPDATE - postgres_table -SET - value = 'test' -FROM - (SELECT * FROM distributed_table LIMIT 1) d1 -WHERE - d1.key = postgres_table.key; -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table LIMIT 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1 WHERE (d1.key OPERATOR(pg_catalog.=) postgres_table.key) -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table p1, distributed_table d2 -WHERE - distributed_table.key = p1.key AND p1.key = d2.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 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.postgres_table p1 WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table SET value = 'test'::text FROM (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)) p1, local_table_join.distributed_table d2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) d2.key)) --- pretty inefficient plan as it requires --- recursive planninng of 2 distributed tables -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table d1, distributed_table d2 -WHERE - postgres_table.key = d1.key AND d1.key = d2.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d1 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.distributed_table d1 WHERE true OFFSET 0 -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table d2 WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) --- currently can't plan subquery-local table join SELECT count(*) FROM (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT d1.key, d1.value, d1.value_2 FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1) d2 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)) postgres_table USING (key)) count --------------------------------------------------------------------- - 0 -(1 row) - ---------------------------------------------------------------------- -SET client_min_messages to ERROR; -SELECT master_add_node('localhost', :master_port, groupId => 0); - master_add_node ---------------------------------------------------------------------- - 5 -(1 row) - -CREATE TABLE citus_local(key int, value text); -SELECT create_citus_local_table('citus_local'); - create_citus_local_table ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO DEBUG1; --- same for citus local table - distributed table joins --- a unique index on key so dist table should be recursively planned -SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table_windex USING (key)) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table_windex USING (value)) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table_windex ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; -DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.citus_local 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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) - count ---------------------------------------------------------------------- - 0 -(1 row) - --- no unique index, citus local table should be recursively planned -SELECT count(*) FROM citus_local JOIN distributed_table USING(key); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table USING (key)) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM citus_local JOIN distributed_table USING(value); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM local_table_join.citus_local WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table USING (value)) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table.key))) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) 10))) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true OFFSET 0 -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) - JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_partitioned_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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) - count ---------------------------------------------------------------------- - 0 -(1 row) - --- update -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - citus_local -WHERE - distributed_table_windex.key = citus_local.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.citus_local WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.distributed_table_windex SET value = 'test'::text 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)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) -UPDATE - citus_local -SET - value = 'test' -FROM - distributed_table_windex -WHERE - distributed_table_windex.key = citus_local.key; -DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex 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.distributed_table_windex WHERE true OFFSET 0 -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.citus_local SET value = 'test'::text FROM (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)) distributed_table_windex WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) --- complex queries -SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table LIMIT 1 -DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM local_table_join.citus_local -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((local_table_join.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.distributed_table LIMIT 1 -DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM local_table_join.citus_local -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((local_table_join.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN local_table_join.reference_table USING (key)) JOIN local_table_join.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) - count ---------------------------------------------------------------------- - 0 + 100 (1 row) -- TODO:: we should support this? UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) 10) ERROR: relation postgres_table is not distributed UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) l WHERE (l.key OPERATOR(pg_catalog.=) 10) -UPDATE citus_local SET key = 1 FROM postgres_table WHERE citus_local.key = 10; -UPDATE postgres_table SET key = 1 FROM citus_local WHERE citus_local.key = 10; -- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? -- though then the planner could give an error SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false OFFSET 0 +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) WHERE false count --------------------------------------------------------------------- 0 (1 row) -DROP TABLE citus_local; -CONTEXT: SQL statement "SELECT master_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name)" -PL/pgSQL function citus_drop_trigger() line 15 at PERFORM RESET client_min_messages; -SELECT master_remove_node('localhost', :master_port); - master_remove_node ---------------------------------------------------------------------- - -(1 row) - \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 15 other objects +NOTICE: drop cascades to 14 other objects diff --git a/src/test/regress/expected/mixed_relkind_tests.out b/src/test/regress/expected/mixed_relkind_tests.out index 65a6d6045..0c40cc1a2 100644 --- a/src/test/regress/expected/mixed_relkind_tests.out +++ b/src/test/regress/expected/mixed_relkind_tests.out @@ -320,8 +320,8 @@ $$); SET client_min_messages TO DEBUG1; SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN distributed_table ON (true); -DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.distributed_table ON (true)) count --------------------------------------------------------------------- @@ -329,8 +329,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN partitioned_distributed_table ON (true); -DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.partitioned_distributed_table ON (true)) count --------------------------------------------------------------------- @@ -338,8 +338,8 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT COUNT(*) FROM distributed_table JOIN partitioned_postgres_local_table ON (true); -DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (mixed_relkind_tests.distributed_table JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table ON (true)) count --------------------------------------------------------------------- @@ -348,20 +348,20 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c INSERT INTO partitioned_distributed_table SELECT foo.* FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a, foo.b FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO partitioned_distributed_table SELECT foo.* FROM distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO distributed_table SELECT foo.a FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) DEBUG: performing repartitioned INSERT ... SELECT -- should fail @@ -392,25 +392,25 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) UPDATE partitioned_distributed_table SET b = foo.a FROM citus_local_table AS foo; -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo UPDATE partitioned_distributed_table SET b = foo.a FROM postgres_local_table AS foo; -DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo UPDATE partitioned_distributed_table SET a = foo.a FROM postgres_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) UPDATE partitioned_distributed_table SET a = foo.a FROM citus_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) -- should fail UPDATE partitioned_distributed_table SET a = foo.a FROM mat_view_on_part_dist AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping relation "mat_view_on_part_dist" to a subquery: SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true OFFSET 0 +DEBUG: Wrapping relation "mat_view_on_part_dist" to a subquery: SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a 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)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) UPDATE partitioned_distributed_table SET a = foo.a FROM partitioned_distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns diff --git a/src/test/regress/expected/multi_partitioning.out b/src/test/regress/expected/multi_partitioning.out index 2e177214e..a31711fe7 100644 --- a/src/test/regress/expected/multi_partitioning.out +++ b/src/test/regress/expected/multi_partitioning.out @@ -1430,7 +1430,7 @@ COMMIT; BEGIN; TRUNCATE partitioning_locks; SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3; - relation | locktype | mode + relation | locktype | mode --------------------------------------------------------------------- partitioning_locks | relation | AccessExclusiveLock partitioning_locks | relation | AccessShareLock @@ -1471,29 +1471,17 @@ BEGIN; UPDATE partitioning_locks_2009 SET time = '2009-03-01'; -- see the locks on parent table SELECT * FROM lockinfo; - logicalrelid | locktype | mode + logicalrelid | locktype | mode --------------------------------------------------------------------- - partitioning_locks | colocated_shards_metadata | ShareLock - partitioning_locks | colocated_shards_metadata | ShareLock - partitioning_locks | colocated_shards_metadata | ShareLock - partitioning_locks | colocated_shards_metadata | ShareLock - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | colocated_shards_metadata | ShareLock - partitioning_locks_2009 | colocated_shards_metadata | ShareLock - partitioning_locks_2009 | colocated_shards_metadata | ShareLock - partitioning_locks_2009 | colocated_shards_metadata | ShareLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock - partitioning_locks_2010 | colocated_shards_metadata | ShareLock - partitioning_locks_2010 | colocated_shards_metadata | ShareLock - partitioning_locks_2010 | colocated_shards_metadata | ShareLock - partitioning_locks_2010 | colocated_shards_metadata | ShareLock -(20 rows) + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock +(8 rows) COMMIT; -- test shard resource locks with TRUNCATE diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out index 20788d6fe..adfe0bf26 100644 --- a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out +++ b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out @@ -31,8 +31,8 @@ SELECT count(*) FROM distributed_table u1 JOIN distributed_table u2 USING(key) JOIN local_table USING (key); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN push_down_filters.distributed_table u2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) local_table USING (key)) count --------------------------------------------------------------------- @@ -44,8 +44,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING (key) WHERE u2.key > ANY(ARRAY[2, 1, 6]); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (u2.key OPERATOR(pg_catalog.>) ANY (ARRAY[2, 1, 6])) count --------------------------------------------------------------------- @@ -57,8 +57,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(key) WHERE ARRAY[u2.key, u2.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (ARRAY[u2.key, u2.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count --------------------------------------------------------------------- @@ -70,8 +70,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE ARRAY[u2.value, u1.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ARRAY[u2.value, u1.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count --------------------------------------------------------------------- @@ -83,8 +83,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value/2.0 > 2)::int::bool::text::bool; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) (2)::numeric))::integer)::boolean)::text)::boolean count --------------------------------------------------------------------- @@ -96,8 +96,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u2.value > 3 THEN u2.value > 2 ELSE false END); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u2.value OPERATOR(pg_catalog.>) 3) THEN (u2.value OPERATOR(pg_catalog.>) 2) ELSE false END count --------------------------------------------------------------------- @@ -109,8 +109,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u1.value > 4000 THEN u2.value / 100 > 1 ELSE false END); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u1.value OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END count --------------------------------------------------------------------- @@ -122,8 +122,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE COALESCE((u2.key/5.0)::int::bool, false); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE COALESCE(((((u2.key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count --------------------------------------------------------------------- @@ -135,8 +135,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE NULLIF((u2.value/5.0)::int::bool, false); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE NULLIF(((((u2.value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count --------------------------------------------------------------------- @@ -148,8 +148,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value IS NOT NULL; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value IS NOT NULL) count --------------------------------------------------------------------- @@ -161,8 +161,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE isfinite(u2.time); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE isfinite(u2."time") count --------------------------------------------------------------------- @@ -174,8 +174,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.value, u1.value) = 55; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.value, u1.value) OPERATOR(pg_catalog.=) 55) count --------------------------------------------------------------------- @@ -187,8 +187,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.key, u2.value) = u2.key; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.key, u2.value) OPERATOR(pg_catalog.=) u2.key) count --------------------------------------------------------------------- @@ -200,8 +200,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE row(u2.value, 2, 3) > row(u2.value, 2, 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(u2.value, 2, 3)) count --------------------------------------------------------------------- @@ -220,8 +220,8 @@ JOIN local_table u2 USING(value) isfinite(u2.time) AND u2.value IS DISTINCT FROM 50040 AND row(u2.value, 2, 3) > row(2000, 2, 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (u2.key OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((u2.key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((u2.value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite(u2."time") AND (u2.value IS DISTINCT FROM 50040) AND (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) count --------------------------------------------------------------------- @@ -236,8 +236,8 @@ WHERE u2.value > (SELECT avg(key) FROM distributed_table); DEBUG: generating subplan XXX_1 for subquery SELECT avg(key) AS avg FROM push_down_filters.distributed_table -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value)::numeric OPERATOR(pg_catalog.>) (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric))) count --------------------------------------------------------------------- @@ -249,8 +249,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > (SELECT 5); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value OPERATOR(pg_catalog.>) (SELECT 5)) count --------------------------------------------------------------------- @@ -262,8 +262,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value * u1.key > 25; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.*) u1.key) OPERATOR(pg_catalog.>) 25) count --------------------------------------------------------------------- @@ -277,8 +277,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value = 3; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.=) 3) count --------------------------------------------------------------------- @@ -290,8 +290,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value > 3; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.>) 3) count --------------------------------------------------------------------- @@ -304,8 +304,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.key = 3; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.key OPERATOR(pg_catalog.=) 3) count --------------------------------------------------------------------- @@ -317,8 +317,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 4 OR u2.value = 4; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 4) OR (u2.value OPERATOR(pg_catalog.=) 4)) count --------------------------------------------------------------------- @@ -330,8 +330,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 2 and u2.time IS NULL; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND (u2."time" IS NULL)) count --------------------------------------------------------------------- @@ -344,8 +344,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -358,8 +358,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) OR (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL) OR ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -372,8 +372,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -385,8 +385,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u1.value IS NULL) AND (u2.key = 10000 * random() OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u1.value IS NULL)) AND (((u2.key)::double precision OPERATOR(pg_catalog.=) ((10000)::double precision OPERATOR(pg_catalog.*) random())) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- @@ -398,8 +398,8 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 AND false); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) count --------------------------------------------------------------------- @@ -418,8 +418,8 @@ JOIN LATERAL WHERE u2.value = 15) AS u3 USING (value) WHERE (u2.value > 2 AND FALSE); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false OFFSET 0 +DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) JOIN LATERAL (SELECT distributed_table.value, random() AS random FROM push_down_filters.distributed_table WHERE (u2.value OPERATOR(pg_catalog.=) 15)) u3 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns \set VERBOSITY terse diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 3c5cb0175..80cf392a5 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -222,7 +222,10 @@ test: multi_modifying_xacts test: multi_repartition_udt multi_repartitioned_subquery_udf multi_subtransactions test: multi_transaction_recovery +test: local_dist_join_modifications test: local_table_join +test: local_dist_join_mixed +test: citus_local_dist_joins # --------- # multi_copy creates hash and range-partitioned tables and performs COPY diff --git a/src/test/regress/sql/citus_local_dist_joins.sql b/src/test/regress/sql/citus_local_dist_joins.sql new file mode 100644 index 000000000..34523eec2 --- /dev/null +++ b/src/test/regress/sql/citus_local_dist_joins.sql @@ -0,0 +1,232 @@ +CREATE SCHEMA citus_local_dist_joins; +SET search_path TO citus_local_dist_joins; + +SET client_min_messages to ERROR; +SELECT master_add_node('localhost', :master_port, groupId => 0); + + +CREATE TABLE citus_local(key int, value text); +SELECT create_citus_local_table('citus_local'); + +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 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'); + +CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; +CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; + +-- set log messages to debug1 so that we can see which tables are recursively planned. +SET client_min_messages TO DEBUG1; + +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; +INSERT INTO citus_local SELECT i, i::varchar(256) FROM generate_series(1, 100) i; + + +-- a unique index on key so dist table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); +SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; +SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; + +-- no unique index, citus local table should be recursively planned +SELECT count(*) FROM citus_local JOIN distributed_table USING(key); +SELECT count(*) FROM citus_local JOIN distributed_table USING(value); +SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; +SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; + +SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); + +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) + JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; + +-- update +BEGIN; +SELECT COUNT(DISTINCT value) FROM citus_local; +UPDATE + citus_local +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM citus_local; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; +UPDATE + distributed_table +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM distributed_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table_pkey.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + citus_local +WHERE + distributed_table_windex.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +ROLLBACK; + +BEGIN; +UPDATE + mv1 +SET + value = 'test' +FROM + citus_local +WHERE + mv1.key = citus_local.key; +ROLLBACK; + +BEGIN; +UPDATE + citus_local +SET + value = 'test' +FROM + mv1 +WHERE + mv1.key = citus_local.key; +ROLLBACK; + +BEGIN; +UPDATE + citus_local +SET + value = 'test' +FROM + mv2 +WHERE + mv2.key = citus_local.key; +ROLLBACK; + +-- DELETE operations + +BEGIN; +SELECT COUNT(DISTINCT value) FROM citus_local; +DELETE FROM + citus_local +USING + distributed_table +WHERE + distributed_table.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM citus_local; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; +DELETE FROM + distributed_table +USING + citus_local +WHERE + distributed_table.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM distributed_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +DELETE FROM + distributed_table_pkey +USING + citus_local +WHERE + distributed_table_pkey.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +DELETE FROM + distributed_table_windex +USING + citus_local +WHERE + distributed_table_windex.key = citus_local.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +ROLLBACK; + +DELETE FROM + mv1 +USING + citus_local +WHERE + mv1.key = citus_local.key; + +DELETE FROM + citus_local +USING + mv1 +WHERE + mv1.key = citus_local.key; + +DELETE FROM + citus_local +USING + mv2 +WHERE + mv2.key = citus_local.key; + +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; +SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; + + + +SET client_min_messages to ERROR; +DROP TABLE citus_local; +SELECT master_remove_node('localhost', :master_port); +\set VERBOSITY terse +DROP SCHEMA citus_local_dist_joins CASCADE; \ No newline at end of file diff --git a/src/test/regress/sql/local_distributed_table_join.sql b/src/test/regress/sql/local_dist_join_mixed.sql similarity index 88% rename from src/test/regress/sql/local_distributed_table_join.sql rename to src/test/regress/sql/local_dist_join_mixed.sql index 78ff90614..1a00c4f22 100644 --- a/src/test/regress/sql/local_distributed_table_join.sql +++ b/src/test/regress/sql/local_dist_join_mixed.sql @@ -1,5 +1,5 @@ -CREATE SCHEMA local_distributed_table_join; -SET search_path TO local_distributed_table_join; +CREATE SCHEMA local_dist_join_mixed; +SET search_path TO local_dist_join_mixed; @@ -20,6 +20,7 @@ INSERT INTO distributed SELECT i, i::text, now() FROM generate_series(0,100)i; INSERT INTO reference SELECT i, i::text FROM generate_series(0,100)i; INSERT INTO local SELECT i, i::text FROM generate_series(0,100)i; +SET client_min_messages to DEBUG1; -- very simple 1-1 Joins SELECT count(*) FROM distributed JOIN local USING (id); @@ -308,11 +309,11 @@ SELECT count(*) FROM distributed CROSS JOIN local WHERE distributed.id = 1; SELECT count(*) FROM distributed LEFT JOIN local USING (id); SELECT count(*) FROM local LEFT JOIN distributed USING (id); -SELECT * FROM distributed LEFT JOIN local USING (id) LIMIT 1; -SELECT * FROM local LEFT JOIN distributed USING (id) LIMIT 1; +SELECT id, name FROM distributed LEFT JOIN local USING (id) LIMIT 1; +SELECT id, name FROM local LEFT JOIN distributed USING (id) LIMIT 1; SELECT - foo1.id, random() + foo1.id FROM (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo9, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo8, @@ -334,38 +335,41 @@ SELECT * FROM local LEFT JOIN distributed USING (id) LIMIT 1; foo1.id = foo3.id AND foo1.id = foo2.id AND foo1.id = foo10.id AND - foo1.id = foo1.id ; + foo1.id = foo1.id +ORDER BY 1; - SELECT - foo1.id - FROM - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo1, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo2, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo3, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo4, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo5 - WHERE - foo1.id = foo4.id AND - foo1.id = foo2.id AND - foo1.id = foo3.id AND - foo1.id = foo4.id AND - foo1.id = foo5.id; +SELECT + foo1.id +FROM + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo1, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo2, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo3, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo4, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo5 +WHERE + foo1.id = foo4.id AND + foo1.id = foo2.id AND + foo1.id = foo3.id AND + foo1.id = foo4.id AND + foo1.id = foo5.id +ORDER BY 1; - SELECT - foo1.id - FROM - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 1) as foo1, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 2) as foo2, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 3) as foo3, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 4) as foo4, - (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 5) as foo5 - WHERE - foo1.id = foo4.id AND - foo1.id = foo2.id AND - foo1.id = foo3.id AND - foo1.id = foo4.id AND - foo1.id = foo5.id; +SELECT + foo1.id +FROM + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 1) as foo1, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 2) as foo2, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 3) as foo3, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 4) as foo4, + (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 5) as foo5 +WHERE + foo1.id = foo4.id AND + foo1.id = foo2.id AND + foo1.id = foo3.id AND + foo1.id = foo4.id AND + foo1.id = foo5.id +ORDER BY 1; -DROP SCHEMA local_distributed_table_join CASCADE; \ No newline at end of file +DROP SCHEMA local_dist_join_mixed CASCADE; \ No newline at end of file diff --git a/src/test/regress/sql/local_dist_join_modifications.sql b/src/test/regress/sql/local_dist_join_modifications.sql new file mode 100644 index 000000000..f8c8ee886 --- /dev/null +++ b/src/test/regress/sql/local_dist_join_modifications.sql @@ -0,0 +1,372 @@ +CREATE SCHEMA local_dist_join_modifications; +SET search_path TO local_dist_join_modifications; + +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 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'); + +CREATE MATERIALIZED VIEW mv1 AS SELECT * FROM postgres_table; +CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM distributed_table; + +-- set log messages to debug1 so that we can see which tables are recursively planned. +SET client_min_messages TO DEBUG1; + +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; + +SET citus.local_table_join_policy to 'auto'; + +-- we can support modification queries as well +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM postgres_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +ROLLBACK; + +BEGIN; +UPDATE + mv1 +SET + value = 'test' +FROM + postgres_table +WHERE + mv1.key = postgres_table.key; +ROLLBACK; + +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + mv1 +WHERE + mv1.key = postgres_table.key; +ROLLBACK; + +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + mv2 +WHERE + mv2.key = postgres_table.key; +ROLLBACK; + +-- in case of update/delete we always recursively plan +-- the tables other than target table no matter what the policy is + +SET citus.local_table_join_policy TO 'prefer-local'; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM postgres_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +ROLLBACK; + +SET citus.local_table_join_policy TO 'prefer-distributed'; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM postgres_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +UPDATE + distributed_table_pkey +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +ROLLBACK; + + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +UPDATE + distributed_table_windex +SET + value = 'test' +FROM + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +ROLLBACK; + +SET citus.local_table_join_policy TO 'auto'; + +-- modifications with multiple tables +BEGIN; +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, postgres_table p2 +WHERE + distributed_table.key = p1.key AND p1.key = p2.key; +ROLLBACK; + +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table) d1 +WHERE + d1.key = postgres_table.key; +ROLLBACK; + +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + (SELECT * FROM distributed_table LIMIT 1) d1 +WHERE + d1.key = postgres_table.key; +ROLLBACK; + +BEGIN; +UPDATE + distributed_table +SET + value = 'test' +FROM + postgres_table p1, distributed_table d2 +WHERE + distributed_table.key = p1.key AND p1.key = d2.key; +ROLLBACK; + +-- pretty inefficient plan as it requires +-- recursive planninng of 2 distributed tables +BEGIN; +UPDATE + postgres_table +SET + value = 'test' +FROM + distributed_table d1, distributed_table d2 +WHERE + postgres_table.key = d1.key AND d1.key = d2.key; +ROLLBACK; +-- DELETE operations + +BEGIN; +SELECT COUNT(DISTINCT value) FROM postgres_table; +DELETE FROM + postgres_table +USING + distributed_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM postgres_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table; +DELETE FROM + distributed_table +USING + postgres_table +WHERE + distributed_table.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +DELETE FROM + distributed_table_pkey +USING + postgres_table +WHERE + distributed_table_pkey.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; +ROLLBACK; + +BEGIN; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +DELETE FROM + distributed_table_windex +USING + postgres_table +WHERE + distributed_table_windex.key = postgres_table.key; +SELECT COUNT(DISTINCT value) FROM distributed_table_windex; +ROLLBACK; + +DELETE FROM + mv1 +USING + postgres_table +WHERE + mv1.key = postgres_table.key; + +DELETE FROM + postgres_table +USING + mv1 +WHERE + mv1.key = postgres_table.key; + +DELETE FROM + postgres_table +USING + mv2 +WHERE + mv2.key = postgres_table.key; + + +SET client_min_messages to ERROR; +DROP SCHEMA local_dist_join_modifications CASCADE; \ No newline at end of file diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index c3786cc4f..dad8459f1 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -15,17 +15,26 @@ SELECT create_distributed_table('distributed_table_windex', 'key'); CREATE UNIQUE INDEX key_index ON distributed_table_windex (key); 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 (10); -CREATE TABLE distributed_partitioned_table_2 PARTITION OF distributed_partitioned_table FOR VALUES FROM (10) TO (20); +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 (10); -CREATE TABLE local_partitioned_table_2 PARTITION OF local_partitioned_table FOR VALUES FROM (10) TO (20); +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; + CREATE FUNCTION fake_fdw_handler() RETURNS fdw_handler AS 'citus' @@ -61,7 +70,6 @@ SET citus.local_table_join_policy TO 'prefer-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); SELECT count(*) FROM postgres_table JOIN reference_table USING(key); --- update/delete -- auto tests -- switch back to the default policy, which is auto @@ -187,179 +195,6 @@ WHERE d1.key = 1; -SET citus.local_table_join_policy to 'auto'; - --- we can support modification queries as well -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table -WHERE - distributed_table.key = postgres_table.key; - - -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table.key = postgres_table.key; - -UPDATE - distributed_table_pkey -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_pkey.key = postgres_table.key; - -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_windex.key = postgres_table.key; - --- in case of update/delete we always recursively plan --- the tables other than target table no matter what the policy is - -SET citus.local_table_join_policy TO 'prefer-local'; - -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table -WHERE - distributed_table.key = postgres_table.key; - - -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table.key = postgres_table.key; - -UPDATE - distributed_table_pkey -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_pkey.key = postgres_table.key; - -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_windex.key = postgres_table.key; - - -SET citus.local_table_join_policy TO 'prefer-distributed'; - -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table -WHERE - distributed_table.key = postgres_table.key; - - -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table.key = postgres_table.key; - -UPDATE - distributed_table_pkey -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_pkey.key = postgres_table.key; - -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - postgres_table -WHERE - distributed_table_windex.key = postgres_table.key; - -SET citus.local_table_join_policy TO 'auto'; - --- modifications with multiple tables -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table p1, postgres_table p2 -WHERE - distributed_table.key = p1.key AND p1.key = p2.key; - -UPDATE - postgres_table -SET - value = 'test' -FROM - (SELECT * FROM distributed_table) d1 -WHERE - d1.key = postgres_table.key; - -UPDATE - postgres_table -SET - value = 'test' -FROM - (SELECT * FROM distributed_table LIMIT 1) d1 -WHERE - d1.key = postgres_table.key; - -UPDATE - distributed_table -SET - value = 'test' -FROM - postgres_table p1, distributed_table d2 -WHERE - distributed_table.key = p1.key AND p1.key = d2.key; - --- pretty inefficient plan as it requires --- recursive planninng of 2 distributed tables -UPDATE - postgres_table -SET - value = 'test' -FROM - distributed_table d1, distributed_table d2 -WHERE - postgres_table.key = d1.key AND d1.key = d2.key; - --- currently can't plan subquery-local table join SELECT count(*) FROM (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 @@ -367,72 +202,15 @@ JOIN postgres_table USING(key); - ---------------------------------------------------------- - -SET client_min_messages to ERROR; -SELECT master_add_node('localhost', :master_port, groupId => 0); - - -CREATE TABLE citus_local(key int, value text); -SELECT create_citus_local_table('citus_local'); -SET client_min_messages TO DEBUG1; - --- same for citus local table - distributed table joins --- a unique index on key so dist table should be recursively planned -SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); -SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); -SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; -SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; - --- no unique index, citus local table should be recursively planned -SELECT count(*) FROM citus_local JOIN distributed_table USING(key); -SELECT count(*) FROM citus_local JOIN distributed_table USING(value); -SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; -SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; - -SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); - -SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) - JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; - --- update -UPDATE - distributed_table_windex -SET - value = 'test' -FROM - citus_local -WHERE - distributed_table_windex.key = citus_local.key; - -UPDATE - citus_local -SET - value = 'test' -FROM - distributed_table_windex -WHERE - distributed_table_windex.key = citus_local.key; - --- complex queries -SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; -SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; - -- TODO:: we should support this? UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; -UPDATE citus_local SET key = 1 FROM postgres_table WHERE citus_local.key = 10; -UPDATE postgres_table SET key = 1 FROM citus_local WHERE citus_local.key = 10; - -- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? -- though then the planner could give an error SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; -DROP TABLE citus_local; RESET client_min_messages; -SELECT master_remove_node('localhost', :master_port); \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; From 28c5b6a425490349b418fa4e89e927c49aed3d85 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Mon, 7 Dec 2020 15:52:05 +0300 Subject: [PATCH 26/37] Convert some hard coded errors to deferred errors in router planner --- .../distributed/executor/citus_custom_scan.c | 3 +- .../planner/multi_physical_planner.c | 44 ++++++++++++++----- .../planner/multi_router_planner.c | 10 +++-- .../distributed/multi_physical_planner.h | 3 +- .../distributed/multi_router_planner.h | 5 ++- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/backend/distributed/executor/citus_custom_scan.c b/src/backend/distributed/executor/citus_custom_scan.c index 106f47cbe..b5617d1c6 100644 --- a/src/backend/distributed/executor/citus_custom_scan.c +++ b/src/backend/distributed/executor/citus_custom_scan.c @@ -546,7 +546,8 @@ RegenerateTaskForFasthPathQuery(Job *workerJob) GenerateSingleShardRouterTaskList(workerJob, relationShardList, - placementList, shardId); + placementList, + shardId); } diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 0bc31a9f5..01802d8ec 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -171,7 +171,8 @@ static Task * QueryPushdownTaskCreate(Query *originalQuery, int shardIndex, RelationRestrictionContext *restrictionContext, uint32 taskId, TaskType taskType, - bool modifyRequiresCoordinatorEvaluation); + bool modifyRequiresCoordinatorEvaluation, + DeferredErrorMessage **planningError); static bool ShardIntervalsEqual(FmgrInfo *comparisonFunction, Oid collation, ShardInterval *firstInterval, @@ -2105,11 +2106,16 @@ BuildJobTreeTaskList(Job *jobTree, PlannerRestrictionContext *plannerRestriction relationRestrictionContext, &isMultiShardQuery, NULL); + DeferredErrorMessage *deferredErrorMessage = NULL; sqlTaskList = QueryPushdownSqlTaskList(job->jobQuery, job->jobId, plannerRestrictionContext-> relationRestrictionContext, prunedRelationShardList, READ_TASK, - false); + false, + &deferredErrorMessage); + if (deferredErrorMessage != NULL) { + RaiseDeferredErrorInternal(deferredErrorMessage, ERROR); + } } else { @@ -2187,7 +2193,8 @@ List * QueryPushdownSqlTaskList(Query *query, uint64 jobId, RelationRestrictionContext *relationRestrictionContext, List *prunedRelationShardList, TaskType taskType, bool - modifyRequiresCoordinatorEvaluation) + modifyRequiresCoordinatorEvaluation, + DeferredErrorMessage **planningError) { List *sqlTaskList = NIL; ListCell *restrictionCell = NULL; @@ -2201,8 +2208,11 @@ QueryPushdownSqlTaskList(Query *query, uint64 jobId, if (list_length(relationRestrictionContext->relationRestrictionList) == 0) { - ereport(ERROR, (errmsg("cannot handle complex subqueries when the " - "router executor is disabled"))); + *planningError = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, + "cannot handle complex subqueries when the " + "router executor is disabled", + NULL, NULL); + return NIL; } /* defaults to be used if this is a reference table-only query */ @@ -2227,8 +2237,11 @@ QueryPushdownSqlTaskList(Query *query, uint64 jobId, /* we expect distributed tables to have the same shard count */ if (shardCount > 0 && shardCount != cacheEntry->shardIntervalArrayLength) { - ereport(ERROR, (errmsg("shard counts of co-located tables do not " - "match"))); + *planningError = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, + "shard counts of co-located tables do not " + "match", + NULL, NULL); + return NIL; } if (taskRequiredForShardIndex == NULL) @@ -2291,7 +2304,11 @@ QueryPushdownSqlTaskList(Query *query, uint64 jobId, relationRestrictionContext, taskIdIndex, taskType, - modifyRequiresCoordinatorEvaluation); + modifyRequiresCoordinatorEvaluation, + planningError); + if (*planningError != NULL) { + return NIL; + } subqueryTask->jobId = jobId; sqlTaskList = lappend(sqlTaskList, subqueryTask); @@ -2467,7 +2484,8 @@ ErrorIfUnsupportedShardDistribution(Query *query) static Task * QueryPushdownTaskCreate(Query *originalQuery, int shardIndex, RelationRestrictionContext *restrictionContext, uint32 taskId, - TaskType taskType, bool modifyRequiresCoordinatorEvaluation) + TaskType taskType, bool modifyRequiresCoordinatorEvaluation, + DeferredErrorMessage **planningError) { Query *taskQuery = copyObject(originalQuery); @@ -2546,8 +2564,12 @@ QueryPushdownTaskCreate(Query *originalQuery, int shardIndex, List *taskPlacementList = PlacementsForWorkersContainingAllShards(taskShardList); if (list_length(taskPlacementList) == 0) { - ereport(ERROR, (errmsg("cannot find a worker that has active placements for all " - "shards in the query"))); + *planningError = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, + "cannot find a worker that has active placements for all " + "shards in the query", + NULL, NULL); + + return NULL; } /* diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 537091359..01ad53a6e 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -1781,12 +1781,16 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon relationRestrictionContext, prunedShardIntervalListList, MODIFY_TASK, - requiresCoordinatorEvaluation); + requiresCoordinatorEvaluation, + planningError); + if (*planningError) { + return NULL; + } } else { GenerateSingleShardRouterTaskList(job, relationShardList, - placementList, shardId); + placementList, shardId); } job->requiresCoordinatorEvaluation = requiresCoordinatorEvaluation; @@ -1806,14 +1810,12 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, { Query *originalQuery = job->jobQuery; - if (originalQuery->commandType == CMD_SELECT) { job->taskList = SingleShardTaskList(originalQuery, job->jobId, relationShardList, placementList, shardId, job->parametersInJobQueryResolved); - /* * Queries to reference tables, or distributed tables with multiple replica's have * their task placements reordered according to the configured diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index c15c6bcf9..bdd38cb54 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -576,7 +576,8 @@ extern List * QueryPushdownSqlTaskList(Query *query, uint64 jobId, RelationRestrictionContext * relationRestrictionContext, List *prunedRelationShardList, TaskType taskType, - bool modifyRequiresCoordinatorEvaluation); + bool modifyRequiresCoordinatorEvaluation, + DeferredErrorMessage **planningError); /* function declarations for managing jobs */ extern uint64 UniqueJobId(void); diff --git a/src/include/distributed/multi_router_planner.h b/src/include/distributed/multi_router_planner.h index 7dff1015c..a6b6b6152 100644 --- a/src/include/distributed/multi_router_planner.h +++ b/src/include/distributed/multi_router_planner.h @@ -83,8 +83,9 @@ extern List * TargetShardIntervalForFastPathQuery(Query *query, Const *inputDistributionKeyValue, Const **outGoingPartitionValueConst); extern void GenerateSingleShardRouterTaskList(Job *job, - List *relationShardList, - List *placementList, uint64 shardId); + List *relationShardList, + List *placementList, + uint64 shardId); extern bool IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionContext); From 5618f3a3fcc6f1dc84e7d24bd382b9921bcdfd81 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Mon, 7 Dec 2020 16:55:15 +0300 Subject: [PATCH 27/37] Use BaseRestrictInfo for finding equality columns Baseinfo also has pushed down filters etc, so it makes more sense to use BaseRestrictInfo to determine what columns have constant equality filters. Also RteIdentity is used for removing conversion candidates instead of rteIndex. --- src/backend/distributed/commands/index.c | 1 + .../distributed/executor/citus_custom_scan.c | 32 +-- .../distributed/planner/distributed_planner.c | 2 +- .../planner/insert_select_planner.c | 3 +- .../planner/local_distributed_join_planner.c | 147 ++++++------- .../planner/multi_logical_planner.c | 8 +- .../planner/multi_physical_planner.c | 117 +++++++--- .../planner/multi_router_planner.c | 48 +++-- .../distributed/planner/recursive_planning.c | 76 +++++-- .../relation_restriction_equivalence.c | 53 +++-- src/backend/distributed/shared_library_init.c | 2 +- .../distributed/utils/citus_copyfuncs.c | 2 +- .../distributed/utils/citus_outfuncs.c | 1 + .../local_distributed_join_planner.h | 11 +- .../distributed/multi_physical_planner.h | 10 +- .../distributed/multi_router_planner.h | 10 +- src/include/distributed/recursive_planning.h | 22 +- .../relation_restriction_equivalence.h | 11 +- .../expected/local_dist_join_mixed.out | 101 +++++++-- .../regress/expected/multi_partitioning.out | 32 ++- src/test/regress/multi_schedule | 4 +- .../regress/sql/citus_local_dist_joins.sql | 16 +- .../regress/sql/local_dist_join_mixed.sql | 199 ++++++++++-------- .../sql/local_dist_join_modifications.sql | 14 +- 24 files changed, 589 insertions(+), 333 deletions(-) diff --git a/src/backend/distributed/commands/index.c b/src/backend/distributed/commands/index.c index 81a037abc..a44cde0cc 100644 --- a/src/backend/distributed/commands/index.c +++ b/src/backend/distributed/commands/index.c @@ -249,6 +249,7 @@ CreateIndexStmtGetSchemaId(IndexStmt *createIndexStatement) return namespaceId; } + /* * ExecuteFunctionOnEachTableIndex executes the given pgIndexProcessor function on each * index of the given relation. diff --git a/src/backend/distributed/executor/citus_custom_scan.c b/src/backend/distributed/executor/citus_custom_scan.c index b5617d1c6..eb59b87a3 100644 --- a/src/backend/distributed/executor/citus_custom_scan.c +++ b/src/backend/distributed/executor/citus_custom_scan.c @@ -368,22 +368,22 @@ CitusBeginModifyScan(CustomScanState *node, EState *estate, int eflags) RebuildQueryStrings(workerJob); } - if (workerJob->onDummyPlacement) { - /* if this job is on a dummy placement, then it doesn't operate on - an actual shard placement */ - return; + + /* We skip shard related things if the job contains only local tables */ + if (!OnlyLocalTableJob(workerJob)) + { + /* + * Now that we know the shard ID(s) we can acquire the necessary shard metadata + * locks. Once we have the locks it's safe to load the placement metadata. + */ + + /* prevent concurrent placement changes */ + AcquireMetadataLocks(workerJob->taskList); + + /* modify tasks are always assigned using first-replica policy */ + workerJob->taskList = FirstReplicaAssignTaskList(workerJob->taskList); } - /* - * Now that we know the shard ID(s) we can acquire the necessary shard metadata - * locks. Once we have the locks it's safe to load the placement metadata. - */ - /* prevent concurrent placement changes */ - AcquireMetadataLocks(workerJob->taskList); - - - /* modify tasks are always assigned using first-replica policy */ - workerJob->taskList = FirstReplicaAssignTaskList(workerJob->taskList); /* * Now that we have populated the task placements we can determine whether @@ -544,10 +544,12 @@ RegenerateTaskForFasthPathQuery(Job *workerJob) shardId = GetAnchorShardId(shardIntervalList); } + bool containsOnlyLocalTable = false; GenerateSingleShardRouterTaskList(workerJob, relationShardList, placementList, - shardId); + shardId, + containsOnlyLocalTable); } diff --git a/src/backend/distributed/planner/distributed_planner.c b/src/backend/distributed/planner/distributed_planner.c index 6a11bb352..a0c27fc66 100644 --- a/src/backend/distributed/planner/distributed_planner.c +++ b/src/backend/distributed/planner/distributed_planner.c @@ -410,7 +410,7 @@ AdjustPartitioningForDistributedPlanning(List *rangeTableList, /* * We want Postgres to behave partitioned tables as regular relations * (i.e. we do not want to expand them to their partitions). To do this - * we set each distributed partitioned table's inh flag to appropriate + * we set each partitioned table's inh flag to appropriate * value before and after dropping to the standart_planner. */ if (rangeTableEntry->rtekind == RTE_RELATION && diff --git a/src/backend/distributed/planner/insert_select_planner.c b/src/backend/distributed/planner/insert_select_planner.c index 5949f1b18..f2da9ef90 100644 --- a/src/backend/distributed/planner/insert_select_planner.c +++ b/src/backend/distributed/planner/insert_select_planner.c @@ -789,7 +789,8 @@ RouterModifyTaskForShardInterval(Query *originalQuery, &relationShardList, &prunedShardIntervalListList, replacePrunedQueryWithDummy, - &multiShardModifyQuery, NULL); + &multiShardModifyQuery, NULL, + false); Assert(!multiShardModifyQuery); diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 7fdf97af6..650136834 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -63,8 +63,7 @@ int LocalTableJoinPolicy = LOCAL_JOIN_POLICY_AUTO; typedef struct RangeTableEntryDetails { RangeTblEntry *rangeTableEntry; - Index rteIndex; - List *restrictionList; + int rteIdentity; List *requiredAttributeNumbers; bool hasConstantFilterOnUniqueColumn; } RangeTableEntryDetails; @@ -75,9 +74,8 @@ typedef struct ConversionCandidates List *localTableList; /* local or citus local table */ }ConversionCandidates; -static bool HasConstantFilterOnUniqueColumn(FromExpr *joinTree, - RangeTblEntry *rangeTableEntry, Index - rteIndex); +static bool HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, + RelationRestriction *relationRestriction); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, PlannerRestrictionContext * plannerRestrictionContext); @@ -92,8 +90,8 @@ static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree conversionCandidates, PlannerRestrictionContext * plannerRestrictionContext); -static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid - relationId); +static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, + int rteIdentity); static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList); /* @@ -103,17 +101,16 @@ static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList */ void RecursivelyPlanLocalTableJoins(Query *query, - RecursivePlanningContext *context, List* rangeTableList) + RecursivePlanningContext *context, List *rangeTableList) { - PlannerRestrictionContext *plannerRestrictionContext = - context->plannerRestrictionContext; + GetPlannerRestrictionContext(context); Oid resultRelationId = InvalidOid; if (IsModifyCommand(query)) { resultRelationId = ModifyQueryResultRelationId(query); - } + } ConversionCandidates *conversionCandidates = CreateConversionCandidates(query->jointree, plannerRestrictionContext, rangeTableList, resultRelationId); @@ -131,15 +128,15 @@ RecursivelyPlanLocalTableJoins(Query *query, } RangeTblEntry *rangeTableEntry = rangeTableEntryDetails->rangeTableEntry; - Oid relId = rangeTableEntryDetails->rangeTableEntry->relid; - List *restrictionList = rangeTableEntryDetails->restrictionList; List *requiredAttributeNumbers = rangeTableEntryDetails->requiredAttributeNumbers; - ReplaceRTERelationWithRteSubquery(rangeTableEntry, restrictionList, + ReplaceRTERelationWithRteSubquery(rangeTableEntry, requiredAttributeNumbers, context); - RemoveFromConversionCandidates(conversionCandidates, relId); + int rteIdentity = rangeTableEntryDetails->rteIdentity; + RemoveFromConversionCandidates(conversionCandidates, rteIdentity); } } + /* * GetNextRTEToConvertToSubquery returns the range table entry * which should be converted to a subquery. It considers the local join policy @@ -211,18 +208,33 @@ AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList) * the relevant list based on the relation id. */ static void -RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, Oid relationId) +RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, int + rteIdentity) { - if (IsRelationLocalTableOrMatView(relationId)) + RangeTableEntryDetails *rangeTableEntryDetails = NULL; + foreach_ptr(rangeTableEntryDetails, conversionCandidates->localTableList) { - conversionCandidates->localTableList = - list_delete_first(conversionCandidates->localTableList); + if (rangeTableEntryDetails->rteIdentity == rteIdentity) + { + conversionCandidates->localTableList = + list_delete_ptr(conversionCandidates->localTableList, + rangeTableEntryDetails); + return; + } } - else + + foreach_ptr(rangeTableEntryDetails, conversionCandidates->distributedTableList) { - conversionCandidates->distributedTableList = - list_delete_first(conversionCandidates->distributedTableList); + if (rangeTableEntryDetails->rteIdentity == rteIdentity) + { + conversionCandidates->distributedTableList = + list_delete_ptr(conversionCandidates->distributedTableList, + rangeTableEntryDetails); + return; + } } + + ereport(ERROR, (errmsg("invalid rte index is given :%d", rteIdentity))); } @@ -241,7 +253,7 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, return false; } - if (!ContainsTableToBeConvertedToSubquery(rangeTableList)) + if (!ContainsTableToBeConvertedToSubquery(rangeTableList)) { return false; } @@ -251,7 +263,7 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, if (IsRouterPlannable(query, plannerRestrictionContext)) { ereport(DEBUG1, (errmsg("local-distributed table joins will not be converted, " - "as the query is router plannable"))); + "as the query is router plannable"))); return false; } return true; @@ -263,32 +275,22 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, * filter on a unique column. */ static bool -HasConstantFilterOnUniqueColumn(FromExpr *joinTree, RangeTblEntry *rangeTableEntry, Index - rteIndex) +HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, + RelationRestriction *relationRestriction) { if (rangeTableEntry == NULL) { return false; } + List *baseRestrictionList = relationRestriction->relOptInfo->baserestrictinfo; + List *restrictClauseList = get_all_actual_clauses(baseRestrictionList); List *rteEqualityQuals = - FetchEqualityAttrNumsForRTEFromQuals(joinTree->quals, rteIndex); + FetchEqualityAttrNumsForRTE((Node *) restrictClauseList); - Node *join = NULL; - foreach_ptr(join, joinTree->fromlist) - { - if (IsA(join, JoinExpr)) - { - JoinExpr *joinExpr = (JoinExpr *) join; - List *joinExprEqualityQuals = - FetchEqualityAttrNumsForRTEFromQuals(joinExpr->quals, rteIndex); - rteEqualityQuals = list_concat(rteEqualityQuals, joinExprEqualityQuals); - } - } - - List *uniqueIndexes = ExecuteFunctionOnEachTableIndex(rangeTableEntry->relid, - GetAllUniqueIndexes); + List *uniqueIndexAttrNumbers = ExecuteFunctionOnEachTableIndex(rangeTableEntry->relid, + GetAllUniqueIndexes); int columnNumber = 0; - foreach_int(columnNumber, uniqueIndexes) + foreach_int(columnNumber, uniqueIndexAttrNumbers) { if (list_member_int(rteEqualityQuals, columnNumber)) { @@ -327,38 +329,28 @@ GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes) * WHERE clause as a filter (e.g., not a join clause). */ static List * -RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, +RequiredAttrNumbersForRelation(RangeTblEntry *rangeTableEntry, PlannerRestrictionContext *plannerRestrictionContext) { - int rteIdentity = GetRTEIdentity(relationRte); - RelationRestrictionContext *relationRestrictionContext = - plannerRestrictionContext->relationRestrictionContext; - Relids queryRteIdentities = bms_make_singleton(rteIdentity); - RelationRestrictionContext *filteredRelationRestrictionContext = - FilterRelationRestrictionContext(relationRestrictionContext, queryRteIdentities); - List *filteredRelationRestrictionList = - filteredRelationRestrictionContext->relationRestrictionList; + RelationRestriction *relationRestriction = + RelationRestrictionForRelation(rangeTableEntry, plannerRestrictionContext); - if (list_length(filteredRelationRestrictionList) != 1) + if (relationRestriction == NULL) { return NIL; } - RelationRestriction *relationRestriction = - (RelationRestriction *) linitial(filteredRelationRestrictionList); PlannerInfo *plannerInfo = relationRestriction->plannerInfo; Query *queryToProcess = plannerInfo->parse; int rteIndex = relationRestriction->index; List *allVarsInQuery = pull_vars_of_level((Node *) queryToProcess, 0); - ListCell *varCell = NULL; List *requiredAttrNumbers = NIL; - foreach(varCell, allVarsInQuery) + Var *var = NULL; + foreach_ptr(var, allVarsInQuery) { - Var *var = (Var *) lfirst(varCell); - if (var->varno == rteIndex) { requiredAttrNumbers = list_append_unique_int(requiredAttrNumbers, @@ -379,15 +371,12 @@ CreateConversionCandidates(FromExpr *joinTree, PlannerRestrictionContext *plannerRestrictionContext, List *rangeTableList, Oid resultRelationId) { - ConversionCandidates *conversionCandidates = palloc0( - sizeof(ConversionCandidates)); + ConversionCandidates *conversionCandidates = + palloc0(sizeof(ConversionCandidates)); - int rteIndex = 0; RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) { - rteIndex++; - /* we're only interested in tables */ if (!IsRecursivelyPlannableRelation(rangeTableEntry)) { @@ -400,23 +389,27 @@ CreateConversionCandidates(FromExpr *joinTree, continue; } + RelationRestriction *relationRestriction = + RelationRestrictionForRelation(rangeTableEntry, plannerRestrictionContext); + if (relationRestriction == NULL) + { + continue; + } + int rteIdentity = GetRTEIdentity(rangeTableEntry); + RangeTableEntryDetails *rangeTableEntryDetails = palloc0(sizeof(RangeTableEntryDetails)); - rangeTableEntryDetails->rangeTableEntry = rangeTableEntry; - rangeTableEntryDetails->rteIndex = rteIndex; - rangeTableEntryDetails->restrictionList = GetRestrictInfoListForRelation( - rangeTableEntry, plannerRestrictionContext); - rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation( - rangeTableEntry, plannerRestrictionContext); - rangeTableEntryDetails->hasConstantFilterOnUniqueColumn = - HasConstantFilterOnUniqueColumn(joinTree, - rangeTableEntry, - rteIndex); - bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, - REFERENCE_TABLE) || - IsCitusTableType(rangeTableEntry->relid, - DISTRIBUTED_TABLE); + rangeTableEntryDetails->rangeTableEntry = rangeTableEntry; + rangeTableEntryDetails->rteIdentity = rteIdentity; + rangeTableEntryDetails->requiredAttributeNumbers = + RequiredAttrNumbersForRelation(rangeTableEntry, plannerRestrictionContext); + rangeTableEntryDetails->hasConstantFilterOnUniqueColumn = + HasConstantFilterOnUniqueColumn(rangeTableEntry, relationRestriction); + + bool referenceOrDistributedTable = + IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE) || + IsCitusTableType(rangeTableEntry->relid, DISTRIBUTED_TABLE); if (referenceOrDistributedTable) { conversionCandidates->distributedTableList = diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index 02e780aa1..8d0289d7c 100644 --- a/src/backend/distributed/planner/multi_logical_planner.c +++ b/src/backend/distributed/planner/multi_logical_planner.c @@ -340,7 +340,13 @@ IsCitusTableRTE(Node *node) bool IsDistributedOrReferenceTableRTE(Node *node) { - return IsDistributedTableRTE(node) || IsReferenceTableRTE(node); + Oid relationId = NodeTryGetRteRelid(node); + if (!OidIsValid(relationId)) + { + return false; + } + return IsCitusTableType(relationId, DISTRIBUTED_TABLE) || + IsCitusTableType(relationId, REFERENCE_TABLE); } diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 01802d8ec..ccfff1215 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -234,9 +234,9 @@ static StringInfo ColumnTypeArrayString(List *targetEntryList); static bool CoPlacedShardIntervals(ShardInterval *firstInterval, ShardInterval *secondInterval); -static List * FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr, Index rteIndex); -static List * FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr, Index rteIndex); - +static List * FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr); +static List * FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr); +static List * FetchEqualityAttrNumsForList(List *nodeList); #if PG_VERSION_NUM >= PG_VERSION_13 static List * GetColumnOriginalIndexes(Oid relationId); #endif @@ -271,6 +271,27 @@ CreatePhysicalDistributedPlan(MultiTreeRoot *multiTree, } +/* + * OnlyLocalTableJob true if the given task contains + * only postgres tables + */ +bool +OnlyLocalTableJob(Job *job) +{ + if (job == NULL) + { + return false; + } + List *taskList = job->taskList; + if (list_length(taskList) != 1) + { + return false; + } + Task *singleTask = (Task *) linitial(taskList); + return singleTask->containsOnlyLocalTable; +} + + /* * BuildJobTree builds the physical job tree from the given logical plan tree. * The function walks over the logical plan from the bottom up, finds boundaries @@ -2113,9 +2134,10 @@ BuildJobTreeTaskList(Job *jobTree, PlannerRestrictionContext *plannerRestriction prunedRelationShardList, READ_TASK, false, &deferredErrorMessage); - if (deferredErrorMessage != NULL) { + if (deferredErrorMessage != NULL) + { RaiseDeferredErrorInternal(deferredErrorMessage, ERROR); - } + } } else { @@ -2209,10 +2231,10 @@ QueryPushdownSqlTaskList(Query *query, uint64 jobId, if (list_length(relationRestrictionContext->relationRestrictionList) == 0) { *planningError = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "cannot handle complex subqueries when the " - "router executor is disabled", - NULL, NULL); - return NIL; + "cannot handle complex subqueries when the " + "router executor is disabled", + NULL, NULL); + return NIL; } /* defaults to be used if this is a reference table-only query */ @@ -2238,9 +2260,9 @@ QueryPushdownSqlTaskList(Query *query, uint64 jobId, if (shardCount > 0 && shardCount != cacheEntry->shardIntervalArrayLength) { *planningError = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "shard counts of co-located tables do not " - "match", - NULL, NULL); + "shard counts of co-located tables do not " + "match", + NULL, NULL); return NIL; } @@ -2306,9 +2328,10 @@ QueryPushdownSqlTaskList(Query *query, uint64 jobId, taskType, modifyRequiresCoordinatorEvaluation, planningError); - if (*planningError != NULL) { + if (*planningError != NULL) + { return NIL; - } + } subqueryTask->jobId = jobId; sqlTaskList = lappend(sqlTaskList, subqueryTask); @@ -2565,11 +2588,11 @@ QueryPushdownTaskCreate(Query *originalQuery, int shardIndex, if (list_length(taskPlacementList) == 0) { *planningError = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "cannot find a worker that has active placements for all " - "shards in the query", - NULL, NULL); + "cannot find a worker that has active placements for all " + "shards in the query", + NULL, NULL); - return NULL; + return NULL; } /* @@ -3615,26 +3638,58 @@ NodeIsRangeTblRefReferenceTable(Node *node, List *rangeTableList) /* - * FetchEqualityAttrNumsForRTEFromQuals fetches the attribute numbers from quals + * FetchEqualityAttrNumsForRTE fetches the attribute numbers from quals * which: * - has equality operator * - belongs to rangeTableEntry with rteIndex */ List * -FetchEqualityAttrNumsForRTEFromQuals(Node *quals, Index rteIndex) +FetchEqualityAttrNumsForRTE(Node *node) { - if (quals == NULL) + if (node == NULL) { return NIL; } - - if (IsA(quals, OpExpr)) + if (IsA(node, List)) { - return FetchEqualityAttrNumsForRTEOpExpr((OpExpr *) quals, rteIndex); + return FetchEqualityAttrNumsForList((List *) node); } - else if (IsA(quals, BoolExpr)) + else if (IsA(node, OpExpr)) { - return FetchEqualityAttrNumsForRTEBoolExpr((BoolExpr *) quals, rteIndex); + return FetchEqualityAttrNumsForRTEOpExpr((OpExpr *) node); + } + else if (IsA(node, BoolExpr)) + { + return FetchEqualityAttrNumsForRTEBoolExpr((BoolExpr *) node); + } + return NIL; +} + +/* + * FetchEqualityAttrNumsForList fetches the constant equality numbers + * from the given node list. + */ +static List *FetchEqualityAttrNumsForList(List *nodeList) +{ + List *attributeNums = NIL; + Node *node = NULL; + bool hasAtLeastOneEquality = false; + foreach_ptr(node, nodeList) + { + List *fetchedEqualityAttrNums = + FetchEqualityAttrNumsForRTE(node); + hasAtLeastOneEquality |= list_length(fetchedEqualityAttrNums) > 0; + attributeNums = list_concat(attributeNums, fetchedEqualityAttrNums); + } + + /* + * the given list is in the form of AND'ed expressions + * hence if we have one equality then it is enough. + * E.g: dist.a = 5 AND dist.a > 10 + */ + if (hasAtLeastOneEquality) + { + return attributeNums; } return NIL; } @@ -3647,7 +3702,7 @@ FetchEqualityAttrNumsForRTEFromQuals(Node *quals, Index rteIndex) * - belongs to rangeTableEntry with rteIndex */ static List * -FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr, Index rteIndex) +FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr) { if (!OperatorImplementsEquality(opExpr->opno)) { @@ -3656,7 +3711,7 @@ FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr, Index rteIndex) List *attributeNums = NIL; Var *var = NULL; - if (VarConstOpExprClause(opExpr, &var, NULL) && var->varno == rteIndex) + if (VarConstOpExprClause(opExpr, &var, NULL)) { attributeNums = lappend_int(attributeNums, var->varattno); } @@ -3671,7 +3726,7 @@ FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr, Index rteIndex) * - belongs to rangeTableEntry with rteIndex */ static List * -FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr, Index rteIndex) +FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr) { if (boolExpr->boolop != AND_EXPR && boolExpr->boolop != OR_EXPR) { @@ -3683,8 +3738,7 @@ FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr, Index rteIndex) Node *arg = NULL; foreach_ptr(arg, boolExpr->args) { - List *attributeNumsInSubExpression = FetchEqualityAttrNumsForRTEFromQuals(arg, - rteIndex); + List *attributeNumsInSubExpression = FetchEqualityAttrNumsForRTE(arg); if (boolExpr->boolop == AND_EXPR) { hasEquality |= list_length(attributeNumsInSubExpression) > 0; @@ -5466,7 +5520,6 @@ ActiveShardPlacementLists(List *taskList) { Task *task = (Task *) lfirst(taskCell); uint64 anchorShardId = task->anchorShardId; - List *shardPlacementList = ActiveShardPlacementList(anchorShardId); /* filter out shard placements that reside in inactive nodes */ diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 01ad53a6e..000061d9c 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -170,7 +170,8 @@ static int CompareInsertValuesByShardId(const void *leftElement, const void *rightElement); static List * SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, List *placementList, - uint64 shardId, bool parametersInQueryResolved); + uint64 shardId, bool parametersInQueryResolved, + bool containsOnlyLocalTable); static bool RowLocksOnRelations(Node *node, List **rtiLockList); static void ReorderTaskPlacementsByTaskAssignmentPolicy(Job *job, TaskAssignmentPolicyType @@ -1717,6 +1718,8 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon /* router planner should create task even if it doesn't hit a shard at all */ bool replacePrunedQueryWithDummy = true; + bool containsOnlyLocalTable = false; + /* check if this query requires coordinator evaluation */ bool requiresCoordinatorEvaluation = RequiresCoordinatorEvaluation(originalQuery); FastPathRestrictionContext *fastPathRestrictionContext = @@ -1744,7 +1747,8 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon &prunedShardIntervalListList, replacePrunedQueryWithDummy, &isMultiShardModifyQuery, - &partitionKeyValue); + &partitionKeyValue, + &containsOnlyLocalTable); } if (*planningError) @@ -1754,7 +1758,6 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon Job *job = CreateJob(originalQuery); job->partitionKeyValue = partitionKeyValue; - job->onDummyPlacement = replacePrunedQueryWithDummy; if (originalQuery->resultRelation > 0) { @@ -1783,14 +1786,15 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon MODIFY_TASK, requiresCoordinatorEvaluation, planningError); - if (*planningError) { + if (*planningError) + { return NULL; - } + } } else { GenerateSingleShardRouterTaskList(job, relationShardList, - placementList, shardId); + placementList, shardId, containsOnlyLocalTable); } job->requiresCoordinatorEvaluation = requiresCoordinatorEvaluation; @@ -1806,7 +1810,8 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon */ void GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, - List *placementList, uint64 shardId) + List *placementList, uint64 shardId, bool + containsOnlyLocalTable) { Query *originalQuery = job->jobQuery; @@ -1815,7 +1820,9 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, job->taskList = SingleShardTaskList(originalQuery, job->jobId, relationShardList, placementList, shardId, - job->parametersInJobQueryResolved); + job->parametersInJobQueryResolved, + containsOnlyLocalTable); + /* * Queries to reference tables, or distributed tables with multiple replica's have * their task placements reordered according to the configured @@ -1831,7 +1838,7 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, placementList); } } - else if (shardId == INVALID_SHARD_ID && !job->onDummyPlacement) + else if (shardId == INVALID_SHARD_ID && !containsOnlyLocalTable) { /* modification that prunes to 0 shards */ job->taskList = NIL; @@ -1841,7 +1848,8 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, job->taskList = SingleShardTaskList(originalQuery, job->jobId, relationShardList, placementList, shardId, - job->parametersInJobQueryResolved); + job->parametersInJobQueryResolved, + containsOnlyLocalTable); } } @@ -1934,7 +1942,8 @@ RemoveCoordinatorPlacementIfNotSingleNode(List *placementList) static List * SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, List *placementList, uint64 shardId, - bool parametersInQueryResolved) + bool parametersInQueryResolved, + bool containsOnlyLocalTable) { TaskType taskType = READ_TASK; char replicationModel = 0; @@ -1993,6 +2002,7 @@ SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, } Task *task = CreateTask(taskType); + task->containsOnlyLocalTable = containsOnlyLocalTable; List *relationRowLockList = NIL; RowLocksOnRelations((Node *) query, &relationRowLockList); @@ -2104,6 +2114,8 @@ SelectsFromDistributedTable(List *rangeTableList, Query *query) } +static bool ContainsOnlyLocalTables(RTEListProperties *rteProperties); + /* * RouterQuery runs router pruning logic for SELECT, UPDATE and DELETE queries. * If there are shards present and query is routable, all RTEs have been updated @@ -2131,7 +2143,8 @@ PlanRouterQuery(Query *originalQuery, List **placementList, uint64 *anchorShardId, List **relationShardList, List **prunedShardIntervalListList, bool replacePrunedQueryWithDummy, bool *multiShardModifyQuery, - Const **partitionValueConst) + Const **partitionValueConst, + bool *containsOnlyLocalTable) { bool isMultiShardQuery = false; DeferredErrorMessage *planningError = NULL; @@ -2247,6 +2260,10 @@ PlanRouterQuery(Query *originalQuery, /* both Postgres tables and materialized tables are locally avaliable */ RTEListProperties *rteProperties = GetRTEListPropertiesForQuery(originalQuery); + if (shardId == INVALID_SHARD_ID && ContainsOnlyLocalTables(rteProperties)) + { + *containsOnlyLocalTable = true; + } bool hasPostgresLocalRelation = rteProperties->hasPostgresLocalTable || rteProperties->hasMaterializedView; List *taskPlacementList = @@ -2280,6 +2297,13 @@ PlanRouterQuery(Query *originalQuery, } +static bool +ContainsOnlyLocalTables(RTEListProperties *rteProperties) +{ + return !rteProperties->hasDistributedTable && !rteProperties->hasReferenceTable; +} + + /* * CreateTaskPlacementListForShardIntervals returns a list of shard placements * on which it can access all shards in shardIntervalListList, which contains diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index a0c0a7b1d..fa7dbea9e 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -100,6 +100,20 @@ #include "utils/guc.h" #include "utils/lsyscache.h" +/* + * RecursivePlanningContext is used to recursively plan subqueries + * and CTEs, pull results to the coordinator, and push it back into + * the workers. + */ +struct RecursivePlanningContextInternal +{ + int level; + uint64 planId; + bool allDistributionKeysInQueryAreEqual; /* used for some optimizations */ + List *subPlanList; + PlannerRestrictionContext *plannerRestrictionContext; +}; + /* track depth of current recursive planner query */ static int recursivePlanningDepth = 0; @@ -159,7 +173,7 @@ static bool AllDistributionKeysInSubqueryAreEqual(Query *subquery, static bool IsTableLocallyAccessible(Oid relationId); static bool ShouldRecursivelyPlanSetOperation(Query *query, RecursivePlanningContext *context); -static void RecursivelyPlanSubquery(Query *subquery, +static bool RecursivelyPlanSubquery(Query *subquery, RecursivePlanningContext *planningContext); static void RecursivelyPlanSetOperations(Query *query, Node *node, RecursivePlanningContext *context); @@ -178,11 +192,10 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); -static void -UpdateVarNosInNode(Query *query, Index newVarNo); +static void UpdateVarNosInNode(Query *query, Index newVarNo); static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, - List **joinRangeTableEntries); + List **joinRangeTableEntries); /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. @@ -347,22 +360,34 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context &rangeTableList); if (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, - plannerRestrictionContext)) { + plannerRestrictionContext)) + { /* - * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or - * a query with local table/citus local table and subquery. We convert local/citus local - * tables to a subquery until they can be planned. - * This is the last call in this function since we want the other calls to be finished - * so that we can check if the current plan is router plannable at any step within this function. - */ + * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or + * a query with local table/citus local table and subquery. We convert local/citus local + * tables to a subquery until they can be planned. + * This is the last call in this function since we want the other calls to be finished + * so that we can check if the current plan is router plannable at any step within this function. + */ RecursivelyPlanLocalTableJoins(query, context, rangeTableList); - } return NULL; } + +/* + * GetPlannerRestrictionContext returns the planner restriction context + * from the given context. + */ +PlannerRestrictionContext * +GetPlannerRestrictionContext(RecursivePlanningContext *recursivePlanningContext) +{ + return recursivePlanningContext->plannerRestrictionContext; +} + + /* * GetRangeTableEntriesFromJoinTree gets the range table entries that are * on the given join tree. @@ -407,7 +432,6 @@ GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, } - /* * ShouldRecursivelyPlanNonColocatedSubqueries returns true if the input query contains joins * that are not on the distribution key. @@ -1180,7 +1204,7 @@ IsRelationLocalTableOrMatView(Oid relationId) * and immediately returns. Later, the planner decides on what to do * with the query. */ -static void +static bool RecursivelyPlanSubquery(Query *subquery, RecursivePlanningContext *planningContext) { uint64 planId = planningContext->planId; @@ -1191,7 +1215,7 @@ RecursivelyPlanSubquery(Query *subquery, RecursivePlanningContext *planningConte elog(DEBUG2, "skipping recursive planning for the subquery since it " "contains references to outer queries"); - return; + return false; } /* @@ -1234,6 +1258,7 @@ RecursivelyPlanSubquery(Query *subquery, RecursivePlanningContext *planningConte /* finally update the input subquery to point the result query */ *subquery = *resultQuery; + return true; } @@ -1419,16 +1444,20 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) /* * ReplaceRTERelationWithRteSubquery replaces the input rte relation target entry * with a subquery. The function also pushes down the filters to the subquery. - * + * * It then recursively plans the subquery. */ void -ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrictionList, +ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, RecursivePlanningContext *context) { Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); - Expr *andedBoundExpressions = make_ands_explicit(restrictionList); + List *restrictionList = + GetRestrictInfoListForRelation(rangeTableEntry, + context->plannerRestrictionContext); + List *copyRestrictionList = copyObject(restrictionList); + Expr *andedBoundExpressions = make_ands_explicit(copyRestrictionList); subquery->jointree->quals = (Node *) andedBoundExpressions; UpdateVarNosInNode(subquery, SINGLE_RTE_INDEX); @@ -1456,7 +1485,13 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *restrict } /* as we created the subquery, now forcefully recursively plan it */ - RecursivelyPlanSubquery(rangeTableEntry->subquery, context); + bool recursivellyPlanned = RecursivelyPlanSubquery(rangeTableEntry->subquery, + context); + if (!recursivellyPlanned) + { + ereport(ERROR, (errmsg( + "unexpected state: query should have been recursively planned"))); + } } @@ -1610,6 +1645,7 @@ ContainsLocalTableDistributedTableJoin(List *rangeTableList) return containsLocalTable && containsDistributedTable; } + /* * WrapFunctionsInSubqueries iterates over all the immediate Range Table Entries * of a query and wraps the functions inside (SELECT * FROM fnc() f) @@ -1733,7 +1769,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) subquery->targetList = lappend(subquery->targetList, targetEntry); } } - /* * If tupleDesc is NULL we have 2 different cases: * @@ -1783,7 +1818,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) columnType = list_nth_oid(rangeTblFunction->funccoltypes, targetColumnIndex); } - /* use the types in the function definition otherwise */ else { diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index ea4fe336d..cf1c5a59d 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -1848,34 +1848,25 @@ List * GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, PlannerRestrictionContext *plannerRestrictionContext) { - int rteIdentity = GetRTEIdentity(rangeTblEntry); - RelationRestrictionContext *relationRestrictionContext = - plannerRestrictionContext->relationRestrictionContext; - Relids queryRteIdentities = bms_make_singleton(rteIdentity); - RelationRestrictionContext *filteredRelationRestrictionContext = - FilterRelationRestrictionContext(relationRestrictionContext, queryRteIdentities); - List *filteredRelationRestrictionList = - filteredRelationRestrictionContext->relationRestrictionList; - - if (list_length(filteredRelationRestrictionList) != 1) + RelationRestriction *relationRestriction = + RelationRestrictionForRelation(rangeTblEntry, plannerRestrictionContext); + if (relationRestriction == NULL) { return NIL; } - RelationRestriction *relationRestriction = - (RelationRestriction *) linitial(filteredRelationRestrictionList); - RelOptInfo *relOptInfo = relationRestriction->relOptInfo; - List *baseRestrictInfo = relOptInfo->baserestrictinfo; List *joinRestrictInfo = relOptInfo->joininfo; + List *baseRestrictInfo = relOptInfo->baserestrictinfo; - List *joinRrestrictClauseList = get_all_actual_clauses(joinRestrictInfo); - if (ContainsFalseClause(joinRrestrictClauseList)) + List *joinRestrictClauseList = get_all_actual_clauses(joinRestrictInfo); + if (ContainsFalseClause(joinRestrictClauseList)) { /* found WHERE false, no need to continue */ - return copyObject((List *) joinRrestrictClauseList); + return copyObject((List *) joinRestrictClauseList); } + List *restrictExprList = NIL; RestrictInfo *restrictInfo = NULL; foreach_ptr(restrictInfo, baseRestrictInfo) @@ -1919,6 +1910,34 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, } +/* + * RelationRestrictionForRelation gets the relation restriction for the given + * range table entry. + */ +RelationRestriction * +RelationRestrictionForRelation(RangeTblEntry *rangeTableEntry, + PlannerRestrictionContext *plannerRestrictionContext) +{ + int rteIdentity = GetRTEIdentity(rangeTableEntry); + RelationRestrictionContext *relationRestrictionContext = + plannerRestrictionContext->relationRestrictionContext; + Relids queryRteIdentities = bms_make_singleton(rteIdentity); + RelationRestrictionContext *filteredRelationRestrictionContext = + FilterRelationRestrictionContext(relationRestrictionContext, queryRteIdentities); + List *filteredRelationRestrictionList = + filteredRelationRestrictionContext->relationRestrictionList; + + if (list_length(filteredRelationRestrictionList) != 1) + { + return NULL; + } + + RelationRestriction *relationRestriction = + (RelationRestriction *) linitial(filteredRelationRestrictionList); + return relationRestriction; +} + + /* * IsParam determines whether the given node is a param. */ diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index c1b4a7b0b..15a2ca416 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -720,7 +720,7 @@ RegisterCitusConfigVariables(void) PGC_SIGHUP, GUC_SUPERUSER_ONLY, NULL, NULL, LocalPoolSizeGucShowHook); - + DefineCustomEnumVariable( "citus.local_table_join_policy", gettext_noop("defines the behaviour when a distributed table " diff --git a/src/backend/distributed/utils/citus_copyfuncs.c b/src/backend/distributed/utils/citus_copyfuncs.c index 698e96449..763f5e910 100644 --- a/src/backend/distributed/utils/citus_copyfuncs.c +++ b/src/backend/distributed/utils/citus_copyfuncs.c @@ -101,7 +101,6 @@ copyJobInfo(Job *newnode, Job *from) COPY_NODE_FIELD(partitionKeyValue); COPY_NODE_FIELD(localPlannedStatements); COPY_SCALAR_FIELD(parametersInJobQueryResolved); - COPY_SCALAR_FIELD(onDummyPlacement); } @@ -328,6 +327,7 @@ CopyNodeTask(COPYFUNC_ARGS) COPY_SCALAR_FIELD(fetchedExplainAnalyzePlacementIndex); COPY_STRING_FIELD(fetchedExplainAnalyzePlan); COPY_SCALAR_FIELD(fetchedExplainAnalyzeExecutionDuration); + COPY_SCALAR_FIELD(containsOnlyLocalTable); } diff --git a/src/backend/distributed/utils/citus_outfuncs.c b/src/backend/distributed/utils/citus_outfuncs.c index 9adbca31a..e359fe7c3 100644 --- a/src/backend/distributed/utils/citus_outfuncs.c +++ b/src/backend/distributed/utils/citus_outfuncs.c @@ -540,6 +540,7 @@ OutTask(OUTFUNC_ARGS) WRITE_INT_FIELD(fetchedExplainAnalyzePlacementIndex); WRITE_STRING_FIELD(fetchedExplainAnalyzePlan); WRITE_FLOAT_FIELD(fetchedExplainAnalyzeExecutionDuration, "%.2f"); + WRITE_BOOL_FIELD(containsOnlyLocalTable); } diff --git a/src/include/distributed/local_distributed_join_planner.h b/src/include/distributed/local_distributed_join_planner.h index 88fa5e1be..041cb63fd 100644 --- a/src/include/distributed/local_distributed_join_planner.h +++ b/src/include/distributed/local_distributed_join_planner.h @@ -27,11 +27,12 @@ typedef enum extern int LocalTableJoinPolicy; -extern bool -ShouldConvertLocalTableJoinsToSubqueries(Query *query, - List *rangeTableList, - PlannerRestrictionContext *plannerRestrictionContext); +extern bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, + List *rangeTableList, + PlannerRestrictionContext * + plannerRestrictionContext); extern void RecursivelyPlanLocalTableJoins(Query *query, - RecursivePlanningContext *context, List *rangeTableList); + RecursivePlanningContext *context, + List *rangeTableList); #endif /* LOCAL_DISTRIBUTED_JOIN_PLANNER_H */ diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index bdd38cb54..125e7406f 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -163,7 +163,6 @@ typedef struct Job * query. */ bool parametersInJobQueryResolved; - bool onDummyPlacement; } Job; @@ -329,6 +328,11 @@ typedef struct Task * ExplainTaskList(). */ double fetchedExplainAnalyzeExecutionDuration; + + /* + * containsOnlyLocalTable is true if the task contains only postgres table/MV. + */ + bool containsOnlyLocalTable; } Task; @@ -579,6 +583,8 @@ extern List * QueryPushdownSqlTaskList(Query *query, uint64 jobId, bool modifyRequiresCoordinatorEvaluation, DeferredErrorMessage **planningError); +extern bool OnlyLocalTableJob(Job *job); + /* function declarations for managing jobs */ extern uint64 UniqueJobId(void); @@ -591,6 +597,6 @@ extern RangeTblEntry * DerivedRangeTableEntry(MultiNode *multiNode, List *column List *funcColumnTypeMods, List *funcCollations); -extern List * FetchEqualityAttrNumsForRTEFromQuals(Node *quals, Index rteIndex); +extern List * FetchEqualityAttrNumsForRTE(Node *quals); #endif /* MULTI_PHYSICAL_PLANNER_H */ diff --git a/src/include/distributed/multi_router_planner.h b/src/include/distributed/multi_router_planner.h index a6b6b6152..d16ad2d3e 100644 --- a/src/include/distributed/multi_router_planner.h +++ b/src/include/distributed/multi_router_planner.h @@ -42,7 +42,8 @@ extern DeferredErrorMessage * PlanRouterQuery(Query *originalQuery, List **prunedShardIntervalListList, bool replacePrunedQueryWithDummy, bool *multiShardModifyQuery, - Const **partitionValueConst); + Const **partitionValueConst, + bool *containOnlyLocalTable); extern List * RelationShardListForShardIntervalList(List *shardIntervalList, bool *shardsPresent); extern List * CreateTaskPlacementListForShardIntervals(List *shardIntervalList, @@ -83,9 +84,10 @@ extern List * TargetShardIntervalForFastPathQuery(Query *query, Const *inputDistributionKeyValue, Const **outGoingPartitionValueConst); extern void GenerateSingleShardRouterTaskList(Job *job, - List *relationShardList, - List *placementList, - uint64 shardId); + List *relationShardList, + List *placementList, + uint64 shardId, + bool containsOnlyLocalTable); extern bool IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionContext); diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index ed85f88ed..24aa3d08b 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -22,21 +22,16 @@ #include "nodes/relation.h" #endif -/* - * RecursivePlanningContext is used to recursively plan subqueries - * and CTEs, pull results to the coordinator, and push it back into - * the workers. - */ -typedef struct RecursivePlanningContext +typedef struct RecursivePlanningContextInternal RecursivePlanningContext; + +typedef struct RangeTblEntryIndex { - int level; - uint64 planId; - bool allDistributionKeysInQueryAreEqual; /* used for some optimizations */ - List *subPlanList; - PlannerRestrictionContext *plannerRestrictionContext; -} RecursivePlanningContext; - + RangeTblEntry *rangeTableEntry; + Index rteIndex; +}RangeTblEntryIndex; +extern PlannerRestrictionContext * GetPlannerRestrictionContext( + RecursivePlanningContext *recursivePlanningContext); extern List * GenerateSubplansForSubqueriesAndCTEs(uint64 planId, Query *originalQuery, PlannerRestrictionContext * plannerRestrictionContext); @@ -50,7 +45,6 @@ extern Query * BuildReadIntermediateResultsArrayQuery(List *targetEntryList, extern bool GeneratingSubplans(void); extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, - List *restrictionList, List *requiredAttrNumbers, RecursivePlanningContext *context); extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList); diff --git a/src/include/distributed/relation_restriction_equivalence.h b/src/include/distributed/relation_restriction_equivalence.h index e9bdb9adc..bfa650c0e 100644 --- a/src/include/distributed/relation_restriction_equivalence.h +++ b/src/include/distributed/relation_restriction_equivalence.h @@ -41,13 +41,18 @@ extern PlannerRestrictionContext * FilterPlannerRestrictionForQuery( extern List * GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry, PlannerRestrictionContext * plannerRestrictionContext); +extern RelationRestriction * RelationRestrictionForRelation( + RangeTblEntry *rangeTableEntry, + PlannerRestrictionContext * + plannerRestrictionContext); extern JoinRestrictionContext * RemoveDuplicateJoinRestrictions(JoinRestrictionContext * joinRestrictionContext); extern bool EquivalenceListContainsRelationsEquality(List *attributeEquivalenceList, RelationRestrictionContext * restrictionContext); -extern RelationRestrictionContext * -FilterRelationRestrictionContext(RelationRestrictionContext *relationRestrictionContext, - Relids queryRteIdentities); +extern RelationRestrictionContext * FilterRelationRestrictionContext( + RelationRestrictionContext *relationRestrictionContext, + Relids + queryRteIdentities); #endif /* RELATION_RESTRICTION_EQUIVALENCE_H */ diff --git a/src/test/regress/expected/local_dist_join_mixed.out b/src/test/regress/expected/local_dist_join_mixed.out index 95cf94ff9..b7d40fd7c 100644 --- a/src/test/regress/expected/local_dist_join_mixed.out +++ b/src/test/regress/expected/local_dist_join_mixed.out @@ -446,9 +446,11 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OP (1 row) SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) WHERE d2.id = 1 ORDER BY 1 DESC LIMIT 4; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) LEFT JOIN local_dist_join_mixed.distributed d2 USING (id)) WHERE (d2.id OPERATOR(pg_catalog.=) 1) ORDER BY (count(*)) DESC LIMIT 4 +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d2 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d2 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local USING (id)) LEFT JOIN (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d2 USING (id)) WHERE (d2.id OPERATOR(pg_catalog.=) 1) ORDER BY (count(*)) DESC LIMIT 4 count --------------------------------------------------------------------- 1 @@ -1171,9 +1173,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- w count(*) it works fine as PG ignores the inner tables SELECT count(*) FROM distributed LEFT JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed LEFT JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed LEFT JOIN local_dist_join_mixed.local USING (id)) count --------------------------------------------------------------------- 101 @@ -1188,20 +1190,19 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 101 (1 row) -SELECT id, name FROM distributed LEFT JOIN local USING (id) LIMIT 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id, distributed.name FROM (local_dist_join_mixed.distributed LEFT JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) LIMIT 1 -DEBUG: push down of limit count: 1 +SELECT id, name FROM distributed LEFT JOIN local USING (id) ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id, distributed.name FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed LEFT JOIN local_dist_join_mixed.local USING (id)) ORDER BY distributed.id LIMIT 1 id | name --------------------------------------------------------------------- - 1 | 1 + 0 | 0 (1 row) -SELECT id, name FROM local LEFT JOIN distributed USING (id) LIMIT 1; +SELECT id, name FROM local LEFT JOIN distributed USING (id) ORDER BY 1 LIMIT 1; DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.id, distributed.name FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) LIMIT 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.id, distributed.name FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY local.id LIMIT 1 ERROR: cannot pushdown the subquery DETAIL: Complex subqueries and CTEs cannot be in the outer part of the outer join SELECT @@ -1521,6 +1522,78 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM --------------------------------------------------------------------- (0 rows) +SELECT + count(*) +FROM + distributed +JOIN LATERAL + (SELECT + * + FROM + local + JOIN + distributed d2 + ON(true) + WHERE local.id = distributed.id AND d2.id = local.id) as foo +ON (true); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN LATERAL (SELECT local.id, local.title, d2.id, d2.name, d2.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed d2 ON (true)) WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (d2.id OPERATOR(pg_catalog.=) local.id))) foo(id, title, id_1, name, created_at) ON (true)) + count +--------------------------------------------------------------------- + 101 +(1 row) + +SELECT local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2 LIMIt 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.title, local.title FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY local.title, local.title LIMIT 1 +DEBUG: push down of limit count: 1 + title | title +--------------------------------------------------------------------- + 0 | 0 +(1 row) + +SELECT NULL FROM local JOIN distributed USING(id) ORDER BY 1 LIMIt 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT NULL::text FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY NULL::text LIMIT 1 +DEBUG: push down of limit count: 1 + ?column? +--------------------------------------------------------------------- + +(1 row) + +SELECT distributed.name, distributed.name, local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2,3,4 LIMIT 1; +DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.name, distributed.name, local.title, local.title FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY distributed.name, distributed.name, local.title, local.title LIMIT 1 +DEBUG: push down of limit count: 1 + name | name | title | title +--------------------------------------------------------------------- + 0 | 0 | 0 | 0 +(1 row) + +SELECT + COUNT(*) +FROM + local +JOIN + distributed +USING + (id) +JOIN + (SELECT id, NULL, NULL FROM distributed) foo +USING + (id); +DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) JOIN (SELECT distributed_1.id, NULL::text, NULL::text FROM local_dist_join_mixed.distributed distributed_1) foo(id, "?column?", "?column?_1") USING (id)) + count +--------------------------------------------------------------------- + 101 +(1 row) + DROP SCHEMA local_dist_join_mixed CASCADE; NOTICE: drop cascades to 7 other objects DETAIL: drop cascades to table distributed diff --git a/src/test/regress/expected/multi_partitioning.out b/src/test/regress/expected/multi_partitioning.out index a31711fe7..c11d800b2 100644 --- a/src/test/regress/expected/multi_partitioning.out +++ b/src/test/regress/expected/multi_partitioning.out @@ -1471,17 +1471,29 @@ BEGIN; UPDATE partitioning_locks_2009 SET time = '2009-03-01'; -- see the locks on parent table SELECT * FROM lockinfo; - logicalrelid | locktype | mode + logicalrelid | locktype | mode --------------------------------------------------------------------- - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock - partitioning_locks_2009 | shard | ShareUpdateExclusiveLock -(8 rows) + partitioning_locks | colocated_shards_metadata | ShareLock + partitioning_locks | colocated_shards_metadata | ShareLock + partitioning_locks | colocated_shards_metadata | ShareLock + partitioning_locks | colocated_shards_metadata | ShareLock + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | colocated_shards_metadata | ShareLock + partitioning_locks_2009 | colocated_shards_metadata | ShareLock + partitioning_locks_2009 | colocated_shards_metadata | ShareLock + partitioning_locks_2009 | colocated_shards_metadata | ShareLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock + partitioning_locks_2009 | shard | ShareUpdateExclusiveLock + partitioning_locks_2010 | colocated_shards_metadata | ShareLock + partitioning_locks_2010 | colocated_shards_metadata | ShareLock + partitioning_locks_2010 | colocated_shards_metadata | ShareLock + partitioning_locks_2010 | colocated_shards_metadata | ShareLock +(20 rows) COMMIT; -- test shard resource locks with TRUNCATE diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 80cf392a5..e80569d40 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -222,10 +222,10 @@ test: multi_modifying_xacts test: multi_repartition_udt multi_repartitioned_subquery_udf multi_subtransactions test: multi_transaction_recovery -test: local_dist_join_modifications +test: local_dist_join_modifications test: local_table_join test: local_dist_join_mixed -test: citus_local_dist_joins +test: citus_local_dist_joins # --------- # multi_copy creates hash and range-partitioned tables and performs COPY diff --git a/src/test/regress/sql/citus_local_dist_joins.sql b/src/test/regress/sql/citus_local_dist_joins.sql index 34523eec2..d9806ddd0 100644 --- a/src/test/regress/sql/citus_local_dist_joins.sql +++ b/src/test/regress/sql/citus_local_dist_joins.sql @@ -128,7 +128,7 @@ SET FROM citus_local WHERE - mv1.key = citus_local.key; + mv1.key = citus_local.key; ROLLBACK; BEGIN; @@ -139,7 +139,7 @@ SET FROM mv1 WHERE - mv1.key = citus_local.key; + mv1.key = citus_local.key; ROLLBACK; BEGIN; @@ -150,9 +150,9 @@ SET FROM mv2 WHERE - mv2.key = citus_local.key; + mv2.key = citus_local.key; ROLLBACK; - + -- DELETE operations BEGIN; @@ -204,21 +204,21 @@ DELETE FROM USING citus_local WHERE - mv1.key = citus_local.key; + mv1.key = citus_local.key; DELETE FROM citus_local USING mv1 WHERE - mv1.key = citus_local.key; + mv1.key = citus_local.key; DELETE FROM citus_local USING mv2 WHERE - mv2.key = citus_local.key; + mv2.key = citus_local.key; SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; @@ -229,4 +229,4 @@ SET client_min_messages to ERROR; DROP TABLE citus_local; SELECT master_remove_node('localhost', :master_port); \set VERBOSITY terse -DROP SCHEMA citus_local_dist_joins CASCADE; \ No newline at end of file +DROP SCHEMA citus_local_dist_joins CASCADE; diff --git a/src/test/regress/sql/local_dist_join_mixed.sql b/src/test/regress/sql/local_dist_join_mixed.sql index 1a00c4f22..65ab89941 100644 --- a/src/test/regress/sql/local_dist_join_mixed.sql +++ b/src/test/regress/sql/local_dist_join_mixed.sql @@ -3,13 +3,13 @@ SET search_path TO local_dist_join_mixed; -CREATE TABLE distributed (id bigserial PRIMARY KEY, - name text, +CREATE TABLE distributed (id bigserial PRIMARY KEY, + name text, created_at timestamptz DEFAULT now()); -CREATE TABLE reference (id bigserial PRIMARY KEY, +CREATE TABLE reference (id bigserial PRIMARY KEY, title text); -CREATE TABLE local (id bigserial PRIMARY KEY, +CREATE TABLE local (id bigserial PRIMARY KEY, title text); -- these above restrictions brought us to the following schema @@ -100,118 +100,118 @@ SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id + local.id) FROM distribut -- nested subqueries -SELECT - count(*) -FROM +SELECT + count(*) +FROM (SELECT * FROM (SELECT * FROM distributed) as foo) as bar - JOIN + JOIN local USING(id); -SELECT - count(*) -FROM +SELECT + count(*) +FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar - JOIN + JOIN local USING(id); -SELECT - count(*) -FROM +SELECT + count(*) +FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar - JOIN + JOIN local USING(id); -SELECT - count(*) -FROM +SELECT + count(*) +FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar - JOIN + JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id); --- TODO: Unnecessary recursive planning for local -SELECT - count(*) -FROM +-- TODO: Unnecessary recursive planning for local +SELECT + count(*) +FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed LIMIT 1) as foo) as bar - JOIN + JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id); -- subqueries in WHERE clause -- is not colocated, and the JOIN inside as well. -- so should be recursively planned twice -SELECT - count(*) -FROM - distributed -WHERE - id > (SELECT - count(*) - FROM +SELECT + count(*) +FROM + distributed +WHERE + id > (SELECT + count(*) + FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar - JOIN + JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id) ); -- two distributed tables are co-located and JOINed on distribution --- key, so should be fine to pushdown -SELECT - count(*) -FROM +-- key, so should be fine to pushdown +SELECT + count(*) +FROM distributed d_upper -WHERE - (SELECT +WHERE + (SELECT bar.id - FROM + FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar - JOIN + JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id) ) IS NOT NULL; -SELECT - count(*) -FROM +SELECT + count(*) +FROM distributed d_upper -WHERE - (SELECT +WHERE + (SELECT bar.id - FROM + FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar - JOIN + JOIN local as foo USING(id) ) IS NOT NULL; -SELECT - count(*) -FROM +SELECT + count(*) +FROM distributed d_upper -WHERE d_upper.id > - (SELECT +WHERE d_upper.id > + (SELECT bar.id - FROM + FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar - JOIN + JOIN local as foo USING(id) ); -SELECT - count(*) -FROM +SELECT + count(*) +FROM distributed d_upper -WHERE - (SELECT +WHERE + (SELECT bar.id - FROM + FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar - JOIN + JOIN (SELECT *, random() FROM (SELECT *,random() FROM local WHERE d_upper.id = id) as foo2) as bar2 USING(id) ) IS NOT NULL; @@ -222,15 +222,15 @@ WHERE -- subqueries in the target list -- router, should work -select (SELECT local.id) FROM local, distributed WHERE distributed.id = 1 LIMIT 1; +select (SELECT local.id) FROM local, distributed WHERE distributed.id = 1 LIMIT 1; -- should fail -select (SELECT local.id) FROM local, distributed WHERE distributed.id != 1 LIMIT 1; +select (SELECT local.id) FROM local, distributed WHERE distributed.id != 1 LIMIT 1; -- currently not supported, but should work with https://github.com/citusdata/citus/pull/4360/files -SELECT +SELECT name, (SELECT id FROM local WHERE id = e.id) -FROM +FROM distributed e ORDER BY 1,2 LIMIT 1; @@ -260,7 +260,7 @@ SELECT count(*) FROM (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) ) bar; -select count(DISTINCT id) +select count(DISTINCT id) FROM ( (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as fo) @@ -303,14 +303,14 @@ SELECT COUNT(*) FROM distributed JOIN LATERAL (SELECT * FROM local WHERE local.i SELECT count(*) FROM distributed CROSS JOIN local; -SELECT count(*) FROM distributed CROSS JOIN local WHERE distributed.id = 1; +SELECT count(*) FROM distributed CROSS JOIN local WHERE distributed.id = 1; -- w count(*) it works fine as PG ignores the inner tables SELECT count(*) FROM distributed LEFT JOIN local USING (id); SELECT count(*) FROM local LEFT JOIN distributed USING (id); -SELECT id, name FROM distributed LEFT JOIN local USING (id) LIMIT 1; -SELECT id, name FROM local LEFT JOIN distributed USING (id) LIMIT 1; +SELECT id, name FROM distributed LEFT JOIN local USING (id) ORDER BY 1 LIMIT 1; +SELECT id, name FROM local LEFT JOIN distributed USING (id) ORDER BY 1 LIMIT 1; SELECT foo1.id @@ -326,18 +326,18 @@ SELECT id, name FROM local LEFT JOIN distributed USING (id) LIMIT 1; (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo10, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo1 WHERE - foo1.id = foo9.id AND - foo1.id = foo8.id AND - foo1.id = foo7.id AND - foo1.id = foo6.id AND - foo1.id = foo5.id AND - foo1.id = foo4.id AND - foo1.id = foo3.id AND - foo1.id = foo2.id AND - foo1.id = foo10.id AND + foo1.id = foo9.id AND + foo1.id = foo8.id AND + foo1.id = foo7.id AND + foo1.id = foo6.id AND + foo1.id = foo5.id AND + foo1.id = foo4.id AND + foo1.id = foo3.id AND + foo1.id = foo2.id AND + foo1.id = foo10.id AND foo1.id = foo1.id -ORDER BY 1; - +ORDER BY 1; + SELECT foo1.id FROM @@ -352,7 +352,7 @@ WHERE foo1.id = foo3.id AND foo1.id = foo4.id AND foo1.id = foo5.id -ORDER BY 1; +ORDER BY 1; SELECT foo1.id @@ -368,8 +368,37 @@ WHERE foo1.id = foo3.id AND foo1.id = foo4.id AND foo1.id = foo5.id -ORDER BY 1; +ORDER BY 1; +SELECT + count(*) +FROM + distributed +JOIN LATERAL + (SELECT + * + FROM + local + JOIN + distributed d2 + ON(true) + WHERE local.id = distributed.id AND d2.id = local.id) as foo +ON (true); +SELECT local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2 LIMIt 1; +SELECT NULL FROM local JOIN distributed USING(id) ORDER BY 1 LIMIt 1; +SELECT distributed.name, distributed.name, local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2,3,4 LIMIT 1; +SELECT + COUNT(*) +FROM + local +JOIN + distributed +USING + (id) +JOIN + (SELECT id, NULL, NULL FROM distributed) foo +USING + (id); -DROP SCHEMA local_dist_join_mixed CASCADE; \ No newline at end of file +DROP SCHEMA local_dist_join_mixed CASCADE; diff --git a/src/test/regress/sql/local_dist_join_modifications.sql b/src/test/regress/sql/local_dist_join_modifications.sql index f8c8ee886..843f04dbe 100644 --- a/src/test/regress/sql/local_dist_join_modifications.sql +++ b/src/test/regress/sql/local_dist_join_modifications.sql @@ -104,7 +104,7 @@ SET FROM postgres_table WHERE - mv1.key = postgres_table.key; + mv1.key = postgres_table.key; ROLLBACK; BEGIN; @@ -115,7 +115,7 @@ SET FROM mv1 WHERE - mv1.key = postgres_table.key; + mv1.key = postgres_table.key; ROLLBACK; BEGIN; @@ -126,7 +126,7 @@ SET FROM mv2 WHERE - mv2.key = postgres_table.key; + mv2.key = postgres_table.key; ROLLBACK; -- in case of update/delete we always recursively plan @@ -351,22 +351,22 @@ DELETE FROM USING postgres_table WHERE - mv1.key = postgres_table.key; + mv1.key = postgres_table.key; DELETE FROM postgres_table USING mv1 WHERE - mv1.key = postgres_table.key; + mv1.key = postgres_table.key; DELETE FROM postgres_table USING mv2 WHERE - mv2.key = postgres_table.key; + mv2.key = postgres_table.key; SET client_min_messages to ERROR; -DROP SCHEMA local_dist_join_modifications CASCADE; \ No newline at end of file +DROP SCHEMA local_dist_join_modifications CASCADE; From 13c43d57447a2c257d3c72248eb8977e96d41997 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 9 Dec 2020 01:47:36 +0300 Subject: [PATCH 28/37] Improve table conversion logic in dist-local joins --- .../planner/local_distributed_join_planner.c | 80 +++-- .../planner/multi_physical_planner.c | 6 +- .../distributed/planner/recursive_planning.c | 2 + .../expected/citus_local_dist_joins.out | 7 +- .../expected/citus_local_tables_queries.out | 4 +- .../regress/expected/local_table_join.out | 319 +++++++++++++++++- .../regress/sql/citus_local_dist_joins.sql | 2 +- .../sql/citus_local_tables_queries.sql | 3 +- src/test/regress/sql/local_table_join.sql | 70 +++- 9 files changed, 452 insertions(+), 41 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 650136834..1d8dfd9f2 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -74,25 +74,29 @@ typedef struct ConversionCandidates List *localTableList; /* local or citus local table */ }ConversionCandidates; +typedef struct IndexColumns +{ + List *indexColumnNos; +}IndexColumns; + static bool HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, RelationRestriction *relationRestriction); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, PlannerRestrictionContext * plannerRestrictionContext); -static ConversionCandidates * CreateConversionCandidates(FromExpr *joinTree, - PlannerRestrictionContext * +static ConversionCandidates * CreateConversionCandidates(PlannerRestrictionContext * plannerRestrictionContext, List *rangeTableList, Oid resultRelationId); static void GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes); -static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(FromExpr *joinTree, - ConversionCandidates * +static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(ConversionCandidates * conversionCandidates, PlannerRestrictionContext * plannerRestrictionContext); static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, int rteIdentity); static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList); +static bool FirstIntListContainsSecondIntList(List *firstIntList, List *secondIntList); /* * RecursivelyPlanLocalTableJoins gets a query and the planner @@ -112,15 +116,14 @@ RecursivelyPlanLocalTableJoins(Query *query, resultRelationId = ModifyQueryResultRelationId(query); } ConversionCandidates *conversionCandidates = - CreateConversionCandidates(query->jointree, plannerRestrictionContext, + CreateConversionCandidates(plannerRestrictionContext, rangeTableList, resultRelationId); while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, plannerRestrictionContext)) { - FromExpr *joinTree = query->jointree; RangeTableEntryDetails *rangeTableEntryDetails = - GetNextRTEToConvertToSubquery(joinTree, conversionCandidates, + GetNextRTEToConvertToSubquery(conversionCandidates, plannerRestrictionContext); if (rangeTableEntryDetails == NULL) { @@ -140,11 +143,10 @@ RecursivelyPlanLocalTableJoins(Query *query, /* * GetNextRTEToConvertToSubquery returns the range table entry * which should be converted to a subquery. It considers the local join policy - * and result relation. + * for conversion priorities. */ static RangeTableEntryDetails * -GetNextRTEToConvertToSubquery(FromExpr *joinTree, - ConversionCandidates *conversionCandidates, +GetNextRTEToConvertToSubquery(ConversionCandidates *conversionCandidates, PlannerRestrictionContext *plannerRestrictionContext) { RangeTableEntryDetails *localRTECandidate = NULL; @@ -169,6 +171,11 @@ GetNextRTEToConvertToSubquery(FromExpr *joinTree, } else { + /* + * We want to convert distributed tables only if all the distributed tables + * have a constant filter on a unique index, otherwise we would be redundantly + * converting a distributed table as we will convert all the other local tables. + */ bool allRangeTableEntriesHaveUniqueIndex = AllRangeTableEntriesHaveUniqueIndex( conversionCandidates->distributedTableList); @@ -284,15 +291,22 @@ HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, } List *baseRestrictionList = relationRestriction->relOptInfo->baserestrictinfo; List *restrictClauseList = get_all_actual_clauses(baseRestrictionList); - List *rteEqualityQuals = + if (ContainsFalseClause(restrictClauseList)) + { + /* If there is a WHERE FALSE, we consider it as a constant filter. */ + return true; + } + List *rteEqualityColumnsNos = FetchEqualityAttrNumsForRTE((Node *) restrictClauseList); - List *uniqueIndexAttrNumbers = ExecuteFunctionOnEachTableIndex(rangeTableEntry->relid, + List *uniqueIndexColumnsList = ExecuteFunctionOnEachTableIndex(rangeTableEntry->relid, GetAllUniqueIndexes); - int columnNumber = 0; - foreach_int(columnNumber, uniqueIndexAttrNumbers) + IndexColumns *indexColumns = NULL; + foreach_ptr(indexColumns, uniqueIndexColumnsList) { - if (list_member_int(rteEqualityQuals, columnNumber)) + List *uniqueIndexColumnNos = indexColumns->indexColumnNos; + if (FirstIntListContainsSecondIntList(rteEqualityColumnsNos, + uniqueIndexColumnNos)) { return true; } @@ -301,6 +315,25 @@ HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, } +/* + * FirstIntListContainsSecondIntList returns true if the first int List + * contains every element of the second int List. + */ +static bool +FirstIntListContainsSecondIntList(List *firstIntList, List *secondIntList) +{ + int curInt = 0; + foreach_int(curInt, secondIntList) + { + if (!list_member_int(firstIntList, curInt)) + { + return false; + } + } + return true; +} + + /* * GetAllUniqueIndexes adds the given index's column numbers if it is a * unique index. @@ -308,15 +341,23 @@ HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, * probably return true only if all the columns in the index exist in the filter. */ static void -GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes) +GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexGroups) { if (indexForm->indisunique || indexForm->indisprimary) { + IndexColumns *indexColumns = palloc0(sizeof(IndexColumns)); + List *uniqueIndexes = NIL; for (int i = 0; i < indexForm->indkey.dim1; i++) { - *uniqueIndexes = list_append_unique_int(*uniqueIndexes, - indexForm->indkey.values[i]); + uniqueIndexes = list_append_unique_int(uniqueIndexes, + indexForm->indkey.values[i]); } + if (list_length(uniqueIndexes) == 0) + { + return; + } + indexColumns->indexColumnNos = uniqueIndexes; + *uniqueIndexGroups = lappend(*uniqueIndexGroups, indexColumns); } } @@ -367,8 +408,7 @@ RequiredAttrNumbersForRelation(RangeTblEntry *rangeTableEntry, * be converted to a subquery so that citus planners can work. */ static ConversionCandidates * -CreateConversionCandidates(FromExpr *joinTree, - PlannerRestrictionContext *plannerRestrictionContext, +CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, List *rangeTableList, Oid resultRelationId) { ConversionCandidates *conversionCandidates = diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index ccfff1215..2bf343e1c 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -3665,11 +3665,13 @@ FetchEqualityAttrNumsForRTE(Node *node) return NIL; } + /* * FetchEqualityAttrNumsForList fetches the constant equality numbers * from the given node list. */ -static List *FetchEqualityAttrNumsForList(List *nodeList) +static List * +FetchEqualityAttrNumsForList(List *nodeList) { List *attributeNums = NIL; Node *node = NULL; @@ -3682,7 +3684,7 @@ static List *FetchEqualityAttrNumsForList(List *nodeList) attributeNums = list_concat(attributeNums, fetchedEqualityAttrNums); } - /* + /* * the given list is in the form of AND'ed expressions * hence if we have one equality then it is enough. * E.g: dist.a = 5 AND dist.a > 10 diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index fa7dbea9e..e0f69340a 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1769,6 +1769,7 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) subquery->targetList = lappend(subquery->targetList, targetEntry); } } + /* * If tupleDesc is NULL we have 2 different cases: * @@ -1818,6 +1819,7 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) columnType = list_nth_oid(rangeTblFunction->funccoltypes, targetColumnIndex); } + /* use the types in the function definition otherwise */ else { diff --git a/src/test/regress/expected/citus_local_dist_joins.out b/src/test/regress/expected/citus_local_dist_joins.out index dbbf37bfe..950cb7464 100644 --- a/src/test/regress/expected/citus_local_dist_joins.out +++ b/src/test/regress/expected/citus_local_dist_joins.out @@ -1,12 +1,7 @@ CREATE SCHEMA citus_local_dist_joins; SET search_path TO citus_local_dist_joins; SET client_min_messages to ERROR; -SELECT master_add_node('localhost', :master_port, groupId => 0); - master_add_node ---------------------------------------------------------------------- - 5 -(1 row) - +SELECT master_add_node('localhost', :master_port, groupId => 0) AS coordinator_nodeid \gset CREATE TABLE citus_local(key int, value text); SELECT create_citus_local_table('citus_local'); create_citus_local_table diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 6ccc25bf9..2cf429b7f 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -756,14 +756,14 @@ 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_1509000 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; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.reference_table_1509002 reference_table -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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)) reference_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table_cte.a) +set citus.log_local_commands to on; --------------------------------------------------------------------- ----- VIEW QUERIES ----- --------------------------------------------------------------------- diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 647c1609e..3ccd32346 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -397,11 +397,82 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) --- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. +-- We will plan postgres table as the index is on key,value not just key SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_composite.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE (distributed_table_composite.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10 OR distributed_table_composite.key = 20; +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) + count +--------------------------------------------------------------------- + 2 +(1 row) + +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key > 10 AND distributed_table_composite.value = 'text'; +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10 AND distributed_table_composite.value = 'text'; +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 10) AND (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 10) AND (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 OR distributed_table_composite.key = 20) + AND (distributed_table_composite.value = 'text' OR distributed_table_composite.value = 'text'); +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) AND ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 OR distributed_table_composite.value = 'text') + AND (distributed_table_composite.value = 'text' OR distributed_table_composite.key = 30); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) OR (value OPERATOR(pg_catalog.=) 'text'::text)) AND ((value OPERATOR(pg_catalog.=) 'text'::text) OR (key OPERATOR(pg_catalog.=) 30))) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) OR (value OPERATOR(pg_catalog.=) 'text'::text)) AND ((value OPERATOR(pg_catalog.=) 'text'::text) OR (key OPERATOR(pg_catalog.=) 30))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) AND ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 30))) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 AND distributed_table_composite.value = 'text') + OR (distributed_table_composite.value = 'text' AND distributed_table_composite.key = 30); +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) OR ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) AND (distributed_table_composite.key OPERATOR(pg_catalog.=) 30))) + count +--------------------------------------------------------------------- + 0 +(1 row) + +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 AND distributed_table_composite.key = 20) + OR (distributed_table_composite.value = 'text' AND distributed_table_composite.value = 'text'); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 20)) OR ((value OPERATOR(pg_catalog.=) 'text'::text) AND (value OPERATOR(pg_catalog.=) 'text'::text))) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 20)) OR ((value OPERATOR(pg_catalog.=) 'text'::text) AND (value OPERATOR(pg_catalog.=) 'text'::text))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) OR ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text))) count --------------------------------------------------------------------- 1 @@ -764,8 +835,6 @@ ERROR: relation postgres_table is not distributed UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) l WHERE (l.key OPERATOR(pg_catalog.=) 10) --- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? --- though then the planner could give an error SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false @@ -775,6 +844,244 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +SELECT count(*) FROM (SELECT * FROM distributed_table JOIN postgres_table USING(key) WHERE false) foo JOIN local_partitioned_table USING(key); +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false +DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE false +DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE false +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, postgres_table.value, postgres_table.value_2 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)) postgres_table USING (key)) WHERE false) foo(key, value, value_2, value_1, value_2_1) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +WITH dist_cte AS (SELECT * FROM distributed_table_pkey WHERE key = 5) +SELECT COUNT(*) FROM dist_cte JOIN postgres_table USING(key) WHERE dist_cte.key = 5; +DEBUG: CTE dist_cte is going to be inlined via distributed planning +DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2 FROM local_table_join.distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5)) dist_cte 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)) postgres_table USING (key)) WHERE (dist_cte.key OPERATOR(pg_catalog.=) 5) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT COUNT(*) FROM postgres_table JOIN distributed_table_pkey USING(key) + WHERE (distributed_table_pkey.key IN (SELECT COUNT(*) AS count FROM postgres_table JOIN distributed_table USING(key)) ); +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) +DEBUG: Wrapping 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 +DEBUG: generating subplan XXX_3 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint))) + count +--------------------------------------------------------------------- + 1 +(1 row) + +-- PREPARED statements +PREPARE local_dist_table_join_select(int) AS SELECT COUNT(*) FROM distributed_table_pkey JOIN postgres_table USING(key) WHERE distributed_table_pkey.key = $1; +EXECUTE local_dist_table_join_select(10); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE local_dist_table_join_select(10); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE local_dist_table_join_select(10); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE local_dist_table_join_select(10); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE local_dist_table_join_select(10); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +EXECUTE local_dist_table_join_select(10); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +PREPARE local_dist_table_join_update(int) AS UPDATE postgres_table SET key = 5 FROM distributed_table_pkey WHERE distributed_table_pkey.key = $1; +EXECUTE local_dist_table_join_update(20); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +EXECUTE local_dist_table_join_update(20); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +EXECUTE local_dist_table_join_update(20); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +EXECUTE local_dist_table_join_update(20); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +EXECUTE local_dist_table_join_update(20); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +EXECUTE local_dist_table_join_update(20); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +PREPARE local_dist_table_join_subquery(int) AS SELECT COUNT(*) FROM postgres_table JOIN (SELECT * FROM distributed_table_pkey JOIN local_partitioned_table USING(key) WHERE distributed_table_pkey.key = $1) foo USING(key); +EXECUTE local_dist_table_join_subquery(5); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +EXECUTE local_dist_table_join_subquery(5); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +EXECUTE local_dist_table_join_subquery(5); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +EXECUTE local_dist_table_join_subquery(5); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +EXECUTE local_dist_table_join_subquery(5); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +EXECUTE local_dist_table_join_subquery(5); +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +PREPARE local_dist_table_join_filters(int) AS SELECT COUNT(*) FROM local_partitioned_table JOIN distributed_table_composite USING(key) + WHERE( + distributed_table_composite.key = $1 OR + distributed_table_composite.key = 20 OR + (distributed_table_composite.key = 10 AND distributed_table_composite.key > 0) OR + distributed_table_composite.value = 'text' + ); +EXECUTE local_dist_table_join_filters(20); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 2 +(1 row) + +EXECUTE local_dist_table_join_filters(20); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 2 +(1 row) + +EXECUTE local_dist_table_join_filters(20); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 2 +(1 row) + +EXECUTE local_dist_table_join_filters(20); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 2 +(1 row) + +EXECUTE local_dist_table_join_filters(20); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 2 +(1 row) + +EXECUTE local_dist_table_join_filters(20); +DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) + count +--------------------------------------------------------------------- + 2 +(1 row) + RESET client_min_messages; \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; diff --git a/src/test/regress/sql/citus_local_dist_joins.sql b/src/test/regress/sql/citus_local_dist_joins.sql index d9806ddd0..5b6950c48 100644 --- a/src/test/regress/sql/citus_local_dist_joins.sql +++ b/src/test/regress/sql/citus_local_dist_joins.sql @@ -2,7 +2,7 @@ CREATE SCHEMA citus_local_dist_joins; SET search_path TO citus_local_dist_joins; SET client_min_messages to ERROR; -SELECT master_add_node('localhost', :master_port, groupId => 0); +SELECT master_add_node('localhost', :master_port, groupId => 0) AS coordinator_nodeid \gset CREATE TABLE citus_local(key int, value text); diff --git a/src/test/regress/sql/citus_local_tables_queries.sql b/src/test/regress/sql/citus_local_tables_queries.sql index 564b7c6c8..f98ead754 100644 --- a/src/test/regress/sql/citus_local_tables_queries.sql +++ b/src/test/regress/sql/citus_local_tables_queries.sql @@ -413,13 +413,14 @@ SET b = 6 FROM distributed_table_cte WHERE citus_local_table.a = 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 ----- ------------------------ diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index dad8459f1..40dd2aff6 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -119,8 +119,23 @@ SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOI SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key::int = d1.key::int AND d1.key < postgres_table.key) WHERE d1.key::int = 1 AND false; --- TODO:: We should probably recursively plan postgres table here because primary key is on key,value not key. +-- We will plan postgres table as the index is on key,value not just key SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10 OR distributed_table_composite.key = 20; +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key > 10 AND distributed_table_composite.value = 'text'; +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10 AND distributed_table_composite.value = 'text'; +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 OR distributed_table_composite.key = 20) + AND (distributed_table_composite.value = 'text' OR distributed_table_composite.value = 'text'); +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 OR distributed_table_composite.value = 'text') + AND (distributed_table_composite.value = 'text' OR distributed_table_composite.key = 30); +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 AND distributed_table_composite.value = 'text') + OR (distributed_table_composite.value = 'text' AND distributed_table_composite.key = 30); +SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) + WHERE (distributed_table_composite.key > 10 AND distributed_table_composite.key = 20) + OR (distributed_table_composite.value = 'text' AND distributed_table_composite.value = 'text'); -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); @@ -207,10 +222,59 @@ UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; --- TODO:: we should probably not wrap postgres_table here as there is a WHERE FALSE? --- though then the planner could give an error SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; +SELECT count(*) FROM (SELECT * FROM distributed_table JOIN postgres_table USING(key) WHERE false) foo JOIN local_partitioned_table USING(key); + +WITH dist_cte AS (SELECT * FROM distributed_table_pkey WHERE key = 5) +SELECT COUNT(*) FROM dist_cte JOIN postgres_table USING(key) WHERE dist_cte.key = 5; + +SELECT COUNT(*) FROM postgres_table JOIN distributed_table_pkey USING(key) + WHERE (distributed_table_pkey.key IN (SELECT COUNT(*) AS count FROM postgres_table JOIN distributed_table USING(key)) ); + +-- PREPARED statements +PREPARE local_dist_table_join_select(int) AS SELECT COUNT(*) FROM distributed_table_pkey JOIN postgres_table USING(key) WHERE distributed_table_pkey.key = $1; + +EXECUTE local_dist_table_join_select(10); +EXECUTE local_dist_table_join_select(10); +EXECUTE local_dist_table_join_select(10); +EXECUTE local_dist_table_join_select(10); +EXECUTE local_dist_table_join_select(10); +EXECUTE local_dist_table_join_select(10); + +PREPARE local_dist_table_join_update(int) AS UPDATE postgres_table SET key = 5 FROM distributed_table_pkey WHERE distributed_table_pkey.key = $1; + +EXECUTE local_dist_table_join_update(20); +EXECUTE local_dist_table_join_update(20); +EXECUTE local_dist_table_join_update(20); +EXECUTE local_dist_table_join_update(20); +EXECUTE local_dist_table_join_update(20); +EXECUTE local_dist_table_join_update(20); + +PREPARE local_dist_table_join_subquery(int) AS SELECT COUNT(*) FROM postgres_table JOIN (SELECT * FROM distributed_table_pkey JOIN local_partitioned_table USING(key) WHERE distributed_table_pkey.key = $1) foo USING(key); + +EXECUTE local_dist_table_join_subquery(5); +EXECUTE local_dist_table_join_subquery(5); +EXECUTE local_dist_table_join_subquery(5); +EXECUTE local_dist_table_join_subquery(5); +EXECUTE local_dist_table_join_subquery(5); +EXECUTE local_dist_table_join_subquery(5); + +PREPARE local_dist_table_join_filters(int) AS SELECT COUNT(*) FROM local_partitioned_table JOIN distributed_table_composite USING(key) + WHERE( + distributed_table_composite.key = $1 OR + distributed_table_composite.key = 20 OR + (distributed_table_composite.key = 10 AND distributed_table_composite.key > 0) OR + distributed_table_composite.value = 'text' + ); + +EXECUTE local_dist_table_join_filters(20); +EXECUTE local_dist_table_join_filters(20); +EXECUTE local_dist_table_join_filters(20); +EXECUTE local_dist_table_join_filters(20); +EXECUTE local_dist_table_join_filters(20); +EXECUTE local_dist_table_join_filters(20); + RESET client_min_messages; \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; From 3aed6c3ad07445cae772e45e6bfee00da84bf44e Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Wed, 9 Dec 2020 13:56:30 +0300 Subject: [PATCH 29/37] Rename containsOnlyLocalTable as isLocalTableModification Update error message in Modify View --- .../distributed/executor/citus_custom_scan.c | 6 ++-- .../planner/multi_physical_planner.c | 8 ++--- .../planner/multi_router_planner.c | 33 ++++++++++--------- .../distributed/utils/citus_copyfuncs.c | 2 +- .../distributed/utils/citus_outfuncs.c | 2 +- .../distributed/multi_physical_planner.h | 6 ++-- .../distributed/multi_router_planner.h | 2 +- .../regress/expected/local_table_join.out | 7 +++- src/test/regress/expected/multi_view.out | 12 +++---- src/test/regress/sql/local_table_join.sql | 8 +++-- 10 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/backend/distributed/executor/citus_custom_scan.c b/src/backend/distributed/executor/citus_custom_scan.c index eb59b87a3..de809848c 100644 --- a/src/backend/distributed/executor/citus_custom_scan.c +++ b/src/backend/distributed/executor/citus_custom_scan.c @@ -370,7 +370,7 @@ CitusBeginModifyScan(CustomScanState *node, EState *estate, int eflags) /* We skip shard related things if the job contains only local tables */ - if (!OnlyLocalTableJob(workerJob)) + if (!ModifyLocalTableJob(workerJob)) { /* * Now that we know the shard ID(s) we can acquire the necessary shard metadata @@ -544,12 +544,12 @@ RegenerateTaskForFasthPathQuery(Job *workerJob) shardId = GetAnchorShardId(shardIntervalList); } - bool containsOnlyLocalTable = false; + bool isLocalTableModification = false; GenerateSingleShardRouterTaskList(workerJob, relationShardList, placementList, shardId, - containsOnlyLocalTable); + isLocalTableModification); } diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 2bf343e1c..d838fc40a 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -272,11 +272,11 @@ CreatePhysicalDistributedPlan(MultiTreeRoot *multiTree, /* - * OnlyLocalTableJob true if the given task contains - * only postgres tables + * ModifyLocalTableJob returns true if the given task contains + * a modification of local table. */ bool -OnlyLocalTableJob(Job *job) +ModifyLocalTableJob(Job *job) { if (job == NULL) { @@ -288,7 +288,7 @@ OnlyLocalTableJob(Job *job) return false; } Task *singleTask = (Task *) linitial(taskList); - return singleTask->containsOnlyLocalTable; + return singleTask->isLocalTableModification; } diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 000061d9c..cc39b88cd 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -171,7 +171,7 @@ static int CompareInsertValuesByShardId(const void *leftElement, static List * SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, List *placementList, uint64 shardId, bool parametersInQueryResolved, - bool containsOnlyLocalTable); + bool isLocalTableModification); static bool RowLocksOnRelations(Node *node, List **rtiLockList); static void ReorderTaskPlacementsByTaskAssignmentPolicy(Job *job, TaskAssignmentPolicyType @@ -321,8 +321,6 @@ IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionCon } } - /* TODO:: we might not need this copy*/ - copyQuery = copyObject(query); RouterJob(copyQuery, plannerRestrictionContext, &deferredErrorMessage); return deferredErrorMessage == NULL; } @@ -1044,7 +1042,8 @@ DeferErrorIfModifyView(Query *queryTree) firstRangeTableElement->inFromCl == false) { return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, - "cannot modify views over distributed tables", NULL, + "cannot modify views when the query contains citus tables", + NULL, NULL); } } @@ -1718,7 +1717,7 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon /* router planner should create task even if it doesn't hit a shard at all */ bool replacePrunedQueryWithDummy = true; - bool containsOnlyLocalTable = false; + bool isLocalTableModification = false; /* check if this query requires coordinator evaluation */ bool requiresCoordinatorEvaluation = RequiresCoordinatorEvaluation(originalQuery); @@ -1748,7 +1747,7 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon replacePrunedQueryWithDummy, &isMultiShardModifyQuery, &partitionKeyValue, - &containsOnlyLocalTable); + &isLocalTableModification); } if (*planningError) @@ -1794,7 +1793,8 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon else { GenerateSingleShardRouterTaskList(job, relationShardList, - placementList, shardId, containsOnlyLocalTable); + placementList, shardId, + isLocalTableModification); } job->requiresCoordinatorEvaluation = requiresCoordinatorEvaluation; @@ -1811,7 +1811,7 @@ RouterJob(Query *originalQuery, PlannerRestrictionContext *plannerRestrictionCon void GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, List *placementList, uint64 shardId, bool - containsOnlyLocalTable) + isLocalTableModification) { Query *originalQuery = job->jobQuery; @@ -1821,7 +1821,7 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, relationShardList, placementList, shardId, job->parametersInJobQueryResolved, - containsOnlyLocalTable); + isLocalTableModification); /* * Queries to reference tables, or distributed tables with multiple replica's have @@ -1838,7 +1838,7 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, placementList); } } - else if (shardId == INVALID_SHARD_ID && !containsOnlyLocalTable) + else if (shardId == INVALID_SHARD_ID && !isLocalTableModification) { /* modification that prunes to 0 shards */ job->taskList = NIL; @@ -1849,7 +1849,7 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, relationShardList, placementList, shardId, job->parametersInJobQueryResolved, - containsOnlyLocalTable); + isLocalTableModification); } } @@ -1943,7 +1943,7 @@ static List * SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, List *placementList, uint64 shardId, bool parametersInQueryResolved, - bool containsOnlyLocalTable) + bool isLocalTableModification) { TaskType taskType = READ_TASK; char replicationModel = 0; @@ -2002,7 +2002,7 @@ SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList, } Task *task = CreateTask(taskType); - task->containsOnlyLocalTable = containsOnlyLocalTable; + task->isLocalTableModification = isLocalTableModification; List *relationRowLockList = NIL; RowLocksOnRelations((Node *) query, &relationRowLockList); @@ -2144,7 +2144,7 @@ PlanRouterQuery(Query *originalQuery, List **prunedShardIntervalListList, bool replacePrunedQueryWithDummy, bool *multiShardModifyQuery, Const **partitionValueConst, - bool *containsOnlyLocalTable) + bool *isLocalTableModification) { bool isMultiShardQuery = false; DeferredErrorMessage *planningError = NULL; @@ -2262,7 +2262,10 @@ PlanRouterQuery(Query *originalQuery, RTEListProperties *rteProperties = GetRTEListPropertiesForQuery(originalQuery); if (shardId == INVALID_SHARD_ID && ContainsOnlyLocalTables(rteProperties)) { - *containsOnlyLocalTable = true; + if (commandType != CMD_SELECT) + { + *isLocalTableModification = true; + } } bool hasPostgresLocalRelation = rteProperties->hasPostgresLocalTable || rteProperties->hasMaterializedView; diff --git a/src/backend/distributed/utils/citus_copyfuncs.c b/src/backend/distributed/utils/citus_copyfuncs.c index 763f5e910..8e725a7d0 100644 --- a/src/backend/distributed/utils/citus_copyfuncs.c +++ b/src/backend/distributed/utils/citus_copyfuncs.c @@ -327,7 +327,7 @@ CopyNodeTask(COPYFUNC_ARGS) COPY_SCALAR_FIELD(fetchedExplainAnalyzePlacementIndex); COPY_STRING_FIELD(fetchedExplainAnalyzePlan); COPY_SCALAR_FIELD(fetchedExplainAnalyzeExecutionDuration); - COPY_SCALAR_FIELD(containsOnlyLocalTable); + COPY_SCALAR_FIELD(isLocalTableModification); } diff --git a/src/backend/distributed/utils/citus_outfuncs.c b/src/backend/distributed/utils/citus_outfuncs.c index e359fe7c3..abf18aa27 100644 --- a/src/backend/distributed/utils/citus_outfuncs.c +++ b/src/backend/distributed/utils/citus_outfuncs.c @@ -540,7 +540,7 @@ OutTask(OUTFUNC_ARGS) WRITE_INT_FIELD(fetchedExplainAnalyzePlacementIndex); WRITE_STRING_FIELD(fetchedExplainAnalyzePlan); WRITE_FLOAT_FIELD(fetchedExplainAnalyzeExecutionDuration, "%.2f"); - WRITE_BOOL_FIELD(containsOnlyLocalTable); + WRITE_BOOL_FIELD(isLocalTableModification); } diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index 125e7406f..6dd9153b8 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -330,9 +330,9 @@ typedef struct Task double fetchedExplainAnalyzeExecutionDuration; /* - * containsOnlyLocalTable is true if the task contains only postgres table/MV. + * isLocalTableModification is true if the task is on modifying a local table. */ - bool containsOnlyLocalTable; + bool isLocalTableModification; } Task; @@ -583,7 +583,7 @@ extern List * QueryPushdownSqlTaskList(Query *query, uint64 jobId, bool modifyRequiresCoordinatorEvaluation, DeferredErrorMessage **planningError); -extern bool OnlyLocalTableJob(Job *job); +extern bool ModifyLocalTableJob(Job *job); /* function declarations for managing jobs */ extern uint64 UniqueJobId(void); diff --git a/src/include/distributed/multi_router_planner.h b/src/include/distributed/multi_router_planner.h index d16ad2d3e..16e4576b3 100644 --- a/src/include/distributed/multi_router_planner.h +++ b/src/include/distributed/multi_router_planner.h @@ -87,7 +87,7 @@ extern void GenerateSingleShardRouterTaskList(Job *job, List *relationShardList, List *placementList, uint64 shardId, - bool containsOnlyLocalTable); + bool isLocalTableModification); extern bool IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionContext); diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 3ccd32346..3b2072709 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -813,6 +813,11 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 1 (1 row) +CREATE view loc_view AS SELECT * FROM postgres_table WHERE key > 0; +UPDATE loc_view SET key = (SELECT COUNT(*) FROM distributed_table); +DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM local_table_join.distributed_table +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) FROM local_table_join.postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.>) 0) +ERROR: cannot modify views when the query contains citus tables SELECT count(*) FROM (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 @@ -1085,4 +1090,4 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c RESET client_min_messages; \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 14 other objects +NOTICE: drop cascades to 15 other objects diff --git a/src/test/regress/expected/multi_view.out b/src/test/regress/expected/multi_view.out index a7ab6a71d..926bc5fcf 100644 --- a/src/test/regress/expected/multi_view.out +++ b/src/test/regress/expected/multi_view.out @@ -920,11 +920,11 @@ CREATE VIEW small_view AS SELECT * from small where id < 100; \copy large FROM STDIN DELIMITER ',' -- running modify statements "on" views is still not supported, hence below two statements will fail UPDATE small_view SET id = 1; -ERROR: cannot modify views over distributed tables +ERROR: cannot modify views when the query contains citus tables DELETE FROM small_view; -ERROR: cannot modify views over distributed tables +ERROR: cannot modify views when the query contains citus tables INSERT INTO small_view VALUES(8, 5) ON CONFLICT(tenant_id) DO UPDATE SET tenant_id=99; -ERROR: cannot modify views over distributed tables +ERROR: cannot modify views when the query contains citus tables -- using views in modify statements' FROM / WHERE clauses is still valid UPDATE large SET id=20 FROM small_view WHERE small_view.id=large.id; SELECT * FROM large order by 1, 2; @@ -1054,7 +1054,7 @@ SELECT * FROM large ORDER BY 1, 2; -- INSERT INTO views is still not supported INSERT INTO small_view VALUES(3, 3); -ERROR: cannot modify views over distributed tables +ERROR: cannot modify views when the query contains citus tables DROP TABLE large; DROP TABLE small CASCADE; NOTICE: drop cascades to view small_view @@ -1081,9 +1081,9 @@ CREATE VIEW small_view AS SELECT * from small where id < 100; \copy large_partitioned FROM STDIN DELIMITER ',' -- running modify statements "on" views is still not supported, hence below two statements will fail UPDATE small_view SET id = 1; -ERROR: cannot modify views over distributed tables +ERROR: cannot modify views when the query contains citus tables DELETE FROM small_view; -ERROR: cannot modify views over distributed tables +ERROR: cannot modify views when the query contains citus tables UPDATE large_partitioned SET id=27 FROM small_view WHERE small_view.tenant_id=large_partitioned.tenant_id; SELECT * FROM large_partitioned ORDER BY 1, 2; id | tenant_id diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 40dd2aff6..475fca5d1 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -209,6 +209,8 @@ FROM WHERE d1.key = 1; +CREATE view loc_view AS SELECT * FROM postgres_table WHERE key > 0; +UPDATE loc_view SET key = (SELECT COUNT(*) FROM distributed_table); SELECT count(*) FROM @@ -260,10 +262,10 @@ EXECUTE local_dist_table_join_subquery(5); EXECUTE local_dist_table_join_subquery(5); EXECUTE local_dist_table_join_subquery(5); -PREPARE local_dist_table_join_filters(int) AS SELECT COUNT(*) FROM local_partitioned_table JOIN distributed_table_composite USING(key) +PREPARE local_dist_table_join_filters(int) AS SELECT COUNT(*) FROM local_partitioned_table JOIN distributed_table_composite USING(key) WHERE( - distributed_table_composite.key = $1 OR - distributed_table_composite.key = 20 OR + distributed_table_composite.key = $1 OR + distributed_table_composite.key = 20 OR (distributed_table_composite.key = 10 AND distributed_table_composite.key > 0) OR distributed_table_composite.value = 'text' ); From 1d82972ff491adb5e7d346b4166fed721ab22ce8 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Thu, 10 Dec 2020 13:55:59 +0300 Subject: [PATCH 30/37] Increase the performance with a trick Instead of sending NULL's over a network, we now convert the subqueries in the form of: SELECT t.a, NULL, NULL FROM (SELECT a FROM table)t; And we recursively plan the inner part so that we don't send the NULL's over network. We still need the NULLs in the outer subquery because we currently don't have an easy way of updating all the necessary places in the query. Add some documentation for how the conversion is done --- .../planner/local_distributed_join_planner.c | 71 ++ .../planner/query_colocation_checker.c | 34 +- .../distributed/planner/recursive_planning.c | 141 +++- src/backend/distributed/shared_library_init.c | 8 +- .../distributed/query_colocation_checker.h | 3 +- .../expected/citus_local_dist_joins.out | 116 +-- .../expected/citus_local_tables_queries.out | 36 +- .../expected/coordinator_shouldhaveshards.out | 18 +- src/test/regress/expected/dml_recursive.out | 6 +- .../expected/local_dist_join_mixed.out | 718 +++++++++--------- .../local_dist_join_modifications.out | 122 +-- .../regress/expected/local_table_join.out | 662 ++++++++-------- .../regress/expected/mixed_relkind_tests.out | 46 +- ...relation_planning_restirction_pushdown.out | 172 ++--- 14 files changed, 1187 insertions(+), 966 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 1d8dfd9f2..17c35150b 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -1,3 +1,74 @@ +/*------------------------------------------------------------------------- + * + * local_distributed_join_planner.c + * + * This file contains functions to convert convert local-distributed + * tables to subqueries so that they can be planned by the router planner. + * + * + * The current algorithm checks if there is any table in the `jointree` that + * should be converted, if so it creates conversion candidates. + * With conversion candidates, it will convert either a distributed table or a local table to a + * subquery until it is plannable by router planner. It will choose a distributed table if we + * expect it to return few rows, such as a constant equality filter on a unique column. + * + * ```sql + * -- assuming dist.a is a unique column, this will convert distributed table + * SELECT * FROM dist join local ON(a) where dist.a = 5; + * ``` + * + * If the uniqueness is defined on multiple columns such as `dist.a, dist.b` + * then distributed table will only be chosen if there is a constant equality in all of the columns such as: + * + * ```sql + * SELECT * FROM dist join local ON(a) where dist.a = 5 AND dist.b =10; -- this will choose distributed table + * SELECT * FROM dist join local ON(a) where dist.a = 5 AND dist.b >10; -- this won't since no equality on dist.b + * SELECT * FROM dist join local ON(a) where dist.a = 5; -- this won't since no equality on dist.b + * ``` + * + * The algorithm will also not favor distributed tables if there exists a + * distributed table which is expected to return many rows, because in that + * case we will already plan local tables hence there is no point in converting some distributed tables. + * + * ```sql + * -- here only the local table will be chosen + * SELECT * FROM dist_without_unique JOIN dist_with_unique USING(a) join local USING (a); + * ``` + * + * this also makes the algorithm consistent. + * + * The algorithm can understand `OR` and `AND` expressions in the filters. + * + * There is a GUC called `local_table_join_policy` consisting of 4 modes: + * `none`: don't do any conversion + * `prefer-local`: prefer converting local tables if there is + * `prefer-distributed`: prefer converting distributed tables if there is + * `auto`: use the above mechanism to decide (constant equality on unique column) + * + * `auto` mode is the default. + * + * While converting to a subquery, we use a trick to avoid unnecessary network bandwidth, + * if there are columns that are not required in a table that will be converted to a subquery, We do: + * + * ```sql + * SELECT t.a, NULL, NULL (SELECT a FROM table) t + * ``` + * + * instead of + * + * ```sql + * SELECT a, NULL, NULL FROM table + * ``` + * + * There are NULLs in the query because we currently don't have an easy way to update the Vars + * that reference the non-required ones and we don't want to break the postgres query. + * + * + * Copyright (c) Citus Data, Inc. + * + *------------------------------------------------------------------------- + */ + #include "postgres.h" #include "distributed/pg_version_constants.h" diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index 62905396d..dd010f652 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -37,6 +37,7 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "parser/parsetree.h" +#include "distributed/listutils.h" #include "parser/parse_relation.h" #include "optimizer/planner.h" #include "optimizer/prep.h" @@ -76,7 +77,9 @@ CreateColocatedJoinChecker(Query *subquery, PlannerRestrictionContext *restricti * functions (i.e., FilterPlannerRestrictionForQuery()) rely on queries * not relations. */ - anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry, NIL); + List *allTargetList = NIL; + anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry, NIL, + &allTargetList); } else if (anchorRangeTblEntry->rtekind == RTE_SUBQUERY) { @@ -260,7 +263,8 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker) * designed for generating a stub query. */ Query * -WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes) +WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes, + List **allTargetList) { Query *subquery = makeNode(Query); RangeTblRef *newRangeTableRef = makeNode(RangeTblRef); @@ -279,7 +283,10 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes Relation relation = relation_open(rteRelation->relid, AccessShareLock); int numberOfAttributes = RelationGetNumberOfAttributes(relation); + bool shouldAssignDummyNullColumn = list_length(requiredAttributes) == 0; + bool assignedDummyNullColumn = false; int attributeNumber = 1; + int resultNo = 1; for (; attributeNumber <= numberOfAttributes; attributeNumber++) { Form_pg_attribute attributeTuple = @@ -291,15 +298,36 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes makeTargetEntry((Expr *) targetColumn, attributeNumber, strdup(attributeTuple->attname.data), false); + if (shouldAssignDummyNullColumn && !assignedDummyNullColumn) + { + subquery->targetList = lappend(subquery->targetList, targetEntry); + assignedDummyNullColumn = true; + } + if (!list_member_int(requiredAttributes, attributeNumber)) { + /* + * We add a null target entry because we don't have an easy + * way of changing all the references to this column and + * we don't want to break postgres query. + */ targetEntry->expr = (Expr *) makeNullConst(attributeTuple->atttypid, attributeTuple->atttypmod, attributeTuple->attcollation); + *allTargetList = lappend(*allTargetList, targetEntry); } + else + { + TargetEntry *copyTargetEntry = copyObject(targetEntry); + *allTargetList = lappend(*allTargetList, copyTargetEntry); - subquery->targetList = lappend(subquery->targetList, targetEntry); + /* In the subquery with only required attribute numbers, the result no + * corresponds to the ordinal index of it in targetList. + */ + targetEntry->resno = resultNo++; + subquery->targetList = lappend(subquery->targetList, targetEntry); + } } relation_close(relation, NoLock); diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index e0f69340a..d6b87a39d 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -196,6 +196,11 @@ static void UpdateVarNosInNode(Query *query, Index newVarNo); static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, List **joinRangeTableEntries); +static Query * CreateOuterSubquery(RangeTblEntry *rangeTableEntry, + List *allTargetList, List *requiredAttrNumbers); +static void MakeVarAttNosSequential(List *targetList); +static List * GenerateRequiredColNamesFromTargetList(List *targetList); +static char * GetRelationNameAndAliasName(RangeTblEntry *rangeTablentry); /* * GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs. @@ -1445,14 +1450,21 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) * ReplaceRTERelationWithRteSubquery replaces the input rte relation target entry * with a subquery. The function also pushes down the filters to the subquery. * - * It then recursively plans the subquery. + * It then recursively plans the subquery. This subquery is wrapped with another subquery + * as a trick to reduce network cost, because we currently don't have an easy way to + * skip generating NULL's for non-required columns, and if we create (SELECT a, NULL, NULL FROM table) + * then this will be sent over network and NULL's also occupy some space. Instead of this we generate: + * (SELECT t.a, NULL, NULL FROM (SELECT a FROM table) t). The inner subquery will be recursively planned + * but the outer part will not be yet it will still have the NULL columns so that the query is correct. */ void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, RecursivePlanningContext *context) { - Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); + List *allTargetList = NIL; + Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers, + &allTargetList); List *restrictionList = GetRestrictInfoListForRelation(rangeTableEntry, context->plannerRestrictionContext); @@ -1474,24 +1486,127 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, if (IsLoggableLevel(DEBUG1)) { - StringInfo subqueryString = makeStringInfo(); - - pg_get_query_def(subquery, - subqueryString); - - ereport(DEBUG1, (errmsg("Wrapping relation \"%s\" to a subquery: %s ", - get_rel_name(rangeTableEntry->relid), - ApplyLogRedaction(subqueryString->data)))); + char *relationAndAliasName = GetRelationNameAndAliasName(rangeTableEntry); + ereport(DEBUG1, (errmsg("Wrapping relation %s to a subquery", + relationAndAliasName))); } /* as we created the subquery, now forcefully recursively plan it */ - bool recursivellyPlanned = RecursivelyPlanSubquery(rangeTableEntry->subquery, - context); - if (!recursivellyPlanned) + bool recursivelyPlanned = RecursivelyPlanSubquery(subquery, context); + if (!recursivelyPlanned) { ereport(ERROR, (errmsg( "unexpected state: query should have been recursively planned"))); } + + Query *outerSubquery = CreateOuterSubquery(rangeTableEntry, allTargetList, + requiredAttrNumbers); + rangeTableEntry->subquery = outerSubquery; +} + + +/* + * GetRelationNameAndAliasName returns the relname + alias name if + * alias name exists otherwise only the relname is returned. + */ +static char * +GetRelationNameAndAliasName(RangeTblEntry *rangeTableEntry) +{ + StringInfo str = makeStringInfo(); + appendStringInfo(str, "\"%s\"", get_rel_name(rangeTableEntry->relid)); + + char *aliasName = NULL; + if (rangeTableEntry->alias) + { + aliasName = rangeTableEntry->alias->aliasname; + } + + if (aliasName) + { + appendStringInfo(str, " \"%s\"", aliasName); + } + return str->data; +} + + +/* + * CreateOuterSubquery creates outer subquery which contains + * the given range table entry in its rtable. + */ +static Query * +CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *allTargetList, + List *requiredAttrNumbers) +{ + MakeVarAttNosSequential(allTargetList); + List *innerSubqueryColNames = GenerateRequiredColNamesFromTargetList(allTargetList); + + Query *outerSubquery = makeNode(Query); + outerSubquery->commandType = CMD_SELECT; + + /* we copy the input rteRelation to preserve the rteIdentity */ + RangeTblEntry *innerSubqueryRTE = copyObject(rangeTableEntry); + + innerSubqueryRTE->eref->colnames = innerSubqueryColNames; + outerSubquery->rtable = list_make1(innerSubqueryRTE); + + /* set the FROM expression to the subquery */ + RangeTblRef *newRangeTableRef = makeNode(RangeTblRef); + newRangeTableRef->rtindex = 1; + outerSubquery->jointree = makeFromExpr(list_make1(newRangeTableRef), NULL); + + outerSubquery->targetList = allTargetList; + return outerSubquery; +} + + +/* + * MakeVarAttNosSequential changes the attribute numbers of the given targetList + * to sequential numbers, [1, 2, 3] ... + */ +static void +MakeVarAttNosSequential(List *targetList) +{ + TargetEntry *entry = NULL; + int attrNo = 1; + foreach_ptr(entry, targetList) + { + if (IsA(entry->expr, Var)) + { + Var *var = (Var *) entry->expr; + + /* + * the inner subquery is an intermediate result hence + * the attribute no's should be in ordinal order. [1, 2, 3...] + */ + var->varattno = attrNo++; + } + } +} + + +/* + * GenerateRequiredColNamesFromTargetList generates the required colnames + * from the given target list. + */ +static List * +GenerateRequiredColNamesFromTargetList(List *targetList) +{ + TargetEntry *entry = NULL; + List *innerSubqueryColNames = NIL; + foreach_ptr(entry, targetList) + { + if (IsA(entry->expr, Var)) + { + /* + * column names of the inner subquery should only contain the + * required columns, as in if we choose 'b' from ('a','b') colnames + * should be 'a' not ('a','b') + */ + innerSubqueryColNames = lappend(innerSubqueryColNames, makeString( + entry->resname)); + } + } + return innerSubqueryColNames; } diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 15a2ca416..d54548b4c 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -725,7 +725,13 @@ RegisterCitusConfigVariables(void) "citus.local_table_join_policy", gettext_noop("defines the behaviour when a distributed table " "is joined with a local table"), - gettext_noop("TODO: fill"), + gettext_noop( + "There are 4 values available. The default, 'auto' will recursively plan" + "distributed tables if there is a constant filter on a unique index." + "'prefer-local' will choose local tables if possible." + "'prefer-distributed' will choose distributed tables if possible" + "'never' will basically skip local table joins." + ), &LocalTableJoinPolicy, LOCAL_JOIN_POLICY_AUTO, local_table_join_policies, diff --git a/src/include/distributed/query_colocation_checker.h b/src/include/distributed/query_colocation_checker.h index fc63522b2..4a9f4fa87 100644 --- a/src/include/distributed/query_colocation_checker.h +++ b/src/include/distributed/query_colocation_checker.h @@ -35,7 +35,8 @@ extern ColocatedJoinChecker CreateColocatedJoinChecker(Query *subquery, restrictionContext); extern bool SubqueryColocated(Query *subquery, ColocatedJoinChecker *context); extern Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, - List *requiredAttributes); + List *requiredAttributes, + List **allTargetList); #endif /* QUERY_COLOCATION_CHECKER_H */ diff --git a/src/test/regress/expected/citus_local_dist_joins.out b/src/test/regress/expected/citus_local_dist_joins.out index 950cb7464..cd41f66a4 100644 --- a/src/test/regress/expected/citus_local_dist_joins.out +++ b/src/test/regress/expected/citus_local_dist_joins.out @@ -87,36 +87,36 @@ DEBUG: distributed INSERT ... SELECT can only select from distributed tables DEBUG: Collecting INSERT ... SELECT results on coordinator -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(key); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table_windex USING (key)) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local JOIN citus_local_dist_joins.distributed_table_windex USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table_windex USING(value); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table_windex USING (value)) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS key, citus_local_1.value FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) citus_local_1) citus_local JOIN citus_local_dist_joins.distributed_table_windex USING (value)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table_windex ON citus_local.key = distributed_table_windex.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table_windex ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local JOIN citus_local_dist_joins.distributed_table_windex ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table_windex ON distributed_table_windex.key = 10; -DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (citus_local_dist_joins.citus_local 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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) +DEBUG: Wrapping relation "distributed_table_windex" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (citus_local_dist_joins.citus_local JOIN (SELECT distributed_table_windex_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_windex_1) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- 100 @@ -124,47 +124,47 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- no unique index, citus local table should be recursively planned SELECT count(*) FROM citus_local JOIN distributed_table USING(key); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table USING (key)) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local JOIN citus_local_dist_joins.distributed_table USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table USING(value); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value FROM citus_local_dist_joins.citus_local WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table USING (value)) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS key, citus_local_1.value FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) citus_local_1) citus_local JOIN citus_local_dist_joins.distributed_table USING (value)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table ON citus_local.key = distributed_table.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table.key))) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local JOIN citus_local_dist_joins.distributed_table ON ((citus_local.key OPERATOR(pg_catalog.=) distributed_table.key))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table ON distributed_table.key = 10; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT NULL::integer AS key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) 10))) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS 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 citus_local_dist_joins.distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM citus_local JOIN distributed_table USING(key) JOIN postgres_table USING (key) JOIN reference_table USING(key); -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local JOIN citus_local_dist_joins.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM citus_local_dist_joins.postgres_table 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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local JOIN citus_local_dist_joins.distributed_table USING (key)) 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)) JOIN citus_local_dist_joins.reference_table USING (key)) count --------------------------------------------------------------------- 100 @@ -172,11 +172,11 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key) JOIN citus_local USING(key) WHERE distributed_partitioned_table.key > 10 and distributed_partitioned_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((citus_local_dist_joins.distributed_partitioned_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)) postgres_table USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((citus_local_dist_joins.distributed_partitioned_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)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN (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 USING (key)) WHERE ((distributed_partitioned_table.key OPERATOR(pg_catalog.>) 10) AND (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10)) count --------------------------------------------------------------------- 0 @@ -198,9 +198,9 @@ FROM distributed_table WHERE distributed_table.key = citus_local.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.citus_local SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.citus_local SET value = 'test'::text 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) SELECT COUNT(DISTINCT value) FROM citus_local; count --------------------------------------------------------------------- @@ -223,9 +223,9 @@ FROM citus_local WHERE distributed_table.key = citus_local.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table SET value = 'test'::text 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)) citus_local WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table SET value = 'test'::text 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.=) citus_local.key) SELECT COUNT(DISTINCT value) FROM distributed_table; count --------------------------------------------------------------------- @@ -248,9 +248,9 @@ FROM citus_local WHERE distributed_table_pkey.key = citus_local.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table_pkey SET value = 'test'::text 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)) citus_local WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table_pkey SET value = 'test'::text 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_pkey.key OPERATOR(pg_catalog.=) citus_local.key) SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; count --------------------------------------------------------------------- @@ -273,9 +273,9 @@ FROM citus_local WHERE distributed_table_windex.key = citus_local.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table_windex SET value = 'test'::text 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)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE citus_local_dist_joins.distributed_table_windex SET value = 'test'::text 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_windex.key OPERATOR(pg_catalog.=) citus_local.key) SELECT COUNT(DISTINCT value) FROM distributed_table_windex; count --------------------------------------------------------------------- @@ -330,9 +330,9 @@ USING distributed_table WHERE distributed_table.key = citus_local.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM citus_local_dist_joins.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.citus_local USING (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.citus_local USING (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) SELECT COUNT(DISTINCT value) FROM citus_local; count --------------------------------------------------------------------- @@ -353,9 +353,9 @@ USING citus_local WHERE distributed_table.key = citus_local.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table USING (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local WHERE (distributed_table.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table USING (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.=) citus_local.key) SELECT COUNT(DISTINCT value) FROM distributed_table; count --------------------------------------------------------------------- @@ -376,9 +376,9 @@ USING citus_local WHERE distributed_table_pkey.key = citus_local.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table_pkey USING (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table_pkey USING (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_pkey.key OPERATOR(pg_catalog.=) citus_local.key) SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; count --------------------------------------------------------------------- @@ -399,9 +399,9 @@ USING citus_local WHERE distributed_table_windex.key = citus_local.key; -DEBUG: Wrapping relation "citus_local" to a subquery: SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM citus_local_dist_joins.citus_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table_windex USING (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) citus_local WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) citus_local.key) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM citus_local_dist_joins.distributed_table_windex USING (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_windex.key OPERATOR(pg_catalog.=) citus_local.key) SELECT COUNT(DISTINCT value) FROM distributed_table_windex; count --------------------------------------------------------------------- diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 2cf429b7f..7fcf05d04 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -154,7 +154,7 @@ 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 a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT NULL::integer AS a FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true count --------------------------------------------------------------------- 36 @@ -527,7 +527,7 @@ NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queri -- 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 a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT NULL::integer AS a FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true count --------------------------------------------------------------------- 36 @@ -654,7 +654,7 @@ NOTICE: executing the copy locally for shard xxxxx 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 a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT NULL::integer AS a FROM citus_local_table_queries.citus_local_table_1509000 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 @@ -699,47 +699,47 @@ 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509000 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true -NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509002 reference_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)) citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509002 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_1509000 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 WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table.a) +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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)) reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509000 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_1509000 citus_local_table USING (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 WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table.a) +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509002 reference_table USING (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509002 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, NULL::integer AS b FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table USING (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509002 reference_table WHERE true +NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509000 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); @@ -795,8 +795,8 @@ 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, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true -NOTICE: executing the command locally: SELECT a, NULL::integer AS b FROM citus_local_table_queries.citus_local_table_2_1509001 citus_local_table_2 WHERE true +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509000 citus_local_table WHERE true +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_2_1509001 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 --------------------------------------------------------------------- @@ -856,7 +856,7 @@ 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_1509000 lt SET a = mt.a 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 WHERE (mt.b OPERATOR(pg_catalog.=) lt.b) RETURNING lt.b, lt.a +NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509000 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 diff --git a/src/test/regress/expected/coordinator_shouldhaveshards.out b/src/test/regress/expected/coordinator_shouldhaveshards.out index 78597ecce..ffb16d44a 100644 --- a/src/test/regress/expected/coordinator_shouldhaveshards.out +++ b/src/test/regress/expected/coordinator_shouldhaveshards.out @@ -140,8 +140,8 @@ NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshar -- this should be run locally SELECT create_distributed_table('dist_table', 'a', colocate_with := 'none'); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503004, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer)');SELECT worker_apply_shard_ddl_command (1503004, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503007, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer)');SELECT worker_apply_shard_ddl_command (1503007, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503004, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) ');SELECT worker_apply_shard_ddl_command (1503004, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503007, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) ');SELECT worker_apply_shard_ddl_command (1503007, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') NOTICE: executing the copy locally for shard xxxxx NOTICE: Copying data from local table... NOTICE: executing the copy locally for shard xxxxx @@ -176,8 +176,8 @@ NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshar -- this should be run locally SELECT create_distributed_table('dist_table', 'a', colocate_with := 'none'); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503010, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer)');SELECT worker_apply_shard_ddl_command (1503010, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503013, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer)');SELECT worker_apply_shard_ddl_command (1503013, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503010, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) ');SELECT worker_apply_shard_ddl_command (1503010, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503013, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) ');SELECT worker_apply_shard_ddl_command (1503013, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') NOTICE: executing the copy locally for shard xxxxx NOTICE: Copying data from local table... NOTICE: executing the copy locally for shard xxxxx @@ -426,7 +426,7 @@ SELECT * FROM local JOIN dist_table ON (a = x) ORDER BY 1,2,3; (3 rows) SELECT * FROM local JOIN dist_table ON (a = x) WHERE a = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT local.x, local.y, dist_table.a FROM ((SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) local JOIN coordinator_shouldhaveshards.dist_table_1503017 dist_table ON ((dist_table.a OPERATOR(pg_catalog.=) local.x))) WHERE (dist_table.a OPERATOR(pg_catalog.=) 1) ORDER BY local.x, local.y, dist_table.a +NOTICE: executing the command locally: SELECT local.x, local.y, dist_table.a FROM ((SELECT local_1.x, local_1.y FROM (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) local_1) local JOIN coordinator_shouldhaveshards.dist_table_1503017 dist_table ON ((dist_table.a OPERATOR(pg_catalog.=) local.x))) WHERE (dist_table.a OPERATOR(pg_catalog.=) 1) ORDER BY local.x, local.y, dist_table.a x | y | a --------------------------------------------------------------------- 1 | 2 | 1 @@ -475,10 +475,10 @@ CREATE TABLE dist_table1(a int); -- this will use queryStringList, make sure it works correctly with -- copying task SELECT create_distributed_table('dist_table1', 'a'); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503029, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503029, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503031, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503031, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503032, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503032, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503034, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503034, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503029, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) ');SELECT worker_apply_shard_ddl_command (1503029, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503031, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) ');SELECT worker_apply_shard_ddl_command (1503031, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503032, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) ');SELECT worker_apply_shard_ddl_command (1503032, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') +NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503034, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) ');SELECT worker_apply_shard_ddl_command (1503034, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') create_distributed_table --------------------------------------------------------------------- diff --git a/src/test/regress/expected/dml_recursive.out b/src/test/regress/expected/dml_recursive.out index 304e53218..bf2da3866 100644 --- a/src/test/regress/expected/dml_recursive.out +++ b/src/test/regress/expected/dml_recursive.out @@ -352,9 +352,9 @@ FROM distributed_table WHERE distributed_table.tenant_id = local_table.id; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM recursive_dml_queries.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE recursive_dml_queries.local_table SET id = 'citus_test'::text FROM (SELECT intermediate_result.tenant_id, intermediate_result.dept, intermediate_result.info FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(tenant_id text, dept integer, info jsonb)) distributed_table WHERE (distributed_table.tenant_id OPERATOR(pg_catalog.=) local_table.id) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT tenant_id FROM recursive_dml_queries.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE recursive_dml_queries.local_table SET id = 'citus_test'::text FROM (SELECT distributed_table_1.tenant_id, NULL::integer AS dept, NULL::jsonb AS info FROM (SELECT intermediate_result.tenant_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(tenant_id text)) distributed_table_1) distributed_table WHERE (distributed_table.tenant_id OPERATOR(pg_catalog.=) local_table.id) RESET client_min_messages; DROP SCHEMA recursive_dml_queries CASCADE; NOTICE: drop cascades to 5 other objects diff --git a/src/test/regress/expected/local_dist_join_mixed.out b/src/test/regress/expected/local_dist_join_mixed.out index b7d40fd7c..d4f3f96a7 100644 --- a/src/test/regress/expected/local_dist_join_mixed.out +++ b/src/test/regress/expected/local_dist_join_mixed.out @@ -26,90 +26,90 @@ INSERT INTO local SELECT i, i::text FROM generate_series(0,100)i; SET client_min_messages to DEBUG1; -- very simple 1-1 Joins SELECT count(*) FROM distributed JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM distributed JOIN local ON (name = title); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((distributed.name OPERATOR(pg_catalog.=) local.title))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON ((distributed.name OPERATOR(pg_catalog.=) local.title))) count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE ((name OPERATOR(pg_catalog.=) (id)::text) AND (id OPERATOR(pg_catalog.=) 1)) -DEBUG: generating subplan XXX_1 for subquery SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE ((name OPERATOR(pg_catalog.=) (id)::text) AND (id OPERATOR(pg_catalog.=) 1)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "distributed" "d1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id, name FROM local_dist_join_mixed.distributed d1 WHERE ((name OPERATOR(pg_catalog.=) (id)::text) AND (id OPERATOR(pg_catalog.=) 1)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT d1_1.id, d1_1.name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id, intermediate_result.name FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text)) d1_1) d1 JOIN local_dist_join_mixed.local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM distributed JOIN local USING (id) WHERE false; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE false -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE false -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) WHERE false +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE false +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) WHERE false count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR True; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name::int + local.id > d1.id AND d1.id < local.title::int) WHERE d1.id = 1; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local ON (((((d1.name)::integer OPERATOR(pg_catalog.+) local.id) OPERATOR(pg_catalog.>) d1.id) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "distributed" "d1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id, name FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT d1_1.id, d1_1.name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id, intermediate_result.name FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text)) d1_1) d1 JOIN local_dist_join_mixed.local ON (((((d1.name)::integer OPERATOR(pg_catalog.+) local.id) OPERATOR(pg_catalog.>) d1.id) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) count --------------------------------------------------------------------- 101 (1 row) SELECT hashtext(local.id::text) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1 LIMIT 4; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT hashtext((local.id)::text) AS hashtext FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) ORDER BY (hashtext((local.id)::text)) LIMIT 4 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT hashtext((local.id)::text) AS hashtext FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, local_1.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_1) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) ORDER BY (hashtext((local.id)::text)) LIMIT 4 DEBUG: push down of limit count: 4 hashtext --------------------------------------------------------------------- @@ -120,9 +120,9 @@ DEBUG: push down of limit count: 4 (4 rows) SELECT '' as "xxx", local.*, 'xxx' as "test" FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1,2,3 LIMIT 4; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT ''::text AS xxx, local.id, local.title, 'xxx'::text AS test FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) ORDER BY ''::text, local.id, local.title LIMIT 4 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT ''::text AS xxx, local.id, local.title, 'xxx'::text AS test FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, local_1.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_1) local ON ((hashtext(distributed.name) OPERATOR(pg_catalog.=) hashtext(local.title)))) ORDER BY ''::text, local.id, local.title LIMIT 4 DEBUG: push down of limit count: 4 xxx | id | title | test --------------------------------------------------------------------- @@ -133,9 +133,9 @@ DEBUG: push down of limit count: 4 (4 rows) SELECT local.title, count(*) FROM distributed JOIN local USING (id) GROUP BY 1 ORDER BY 1, 2 DESC LIMIT 5; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.title, count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) GROUP BY local.title ORDER BY local.title, (count(*)) DESC LIMIT 5 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.title, count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, local_1.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_1) local USING (id)) GROUP BY local.title ORDER BY local.title, (count(*)) DESC LIMIT 5 title | count --------------------------------------------------------------------- 0 | 1 @@ -146,9 +146,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.title, (5 rows) SELECT distributed.id as id1, local.id as id2 FROM distributed JOIN local USING(id) ORDER BY distributed.id + local.id LIMIT 5; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id AS id1, local.id AS id2 FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) ORDER BY (distributed.id OPERATOR(pg_catalog.+) local.id) LIMIT 5 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id AS id1, local.id AS id2 FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) ORDER BY (distributed.id OPERATOR(pg_catalog.+) local.id) LIMIT 5 DEBUG: push down of limit count: 5 id1 | id2 --------------------------------------------------------------------- @@ -160,9 +160,9 @@ DEBUG: push down of limit count: 5 (5 rows) SELECT distributed.id as id1, local.id as id2, count(*) FROM distributed JOIN local USING(id) GROUP BY distributed.id, local.id ORDER BY 1,2 LIMIT 5; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id AS id1, local.id AS id2, count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) GROUP BY distributed.id, local.id ORDER BY distributed.id, local.id LIMIT 5 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id AS id1, local.id AS id2, count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) GROUP BY distributed.id, local.id ORDER BY distributed.id, local.id LIMIT 5 DEBUG: push down of limit count: 5 id1 | id2 | count --------------------------------------------------------------------- @@ -175,63 +175,63 @@ DEBUG: push down of limit count: 5 -- basic subqueries that cannot be pulled up SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = title); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) local.title))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON ((d1.name OPERATOR(pg_catalog.=) local.title))) count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) AND false) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) count --------------------------------------------------------------------- 5050 @@ -239,81 +239,81 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- pull up subqueries as they are pretty simple, local table should be recursively planned SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = title); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) local.title))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON ((d1.name OPERATOR(pg_catalog.=) local.title))) count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local ON ((d1.name OPERATOR(pg_catalog.=) (d1.id)::text))) count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) AND false) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE ((d1.id OPERATOR(pg_catalog.=) 1) OR true) count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM (SELECT * FROM distributed WHERE id = 2) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) 2)) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE ((id OPERATOR(pg_catalog.<) (title)::integer) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) 2)) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT * FROM distributed WHERE false) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE (false AND (id OPERATOR(pg_catalog.<) (title)::integer)) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, title FROM local_dist_join_mixed.local WHERE (false AND (id OPERATOR(pg_catalog.<) (title)::integer)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE false) d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT title FROM local_dist_join_mixed.local WHERE (false AND (id OPERATOR(pg_catalog.<) (title)::integer)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE false) d1 JOIN (SELECT NULL::bigint AS id, local_1.title FROM (SELECT intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(title text)) local_1) local ON (((d1.name OPERATOR(pg_catalog.=) (d1.id)::text) AND (d1.id OPERATOR(pg_catalog.<) (local.title)::integer)))) WHERE (d1.id OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 0 @@ -322,9 +322,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- TEMPORARY table CREATE TEMPORARY TABLE temp_local AS SELECT * FROM local; SELECT count(*) FROM distributed JOIN temp_local USING (id); -DEBUG: Wrapping relation "temp_local" to a subquery: SELECT id, NULL::text AS title FROM temp_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM temp_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) temp_local USING (id)) +DEBUG: Wrapping relation "temp_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM temp_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT temp_local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) temp_local_1) temp_local USING (id)) count --------------------------------------------------------------------- 101 @@ -333,9 +333,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- UNLOGGED table CREATE UNLOGGED TABLE unlogged_local AS SELECT * FROM local; SELECT count(*) FROM distributed JOIN unlogged_local USING (id); -DEBUG: Wrapping relation "unlogged_local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.unlogged_local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.unlogged_local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) unlogged_local USING (id)) +DEBUG: Wrapping relation "unlogged_local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.unlogged_local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT unlogged_local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) unlogged_local_1) unlogged_local USING (id)) count --------------------------------------------------------------------- 101 @@ -344,9 +344,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- mat view CREATE MATERIALIZED VIEW mat_view AS SELECT * FROM local; SELECT count(*) FROM distributed JOIN mat_view USING (id); -DEBUG: Wrapping relation "mat_view" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.mat_view WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.mat_view WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) mat_view USING (id)) +DEBUG: Wrapping relation "mat_view" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.mat_view WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN (SELECT mat_view_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) mat_view_1) mat_view USING (id)) count --------------------------------------------------------------------- 101 @@ -363,9 +363,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) SELECT count(*) FROM local JOIN dist_regular_view USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) dist_regular_view USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) dist_regular_view USING (id)) count --------------------------------------------------------------------- 101 @@ -386,18 +386,18 @@ SELECT COUNT(*) FROM (distributed d1(x,y,y1) JOIN local l1(x,t) USING (x)) AS t( ERROR: column "l1.t" must appear in the GROUP BY clause or be used in an aggregate function -- final queries are pushdown queries SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) sum --------------------------------------------------------------------- 10100 (1 row) SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id)) DESC LIMIT 4 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id)) DESC LIMIT 4 DEBUG: push down of limit count: 4 sum --------------------------------------------------------------------- @@ -408,9 +408,9 @@ DEBUG: push down of limit count: 4 (4 rows) SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) ORDER BY 1 DESC LIMIT 4; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) LEFT JOIN local_dist_join_mixed.distributed d2 USING (id)) ORDER BY (count(*)) DESC LIMIT 4 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_dist_join_mixed.distributed d1 JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) LEFT JOIN local_dist_join_mixed.distributed d2 USING (id)) ORDER BY (count(*)) DESC LIMIT 4 DEBUG: push down of limit count: 4 count --------------------------------------------------------------------- @@ -418,9 +418,9 @@ DEBUG: push down of limit count: 4 (1 row) SELECT count(DISTINCT d1.name::int * local.id) FROM distributed d1 JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(DISTINCT ((d1.name)::integer OPERATOR(pg_catalog.*) local.id)) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(DISTINCT ((d1.name)::integer OPERATOR(pg_catalog.*) local.id)) AS count FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) count --------------------------------------------------------------------- 101 @@ -428,29 +428,29 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(DISTINC -- final queries are router queries SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local USING (id)) WHERE (d1.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "distributed" "d1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM ((SELECT d1_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) d1_1) d1 JOIN local_dist_join_mixed.local USING (id)) WHERE (d1.id OPERATOR(pg_catalog.=) 1) sum --------------------------------------------------------------------- 2 (1 row) SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1 ORDER BY 1 DESC LIMIT 4; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id) AS sum FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local USING (id)) WHERE (d1.id OPERATOR(pg_catalog.=) 1) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id)) DESC LIMIT 4 +DEBUG: Wrapping relation "distributed" "d1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id) AS sum FROM ((SELECT d1_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) d1_1) d1 JOIN local_dist_join_mixed.local USING (id)) WHERE (d1.id OPERATOR(pg_catalog.=) 1) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY d1.id)) DESC LIMIT 4 sum --------------------------------------------------------------------- 2 (1 row) SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) WHERE d2.id = 1 ORDER BY 1 DESC LIMIT 4; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d2 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed d2 WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d1 JOIN local_dist_join_mixed.local USING (id)) LEFT JOIN (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) d2 USING (id)) WHERE (d2.id OPERATOR(pg_catalog.=) 1) ORDER BY (count(*)) DESC LIMIT 4 +DEBUG: Wrapping relation "distributed" "d1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.distributed d1 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "distributed" "d2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT id FROM local_dist_join_mixed.distributed d2 WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT d1_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) d1_1) d1 JOIN local_dist_join_mixed.local USING (id)) LEFT JOIN (SELECT d2_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) d2_1) d2 USING (id)) WHERE (d2.id OPERATOR(pg_catalog.=) 1) ORDER BY (count(*)) DESC LIMIT 4 count --------------------------------------------------------------------- 1 @@ -458,9 +458,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- final queries are pull to coordinator queries SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id + local.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY (d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY (d1.id OPERATOR(pg_catalog.+) local.id))) DESC LIMIT 4 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY (d1.id OPERATOR(pg_catalog.+) local.id)) AS sum FROM (local_dist_join_mixed.distributed d1 JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) ORDER BY (sum((d1.id OPERATOR(pg_catalog.+) local.id)) OVER (PARTITION BY (d1.id OPERATOR(pg_catalog.+) local.id))) DESC LIMIT 4 sum --------------------------------------------------------------------- 200 @@ -477,9 +477,9 @@ FROM JOIN local USING(id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) foo) bar JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed) foo) bar JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) count --------------------------------------------------------------------- 101 @@ -492,9 +492,9 @@ FROM JOIN local USING(id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) count --------------------------------------------------------------------- 101 @@ -507,9 +507,9 @@ FROM JOIN local USING(id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo.id, foo.name, foo.created_at, foo.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed) foo) bar(id, name, created_at, random, random_1) JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) count --------------------------------------------------------------------- 101 @@ -605,9 +605,9 @@ WHERE local as foo USING(id) ) IS NOT NULL; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed d_upper WHERE ((SELECT bar.id FROM ((SELECT foo_1.id, foo_1.name, foo_1.created_at, foo_1.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) d_upper.id)) foo_1) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) foo USING (id))) IS NOT NULL) +DEBUG: Wrapping relation "local" "foo" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local foo WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed d_upper WHERE ((SELECT bar.id FROM ((SELECT foo_1.id, foo_1.name, foo_1.created_at, foo_1.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) d_upper.id)) foo_1) bar(id, name, created_at, random, random_1) JOIN (SELECT foo_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo_1) foo USING (id))) IS NOT NULL) count --------------------------------------------------------------------- 101 @@ -626,9 +626,9 @@ WHERE d_upper.id > local as foo USING(id) ); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local foo WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed d_upper WHERE (id OPERATOR(pg_catalog.>) (SELECT bar.id FROM ((SELECT foo_1.id, foo_1.name, foo_1.created_at, foo_1.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) d_upper.id)) foo_1) bar(id, name, created_at, random, random_1) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) foo USING (id)))) +DEBUG: Wrapping relation "local" "foo" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local foo WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM local_dist_join_mixed.distributed d_upper WHERE (id OPERATOR(pg_catalog.>) (SELECT bar.id FROM ((SELECT foo_1.id, foo_1.name, foo_1.created_at, foo_1.random, random() AS random FROM (SELECT distributed.id, distributed.name, distributed.created_at, random() AS random FROM local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.=) d_upper.id)) foo_1) bar(id, name, created_at, random, random_1) JOIN (SELECT foo_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo_1) foo USING (id)))) count --------------------------------------------------------------------- 0 @@ -652,9 +652,9 @@ HINT: Use CTE's or subqueries to select from local tables and use them in joins -- subqueries in the target list -- router, should work select (SELECT local.id) FROM local, distributed WHERE distributed.id = 1 LIMIT 1; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local.id) AS id FROM local_dist_join_mixed.local, (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed WHERE (distributed.id OPERATOR(pg_catalog.=) 1) LIMIT 1 +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local.id) AS id FROM local_dist_join_mixed.local, (SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed WHERE (distributed.id OPERATOR(pg_catalog.=) 1) LIMIT 1 id --------------------------------------------------------------------- 0 @@ -662,9 +662,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local -- should fail select (SELECT local.id) FROM local, distributed WHERE distributed.id != 1 LIMIT 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local.id) AS id FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.<>) 1) LIMIT 1 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local.id) AS id FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.<>) 1) LIMIT 1 ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses HINT: Consider using an equality filter on the distributed table's partition column. -- currently not supported, but should work with https://github.com/citusdata/citus/pull/4360/files @@ -679,12 +679,12 @@ HINT: Consider using an equality filter on the distributed table's partition co SELECT local.* FROM distributed JOIN local USING (id) EXCEPT SELECT local.* FROM distributed JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_2 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_3 for subquery SELECT local.id, local.title FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) -DEBUG: generating subplan XXX_4 for subquery SELECT local.id, local.title FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: generating subplan XXX_3 for subquery SELECT local.id, local.title FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, local_1.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_1) local USING (id)) +DEBUG: generating subplan XXX_4 for subquery SELECT local.id, local.title FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, local_1.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_1) local USING (id)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text) EXCEPT SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text) id | title --------------------------------------------------------------------- @@ -693,12 +693,12 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_ SELECT distributed.* FROM distributed JOIN local USING (id) EXCEPT SELECT distributed.* FROM distributed JOIN local USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_3 for subquery SELECT distributed.id, distributed.name, distributed.created_at FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) -DEBUG: generating subplan XXX_4 for subquery SELECT distributed.id, distributed.name, distributed.created_at FROM (local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT distributed.id, distributed.name, distributed.created_at FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) +DEBUG: generating subplan XXX_4 for subquery SELECT distributed.id, distributed.name, distributed.created_at FROM (local_dist_join_mixed.distributed JOIN (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local USING (id)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) EXCEPT SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) id | name | created_at --------------------------------------------------------------------- @@ -727,12 +727,12 @@ SELECT count(*) FROM UNION ALL (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) ) bar; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_3 for subquery SELECT id, name, created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) fo -DEBUG: generating subplan XXX_4 for subquery SELECT id, name, created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) ba +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT id, name, created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed USING (id))) fo +DEBUG: generating subplan XXX_4 for subquery SELECT id, name, created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed USING (id))) ba DEBUG: generating subplan XXX_5 for subquery SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) UNION ALL SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) bar count @@ -747,11 +747,11 @@ FROM UNION ALL (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) ) bar; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(DISTINCT id) AS count FROM (SELECT fo.id, fo.name, fo.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) fo UNION ALL SELECT ba.id, ba.name, ba.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id))) ba) bar +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(DISTINCT id) AS count FROM (SELECT fo.id, fo.name, fo.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed USING (id))) fo UNION ALL SELECT ba.id, ba.name, ba.created_at FROM (SELECT distributed.id, distributed.name, distributed.created_at FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed USING (id))) ba) bar count --------------------------------------------------------------------- 101 @@ -818,57 +818,57 @@ JOIN local u22 USING (id) INNER JOIN local u23 USING (id) INNER JOIN local u24 USING (id) INNER JOIN local u25 USING (id) -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE true -DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE true -DEBUG: generating subplan XXX_4 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE true -DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE true -DEBUG: generating subplan XXX_6 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE true -DEBUG: generating subplan XXX_7 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE true -DEBUG: generating subplan XXX_8 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE true -DEBUG: generating subplan XXX_9 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE true -DEBUG: generating subplan XXX_10 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE true -DEBUG: generating subplan XXX_11 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE true -DEBUG: generating subplan XXX_12 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE true -DEBUG: generating subplan XXX_13 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE true -DEBUG: generating subplan XXX_14 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE true -DEBUG: generating subplan XXX_15 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE true -DEBUG: generating subplan XXX_16 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE true -DEBUG: generating subplan XXX_17 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE true -DEBUG: generating subplan XXX_18 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE true -DEBUG: generating subplan XXX_19 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE true -DEBUG: generating subplan XXX_20 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE true -DEBUG: generating subplan XXX_21 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE true -DEBUG: generating subplan XXX_22 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE true -DEBUG: generating subplan XXX_23 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE true -DEBUG: generating subplan XXX_24 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE true -DEBUG: generating subplan XXX_25 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((((((((((((((((((((((((local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u1 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u2 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u3 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u4 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u5 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u6 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u7 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u8 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u9 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u10 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_11'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u11 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_12'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u12 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_13'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u13 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_14'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u14 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u15 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u16 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u17 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_18'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u18 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_19'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u19 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_20'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u20 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_21'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u21 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_22'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u22 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_23'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u23 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_24'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u24 USING (id)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_25'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u25 USING (id)) +DEBUG: Wrapping relation "local" "u1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local u1 WHERE true +DEBUG: Wrapping relation "local" "u2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT id FROM local_dist_join_mixed.local u2 WHERE true +DEBUG: Wrapping relation "local" "u3" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT id FROM local_dist_join_mixed.local u3 WHERE true +DEBUG: Wrapping relation "local" "u4" to a subquery +DEBUG: generating subplan XXX_4 for subquery SELECT id FROM local_dist_join_mixed.local u4 WHERE true +DEBUG: Wrapping relation "local" "u5" to a subquery +DEBUG: generating subplan XXX_5 for subquery SELECT id FROM local_dist_join_mixed.local u5 WHERE true +DEBUG: Wrapping relation "local" "u6" to a subquery +DEBUG: generating subplan XXX_6 for subquery SELECT id FROM local_dist_join_mixed.local u6 WHERE true +DEBUG: Wrapping relation "local" "u7" to a subquery +DEBUG: generating subplan XXX_7 for subquery SELECT id FROM local_dist_join_mixed.local u7 WHERE true +DEBUG: Wrapping relation "local" "u8" to a subquery +DEBUG: generating subplan XXX_8 for subquery SELECT id FROM local_dist_join_mixed.local u8 WHERE true +DEBUG: Wrapping relation "local" "u9" to a subquery +DEBUG: generating subplan XXX_9 for subquery SELECT id FROM local_dist_join_mixed.local u9 WHERE true +DEBUG: Wrapping relation "local" "u10" to a subquery +DEBUG: generating subplan XXX_10 for subquery SELECT id FROM local_dist_join_mixed.local u10 WHERE true +DEBUG: Wrapping relation "local" "u11" to a subquery +DEBUG: generating subplan XXX_11 for subquery SELECT id FROM local_dist_join_mixed.local u11 WHERE true +DEBUG: Wrapping relation "local" "u12" to a subquery +DEBUG: generating subplan XXX_12 for subquery SELECT id FROM local_dist_join_mixed.local u12 WHERE true +DEBUG: Wrapping relation "local" "u13" to a subquery +DEBUG: generating subplan XXX_13 for subquery SELECT id FROM local_dist_join_mixed.local u13 WHERE true +DEBUG: Wrapping relation "local" "u14" to a subquery +DEBUG: generating subplan XXX_14 for subquery SELECT id FROM local_dist_join_mixed.local u14 WHERE true +DEBUG: Wrapping relation "local" "u15" to a subquery +DEBUG: generating subplan XXX_15 for subquery SELECT id FROM local_dist_join_mixed.local u15 WHERE true +DEBUG: Wrapping relation "local" "u16" to a subquery +DEBUG: generating subplan XXX_16 for subquery SELECT id FROM local_dist_join_mixed.local u16 WHERE true +DEBUG: Wrapping relation "local" "u17" to a subquery +DEBUG: generating subplan XXX_17 for subquery SELECT id FROM local_dist_join_mixed.local u17 WHERE true +DEBUG: Wrapping relation "local" "u18" to a subquery +DEBUG: generating subplan XXX_18 for subquery SELECT id FROM local_dist_join_mixed.local u18 WHERE true +DEBUG: Wrapping relation "local" "u19" to a subquery +DEBUG: generating subplan XXX_19 for subquery SELECT id FROM local_dist_join_mixed.local u19 WHERE true +DEBUG: Wrapping relation "local" "u20" to a subquery +DEBUG: generating subplan XXX_20 for subquery SELECT id FROM local_dist_join_mixed.local u20 WHERE true +DEBUG: Wrapping relation "local" "u21" to a subquery +DEBUG: generating subplan XXX_21 for subquery SELECT id FROM local_dist_join_mixed.local u21 WHERE true +DEBUG: Wrapping relation "local" "u22" to a subquery +DEBUG: generating subplan XXX_22 for subquery SELECT id FROM local_dist_join_mixed.local u22 WHERE true +DEBUG: Wrapping relation "local" "u23" to a subquery +DEBUG: generating subplan XXX_23 for subquery SELECT id FROM local_dist_join_mixed.local u23 WHERE true +DEBUG: Wrapping relation "local" "u24" to a subquery +DEBUG: generating subplan XXX_24 for subquery SELECT id FROM local_dist_join_mixed.local u24 WHERE true +DEBUG: Wrapping relation "local" "u25" to a subquery +DEBUG: generating subplan XXX_25 for subquery SELECT id FROM local_dist_join_mixed.local u25 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((((((((((((((((((((((((local_dist_join_mixed.distributed JOIN (SELECT u1_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u1_1) u1 USING (id)) JOIN (SELECT u2_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u2_1) u2 USING (id)) JOIN (SELECT u3_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u3_1) u3 USING (id)) JOIN (SELECT u4_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u4_1) u4 USING (id)) JOIN (SELECT u5_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u5_1) u5 USING (id)) JOIN (SELECT u6_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u6_1) u6 USING (id)) JOIN (SELECT u7_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u7_1) u7 USING (id)) JOIN (SELECT u8_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u8_1) u8 USING (id)) JOIN (SELECT u9_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u9_1) u9 USING (id)) JOIN (SELECT u10_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u10_1) u10 USING (id)) JOIN (SELECT u11_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_11'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u11_1) u11 USING (id)) JOIN (SELECT u12_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_12'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u12_1) u12 USING (id)) JOIN (SELECT u13_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_13'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u13_1) u13 USING (id)) JOIN (SELECT u14_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_14'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u14_1) u14 USING (id)) JOIN (SELECT u15_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u15_1) u15 USING (id)) JOIN (SELECT u16_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u16_1) u16 USING (id)) JOIN (SELECT u17_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u17_1) u17 USING (id)) JOIN (SELECT u18_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_18'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u18_1) u18 USING (id)) JOIN (SELECT u19_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_19'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u19_1) u19 USING (id)) JOIN (SELECT u20_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_20'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u20_1) u20 USING (id)) JOIN (SELECT u21_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_21'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u21_1) u21 USING (id)) JOIN (SELECT u22_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_22'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u22_1) u22 USING (id)) JOIN (SELECT u23_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_23'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u23_1) u23 USING (id)) JOIN (SELECT u24_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_24'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u24_1) u24 USING (id)) JOIN (SELECT u25_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_25'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u25_1) u25 USING (id)) count --------------------------------------------------------------------- 101 @@ -934,57 +934,57 @@ JOIN local u22 ON (false) INNER JOIN local u23 ON (false) INNER JOIN local u24 ON (false) INNER JOIN local u25 ON (false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u1 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u2 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_3 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u3 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_4 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u4 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_5 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u5 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_6 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u6 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_7 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u7 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_8 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u8 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_9 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u9 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_10 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u10 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_11 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u11 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_12 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u12 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_13 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u13 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_14 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u14 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_15 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u15 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_16 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u16 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_17 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u17 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_18 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u18 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_19 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u19 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_20 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u20 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_21 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u21 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_22 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u22 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_23 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u23 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_24 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u24 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_25 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local u25 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((((((((((((((((((((((((local_dist_join_mixed.distributed JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u1 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u2 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u3 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u4 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u5 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u6 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u7 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u8 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u9 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u10 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_11'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u11 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_12'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u12 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_13'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u13 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_14'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u14 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u15 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u16 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u17 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_18'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u18 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_19'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u19 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_20'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u20 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_21'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u21 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_22'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u22 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_23'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u23 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_24'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u24 ON (false)) JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_25'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) u25 ON (false)) +DEBUG: Wrapping relation "local" "u1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u1 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u2 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u3" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u3 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u4" to a subquery +DEBUG: generating subplan XXX_4 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u4 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u5" to a subquery +DEBUG: generating subplan XXX_5 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u5 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u6" to a subquery +DEBUG: generating subplan XXX_6 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u6 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u7" to a subquery +DEBUG: generating subplan XXX_7 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u7 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u8" to a subquery +DEBUG: generating subplan XXX_8 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u8 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u9" to a subquery +DEBUG: generating subplan XXX_9 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u9 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u10" to a subquery +DEBUG: generating subplan XXX_10 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u10 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u11" to a subquery +DEBUG: generating subplan XXX_11 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u11 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u12" to a subquery +DEBUG: generating subplan XXX_12 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u12 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u13" to a subquery +DEBUG: generating subplan XXX_13 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u13 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u14" to a subquery +DEBUG: generating subplan XXX_14 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u14 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u15" to a subquery +DEBUG: generating subplan XXX_15 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u15 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u16" to a subquery +DEBUG: generating subplan XXX_16 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u16 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u17" to a subquery +DEBUG: generating subplan XXX_17 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u17 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u18" to a subquery +DEBUG: generating subplan XXX_18 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u18 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u19" to a subquery +DEBUG: generating subplan XXX_19 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u19 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u20" to a subquery +DEBUG: generating subplan XXX_20 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u20 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u21" to a subquery +DEBUG: generating subplan XXX_21 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u21 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u22" to a subquery +DEBUG: generating subplan XXX_22 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u22 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u23" to a subquery +DEBUG: generating subplan XXX_23 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u23 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u24" to a subquery +DEBUG: generating subplan XXX_24 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u24 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Wrapping relation "local" "u25" to a subquery +DEBUG: generating subplan XXX_25 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local u25 WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((((((((((((((((((((((((local_dist_join_mixed.distributed JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u1_1) u1 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u2_1) u2 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u3_1) u3 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u4_1) u4 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u5_1) u5 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u6_1) u6 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u7_1) u7 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u8_1) u8 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u9_1) u9 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u10_1) u10 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_11'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u11_1) u11 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_12'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u12_1) u12 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_13'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u13_1) u13 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_14'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u14_1) u14 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u15_1) u15 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u16_1) u16 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u17_1) u17 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_18'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u18_1) u18 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_19'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u19_1) u19 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_20'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u20_1) u20 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_21'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u21_1) u21 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_22'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u22_1) u22 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_23'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u23_1) u23 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_24'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u24_1) u24 ON (false)) JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_25'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) u25_1) u25 ON (false)) count --------------------------------------------------------------------- 0 @@ -1050,9 +1050,9 @@ JOIN distributed u22 USING (id) INNER JOIN distributed u23 USING (id) INNER JOIN distributed u24 USING (id) INNER JOIN distributed u25 USING (id) -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((((((((((((((((((((((((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed u1 USING (id)) JOIN local_dist_join_mixed.distributed u2 USING (id)) JOIN local_dist_join_mixed.distributed u3 USING (id)) JOIN local_dist_join_mixed.distributed u4 USING (id)) JOIN local_dist_join_mixed.distributed u5 USING (id)) JOIN local_dist_join_mixed.distributed u6 USING (id)) JOIN local_dist_join_mixed.distributed u7 USING (id)) JOIN local_dist_join_mixed.distributed u8 USING (id)) JOIN local_dist_join_mixed.distributed u9 USING (id)) JOIN local_dist_join_mixed.distributed u10 USING (id)) JOIN local_dist_join_mixed.distributed u11 USING (id)) JOIN local_dist_join_mixed.distributed u12 USING (id)) JOIN local_dist_join_mixed.distributed u13 USING (id)) JOIN local_dist_join_mixed.distributed u14 USING (id)) JOIN local_dist_join_mixed.distributed u15 USING (id)) JOIN local_dist_join_mixed.distributed u16 USING (id)) JOIN local_dist_join_mixed.distributed u17 USING (id)) JOIN local_dist_join_mixed.distributed u18 USING (id)) JOIN local_dist_join_mixed.distributed u19 USING (id)) JOIN local_dist_join_mixed.distributed u20 USING (id)) JOIN local_dist_join_mixed.distributed u21 USING (id)) JOIN local_dist_join_mixed.distributed u22 USING (id)) JOIN local_dist_join_mixed.distributed u23 USING (id)) JOIN local_dist_join_mixed.distributed u24 USING (id)) JOIN local_dist_join_mixed.distributed u25 USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((((((((((((((((((((((((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed u1 USING (id)) JOIN local_dist_join_mixed.distributed u2 USING (id)) JOIN local_dist_join_mixed.distributed u3 USING (id)) JOIN local_dist_join_mixed.distributed u4 USING (id)) JOIN local_dist_join_mixed.distributed u5 USING (id)) JOIN local_dist_join_mixed.distributed u6 USING (id)) JOIN local_dist_join_mixed.distributed u7 USING (id)) JOIN local_dist_join_mixed.distributed u8 USING (id)) JOIN local_dist_join_mixed.distributed u9 USING (id)) JOIN local_dist_join_mixed.distributed u10 USING (id)) JOIN local_dist_join_mixed.distributed u11 USING (id)) JOIN local_dist_join_mixed.distributed u12 USING (id)) JOIN local_dist_join_mixed.distributed u13 USING (id)) JOIN local_dist_join_mixed.distributed u14 USING (id)) JOIN local_dist_join_mixed.distributed u15 USING (id)) JOIN local_dist_join_mixed.distributed u16 USING (id)) JOIN local_dist_join_mixed.distributed u17 USING (id)) JOIN local_dist_join_mixed.distributed u18 USING (id)) JOIN local_dist_join_mixed.distributed u19 USING (id)) JOIN local_dist_join_mixed.distributed u20 USING (id)) JOIN local_dist_join_mixed.distributed u21 USING (id)) JOIN local_dist_join_mixed.distributed u22 USING (id)) JOIN local_dist_join_mixed.distributed u23 USING (id)) JOIN local_dist_join_mixed.distributed u24 USING (id)) JOIN local_dist_join_mixed.distributed u25 USING (id)) count --------------------------------------------------------------------- 101 @@ -1118,9 +1118,9 @@ JOIN distributed u22 ON (false) INNER JOIN distributed u23 ON (false) INNER JOIN distributed u24 ON (false) INNER JOIN distributed u25 ON (false) -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((((((((((((((((((((((((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed u1 ON (false)) JOIN local_dist_join_mixed.distributed u2 ON (false)) JOIN local_dist_join_mixed.distributed u3 ON (false)) JOIN local_dist_join_mixed.distributed u4 ON (false)) JOIN local_dist_join_mixed.distributed u5 ON (false)) JOIN local_dist_join_mixed.distributed u6 ON (false)) JOIN local_dist_join_mixed.distributed u7 ON (false)) JOIN local_dist_join_mixed.distributed u8 ON (false)) JOIN local_dist_join_mixed.distributed u9 ON (false)) JOIN local_dist_join_mixed.distributed u10 ON (false)) JOIN local_dist_join_mixed.distributed u11 ON (false)) JOIN local_dist_join_mixed.distributed u12 ON (false)) JOIN local_dist_join_mixed.distributed u13 ON (false)) JOIN local_dist_join_mixed.distributed u14 ON (false)) JOIN local_dist_join_mixed.distributed u15 ON (false)) JOIN local_dist_join_mixed.distributed u16 ON (false)) JOIN local_dist_join_mixed.distributed u17 ON (false)) JOIN local_dist_join_mixed.distributed u18 ON (false)) JOIN local_dist_join_mixed.distributed u19 ON (false)) JOIN local_dist_join_mixed.distributed u20 ON (false)) JOIN local_dist_join_mixed.distributed u21 ON (false)) JOIN local_dist_join_mixed.distributed u22 ON (false)) JOIN local_dist_join_mixed.distributed u23 ON (false)) JOIN local_dist_join_mixed.distributed u24 ON (false)) JOIN local_dist_join_mixed.distributed u25 ON (false)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local WHERE (false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((((((((((((((((((((((((SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed u1 ON (false)) JOIN local_dist_join_mixed.distributed u2 ON (false)) JOIN local_dist_join_mixed.distributed u3 ON (false)) JOIN local_dist_join_mixed.distributed u4 ON (false)) JOIN local_dist_join_mixed.distributed u5 ON (false)) JOIN local_dist_join_mixed.distributed u6 ON (false)) JOIN local_dist_join_mixed.distributed u7 ON (false)) JOIN local_dist_join_mixed.distributed u8 ON (false)) JOIN local_dist_join_mixed.distributed u9 ON (false)) JOIN local_dist_join_mixed.distributed u10 ON (false)) JOIN local_dist_join_mixed.distributed u11 ON (false)) JOIN local_dist_join_mixed.distributed u12 ON (false)) JOIN local_dist_join_mixed.distributed u13 ON (false)) JOIN local_dist_join_mixed.distributed u14 ON (false)) JOIN local_dist_join_mixed.distributed u15 ON (false)) JOIN local_dist_join_mixed.distributed u16 ON (false)) JOIN local_dist_join_mixed.distributed u17 ON (false)) JOIN local_dist_join_mixed.distributed u18 ON (false)) JOIN local_dist_join_mixed.distributed u19 ON (false)) JOIN local_dist_join_mixed.distributed u20 ON (false)) JOIN local_dist_join_mixed.distributed u21 ON (false)) JOIN local_dist_join_mixed.distributed u22 ON (false)) JOIN local_dist_join_mixed.distributed u23 ON (false)) JOIN local_dist_join_mixed.distributed u24 ON (false)) JOIN local_dist_join_mixed.distributed u25 ON (false)) count --------------------------------------------------------------------- 0 @@ -1130,18 +1130,18 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT COUNT(*) FROM (VALUES (1), (2), (3)) as f(x) LATERAL JOIN (SELECT * FROM local WHERE id = x) as bar; ERROR: syntax error at or near "LATERAL" SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id = distributed.id) as foo ON (true); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN LATERAL (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo ON (true)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN LATERAL (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo ON (true)) count --------------------------------------------------------------------- 101 (1 row) SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id > distributed.id) as foo ON (true); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN LATERAL (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.>) distributed.id)) foo ON (true)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN LATERAL (SELECT distributed.id, distributed.name, distributed.created_at FROM local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.>) distributed.id)) foo ON (true)) count --------------------------------------------------------------------- 5050 @@ -1154,18 +1154,18 @@ SELECT COUNT(*) FROM distributed JOIN LATERAL (SELECT * FROM local WHERE local.i ERROR: direct joins between distributed and local tables are not supported HINT: Use CTE's or subqueries to select from local tables and use them in joins SELECT count(*) FROM distributed CROSS JOIN local; -DEBUG: Wrapping relation "local" to a subquery: SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed CROSS JOIN (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::bigint AS id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed CROSS JOIN (SELECT NULL::bigint AS id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local) count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM distributed CROSS JOIN local WHERE distributed.id = 1; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed CROSS JOIN local_dist_join_mixed.local) WHERE (distributed.id OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE (id OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed CROSS JOIN local_dist_join_mixed.local) WHERE (distributed.id OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 101 @@ -1173,36 +1173,36 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- w count(*) it works fine as PG ignores the inner tables SELECT count(*) FROM distributed LEFT JOIN local USING (id); -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed LEFT JOIN local_dist_join_mixed.local USING (id)) +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed LEFT JOIN local_dist_join_mixed.local USING (id)) count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM local LEFT JOIN distributed USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) count --------------------------------------------------------------------- 101 (1 row) SELECT id, name FROM distributed LEFT JOIN local USING (id) ORDER BY 1 LIMIT 1; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id, distributed.name FROM ((SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed LEFT JOIN local_dist_join_mixed.local USING (id)) ORDER BY distributed.id LIMIT 1 +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id, name FROM local_dist_join_mixed.distributed WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.id, distributed.name FROM ((SELECT distributed_1.id, distributed_1.name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id, intermediate_result.name FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text)) distributed_1) distributed LEFT JOIN local_dist_join_mixed.local USING (id)) ORDER BY distributed.id LIMIT 1 id | name --------------------------------------------------------------------- 0 | 0 (1 row) SELECT id, name FROM local LEFT JOIN distributed USING (id) ORDER BY 1 LIMIT 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.id, distributed.name FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY local.id LIMIT 1 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.id, distributed.name FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local LEFT JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY local.id LIMIT 1 ERROR: cannot pushdown the subquery DETAIL: Complex subqueries and CTEs cannot be in the outer part of the outer join SELECT @@ -1230,27 +1230,27 @@ DETAIL: Complex subqueries and CTEs cannot be in the outer part of the outer jo foo1.id = foo10.id AND foo1.id = foo1.id ORDER BY 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_4 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_6 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_7 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_8 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_9 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id IS NOT NULL) -DEBUG: generating subplan XXX_10 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE (id IS NOT NULL) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo9, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo8, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo7, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo6, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo5, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo4, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo3, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo2, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo10, (SELECT local.id, local.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo1 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo9.id) AND (foo1.id OPERATOR(pg_catalog.=) foo8.id) AND (foo1.id OPERATOR(pg_catalog.=) foo7.id) AND (foo1.id OPERATOR(pg_catalog.=) foo6.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo10.id) AND (foo1.id OPERATOR(pg_catalog.=) foo1.id)) ORDER BY foo1.id +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_4 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_5 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_6 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_7 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_8 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_9 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_10 for subquery SELECT id FROM local_dist_join_mixed.local WHERE (id IS NOT NULL) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo9, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo8, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo7, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo6, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo5, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo4, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo3, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo2, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo10, (SELECT local.id, local.title FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo1 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo9.id) AND (foo1.id OPERATOR(pg_catalog.=) foo8.id) AND (foo1.id OPERATOR(pg_catalog.=) foo7.id) AND (foo1.id OPERATOR(pg_catalog.=) foo6.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo10.id) AND (foo1.id OPERATOR(pg_catalog.=) foo1.id)) ORDER BY foo1.id id --------------------------------------------------------------------- 0 @@ -1371,17 +1371,17 @@ WHERE foo1.id = foo4.id AND foo1.id = foo5.id ORDER BY 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_4 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo1, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo2, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo3, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo4, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo5 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id)) ORDER BY foo1.id +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_4 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_5 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo1, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo2, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo3, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo4, (SELECT local.id FROM local_dist_join_mixed.distributed, (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local WHERE (local.id OPERATOR(pg_catalog.=) distributed.id)) foo5 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id)) ORDER BY foo1.id id --------------------------------------------------------------------- 0 @@ -1502,21 +1502,21 @@ WHERE foo1.id = foo4.id AND foo1.id = foo5.id ORDER BY 1; -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_2 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 1)) -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_3 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_4 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 2)) -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_5 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_6 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 3)) -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_7 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_8 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 4)) -DEBUG: Wrapping relation "distributed" to a subquery: SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_9 for subquery SELECT id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) -DEBUG: generating subplan XXX_10 for subquery SELECT local.id FROM (SELECT intermediate_result.id, intermediate_result.name, intermediate_result.created_at FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name text, created_at timestamp with time zone)) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 5)) +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_2 for subquery SELECT local.id FROM (SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 1)) +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_4 for subquery SELECT local.id FROM (SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 2)) +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_5 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_6 for subquery SELECT local.id FROM (SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 3)) +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_7 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_8 for subquery SELECT local.id FROM (SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 4)) +DEBUG: Wrapping relation "distributed" to a subquery +DEBUG: generating subplan XXX_9 for subquery SELECT id FROM local_dist_join_mixed.distributed WHERE (false AND false AND false AND false) +DEBUG: generating subplan XXX_10 for subquery SELECT local.id FROM (SELECT distributed_1.id, NULL::text AS name, NULL::timestamp with time zone AS created_at FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) distributed_1) distributed, local_dist_join_mixed.local WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (distributed.id OPERATOR(pg_catalog.=) 5)) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo1.id FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo1, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo2, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo3, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo4, (SELECT intermediate_result.id FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) foo5 WHERE ((foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo2.id) AND (foo1.id OPERATOR(pg_catalog.=) foo3.id) AND (foo1.id OPERATOR(pg_catalog.=) foo4.id) AND (foo1.id OPERATOR(pg_catalog.=) foo5.id)) ORDER BY foo1.id id --------------------------------------------------------------------- @@ -1536,18 +1536,18 @@ JOIN LATERAL ON(true) WHERE local.id = distributed.id AND d2.id = local.id) as foo ON (true); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN LATERAL (SELECT local.id, local.title, d2.id, d2.name, d2.created_at FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed d2 ON (true)) WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (d2.id OPERATOR(pg_catalog.=) local.id))) foo(id, title, id_1, name, created_at) ON (true)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_dist_join_mixed.distributed JOIN LATERAL (SELECT local.id, local.title, d2.id, d2.name, d2.created_at FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed d2 ON (true)) WHERE ((local.id OPERATOR(pg_catalog.=) distributed.id) AND (d2.id OPERATOR(pg_catalog.=) local.id))) foo(id, title, id_1, name, created_at) ON (true)) count --------------------------------------------------------------------- 101 (1 row) SELECT local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2 LIMIt 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.title, local.title FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY local.title, local.title LIMIT 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.title, local.title FROM ((SELECT local_1.id, local_1.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_1) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY local.title, local.title LIMIT 1 DEBUG: push down of limit count: 1 title | title --------------------------------------------------------------------- @@ -1555,9 +1555,9 @@ DEBUG: push down of limit count: 1 (1 row) SELECT NULL FROM local JOIN distributed USING(id) ORDER BY 1 LIMIt 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT NULL::text FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY NULL::text LIMIT 1 +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT NULL::text FROM ((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY NULL::text LIMIT 1 DEBUG: push down of limit count: 1 ?column? --------------------------------------------------------------------- @@ -1565,9 +1565,9 @@ DEBUG: push down of limit count: 1 (1 row) SELECT distributed.name, distributed.name, local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2,3,4 LIMIT 1; -DEBUG: Wrapping relation "local" to a subquery: SELECT id, title FROM local_dist_join_mixed.local WHERE true +DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT id, title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.name, distributed.name, local.title, local.title FROM ((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY distributed.name, distributed.name, local.title, local.title LIMIT 1 +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT distributed.name, distributed.name, local.title, local.title FROM ((SELECT local_1.id, local_1.title FROM (SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local_1) local JOIN local_dist_join_mixed.distributed USING (id)) ORDER BY distributed.name, distributed.name, local.title, local.title LIMIT 1 DEBUG: push down of limit count: 1 name | name | title | title --------------------------------------------------------------------- @@ -1586,9 +1586,9 @@ JOIN (SELECT id, NULL, NULL FROM distributed) foo USING (id); -DEBUG: Wrapping relation "local" to a subquery: SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT id, NULL::text AS title FROM local_dist_join_mixed.local WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.id, intermediate_result.title FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, title text)) local JOIN local_dist_join_mixed.distributed USING (id)) JOIN (SELECT distributed_1.id, NULL::text, NULL::text FROM local_dist_join_mixed.distributed distributed_1) foo(id, "?column?", "?column?_1") USING (id)) +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local JOIN local_dist_join_mixed.distributed USING (id)) JOIN (SELECT distributed_1.id, NULL::text, NULL::text FROM local_dist_join_mixed.distributed distributed_1) foo(id, "?column?", "?column?_1") USING (id)) count --------------------------------------------------------------------- 101 diff --git a/src/test/regress/expected/local_dist_join_modifications.out b/src/test/regress/expected/local_dist_join_modifications.out index a42de58bf..988fc243d 100644 --- a/src/test/regress/expected/local_dist_join_modifications.out +++ b/src/test/regress/expected/local_dist_join_modifications.out @@ -90,9 +90,9 @@ FROM distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text 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) SELECT COUNT(DISTINCT value) FROM postgres_table; count --------------------------------------------------------------------- @@ -115,9 +115,9 @@ FROM postgres_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text 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.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table; count --------------------------------------------------------------------- @@ -140,9 +140,9 @@ FROM postgres_table WHERE distributed_table_pkey.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text 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_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; count --------------------------------------------------------------------- @@ -165,9 +165,9 @@ FROM postgres_table WHERE distributed_table_windex.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text 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_windex.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_windex; count --------------------------------------------------------------------- @@ -224,9 +224,9 @@ FROM distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text 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) SELECT COUNT(DISTINCT value) FROM postgres_table; count --------------------------------------------------------------------- @@ -249,9 +249,9 @@ FROM postgres_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text 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.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table; count --------------------------------------------------------------------- @@ -274,9 +274,9 @@ FROM postgres_table WHERE distributed_table_pkey.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text 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_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; count --------------------------------------------------------------------- @@ -299,9 +299,9 @@ FROM postgres_table WHERE distributed_table_windex.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text 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_windex.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_windex; count --------------------------------------------------------------------- @@ -325,9 +325,9 @@ FROM distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text 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) SELECT COUNT(DISTINCT value) FROM postgres_table; count --------------------------------------------------------------------- @@ -350,9 +350,9 @@ FROM postgres_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text 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.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table; count --------------------------------------------------------------------- @@ -375,9 +375,9 @@ FROM postgres_table WHERE distributed_table_pkey.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_pkey SET value = 'test'::text 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_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; count --------------------------------------------------------------------- @@ -400,9 +400,9 @@ FROM postgres_table WHERE distributed_table_windex.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text FROM (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table_windex SET value = 'test'::text 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_windex.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_windex; count --------------------------------------------------------------------- @@ -421,11 +421,11 @@ FROM postgres_table p1, postgres_table p2 WHERE distributed_table.key = p1.key AND p1.key = p2.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p2 WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) p1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) +DEBUG: Wrapping relation "postgres_table" "p1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table p1 WHERE true +DEBUG: Wrapping relation "postgres_table" "p2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_dist_join_modifications.postgres_table p2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (SELECT p1_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)) p1_1) p1, (SELECT p2_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)) p2_1) p2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) p2.key)) ROLLBACK; BEGIN; UPDATE @@ -460,9 +460,9 @@ FROM postgres_table p1, distributed_table d2 WHERE distributed_table.key = p1.key AND p1.key = d2.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table p1 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (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)) p1, local_dist_join_modifications.distributed_table d2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) d2.key)) +DEBUG: Wrapping relation "postgres_table" "p1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table p1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.distributed_table SET value = 'test'::text FROM (SELECT p1_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)) p1_1) p1, local_dist_join_modifications.distributed_table d2 WHERE ((distributed_table.key OPERATOR(pg_catalog.=) p1.key) AND (p1.key OPERATOR(pg_catalog.=) d2.key)) ROLLBACK; -- pretty inefficient plan as it requires -- recursive planninng of 2 distributed tables @@ -475,11 +475,11 @@ FROM distributed_table d1, distributed_table d2 WHERE postgres_table.key = d1.key AND d1.key = d2.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d1 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d1 WHERE true -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d2 WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table d2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (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)) d1, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) +DEBUG: Wrapping relation "distributed_table" "d1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.distributed_table d1 WHERE true +DEBUG: Wrapping relation "distributed_table" "d2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_dist_join_modifications.distributed_table d2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_dist_join_modifications.postgres_table SET value = 'test'::text FROM (SELECT d1_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)) d1_1) d1, (SELECT d2_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)) d2_1) d2 WHERE ((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.=) d2.key)) ROLLBACK; -- DELETE operations BEGIN; @@ -495,9 +495,9 @@ USING distributed_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.postgres_table USING (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)) distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.postgres_table USING (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) SELECT COUNT(DISTINCT value) FROM postgres_table; count --------------------------------------------------------------------- @@ -518,9 +518,9 @@ USING postgres_table WHERE distributed_table.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table USING (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)) postgres_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table USING (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.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table; count --------------------------------------------------------------------- @@ -541,9 +541,9 @@ USING postgres_table WHERE distributed_table_pkey.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table_pkey USING (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)) postgres_table WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table_pkey USING (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_pkey.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_pkey; count --------------------------------------------------------------------- @@ -564,9 +564,9 @@ USING postgres_table WHERE distributed_table_windex.key = postgres_table.key; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_dist_join_modifications.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table_windex USING (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)) postgres_table WHERE (distributed_table_windex.key OPERATOR(pg_catalog.=) postgres_table.key) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_dist_join_modifications.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM local_dist_join_modifications.distributed_table_windex USING (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_windex.key OPERATOR(pg_catalog.=) postgres_table.key) SELECT COUNT(DISTINCT value) FROM distributed_table_windex; count --------------------------------------------------------------------- diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 3b2072709..9592ba95e 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -81,18 +81,18 @@ HINT: Use CTE's or subqueries to select from local tables and use them in joins -- the user prefers local table recursively planned SET citus.local_table_join_policy TO 'prefer-local'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.reference_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 100 @@ -101,18 +101,18 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- the user prefers distributed table recursively planned SET citus.local_table_join_policy TO 'prefer-distributed'; SELECT count(*) FROM postgres_table JOIN distributed_table USING(key); -DEBUG: Wrapping relation "distributed_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table USING (key)) +DEBUG: Wrapping relation "distributed_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (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 USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN reference_table USING(key); -DEBUG: Wrapping relation "reference_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.reference_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) reference_table USING (key)) +DEBUG: Wrapping relation "reference_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.reference_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT reference_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)) reference_table_1) reference_table USING (key)) count --------------------------------------------------------------------- 100 @@ -124,27 +124,27 @@ SET citus.local_table_join_policy to 'auto'; -- on the auto mode, the local tables should be recursively planned -- unless a unique index exists in a column for distributed table SELECT count(*) FROM distributed_table JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -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)) postgres_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.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)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM reference_table JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -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)) postgres_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_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)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.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)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 100 @@ -152,27 +152,27 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- partititoned local tables should work as well SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM reference_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -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 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 100 @@ -180,72 +180,72 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- materialized views should work too SELECT count(*) FROM distributed_table JOIN mv1 USING(key); -DEBUG: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT mv1_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)) mv1_1) mv1 USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv1 USING(key); -DEBUG: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +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 mv1_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)) mv1_1) mv1 USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM reference_table JOIN mv1 USING(key); -DEBUG: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_table JOIN (SELECT mv1_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)) mv1_1) mv1 USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_table JOIN mv1 USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "mv1" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv1 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_table JOIN (SELECT mv1_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)) mv1_1) mv1 USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_table JOIN mv2 USING(key); -DEBUG: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT mv2_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)) mv2_1) mv2 USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv2 USING(key); -DEBUG: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +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 mv2_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)) mv2_1) mv2 USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM reference_table JOIN mv2 USING(key); -DEBUG: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_table JOIN (SELECT mv2_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)) mv2_1) mv2 USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_table JOIN mv2 USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "mv2" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.mv2 WHERE true -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 -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)) +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_table JOIN (SELECT mv2_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)) mv2_1) mv2 USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 100 @@ -253,9 +253,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- foreign tables should work too SELECT count(*) FROM foreign_table JOIN distributed_table USING(key); -DEBUG: Wrapping relation "foreign_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.foreign_table WHERE true -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_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) foreign_table JOIN local_table_join.distributed_table USING (key)) +DEBUG: Wrapping relation "foreign_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.foreign_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foreign_table_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)) foreign_table_1) foreign_table JOIN local_table_join.distributed_table USING (key)) count --------------------------------------------------------------------- 0 @@ -263,54 +263,54 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- partitioned tables should work as well SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) WHERE distributed_partitioned_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) postgres_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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_partitioned_table.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_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)) postgres_table USING (key)) JOIN local_table_join.reference_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_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)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) count --------------------------------------------------------------------- 100 @@ -318,80 +318,80 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- the conversions should be independent from the order of table entries in the query SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table_pkey USING (key)) JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- 1 (1 row) SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join distributed_table_pkey using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) JOIN local_table_join.distributed_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- 1 (1 row) SELECT COUNT(*) FROM postgres_table join distributed_table using(key) join local_partitioned_table using(key) join distributed_table_pkey using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table USING (key)) JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- 1 (1 row) SELECT COUNT(*) FROM distributed_table_pkey join distributed_table using(key) join postgres_table using(key) join local_partitioned_table using(key) where distributed_table_pkey.key = 5; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table_pkey JOIN local_table_join.distributed_table USING (key)) 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)) postgres_table USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table_pkey JOIN local_table_join.distributed_table USING (key)) 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)) JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -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, random() AS random 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +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, random() AS random FROM local_table_join.distributed_table) d1 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 ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, random() AS random FROM local_table_join.distributed_table_pkey) 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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, random() AS random FROM local_table_join.distributed_table_pkey) d1 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 ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_table) d1 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 ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key::int = d1.key::int AND d1.key < postgres_table.key) WHERE d1.key::int = 1 AND false; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_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)) postgres_table ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE ((key OPERATOR(pg_catalog.<) key) AND false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_partitioned_table.key, distributed_partitioned_table.value, random() AS random FROM local_table_join.distributed_partitioned_table) d1 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 ON (((postgres_table.key OPERATOR(pg_catalog.=) d1.key) AND (d1.key OPERATOR(pg_catalog.<) postgres_table.key)))) WHERE ((d1.key OPERATOR(pg_catalog.=) 1) AND false) count --------------------------------------------------------------------- 0 @@ -399,36 +399,36 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- We will plan postgres table as the index is on key,value not just key SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE (distributed_table_composite.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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_composite.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10 OR distributed_table_composite.key = 20; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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_composite.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) count --------------------------------------------------------------------- 2 (1 row) SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key > 10 AND distributed_table_composite.value = 'text'; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10 AND distributed_table_composite.value = 'text'; -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 10) AND (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 10) AND (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 10) AND (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 0 @@ -437,9 +437,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE (distributed_table_composite.key > 10 OR distributed_table_composite.key = 20) AND (distributed_table_composite.value = 'text' OR distributed_table_composite.value = 'text'); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) AND ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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_composite.key OPERATOR(pg_catalog.>) 10) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) AND ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text))) count --------------------------------------------------------------------- 0 @@ -448,9 +448,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE (distributed_table_composite.key > 10 OR distributed_table_composite.value = 'text') AND (distributed_table_composite.value = 'text' OR distributed_table_composite.key = 30); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) OR (value OPERATOR(pg_catalog.=) 'text'::text)) AND ((value OPERATOR(pg_catalog.=) 'text'::text) OR (key OPERATOR(pg_catalog.=) 30))) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) OR (value OPERATOR(pg_catalog.=) 'text'::text)) AND ((value OPERATOR(pg_catalog.=) 'text'::text) OR (key OPERATOR(pg_catalog.=) 30))) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) AND ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 30))) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) OR (value OPERATOR(pg_catalog.=) 'text'::text)) AND ((value OPERATOR(pg_catalog.=) 'text'::text) OR (key OPERATOR(pg_catalog.=) 30))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) AND ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 30))) count --------------------------------------------------------------------- 1 @@ -459,9 +459,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE (distributed_table_composite.key > 10 AND distributed_table_composite.value = 'text') OR (distributed_table_composite.value = 'text' AND distributed_table_composite.key = 30); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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)) postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) OR ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) AND (distributed_table_composite.key OPERATOR(pg_catalog.=) 30))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table_composite 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_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) OR ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) AND (distributed_table_composite.key OPERATOR(pg_catalog.=) 30))) count --------------------------------------------------------------------- 0 @@ -470,9 +470,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE (distributed_table_composite.key > 10 AND distributed_table_composite.key = 20) OR (distributed_table_composite.value = 'text' AND distributed_table_composite.value = 'text'); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 20)) OR ((value OPERATOR(pg_catalog.=) 'text'::text) AND (value OPERATOR(pg_catalog.=) 'text'::text))) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 20)) OR ((value OPERATOR(pg_catalog.=) 'text'::text) AND (value OPERATOR(pg_catalog.=) 'text'::text))) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) OR ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text))) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE (((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 20)) OR ((value OPERATOR(pg_catalog.=) 'text'::text) AND (value OPERATOR(pg_catalog.=) 'text'::text))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite JOIN local_table_join.postgres_table USING (key)) WHERE (((distributed_table_composite.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.=) 20)) OR ((distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text) AND (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text))) count --------------------------------------------------------------------- 1 @@ -480,36 +480,36 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table_pkey USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey USING (value)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS key, postgres_table_1.value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) postgres_table_1) postgres_table JOIN local_table_join.distributed_table_pkey USING (value)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = distributed_table_pkey.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_pkey.key))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_pkey.key))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- 100 @@ -517,81 +517,81 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- it should favor distributed table only if it has equality on the unique column SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key > 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS 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 JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10))) count --------------------------------------------------------------------- 9000 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key < 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.<) 10))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS 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 JOIN local_table_join.distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.<) 10))) count --------------------------------------------------------------------- 900 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 ; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 AND distributed_table_pkey.key > 10 AND postgres_table.key = 5; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (postgres_table.key OPERATOR(pg_catalog.=) 5)))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.>) 10) AND (key OPERATOR(pg_catalog.=) 10)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (postgres_table.key OPERATOR(pg_catalog.=) 5)))) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key > 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS 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 JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.>) 10)))) count --------------------------------------------------------------------- 9100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20)))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20)))) count --------------------------------------------------------------------- 200 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR distributed_table_pkey.key = 20 OR distributed_table_pkey.key = 30; -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 30)))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR (key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 30)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) 30)))) count --------------------------------------------------------------------- 300 @@ -601,81 +601,81 @@ SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_t SELECT count(*) FROM distributed_table_pkey ); DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM local_table_join.distributed_table_pkey -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)))))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS 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 JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR (distributed_table_pkey.key OPERATOR(pg_catalog.=) (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)))))) count --------------------------------------------------------------------- 200 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 5 and distributed_table_pkey.key > 15); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.=) 5) AND (key OPERATOR(pg_catalog.>) 15))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.key > 15); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS 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 JOIN local_table_join.distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.key OPERATOR(pg_catalog.>) 15))))) count --------------------------------------------------------------------- 8600 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key > 10 and distributed_table_pkey.value = 'notext'); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_pkey WHERE ((key OPERATOR(pg_catalog.=) 10) OR ((key OPERATOR(pg_catalog.>) 10) AND (value OPERATOR(pg_catalog.=) 'notext'::text))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_1.key, distributed_table_pkey_1.value, NULL::jsonb AS value_2 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)) distributed_table_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.>) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON distributed_table_pkey.key = 10 OR (distributed_table_pkey.key = 10 and distributed_table_pkey.value = 'notext'); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey ON (((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) OR ((distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_pkey.value OPERATOR(pg_catalog.=) 'notext'::text))))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_pkey ON postgres_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) 10))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table_pkey ON ((postgres_table.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- 100 (1 row) select count(*) FROM postgres_table JOIN (SELECT a.key,random() FROM distributed_table a JOIN distributed_table b USING(key)) as foo USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN (SELECT a.key, random() AS random FROM (local_table_join.distributed_table a JOIN local_table_join.distributed_table b USING (key))) foo USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN (SELECT a.key, random() AS random FROM (local_table_join.distributed_table a JOIN local_table_join.distributed_table b USING (key))) foo USING (key)) count --------------------------------------------------------------------- 100 (1 row) select count(*) FROM (SELECT a.key, random() FROM distributed_table a JOIN distributed_table b USING(key)) as foo JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT a.key, random() AS random FROM (local_table_join.distributed_table a JOIN local_table_join.distributed_table b USING (key))) foo 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)) postgres_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT a.key, random() AS random FROM (local_table_join.distributed_table a JOIN local_table_join.distributed_table b USING (key))) foo 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)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN (SELECT * FROM distributed_table) d1 USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1 USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1 USING (key)) count --------------------------------------------------------------------- 100 @@ -693,36 +693,36 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table_windex USING (key)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex USING(value); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex USING (value)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS key, postgres_table_1.value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) postgres_table_1) postgres_table JOIN local_table_join.distributed_table_windex USING (value)) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON postgres_table.key = distributed_table_windex.key; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table_windex ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table_windex ON ((postgres_table.key OPERATOR(pg_catalog.=) distributed_table_windex.key))) count --------------------------------------------------------------------- 100 (1 row) SELECT count(*) FROM postgres_table JOIN distributed_table_windex ON distributed_table_windex.key = 10; -DEBUG: Wrapping relation "distributed_table_windex" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_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)) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) +DEBUG: Wrapping relation "distributed_table_windex" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_windex WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_windex_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_windex_1) distributed_table_windex ON ((distributed_table_windex.key OPERATOR(pg_catalog.=) 10))) count --------------------------------------------------------------------- 100 @@ -730,18 +730,18 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- no unique index on value so local table should be recursively planned. SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test'; -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -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)) postgres_table USING (key)) WHERE (distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.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.value OPERATOR(pg_catalog.=) 'test'::text) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.key = 1; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) -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)) postgres_table USING (key)) WHERE (distributed_table.key OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.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.=) 1) count --------------------------------------------------------------------- 1 @@ -749,18 +749,18 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- if both local and distributed tables have a filter, we prefer local unless distributed table has unique indexes on any equality filter SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' AND postgres_table.value = 'test'; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) -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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) AND (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.postgres_table WHERE (value OPERATOR(pg_catalog.=) 'test'::text) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT postgres_table_1.key, postgres_table_1.value, NULL::jsonb AS value_2 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)) postgres_table_1) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) AND (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM distributed_table JOIN postgres_table USING(key) WHERE distributed_table.value = 'test' OR postgres_table.value = 'test'; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -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)) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) OR (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT postgres_table_1.key, postgres_table_1.value, NULL::jsonb AS value_2 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)) postgres_table_1) postgres_table USING (key)) WHERE ((distributed_table.value OPERATOR(pg_catalog.=) 'test'::text) OR (postgres_table.value OPERATOR(pg_catalog.=) 'test'::text)) count --------------------------------------------------------------------- 0 @@ -769,11 +769,11 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- multiple local/distributed tables -- only local tables are recursively planned SELECT count(*) FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) +DEBUG: Wrapping relation "postgres_table" "p1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table p1 WHERE true +DEBUG: Wrapping relation "postgres_table" "p2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.postgres_table p2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table d1 JOIN (SELECT p1_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)) p1_1) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT p2_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)) p2_1) p2 USING (key)) count --------------------------------------------------------------------- 100 @@ -785,11 +785,11 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.value = '1'; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE true -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) +DEBUG: Wrapping relation "postgres_table" "p1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table p1 WHERE true +DEBUG: Wrapping relation "postgres_table" "p2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.postgres_table p2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table d1 JOIN (SELECT p1_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)) p1_1) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT p2_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)) p2_1) p2 USING (key)) WHERE (d1.value OPERATOR(pg_catalog.=) '1'::text) count --------------------------------------------------------------------- 1 @@ -803,11 +803,11 @@ FROM distributed_table d1 JOIN postgres_table p1 USING(key) JOIN distributed_table d2 USING(key) JOIN postgres_table p2 USING(key) WHERE d1.key = 1; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count 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)) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) p2 USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "postgres_table" "p1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table p1 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: Wrapping relation "postgres_table" "p2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.postgres_table p2 WHERE (key OPERATOR(pg_catalog.=) 1) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((local_table_join.distributed_table d1 JOIN (SELECT p1_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)) p1_1) p1 USING (key)) JOIN local_table_join.distributed_table d2 USING (key)) JOIN (SELECT p2_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)) p2_1) p2 USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) count --------------------------------------------------------------------- 1 @@ -823,9 +823,9 @@ FROM (SELECT * FROM (SELECT * FROM distributed_table) d1) d2 JOIN postgres_table USING(key); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT d1.key, d1.value, d1.value_2 FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1) d2 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)) postgres_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT d1.key, d1.value, d1.value_2 FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.value_2 FROM local_table_join.distributed_table) d1) d2 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)) count --------------------------------------------------------------------- 100 @@ -833,28 +833,28 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- TODO:: we should support this? UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) postgres_table WHERE (postgres_table.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 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.=) 10) ERROR: relation postgres_table is not distributed UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (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)) l WHERE (l.key OPERATOR(pg_catalog.=) 10) SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE; -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) WHERE false +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE false +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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 JOIN local_table_join.distributed_table USING (key)) WHERE false count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT * FROM distributed_table JOIN postgres_table USING(key) WHERE false) foo JOIN local_partitioned_table USING(key); -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE false -DEBUG: Wrapping relation "local_partitioned_table" to a subquery: SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE false -DEBUG: generating subplan XXX_2 for subquery SELECT key, NULL::text AS value FROM local_table_join.local_partitioned_table WHERE false -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, postgres_table.value, postgres_table.value_2 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)) postgres_table USING (key)) WHERE false) foo(key, value, value_2, value_1, value_2_1) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) local_partitioned_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE false +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE false +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, postgres_table.value, postgres_table.value_2 FROM (local_table_join.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 false) foo(key, value, value_2, value_1, value_2_1) JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) count --------------------------------------------------------------------- 0 @@ -863,9 +863,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c WITH dist_cte AS (SELECT * FROM distributed_table_pkey WHERE key = 5) SELECT COUNT(*) FROM dist_cte JOIN postgres_table USING(key) WHERE dist_cte.key = 5; DEBUG: CTE dist_cte is going to be inlined via distributed planning -DEBUG: Wrapping relation "postgres_table" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2 FROM local_table_join.distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5)) dist_cte 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)) postgres_table USING (key)) WHERE (dist_cte.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2 FROM local_table_join.distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5)) dist_cte 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 (dist_cte.key OPERATOR(pg_catalog.=) 5) count --------------------------------------------------------------------- 1 @@ -873,12 +873,12 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c SELECT COUNT(*) FROM postgres_table JOIN distributed_table_pkey USING(key) WHERE (distributed_table_pkey.key IN (SELECT COUNT(*) AS count FROM postgres_table JOIN distributed_table USING(key)) ); -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT count(*) AS count FROM ((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)) postgres_table JOIN local_table_join.distributed_table USING (key)) -DEBUG: Wrapping 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 -DEBUG: generating subplan XXX_3 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.postgres_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint))) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: generating subplan XXX_2 for subquery 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 JOIN local_table_join.distributed_table USING (key)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table JOIN local_table_join.distributed_table_pkey USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint))) count --------------------------------------------------------------------- 1 @@ -887,54 +887,54 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- PREPARED statements PREPARE local_dist_table_join_select(int) AS SELECT COUNT(*) FROM distributed_table_pkey JOIN postgres_table USING(key) WHERE distributed_table_pkey.key = $1; EXECUTE local_dist_table_join_select(10); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) EXECUTE local_dist_table_join_select(10); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) EXECUTE local_dist_table_join_select(10); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) EXECUTE local_dist_table_join_select(10); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) EXECUTE local_dist_table_join_select(10); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 (1 row) EXECUTE local_dist_table_join_select(10); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((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)) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.postgres_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 10) count --------------------------------------------------------------------- 1 @@ -942,34 +942,34 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c PREPARE local_dist_table_join_update(int) AS UPDATE postgres_table SET key = 5 FROM distributed_table_pkey WHERE distributed_table_pkey.key = $1; EXECUTE local_dist_table_join_update(20); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) EXECUTE local_dist_table_join_update(20); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) EXECUTE local_dist_table_join_update(20); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) EXECUTE local_dist_table_join_update(20); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) EXECUTE local_dist_table_join_update(20); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) EXECUTE local_dist_table_join_update(20); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (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)) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 20) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.postgres_table SET key = 5 FROM (SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 20) PREPARE local_dist_table_join_subquery(int) AS SELECT COUNT(*) FROM postgres_table JOIN (SELECT * FROM distributed_table_pkey JOIN local_partitioned_table USING(key) WHERE distributed_table_pkey.key = $1) foo USING(key); EXECUTE local_dist_table_join_subquery(5); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) count --------------------------------------------------------------------- @@ -977,9 +977,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) EXECUTE local_dist_table_join_subquery(5); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) count --------------------------------------------------------------------- @@ -987,9 +987,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) EXECUTE local_dist_table_join_subquery(5); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) count --------------------------------------------------------------------- @@ -997,9 +997,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) EXECUTE local_dist_table_join_subquery(5); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) count --------------------------------------------------------------------- @@ -1007,9 +1007,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) EXECUTE local_dist_table_join_subquery(5); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) count --------------------------------------------------------------------- @@ -1017,9 +1017,9 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) EXECUTE local_dist_table_join_subquery(5); -DEBUG: Wrapping relation "distributed_table_pkey" to a subquery: SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::text AS value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) -DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((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)) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) +DEBUG: Wrapping relation "distributed_table_pkey" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table_pkey WHERE (key OPERATOR(pg_catalog.=) 5) +DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table_pkey.key, distributed_table_pkey.value, distributed_table_pkey.value_2, local_partitioned_table.value FROM ((SELECT distributed_table_pkey_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_pkey_1) distributed_table_pkey JOIN local_table_join.local_partitioned_table USING (key)) WHERE (distributed_table_pkey.key OPERATOR(pg_catalog.=) 5) DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text)) foo(key, value, value_2, value_1) USING (key)) count --------------------------------------------------------------------- @@ -1034,54 +1034,54 @@ PREPARE local_dist_table_join_filters(int) AS SELECT COUNT(*) FROM local_partiti distributed_table_composite.value = 'text' ); EXECUTE local_dist_table_join_filters(20); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_table JOIN (SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 2 (1 row) EXECUTE local_dist_table_join_filters(20); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_table JOIN (SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 2 (1 row) EXECUTE local_dist_table_join_filters(20); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_table JOIN (SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 2 (1 row) EXECUTE local_dist_table_join_filters(20); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_table JOIN (SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 2 (1 row) EXECUTE local_dist_table_join_filters(20); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_table JOIN (SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 2 (1 row) EXECUTE local_dist_table_join_filters(20); -DEBUG: Wrapping relation "distributed_table_composite" to a subquery: SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::jsonb AS value_2 FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_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)) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Wrapping relation "distributed_table_composite" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM local_table_join.distributed_table_composite WHERE ((key OPERATOR(pg_catalog.=) 20) OR (key OPERATOR(pg_catalog.=) 20) OR ((key OPERATOR(pg_catalog.=) 10) AND (key OPERATOR(pg_catalog.>) 0)) OR (value OPERATOR(pg_catalog.=) 'text'::text)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.local_partitioned_table JOIN (SELECT distributed_table_composite_1.key, distributed_table_composite_1.value, NULL::jsonb AS value_2 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)) distributed_table_composite_1) distributed_table_composite USING (key)) WHERE ((distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR (distributed_table_composite.key OPERATOR(pg_catalog.=) 20) OR ((distributed_table_composite.key OPERATOR(pg_catalog.=) 10) AND (distributed_table_composite.key OPERATOR(pg_catalog.>) 0)) OR (distributed_table_composite.value OPERATOR(pg_catalog.=) 'text'::text)) count --------------------------------------------------------------------- 2 diff --git a/src/test/regress/expected/mixed_relkind_tests.out b/src/test/regress/expected/mixed_relkind_tests.out index 0c40cc1a2..6abf7e65d 100644 --- a/src/test/regress/expected/mixed_relkind_tests.out +++ b/src/test/regress/expected/mixed_relkind_tests.out @@ -320,27 +320,27 @@ $$); SET client_min_messages TO DEBUG1; SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN distributed_table ON (true); -DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.distributed_table ON (true)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table_1) partitioned_postgres_local_table JOIN mixed_relkind_tests.distributed_table ON (true)) count --------------------------------------------------------------------- 36 (1 row) SELECT COUNT(*) FROM partitioned_postgres_local_table JOIN partitioned_distributed_table ON (true); -DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table JOIN mixed_relkind_tests.partitioned_distributed_table ON (true)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT NULL::integer AS a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table_1) partitioned_postgres_local_table JOIN mixed_relkind_tests.partitioned_distributed_table ON (true)) count --------------------------------------------------------------------- 36 (1 row) SELECT COUNT(*) FROM distributed_table JOIN partitioned_postgres_local_table ON (true); -DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true +DEBUG: Wrapping relation "partitioned_postgres_local_table" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.partitioned_postgres_local_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (mixed_relkind_tests.distributed_table JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table ON (true)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (mixed_relkind_tests.distributed_table JOIN (SELECT NULL::integer AS a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) partitioned_postgres_local_table_1) partitioned_postgres_local_table ON (true)) count --------------------------------------------------------------------- 36 @@ -348,21 +348,21 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c INSERT INTO partitioned_distributed_table SELECT foo.* FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true +DEBUG: Wrapping relation "citus_local_table" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a, foo.b FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a, foo.b FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT NULL::integer AS a 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 ON (true)) DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO partitioned_distributed_table SELECT foo.* FROM distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true +DEBUG: Wrapping relation "citus_local_table" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.distributed_table foo JOIN (SELECT NULL::integer AS a 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 ON (true)) DEBUG: performing repartitioned INSERT ... SELECT INSERT INTO distributed_table SELECT foo.a FROM partitioned_distributed_table AS foo JOIN citus_local_table ON (true); DEBUG: distributed INSERT ... SELECT cannot select from distributed tables and local tables at the same time -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true +DEBUG: Wrapping relation "citus_local_table" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS a FROM mixed_relkind_tests.citus_local_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table ON (true)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM (mixed_relkind_tests.partitioned_distributed_table foo JOIN (SELECT NULL::integer AS a 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 ON (true)) DEBUG: performing repartitioned INSERT ... SELECT -- should fail SELECT COUNT(*) FROM reference_table LEFT JOIN partitioned_distributed_table ON true; @@ -392,26 +392,26 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c (1 row) UPDATE partitioned_distributed_table SET b = foo.a FROM citus_local_table AS foo; -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true +DEBUG: Wrapping relation "citus_local_table" "foo" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT foo_1.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo_1) foo UPDATE partitioned_distributed_table SET b = foo.a FROM postgres_local_table AS foo; -DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true +DEBUG: Wrapping relation "postgres_local_table" "foo" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET b = foo.a FROM (SELECT foo_1.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo_1) foo UPDATE partitioned_distributed_table SET a = foo.a FROM postgres_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping relation "postgres_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true +DEBUG: Wrapping relation "postgres_local_table" "foo" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.postgres_local_table foo WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT foo_1.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo_1) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) UPDATE partitioned_distributed_table SET a = foo.a FROM citus_local_table AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping relation "citus_local_table" to a subquery: SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true +DEBUG: Wrapping relation "citus_local_table" "foo" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT foo_1.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) foo_1) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) -- should fail UPDATE partitioned_distributed_table SET a = foo.a FROM mat_view_on_part_dist AS foo WHERE foo.a = partitioned_distributed_table.a; -DEBUG: Wrapping relation "mat_view_on_part_dist" to a subquery: SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT a, NULL::integer AS b FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a 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)) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) +DEBUG: Wrapping relation "mat_view_on_part_dist" "foo" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.mat_view_on_part_dist foo WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE mixed_relkind_tests.partitioned_distributed_table SET a = foo.a FROM (SELECT foo_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)) foo_1) foo WHERE (foo.a OPERATOR(pg_catalog.=) partitioned_distributed_table.a) UPDATE partitioned_distributed_table SET a = foo.a FROM partitioned_distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns UPDATE partitioned_distributed_table SET a = foo.a FROM distributed_table AS foo WHERE foo.a < partitioned_distributed_table.a; diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out index adfe0bf26..840343aa0 100644 --- a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out +++ b/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out @@ -31,9 +31,9 @@ SELECT count(*) FROM distributed_table u1 JOIN distributed_table u2 USING(key) JOIN local_table USING (key); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN push_down_filters.distributed_table u2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) local_table USING (key)) +DEBUG: Wrapping relation "local_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM push_down_filters.local_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN push_down_filters.distributed_table u2 USING (key)) JOIN (SELECT local_table_1.key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) local_table_1) local_table USING (key)) count --------------------------------------------------------------------- 0 @@ -44,9 +44,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING (key) WHERE u2.key > ANY(ARRAY[2, 1, 6]); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) -DEBUG: generating subplan XXX_1 for subquery SELECT key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (u2.key OPERATOR(pg_catalog.>) ANY (ARRAY[2, 1, 6])) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM push_down_filters.local_table u2 WHERE (key OPERATOR(pg_catalog.>) ANY ('{2,1,6}'::integer[])) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, NULL::integer AS value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) u2_1) u2 USING (key)) WHERE (u2.key OPERATOR(pg_catalog.>) ANY (ARRAY[2, 1, 6])) count --------------------------------------------------------------------- 0 @@ -57,9 +57,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(key) WHERE ARRAY[u2.key, u2.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (key)) WHERE (ARRAY[u2.key, u2.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table u2 WHERE (ARRAY[key, value] OPERATOR(pg_catalog.@>) '{2,3}'::integer[]) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer)) u2_1) u2 USING (key)) WHERE (ARRAY[u2.key, u2.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count --------------------------------------------------------------------- 0 @@ -70,9 +70,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE ARRAY[u2.value, u1.value] @> (ARRAY[2, 3]); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ARRAY[u2.value, u1.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (ARRAY[u2.value, u1.value] OPERATOR(pg_catalog.@>) ARRAY[2, 3]) count --------------------------------------------------------------------- 0 @@ -83,9 +83,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value/2.0 > 2)::int::bool::text::bool; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) (2)::numeric))::integer)::boolean)::text)::boolean +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE (((((((value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) '2'::numeric))::integer)::boolean)::text)::boolean +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (((((((u2.value)::numeric OPERATOR(pg_catalog./) 2.0) OPERATOR(pg_catalog.>) (2)::numeric))::integer)::boolean)::text)::boolean count --------------------------------------------------------------------- 0 @@ -96,9 +96,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u2.value > 3 THEN u2.value > 2 ELSE false END); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u2.value OPERATOR(pg_catalog.>) 3) THEN (u2.value OPERATOR(pg_catalog.>) 2) ELSE false END +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE CASE WHEN (value OPERATOR(pg_catalog.>) 3) THEN (value OPERATOR(pg_catalog.>) 2) ELSE false END +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE CASE WHEN (u2.value OPERATOR(pg_catalog.>) 3) THEN (u2.value OPERATOR(pg_catalog.>) 2) ELSE false END count --------------------------------------------------------------------- 0 @@ -109,9 +109,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (CASE WHEN u1.value > 4000 THEN u2.value / 100 > 1 ELSE false END); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE CASE WHEN (u1.value OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE CASE WHEN (u1.value OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END count --------------------------------------------------------------------- 0 @@ -122,9 +122,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE COALESCE((u2.key/5.0)::int::bool, false); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE COALESCE(((((u2.key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table u2 WHERE COALESCE(((((key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer)) u2_1) u2 USING (value)) WHERE COALESCE(((((u2.key)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count --------------------------------------------------------------------- 0 @@ -135,9 +135,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE NULLIF((u2.value/5.0)::int::bool, false); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE NULLIF(((((u2.value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE NULLIF(((((value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE NULLIF(((((u2.value)::numeric OPERATOR(pg_catalog./) 5.0))::integer)::boolean, false) count --------------------------------------------------------------------- 0 @@ -148,9 +148,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value IS NOT NULL; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value IS NOT NULL) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE (value IS NOT NULL) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (u2.value IS NOT NULL) count --------------------------------------------------------------------- 0 @@ -161,9 +161,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE isfinite(u2.time); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE isfinite(u2."time") +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value, "time" FROM push_down_filters.local_table u2 WHERE isfinite("time") +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, u2_1."time" FROM (SELECT intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer, "time" timestamp with time zone)) u2_1) u2 USING (value)) WHERE isfinite(u2."time") count --------------------------------------------------------------------- 0 @@ -174,9 +174,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.value, u1.value) = 55; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.value, u1.value) OPERATOR(pg_catalog.=) 55) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (int4smaller(u2.value, u1.value) OPERATOR(pg_catalog.=) 55) count --------------------------------------------------------------------- 0 @@ -187,9 +187,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE int4smaller(u2.key, u2.value) = u2.key; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (int4smaller(u2.key, u2.value) OPERATOR(pg_catalog.=) u2.key) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table u2 WHERE (int4smaller(key, value) OPERATOR(pg_catalog.=) key) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer)) u2_1) u2 USING (value)) WHERE (int4smaller(u2.key, u2.value) OPERATOR(pg_catalog.=) u2.key) count --------------------------------------------------------------------- 0 @@ -200,9 +200,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE row(u2.value, 2, 3) > row(u2.value, 2, 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(u2.value, 2, 3)) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(value, 2, 3)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(u2.value, 2, 3)) count --------------------------------------------------------------------- 0 @@ -220,9 +220,9 @@ JOIN local_table u2 USING(value) isfinite(u2.time) AND u2.value IS DISTINCT FROM 50040 AND row(u2.value, 2, 3) > row(2000, 2, 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) +DEBUG: Wrapping relation "local_table" "u2" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT key, value, "time" FROM push_down_filters.local_table u2 WHERE (((((((key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (key OPERATOR(pg_catalog.>) 4000) THEN ((value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite("time") AND (value IS DISTINCT FROM 50040) AND (ROW(value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((((((u2.key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (u2.key OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((u2.key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((u2.value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite(u2."time") AND (u2.value IS DISTINCT FROM 50040) AND (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, u2_1."time" FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2_1) u2 USING (value)) WHERE (((((((u2.key)::numeric OPERATOR(pg_catalog./) 1.0))::integer)::boolean)::text)::boolean AND CASE WHEN (u2.key OPERATOR(pg_catalog.>) 4000) THEN ((u2.value OPERATOR(pg_catalog./) 100) OPERATOR(pg_catalog.>) 1) ELSE false END AND COALESCE(((u2.key OPERATOR(pg_catalog./) 50000))::boolean, false) AND NULLIF(((u2.value OPERATOR(pg_catalog./) 50000))::boolean, false) AND isfinite(u2."time") AND (u2.value IS DISTINCT FROM 50040) AND (ROW(u2.value, 2, 3) OPERATOR(pg_catalog.>) ROW(2000, 2, 3))) count --------------------------------------------------------------------- 0 @@ -236,9 +236,9 @@ WHERE u2.value > (SELECT avg(key) FROM distributed_table); DEBUG: generating subplan XXX_1 for subquery SELECT avg(key) AS avg FROM push_down_filters.distributed_table -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value)::numeric OPERATOR(pg_catalog.>) (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric))) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE ((u2.value)::numeric OPERATOR(pg_catalog.>) (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric))) count --------------------------------------------------------------------- 0 @@ -249,9 +249,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > (SELECT 5); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u2.value OPERATOR(pg_catalog.>) (SELECT 5)) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (u2.value OPERATOR(pg_catalog.>) (SELECT 5)) count --------------------------------------------------------------------- 0 @@ -262,9 +262,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value * u1.key > 25; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.*) u1.key) OPERATOR(pg_catalog.>) 25) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.*) u1.key) OPERATOR(pg_catalog.>) 25) count --------------------------------------------------------------------- 0 @@ -277,9 +277,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value = 3; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.=) 3) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE (value OPERATOR(pg_catalog.=) 3) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.=) 3) count --------------------------------------------------------------------- 0 @@ -290,9 +290,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.value > 3; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.>) 3) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (u1.value OPERATOR(pg_catalog.>) 3) count --------------------------------------------------------------------- 0 @@ -304,9 +304,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u1.key = 3; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (u1.key OPERATOR(pg_catalog.=) 3) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE (u1.key OPERATOR(pg_catalog.=) 3) count --------------------------------------------------------------------- 0 @@ -317,9 +317,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 4 OR u2.value = 4; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 4) OR (u2.value OPERATOR(pg_catalog.=) 4)) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 4) OR (value OPERATOR(pg_catalog.=) 4)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 4) OR (u2.value OPERATOR(pg_catalog.=) 4)) count --------------------------------------------------------------------- 0 @@ -330,9 +330,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE u2.value > 2 and u2.time IS NULL; -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND (u2."time" IS NULL)) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value, "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) AND ("time" IS NULL)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, u2_1."time" FROM (SELECT intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer, "time" timestamp with time zone)) u2_1) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND (u2."time" IS NULL)) count --------------------------------------------------------------------- 0 @@ -344,9 +344,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer)) u2_1) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- 0 @@ -358,9 +358,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) OR (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL) OR ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer)) u2_1) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL) OR ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- 0 @@ -372,9 +372,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u2.value IS NULL) AND (u2.key > 4 OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table u2 WHERE ((value OPERATOR(pg_catalog.>) 2) OR (value IS NULL)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer)) u2_1) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u2.value IS NULL)) AND ((u2.key OPERATOR(pg_catalog.>) 4) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- 0 @@ -385,9 +385,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 OR u1.value IS NULL) AND (u2.key = 10000 * random() OR u1.key > 3); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u1.value IS NULL)) AND (((u2.key)::double precision OPERATOR(pg_catalog.=) ((10000)::double precision OPERATOR(pg_catalog.*) random())) OR (u1.key OPERATOR(pg_catalog.>) 3))) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table u2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT u2_1.key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer)) u2_1) u2 USING (value)) WHERE (((u2.value OPERATOR(pg_catalog.>) 2) OR (u1.value IS NULL)) AND (((u2.key)::double precision OPERATOR(pg_catalog.=) ((10000)::double precision OPERATOR(pg_catalog.*) random())) OR (u1.key OPERATOR(pg_catalog.>) 3))) count --------------------------------------------------------------------- 0 @@ -398,9 +398,9 @@ SELECT count(*) FROM distributed_table u1 JOIN local_table u2 USING(value) WHERE (u2.value > 2 AND false); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE false +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) count --------------------------------------------------------------------- 0 @@ -418,9 +418,9 @@ JOIN LATERAL WHERE u2.value = 15) AS u3 USING (value) WHERE (u2.value > 2 AND FALSE); -DEBUG: Wrapping relation "local_table" to a subquery: SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false -DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key, value, NULL::timestamp with time zone AS "time" FROM push_down_filters.local_table u2 WHERE false -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result."time" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value integer, "time" timestamp with time zone)) u2 USING (value)) JOIN LATERAL (SELECT distributed_table.value, random() AS random FROM push_down_filters.distributed_table WHERE (u2.value OPERATOR(pg_catalog.=) 15)) u3 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) +DEBUG: Wrapping relation "local_table" "u2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table u2 WHERE false +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((push_down_filters.distributed_table u1 JOIN (SELECT NULL::integer AS key, u2_1.value, NULL::timestamp with time zone AS "time" FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value integer)) u2_1) u2 USING (value)) JOIN LATERAL (SELECT distributed_table.value, random() AS random FROM push_down_filters.distributed_table WHERE (u2.value OPERATOR(pg_catalog.=) 15)) u3 USING (value)) WHERE ((u2.value OPERATOR(pg_catalog.>) 2) AND false) ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns \set VERBOSITY terse RESET client_min_messages; From f7c1509fedaac24255164294f99d975ac1d5a3f0 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Thu, 10 Dec 2020 20:03:46 +0300 Subject: [PATCH 31/37] Not check if the query is routable for converting It seems that there are only very few cases where that is useful, and for now we prefer not having that check. This means that we might perform some unnecessary checks, but that should be rare and not performance critical. --- .../planner/local_distributed_join_planner.c | 9 ----- .../planner/multi_router_planner.c | 35 ------------------- .../distributed/multi_router_planner.h | 2 -- .../expected/citus_local_dist_joins.out | 14 +++++--- 4 files changed, 10 insertions(+), 50 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 17c35150b..3f587dde0 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -335,15 +335,6 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, { return false; } - - plannerRestrictionContext = FilterPlannerRestrictionForQuery( - plannerRestrictionContext, query); - if (IsRouterPlannable(query, plannerRestrictionContext)) - { - ereport(DEBUG1, (errmsg("local-distributed table joins will not be converted, " - "as the query is router plannable"))); - return false; - } return true; } diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index cc39b88cd..41406688d 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -291,41 +291,6 @@ CreateSingleTaskRouterSelectPlan(DistributedPlan *distributedPlan, Query *origin } -/* - * IsRouterPlannable returns true if the given query can be planned by - * router planner. - */ -bool -IsRouterPlannable(Query *query, PlannerRestrictionContext *plannerRestrictionContext) -{ - /* copy the query as the following methods can change the underlying query */ - Query *copyQuery = copyObject(query); - DeferredErrorMessage *deferredErrorMessage = NULL; - if (copyQuery->commandType == CMD_SELECT) - { - deferredErrorMessage = DeferErrorIfUnsupportedRouterPlannableSelectQuery( - copyQuery); - } - if (deferredErrorMessage) - { - return false; - } - - if (IsModifyCommand(query)) - { - deferredErrorMessage = ModifyQuerySupported(copyQuery, copyQuery, false, - plannerRestrictionContext); - if (deferredErrorMessage) - { - return false; - } - } - - RouterJob(copyQuery, plannerRestrictionContext, &deferredErrorMessage); - return deferredErrorMessage == NULL; -} - - /* * ShardIntervalOpExpressions returns a list of OpExprs with exactly two * items in it. The list consists of shard interval ranges with partition columns diff --git a/src/include/distributed/multi_router_planner.h b/src/include/distributed/multi_router_planner.h index 16e4576b3..40cbaf447 100644 --- a/src/include/distributed/multi_router_planner.h +++ b/src/include/distributed/multi_router_planner.h @@ -88,8 +88,6 @@ extern void GenerateSingleShardRouterTaskList(Job *job, List *placementList, uint64 shardId, bool isLocalTableModification); -extern bool IsRouterPlannable(Query *query, - PlannerRestrictionContext *plannerRestrictionContext); /* * FastPathPlanner is a subset of router planner, that's why we prefer to diff --git a/src/test/regress/expected/citus_local_dist_joins.out b/src/test/regress/expected/citus_local_dist_joins.out index cd41f66a4..664a3bdcd 100644 --- a/src/test/regress/expected/citus_local_dist_joins.out +++ b/src/test/regress/expected/citus_local_dist_joins.out @@ -434,8 +434,11 @@ SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distribut DEBUG: push down of limit count: 1 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM citus_local_dist_joins.distributed_table LIMIT 1 DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM citus_local_dist_joins.citus_local -DEBUG: local-distributed table joins will not be converted, as the query is router plannable -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((citus_local_dist_joins.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN citus_local_dist_joins.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT key FROM citus_local_dist_joins.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_4 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) count --------------------------------------------------------------------- 0 @@ -445,8 +448,11 @@ SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distribut DEBUG: push down of limit count: 1 DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM citus_local_dist_joins.distributed_table LIMIT 1 DEBUG: generating subplan XXX_2 for subquery SELECT key, value FROM citus_local_dist_joins.citus_local -DEBUG: local-distributed table joins will not be converted, as the query is router plannable -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((citus_local_dist_joins.postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN citus_local_dist_joins.citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT key FROM citus_local_dist_joins.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Wrapping relation "citus_local" to a subquery +DEBUG: generating subplan XXX_4 for subquery SELECT key FROM citus_local_dist_joins.citus_local WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: 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_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table JOIN (SELECT d1.key, d1.value, d1.value_2 FROM (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)) d1) d2 USING (key)) JOIN citus_local_dist_joins.reference_table USING (key)) JOIN (SELECT citus_local_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) citus_local_1) citus_local USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) c1 USING (key)) WHERE ((d2.key OPERATOR(pg_catalog.>) 10) AND (d2.key OPERATOR(pg_catalog.=) 10)) count --------------------------------------------------------------------- 0 From f5dd5379b2eb740618e7f51d5c27f26a3fe49636 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Thu, 10 Dec 2020 21:31:26 +0300 Subject: [PATCH 32/37] Add more tests --- .../planner/local_distributed_join_planner.c | 37 ++-- .../planner/multi_physical_planner.c | 12 +- .../planner/multi_router_planner.c | 23 ++- .../planner/query_colocation_checker.c | 35 ++++ .../distributed/planner/recursive_planning.c | 56 ++---- .../expected/citus_local_tables_queries.out | 3 +- .../expected/coordinator_shouldhaveshards.out | 2 +- .../regress/expected/local_table_join.out | 161 ++++++++++++++++++ ...elation_planning_restriction_pushdown.out} | 50 +++++- ...licate_reference_tables_to_coordinator.out | 14 +- src/test/regress/multi_schedule | 2 +- src/test/regress/sql/local_table_join.sql | 34 ++++ ...elation_planning_restriction_pushdown.sql} | 24 +++ 13 files changed, 364 insertions(+), 89 deletions(-) rename src/test/regress/expected/{recursive_relation_planning_restirction_pushdown.out => recursive_relation_planning_restriction_pushdown.out} (90%) rename src/test/regress/sql/{recursive_relation_planning_restirction_pushdown.sql => recursive_relation_planning_restriction_pushdown.sql} (90%) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 3f587dde0..c1c3fb048 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -125,6 +125,7 @@ #include "utils/guc.h" #include "utils/lsyscache.h" +#define INVALID_RTE_IDENTITY -1 /* * Managed via a GUC @@ -158,8 +159,8 @@ static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, static ConversionCandidates * CreateConversionCandidates(PlannerRestrictionContext * plannerRestrictionContext, List *rangeTableList, - Oid resultRelationId); -static void GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexes); + int resultRTEIdentity); +static void AppendUniqueIndexColumnsToList(Form_pg_index indexForm, List **uniqueIndexes); static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(ConversionCandidates * conversionCandidates, PlannerRestrictionContext * @@ -167,7 +168,7 @@ static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(ConversionCandidat static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, int rteIdentity); static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList); -static bool FirstIntListContainsSecondIntList(List *firstIntList, List *secondIntList); +static bool FirstIsSuperSetOfSecond(List *firstIntList, List *secondIntList); /* * RecursivelyPlanLocalTableJoins gets a query and the planner @@ -181,14 +182,15 @@ RecursivelyPlanLocalTableJoins(Query *query, PlannerRestrictionContext *plannerRestrictionContext = GetPlannerRestrictionContext(context); - Oid resultRelationId = InvalidOid; + int resultRTEIdentity = INVALID_RTE_IDENTITY; if (IsModifyCommand(query)) { - resultRelationId = ModifyQueryResultRelationId(query); + RangeTblEntry *resultRTE = ExtractResultRelationRTE(query); + resultRTEIdentity = GetRTEIdentity(resultRTE); } ConversionCandidates *conversionCandidates = CreateConversionCandidates(plannerRestrictionContext, - rangeTableList, resultRelationId); + rangeTableList, resultRTEIdentity); while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, plannerRestrictionContext)) @@ -362,12 +364,12 @@ HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, FetchEqualityAttrNumsForRTE((Node *) restrictClauseList); List *uniqueIndexColumnsList = ExecuteFunctionOnEachTableIndex(rangeTableEntry->relid, - GetAllUniqueIndexes); + AppendUniqueIndexColumnsToList); IndexColumns *indexColumns = NULL; foreach_ptr(indexColumns, uniqueIndexColumnsList) { List *uniqueIndexColumnNos = indexColumns->indexColumnNos; - if (FirstIntListContainsSecondIntList(rteEqualityColumnsNos, + if (FirstIsSuperSetOfSecond(rteEqualityColumnsNos, uniqueIndexColumnNos)) { return true; @@ -378,11 +380,11 @@ HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, /* - * FirstIntListContainsSecondIntList returns true if the first int List + * FirstIsSuperSetOfSecond returns true if the first int List * contains every element of the second int List. */ static bool -FirstIntListContainsSecondIntList(List *firstIntList, List *secondIntList) +FirstIsSuperSetOfSecond(List *firstIntList, List *secondIntList) { int curInt = 0; foreach_int(curInt, secondIntList) @@ -397,13 +399,11 @@ FirstIntListContainsSecondIntList(List *firstIntList, List *secondIntList) /* - * GetAllUniqueIndexes adds the given index's column numbers if it is a + * AppendUniqueIndexColumnsToList adds the given index's column numbers if it is a * unique index. - * TODO:: if there is a unique index on a multiple column, then we should - * probably return true only if all the columns in the index exist in the filter. */ static void -GetAllUniqueIndexes(Form_pg_index indexForm, List **uniqueIndexGroups) +AppendUniqueIndexColumnsToList(Form_pg_index indexForm, List **uniqueIndexGroups) { if (indexForm->indisunique || indexForm->indisprimary) { @@ -471,22 +471,25 @@ RequiredAttrNumbersForRelation(RangeTblEntry *rangeTableEntry, */ static ConversionCandidates * CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, - List *rangeTableList, Oid resultRelationId) + List *rangeTableList, int resultRTEIdentity) { ConversionCandidates *conversionCandidates = palloc0(sizeof(ConversionCandidates)); + RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) { + /* we're only interested in tables */ if (!IsRecursivelyPlannableRelation(rangeTableEntry)) { continue; } + int rteIdentity = GetRTEIdentity(rangeTableEntry); /* result relation cannot converted to a subquery */ - if (resultRelationId == rangeTableEntry->relid) + if (resultRTEIdentity == rteIdentity) { continue; } @@ -497,7 +500,7 @@ CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, { continue; } - int rteIdentity = GetRTEIdentity(rangeTableEntry); + RangeTableEntryDetails *rangeTableEntryDetails = palloc0(sizeof(RangeTableEntryDetails)); diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index d838fc40a..995dfad5c 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -3639,9 +3639,7 @@ NodeIsRangeTblRefReferenceTable(Node *node, List *rangeTableList) /* * FetchEqualityAttrNumsForRTE fetches the attribute numbers from quals - * which: - * - has equality operator - * - belongs to rangeTableEntry with rteIndex + * which has equality operator */ List * FetchEqualityAttrNumsForRTE(Node *node) @@ -3699,9 +3697,7 @@ FetchEqualityAttrNumsForList(List *nodeList) /* * FetchEqualityAttrNumsForRTEOpExpr fetches the attribute numbers from opExpr - * which: - * - has equality operator - * - belongs to rangeTableEntry with rteIndex + * which has equality operator. */ static List * FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr) @@ -3723,9 +3719,7 @@ FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr) /* * FetchEqualityAttrNumsForRTEBoolExpr fetches the attribute numbers from boolExpr - * which: - * - has equality operator - * - belongs to rangeTableEntry with rteIndex + * which has equality operator */ static List * FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr) diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 41406688d..788d0f486 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -520,19 +520,8 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, { return deferredError; } - uint32 rangeTableId = 1; CmdType commandType = queryTree->commandType; - Oid resultRelationId = ModifyQueryResultRelationId(queryTree); - *distributedTableIdOutput = resultRelationId; - - Var *partitionColumn = NULL; - - if (IsCitusTable(resultRelationId)) - { - partitionColumn = PartitionColumn(resultRelationId, rangeTableId); - } - deferredError = DeferErrorIfModifyView(queryTree); if (deferredError != NULL) { @@ -624,9 +613,13 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, } } - resultRelationId = ModifyQueryResultRelationId(queryTree); - rangeTableId = 1; + + Oid resultRelationId = ModifyQueryResultRelationId(queryTree); + *distributedTableIdOutput = resultRelationId; + uint32 rangeTableId = 1; + + Var *partitionColumn = NULL; if (IsCitusTable(resultRelationId)) { partitionColumn = PartitionColumn(resultRelationId, rangeTableId); @@ -2265,6 +2258,10 @@ PlanRouterQuery(Query *originalQuery, } +/* + * ContainsOnlyLocalTables returns true if there is only + * local tables and not any distributed or reference table. + */ static bool ContainsOnlyLocalTables(RTEListProperties *rteProperties) { diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index dd010f652..864fd6dcb 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -47,6 +47,7 @@ static RangeTblEntry * AnchorRte(Query *subquery); static List * UnionRelationRestrictionLists(List *firstRelationList, List *secondRelationList); +static void MakeVarAttNosSequential(List *targetList); /* @@ -261,6 +262,9 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker) * Note that the query returned by this function does not contain any filters or * projections. The returned query should be used cautiosly and it is mostly * designed for generating a stub query. + * + * allTargetList will contain all columns for the given rteRelation but for the ones + * that are not required, it will have NULL entries. */ Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes, @@ -300,6 +304,11 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes if (shouldAssignDummyNullColumn && !assignedDummyNullColumn) { + /* + * in case there is no required column, we assign one dummy NULL target entry + * to the subquery targetList so that it has at least one target. + * (targetlist should have at least one element) + */ subquery->targetList = lappend(subquery->targetList, targetEntry); assignedDummyNullColumn = true; } @@ -329,12 +338,38 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes subquery->targetList = lappend(subquery->targetList, targetEntry); } } + MakeVarAttNosSequential(*allTargetList); relation_close(relation, NoLock); return subquery; } +/* + * MakeVarAttNosSequential changes the attribute numbers of the given targetList + * to sequential numbers, [1, 2, 3] ... + */ +static void +MakeVarAttNosSequential(List *targetList) +{ + TargetEntry *entry = NULL; + int attrNo = 1; + foreach_ptr(entry, targetList) + { + if (IsA(entry->expr, Var)) + { + Var *var = (Var *) entry->expr; + + /* + * the inner subquery is an intermediate result hence + * the attribute no's should be in ordinal order. [1, 2, 3...] + */ + var->varattno = attrNo++; + } + } +} + + /* * UnionRelationRestrictionLists merges two relation restriction lists diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index d6b87a39d..61477b709 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -197,8 +197,7 @@ static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, List **joinRangeTableEntries); static Query * CreateOuterSubquery(RangeTblEntry *rangeTableEntry, - List *allTargetList, List *requiredAttrNumbers); -static void MakeVarAttNosSequential(List *targetList); + List *outerSubqueryTargetList); static List * GenerateRequiredColNamesFromTargetList(List *targetList); static char * GetRelationNameAndAliasName(RangeTblEntry *rangeTablentry); @@ -371,8 +370,6 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or * a query with local table/citus local table and subquery. We convert local/citus local * tables to a subquery until they can be planned. - * This is the last call in this function since we want the other calls to be finished - * so that we can check if the current plan is router plannable at any step within this function. */ RecursivelyPlanLocalTableJoins(query, context, rangeTableList); } @@ -1462,15 +1459,24 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, RecursivePlanningContext *context) { - List *allTargetList = NIL; + List *outerQueryTargetList = NIL; Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers, - &allTargetList); + &outerQueryTargetList); List *restrictionList = GetRestrictInfoListForRelation(rangeTableEntry, context->plannerRestrictionContext); List *copyRestrictionList = copyObject(restrictionList); Expr *andedBoundExpressions = make_ands_explicit(copyRestrictionList); subquery->jointree->quals = (Node *) andedBoundExpressions; + /* + * Originally the quals were pointing to the RTE and its varno + * was pointing to its index in rtable. However now we converted the RTE + * to a subquery and the quals should be pointing to that subquery, which + * is the only RTE in its rtable, hence we update the varnos so that they + * point to the subquery RTE. + * Originally: rtable: [rte1, current_rte, rte3...] + * Now: rtable: [rte1, subquery[current_rte], rte3...] --subquery[current_rte] refers to its rtable. + */ UpdateVarNosInNode(subquery, SINGLE_RTE_INDEX); /* replace the function with the constructed subquery */ @@ -1499,8 +1505,7 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, "unexpected state: query should have been recursively planned"))); } - Query *outerSubquery = CreateOuterSubquery(rangeTableEntry, allTargetList, - requiredAttrNumbers); + Query *outerSubquery = CreateOuterSubquery(rangeTableEntry, outerQueryTargetList); rangeTableEntry->subquery = outerSubquery; } @@ -1534,11 +1539,9 @@ GetRelationNameAndAliasName(RangeTblEntry *rangeTableEntry) * the given range table entry in its rtable. */ static Query * -CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *allTargetList, - List *requiredAttrNumbers) +CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *outerSubqueryTargetList) { - MakeVarAttNosSequential(allTargetList); - List *innerSubqueryColNames = GenerateRequiredColNamesFromTargetList(allTargetList); + List *innerSubqueryColNames = GenerateRequiredColNamesFromTargetList(outerSubqueryTargetList); Query *outerSubquery = makeNode(Query); outerSubquery->commandType = CMD_SELECT; @@ -1554,36 +1557,11 @@ CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *allTargetList, newRangeTableRef->rtindex = 1; outerSubquery->jointree = makeFromExpr(list_make1(newRangeTableRef), NULL); - outerSubquery->targetList = allTargetList; + outerSubquery->targetList = outerSubqueryTargetList; return outerSubquery; } -/* - * MakeVarAttNosSequential changes the attribute numbers of the given targetList - * to sequential numbers, [1, 2, 3] ... - */ -static void -MakeVarAttNosSequential(List *targetList) -{ - TargetEntry *entry = NULL; - int attrNo = 1; - foreach_ptr(entry, targetList) - { - if (IsA(entry->expr, Var)) - { - Var *var = (Var *) entry->expr; - - /* - * the inner subquery is an intermediate result hence - * the attribute no's should be in ordinal order. [1, 2, 3...] - */ - var->varattno = attrNo++; - } - } -} - - /* * GenerateRequiredColNamesFromTargetList generates the required colnames * from the given target list. @@ -1612,7 +1590,7 @@ GenerateRequiredColNamesFromTargetList(List *targetList) /* * UpdateVarNosInNode iterates the Vars in the - * given node and updates the varno's as the newVarNo. + * given node's join tree quals and updates the varno's as the newVarNo. */ static void UpdateVarNosInNode(Query *query, Index newVarNo) diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 7fcf05d04..1f6ec90a6 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -818,7 +818,8 @@ NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT co -- view treated as subquery, so should work SELECT count(*) FROM view_3, distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM (citus_local_table_queries.citus_local_table_2_1509001 citus_local_table_2(a, b) JOIN citus_local_table_queries.reference_table_1509002 reference_table(a, b) USING (a)) +NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_2_1509001 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_1509002 reference_table(a, b) USING (a)) count --------------------------------------------------------------------- 6 diff --git a/src/test/regress/expected/coordinator_shouldhaveshards.out b/src/test/regress/expected/coordinator_shouldhaveshards.out index ffb16d44a..c847efb87 100644 --- a/src/test/regress/expected/coordinator_shouldhaveshards.out +++ b/src/test/regress/expected/coordinator_shouldhaveshards.out @@ -438,7 +438,7 @@ WITH cte_1 AS (SELECT * FROM dist_table ORDER BY 1 LIMIT 1) SELECT * FROM ref JOIN local ON (a = x) JOIN cte_1 ON (local.x = cte_1.a); NOTICE: executing the command locally: SELECT a FROM coordinator_shouldhaveshards.dist_table_1503017 dist_table WHERE true ORDER BY a LIMIT '1'::bigint NOTICE: executing the command locally: SELECT a FROM coordinator_shouldhaveshards.dist_table_1503020 dist_table WHERE true ORDER BY a LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y, cte_1.a FROM ((coordinator_shouldhaveshards.ref_1503016 ref JOIN coordinator_shouldhaveshards.local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) cte_1 ON ((local.x OPERATOR(pg_catalog.=) cte_1.a))) +NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y, cte_1.a FROM ((coordinator_shouldhaveshards.ref_1503016 ref JOIN (SELECT local_1.x, local_1.y FROM (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) local_1) local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) cte_1 ON ((local.x OPERATOR(pg_catalog.=) cte_1.a))) a | b | x | y | a --------------------------------------------------------------------- 1 | 2 | 1 | 2 | 1 diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 9592ba95e..ff884f92f 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -316,6 +316,147 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 100 (1 row) +-- similar tests in transaction block should work fine +BEGIN; +-- materialized views should work too +SELECT count(*) FROM distributed_table JOIN mv1 USING(key); +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT mv1_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)) mv1_1) mv1 USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv1 USING(key); +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +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 mv1_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)) mv1_1) mv1 USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM reference_table JOIN mv1 USING(key); +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_table JOIN (SELECT mv1_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)) mv1_1) mv1 USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM distributed_table JOIN mv1 USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping relation "mv1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_table JOIN (SELECT mv1_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)) mv1_1) mv1 USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM distributed_table JOIN mv2 USING(key); +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_table JOIN (SELECT mv2_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)) mv2_1) mv2 USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM (SELECT * FROM distributed_table) d1 JOIN mv2 USING(key); +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +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 mv2_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)) mv2_1) mv2 USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM reference_table JOIN mv2 USING(key); +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.reference_table JOIN (SELECT mv2_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)) mv2_1) mv2 USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM distributed_table JOIN mv2 USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping relation "mv2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.mv2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_table JOIN (SELECT mv2_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)) mv2_1) mv2 USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +-- foreign tables should work too +SELECT count(*) FROM foreign_table JOIN distributed_table USING(key); +DEBUG: Wrapping relation "foreign_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.foreign_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foreign_table_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)) foreign_table_1) foreign_table JOIN local_table_join.distributed_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 relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) WHERE distributed_partitioned_table.key = 10; +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_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_partitioned_table.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_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)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE (key OPERATOR(pg_catalog.=) 10) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.distributed_partitioned_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) WHERE (distributed_partitioned_table.key OPERATOR(pg_catalog.=) 10) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); +DEBUG: Wrapping relation "local_partitioned_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((local_table_join.distributed_partitioned_table JOIN (SELECT local_partitioned_table_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)) local_partitioned_table_1) local_partitioned_table USING (key)) JOIN local_table_join.reference_table USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + +ROLLBACK; -- the conversions should be independent from the order of table entries in the query SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; DEBUG: Wrapping relation "postgres_table" to a subquery @@ -397,6 +538,17 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +-- different column names +SELECT a FROM postgres_table foo (a,b,c) JOIN distributed_table ON (distributed_table.key = foo.a) ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "postgres_table" "foo" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT a AS key FROM local_table_join.postgres_table foo(a, b, c) WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT foo.a FROM ((SELECT foo_1.a AS 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)) foo_1(a)) foo(a, b, c) JOIN local_table_join.distributed_table ON ((distributed_table.key OPERATOR(pg_catalog.=) foo.a))) ORDER BY foo.a LIMIT 1 +DEBUG: push down of limit count: 1 + a +--------------------------------------------------------------------- + 1 +(1 row) + -- We will plan postgres table as the index is on key,value not just key SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; DEBUG: Wrapping relation "postgres_table" to a subquery @@ -478,6 +630,15 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 1 (1 row) +-- Known bug: #4269 +SELECT count(*) FROM distributed_table_composite foo(a,b,c) JOIN postgres_table ON(foo.a > 1) + WHERE foo.a IN (SELECT COUNT(*) FROM local_partitioned_table) AND (foo.a = 10 OR foo.b ='text'); +DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM local_table_join.local_partitioned_table +DEBUG: Wrapping relation "distributed_table_composite" "foo" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT a AS key, b AS value FROM local_table_join.distributed_table_composite foo(a, b, c) WHERE ((a OPERATOR(pg_catalog.>) 1) AND ((a OPERATOR(pg_catalog.=) 10) OR (b OPERATOR(pg_catalog.=) 'text'::text))) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT foo_1.a AS key, foo_1.b AS value, NULL::jsonb AS value_2 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)) foo_1(a, b)) foo(a, b, c) JOIN local_table_join.postgres_table ON ((foo.a OPERATOR(pg_catalog.>) 1))) WHERE ((foo.a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint))) AND ((foo.a OPERATOR(pg_catalog.=) 10) OR (foo.b OPERATOR(pg_catalog.=) 'text'::text))) +ERROR: column "a" does not exist +CONTEXT: while executing command on localhost:xxxxx -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); DEBUG: Wrapping relation "postgres_table" to a subquery diff --git a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out b/src/test/regress/expected/recursive_relation_planning_restriction_pushdown.out similarity index 90% rename from src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out rename to src/test/regress/expected/recursive_relation_planning_restriction_pushdown.out index 840343aa0..9f9309563 100644 --- a/src/test/regress/expected/recursive_relation_planning_restirction_pushdown.out +++ b/src/test/regress/expected/recursive_relation_planning_restriction_pushdown.out @@ -21,6 +21,15 @@ SELECT create_distributed_table('distributed_table', 'key'); (1 row) +CREATE TYPE new_type AS (n int, m text); +CREATE TABLE local_table_type (key int, value new_type, value_2 jsonb); +CREATE TABLE distributed_table_type (key int, value new_type, value_2 jsonb); +SELECT create_distributed_table('distributed_table_type', 'key'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + -- Setting the debug level so that filters can be observed SET client_min_messages TO DEBUG1; -- for the purposes of these tests, we always want to recursively @@ -39,6 +48,45 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +-- composite types can be pushed down +SELECT count(*) +FROM distributed_table d1 +JOIN local_table_type d2 using(key) +WHERE d2.value = (83, 'citus8.3')::new_type; +DEBUG: Wrapping relation "local_table_type" "d2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table_type d2 WHERE (value OPERATOR(pg_catalog.=) '(83,citus8.3)'::push_down_filters.new_type) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table d1 JOIN (SELECT d2_1.key, d2_1.value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'text'::citus_copy_format) intermediate_result(key integer, value push_down_filters.new_type)) d2_1) d2 USING (key)) WHERE (d2.value OPERATOR(pg_catalog.=) ROW(83, 'citus8.3'::text)::push_down_filters.new_type) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- composite types can be pushed down +SELECT count(*) +FROM distributed_table d1 +JOIN local_table_type d2 using(key) +WHERE d2.value = (83, 'citus8.3')::new_type +AND d2.key = 10; +DEBUG: Wrapping relation "local_table_type" "d2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key, value FROM push_down_filters.local_table_type d2 WHERE ((key OPERATOR(pg_catalog.=) 10) AND (value OPERATOR(pg_catalog.=) '(83,citus8.3)'::push_down_filters.new_type)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table d1 JOIN (SELECT d2_1.key, d2_1.value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'text'::citus_copy_format) intermediate_result(key integer, value push_down_filters.new_type)) d2_1) d2 USING (key)) WHERE ((d2.value OPERATOR(pg_catalog.=) ROW(83, 'citus8.3'::text)::push_down_filters.new_type) AND (d2.key OPERATOR(pg_catalog.=) 10)) + count +--------------------------------------------------------------------- + 0 +(1 row) + +-- join on a composite type works +SELECT count(*) +FROM distributed_table_type d1 +JOIN local_table_type d2 USING(value); +DEBUG: Wrapping relation "local_table_type" "d2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT value FROM push_down_filters.local_table_type d2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (push_down_filters.distributed_table_type d1 JOIN (SELECT NULL::integer AS key, d2_1.value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'text'::citus_copy_format) intermediate_result(value push_down_filters.new_type)) d2_1) d2 USING (value)) + count +--------------------------------------------------------------------- + 0 +(1 row) + -- scalar array expressions can be pushed down SELECT count(*) FROM distributed_table u1 @@ -425,4 +473,4 @@ ERROR: complex joins are only supported when all distributed tables are co-loca \set VERBOSITY terse RESET client_min_messages; DROP SCHEMA push_down_filters CASCADE; -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 5 other objects diff --git a/src/test/regress/expected/replicate_reference_tables_to_coordinator.out b/src/test/regress/expected/replicate_reference_tables_to_coordinator.out index d3a50e814..a0c20f879 100644 --- a/src/test/regress/expected/replicate_reference_tables_to_coordinator.out +++ b/src/test/regress/expected/replicate_reference_tables_to_coordinator.out @@ -283,20 +283,20 @@ SELECT test_reference_local_join_func(); WITH ins AS (INSERT INTO numbers VALUES (1) RETURNING *) SELECT * FROM numbers, local_table; NOTICE: executing the command locally: INSERT INTO replicate_ref_to_coordinator.numbers_8000001 (a) VALUES (1) RETURNING a -NOTICE: executing the command locally: SELECT numbers.a, local_table.a FROM replicate_ref_to_coordinator.numbers_8000001 numbers, replicate_ref_to_coordinator.local_table +NOTICE: executing the command locally: SELECT numbers.a, local_table.a FROM replicate_ref_to_coordinator.numbers_8000001 numbers, (SELECT local_table_1.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) local_table_1) local_table a | a --------------------------------------------------------------------- 20 | 2 - 20 | 4 - 20 | 7 - 20 | 20 21 | 2 - 21 | 4 - 21 | 7 - 21 | 20 2 | 2 + 20 | 4 + 21 | 4 2 | 4 + 20 | 7 + 21 | 7 2 | 7 + 20 | 20 + 21 | 20 2 | 20 (12 rows) diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index e80569d40..e35822bbc 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -110,7 +110,7 @@ test: multi_average_expression multi_working_columns multi_having_pushdown havin test: multi_array_agg multi_limit_clause multi_orderby_limit_pushdown test: multi_jsonb_agg multi_jsonb_object_agg multi_json_agg multi_json_object_agg bool_agg ch_bench_having chbenchmark_all_queries expression_reference_join anonymous_columns test: ch_bench_subquery_repartition -test: multi_agg_type_conversion multi_count_type_conversion recursive_relation_planning_restirction_pushdown +test: multi_agg_type_conversion multi_count_type_conversion recursive_relation_planning_restriction_pushdown test: multi_partition_pruning single_hash_repartition_join test: multi_join_pruning multi_hash_pruning intermediate_result_pruning test: multi_null_minmax_value_pruning cursors diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 475fca5d1..3c259216c 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -108,6 +108,32 @@ SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); +-- similar tests in transaction block should work fine + +BEGIN; +-- 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); + +-- foreign tables should work too +SELECT count(*) FROM foreign_table JOIN distributed_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; +SELECT count(*) FROM distributed_partitioned_table JOIN postgres_table USING(key) JOIN reference_table USING (key); + +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key); +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) WHERE distributed_partitioned_table.key = 10; +SELECT count(*) FROM distributed_partitioned_table JOIN local_partitioned_table USING(key) JOIN reference_table USING (key); +ROLLBACK; + -- the conversions should be independent from the order of table entries in the query SELECT COUNT(*) FROM postgres_table join distributed_table_pkey using(key) join local_partitioned_table using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; SELECT COUNT(*) FROM postgres_table join local_partitioned_table using(key) join distributed_table_pkey using(key) join distributed_table using(key) where distributed_table_pkey.key = 5; @@ -119,6 +145,10 @@ SELECT count(*) FROM (SELECT *, random() FROM distributed_table_pkey) as d1 JOI SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key = d1.key AND d1.key < postgres_table.key) WHERE d1.key = 1 AND false; SELECT count(*) FROM (SELECT *, random() FROM distributed_partitioned_table) as d1 JOIN postgres_table ON (postgres_table.key::int = d1.key::int AND d1.key < postgres_table.key) WHERE d1.key::int = 1 AND false; +-- different column names +SELECT a FROM postgres_table foo (a,b,c) JOIN distributed_table ON (distributed_table.key = foo.a) ORDER BY 1 LIMIT 1; + + -- We will plan postgres table as the index is on key,value not just key SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10; SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE distributed_table_composite.key = 10 OR distributed_table_composite.key = 20; @@ -137,6 +167,10 @@ SELECT count(*) FROM distributed_table_composite JOIN postgres_table USING(key) WHERE (distributed_table_composite.key > 10 AND distributed_table_composite.key = 20) OR (distributed_table_composite.value = 'text' AND distributed_table_composite.value = 'text'); +-- Known bug: #4269 +SELECT count(*) FROM distributed_table_composite foo(a,b,c) JOIN postgres_table ON(foo.a > 1) + WHERE foo.a IN (SELECT COUNT(*) FROM local_partitioned_table) AND (foo.a = 10 OR foo.b ='text'); + -- a unique index on key so dist table should be recursively planned SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(key); SELECT count(*) FROM postgres_table JOIN distributed_table_pkey USING(value); diff --git a/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql b/src/test/regress/sql/recursive_relation_planning_restriction_pushdown.sql similarity index 90% rename from src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql rename to src/test/regress/sql/recursive_relation_planning_restriction_pushdown.sql index 7a1e9923d..ebc1c5ccc 100644 --- a/src/test/regress/sql/recursive_relation_planning_restirction_pushdown.sql +++ b/src/test/regress/sql/recursive_relation_planning_restriction_pushdown.sql @@ -21,6 +21,12 @@ CREATE TABLE local_table (key int, value int, time timestamptz); CREATE TABLE distributed_table (key int, value int, metadata jsonb); SELECT create_distributed_table('distributed_table', 'key'); +CREATE TYPE new_type AS (n int, m text); +CREATE TABLE local_table_type (key int, value new_type, value_2 jsonb); + +CREATE TABLE distributed_table_type (key int, value new_type, value_2 jsonb); +SELECT create_distributed_table('distributed_table_type', 'key'); + -- Setting the debug level so that filters can be observed SET client_min_messages TO DEBUG1; @@ -35,6 +41,24 @@ FROM distributed_table u1 JOIN distributed_table u2 USING(key) JOIN local_table USING (key); +-- composite types can be pushed down +SELECT count(*) +FROM distributed_table d1 +JOIN local_table_type d2 using(key) +WHERE d2.value = (83, 'citus8.3')::new_type; + +-- composite types can be pushed down +SELECT count(*) +FROM distributed_table d1 +JOIN local_table_type d2 using(key) +WHERE d2.value = (83, 'citus8.3')::new_type +AND d2.key = 10; + +-- join on a composite type works +SELECT count(*) +FROM distributed_table_type d1 +JOIN local_table_type d2 USING(value); + -- scalar array expressions can be pushed down SELECT count(*) FROM distributed_table u1 From c4d3927956dddda6bb42c5b38619f0e23b20d5ff Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Fri, 11 Dec 2020 17:25:22 +0300 Subject: [PATCH 33/37] Not allow local table updates with remote citus local tables --- .../planner/local_distributed_join_planner.c | 6 +- .../planner/multi_router_planner.c | 92 ++++++++++++++++++- .../planner/query_colocation_checker.c | 8 +- .../distributed/planner/recursive_planning.c | 83 ++--------------- .../citus_local_tables_queries_mx.out | 20 ++-- 5 files changed, 111 insertions(+), 98 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index c1c3fb048..8828fe255 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -370,7 +370,7 @@ HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, { List *uniqueIndexColumnNos = indexColumns->indexColumnNos; if (FirstIsSuperSetOfSecond(rteEqualityColumnsNos, - uniqueIndexColumnNos)) + uniqueIndexColumnNos)) { return true; } @@ -480,7 +480,6 @@ CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, RangeTblEntry *rangeTableEntry = NULL; foreach_ptr(rangeTableEntry, rangeTableList) { - /* we're only interested in tables */ if (!IsRecursivelyPlannableRelation(rangeTableEntry)) { @@ -488,6 +487,7 @@ CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, } int rteIdentity = GetRTEIdentity(rangeTableEntry); + /* result relation cannot converted to a subquery */ if (resultRTEIdentity == rteIdentity) { @@ -500,7 +500,7 @@ CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, { continue; } - + RangeTableEntryDetails *rangeTableEntryDetails = palloc0(sizeof(RangeTableEntryDetails)); diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 788d0f486..768e9b171 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -177,6 +177,10 @@ static void ReorderTaskPlacementsByTaskAssignmentPolicy(Job *job, TaskAssignmentPolicyType taskAssignmentPolicy, List *placementList); +static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList); +static DeferredErrorMessage * DeferErrorIfUnsupportedLocalTableJoin(List *rangeTableList); +static bool IsTableLocallyAccessible(Oid relationId); + /* * CreateRouterPlan attempts to create a router executor plan for the given @@ -522,7 +526,7 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, } CmdType commandType = queryTree->commandType; - deferredError = DeferErrorIfModifyView(queryTree); + deferredError = DeferErrorIfUnsupportedLocalTableJoin(queryTree->rtable); if (deferredError != NULL) { return deferredError; @@ -614,7 +618,6 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, } - Oid resultRelationId = ModifyQueryResultRelationId(queryTree); *distributedTableIdOutput = resultRelationId; uint32 rangeTableId = 1; @@ -758,6 +761,91 @@ ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery, } +/* + * DeferErrorIfUnsupportedLocalTableJoin returns an error message + * if there is an unsupported join in the given range table list. + */ +static DeferredErrorMessage * +DeferErrorIfUnsupportedLocalTableJoin(List *rangeTableList) +{ + if (ModifiesLocalTableWithRemoteCitusLocalTable(rangeTableList)) + { + return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, + "Modifying local tables with citus local tables is " + "supported only from the coordinator.", + NULL, + "Consider wrapping citus local table to a CTE, or subquery"); + } + return NULL; +} + + +/* + * ModifiesLocalTableWithRemoteCitusLocalTable returns true if a local + * table is modified with a remote citus local table. This could be a case with + * MX structure. + */ +static bool +ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList) +{ + bool containsLocalResultRelation = false; + bool containsRemoteCitusLocalTable = false; + + RangeTblEntry *rangeTableEntry = NULL; + foreach_ptr(rangeTableEntry, rangeTableList) + { + if (!IsRecursivelyPlannableRelation(rangeTableEntry)) + { + continue; + } + if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE)) + { + if (!IsTableLocallyAccessible(rangeTableEntry->relid)) + { + containsRemoteCitusLocalTable = true; + } + } + else if (!IsCitusTable(rangeTableEntry->relid)) + { + containsLocalResultRelation = true; + } + } + return containsLocalResultRelation && containsRemoteCitusLocalTable; +} + + +/* + * IsTableLocallyAccessible returns true if the given table + * can be accessed in local. + */ +static bool +IsTableLocallyAccessible(Oid relationId) +{ + if (!IsCitusTable(relationId)) + { + /* local tables are locally accessible */ + return true; + } + + List *shardIntervalList = LoadShardIntervalList(relationId); + if (list_length(shardIntervalList) != 1) + { + return false; + } + + ShardInterval *shardInterval = linitial(shardIntervalList); + uint64 shardId = shardInterval->shardId; + ShardPlacement *localShardPlacement = + ShardPlacementOnGroup(shardId, GetLocalGroupId()); + if (localShardPlacement != NULL) + { + /* the table has a placement on this node */ + return true; + } + return false; +} + + /* * NodeIsFieldStore returns true if given Node is a FieldStore object. */ diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index 864fd6dcb..018fc376e 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -262,7 +262,7 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker) * Note that the query returned by this function does not contain any filters or * projections. The returned query should be used cautiosly and it is mostly * designed for generating a stub query. - * + * * allTargetList will contain all columns for the given rteRelation but for the ones * that are not required, it will have NULL entries. */ @@ -304,9 +304,9 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes if (shouldAssignDummyNullColumn && !assignedDummyNullColumn) { - /* + /* * in case there is no required column, we assign one dummy NULL target entry - * to the subquery targetList so that it has at least one target. + * to the subquery targetList so that it has at least one target. * (targetlist should have at least one element) */ subquery->targetList = lappend(subquery->targetList, targetEntry); @@ -345,6 +345,7 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes return subquery; } + /* * MakeVarAttNosSequential changes the attribute numbers of the given targetList * to sequential numbers, [1, 2, 3] ... @@ -370,7 +371,6 @@ MakeVarAttNosSequential(List *targetList) } - /* * UnionRelationRestrictionLists merges two relation restriction lists * and returns a newly allocated list. The merged relation restriction diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 61477b709..5ac46d360 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -170,7 +170,6 @@ static bool ShouldRecursivelyPlanSubquery(Query *subquery, static bool AllDistributionKeysInSubqueryAreEqual(Query *subquery, PlannerRestrictionContext * restrictionContext); -static bool IsTableLocallyAccessible(Oid relationId); static bool ShouldRecursivelyPlanSetOperation(Query *query, RecursivePlanningContext *context); static bool RecursivelyPlanSubquery(Query *subquery, @@ -193,7 +192,6 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); static void UpdateVarNosInNode(Query *query, Index newVarNo); -static bool ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList); static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, List **joinRangeTableEntries); static Query * CreateOuterSubquery(RangeTblEntry *rangeTableEntry, @@ -1468,12 +1466,13 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *copyRestrictionList = copyObject(restrictionList); Expr *andedBoundExpressions = make_ands_explicit(copyRestrictionList); subquery->jointree->quals = (Node *) andedBoundExpressions; + /* * Originally the quals were pointing to the RTE and its varno * was pointing to its index in rtable. However now we converted the RTE - * to a subquery and the quals should be pointing to that subquery, which - * is the only RTE in its rtable, hence we update the varnos so that they - * point to the subquery RTE. + * to a subquery and the quals should be pointing to that subquery, which + * is the only RTE in its rtable, hence we update the varnos so that they + * point to the subquery RTE. * Originally: rtable: [rte1, current_rte, rte3...] * Now: rtable: [rte1, subquery[current_rte], rte3...] --subquery[current_rte] refers to its rtable. */ @@ -1541,7 +1540,8 @@ GetRelationNameAndAliasName(RangeTblEntry *rangeTableEntry) static Query * CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *outerSubqueryTargetList) { - List *innerSubqueryColNames = GenerateRequiredColNamesFromTargetList(outerSubqueryTargetList); + List *innerSubqueryColNames = GenerateRequiredColNamesFromTargetList( + outerSubqueryTargetList); Query *outerSubquery = makeNode(Query); outerSubquery->commandType = CMD_SELECT; @@ -1616,76 +1616,7 @@ ContainsTableToBeConvertedToSubquery(List *rangeTableList) { return true; } - if (ModifiesLocalTableWithRemoteCitusLocalTable(rangeTableList)) - { - return true; - } - return false; -} - -/* - * ModifiesLocalTableWithRemoteCitusLocalTable returns true if a local - * table is modified with a remote citus local table. This could be a case with - * MX structure. - */ -static bool -ModifiesLocalTableWithRemoteCitusLocalTable(List *rangeTableList) -{ - bool containsLocalResultRelation = false; - bool containsRemoteCitusLocalTable = false; - - RangeTblEntry *rangeTableEntry = NULL; - foreach_ptr(rangeTableEntry, rangeTableList) - { - if (!IsRecursivelyPlannableRelation(rangeTableEntry)) - { - continue; - } - if (IsCitusTableType(rangeTableEntry->relid, CITUS_LOCAL_TABLE)) - { - if (!IsTableLocallyAccessible(rangeTableEntry->relid)) - { - containsRemoteCitusLocalTable = true; - } - } - else if (!IsCitusTable(rangeTableEntry->relid)) - { - containsLocalResultRelation = true; - } - } - return containsLocalResultRelation && containsRemoteCitusLocalTable; -} - - -/* - * IsTableLocallyAccessible returns true if the given table - * can be accessed in local. - */ -static bool -IsTableLocallyAccessible(Oid relationId) -{ - if (!IsCitusTable(relationId)) - { - /* local tables are locally accessible */ - return true; - } - - List *shardIntervalList = LoadShardIntervalList(relationId); - if (list_length(shardIntervalList) != 1) - { - return false; - } - - ShardInterval *shardInterval = linitial(shardIntervalList); - uint64 shardId = shardInterval->shardId; - ShardPlacement *localShardPlacement = - ShardPlacementOnGroup(shardId, GetLocalGroupId()); - if (localShardPlacement != NULL) - { - /* the table has a placement on this node */ - return true; - } return false; } @@ -1862,7 +1793,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) subquery->targetList = lappend(subquery->targetList, targetEntry); } } - /* * If tupleDesc is NULL we have 2 different cases: * @@ -1912,7 +1842,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) columnType = list_nth_oid(rangeTblFunction->funccoltypes, targetColumnIndex); } - /* use the types in the function definition otherwise */ else { diff --git a/src/test/regress/expected/citus_local_tables_queries_mx.out b/src/test/regress/expected/citus_local_tables_queries_mx.out index 7791e57bc..ce61c7fdb 100644 --- a/src/test/regress/expected/citus_local_tables_queries_mx.out +++ b/src/test/regress/expected/citus_local_tables_queries_mx.out @@ -148,11 +148,7 @@ SELECT count(*) FROM ( SELECT * FROM (SELECT count(*) FROM citus_local_table, postgres_local_table) as subquery_inner ) as subquery_top; - count ---------------------------------------------------------------------- - 1 -(1 row) - +ERROR: direct joins between distributed and local tables are not supported -- should fail as we don't support direct joins between distributed/local tables SELECT count(*) FROM ( @@ -486,11 +482,7 @@ ERROR: could not run distributed query with FOR UPDATE/SHARE commands 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; - count | count ---------------------------------------------------------------------- - 6 | 6 -(1 row) - +ERROR: direct joins between distributed and local tables are not supported -- select for update is just OK SELECT * FROM citus_local_table ORDER BY 1,2 FOR UPDATE; a | b @@ -599,17 +591,21 @@ SELECT clear_and_init_test_tables(); DELETE FROM citus_local_table USING postgres_local_table WHERE citus_local_table.b = postgres_local_table.b; +ERROR: Modifying local tables with citus local tables is supported only from the coordinator. 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; +ERROR: Modifying local tables with citus local tables is supported only from the coordinator. DELETE FROM postgres_local_table USING citus_local_table WHERE citus_local_table.b = postgres_local_table.b; +ERROR: Modifying local tables with citus local tables is supported only from the coordinator. 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; +ERROR: Modifying local tables with citus local tables is supported only from the coordinator. -- no direct joins supported UPDATE distributed_table SET b = 6 @@ -682,7 +678,7 @@ SELECT count(*) FROM distributed_table WHERE b in (SELECT count FROM mat_view_4); count --------------------------------------------------------------------- - 1 + 0 (1 row) CREATE VIEW view_2 AS @@ -713,7 +709,7 @@ SELECT count(*) FROM view_3; SELECT count(*) FROM view_3, distributed_table; count --------------------------------------------------------------------- - 6 + 0 (1 row) --------------------------------------------------------------------- From d5b0f02a6468504a9ac551322ef13fe6f988db2a Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Fri, 11 Dec 2020 17:50:02 +0300 Subject: [PATCH 34/37] Decide what group to convert, then convert them all in one go --- .../planner/local_distributed_join_planner.c | 119 ++++++++---------- .../distributed/planner/recursive_planning.c | 2 + 2 files changed, 52 insertions(+), 69 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 8828fe255..99bbab7f8 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -135,7 +135,6 @@ int LocalTableJoinPolicy = LOCAL_JOIN_POLICY_AUTO; typedef struct RangeTableEntryDetails { RangeTblEntry *rangeTableEntry; - int rteIdentity; List *requiredAttributeNumbers; bool hasConstantFilterOnUniqueColumn; } RangeTableEntryDetails; @@ -151,6 +150,12 @@ typedef struct IndexColumns List *indexColumnNos; }IndexColumns; +typedef enum ConversionChoice +{ + CONVERT_LOCAL_TABLES = 1, + CONVERT_DISTRIBUTED_TABLES = 2 +}ConversionChoice; + static bool HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, RelationRestriction *relationRestriction); static List * RequiredAttrNumbersForRelation(RangeTblEntry *relationRte, @@ -161,14 +166,14 @@ static ConversionCandidates * CreateConversionCandidates(PlannerRestrictionConte List *rangeTableList, int resultRTEIdentity); static void AppendUniqueIndexColumnsToList(Form_pg_index indexForm, List **uniqueIndexes); -static RangeTableEntryDetails * GetNextRTEToConvertToSubquery(ConversionCandidates * - conversionCandidates, - PlannerRestrictionContext * - plannerRestrictionContext); -static void RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, - int rteIdentity); +static ConversionChoice GetConversionChoice(ConversionCandidates * + conversionCandidates, + PlannerRestrictionContext * + plannerRestrictionContext); static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList); static bool FirstIsSuperSetOfSecond(List *firstIntList, List *secondIntList); +static void ConvertRTEsToSubquery(List *rangeTableEntryDetailsList, + RecursivePlanningContext *context); /* * RecursivelyPlanLocalTableJoins gets a query and the planner @@ -192,35 +197,27 @@ RecursivelyPlanLocalTableJoins(Query *query, CreateConversionCandidates(plannerRestrictionContext, rangeTableList, resultRTEIdentity); - while (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, - plannerRestrictionContext)) - { - RangeTableEntryDetails *rangeTableEntryDetails = - GetNextRTEToConvertToSubquery(conversionCandidates, - plannerRestrictionContext); - if (rangeTableEntryDetails == NULL) - { - break; - } + ConversionChoice conversionChoise = + GetConversionChoice(conversionCandidates, plannerRestrictionContext); - RangeTblEntry *rangeTableEntry = rangeTableEntryDetails->rangeTableEntry; - List *requiredAttributeNumbers = rangeTableEntryDetails->requiredAttributeNumbers; - ReplaceRTERelationWithRteSubquery(rangeTableEntry, - requiredAttributeNumbers, context); - int rteIdentity = rangeTableEntryDetails->rteIdentity; - RemoveFromConversionCandidates(conversionCandidates, rteIdentity); + if (conversionChoise == CONVERT_LOCAL_TABLES) + { + ConvertRTEsToSubquery(conversionCandidates->localTableList, context); + } + else + { + ConvertRTEsToSubquery(conversionCandidates->distributedTableList, context); } } /* - * GetNextRTEToConvertToSubquery returns the range table entry - * which should be converted to a subquery. It considers the local join policy - * for conversion priorities. + * GetConversionChoice returns the conversion choice considering the local table + * join policy. */ -static RangeTableEntryDetails * -GetNextRTEToConvertToSubquery(ConversionCandidates *conversionCandidates, - PlannerRestrictionContext *plannerRestrictionContext) +static ConversionChoice +GetConversionChoice(ConversionCandidates *conversionCandidates, + PlannerRestrictionContext *plannerRestrictionContext) { RangeTableEntryDetails *localRTECandidate = NULL; RangeTableEntryDetails *distributedRTECandidate = NULL; @@ -236,11 +233,12 @@ GetNextRTEToConvertToSubquery(ConversionCandidates *conversionCandidates, if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_LOCAL) { - return localRTECandidate ? localRTECandidate : distributedRTECandidate; + return localRTECandidate ? CONVERT_LOCAL_TABLES : CONVERT_DISTRIBUTED_TABLES; } else if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_PREFER_DISTRIBUTED) { - return distributedRTECandidate ? distributedRTECandidate : localRTECandidate; + return distributedRTECandidate ? CONVERT_DISTRIBUTED_TABLES : + CONVERT_LOCAL_TABLES; } else { @@ -254,16 +252,35 @@ GetNextRTEToConvertToSubquery(ConversionCandidates *conversionCandidates, if (allRangeTableEntriesHaveUniqueIndex) { - return distributedRTECandidate ? distributedRTECandidate : localRTECandidate; + return distributedRTECandidate ? CONVERT_DISTRIBUTED_TABLES : + CONVERT_LOCAL_TABLES; } else { - return localRTECandidate ? localRTECandidate : distributedRTECandidate; + return localRTECandidate ? CONVERT_LOCAL_TABLES : CONVERT_DISTRIBUTED_TABLES; } } } +/* + * ConvertRTEsToSubquery converts all the given range table entries + * to a subquery. + */ +static void +ConvertRTEsToSubquery(List *rangeTableEntryDetailsList, RecursivePlanningContext *context) +{ + RangeTableEntryDetails *rangeTableEntryDetails = NULL; + foreach_ptr(rangeTableEntryDetails, rangeTableEntryDetailsList) + { + RangeTblEntry *rangeTableEntry = rangeTableEntryDetails->rangeTableEntry; + List *requiredAttributeNumbers = rangeTableEntryDetails->requiredAttributeNumbers; + ReplaceRTERelationWithRteSubquery(rangeTableEntry, + requiredAttributeNumbers, context); + } +} + + /* * AllRangeTableEntriesHaveUniqueIndex returns true if all of the RTE's in the given * list have a unique index. @@ -283,41 +300,6 @@ AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList) } -/* - * RemoveFromConversionCandidates removes an element from - * the relevant list based on the relation id. - */ -static void -RemoveFromConversionCandidates(ConversionCandidates *conversionCandidates, int - rteIdentity) -{ - RangeTableEntryDetails *rangeTableEntryDetails = NULL; - foreach_ptr(rangeTableEntryDetails, conversionCandidates->localTableList) - { - if (rangeTableEntryDetails->rteIdentity == rteIdentity) - { - conversionCandidates->localTableList = - list_delete_ptr(conversionCandidates->localTableList, - rangeTableEntryDetails); - return; - } - } - - foreach_ptr(rangeTableEntryDetails, conversionCandidates->distributedTableList) - { - if (rangeTableEntryDetails->rteIdentity == rteIdentity) - { - conversionCandidates->distributedTableList = - list_delete_ptr(conversionCandidates->distributedTableList, - rangeTableEntryDetails); - return; - } - } - - ereport(ERROR, (errmsg("invalid rte index is given :%d", rteIdentity))); -} - - /* * ShouldConvertLocalTableJoinsToSubqueries returns true if we should * convert local-dist table joins to subqueries. @@ -506,7 +488,6 @@ CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, palloc0(sizeof(RangeTableEntryDetails)); rangeTableEntryDetails->rangeTableEntry = rangeTableEntry; - rangeTableEntryDetails->rteIdentity = rteIdentity; rangeTableEntryDetails->requiredAttributeNumbers = RequiredAttrNumbersForRelation(rangeTableEntry, plannerRestrictionContext); rangeTableEntryDetails->hasConstantFilterOnUniqueColumn = diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 5ac46d360..5ec48c346 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1793,6 +1793,7 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) subquery->targetList = lappend(subquery->targetList, targetEntry); } } + /* * If tupleDesc is NULL we have 2 different cases: * @@ -1842,6 +1843,7 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) columnType = list_nth_oid(rangeTblFunction->funccoltypes, targetColumnIndex); } + /* use the types in the function definition otherwise */ else { From 0e53aa5d3bf18b367ffee33a6a91b9b705a5572c Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Mon, 14 Dec 2020 12:09:45 +0300 Subject: [PATCH 35/37] Add more tests --- .../planner/local_distributed_join_planner.c | 60 ++++++++++--- .../planner/multi_logical_optimizer.c | 4 +- .../planner/multi_physical_planner.c | 14 +-- .../distributed/planner/recursive_planning.c | 85 ++----------------- .../local_distributed_join_planner.h | 8 +- .../distributed/multi_logical_optimizer.h | 1 - src/include/distributed/recursive_planning.h | 1 - .../expected/citus_local_dist_joins.out | 39 +++++++++ .../regress/expected/local_table_join.out | 10 ++- .../regress/expected/multi_simple_queries.out | 3 +- ...licate_reference_tables_to_coordinator.out | 20 ++--- .../regress/sql/citus_local_dist_joins.sql | 26 ++++++ src/test/regress/sql/local_table_join.sql | 6 +- ...licate_reference_tables_to_coordinator.sql | 2 +- 14 files changed, 157 insertions(+), 122 deletions(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 99bbab7f8..e5bcbdb1c 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -174,6 +174,10 @@ static bool AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList static bool FirstIsSuperSetOfSecond(List *firstIntList, List *secondIntList); static void ConvertRTEsToSubquery(List *rangeTableEntryDetailsList, RecursivePlanningContext *context); +static int ResultRTEIdentity(Query *query); +static List * RTEListToConvert(ConversionCandidates *conversionCandidates, + ConversionChoice conversionChoice); + /* * RecursivelyPlanLocalTableJoins gets a query and the planner @@ -182,17 +186,13 @@ static void ConvertRTEsToSubquery(List *rangeTableEntryDetailsList, */ void RecursivelyPlanLocalTableJoins(Query *query, - RecursivePlanningContext *context, List *rangeTableList) + RecursivePlanningContext *context) { PlannerRestrictionContext *plannerRestrictionContext = GetPlannerRestrictionContext(context); - int resultRTEIdentity = INVALID_RTE_IDENTITY; - if (IsModifyCommand(query)) - { - RangeTblEntry *resultRTE = ExtractResultRelationRTE(query); - resultRTEIdentity = GetRTEIdentity(resultRTE); - } + List *rangeTableList = query->rtable; + int resultRTEIdentity = ResultRTEIdentity(query); ConversionCandidates *conversionCandidates = CreateConversionCandidates(plannerRestrictionContext, rangeTableList, resultRTEIdentity); @@ -200,14 +200,48 @@ RecursivelyPlanLocalTableJoins(Query *query, ConversionChoice conversionChoise = GetConversionChoice(conversionCandidates, plannerRestrictionContext); - if (conversionChoise == CONVERT_LOCAL_TABLES) + + List *rteListToConvert = RTEListToConvert(conversionCandidates, conversionChoise); + ConvertRTEsToSubquery(rteListToConvert, context); +} + + +/* + * ResultRTEIdentity returns the result RTE's identity if it exists, + * otherwise it returns INVALID_RTE_INDENTITY + */ +static int +ResultRTEIdentity(Query *query) +{ + int resultRTEIdentity = INVALID_RTE_IDENTITY; + if (IsModifyCommand(query)) { - ConvertRTEsToSubquery(conversionCandidates->localTableList, context); + RangeTblEntry *resultRTE = ExtractResultRelationRTE(query); + resultRTEIdentity = GetRTEIdentity(resultRTE); + } + return resultRTEIdentity; +} + + +/* + * RTEListToConvert to converts returns a list of RTEs that should + * be converted to a subquery. + */ +static List * +RTEListToConvert(ConversionCandidates *conversionCandidates, ConversionChoice + conversionChoice) +{ + List *rtesToConvert = NIL; + if (conversionChoice == CONVERT_LOCAL_TABLES) + { + rtesToConvert = list_concat(rtesToConvert, conversionCandidates->localTableList); } else { - ConvertRTEsToSubquery(conversionCandidates->distributedTableList, context); + rtesToConvert = list_concat(rtesToConvert, + conversionCandidates->distributedTableList); } + return rtesToConvert; } @@ -305,9 +339,7 @@ AllRangeTableEntriesHaveUniqueIndex(List *rangeTableEntryDetailsList) * convert local-dist table joins to subqueries. */ bool -ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, - PlannerRestrictionContext * - plannerRestrictionContext) +ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList) { if (LocalTableJoinPolicy == LOCAL_JOIN_POLICY_NEVER) { @@ -315,7 +347,7 @@ ShouldConvertLocalTableJoinsToSubqueries(Query *query, List *rangeTableList, return false; } - if (!ContainsTableToBeConvertedToSubquery(rangeTableList)) + if (!ContainsLocalTableDistributedTableJoin(rangeTableList)) { return false; } diff --git a/src/backend/distributed/planner/multi_logical_optimizer.c b/src/backend/distributed/planner/multi_logical_optimizer.c index 27509e8e1..5a3f78745 100644 --- a/src/backend/distributed/planner/multi_logical_optimizer.c +++ b/src/backend/distributed/planner/multi_logical_optimizer.c @@ -292,6 +292,8 @@ static SortGroupClause * CreateSortGroupClause(Var *column); static const char * CountDistinctHashFunctionName(Oid argumentType); static int CountDistinctStorageSize(double approximationErrorRate); static Const * MakeIntegerConstInt64(int64 integerValue); +static Const * MakeIntegerConst(int32 integerValue); + /* Local functions forward declarations for aggregate expression checks */ static bool HasNonDistributableAggregates(MultiNode *logicalPlanNode); @@ -3789,7 +3791,7 @@ CountDistinctStorageSize(double approximationErrorRate) /* Makes an integer constant node from the given value, and returns that node. */ -Const * +static Const * MakeIntegerConst(int32 integerValue) { const int typeCollationId = get_typcollation(INT4OID); diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 995dfad5c..1ef7554ac 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -3639,7 +3639,7 @@ NodeIsRangeTblRefReferenceTable(Node *node, List *rangeTableList) /* * FetchEqualityAttrNumsForRTE fetches the attribute numbers from quals - * which has equality operator + * which have an equality operator */ List * FetchEqualityAttrNumsForRTE(Node *node) @@ -3665,8 +3665,8 @@ FetchEqualityAttrNumsForRTE(Node *node) /* - * FetchEqualityAttrNumsForList fetches the constant equality numbers - * from the given node list. + * FetchEqualityAttrNumsForList fetches the attribute numbers of expression + * of the form "= constant" from the given node list. */ static List * FetchEqualityAttrNumsForList(List *nodeList) @@ -3696,8 +3696,8 @@ FetchEqualityAttrNumsForList(List *nodeList) /* - * FetchEqualityAttrNumsForRTEOpExpr fetches the attribute numbers from opExpr - * which has equality operator. + * FetchEqualityAttrNumsForRTEOpExpr fetches the attribute numbers of expression + * of the form "= constant" from the given opExpr. */ static List * FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr) @@ -3718,8 +3718,8 @@ FetchEqualityAttrNumsForRTEOpExpr(OpExpr *opExpr) /* - * FetchEqualityAttrNumsForRTEBoolExpr fetches the attribute numbers from boolExpr - * which has equality operator + * FetchEqualityAttrNumsForRTEBoolExpr fetches the attribute numbers of expression + * of the form "= constant" from the given boolExpr. */ static List * FetchEqualityAttrNumsForRTEBoolExpr(BoolExpr *boolExpr) diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 5ec48c346..7ef87e626 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -191,9 +191,7 @@ static Query * BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Const *resultIdConst, Oid functionOid, bool useBinaryCopyFormat); -static void UpdateVarNosInNode(Query *query, Index newVarNo); -static void GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, - List **joinRangeTableEntries); +static void UpdateVarNosInNode(Node *node, Index newVarNo); static Query * CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *outerSubqueryTargetList); static List * GenerateRequiredColNamesFromTargetList(List *targetList); @@ -354,22 +352,14 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context } - PlannerRestrictionContext *plannerRestrictionContext = - context->plannerRestrictionContext; - - List *rangeTableList = NIL; - GetRangeTableEntriesFromJoinTree((Node *) query->jointree, query->rtable, - &rangeTableList); - - if (ShouldConvertLocalTableJoinsToSubqueries(query, rangeTableList, - plannerRestrictionContext)) + if (ShouldConvertLocalTableJoinsToSubqueries(query->rtable)) { /* * Logical planner cannot handle "local_table" [OUTER] JOIN "dist_table", or * a query with local table/citus local table and subquery. We convert local/citus local * tables to a subquery until they can be planned. */ - RecursivelyPlanLocalTableJoins(query, context, rangeTableList); + RecursivelyPlanLocalTableJoins(query, context); } @@ -388,50 +378,6 @@ GetPlannerRestrictionContext(RecursivePlanningContext *recursivePlanningContext) } -/* - * GetRangeTableEntriesFromJoinTree gets the range table entries that are - * on the given join tree. - */ -static void -GetRangeTableEntriesFromJoinTree(Node *joinNode, List *rangeTableList, - List **joinRangeTableEntries) -{ - if (joinNode == NULL) - { - return; - } - else if (IsA(joinNode, FromExpr)) - { - FromExpr *fromExpr = (FromExpr *) joinNode; - Node *fromElement; - - foreach_ptr(fromElement, fromExpr->fromlist) - { - GetRangeTableEntriesFromJoinTree(fromElement, rangeTableList, - joinRangeTableEntries); - } - } - else if (IsA(joinNode, JoinExpr)) - { - JoinExpr *joinExpr = (JoinExpr *) joinNode; - GetRangeTableEntriesFromJoinTree(joinExpr->larg, rangeTableList, - joinRangeTableEntries); - GetRangeTableEntriesFromJoinTree(joinExpr->rarg, rangeTableList, - joinRangeTableEntries); - } - else if (IsA(joinNode, RangeTblRef)) - { - int rangeTableIndex = ((RangeTblRef *) joinNode)->rtindex; - RangeTblEntry *rte = rt_fetch(rangeTableIndex, rangeTableList); - *joinRangeTableEntries = lappend(*joinRangeTableEntries, rte); - } - else - { - pg_unreachable(); - } -} - - /* * ShouldRecursivelyPlanNonColocatedSubqueries returns true if the input query contains joins * that are not on the distribution key. @@ -1476,7 +1422,8 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, * Originally: rtable: [rte1, current_rte, rte3...] * Now: rtable: [rte1, subquery[current_rte], rte3...] --subquery[current_rte] refers to its rtable. */ - UpdateVarNosInNode(subquery, SINGLE_RTE_INDEX); + Node *quals = subquery->jointree->quals; + UpdateVarNosInNode(quals, SINGLE_RTE_INDEX); /* replace the function with the constructed subquery */ rangeTableEntry->rtekind = RTE_SUBQUERY; @@ -1590,12 +1537,12 @@ GenerateRequiredColNamesFromTargetList(List *targetList) /* * UpdateVarNosInNode iterates the Vars in the - * given node's join tree quals and updates the varno's as the newVarNo. + * given node and updates the varno's as the newVarNo. */ static void -UpdateVarNosInNode(Query *query, Index newVarNo) +UpdateVarNosInNode(Node *node, Index newVarNo) { - List *varList = pull_var_clause(query->jointree->quals, PVC_RECURSE_AGGREGATES | + List *varList = pull_var_clause(node, PVC_RECURSE_AGGREGATES | PVC_RECURSE_PLACEHOLDERS); Var *var = NULL; foreach_ptr(var, varList) @@ -1605,22 +1552,6 @@ UpdateVarNosInNode(Query *query, Index newVarNo) } -/* - * ContainsTableToBeConvertedToSubquery checks if the given range table list contains - * any table that should be converted to a subquery, which otherwise is not plannable. - */ -bool -ContainsTableToBeConvertedToSubquery(List *rangeTableList) -{ - if (ContainsLocalTableDistributedTableJoin(rangeTableList)) - { - return true; - } - - return false; -} - - /* * IsRecursivelyPlannableRelation returns true if the given range table entry * is a relation type that can be converted to a subquery. diff --git a/src/include/distributed/local_distributed_join_planner.h b/src/include/distributed/local_distributed_join_planner.h index 041cb63fd..dd74c8fb1 100644 --- a/src/include/distributed/local_distributed_join_planner.h +++ b/src/include/distributed/local_distributed_join_planner.h @@ -27,12 +27,8 @@ typedef enum extern int LocalTableJoinPolicy; -extern bool ShouldConvertLocalTableJoinsToSubqueries(Query *query, - List *rangeTableList, - PlannerRestrictionContext * - plannerRestrictionContext); +extern bool ShouldConvertLocalTableJoinsToSubqueries(List *rangeTableList); extern void RecursivelyPlanLocalTableJoins(Query *query, - RecursivePlanningContext *context, - List *rangeTableList); + RecursivePlanningContext *context); #endif /* LOCAL_DISTRIBUTED_JOIN_PLANNER_H */ diff --git a/src/include/distributed/multi_logical_optimizer.h b/src/include/distributed/multi_logical_optimizer.h index ddfaae315..9e6167959 100644 --- a/src/include/distributed/multi_logical_optimizer.h +++ b/src/include/distributed/multi_logical_optimizer.h @@ -177,6 +177,5 @@ extern void FindReferencedTableColumn(Expr *columnExpression, List *parentQueryL extern char * WorkerColumnName(AttrNumber resno); extern bool IsGroupBySubsetOfDistinct(List *groupClauses, List *distinctClauses); extern bool TargetListHasAggregates(List *targetEntryList); -extern Const * MakeIntegerConst(int32 integerValue); #endif /* MULTI_LOGICAL_OPTIMIZER_H */ diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 24aa3d08b..0a64f6845 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -47,7 +47,6 @@ extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, RecursivePlanningContext *context); -extern bool ContainsTableToBeConvertedToSubquery(List *rangeTableList); extern bool IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry); extern bool IsRelationLocalTableOrMatView(Oid relationId); #endif /* RECURSIVE_PLANNING_H */ diff --git a/src/test/regress/expected/citus_local_dist_joins.out b/src/test/regress/expected/citus_local_dist_joins.out index 664a3bdcd..56d40ff23 100644 --- a/src/test/regress/expected/citus_local_dist_joins.out +++ b/src/test/regress/expected/citus_local_dist_joins.out @@ -458,6 +458,45 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 0 (1 row) +SELECT + COUNT(*) +FROM + postgres_table p1 +JOIN + distributed_partitioned_table dp1 +USING (key) +JOIN + distributed_table d1 +USING (key) +JOIN + citus_local c1 +USING (key) +JOIN + postgres_table p2 +USING (key) +JOIN + reference_table r1 +USING (key) +JOIN + distributed_table d2 +USING (key) +JOIN + citus_local c2 +USING (key); +DEBUG: Wrapping relation "postgres_table" "p1" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key FROM citus_local_dist_joins.postgres_table p1 WHERE true +DEBUG: Wrapping relation "citus_local" "c1" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT key FROM citus_local_dist_joins.citus_local c1 WHERE true +DEBUG: Wrapping relation "postgres_table" "p2" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT key FROM citus_local_dist_joins.postgres_table p2 WHERE true +DEBUG: Wrapping relation "citus_local" "c2" to a subquery +DEBUG: generating subplan XXX_4 for subquery SELECT key FROM citus_local_dist_joins.citus_local c2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((((((((SELECT p1_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)) p1_1) p1 JOIN citus_local_dist_joins.distributed_partitioned_table dp1 USING (key)) JOIN citus_local_dist_joins.distributed_table d1 USING (key)) JOIN (SELECT c1_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)) c1_1) c1 USING (key)) JOIN (SELECT p2_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) p2_1) p2 USING (key)) JOIN citus_local_dist_joins.reference_table r1 USING (key)) JOIN citus_local_dist_joins.distributed_table d2 USING (key)) JOIN (SELECT c2_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) c2_1) c2 USING (key)) + count +--------------------------------------------------------------------- + 100 +(1 row) + SET client_min_messages to ERROR; DROP TABLE citus_local; SELECT master_remove_node('localhost', :master_port); diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index ff884f92f..2d0d13c64 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -992,7 +992,15 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 100 (1 row) --- TODO:: we should support this? +-- will error as we don't support complex joins +SELECT COUNT(*) FROM postgres_table, distributed_table d1, distributed_table d2 WHERE d1.value = d2.value; +DEBUG: Wrapping relation "postgres_table" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS key FROM local_table_join.postgres_table WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT NULL::integer AS 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, local_table_join.distributed_table d1, local_table_join.distributed_table d2 WHERE (d1.value OPERATOR(pg_catalog.=) d2.value) +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +-- This will error because router planner will think that since reference tables have a single +-- shard, it contains only a single task for modify. However, updating a reference tables +-- will require multiple tasks. So requires some rewrite in router planner. UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; DEBUG: Wrapping relation "postgres_table" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE (key OPERATOR(pg_catalog.=) 10) diff --git a/src/test/regress/expected/multi_simple_queries.out b/src/test/regress/expected/multi_simple_queries.out index 7cba49921..d518bb408 100644 --- a/src/test/regress/expected/multi_simple_queries.out +++ b/src/test/regress/expected/multi_simple_queries.out @@ -280,8 +280,7 @@ ORDER BY articles.id; -- subqueries are not supported in SELECT clause SELECT a.title AS name, (SELECT a2.id FROM articles_single_shard a2 WHERE a.id = a2.id LIMIT 1) AS special_price FROM articles a; -ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses -HINT: Consider using an equality filter on the distributed table's partition column. +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- joins are supported between local and distributed tables SELECT title, authors.name FROM authors, articles WHERE authors.id = articles.author_id; title | name diff --git a/src/test/regress/expected/replicate_reference_tables_to_coordinator.out b/src/test/regress/expected/replicate_reference_tables_to_coordinator.out index a0c20f879..72082810a 100644 --- a/src/test/regress/expected/replicate_reference_tables_to_coordinator.out +++ b/src/test/regress/expected/replicate_reference_tables_to_coordinator.out @@ -281,23 +281,23 @@ SELECT test_reference_local_join_func(); -- CTEs are allowed WITH ins AS (INSERT INTO numbers VALUES (1) RETURNING *) -SELECT * FROM numbers, local_table; +SELECT * FROM numbers, local_table ORDER BY 1,2; NOTICE: executing the command locally: INSERT INTO replicate_ref_to_coordinator.numbers_8000001 (a) VALUES (1) RETURNING a -NOTICE: executing the command locally: SELECT numbers.a, local_table.a FROM replicate_ref_to_coordinator.numbers_8000001 numbers, (SELECT local_table_1.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) local_table_1) local_table +NOTICE: executing the command locally: SELECT numbers.a, local_table.a FROM replicate_ref_to_coordinator.numbers_8000001 numbers, (SELECT local_table_1.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) local_table_1) local_table ORDER BY numbers.a, local_table.a a | a --------------------------------------------------------------------- - 20 | 2 - 21 | 2 2 | 2 - 20 | 4 - 21 | 4 2 | 4 - 20 | 7 - 21 | 7 2 | 7 - 20 | 20 - 21 | 20 2 | 20 + 20 | 2 + 20 | 4 + 20 | 7 + 20 | 20 + 21 | 2 + 21 | 4 + 21 | 7 + 21 | 20 (12 rows) WITH t AS (SELECT *, my_volatile_fn() x FROM numbers FOR UPDATE) diff --git a/src/test/regress/sql/citus_local_dist_joins.sql b/src/test/regress/sql/citus_local_dist_joins.sql index 5b6950c48..8559ef728 100644 --- a/src/test/regress/sql/citus_local_dist_joins.sql +++ b/src/test/regress/sql/citus_local_dist_joins.sql @@ -224,6 +224,32 @@ SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distribut SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; +SELECT + COUNT(*) +FROM + postgres_table p1 +JOIN + distributed_partitioned_table dp1 +USING (key) +JOIN + distributed_table d1 +USING (key) +JOIN + citus_local c1 +USING (key) +JOIN + postgres_table p2 +USING (key) +JOIN + reference_table r1 +USING (key) +JOIN + distributed_table d2 +USING (key) +JOIN + citus_local c2 +USING (key); + SET client_min_messages to ERROR; DROP TABLE citus_local; diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index 3c259216c..fc55fe4c9 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -252,8 +252,12 @@ FROM JOIN postgres_table USING(key); +-- will error as we don't support complex joins +SELECT COUNT(*) FROM postgres_table, distributed_table d1, distributed_table d2 WHERE d1.value = d2.value; --- TODO:: we should support this? +-- This will error because router planner will think that since reference tables have a single +-- shard, it contains only a single task for modify. However, updating a reference tables +-- will require multiple tasks. So requires some rewrite in router planner. UPDATE reference_table SET key = 1 FROM postgres_table WHERE postgres_table.key = 10; UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l.key = 10; diff --git a/src/test/regress/sql/replicate_reference_tables_to_coordinator.sql b/src/test/regress/sql/replicate_reference_tables_to_coordinator.sql index 47f8df9a6..0587ebfaa 100644 --- a/src/test/regress/sql/replicate_reference_tables_to_coordinator.sql +++ b/src/test/regress/sql/replicate_reference_tables_to_coordinator.sql @@ -145,7 +145,7 @@ SELECT test_reference_local_join_func(); -- CTEs are allowed WITH ins AS (INSERT INTO numbers VALUES (1) RETURNING *) -SELECT * FROM numbers, local_table; +SELECT * FROM numbers, local_table ORDER BY 1,2; WITH t AS (SELECT *, my_volatile_fn() x FROM numbers FOR UPDATE) SELECT * FROM numbers, local_table From 7951273f74d9bedeac5b46e52ee0b583ff6ac8ef Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Mon, 14 Dec 2020 21:07:02 +0300 Subject: [PATCH 36/37] Refactor WrapRteRelationIntoSubquery --- .../planner/query_colocation_checker.c | 218 +++++++++++------- .../distributed/planner/recursive_planning.c | 7 +- .../distributed/query_colocation_checker.h | 5 +- .../expected/local_dist_join_mixed.out | 12 +- .../regress/sql/citus_local_dist_joins.sql | 22 +- 5 files changed, 163 insertions(+), 101 deletions(-) diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index 018fc376e..e38a282e8 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -47,7 +47,14 @@ static RangeTblEntry * AnchorRte(Query *subquery); static List * UnionRelationRestrictionLists(List *firstRelationList, List *secondRelationList); -static void MakeVarAttNosSequential(List *targetList); +static List * CreateFilteredTargetListForRelation(Oid relationId, + List *requiredAttributes); +static List * CreateDummyTargetList(Oid relationId, List *requiredAttributes); +static TargetEntry * CreateTargetEntryForColumn(Form_pg_attribute attributeTuple, Index + rteIndex, + int attributeNumber, int resno); +static TargetEntry * CreateTargetEntryForNullCol(Form_pg_attribute attributeTuple, int + resno); /* @@ -78,9 +85,7 @@ CreateColocatedJoinChecker(Query *subquery, PlannerRestrictionContext *restricti * functions (i.e., FilterPlannerRestrictionForQuery()) rely on queries * not relations. */ - List *allTargetList = NIL; - anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry, NIL, - &allTargetList); + anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry, NIL); } else if (anchorRangeTblEntry->rtekind == RTE_SUBQUERY) { @@ -262,13 +267,9 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker) * Note that the query returned by this function does not contain any filters or * projections. The returned query should be used cautiosly and it is mostly * designed for generating a stub query. - * - * allTargetList will contain all columns for the given rteRelation but for the ones - * that are not required, it will have NULL entries. */ Query * -WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes, - List **allTargetList) +WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes) { Query *subquery = makeNode(Query); RangeTblRef *newRangeTableRef = makeNode(RangeTblRef); @@ -281,93 +282,150 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes /* set the FROM expression to the subquery */ newRangeTableRef = makeNode(RangeTblRef); - newRangeTableRef->rtindex = 1; + newRangeTableRef->rtindex = SINGLE_RTE_INDEX; subquery->jointree = makeFromExpr(list_make1(newRangeTableRef), NULL); - Relation relation = relation_open(rteRelation->relid, AccessShareLock); - int numberOfAttributes = RelationGetNumberOfAttributes(relation); + subquery->targetList = + CreateFilteredTargetListForRelation(rteRelation->relid, requiredAttributes); - bool shouldAssignDummyNullColumn = list_length(requiredAttributes) == 0; - bool assignedDummyNullColumn = false; - int attributeNumber = 1; - int resultNo = 1; - for (; attributeNumber <= numberOfAttributes; attributeNumber++) + if (list_length(subquery->targetList) == 0) { - Form_pg_attribute attributeTuple = - TupleDescAttr(relation->rd_att, attributeNumber - 1); - Var *targetColumn = - makeVar(newRangeTableRef->rtindex, attributeNumber, attributeTuple->atttypid, - attributeTuple->atttypmod, attributeTuple->attcollation, 0); - TargetEntry *targetEntry = - makeTargetEntry((Expr *) targetColumn, attributeNumber, - strdup(attributeTuple->attname.data), false); - - if (shouldAssignDummyNullColumn && !assignedDummyNullColumn) - { - /* - * in case there is no required column, we assign one dummy NULL target entry - * to the subquery targetList so that it has at least one target. - * (targetlist should have at least one element) - */ - subquery->targetList = lappend(subquery->targetList, targetEntry); - assignedDummyNullColumn = true; - } - - if (!list_member_int(requiredAttributes, attributeNumber)) - { - /* - * We add a null target entry because we don't have an easy - * way of changing all the references to this column and - * we don't want to break postgres query. - */ - targetEntry->expr = - (Expr *) makeNullConst(attributeTuple->atttypid, - attributeTuple->atttypmod, - attributeTuple->attcollation); - *allTargetList = lappend(*allTargetList, targetEntry); - } - else - { - TargetEntry *copyTargetEntry = copyObject(targetEntry); - *allTargetList = lappend(*allTargetList, copyTargetEntry); - - /* In the subquery with only required attribute numbers, the result no - * corresponds to the ordinal index of it in targetList. - */ - targetEntry->resno = resultNo++; - subquery->targetList = lappend(subquery->targetList, targetEntry); - } + /* + * in case there is no required column, we assign one dummy NULL target entry + * to the subquery targetList so that it has at least one target. + * (targetlist should have at least one element) + */ + subquery->targetList = CreateDummyTargetList(rteRelation->relid, + requiredAttributes); } - MakeVarAttNosSequential(*allTargetList); - - relation_close(relation, NoLock); return subquery; } /* - * MakeVarAttNosSequential changes the attribute numbers of the given targetList - * to sequential numbers, [1, 2, 3] ... + * CreateAllTargetListForRelation creates a target list which contains all the columns + * of the given relation. If the column is not in required columns, then it is added + * as a NULL column. */ -static void -MakeVarAttNosSequential(List *targetList) +List * +CreateAllTargetListForRelation(Oid relationId, List *requiredAttributes) { - TargetEntry *entry = NULL; - int attrNo = 1; - foreach_ptr(entry, targetList) - { - if (IsA(entry->expr, Var)) - { - Var *var = (Var *) entry->expr; + Relation relation = relation_open(relationId, AccessShareLock); + int numberOfAttributes = RelationGetNumberOfAttributes(relation); - /* - * the inner subquery is an intermediate result hence - * the attribute no's should be in ordinal order. [1, 2, 3...] - */ - var->varattno = attrNo++; + List *targetList = NIL; + int varAttrNo = 1; + for (int attrNum = 1; attrNum <= numberOfAttributes; attrNum++) + { + Form_pg_attribute attributeTuple = + TupleDescAttr(relation->rd_att, attrNum - 1); + + int resNo = attrNum; + if (!list_member_int(requiredAttributes, attrNum)) + { + TargetEntry *nullTargetEntry = + CreateTargetEntryForNullCol(attributeTuple, resNo); + targetList = lappend(targetList, nullTargetEntry); + } + else + { + TargetEntry *targetEntry = + CreateTargetEntryForColumn(attributeTuple, SINGLE_RTE_INDEX, varAttrNo++, + resNo); + targetList = lappend(targetList, targetEntry); } } + + relation_close(relation, NoLock); + return targetList; +} + + +/* + * CreateFilteredTargetListForRelation creates a target list which contains + * only the required columns of the given relation. If there is not required + * columns then a dummy NULL column is put as the only entry. + */ +static List * +CreateFilteredTargetListForRelation(Oid relationId, List *requiredAttributes) +{ + Relation relation = relation_open(relationId, AccessShareLock); + int numberOfAttributes = RelationGetNumberOfAttributes(relation); + + List *targetList = NIL; + int resultNo = 1; + for (int attrNum = 1; attrNum <= numberOfAttributes; attrNum++) + { + Form_pg_attribute attributeTuple = + TupleDescAttr(relation->rd_att, attrNum - 1); + + if (list_member_int(requiredAttributes, attrNum)) + { + /* In the subquery with only required attribute numbers, the result no + * corresponds to the ordinal index of it in targetList. + */ + TargetEntry *targetEntry = + CreateTargetEntryForColumn(attributeTuple, SINGLE_RTE_INDEX, attrNum, + resultNo++); + targetList = lappend(targetList, targetEntry); + } + } + relation_close(relation, NoLock); + return targetList; +} + + +/* + * CreateDummyTargetList creates a target list which contains only a + * NULL entry. + */ +static List * +CreateDummyTargetList(Oid relationId, List *requiredAttributes) +{ + Relation relation = relation_open(relationId, AccessShareLock); + + Form_pg_attribute attributeTuple = + TupleDescAttr(relation->rd_att, 0); + TargetEntry *nullTargetEntry = + CreateTargetEntryForNullCol(attributeTuple, 1); + + relation_close(relation, NoLock); + return list_make1(nullTargetEntry); +} + + +/* + * CreateTargetEntryForColumn creates a target entry for the given + * column. + */ +static TargetEntry * +CreateTargetEntryForColumn(Form_pg_attribute attributeTuple, Index rteIndex, + int attributeNumber, int resno) +{ + Var *targetColumn = + makeVar(rteIndex, attributeNumber, attributeTuple->atttypid, + attributeTuple->atttypmod, attributeTuple->attcollation, 0); + TargetEntry *targetEntry = + makeTargetEntry((Expr *) targetColumn, resno, + strdup(attributeTuple->attname.data), false); + return targetEntry; +} + + +/* + * CreateTargetEntryForNullCol creates a target entry that has a NULL expression. + */ +static TargetEntry * +CreateTargetEntryForNullCol(Form_pg_attribute attributeTuple, int resno) +{ + Expr *nullExpr = (Expr *) makeNullConst(attributeTuple->atttypid, + attributeTuple->atttypmod, + attributeTuple->attcollation); + TargetEntry *targetEntry = + makeTargetEntry(nullExpr, resno, + strdup(attributeTuple->attname.data), false); + return targetEntry; } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 7ef87e626..f8cc45cc7 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -1403,9 +1403,10 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, RecursivePlanningContext *context) { - List *outerQueryTargetList = NIL; - Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers, - &outerQueryTargetList); + Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); + List *outerQueryTargetList = CreateAllTargetListForRelation(rangeTableEntry->relid, + requiredAttrNumbers); + List *restrictionList = GetRestrictInfoListForRelation(rangeTableEntry, context->plannerRestrictionContext); diff --git a/src/include/distributed/query_colocation_checker.h b/src/include/distributed/query_colocation_checker.h index 4a9f4fa87..969ecbcf9 100644 --- a/src/include/distributed/query_colocation_checker.h +++ b/src/include/distributed/query_colocation_checker.h @@ -35,8 +35,7 @@ extern ColocatedJoinChecker CreateColocatedJoinChecker(Query *subquery, restrictionContext); extern bool SubqueryColocated(Query *subquery, ColocatedJoinChecker *context); extern Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, - List *requiredAttributes, - List **allTargetList); - + List *requiredAttributes); +extern List * CreateAllTargetListForRelation(Oid relationId, List *requiredAttributes); #endif /* QUERY_COLOCATION_CHECKER_H */ diff --git a/src/test/regress/expected/local_dist_join_mixed.out b/src/test/regress/expected/local_dist_join_mixed.out index d4f3f96a7..141509dfd 100644 --- a/src/test/regress/expected/local_dist_join_mixed.out +++ b/src/test/regress/expected/local_dist_join_mixed.out @@ -665,16 +665,20 @@ select (SELECT local.id) FROM local, distributed WHERE distributed.id != 1 LIMIT DEBUG: Wrapping relation "local" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT id FROM local_dist_join_mixed.local WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT local.id) AS id FROM (SELECT local_1.id, NULL::text AS title FROM (SELECT intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint)) local_1) local, local_dist_join_mixed.distributed WHERE (distributed.id OPERATOR(pg_catalog.<>) 1) LIMIT 1 -ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses -HINT: Consider using an equality filter on the distributed table's partition column. +DEBUG: push down of limit count: 1 + id +--------------------------------------------------------------------- + 0 +(1 row) + -- currently not supported, but should work with https://github.com/citusdata/citus/pull/4360/files SELECT name, (SELECT id FROM local WHERE id = e.id) FROM distributed e ORDER BY 1,2 LIMIT 1; -ERROR: could not run distributed query with subquery outside the FROM, WHERE and HAVING clauses -HINT: Consider using an equality filter on the distributed table's partition column. +ERROR: direct joins between distributed and local tables are not supported +HINT: Use CTE's or subqueries to select from local tables and use them in joins -- set operations SELECT local.* FROM distributed JOIN local USING (id) EXCEPT diff --git a/src/test/regress/sql/citus_local_dist_joins.sql b/src/test/regress/sql/citus_local_dist_joins.sql index 8559ef728..ceaff4218 100644 --- a/src/test/regress/sql/citus_local_dist_joins.sql +++ b/src/test/regress/sql/citus_local_dist_joins.sql @@ -224,30 +224,30 @@ SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distribut SELECT count(*) FROM postgres_table JOIN (SELECT * FROM (SELECT * FROM distributed_table LIMIT 1) d1) d2 using (key) JOIN reference_table USING(key) JOIN citus_local USING (key) JOIN (SELECT * FROM citus_local) c1 USING (key) WHERE d2.key > 10 AND d2.key = 10; -SELECT - COUNT(*) -FROM +SELECT + COUNT(*) +FROM postgres_table p1 -JOIN +JOIN distributed_partitioned_table dp1 USING (key) JOIN - distributed_table d1 + distributed_table d1 USING (key) -JOIN - citus_local c1 -USING (key) -JOIN +JOIN + citus_local c1 +USING (key) +JOIN postgres_table p2 USING (key) JOIN reference_table r1 USING (key) -JOIN +JOIN distributed_table d2 USING (key) JOIN - citus_local c2 + citus_local c2 USING (key); From 181a7e1d36be5241d138ed14de4b36a5a4ad38a0 Mon Sep 17 00:00:00 2001 From: Sait Talha Nisanci Date: Tue, 15 Dec 2020 14:53:00 +0300 Subject: [PATCH 37/37] Skip dropped columns --- .../planner/local_distributed_join_planner.c | 28 +++++++++++++++++++ .../planner/query_colocation_checker.c | 5 ++++ .../regress/expected/local_table_join.out | 25 ++++++++++++++++- src/test/regress/sql/local_table_join.sql | 8 ++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index e5bcbdb1c..17eee2724 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -132,6 +132,11 @@ */ int LocalTableJoinPolicy = LOCAL_JOIN_POLICY_AUTO; +/* + * RangeTableEntryDetails contains some information about + * a range table entry so that we don't need to calculate + * them over and over. + */ typedef struct RangeTableEntryDetails { RangeTblEntry *rangeTableEntry; @@ -139,17 +144,33 @@ typedef struct RangeTableEntryDetails bool hasConstantFilterOnUniqueColumn; } RangeTableEntryDetails; +/* + * ConversionCandidates contains candidates that could + * be converted to a subquery. This is used as a convenience to + * first generate all the candidates and then choose which ones to convert. + */ typedef struct ConversionCandidates { List *distributedTableList; /* reference or distributed table */ List *localTableList; /* local or citus local table */ }ConversionCandidates; + +/* + * IndexColumns contains the column numbers for an index. + * For example if there is an index on (a, b) then it will contain + * their column numbers (1,2). + */ typedef struct IndexColumns { List *indexColumnNos; }IndexColumns; +/* + * ConversionChoice represents which conversion group + * to convert to a subquery. Currently we either convert all + * local tables, or distributed tables. + */ typedef enum ConversionChoice { CONVERT_LOCAL_TABLES = 1, @@ -458,6 +479,13 @@ RequiredAttrNumbersForRelation(RangeTblEntry *rangeTableEntry, } PlannerInfo *plannerInfo = relationRestriction->plannerInfo; + + /* + * Here we used the query from plannerInfo because it has the optimizations + * so that it doesn't have unnecessary columns. The original query doesn't have + * some of these optimizations hence if we use it here, we don't get the + * 'required' attributes. + */ Query *queryToProcess = plannerInfo->parse; int rteIndex = relationRestriction->index; diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index e38a282e8..b20d6664d 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -321,6 +321,11 @@ CreateAllTargetListForRelation(Oid relationId, List *requiredAttributes) Form_pg_attribute attributeTuple = TupleDescAttr(relation->rd_att, attrNum - 1); + if (attributeTuple->attisdropped) + { + continue; + } + int resNo = attrNum; if (!list_member_int(requiredAttributes, attrNum)) { diff --git a/src/test/regress/expected/local_table_join.out b/src/test/regress/expected/local_table_join.out index 2d0d13c64..5749cb824 100644 --- a/src/test/regress/expected/local_table_join.out +++ b/src/test/regress/expected/local_table_join.out @@ -1256,7 +1256,30 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c 2 (1 row) +CREATE TABLE local (key1 int, key2 int, key3 int); +INSERT INTO local VALUES (1,2,3); +ALTER TABLE local DROP column key2; +-- verify we ignore dropped columns +SELECT COUNT(*) FROM local JOIN distributed_table ON(key1 = key); +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key1 FROM local_table_join.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT local_1.key1, NULL::integer AS key3 FROM (SELECT intermediate_result.key1 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key1 integer)) local_1) local JOIN local_table_join.distributed_table ON ((local.key1 OPERATOR(pg_catalog.=) distributed_table.key))) + count +--------------------------------------------------------------------- + 1 +(1 row) + +SELECT * FROM local JOIN distributed_table ON(key1 = key) ORDER BY 1 LIMIT 1; +DEBUG: Wrapping relation "local" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT key1, key3 FROM local_table_join.local WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT local.key1, local.key3, distributed_table.key, distributed_table.value, distributed_table.value_2 FROM ((SELECT local_1.key1, local_1.key3 FROM (SELECT intermediate_result.key1, intermediate_result.key3 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key1 integer, key3 integer)) local_1) local JOIN local_table_join.distributed_table ON ((local.key1 OPERATOR(pg_catalog.=) distributed_table.key))) ORDER BY local.key1 LIMIT 1 +DEBUG: push down of limit count: 1 + key1 | key3 | key | value | value_2 +--------------------------------------------------------------------- + 1 | 3 | 1 | 1 | +(1 row) + RESET client_min_messages; \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE; -NOTICE: drop cascades to 15 other objects +NOTICE: drop cascades to 16 other objects diff --git a/src/test/regress/sql/local_table_join.sql b/src/test/regress/sql/local_table_join.sql index fc55fe4c9..49d71a551 100644 --- a/src/test/regress/sql/local_table_join.sql +++ b/src/test/regress/sql/local_table_join.sql @@ -315,6 +315,14 @@ EXECUTE local_dist_table_join_filters(20); EXECUTE local_dist_table_join_filters(20); EXECUTE local_dist_table_join_filters(20); +CREATE TABLE local (key1 int, key2 int, key3 int); +INSERT INTO local VALUES (1,2,3); +ALTER TABLE local DROP column key2; +-- verify we ignore dropped columns +SELECT COUNT(*) FROM local JOIN distributed_table ON(key1 = key); +SELECT * FROM local JOIN distributed_table ON(key1 = key) ORDER BY 1 LIMIT 1; + + RESET client_min_messages; \set VERBOSITY terse DROP SCHEMA local_table_join CASCADE;