diff --git a/src/backend/distributed/planner/multi_logical_optimizer.c b/src/backend/distributed/planner/multi_logical_optimizer.c index 395f94bf0..77914f4ec 100644 --- a/src/backend/distributed/planner/multi_logical_optimizer.c +++ b/src/backend/distributed/planner/multi_logical_optimizer.c @@ -3400,10 +3400,10 @@ SupportedLateralQuery(Query *parentQuery, Query *lateralQuery) bool supportedLateralQuery = false; List *outerCompositeFieldList = NIL; List *localCompositeFieldList = NIL; - List *whereClauseList = WhereClauseList(lateralQuery->jointree); + ListCell *qualifierCell = NULL; - ListCell *whereClauseCell = NULL; - foreach(whereClauseCell, whereClauseList) + List *qualifierList = QualifierList(lateralQuery->jointree); + foreach(qualifierCell, qualifierList) { OpExpr *operatorExpression = NULL; List *argumentList = NIL; @@ -3417,13 +3417,13 @@ SupportedLateralQuery(Query *parentQuery, Query *lateralQuery) bool outerColumnIsPartitionColumn = false; bool localColumnIsPartitionColumn = false; - Node *clause = (Node *) lfirst(whereClauseCell); - if (!IsA(clause, OpExpr)) + Node *qualifier = (Node *) lfirst(qualifierCell); + if (!IsA(qualifier, OpExpr)) { continue; } - operatorExpression = (OpExpr *) clause; + operatorExpression = (OpExpr *) qualifier; argumentList = operatorExpression->args; /* @@ -3566,8 +3566,8 @@ JoinOnPartitionColumn(Query *query) bool joinOnPartitionColumn = false; List *leftCompositeFieldList = NIL; List *rightCompositeFieldList = NIL; - List *whereClauseList = WhereClauseList(query->jointree); - List *joinClauseList = JoinClauseList(whereClauseList); + List *qualifierList = QualifierList(query->jointree); + List *joinClauseList = JoinClauseList(qualifierList); ListCell *joinClauseCell = NULL; foreach(joinClauseCell, joinClauseList) diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index fa4384a02..067835338 100644 --- a/src/backend/distributed/planner/multi_logical_planner.c +++ b/src/backend/distributed/planner/multi_logical_planner.c @@ -38,6 +38,14 @@ bool SubqueryPushdown = false; /* is subquery pushdown enabled */ +/* Struct to differentiate different qualifier types in an expression tree walker */ +typedef struct QualifierWalkerContext +{ + List *baseQualifierList; + List *outerJoinQualifierList; +} QualifierWalkerContext; + + /* Function pointer type definition for apply join rule functions */ typedef MultiNode *(*RuleApplyFunction) (MultiNode *leftNode, MultiNode *rightNode, Var *partitionColumn, JoinType joinType, @@ -56,7 +64,8 @@ static bool HasOuterJoinWalker(Node *node, void *maxJoinLevel); static bool HasComplexJoinOrder(Query *queryTree); static bool HasComplexRangeTableType(Query *queryTree); static void ValidateClauseList(List *clauseList); -static bool ExtractFromExpressionWalker(Node *node, List **qualifierList); +static bool ExtractFromExpressionWalker(Node *node, + QualifierWalkerContext *walkerContext); static List * MultiTableNodeList(List *tableEntryList, List *rangeTableList); static List * AddMultiCollectNodes(List *tableNodeList); static MultiNode * MultiJoinTree(List *joinOrderList, List *collectTableList, @@ -720,23 +729,48 @@ ExtractRangeTableIndexWalker(Node *node, List **rangeTableIndexList) /* * WhereClauseList walks over the FROM expression in the query tree, and builds * a list of all clauses from the expression tree. The function checks for both - * implicitly and explicitly defined clauses. Explicit clauses are expressed as - * "SELECT ... FROM R1 INNER JOIN R2 ON R1.A = R2.A". Implicit joins differ in - * that they live in the WHERE clause, and are expressed as "SELECT ... FROM - * ... WHERE R1.a = R2.a". + * implicitly and explicitly defined clauses, but only selects INNER join + * explicit clauses, and skips any outer-join clauses. Explicit clauses are + * expressed as "SELECT ... FROM R1 INNER JOIN R2 ON R1.A = R2.A". Implicit + * joins differ in that they live in the WHERE clause, and are expressed as + * "SELECT ... FROM ... WHERE R1.a = R2.a". */ List * WhereClauseList(FromExpr *fromExpr) { FromExpr *fromExprCopy = copyObject(fromExpr); + QualifierWalkerContext *walkerContext = palloc0(sizeof(QualifierWalkerContext)); List *whereClauseList = NIL; - ExtractFromExpressionWalker((Node *) fromExprCopy, &whereClauseList); + ExtractFromExpressionWalker((Node *) fromExprCopy, walkerContext); + whereClauseList = walkerContext->baseQualifierList; return whereClauseList; } +/* + * QualifierList walks over the FROM expression in the query tree, and builds + * a list of all qualifiers from the expression tree. The function checks for + * both implicitly and explicitly defined qualifiers. Note that this function + * is very similar to WhereClauseList(), but QualifierList() also includes + * outer-join clauses. + */ +List * +QualifierList(FromExpr *fromExpr) +{ + FromExpr *fromExprCopy = copyObject(fromExpr); + QualifierWalkerContext *walkerContext = palloc0(sizeof(QualifierWalkerContext)); + List *qualifierList = NIL; + + ExtractFromExpressionWalker((Node *) fromExprCopy, walkerContext); + qualifierList = list_concat(qualifierList, walkerContext->baseQualifierList); + qualifierList = list_concat(qualifierList, walkerContext->outerJoinQualifierList); + + return qualifierList; +} + + /* * ValidateClauseList walks over the given list of clauses, and checks that we * can recognize all the clauses. This function ensures that we do not drop an @@ -790,8 +824,15 @@ JoinClauseList(List *whereClauseList) /* * ExtractFromExpressionWalker walks over a FROM expression, and finds all - * explicit qualifiers in the expression. The function looks at join and from - * expression nodes to find explicit qualifiers, and returns these qualifiers. + * implicit and explicit qualifiers in the expression. The function looks at + * join and from expression nodes to find qualifiers, and returns these + * qualifiers. + * + * Note that we don't want outer join clauses in regular outer join planning, + * but we need outer join clauses in subquery pushdown prerequisite checks. + * Therefore, outer join qualifiers are returned in a different list than other + * qualifiers inside the given walker context. For this reason, we return two + * qualifier lists. * * Note that we check if the qualifier node in join and from expression nodes * is a list node. If it is not a list node which is the case for subqueries, @@ -803,7 +844,7 @@ JoinClauseList(List *whereClauseList) * query tree. */ static bool -ExtractFromExpressionWalker(Node *node, List **qualifierList) +ExtractFromExpressionWalker(Node *node, QualifierWalkerContext *walkerContext) { bool walkerResult = false; if (node == NULL) @@ -824,11 +865,7 @@ ExtractFromExpressionWalker(Node *node, List **qualifierList) Node *joinQualifiersNode = joinExpression->quals; JoinType joinType = joinExpression->jointype; - /* - * We only extract qualifiers from inner join clauses, which can be - * treated as WHERE clauses. - */ - if (joinQualifiersNode != NULL && joinType == JOIN_INNER) + if (joinQualifiersNode != NULL) { if (IsA(joinQualifiersNode, List)) { @@ -841,8 +878,18 @@ ExtractFromExpressionWalker(Node *node, List **qualifierList) joinClause = (Node *) canonicalize_qual((Expr *) joinClause); joinQualifierList = make_ands_implicit((Expr *) joinClause); } + } - (*qualifierList) = list_concat(*qualifierList, joinQualifierList); + /* return outer join clauses in a separate list */ + if (joinType == JOIN_INNER) + { + walkerContext->baseQualifierList = + list_concat(walkerContext->baseQualifierList, joinQualifierList); + } + else if (IS_OUTER_JOIN(joinType)) + { + walkerContext->outerJoinQualifierList = + list_concat(walkerContext->outerJoinQualifierList, joinQualifierList); } } else if (IsA(node, FromExpr)) @@ -865,12 +912,13 @@ ExtractFromExpressionWalker(Node *node, List **qualifierList) fromQualifierList = make_ands_implicit((Expr *) fromClause); } - (*qualifierList) = list_concat(*qualifierList, fromQualifierList); + walkerContext->baseQualifierList = + list_concat(walkerContext->baseQualifierList, fromQualifierList); } } walkerResult = expression_tree_walker(node, ExtractFromExpressionWalker, - (void *) qualifierList); + (void *) walkerContext); return walkerResult; } @@ -1867,8 +1915,8 @@ static MultiNode * SubqueryPushdownMultiPlanTree(Query *queryTree, List *subqueryEntryList) { List *targetEntryList = queryTree->targetList; - List *whereClauseList = NIL; - List *whereClauseColumnList = NIL; + List *qualifierList = NIL; + List *qualifierColumnList = NIL; List *targetListColumnList = NIL; List *columnList = NIL; ListCell *columnCell = NULL; @@ -1884,9 +1932,9 @@ SubqueryPushdownMultiPlanTree(Query *queryTree, List *subqueryEntryList) ErrorIfQueryNotSupported(queryTree); ErrorIfSubqueryJoin(queryTree); - /* extract where clause qualifiers and verify we can plan for them */ - whereClauseList = WhereClauseList(queryTree->jointree); - ValidateClauseList(whereClauseList); + /* extract qualifiers and verify we can plan for them */ + qualifierList = QualifierList(queryTree->jointree); + ValidateClauseList(qualifierList); /* * We disregard pulled subqueries. This changes order of range table list. @@ -1897,10 +1945,10 @@ SubqueryPushdownMultiPlanTree(Query *queryTree, List *subqueryEntryList) */ Assert(list_length(subqueryEntryList) == 1); - whereClauseColumnList = pull_var_clause_default((Node *) whereClauseList); + qualifierColumnList = pull_var_clause_default((Node *) qualifierList); targetListColumnList = pull_var_clause_default((Node *) targetEntryList); - columnList = list_concat(whereClauseColumnList, targetListColumnList); + columnList = list_concat(qualifierColumnList, targetListColumnList); foreach(columnCell, columnList) { Var *column = (Var *) lfirst(columnCell); @@ -1915,7 +1963,7 @@ SubqueryPushdownMultiPlanTree(Query *queryTree, List *subqueryEntryList) currentTopNode = (MultiNode *) subqueryCollectNode; /* build select node if the query has selection criteria */ - selectNode = MultiSelectNode(whereClauseList); + selectNode = MultiSelectNode(qualifierList); if (selectNode != NULL) { SetChild((MultiUnaryNode *) selectNode, currentTopNode); diff --git a/src/include/distributed/multi_logical_planner.h b/src/include/distributed/multi_logical_planner.h index 839dd740b..3698934d3 100644 --- a/src/include/distributed/multi_logical_planner.h +++ b/src/include/distributed/multi_logical_planner.h @@ -198,6 +198,7 @@ extern bool IsJoinClause(Node *clause); extern List * SubqueryEntryList(Query *queryTree); extern bool ExtractRangeTableIndexWalker(Node *node, List **rangeTableIndexList); extern List * WhereClauseList(FromExpr *fromExpr); +extern List * QualifierList(FromExpr *fromExpr); extern List * TableEntryList(List *rangeTableList); extern bool ExtractRangeTableRelationWalker(Node *node, List **rangeTableList); extern bool ExtractRangeTableEntryWalker(Node *node, List **rangeTableList);