diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index 37d3b9b9a..79be0cbe3 100644 --- a/src/backend/distributed/planner/multi_logical_planner.c +++ b/src/backend/distributed/planner/multi_logical_planner.c @@ -59,7 +59,6 @@ static bool HasComplexJoinOrder(Query *queryTree); static bool HasComplexRangeTableType(Query *queryTree); static void ValidateClauseList(List *clauseList); static bool ExtractFromExpressionWalker(Node *node, List **qualifierList); -static bool IsJoinClause(Node *clause); static List * MultiTableNodeList(List *tableEntryList, List *rangeTableList); static List * AddMultiCollectNodes(List *tableNodeList); static MultiNode * MultiJoinTree(List *joinOrderList, List *collectTableList, @@ -834,8 +833,13 @@ ExtractFromExpressionWalker(Node *node, List **qualifierList) List *joinQualifierList = NIL; JoinExpr *joinExpression = (JoinExpr *) node; Node *joinQualifiersNode = joinExpression->quals; + JoinType joinType = joinExpression->jointype; - if (joinQualifiersNode != NULL) + /* + * We only extract qualifiers from inner join clauses, which can be + * treated as WHERE clauses. + */ + if (joinQualifiersNode != NULL && joinType == JOIN_INNER) { if (IsA(joinQualifiersNode, List)) { @@ -888,7 +892,7 @@ ExtractFromExpressionWalker(Node *node, List **qualifierList) * criteria. Our criteria defines a join clause as an equi join operator between * two columns that belong to two different tables. */ -static bool +bool IsJoinClause(Node *clause) { bool isJoinClause = false; diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 3ceca75ba..f714aa3c3 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -3286,13 +3286,23 @@ JoinSequenceArray(List *rangeTableFragmentsList, Query *jobQuery, List *depended foreach(nextJoinClauseCell, nextJoinClauseList) { OpExpr *nextJoinClause = (OpExpr *) lfirst(nextJoinClauseCell); - Var *leftColumn = LeftColumn(nextJoinClause); - Var *rightColumn = RightColumn(nextJoinClause); - Index leftRangeTableId = leftColumn->varno; - Index rightRangeTableId = rightColumn->varno; + Var *leftColumn = NULL; + Var *rightColumn = NULL; + Index leftRangeTableId = 0; + Index rightRangeTableId = 0; bool leftPartitioned = false; bool rightPartitioned = false; + if (!IsJoinClause((Node *) nextJoinClause)) + { + continue; + } + + leftColumn = LeftColumn(nextJoinClause); + rightColumn = RightColumn(nextJoinClause); + leftRangeTableId = leftColumn->varno; + rightRangeTableId = rightColumn->varno; + /* * We have a table from the existing join list joining with the next * table. First resolve the existing table's range table id. diff --git a/src/include/distributed/multi_logical_planner.h b/src/include/distributed/multi_logical_planner.h index 825251613..ce9a8d092 100644 --- a/src/include/distributed/multi_logical_planner.h +++ b/src/include/distributed/multi_logical_planner.h @@ -192,6 +192,7 @@ extern bool BinaryOperator(MultiNode *node); extern List * OutputTableIdList(MultiNode *multiNode); extern List * FindNodesOfType(MultiNode *node, int type); extern List * JoinClauseList(List *whereClauseList); +extern bool IsJoinClause(Node *clause); extern List * SubqueryEntryList(Query *queryTree); extern bool ExtractRangeTableIndexWalker(Node *node, List **rangeTableIndexList); extern List * WhereClauseList(FromExpr *fromExpr); diff --git a/src/test/regress/input/multi_outer_join.source b/src/test/regress/input/multi_outer_join.source index d8a6b11e1..6aeca757f 100644 --- a/src/test/regress/input/multi_outer_join.source +++ b/src/test/regress/input/multi_outer_join.source @@ -113,6 +113,27 @@ WHERE r_custkey = 5; +-- Apply a filter before the join +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND r_custkey = 5); + +-- Apply a filter before the join (no matches right) +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND r_custkey = -1 /* nonexistant */); + +-- Apply a filter before the join (no matches left) +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND l_custkey = -1 /* nonexistant */); + -- Right join should be disallowed in this case SELECT min(r_custkey), max(r_custkey) @@ -191,6 +212,14 @@ WHERE r_custkey = 21; +-- Apply a filter before the join +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND r_custkey = 21); + + -- Right join should be allowed in this case SELECT min(r_custkey), max(r_custkey) diff --git a/src/test/regress/output/multi_outer_join.source b/src/test/regress/output/multi_outer_join.source index 0abc638bc..fedd7a657 100644 --- a/src/test/regress/output/multi_outer_join.source +++ b/src/test/regress/output/multi_outer_join.source @@ -146,6 +146,42 @@ LOG: join order: [ "multi_outer_join_left" ][ broadcast join "multi_outer_join_ 5 | 5 (1 row) +-- Apply a filter before the join +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND r_custkey = 5); +LOG: join order: [ "multi_outer_join_left" ][ broadcast join "multi_outer_join_right" ] + count | count +-------+------- + 20 | 1 +(1 row) + +-- Apply a filter before the join (no matches right) +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND r_custkey = -1 /* nonexistant */); +LOG: join order: [ "multi_outer_join_left" ][ broadcast join "multi_outer_join_right" ] + count | count +-------+------- + 20 | 0 +(1 row) + +-- Apply a filter before the join (no matches left) +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND l_custkey = -1 /* nonexistant */); +LOG: join order: [ "multi_outer_join_left" ][ broadcast join "multi_outer_join_right" ] + count | count +-------+------- + 20 | 0 +(1 row) + -- Right join should be disallowed in this case SELECT min(r_custkey), max(r_custkey) @@ -249,6 +285,18 @@ LOG: join order: [ "multi_outer_join_left" ][ local partition join "multi_outer 21 | 21 (1 row) +-- Apply a filter before the join +SELECT + count(l_custkey), count(r_custkey) +FROM + multi_outer_join_left a LEFT JOIN multi_outer_join_right b + ON (l_custkey = r_custkey AND r_custkey = 21); +LOG: join order: [ "multi_outer_join_left" ][ local partition join "multi_outer_join_right" ] + count | count +-------+------- + 25 | 1 +(1 row) + -- Right join should be allowed in this case SELECT min(r_custkey), max(r_custkey)