Merge pull request #603 from citusdata/fix/outer-join-filter

Do not copy outer join clauses into WHERE
pull/608/head
Andres Freund 2016-06-16 17:16:49 -07:00 committed by GitHub
commit e697bf7ca7
5 changed files with 99 additions and 7 deletions

View File

@ -59,7 +59,6 @@ static bool HasComplexJoinOrder(Query *queryTree);
static bool HasComplexRangeTableType(Query *queryTree); static bool HasComplexRangeTableType(Query *queryTree);
static void ValidateClauseList(List *clauseList); static void ValidateClauseList(List *clauseList);
static bool ExtractFromExpressionWalker(Node *node, List **qualifierList); static bool ExtractFromExpressionWalker(Node *node, List **qualifierList);
static bool IsJoinClause(Node *clause);
static List * MultiTableNodeList(List *tableEntryList, List *rangeTableList); static List * MultiTableNodeList(List *tableEntryList, List *rangeTableList);
static List * AddMultiCollectNodes(List *tableNodeList); static List * AddMultiCollectNodes(List *tableNodeList);
static MultiNode * MultiJoinTree(List *joinOrderList, List *collectTableList, static MultiNode * MultiJoinTree(List *joinOrderList, List *collectTableList,
@ -834,8 +833,13 @@ ExtractFromExpressionWalker(Node *node, List **qualifierList)
List *joinQualifierList = NIL; List *joinQualifierList = NIL;
JoinExpr *joinExpression = (JoinExpr *) node; JoinExpr *joinExpression = (JoinExpr *) node;
Node *joinQualifiersNode = joinExpression->quals; 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)) 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 * criteria. Our criteria defines a join clause as an equi join operator between
* two columns that belong to two different tables. * two columns that belong to two different tables.
*/ */
static bool bool
IsJoinClause(Node *clause) IsJoinClause(Node *clause)
{ {
bool isJoinClause = false; bool isJoinClause = false;

View File

@ -3286,13 +3286,23 @@ JoinSequenceArray(List *rangeTableFragmentsList, Query *jobQuery, List *depended
foreach(nextJoinClauseCell, nextJoinClauseList) foreach(nextJoinClauseCell, nextJoinClauseList)
{ {
OpExpr *nextJoinClause = (OpExpr *) lfirst(nextJoinClauseCell); OpExpr *nextJoinClause = (OpExpr *) lfirst(nextJoinClauseCell);
Var *leftColumn = LeftColumn(nextJoinClause); Var *leftColumn = NULL;
Var *rightColumn = RightColumn(nextJoinClause); Var *rightColumn = NULL;
Index leftRangeTableId = leftColumn->varno; Index leftRangeTableId = 0;
Index rightRangeTableId = rightColumn->varno; Index rightRangeTableId = 0;
bool leftPartitioned = false; bool leftPartitioned = false;
bool rightPartitioned = 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 * We have a table from the existing join list joining with the next
* table. First resolve the existing table's range table id. * table. First resolve the existing table's range table id.

View File

@ -192,6 +192,7 @@ extern bool BinaryOperator(MultiNode *node);
extern List * OutputTableIdList(MultiNode *multiNode); extern List * OutputTableIdList(MultiNode *multiNode);
extern List * FindNodesOfType(MultiNode *node, int type); extern List * FindNodesOfType(MultiNode *node, int type);
extern List * JoinClauseList(List *whereClauseList); extern List * JoinClauseList(List *whereClauseList);
extern bool IsJoinClause(Node *clause);
extern List * SubqueryEntryList(Query *queryTree); extern List * SubqueryEntryList(Query *queryTree);
extern bool ExtractRangeTableIndexWalker(Node *node, List **rangeTableIndexList); extern bool ExtractRangeTableIndexWalker(Node *node, List **rangeTableIndexList);
extern List * WhereClauseList(FromExpr *fromExpr); extern List * WhereClauseList(FromExpr *fromExpr);

View File

@ -113,6 +113,27 @@ WHERE
r_custkey = 5; 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 -- Right join should be disallowed in this case
SELECT SELECT
min(r_custkey), max(r_custkey) min(r_custkey), max(r_custkey)
@ -191,6 +212,14 @@ WHERE
r_custkey = 21; 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 -- Right join should be allowed in this case
SELECT SELECT
min(r_custkey), max(r_custkey) min(r_custkey), max(r_custkey)

View File

@ -146,6 +146,42 @@ LOG: join order: [ "multi_outer_join_left" ][ broadcast join "multi_outer_join_
5 | 5 5 | 5
(1 row) (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 -- Right join should be disallowed in this case
SELECT SELECT
min(r_custkey), max(r_custkey) min(r_custkey), max(r_custkey)
@ -249,6 +285,18 @@ LOG: join order: [ "multi_outer_join_left" ][ local partition join "multi_outer
21 | 21 21 | 21
(1 row) (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 -- Right join should be allowed in this case
SELECT SELECT
min(r_custkey), max(r_custkey) min(r_custkey), max(r_custkey)