diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index a0ef2c739..16fb25336 100644 --- a/src/backend/distributed/planner/multi_logical_planner.c +++ b/src/backend/distributed/planner/multi_logical_planner.c @@ -85,6 +85,8 @@ static FieldSelect * CompositeFieldRecursive(Expr *expression, Query *query); static bool FullCompositeFieldList(List *compositeFieldList); static MultiNode * MultiPlanTree(Query *queryTree); static void ErrorIfQueryNotSupported(Query *queryTree); +static bool HasUnsupportedReferenceTableJoin( + PlannerRestrictionContext *plannerRestrictionContext); static bool HasUnsupportedJoinWalker(Node *node, void *context); static bool ErrorHintRequired(const char *errorHint, Query *queryTree); static DeferredErrorMessage * DeferErrorIfUnsupportedSubqueryRepartition(Query * @@ -94,6 +96,8 @@ static bool HasOuterJoin(Query *queryTree); static bool HasOuterJoinWalker(Node *node, void *maxJoinLevel); static bool HasComplexJoinOrder(Query *queryTree); static bool HasComplexRangeTableType(Query *queryTree); +static bool RelationInfoHasReferenceTable(PlannerInfo *plannerInfo, + RelOptInfo *relationInfo); static void ValidateClauseList(List *clauseList); static void ValidateSubqueryPushdownClauseList(List *clauseList); static bool ExtractFromExpressionWalker(Node *node, @@ -188,7 +192,6 @@ MultiLogicalPlanCreate(Query *originalQuery, Query *queryTree, { originalQuery = (Query *) ResolveExternalParams((Node *) originalQuery, boundParams); - multiQueryNode = MultiSubqueryPlanTree(originalQuery, queryTree, plannerRestrictionContext); } @@ -539,6 +542,13 @@ DeferErrorIfUnsupportedSubqueryPushdown(Query *originalQuery, "one another relation using distribution keys and " "equality operator.", NULL); } + else if (HasUnsupportedReferenceTableJoin(plannerRestrictionContext)) + { + return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, + "cannot pushdown the subquery", + "There exist a reference table in the outer part of the outer join", + NULL); + } /* * We first extract all the queries that appear in the original query. Later, @@ -871,6 +881,10 @@ DeferErrorIfUnsupportedUnionQuery(Query *subqueryTree, { SetOperationStmt *setOperation = (SetOperationStmt *) lfirst(setOperationStatmentCell); + Node *leftArg = setOperation->larg; + Node *rightArg = setOperation->rarg; + int leftArgRTI = 0; + int rightArgRTI = 0; if (setOperation->op != SETOP_UNION) { @@ -878,6 +892,36 @@ DeferErrorIfUnsupportedUnionQuery(Query *subqueryTree, "cannot push down this subquery", "Intersect and Except are currently unsupported", NULL); } + + if (IsA(leftArg, RangeTblRef)) + { + Node *leftArgSubquery = NULL; + leftArgRTI = ((RangeTblRef *) leftArg)->rtindex; + leftArgSubquery = (Node *) rt_fetch(leftArgRTI, + subqueryTree->rtable)->subquery; + if (HasReferenceTable(leftArgSubquery)) + { + return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, + "cannot push down this subquery ", + "Reference tables are not supported with union" + " operator", NULL); + } + } + + if (IsA(rightArg, RangeTblRef)) + { + Node *rightArgSubquery = NULL; + rightArgRTI = ((RangeTblRef *) rightArg)->rtindex; + rightArgSubquery = (Node *) rt_fetch(rightArgRTI, + subqueryTree->rtable)->subquery; + if (HasReferenceTable(rightArgSubquery)) + { + return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, + "cannot push down this subquery", + "Reference tables are not supported with union" + " operator", NULL); + } + } } return NULL; @@ -982,7 +1026,7 @@ DeferErrorIfUnsupportedTableCombination(Query *queryTree) /* * TargetListOnPartitionColumn checks if at least one target list entry is on - * partition column. + * partition column or the table is a reference table. */ static bool TargetListOnPartitionColumn(Query *query, List *targetEntryList) @@ -1003,9 +1047,9 @@ TargetListOnPartitionColumn(Query *query, List *targetEntryList) FindReferencedTableColumn(targetExpression, NIL, query, &relationId, &column); /* - * If the expression belongs to reference table directly returns true, - * since logic of caller function checks whether it can find the necessaary - * data from each node. + * If the expression belongs to reference table directly returns true. + * We can assume that target list entry always on partition column of + * reference tables. */ if (IsDistributedTable(relationId) && PartitionMethod(relationId) == DISTRIBUTE_BY_NONE) @@ -1380,6 +1424,149 @@ MultiPlanTree(Query *queryTree) } +/* + * HasUnsupportedReferenceTableJoin returns true if there exists a outer join + * exist between reference table and distributed tables which does not obey the + * rules : + * - Reference tables can not be located in the outer part of the semi join (or + * the inner part of the anti join). Otherwise, we may have duplicate results. + * Although getting duplicate results is not possible by checking the equality + * on the column of the reference table and partition column of distributed table, + * we still keep these checks. Because, using the reference table in the outer + * part of the semi join is not very common. + * - Reference tables can not be located in the outer part of the left join and + * inner part of the right join. Otherwise we will definitely have duplicate rows. + * Beside, reference tables can not be used with full outer joins because of the + * same reason. + */ +static bool +HasUnsupportedReferenceTableJoin(PlannerRestrictionContext *plannerRestrictionContext) +{ + List *joinRestrictionList = + plannerRestrictionContext->joinRestrictionContext->joinRestrictionList; + ListCell *joinRestrictionCell = NULL; + + foreach(joinRestrictionCell, joinRestrictionList) + { + JoinRestriction *joinRestriction = (JoinRestriction *) lfirst( + joinRestrictionCell); + JoinType joinType = joinRestriction->joinType; + PlannerInfo *plannerInfo = joinRestriction->plannerInfo; + RelOptInfo *innerrel = joinRestriction->innerrel; + RelOptInfo *outerrel = joinRestriction->outerrel; + + switch (joinType) + { + case JOIN_SEMI: + { + if (RelationInfoHasReferenceTable(plannerInfo, outerrel)) + { + return true; + } + } + break; + + case JOIN_ANTI: + { + if (RelationInfoHasReferenceTable(plannerInfo, innerrel)) + { + return true; + } + } + break; + + case JOIN_LEFT: + { + if (RelationInfoHasReferenceTable(plannerInfo, outerrel)) + { + return true; + } + } + break; + + case JOIN_RIGHT: + { + if (RelationInfoHasReferenceTable(plannerInfo, innerrel)) + { + return true; + } + } + break; + + case JOIN_FULL: + { + if (RelationInfoHasReferenceTable(plannerInfo, innerrel) || + RelationInfoHasReferenceTable( + plannerInfo, outerrel)) + { + return true; + } + } + break; + + default: + { } + break; + } + } + + return false; +} + + +/* + * ReferenceTableExist check whether the relationInfo has reference table. + * Since relation ids of relationInfo indexes to the range table entry list of + * planner info, planner info is also passed. + */ +static bool +RelationInfoHasReferenceTable(PlannerInfo *plannerInfo, RelOptInfo *relationInfo) +{ + Relids relids = bms_copy(relationInfo->relids); + int relationId = -1; + + while ((relationId = bms_first_member(relids)) >= 0) + { + RangeTblEntry *rangeTableEntry = plannerInfo->simple_rte_array[relationId]; + + /* relationInfo has this range table entry */ + if (HasReferenceTable((Node *) rangeTableEntry)) + { + return true; + } + } + + return false; +} + + +/* + * HasReferenceTable checks whether there exist a reference table in the + * given node. + */ +bool +HasReferenceTable(Node *node) +{ + List *relationList = NIL; + ListCell *relationCell = NULL; + ExtractRangeTableRelationWalkerInRTE(node, &relationList); + + foreach(relationCell, relationList) + { + RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(relationCell); + Oid relationId = rangeTableEntry->relid; + + if (IsDistributedTable(relationId) && PartitionMethod(relationId) == + DISTRIBUTE_BY_NONE) + { + return true; + } + } + + return false; +} + + /* * ErrorIfQueryNotSupported checks that we can perform distributed planning for * the given query. The checks in this function will be removed as we support @@ -2745,44 +2932,41 @@ ExtractRangeTableRelationWalker(Node *node, List **rangeTableRelationList) } -/* Get the list of relations from the given node. Note that the difference between - * this function and ExtractRangeTableRelationWalker is that this one recursively +/* + * ExtractRangeTableRelationWalkerInRTE obtains the list of relations from the + * given node. Note that the difference between this function and + * ExtractRangeTableRelationWalker is that this one recursively * walk into range table entries if it can. */ bool -ExtractRTRelationFromNode(Node *node, List **rangeTableList) +ExtractRangeTableRelationWalkerInRTE(Node *node, List **rangeTableRelationList) { bool walkIsComplete = false; + if (node == NULL) { - return false; + return walkIsComplete; } - - if (IsA(node, RangeTblEntry)) + else if (IsA(node, RangeTblEntry)) { RangeTblEntry *rangeTableEntry = (RangeTblEntry *) node; + List *rangeTableList = NIL; + rangeTableList = lappend(rangeTableList, rangeTableEntry); - if (rangeTableEntry->rtekind == RTE_RELATION && - rangeTableEntry->relkind != RELKIND_VIEW) + if (rangeTableEntry->rtekind == RTE_RELATION) { - (*rangeTableList) = lappend(*rangeTableList, rangeTableEntry); + (*rangeTableRelationList) = lappend(*rangeTableRelationList, rangeTableEntry); } - else if (rangeTableEntry->rtekind == RTE_SUBQUERY) + else { - walkIsComplete = query_tree_walker(rangeTableEntry->subquery, - ExtractRTRelationFromNode, - rangeTableList, QTW_EXAMINE_RTES); + walkIsComplete = range_table_walker(rangeTableList, + ExtractRangeTableRelationWalkerInRTE, + rangeTableRelationList, 0); } } - else if (IsA(node, Query)) - { - walkIsComplete = query_tree_walker((Query *) node, ExtractRTRelationFromNode, - rangeTableList, QTW_EXAMINE_RTES); - } else { - walkIsComplete = expression_tree_walker(node, ExtractRTRelationFromNode, - rangeTableList); + walkIsComplete = ExtractRangeTableRelationWalker(node, rangeTableRelationList); } return walkIsComplete; diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index a70527b70..53eeba729 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -127,8 +127,6 @@ static Job * BuildJobTreeTaskList(Job *jobTree, static List * SubquerySqlTaskList(Job *job, PlannerRestrictionContext *plannerRestrictionContext); static void ErrorIfUnsupportedShardDistribution(Query *query); -static void ErrorIfUnsupportedJoinReferenceTable( - PlannerRestrictionContext *plannerRestrictionContext); static bool CoPartitionedTables(Oid firstRelationId, Oid secondRelationId); static bool ShardIntervalsEqual(FmgrInfo *comparisonFunction, ShardInterval *firstInterval, @@ -197,8 +195,6 @@ static StringInfo MergeTableQueryString(uint32 taskIdIndex, List *targetEntryLis static StringInfo IntermediateTableQueryString(uint64 jobId, uint32 taskIdIndex, Query *reduceQuery); static uint32 FinalTargetEntryCount(List *targetEntryList); -static bool ReferenceTableExist(PlannerInfo *plannerInfo, RelOptInfo *relationInfo); -static void ErrorIfSetOpWithReferenceTable(Query *queryTree); /* @@ -2042,12 +2038,6 @@ SubquerySqlTaskList(Job *job, PlannerRestrictionContext *plannerRestrictionConte /* error if shards are not co-partitioned */ ErrorIfUnsupportedShardDistribution(subquery); - /* error if unsupported join on reference tables */ - ErrorIfUnsupportedJoinReferenceTable(plannerRestrictionContext); - - /* error if reference table exists as a part of any set operation */ - ErrorIfSetOpWithReferenceTable(subquery); - /* get list of all range tables in subquery tree */ ExtractRangeTableRelationWalker((Node *) subquery, &rangeTableList); @@ -2072,8 +2062,8 @@ SubquerySqlTaskList(Job *job, PlannerRestrictionContext *plannerRestrictionConte } /* - * That means all table are reference table and we can assign any reference - * table as an anchor one . + * That means all tables are reference tables and we can pick any any of them + * as an anchor table. */ if (targetCacheEntry == NULL) { @@ -2107,196 +2097,6 @@ SubquerySqlTaskList(Job *job, PlannerRestrictionContext *plannerRestrictionConte } -/* - * ErrorIfUnsupportedJoinReferenceTable errors out if there exists a outer join - * exist between reference table and distributed tables. - */ -static void -ErrorIfUnsupportedJoinReferenceTable(PlannerRestrictionContext *plannerRestrictionContext) -{ - List *joinRestrictionList = - plannerRestrictionContext->joinRestrictionContext->joinRestrictionList; - ListCell *joinRestrictionCell = NULL; - - foreach(joinRestrictionCell, joinRestrictionList) - { - JoinRestriction *joinRestriction = (JoinRestriction *) lfirst( - joinRestrictionCell); - JoinType joinType = joinRestriction->joinType; - PlannerInfo *plannerInfo = joinRestriction->plannerInfo; - RelOptInfo *innerrel = joinRestriction->innerrel; - RelOptInfo *outerrel = joinRestriction->outerrel; - - switch (joinType) - { - case JOIN_SEMI: - { - if (ReferenceTableExist(plannerInfo, outerrel)) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("can not plan query having reference table on" - " the left part of semi join"))); - } - } - break; - - case JOIN_ANTI: - { - if (ReferenceTableExist(plannerInfo, innerrel)) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("can not plan query having reference table on" - " the left part of anti join"))); - } - } - break; - - case JOIN_LEFT: - { - if (ReferenceTableExist(plannerInfo, outerrel)) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("can not plan query having reference table on" - " the left part of left join"))); - } - } - break; - - case JOIN_RIGHT: - { - if (ReferenceTableExist(plannerInfo, innerrel)) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("can not plan query having reference table on" - " the right part of right join"))); - } - } - break; - - case JOIN_FULL: - { - if (ReferenceTableExist(plannerInfo, innerrel) || ReferenceTableExist( - plannerInfo, outerrel)) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg( - "can not plan query having reference table as a" - " part of full join"))); - } - } - break; - - default: - { } - break; - } - } -} - - -/* - * ReferenceTableExist check whether the relationInfo has reference table. - * Since relation ids of relationInfo indexes to the range table entry list of - * query, query is also passed. - */ -static bool -ReferenceTableExist(PlannerInfo *plannerInfo, RelOptInfo *relationInfo) -{ - Relids relids = bms_copy(relationInfo->relids); - int relationId = -1; - - while ((relationId = bms_first_member(relids)) >= 0) - { - RangeTblEntry *rangeTableEntry = plannerInfo->simple_rte_array[relationId]; - - /* relationInfo has this range table entry */ - if (RTEContainsReferenceTable(rangeTableEntry)) - { - return true; - } - } - - return false; -} - - -/* - * RTEContainsReferenceTable checks whether there exist a reference table in the - * given range table entry. - */ -bool -RTEContainsReferenceTable(RangeTblEntry *rangeTableEntry) -{ - List *relationList = NIL; - ListCell *relationCell = NULL; - ExtractRTRelationFromNode((Node *) rangeTableEntry, &relationList); - - foreach(relationCell, relationList) - { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(relationCell); - Oid relationId = rangeTableEntry->relid; - - if (IsDistributedTable(relationId) && PartitionMethod(relationId) == - DISTRIBUTE_BY_NONE) - { - return true; - } - } - - return false; -} - - -/* - * ErrorIfSetOpWithReferenceTable checks whether there exist a reference table - * as a part of any set operation. - */ -static void -ErrorIfSetOpWithReferenceTable(Query *queryTree) -{ - List *joinTreeTableIndexList = NIL; - Index subqueryRteIndex = 0; - RangeTblEntry *rangeTableEntry = NULL; - Query *subqueryTree = NULL; - List *rangeTableList = queryTree->rtable; - Node *setOperations = queryTree->setOperations; - ExtractRangeTableIndexWalker((Node *) queryTree->jointree, &joinTreeTableIndexList); - - if (setOperations != NULL) - { - List *rangeTableList = NIL; - ListCell *rangeTableCell = NULL; - ExtractRangeTableRelationWalker((Node *) queryTree, &rangeTableList); - - foreach(rangeTableCell, rangeTableList) - { - RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell); - Oid relationId = rangeTableEntry->relid; - if (PartitionMethod(relationId) == DISTRIBUTE_BY_NONE) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg( - "can not plan query having reference table with union"))); - } - } - } - - if (list_length(joinTreeTableIndexList) < 1) - { - return; - } - - subqueryRteIndex = linitial_int(joinTreeTableIndexList); - rangeTableEntry = rt_fetch(subqueryRteIndex, rangeTableList); - subqueryTree = rangeTableEntry->subquery; - - if (subqueryTree != NULL) - { - return ErrorIfSetOpWithReferenceTable(subqueryTree); - } -} - - /* * ErrorIfUnsupportedShardDistribution gets list of relations in the given query * and checks if two conditions below hold for them, otherwise it errors out. @@ -2311,6 +2111,7 @@ ErrorIfUnsupportedShardDistribution(Query *query) { Oid firstTableRelationId = InvalidOid; List *relationIdList = RelationIdList(query); + List *distributedRelationIdList = NIL; ListCell *relationIdCell = NULL; uint32 relationIndex = 0; uint32 rangeDistributedRelationCount = 0; @@ -2320,19 +2121,31 @@ ErrorIfUnsupportedShardDistribution(Query *query) { Oid relationId = lfirst_oid(relationIdCell); char partitionMethod = PartitionMethod(relationId); + if (partitionMethod == DISTRIBUTE_BY_RANGE) { rangeDistributedRelationCount++; + distributedRelationIdList = lappend_oid(distributedRelationIdList, + relationId); } else if (partitionMethod == DISTRIBUTE_BY_HASH) { hashDistributedRelationCount++; + distributedRelationIdList = lappend_oid(distributedRelationIdList, + relationId); } - else + else if (partitionMethod == DISTRIBUTE_BY_NONE) { /* do not need to handle reference tables */ continue; } + else + { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot pushdown this subquery"), + errdetail("Currently append partitioned relations " + "are not supported"))); + } } if ((rangeDistributedRelationCount > 0) && (hashDistributedRelationCount > 0)) @@ -2343,18 +2156,11 @@ ErrorIfUnsupportedShardDistribution(Query *query) "partitioned relations are unsupported"))); } - foreach(relationIdCell, relationIdList) + foreach(relationIdCell, distributedRelationIdList) { Oid relationId = lfirst_oid(relationIdCell); bool coPartitionedTables = false; Oid currentRelationId = relationId; - char partitionMethod = PartitionMethod(relationId); - - /* do not need to check reference tables */ - if (partitionMethod == DISTRIBUTE_BY_NONE) - { - continue; - } /* get shard list of first relation and continue for the next relation */ if (relationIndex == 0) diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 7734ae32c..284496427 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -275,7 +275,7 @@ CreateSingleTaskRouterPlan(Query *originalQuery, Query *query, * The function returns hashed columns generated by MakeInt4Column() for the hash * partitioned tables in place of partition columns. * - * The function errors out if the given shard interval does not belong to a hash, + * The function returns NIL if shard interval does not belong to a hash, * range and append distributed tables. * * NB: If you update this, also look at PrunableExpressionsWalker(). diff --git a/src/backend/distributed/planner/relation_restriction_equivalence.c b/src/backend/distributed/planner/relation_restriction_equivalence.c index 657e8751e..1fa38f8d6 100644 --- a/src/backend/distributed/planner/relation_restriction_equivalence.c +++ b/src/backend/distributed/planner/relation_restriction_equivalence.c @@ -153,6 +153,7 @@ SafeToPushdownUnionSubquery(RelationRestrictionContext *restrictionContext) foreach(relationRestrictionCell, restrictionContext->relationRestrictionList) { RelationRestriction *relationRestriction = lfirst(relationRestrictionCell); + Oid relationId = relationRestriction->relationId; Index partitionKeyIndex = InvalidAttrNumber; PlannerInfo *relationPlannerRoot = relationRestriction->plannerInfo; List *targetList = relationPlannerRoot->parse->targetList; @@ -160,6 +161,20 @@ SafeToPushdownUnionSubquery(RelationRestrictionContext *restrictionContext) Var *varToBeAdded = NULL; TargetEntry *targetEntryToAdd = NULL; + /* + * Although it is not the best place to error out when facing with reference + * tables, we decide to error out here. Otherwise, we need to add equality + * for each reference table and it is more complex to implement. In the + * future implementation all checks will be gathered to single point. + */ + if (PartitionMethod(relationId) == DISTRIBUTE_BY_NONE) + { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot pushdown this query"), + errdetail( + "Reference tables are not allowed with set operations"))); + } + /* * We first check whether UNION ALLs are pulled up or not. Note that Postgres * planner creates AppendRelInfos per each UNION ALL query that is pulled up. diff --git a/src/include/distributed/multi_logical_planner.h b/src/include/distributed/multi_logical_planner.h index f73deb79b..bc4795d65 100644 --- a/src/include/distributed/multi_logical_planner.h +++ b/src/include/distributed/multi_logical_planner.h @@ -206,7 +206,7 @@ extern List * TableEntryList(List *rangeTableList); extern List * UsedTableEntryList(Query *query); extern bool ExtractRangeTableRelationWalker(Node *node, List **rangeTableList); extern bool ExtractRangeTableEntryWalker(Node *node, List **rangeTableList); -extern bool ExtractRTRelationFromNode(Node *node, List **rangeTableList); +extern bool ExtractRangeTableRelationWalkerInRTE(Node *node, List **rangeTableList); extern List * pull_var_clause_default(Node *node); extern bool OperatorImplementsEquality(Oid opno); diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index 5f2f08f1d..8f753a4e5 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -286,7 +286,7 @@ extern Const * MakeInt4Constant(Datum constantValue); extern int CompareShardPlacements(const void *leftElement, const void *rightElement); extern bool ShardIntervalsOverlap(ShardInterval *firstInterval, ShardInterval *secondInterval); -extern bool RTEContainsReferenceTable(RangeTblEntry *rangeTableEntry); +extern bool HasReferenceTable(Node *node); /* function declarations for Task and Task list operations */ extern bool TasksEqual(const Task *a, const Task *b); diff --git a/src/test/regress/expected/multi_subquery_complex_reference_clause.out b/src/test/regress/expected/multi_subquery_complex_reference_clause.out index d57954b5b..865d44e8e 100644 --- a/src/test/regress/expected/multi_subquery_complex_reference_clause.out +++ b/src/test/regress/expected/multi_subquery_complex_reference_clause.out @@ -303,7 +303,8 @@ count(*) AS cnt, "generated_group_field" ORDER BY cnt DESC, generated_group_field ASC LIMIT 10; -ERROR: can not plan query having reference table on the left part of left join +ERROR: cannot pushdown the subquery +DETAIL: There exist a reference table in the outer part of the outer join -- RIGHT JOINs used with INNER JOINs should error out since reference table exist in the -- right side of the RIGHT JOIN. SELECT @@ -342,7 +343,8 @@ count(*) AS cnt, "generated_group_field" ORDER BY cnt DESC, generated_group_field ASC LIMIT 10; -ERROR: can not plan query having reference table on the left part of left join +ERROR: cannot pushdown the subquery +DETAIL: There exist a reference table in the outer part of the outer join -- Outer subquery with reference table SELECT "some_users_data".user_id, lastseen FROM @@ -373,7 +375,8 @@ FROM ORDER BY user_id limit 50; -ERROR: can not plan query having reference table as a part of full join +ERROR: cannot pushdown the subquery +DETAIL: There exist a reference table in the outer part of the outer join -- -- UNIONs and JOINs with reference tables, shoukld error out -- @@ -437,7 +440,8 @@ GROUP BY types ORDER BY types; -ERROR: can not plan query having reference table with union +ERROR: cannot push down this subquery +DETAIL: Reference tables are not supported with union operator -- reference table exist in the subquery of union, should error out SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType FROM @@ -509,7 +513,8 @@ GROUP BY types ORDER BY types; -ERROR: can not plan query having reference table with union +ERROR: cannot push down this subquery +DETAIL: Reference tables are not supported with union operator -- -- Should error out with UNION ALL Queries on reference tables -- @@ -563,4 +568,5 @@ INNER JOIN WHERE value_1 > 50 and value_1 < 70) AS t ON (t.user_id = q.user_id)) as final_query GROUP BY types ORDER BY types; -ERROR: can not plan query having reference table with union +ERROR: cannot push down this subquery +DETAIL: Reference tables are not supported with union operator diff --git a/src/test/regress/expected/multi_subquery_in_where_reference_clause.out b/src/test/regress/expected/multi_subquery_in_where_reference_clause.out index 0159510b2..d45ec005f 100644 --- a/src/test/regress/expected/multi_subquery_in_where_reference_clause.out +++ b/src/test/regress/expected/multi_subquery_in_where_reference_clause.out @@ -139,6 +139,7 @@ SELECT user_id, value_2 FROM users_table WHERE HAVING sum(submit_card_info) > 0 ) ORDER BY 1, 2; -ERROR: can not plan query having reference table on the left part of left join +ERROR: cannot pushdown the subquery +DETAIL: There exist a reference table in the outer part of the outer join DROP TABLE events_reference_table; DROP TABLE users_reference_table;