outer-join-noncolocated-dist-tables
aykutbozkurt 2023-02-01 19:59:20 +03:00
parent 2ac2399005
commit 6bacdbab46
5 changed files with 52 additions and 109 deletions

View File

@ -136,7 +136,7 @@ static List * TranslatedVars(PlannerInfo *root, int relationIndex);
static void WarnIfListHasForeignDistributedTable(List *rangeTableList); static void WarnIfListHasForeignDistributedTable(List *rangeTableList);
static void ErrorIfMergeHasUnsupportedTables(Query *parse, List *rangeTableList); static void ErrorIfMergeHasUnsupportedTables(Query *parse, List *rangeTableList);
static void AddFastPathRestrictInfoIntoPlannerContext( static void AddFastPathRestrictInfoIntoPlannerContext(
PlannerRestrictionContext *plannerRestrictionContext); PlannerRestrictionContext *plannerRestrictionContext, int fastPathRelId);
static List * GenerateImplicitJoinRestrictInfoList(PlannerInfo *plannerInfo, static List * GenerateImplicitJoinRestrictInfoList(PlannerInfo *plannerInfo,
RelOptInfo *innerrel, RelOptInfo *innerrel,
RelOptInfo *outerrel); RelOptInfo *outerrel);
@ -706,9 +706,6 @@ PlanFastPathDistributedStmt(DistributedPlanningContext *planContext,
planContext->plannerRestrictionContext->fastPathRestrictionContext-> planContext->plannerRestrictionContext->fastPathRestrictionContext->
fastPathRouterQuery = true; fastPathRouterQuery = true;
planContext->plannerRestrictionContext->fastPathRestrictionContext->
distRelId = fastPathRelId;
if (distributionKeyValue == NULL) if (distributionKeyValue == NULL)
{ {
/* nothing to record */ /* nothing to record */
@ -726,7 +723,8 @@ PlanFastPathDistributedStmt(DistributedPlanningContext *planContext,
planContext->boundParams); planContext->boundParams);
/* generate simple base restrict info inside plannerRestrictionContext */ /* generate simple base restrict info inside plannerRestrictionContext */
AddFastPathRestrictInfoIntoPlannerContext(planContext->plannerRestrictionContext); AddFastPathRestrictInfoIntoPlannerContext(planContext->plannerRestrictionContext,
fastPathRelId);
return CreateDistributedPlannedStmt(planContext); return CreateDistributedPlannedStmt(planContext);
} }
@ -1860,7 +1858,7 @@ CheckNodeCopyAndSerialization(Node *node)
static static
void void
AddFastPathRestrictInfoIntoPlannerContext( AddFastPathRestrictInfoIntoPlannerContext(
PlannerRestrictionContext *plannerRestrictionContext) PlannerRestrictionContext *plannerRestrictionContext, int fastPathRelId)
{ {
if (plannerRestrictionContext->fastPathRestrictionContext == NULL || if (plannerRestrictionContext->fastPathRestrictionContext == NULL ||
plannerRestrictionContext->fastPathRestrictionContext->distributionKeyValue == plannerRestrictionContext->fastPathRestrictionContext->distributionKeyValue ==
@ -1871,8 +1869,7 @@ AddFastPathRestrictInfoIntoPlannerContext(
Const *distKeyVal = Const *distKeyVal =
plannerRestrictionContext->fastPathRestrictionContext->distributionKeyValue; plannerRestrictionContext->fastPathRestrictionContext->distributionKeyValue;
Var *partitionColumn = PartitionColumn( Var *partitionColumn = PartitionColumn(fastPathRelId, 1);
plannerRestrictionContext->fastPathRestrictionContext->distRelId, 1);
OpExpr *partitionExpression = MakeOpExpression(partitionColumn, OpExpr *partitionExpression = MakeOpExpression(partitionColumn,
BTEqualStrategyNumber); BTEqualStrategyNumber);
Node *rightOp = get_rightop((Expr *) partitionExpression); Node *rightOp = get_rightop((Expr *) partitionExpression);

View File

@ -67,8 +67,8 @@ 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 ConvertSemiToInnerInJoinInfoContext(JoinInfoContext *joinOrderContext); static bool ConvertSemiToInnerInJoinOrderInfoList(List *joinOrderInfoList);
static bool JoinInfoContextHasAntiJoin(JoinInfoContext *joinOrderContext); static bool JoinOrderInfoListContainsAntiJoin(List *joinOrderInfoList);
static List * FindApplicableJoinClausesForTables(List *joinRestrictInfoListList, static List * FindApplicableJoinClausesForTables(List *joinRestrictInfoListList,
List *generatedEcJoinClauseList, List *generatedEcJoinClauseList,
List *lhsTableIdList, List *lhsTableIdList,
@ -532,11 +532,11 @@ ExtractApplicableJoinClauseContextFromJoinList(List *joinOrderList)
* applicable join rules for the nodes in the list. * applicable join rules for the nodes in the list.
*/ */
List * List *
FixedJoinOrderList(List *tableEntryList, JoinInfoContext *joinInfoContext, FixedJoinOrderList(List *tableEntryList, List *joinOrderInfoList,
List *joinRestrictInfoListList, List *generatedEcJoinClauseList) List *joinRestrictInfoListList, List *generatedEcJoinClauseList)
{ {
/* we donot support anti joins as ruleutils files cannot deparse JOIN_ANTI */ /* we donot support anti joins as ruleutils files cannot deparse JOIN_ANTI */
if (JoinInfoContextHasAntiJoin(joinInfoContext)) if (JoinOrderInfoListContainsAntiJoin(joinOrderInfoList))
{ {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg( errmsg(
@ -550,14 +550,14 @@ FixedJoinOrderList(List *tableEntryList, JoinInfoContext *joinInfoContext,
* at query_pushdown_planning that planner did not actually plan any semi join. * at query_pushdown_planning that planner did not actually plan any semi join.
* ruleutils files cannot deparse JOIN_SEMI, so we convert those to JOIN_INNER. * ruleutils files cannot deparse JOIN_SEMI, so we convert those to JOIN_INNER.
*/ */
ConvertSemiToInnerInJoinInfoContext(joinInfoContext); ConvertSemiToInnerInJoinOrderInfoList(joinOrderInfoList);
List *joinOrderList = NIL; List *joinOrderList = NIL;
List *joinedTableList = NIL; List *joinedTableList = NIL;
JoinOrderNode *nextJoinNode = NULL; JoinOrderNode *nextJoinNode = NULL;
/* fetch joininfo */ /* fetch joininfo */
JoinInfo *firstJoinInfo = (JoinInfo *) list_nth(joinInfoContext->joinInfoList, 0); JoinOrderInfo *firstJoinInfo = (JoinOrderInfo *) list_nth(joinOrderInfoList, 0);
/* add first table into joinedtable list */ /* add first table into joinedtable list */
TableEntry *firstTable = TableEntryByRangeTableId(tableEntryList, TableEntry *firstTable = TableEntryByRangeTableId(tableEntryList,
@ -577,18 +577,18 @@ FixedJoinOrderList(List *tableEntryList, JoinInfoContext *joinInfoContext,
firstJoinInfo->joinType); firstJoinInfo->joinType);
joinOrderList = lappend(joinOrderList, currentJoinNode); joinOrderList = lappend(joinOrderList, currentJoinNode);
JoinInfo *joinInfo = NULL; JoinOrderInfo *joinOrderInfo = NULL;
foreach_ptr(joinInfo, joinInfoContext->joinInfoList) foreach_ptr(joinOrderInfo, joinOrderInfoList)
{ {
TableEntry *nextTable = TableEntryByRangeTableId(tableEntryList, TableEntry *nextTable = TableEntryByRangeTableId(tableEntryList,
joinInfo->rightTableIdx); joinOrderInfo->rightTableIdx);
nextJoinNode = EvaluateJoinRules(joinedTableList, nextJoinNode = EvaluateJoinRules(joinedTableList,
currentJoinNode, currentJoinNode,
nextTable, nextTable,
joinRestrictInfoListList, joinRestrictInfoListList,
generatedEcJoinClauseList, generatedEcJoinClauseList,
joinInfo->joinType); joinOrderInfo->joinType);
if (nextJoinNode == NULL) if (nextJoinNode == NULL)
{ {
@ -618,16 +618,16 @@ FixedJoinOrderList(List *tableEntryList, JoinInfoContext *joinInfoContext,
/* /*
* JoinInfoContextHasAntiJoin returns true if given join info context contains * JoinOrderInfoListContainsAntiJoin returns true if given join order info list contains
* an anti join. * an anti join.
*/ */
static bool static bool
JoinInfoContextHasAntiJoin(JoinInfoContext *joinOrderContext) JoinOrderInfoListContainsAntiJoin(List *joinOrderInfoList)
{ {
JoinInfo *joinInfo = NULL; JoinOrderInfo *joinOrderInfo = NULL;
foreach_ptr(joinInfo, joinOrderContext->joinInfoList) foreach_ptr(joinOrderInfo, joinOrderInfoList)
{ {
if (joinInfo->joinType == JOIN_ANTI) if (joinOrderInfo->joinType == JOIN_ANTI)
{ {
return true; return true;
} }
@ -638,20 +638,20 @@ JoinInfoContextHasAntiJoin(JoinInfoContext *joinOrderContext)
/* /*
* ConvertSemiToInnerInJoinInfoContext converts semi joins in given join info context * ConvertSemiToInnerInJoinOrderInfoList converts semi joins in given join order info list
* to inner joins as we checked at query_pushdown_planning that planner did not actually * to inner joins as we checked at query_pushdown_planning that planner did not actually
* plan any semi join. ruleutils files cannot deparse JOIN_SEMI, so we convert those * plan any semi join. ruleutils files cannot deparse JOIN_SEMI, so we convert those
* to JOIN_INNER. * to JOIN_INNER.
*/ */
static bool static bool
ConvertSemiToInnerInJoinInfoContext(JoinInfoContext *joinOrderContext) ConvertSemiToInnerInJoinOrderInfoList(List *joinOrderInfoList)
{ {
JoinInfo *joinInfo = NULL; JoinOrderInfo *joinOrderInfo = NULL;
foreach_ptr(joinInfo, joinOrderContext->joinInfoList) foreach_ptr(joinOrderInfo, joinOrderInfoList)
{ {
if (joinInfo->joinType == JOIN_SEMI) if (joinOrderInfo->joinType == JOIN_SEMI)
{ {
joinInfo->joinType = JOIN_INNER; joinOrderInfo->joinType = JOIN_INNER;
} }
} }

View File

@ -93,8 +93,8 @@ static MultiSelect * MultiSelectNode(List *pushdownableClauseList,
static bool IsSelectClause(Node *clause); static bool IsSelectClause(Node *clause);
static List * SelectClauseList(List *clauseList); static List * SelectClauseList(List *clauseList);
static JoinInfoContext * FetchJoinOrderContext(FromExpr *fromExpr); static List * FetchJoinOrderInfoList(FromExpr *fromExpr);
static bool JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext); static bool JoinOrderInfoWalker(Node *node, List **joinOrderInfoList);
/* Local functions forward declarations for applying joins */ /* Local functions forward declarations for applying joins */
static MultiNode * ApplyJoinRule(MultiNode *leftNode, MultiNode *rightNode, static MultiNode * ApplyJoinRule(MultiNode *leftNode, MultiNode *rightNode,
@ -698,11 +698,11 @@ MultiNodeTree(Query *queryTree, PlannerRestrictionContext *plannerRestrictionCon
*/ */
if (FindNodeMatchingCheckFunction((Node *) queryTree->jointree, IsOuterJoinExpr)) if (FindNodeMatchingCheckFunction((Node *) queryTree->jointree, IsOuterJoinExpr))
{ {
/* extract join infos for left recursive join tree */ /* extract join order info list for left recursive join tree */
JoinInfoContext *joinInfoContext = FetchJoinOrderContext(queryTree->jointree); List *joinOrderInfoList = FetchJoinOrderInfoList(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, joinInfoContext, joinOrderList = FixedJoinOrderList(tableEntryList, joinOrderInfoList,
joinRestrictInfoListList, joinRestrictInfoListList,
generatedEcJoinClauseList); generatedEcJoinClauseList);
} }
@ -890,34 +890,34 @@ ExtractRestrictInfosFromPlannerContext(
/* /*
* FetchJoinOrderContext returns all join info for given node. * FetchJoinOrderInfoList returns all join order info list for given node.
*/ */
static JoinInfoContext * static List *
FetchJoinOrderContext(FromExpr *fromExpr) FetchJoinOrderInfoList(FromExpr *fromExpr)
{ {
/* we do not allow cartesian product for outer joins */ /* we do not allow cartesian product for outer joins */
Assert(fromExpr->fromlist && list_length(fromExpr->fromlist) == 1); Assert(fromExpr->fromlist && list_length(fromExpr->fromlist) == 1);
JoinInfoContext *joinInfoContext = palloc0(sizeof(JoinInfoContext)); List *joinOrderInfoList = NIL;
JoinInfoWalker((Node *) fromExpr, joinInfoContext); JoinOrderInfoWalker((Node *) fromExpr, &joinOrderInfoList);
/* only leftmost table will have valid(ltableIdx != 0) ltableIdx */ /* only leftmost table will have valid(ltableIdx != 0) ltableIdx */
int leftMostTableIdx = 0; int leftMostTableIdx = 0;
ExtractLeftMostRangeTableIndex((Node *) fromExpr, &leftMostTableIdx); ExtractLeftMostRangeTableIndex((Node *) fromExpr, &leftMostTableIdx);
Assert(list_length(joinInfoContext->joinInfoList) > 0); Assert(list_length(joinOrderInfoList) > 0);
JoinInfo *leftMostJoinInfo = list_nth(joinInfoContext->joinInfoList, 0); JoinOrderInfo *leftMostJoinInfo = list_nth(joinOrderInfoList, 0);
leftMostJoinInfo->leftTableIdx = leftMostTableIdx; leftMostJoinInfo->leftTableIdx = leftMostTableIdx;
return joinInfoContext; return joinOrderInfoList;
} }
/* /*
* JoinInfoWalker descends into given node and pushes all join info into * JoinOrderInfoWalker descends into given node and pushes all join order infos into
* joinInfoContext. * joinOrderInfoList.
*/ */
static bool static bool
JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext) JoinOrderInfoWalker(Node *node, List **joinOrderInfoList)
{ {
if (node == NULL) if (node == NULL)
{ {
@ -925,8 +925,8 @@ JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext)
} }
/* process the deepest node first */ /* process the deepest node first */
bool walkerResult = expression_tree_walker(node, JoinInfoWalker, bool walkerResult = expression_tree_walker(node, JoinOrderInfoWalker,
(void *) joinInfoContext); joinOrderInfoList);
/* /*
* Get qualifier lists of join and from expression nodes. Note that in the * Get qualifier lists of join and from expression nodes. Note that in the
@ -951,56 +951,14 @@ JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext)
"equal operator"))); "equal operator")));
} }
Node *joinQualifiersNode = joinExpression->quals;
JoinType joinType = joinExpression->jointype; JoinType joinType = joinExpression->jointype;
RangeTblRef *rightTableRef = (RangeTblRef *) joinExpression->rarg; RangeTblRef *rightTableRef = (RangeTblRef *) joinExpression->rarg;
List *joinQualifierList = NIL; JoinOrderInfo *joinOrderInfo = palloc0(sizeof(JoinOrderInfo));
if (joinQualifiersNode != NULL) joinOrderInfo->joinType = joinType;
{ joinOrderInfo->rightTableIdx = rightTableRef->rtindex;
if (IsA(joinQualifiersNode, List))
{
joinQualifierList = (List *) joinQualifiersNode;
}
else
{
/* this part of code only run for subqueries */
Node *joinClause = eval_const_expressions(NULL, joinQualifiersNode);
joinClause = (Node *) canonicalize_qual((Expr *) joinClause, false);
joinQualifierList = make_ands_implicit((Expr *) joinClause);
}
}
JoinInfo *joinInfo = palloc0(sizeof(JoinInfo)); *joinOrderInfoList = lappend(*joinOrderInfoList, joinOrderInfo);
joinInfo->joinType = joinType;
joinInfo->rightTableIdx = rightTableRef->rtindex;
joinInfo->joinQualifierList = joinQualifierList;
joinInfoContext->joinInfoList = lappend(joinInfoContext->joinInfoList, joinInfo);
}
else if (IsA(node, FromExpr))
{
List *fromQualifierList = NIL;
FromExpr *fromExpression = (FromExpr *) node;
Node *fromQualifiersNode = fromExpression->quals;
if (fromQualifiersNode != NULL)
{
if (IsA(fromQualifiersNode, List))
{
fromQualifierList = (List *) fromQualifiersNode;
}
else
{
/* this part of code only run for subqueries */
Node *fromClause = eval_const_expressions(NULL, fromQualifiersNode);
fromClause = (Node *) canonicalize_qual((Expr *) fromClause, false);
fromQualifierList = make_ands_implicit((Expr *) fromClause);
}
joinInfoContext->baseQualifierList =
list_concat(joinInfoContext->baseQualifierList, fromQualifierList);
}
} }
return walkerResult; return walkerResult;

View File

@ -106,8 +106,6 @@ typedef struct FastPathRestrictionContext
* Set to true when distKey = Param; in the queryTree * Set to true when distKey = Param; in the queryTree
*/ */
bool distributionKeyHasParam; bool distributionKeyHasParam;
int distRelId;
}FastPathRestrictionContext; }FastPathRestrictionContext;
typedef struct PlannerRestrictionContext typedef struct PlannerRestrictionContext

View File

@ -96,28 +96,18 @@ typedef struct JoinOrderNode
} JoinOrderNode; } JoinOrderNode;
/* JoinInfoContext stores list of JoinInfo and base qualifications */
typedef struct JoinInfoContext
{
List *baseQualifierList;
List *joinInfoList;
} JoinInfoContext;
/* /*
* JoinInfo stores information about a join between 2 tables. * JoinOrderInfo stores information about a join between 2 tables.
* joinType: join type between left and right tables in join * joinType: join type between left and right tables in join
* leftTableIdx: rtable index for left table in join * leftTableIdx: rtable index for left table in join
* rightTableIdx: rtable index for right table in join * rightTableIdx: rtable index for right table in join
* joinQualifierList: list of join qualifications in join, i.e. ON (...)
*/ */
typedef struct JoinInfo typedef struct JoinOrderInfo
{ {
JoinType joinType; JoinType joinType;
uint32 leftTableIdx; uint32 leftTableIdx;
uint32 rightTableIdx; uint32 rightTableIdx;
List *joinQualifierList; } JoinOrderInfo;
} JoinInfo;
/* Config variables managed via guc.c */ /* Config variables managed via guc.c */
@ -130,7 +120,7 @@ extern List * JoinExprList(FromExpr *fromExpr);
extern List * JoinOrderList(List *rangeTableEntryList, List *joinRestrictInfoListList, extern List * JoinOrderList(List *rangeTableEntryList, List *joinRestrictInfoListList,
List *generatedEcJoinClauseList); List *generatedEcJoinClauseList);
extern List * FixedJoinOrderList(List *rangeTableEntryList, extern List * FixedJoinOrderList(List *rangeTableEntryList,
JoinInfoContext *joinInfoContext, List *joinOrderInfoList,
List *joinRestrictInfoListList, List *joinRestrictInfoListList,
List *generatedEcJoinClauseList); List *generatedEcJoinClauseList);
extern bool IsApplicableJoinClause(List *leftTableIdList, uint32 rightTableId, extern bool IsApplicableJoinClause(List *leftTableIdList, uint32 rightTableId,