From e403f0959e3549e05f78faa618ac196f6819b4c0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 31 Jul 2007 19:53:50 +0000 Subject: [PATCH] Fix a bug in the original implementation of redundant-join-clause removal: clauses in which one side or the other references both sides of the join cannot be removed as redundant, because that expression won't have been constrained below the join. Per report from Sergey Burladyan. --- src/backend/optimizer/path/indxpath.c | 2 ++ src/backend/optimizer/plan/createplan.c | 8 ++++-- src/backend/optimizer/util/relnode.c | 2 ++ src/backend/optimizer/util/restrictinfo.c | 30 +++++++++++++++++++++-- src/include/optimizer/restrictinfo.h | 4 +++ src/test/regress/expected/join.out | 16 ++++++++++++ src/test/regress/expected/join_1.out | 16 ++++++++++++ src/test/regress/sql/join.sql | 16 ++++++++++++ 8 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 96a3353ac4..1bec7780e8 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -1755,6 +1755,8 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, { clause_list = remove_redundant_join_clauses(root, clause_list, + outer_relids, + rel->relids, isouterjoin); } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index c66bfe830a..019ca8c78f 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1398,7 +1398,9 @@ create_nestloop_plan(PlannerInfo *root, select_nonredundant_join_clauses(root, joinrestrictclauses, innerpath->indexclauses, - IS_OUTER_JOIN(best_path->jointype)); + best_path->outerjoinpath->parent->relids, + best_path->innerjoinpath->parent->relids, + IS_OUTER_JOIN(best_path->jointype)); } } else if (IsA(best_path->innerjoinpath, BitmapHeapPath)) @@ -1430,7 +1432,9 @@ create_nestloop_plan(PlannerInfo *root, select_nonredundant_join_clauses(root, joinrestrictclauses, bitmapclauses, - IS_OUTER_JOIN(best_path->jointype)); + best_path->outerjoinpath->parent->relids, + best_path->innerjoinpath->parent->relids, + IS_OUTER_JOIN(best_path->jointype)); } } diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index f7ab684b6f..3ba0ac6d47 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -515,6 +515,8 @@ build_joinrel_restrictlist(PlannerInfo *root, * omit the redundant clause from the result list. */ result = remove_redundant_join_clauses(root, rlist, + outer_rel->relids, + inner_rel->relids, IS_OUTER_JOIN(jointype)); list_free(rlist); diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index ad036358b3..8e96d17be0 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -36,6 +36,8 @@ static Expr *make_sub_restrictinfos(Expr *clause, static RestrictInfo *join_clause_is_redundant(PlannerInfo *root, RestrictInfo *rinfo, List *reference_list, + Relids outer_relids, + Relids inner_relids, bool isouterjoin); @@ -546,6 +548,8 @@ extract_actual_join_clauses(List *restrictinfo_list, */ List * remove_redundant_join_clauses(PlannerInfo *root, List *restrictinfo_list, + Relids outer_relids, + Relids inner_relids, bool isouterjoin) { List *result = NIL; @@ -572,7 +576,9 @@ remove_redundant_join_clauses(PlannerInfo *root, List *restrictinfo_list, RestrictInfo *prevrinfo; /* is it redundant with any prior clause? */ - prevrinfo = join_clause_is_redundant(root, rinfo, result, isouterjoin); + prevrinfo = join_clause_is_redundant(root, rinfo, result, + outer_relids, inner_relids, + isouterjoin); if (prevrinfo == NULL) { /* no, so add it to result list */ @@ -608,6 +614,8 @@ List * select_nonredundant_join_clauses(PlannerInfo *root, List *restrictinfo_list, List *reference_list, + Relids outer_relids, + Relids inner_relids, bool isouterjoin) { List *result = NIL; @@ -618,7 +626,9 @@ select_nonredundant_join_clauses(PlannerInfo *root, RestrictInfo *rinfo = (RestrictInfo *) lfirst(item); /* drop it if redundant with any reference clause */ - if (join_clause_is_redundant(root, rinfo, reference_list, isouterjoin) != NULL) + if (join_clause_is_redundant(root, rinfo, reference_list, + outer_relids, inner_relids, + isouterjoin) != NULL) continue; /* otherwise, add it to result list */ @@ -651,6 +661,12 @@ select_nonredundant_join_clauses(PlannerInfo *root, * of the latter, even though they might seem redundant by the pathkey * membership test. * + * Also, we cannot eliminate clauses wherein one side mentions vars from + * both relations, as in "WHERE t1.f1 = t2.f1 AND t1.f1 = t1.f2 - t2.f2". + * In this example, "t1.f2 - t2.f2" could not have been computed at all + * before forming the join of t1 and t2, so it certainly wasn't constrained + * earlier. + * * Weird special case: if we have two clauses that seem redundant * except one is pushed down into an outer join and the other isn't, * then they're not really redundant, because one constrains the @@ -660,6 +676,8 @@ static RestrictInfo * join_clause_is_redundant(PlannerInfo *root, RestrictInfo *rinfo, List *reference_list, + Relids outer_relids, + Relids inner_relids, bool isouterjoin) { ListCell *refitem; @@ -681,6 +699,14 @@ join_clause_is_redundant(PlannerInfo *root, bms_is_empty(rinfo->right_relids)) return NULL; /* var = const, so not redundant */ + /* check for either side mentioning both rels */ + if (bms_overlap(rinfo->left_relids, outer_relids) && + bms_overlap(rinfo->left_relids, inner_relids)) + return NULL; /* clause LHS uses both, so not redundant */ + if (bms_overlap(rinfo->right_relids, outer_relids) && + bms_overlap(rinfo->right_relids, inner_relids)) + return NULL; /* clause RHS uses both, so not redundant */ + cache_mergeclause_pathkeys(root, rinfo); foreach(refitem, reference_list) diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h index 6e2a0c00cf..1584cf67f4 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -34,10 +34,14 @@ extern void extract_actual_join_clauses(List *restrictinfo_list, List **otherquals); extern List *remove_redundant_join_clauses(PlannerInfo *root, List *restrictinfo_list, + Relids outer_relids, + Relids inner_relids, bool isouterjoin); extern List *select_nonredundant_join_clauses(PlannerInfo *root, List *restrictinfo_list, List *reference_list, + Relids outer_relids, + Relids inner_relids, bool isouterjoin); #endif /* RESTRICTINFO_H */ diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 8b6716def8..3b7bdd9cbb 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -2250,3 +2250,19 @@ WHERE d.f1 IS NULL; 9999 (3 rows) +-- +-- regression test for problems of the sort depicted in bug #3494 +-- +create temp table tt5(f1 int, f2 int); +create temp table tt6(f1 int, f2 int); +insert into tt5 values(1, 10); +insert into tt5 values(1, 11); +insert into tt6 values(1, 9); +insert into tt6 values(1, 2); +insert into tt6 values(2, 9); +select * from tt5,tt6 where tt5.f1 = tt6.f1 and tt5.f1 = tt5.f2 - tt6.f2; + f1 | f2 | f1 | f2 +----+----+----+---- + 1 | 10 | 1 | 9 +(1 row) + diff --git a/src/test/regress/expected/join_1.out b/src/test/regress/expected/join_1.out index 8e7e4de014..f1bf4b9af2 100644 --- a/src/test/regress/expected/join_1.out +++ b/src/test/regress/expected/join_1.out @@ -2250,3 +2250,19 @@ WHERE d.f1 IS NULL; 9999 (3 rows) +-- +-- regression test for problems of the sort depicted in bug #3494 +-- +create temp table tt5(f1 int, f2 int); +create temp table tt6(f1 int, f2 int); +insert into tt5 values(1, 10); +insert into tt5 values(1, 11); +insert into tt6 values(1, 9); +insert into tt6 values(1, 2); +insert into tt6 values(2, 9); +select * from tt5,tt6 where tt5.f1 = tt6.f1 and tt5.f1 = tt5.f2 - tt6.f2; + f1 | f2 | f1 | f2 +----+----+----+---- + 1 | 10 | 1 | 9 +(1 row) + diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index d3433effd1..ad8957cd6e 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -424,3 +424,19 @@ LEFT JOIN ( WHERE c.f1 IS NULL ) AS d ON (a.f1 = d.f1) WHERE d.f1 IS NULL; + +-- +-- regression test for problems of the sort depicted in bug #3494 +-- + +create temp table tt5(f1 int, f2 int); +create temp table tt6(f1 int, f2 int); + +insert into tt5 values(1, 10); +insert into tt5 values(1, 11); + +insert into tt6 values(1, 9); +insert into tt6 values(1, 2); +insert into tt6 values(2, 9); + +select * from tt5,tt6 where tt5.f1 = tt6.f1 and tt5.f1 = tt5.f2 - tt6.f2; -- 2.39.5