diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index 33acc0d46..6826b0b23 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 181db5e9d..98f0b48fc 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -3287,13 +3287,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 890d202ea..c9b8890be 100644 --- a/src/include/distributed/multi_logical_planner.h +++ b/src/include/distributed/multi_logical_planner.h @@ -194,6 +194,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 b0d0fce73..3c6eaa416 100644 --- a/src/test/regress/input/multi_outer_join.source +++ b/src/test/regress/input/multi_outer_join.source @@ -108,6 +108,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) @@ -186,6 +207,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 025f258fe..fba6898ee 100644 --- a/src/test/regress/output/multi_outer_join.source +++ b/src/test/regress/output/multi_outer_join.source @@ -144,6 +144,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) @@ -247,6 +283,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)