find join type from left recursive join tree

outer-join-noncolocated-dist-tables
aykutbozkurt 2022-12-19 22:42:23 +03:00
parent 8951e99d39
commit 3cc9536bef
2 changed files with 131 additions and 1 deletions

View File

@ -55,6 +55,7 @@ static RuleEvalFunction RuleEvalFunctionArray[JOIN_RULE_LAST] = { 0 }; /* join r
/* Local functions forward declarations */ /* Local functions forward declarations */
static bool JoinExprListWalker(Node *node, List **joinList); static bool JoinExprListWalker(Node *node, List **joinList);
static bool ExtractLeftMostRangeTableIndex(Node *node, int *rangeTableIndex); static bool ExtractLeftMostRangeTableIndex(Node *node, int *rangeTableIndex);
static bool ExtractRightMostRangeTableIndex(Node *node, int *rangeTableIndex);
static List * JoinOrderForTable(TableEntry *firstTable, List *tableEntryList, static List * JoinOrderForTable(TableEntry *firstTable, List *tableEntryList,
List *joinClauseList); List *joinClauseList);
static List * BestJoinOrder(List *candidateJoinOrders); static List * BestJoinOrder(List *candidateJoinOrders);
@ -64,6 +65,9 @@ static List * LatestLargeDataTransfer(List *candidateJoinOrders);
static void PrintJoinOrderList(List *joinOrder); static void PrintJoinOrderList(List *joinOrder);
static uint32 LargeDataTransferLocation(List *joinOrder); static uint32 LargeDataTransferLocation(List *joinOrder);
static List * TableEntryListDifference(List *lhsTableList, List *rhsTableList); 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 */ /* Local functions forward declarations for join evaluations */
static JoinOrderNode * EvaluateJoinRules(List *joinedTableList, 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. * 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, &ltableIdx);
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 * 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.
@ -345,13 +448,29 @@ 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 = ((JoinExpr *) list_nth(joinExprList, tableIdx - 1))->jointype;
if (firstTable) if (firstTable)
{ {
/* add first table into joinedtable list */ /* add first table into joinedtable list */
joinedTableList = lappend(joinedTableList, currentTable); 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 */ /* create join node for the first table */
JoinRuleType joinRule = JOIN_RULE_INVALID_FIRST; JoinRuleType joinRule = JOIN_RULE_INVALID_FIRST;
Oid relationId = currentTable->relationId; Oid relationId = currentTable->relationId;

View File

@ -83,6 +83,17 @@ typedef struct JoinOrderNode
} 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 */ /* Config variables managed via guc.c */
extern bool LogMultiJoinOrder; extern bool LogMultiJoinOrder;
extern bool EnableSingleHashRepartitioning; extern bool EnableSingleHashRepartitioning;