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

View File

@ -67,8 +67,8 @@ static List * LatestLargeDataTransfer(List *candidateJoinOrders);
static void PrintJoinOrderList(List *joinOrder);
static uint32 LargeDataTransferLocation(List *joinOrder);
static List * TableEntryListDifference(List *lhsTableList, List *rhsTableList);
static bool ConvertSemiToInnerInJoinInfoContext(JoinInfoContext *joinOrderContext);
static bool JoinInfoContextHasAntiJoin(JoinInfoContext *joinOrderContext);
static bool ConvertSemiToInnerInJoinOrderInfoList(List *joinOrderInfoList);
static bool JoinOrderInfoListContainsAntiJoin(List *joinOrderInfoList);
static List * FindApplicableJoinClausesForTables(List *joinRestrictInfoListList,
List *generatedEcJoinClauseList,
List *lhsTableIdList,
@ -532,11 +532,11 @@ ExtractApplicableJoinClauseContextFromJoinList(List *joinOrderList)
* applicable join rules for the nodes in the list.
*/
List *
FixedJoinOrderList(List *tableEntryList, JoinInfoContext *joinInfoContext,
FixedJoinOrderList(List *tableEntryList, List *joinOrderInfoList,
List *joinRestrictInfoListList, List *generatedEcJoinClauseList)
{
/* 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),
errmsg(
@ -550,14 +550,14 @@ FixedJoinOrderList(List *tableEntryList, JoinInfoContext *joinInfoContext,
* 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.
*/
ConvertSemiToInnerInJoinInfoContext(joinInfoContext);
ConvertSemiToInnerInJoinOrderInfoList(joinOrderInfoList);
List *joinOrderList = NIL;
List *joinedTableList = NIL;
JoinOrderNode *nextJoinNode = NULL;
/* fetch joininfo */
JoinInfo *firstJoinInfo = (JoinInfo *) list_nth(joinInfoContext->joinInfoList, 0);
JoinOrderInfo *firstJoinInfo = (JoinOrderInfo *) list_nth(joinOrderInfoList, 0);
/* add first table into joinedtable list */
TableEntry *firstTable = TableEntryByRangeTableId(tableEntryList,
@ -577,18 +577,18 @@ FixedJoinOrderList(List *tableEntryList, JoinInfoContext *joinInfoContext,
firstJoinInfo->joinType);
joinOrderList = lappend(joinOrderList, currentJoinNode);
JoinInfo *joinInfo = NULL;
foreach_ptr(joinInfo, joinInfoContext->joinInfoList)
JoinOrderInfo *joinOrderInfo = NULL;
foreach_ptr(joinOrderInfo, joinOrderInfoList)
{
TableEntry *nextTable = TableEntryByRangeTableId(tableEntryList,
joinInfo->rightTableIdx);
joinOrderInfo->rightTableIdx);
nextJoinNode = EvaluateJoinRules(joinedTableList,
currentJoinNode,
nextTable,
joinRestrictInfoListList,
generatedEcJoinClauseList,
joinInfo->joinType);
joinOrderInfo->joinType);
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.
*/
static bool
JoinInfoContextHasAntiJoin(JoinInfoContext *joinOrderContext)
JoinOrderInfoListContainsAntiJoin(List *joinOrderInfoList)
{
JoinInfo *joinInfo = NULL;
foreach_ptr(joinInfo, joinOrderContext->joinInfoList)
JoinOrderInfo *joinOrderInfo = NULL;
foreach_ptr(joinOrderInfo, joinOrderInfoList)
{
if (joinInfo->joinType == JOIN_ANTI)
if (joinOrderInfo->joinType == JOIN_ANTI)
{
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
* plan any semi join. ruleutils files cannot deparse JOIN_SEMI, so we convert those
* to JOIN_INNER.
*/
static bool
ConvertSemiToInnerInJoinInfoContext(JoinInfoContext *joinOrderContext)
ConvertSemiToInnerInJoinOrderInfoList(List *joinOrderInfoList)
{
JoinInfo *joinInfo = NULL;
foreach_ptr(joinInfo, joinOrderContext->joinInfoList)
JoinOrderInfo *joinOrderInfo = NULL;
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 List * SelectClauseList(List *clauseList);
static JoinInfoContext * FetchJoinOrderContext(FromExpr *fromExpr);
static bool JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext);
static List * FetchJoinOrderInfoList(FromExpr *fromExpr);
static bool JoinOrderInfoWalker(Node *node, List **joinOrderInfoList);
/* Local functions forward declarations for applying joins */
static MultiNode * ApplyJoinRule(MultiNode *leftNode, MultiNode *rightNode,
@ -698,11 +698,11 @@ MultiNodeTree(Query *queryTree, PlannerRestrictionContext *plannerRestrictionCon
*/
if (FindNodeMatchingCheckFunction((Node *) queryTree->jointree, IsOuterJoinExpr))
{
/* extract join infos for left recursive join tree */
JoinInfoContext *joinInfoContext = FetchJoinOrderContext(queryTree->jointree);
/* extract join order info list for left recursive join tree */
List *joinOrderInfoList = FetchJoinOrderInfoList(queryTree->jointree);
/* we simply donot commute joins as we have at least 1 outer join */
joinOrderList = FixedJoinOrderList(tableEntryList, joinInfoContext,
joinOrderList = FixedJoinOrderList(tableEntryList, joinOrderInfoList,
joinRestrictInfoListList,
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 *
FetchJoinOrderContext(FromExpr *fromExpr)
static List *
FetchJoinOrderInfoList(FromExpr *fromExpr)
{
/* we do not allow cartesian product for outer joins */
Assert(fromExpr->fromlist && list_length(fromExpr->fromlist) == 1);
JoinInfoContext *joinInfoContext = palloc0(sizeof(JoinInfoContext));
JoinInfoWalker((Node *) fromExpr, joinInfoContext);
List *joinOrderInfoList = NIL;
JoinOrderInfoWalker((Node *) fromExpr, &joinOrderInfoList);
/* only leftmost table will have valid(ltableIdx != 0) ltableIdx */
int leftMostTableIdx = 0;
ExtractLeftMostRangeTableIndex((Node *) fromExpr, &leftMostTableIdx);
Assert(list_length(joinInfoContext->joinInfoList) > 0);
JoinInfo *leftMostJoinInfo = list_nth(joinInfoContext->joinInfoList, 0);
Assert(list_length(joinOrderInfoList) > 0);
JoinOrderInfo *leftMostJoinInfo = list_nth(joinOrderInfoList, 0);
leftMostJoinInfo->leftTableIdx = leftMostTableIdx;
return joinInfoContext;
return joinOrderInfoList;
}
/*
* JoinInfoWalker descends into given node and pushes all join info into
* joinInfoContext.
* JoinOrderInfoWalker descends into given node and pushes all join order infos into
* joinOrderInfoList.
*/
static bool
JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext)
JoinOrderInfoWalker(Node *node, List **joinOrderInfoList)
{
if (node == NULL)
{
@ -925,8 +925,8 @@ JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext)
}
/* process the deepest node first */
bool walkerResult = expression_tree_walker(node, JoinInfoWalker,
(void *) joinInfoContext);
bool walkerResult = expression_tree_walker(node, JoinOrderInfoWalker,
joinOrderInfoList);
/*
* Get qualifier lists of join and from expression nodes. Note that in the
@ -951,56 +951,14 @@ JoinInfoWalker(Node *node, JoinInfoContext *joinInfoContext)
"equal operator")));
}
Node *joinQualifiersNode = joinExpression->quals;
JoinType joinType = joinExpression->jointype;
RangeTblRef *rightTableRef = (RangeTblRef *) joinExpression->rarg;
List *joinQualifierList = NIL;
if (joinQualifiersNode != NULL)
{
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);
}
}
JoinOrderInfo *joinOrderInfo = palloc0(sizeof(JoinOrderInfo));
joinOrderInfo->joinType = joinType;
joinOrderInfo->rightTableIdx = rightTableRef->rtindex;
JoinInfo *joinInfo = palloc0(sizeof(JoinInfo));
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);
}
*joinOrderInfoList = lappend(*joinOrderInfoList, joinOrderInfo);
}
return walkerResult;

View File

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

View File

@ -96,28 +96,18 @@ typedef struct 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
* leftTableIdx: rtable index for left 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;
uint32 leftTableIdx;
uint32 rightTableIdx;
List *joinQualifierList;
} JoinInfo;
} JoinOrderInfo;
/* Config variables managed via guc.c */
@ -130,7 +120,7 @@ extern List * JoinExprList(FromExpr *fromExpr);
extern List * JoinOrderList(List *rangeTableEntryList, List *joinRestrictInfoListList,
List *generatedEcJoinClauseList);
extern List * FixedJoinOrderList(List *rangeTableEntryList,
JoinInfoContext *joinInfoContext,
List *joinOrderInfoList,
List *joinRestrictInfoListList,
List *generatedEcJoinClauseList);
extern bool IsApplicableJoinClause(List *leftTableIdList, uint32 rightTableId,