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,
|
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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue