diff --git a/src/backend/distributed/planner/multi_join_order.c b/src/backend/distributed/planner/multi_join_order.c index e4aabbbb1..da45c6205 100644 --- a/src/backend/distributed/planner/multi_join_order.c +++ b/src/backend/distributed/planner/multi_join_order.c @@ -71,8 +71,6 @@ static JoinOrderNode * EvaluateJoinRules(List *joinedTableList, TableEntry *candidateTable, List *joinClauseList, JoinType joinType); static List * RangeTableIdList(List *tableList); -static JoinType JoinTypeBetweenTables(TableEntry *table1, TableEntry *table2, - JoinRestrictionContext *joinRestrictionContext); static RuleEvalFunction JoinRuleEvalFunction(JoinRuleType ruleType); static char * JoinRuleName(JoinRuleType ruleType); static JoinOrderNode * ReferenceJoin(JoinOrderNode *joinNode, TableEntry *candidateTable, @@ -327,43 +325,13 @@ JoinOrderList(List *tableEntryList, List *joinClauseList) } -/* - * JoinTypeBetweenTables returns join type between given tables. - */ -static JoinType -JoinTypeBetweenTables(TableEntry *table1, TableEntry *table2, - JoinRestrictionContext *joinRestrictionContext) -{ - uint32 rteIdx1 = table1->rangeTableId; - uint32 rteIdx2 = table2->rangeTableId; - - JoinRestriction *joinRestriction = NULL; - foreach_ptr(joinRestriction, joinRestrictionContext->joinRestrictionList) - { - if (bms_is_member(rteIdx1, joinRestriction->innerrelRelids) && - bms_is_member(rteIdx2, joinRestriction->outerrelRelids)) - { - return joinRestriction->joinType; - } - else if (bms_is_member(rteIdx2, joinRestriction->innerrelRelids) && - bms_is_member(rteIdx1, joinRestriction->outerrelRelids)) - { - return joinRestriction->joinType; - } - } - - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("no join is found between tables"))); -} - - /* * FixedJoinOrderList returns the best fixed join order according to * applicable join rules for the nodes in the list. */ List * FixedJoinOrderList(List *tableEntryList, List *joinClauseList, - JoinRestrictionContext *joinRestrictionContext) + List *joinExprList) { List *joinOrderList = NIL; List *joinedTableList = NIL; @@ -377,8 +345,7 @@ FixedJoinOrderList(List *tableEntryList, List *joinClauseList, { TableEntry *currentTable = (TableEntry *) list_nth(tableEntryList, tableIdx - 1); TableEntry *nextTable = (TableEntry *) list_nth(tableEntryList, tableIdx); - JoinType joinType = JoinTypeBetweenTables(currentTable, nextTable, - joinRestrictionContext); + JoinType joinType = ((JoinExpr *) list_nth(joinExprList, tableIdx - 1))->jointype; if (firstTable) { diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index 2b365e9aa..a3933807e 100644 --- a/src/backend/distributed/planner/multi_logical_planner.c +++ b/src/backend/distributed/planner/multi_logical_planner.c @@ -153,8 +153,7 @@ MultiLogicalPlanCreate(Query *originalQuery, Query *queryTree, } else { - multiQueryNode = MultiNodeTree(queryTree, - plannerRestrictionContext->joinRestrictionContext); + multiQueryNode = MultiNodeTree(queryTree); } /* add a root node to serve as the permanent handle to the tree */ @@ -563,7 +562,7 @@ SubqueryEntryList(Query *queryTree) * group, and limit nodes if they appear in the original query tree. */ MultiNode * -MultiNodeTree(Query *queryTree, JoinRestrictionContext *joinRestrictionContext) +MultiNodeTree(Query *queryTree) { List *rangeTableList = queryTree->rtable; List *targetEntryList = queryTree->targetList; @@ -638,8 +637,7 @@ MultiNodeTree(Query *queryTree, JoinRestrictionContext *joinRestrictionContext) } /* recursively create child nested multitree */ - MultiNode *subqueryExtendedNode = MultiNodeTree(subqueryTree, - joinRestrictionContext); + MultiNode *subqueryExtendedNode = MultiNodeTree(subqueryTree); SetChild((MultiUnaryNode *) subqueryCollectNode, (MultiNode *) subqueryNode); SetChild((MultiUnaryNode *) subqueryNode, subqueryExtendedNode); @@ -667,10 +665,11 @@ MultiNodeTree(Query *queryTree, JoinRestrictionContext *joinRestrictionContext) /* consider outer join qualifications as well */ List *allRestrictionClauseList = QualifierList(queryTree->jointree); joinClauseList = JoinClauseList(allRestrictionClauseList); + List *joinExprList = JoinExprList(queryTree->jointree); /* we simply donot commute joins as we have at least 1 outer join */ joinOrderList = FixedJoinOrderList(tableEntryList, joinClauseList, - joinRestrictionContext); + joinExprList); } else { diff --git a/src/backend/distributed/planner/query_pushdown_planning.c b/src/backend/distributed/planner/query_pushdown_planning.c index 60a6b7a3a..75ded42bc 100644 --- a/src/backend/distributed/planner/query_pushdown_planning.c +++ b/src/backend/distributed/planner/query_pushdown_planning.c @@ -111,7 +111,8 @@ static Var * PartitionColumnForPushedDownSubquery(Query *query); static bool ContainsReferencesToRelids(Query *query, Relids relids, int *foundRelid); static bool ContainsReferencesToRelidsWalker(Node *node, RelidsReferenceWalkerContext *context); - +static bool HasRightRecursiveJoin(FromExpr *fromExpr); +static bool RightRecursiveJoinExprWalker(Node *node, void *context); /* * ShouldUseSubqueryPushDown determines whether it's desirable to use @@ -173,6 +174,11 @@ ShouldUseSubqueryPushDown(Query *originalQuery, Query *rewrittenQuery, return true; } + /* if there is right recursive join, fix join order can not handle it */ + if (HasRightRecursiveJoin(rewrittenQuery->jointree)) + { + return true; + } /* * We process function and VALUES RTEs as subqueries, since the join order planner @@ -204,6 +210,53 @@ ShouldUseSubqueryPushDown(Query *originalQuery, Query *rewrittenQuery, } +/* + * HasRightRecursiveJoin returns true if join tree contains any right recursive join. + * That method should be removed when we support right recursive outer joins at join + * order planner. + */ +static bool +HasRightRecursiveJoin(FromExpr *fromExpr) +{ + JoinExpr *joinExpr = NULL; + foreach_ptr(joinExpr, fromExpr->fromlist) + { + if (RightRecursiveJoinExprWalker((Node *) joinExpr, NULL)) + { + return true; + } + } + + return false; +} + + +/* + * RightRecursiveJoinExprWalker returns true if it finds right recursive join + * in given join tree. + */ +static bool +RightRecursiveJoinExprWalker(Node *node, void *context) +{ + if (node == NULL) + { + return false; + } + + if (IsA(node, JoinExpr)) + { + JoinExpr *joinExpr = (JoinExpr *) node; + + if (joinExpr->rarg && IsA(joinExpr->rarg, JoinExpr)) + { + return true; + } + } + + return expression_tree_walker(node, RightRecursiveJoinExprWalker, NULL); +} + + /* * JoinTreeContainsSubquery returns true if the input query contains any subqueries * in the join tree (e.g., FROM clause). diff --git a/src/include/distributed/multi_join_order.h b/src/include/distributed/multi_join_order.h index 21ee86806..c6ca6b0ca 100644 --- a/src/include/distributed/multi_join_order.h +++ b/src/include/distributed/multi_join_order.h @@ -93,7 +93,7 @@ extern bool EnableSingleHashRepartitioning; extern List * JoinExprList(FromExpr *fromExpr); extern List * JoinOrderList(List *rangeTableEntryList, List *joinClauseList); extern List * FixedJoinOrderList(List *rangeTableEntryList, List *joinClauseList, - JoinRestrictionContext *joinRestrictionContext); + List *joinExprList); extern bool IsApplicableJoinClause(List *leftTableIdList, uint32 rightTableId, Node *joinClause); extern List * ApplicableJoinClauses(List *leftTableIdList, uint32 rightTableId, diff --git a/src/include/distributed/multi_logical_planner.h b/src/include/distributed/multi_logical_planner.h index 6f8ff6aec..189170358 100644 --- a/src/include/distributed/multi_logical_planner.h +++ b/src/include/distributed/multi_logical_planner.h @@ -229,8 +229,7 @@ extern MultiProject * MultiProjectNode(List *targetEntryList); extern MultiExtendedOp * MultiExtendedOpNode(Query *queryTree, Query *originalQuery); extern DeferredErrorMessage * DeferErrorIfUnsupportedSubqueryRepartition(Query * subqueryTree); -extern MultiNode * MultiNodeTree(Query *queryTree, - JoinRestrictionContext *joinRestrictionContext); +extern MultiNode * MultiNodeTree(Query *queryTree); #endif /* MULTI_LOGICAL_PLANNER_H */