right recursive joins should be handled by pushdown planner

outer-join-noncolocated-dist-tables
aykutbozkurt 2022-12-19 12:25:57 +03:00
parent 17c6187448
commit be39d028c7
5 changed files with 63 additions and 45 deletions

View File

@ -71,8 +71,6 @@ static JoinOrderNode * EvaluateJoinRules(List *joinedTableList,
TableEntry *candidateTable, TableEntry *candidateTable,
List *joinClauseList, JoinType joinType); List *joinClauseList, JoinType joinType);
static List * RangeTableIdList(List *tableList); static List * RangeTableIdList(List *tableList);
static JoinType JoinTypeBetweenTables(TableEntry *table1, TableEntry *table2,
JoinRestrictionContext *joinRestrictionContext);
static RuleEvalFunction JoinRuleEvalFunction(JoinRuleType ruleType); static RuleEvalFunction JoinRuleEvalFunction(JoinRuleType ruleType);
static char * JoinRuleName(JoinRuleType ruleType); static char * JoinRuleName(JoinRuleType ruleType);
static JoinOrderNode * ReferenceJoin(JoinOrderNode *joinNode, TableEntry *candidateTable, 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 * FixedJoinOrderList returns the best fixed join order according to
* applicable join rules for the nodes in the list. * applicable join rules for the nodes in the list.
*/ */
List * List *
FixedJoinOrderList(List *tableEntryList, List *joinClauseList, FixedJoinOrderList(List *tableEntryList, List *joinClauseList,
JoinRestrictionContext *joinRestrictionContext) List *joinExprList)
{ {
List *joinOrderList = NIL; List *joinOrderList = NIL;
List *joinedTableList = NIL; List *joinedTableList = NIL;
@ -377,8 +345,7 @@ FixedJoinOrderList(List *tableEntryList, List *joinClauseList,
{ {
TableEntry *currentTable = (TableEntry *) list_nth(tableEntryList, tableIdx - 1); TableEntry *currentTable = (TableEntry *) list_nth(tableEntryList, tableIdx - 1);
TableEntry *nextTable = (TableEntry *) list_nth(tableEntryList, tableIdx); TableEntry *nextTable = (TableEntry *) list_nth(tableEntryList, tableIdx);
JoinType joinType = JoinTypeBetweenTables(currentTable, nextTable, JoinType joinType = ((JoinExpr *) list_nth(joinExprList, tableIdx - 1))->jointype;
joinRestrictionContext);
if (firstTable) if (firstTable)
{ {

View File

@ -153,8 +153,7 @@ MultiLogicalPlanCreate(Query *originalQuery, Query *queryTree,
} }
else else
{ {
multiQueryNode = MultiNodeTree(queryTree, multiQueryNode = MultiNodeTree(queryTree);
plannerRestrictionContext->joinRestrictionContext);
} }
/* add a root node to serve as the permanent handle to the tree */ /* 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. * group, and limit nodes if they appear in the original query tree.
*/ */
MultiNode * MultiNode *
MultiNodeTree(Query *queryTree, JoinRestrictionContext *joinRestrictionContext) MultiNodeTree(Query *queryTree)
{ {
List *rangeTableList = queryTree->rtable; List *rangeTableList = queryTree->rtable;
List *targetEntryList = queryTree->targetList; List *targetEntryList = queryTree->targetList;
@ -638,8 +637,7 @@ MultiNodeTree(Query *queryTree, JoinRestrictionContext *joinRestrictionContext)
} }
/* recursively create child nested multitree */ /* recursively create child nested multitree */
MultiNode *subqueryExtendedNode = MultiNodeTree(subqueryTree, MultiNode *subqueryExtendedNode = MultiNodeTree(subqueryTree);
joinRestrictionContext);
SetChild((MultiUnaryNode *) subqueryCollectNode, (MultiNode *) subqueryNode); SetChild((MultiUnaryNode *) subqueryCollectNode, (MultiNode *) subqueryNode);
SetChild((MultiUnaryNode *) subqueryNode, subqueryExtendedNode); SetChild((MultiUnaryNode *) subqueryNode, subqueryExtendedNode);
@ -667,10 +665,11 @@ MultiNodeTree(Query *queryTree, JoinRestrictionContext *joinRestrictionContext)
/* consider outer join qualifications as well */ /* consider outer join qualifications as well */
List *allRestrictionClauseList = QualifierList(queryTree->jointree); List *allRestrictionClauseList = QualifierList(queryTree->jointree);
joinClauseList = JoinClauseList(allRestrictionClauseList); joinClauseList = JoinClauseList(allRestrictionClauseList);
List *joinExprList = JoinExprList(queryTree->jointree);
/* we simply donot commute joins as we have at least 1 outer join */ /* we simply donot commute joins as we have at least 1 outer join */
joinOrderList = FixedJoinOrderList(tableEntryList, joinClauseList, joinOrderList = FixedJoinOrderList(tableEntryList, joinClauseList,
joinRestrictionContext); joinExprList);
} }
else else
{ {

View File

@ -111,7 +111,8 @@ static Var * PartitionColumnForPushedDownSubquery(Query *query);
static bool ContainsReferencesToRelids(Query *query, Relids relids, int *foundRelid); static bool ContainsReferencesToRelids(Query *query, Relids relids, int *foundRelid);
static bool ContainsReferencesToRelidsWalker(Node *node, static bool ContainsReferencesToRelidsWalker(Node *node,
RelidsReferenceWalkerContext *context); RelidsReferenceWalkerContext *context);
static bool HasRightRecursiveJoin(FromExpr *fromExpr);
static bool RightRecursiveJoinExprWalker(Node *node, void *context);
/* /*
* ShouldUseSubqueryPushDown determines whether it's desirable to use * ShouldUseSubqueryPushDown determines whether it's desirable to use
@ -173,6 +174,11 @@ ShouldUseSubqueryPushDown(Query *originalQuery, Query *rewrittenQuery,
return true; 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 * 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 * JoinTreeContainsSubquery returns true if the input query contains any subqueries
* in the join tree (e.g., FROM clause). * in the join tree (e.g., FROM clause).

View File

@ -93,7 +93,7 @@ extern bool EnableSingleHashRepartitioning;
extern List * JoinExprList(FromExpr *fromExpr); extern List * JoinExprList(FromExpr *fromExpr);
extern List * JoinOrderList(List *rangeTableEntryList, List *joinClauseList); extern List * JoinOrderList(List *rangeTableEntryList, List *joinClauseList);
extern List * FixedJoinOrderList(List *rangeTableEntryList, List *joinClauseList, extern List * FixedJoinOrderList(List *rangeTableEntryList, List *joinClauseList,
JoinRestrictionContext *joinRestrictionContext); List *joinExprList);
extern bool IsApplicableJoinClause(List *leftTableIdList, uint32 rightTableId, extern bool IsApplicableJoinClause(List *leftTableIdList, uint32 rightTableId,
Node *joinClause); Node *joinClause);
extern List * ApplicableJoinClauses(List *leftTableIdList, uint32 rightTableId, extern List * ApplicableJoinClauses(List *leftTableIdList, uint32 rightTableId,

View File

@ -229,8 +229,7 @@ extern MultiProject * MultiProjectNode(List *targetEntryList);
extern MultiExtendedOp * MultiExtendedOpNode(Query *queryTree, Query *originalQuery); extern MultiExtendedOp * MultiExtendedOpNode(Query *queryTree, Query *originalQuery);
extern DeferredErrorMessage * DeferErrorIfUnsupportedSubqueryRepartition(Query * extern DeferredErrorMessage * DeferErrorIfUnsupportedSubqueryRepartition(Query *
subqueryTree); subqueryTree);
extern MultiNode * MultiNodeTree(Query *queryTree, extern MultiNode * MultiNodeTree(Query *queryTree);
JoinRestrictionContext *joinRestrictionContext);
#endif /* MULTI_LOGICAL_PLANNER_H */ #endif /* MULTI_LOGICAL_PLANNER_H */