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,
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)
{

View File

@ -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
{

View File

@ -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).

View File

@ -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,

View File

@ -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 */