mirror of https://github.com/citusdata/citus.git
right recursive joins should be handled by pushdown planner
parent
17c6187448
commit
be39d028c7
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue