From 3cc9536bef8845524dc8078deeee8d795d25dfb2 Mon Sep 17 00:00:00 2001 From: aykutbozkurt Date: Mon, 19 Dec 2022 22:42:23 +0300 Subject: [PATCH] find join type from left recursive join tree --- .../distributed/planner/multi_join_order.c | 121 +++++++++++++++++- src/include/distributed/multi_join_order.h | 11 ++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/backend/distributed/planner/multi_join_order.c b/src/backend/distributed/planner/multi_join_order.c index da45c6205..47ea83c38 100644 --- a/src/backend/distributed/planner/multi_join_order.c +++ b/src/backend/distributed/planner/multi_join_order.c @@ -55,6 +55,7 @@ static RuleEvalFunction RuleEvalFunctionArray[JOIN_RULE_LAST] = { 0 }; /* join r /* Local functions forward declarations */ static bool JoinExprListWalker(Node *node, List **joinList); static bool ExtractLeftMostRangeTableIndex(Node *node, int *rangeTableIndex); +static bool ExtractRightMostRangeTableIndex(Node *node, int *rangeTableIndex); static List * JoinOrderForTable(TableEntry *firstTable, List *tableEntryList, List *joinClauseList); static List * BestJoinOrder(List *candidateJoinOrders); @@ -64,6 +65,9 @@ static List * LatestLargeDataTransfer(List *candidateJoinOrders); static void PrintJoinOrderList(List *joinOrder); static uint32 LargeDataTransferLocation(List *joinOrder); static List * TableEntryListDifference(List *lhsTableList, List *rhsTableList); +static bool JoinTypeJoinExprWalker(Node *node, JoinTypeContext *joinTypeContext); +static JoinType * FindJoinTypeBetweenTables(List *joinExprList, List *leftTableIdxList, + uint32 rtableIdx); /* Local functions forward declarations for join evaluations */ static JoinOrderNode * EvaluateJoinRules(List *joinedTableList, @@ -209,6 +213,40 @@ ExtractLeftMostRangeTableIndex(Node *node, int *rangeTableIndex) } +/* + * ExtractRightMostRangeTableIndex extracts the range table index of the right-most + * leaf in a join tree. + */ +static bool +ExtractRightMostRangeTableIndex(Node *node, int *rangeTableIndex) +{ + bool walkerResult = false; + + Assert(node != NULL); + + if (IsA(node, JoinExpr)) + { + JoinExpr *joinExpr = (JoinExpr *) node; + + walkerResult = ExtractRightMostRangeTableIndex(joinExpr->rarg, rangeTableIndex); + } + else if (IsA(node, RangeTblRef)) + { + RangeTblRef *rangeTableRef = (RangeTblRef *) node; + + *rangeTableIndex = rangeTableRef->rtindex; + walkerResult = true; + } + else + { + walkerResult = expression_tree_walker(node, ExtractRightMostRangeTableIndex, + rangeTableIndex); + } + + return walkerResult; +} + + /* * JoinOnColumns determines whether two columns are joined by a given join clause list. */ @@ -325,6 +363,71 @@ JoinOrderList(List *tableEntryList, List *joinClauseList) } +static JoinType * +FindJoinTypeBetweenTables(List *joinExprList, List *leftTableIdxList, uint32 rtableIdx) +{ + uint32 ltableIdx; + foreach_int(ltableIdx, leftTableIdxList) + { + JoinTypeContext joinTypeContext = { + .ltableIdx = ltableIdx, + .rtableIdx = rtableIdx, + .joinType = NULL, + }; + + JoinExpr *joinExpr = NULL; + foreach_ptr(joinExpr, joinExprList) + { + JoinTypeJoinExprWalker((Node *) joinExpr, &joinTypeContext); + if (joinTypeContext.joinType) + { + return joinTypeContext.joinType; + } + } + } + + return NULL; +} + + +/* + * JoinTypeJoinExprWalker finds join type between range table indexes. + * Only handles left recursive join trees. + */ +static bool +JoinTypeJoinExprWalker(Node *node, JoinTypeContext *joinTypeContext) +{ + if (node == NULL) + { + return false; + } + + if (IsA(node, JoinExpr)) + { + JoinExpr *joinExpr = (JoinExpr *) node; + + if (IsA(joinExpr->rarg, RangeTblRef) && + ((RangeTblRef *) joinExpr->rarg)->rtindex == joinTypeContext->rtableIdx) + { + /* + * we found right table entry, then we need to find rightmost entry of left arg + * of the join tree + */ + int ltableIdx = 0; + ExtractRightMostRangeTableIndex(joinExpr->larg, <ableIdx); + + if (joinTypeContext->ltableIdx == ltableIdx) + { + joinTypeContext->joinType = &(joinExpr->jointype); + return true; + } + } + } + + return expression_tree_walker(node, JoinTypeJoinExprWalker, joinTypeContext); +} + + /* * FixedJoinOrderList returns the best fixed join order according to * applicable join rules for the nodes in the list. @@ -345,13 +448,29 @@ FixedJoinOrderList(List *tableEntryList, List *joinClauseList, { TableEntry *currentTable = (TableEntry *) list_nth(tableEntryList, tableIdx - 1); TableEntry *nextTable = (TableEntry *) list_nth(tableEntryList, tableIdx); - JoinType joinType = ((JoinExpr *) list_nth(joinExprList, tableIdx - 1))->jointype; if (firstTable) { /* add first table into joinedtable list */ joinedTableList = lappend(joinedTableList, currentTable); + } + /* + * if we cannot find join type between tables, then it is cartesian product. We can use JOIN_INNER, + * which will be executed as cartesian product. + */ + JoinType joinType = JOIN_INNER; + List *joinedTableIdxList = RangeTableIdList(joinedTableList); + JoinType *applicableJoinType = FindJoinTypeBetweenTables(joinExprList, + joinedTableIdxList, + nextTable->rangeTableId); + if (applicableJoinType) + { + joinType = *applicableJoinType; + } + + if (firstTable) + { /* create join node for the first table */ JoinRuleType joinRule = JOIN_RULE_INVALID_FIRST; Oid relationId = currentTable->relationId; diff --git a/src/include/distributed/multi_join_order.h b/src/include/distributed/multi_join_order.h index 459146266..923c7184c 100644 --- a/src/include/distributed/multi_join_order.h +++ b/src/include/distributed/multi_join_order.h @@ -83,6 +83,17 @@ typedef struct JoinOrderNode } JoinOrderNode; +/* + * JoinTypeContext stores jointype between given rangetable indexes + */ +typedef struct JoinTypeContext +{ + uint32 ltableIdx; + uint32 rtableIdx; + JoinType *joinType; +} JoinTypeContext; + + /* Config variables managed via guc.c */ extern bool LogMultiJoinOrder; extern bool EnableSingleHashRepartitioning;