diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 379e15a9641..f35372ebbef 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.212.2.2 2007/05/22 01:40:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.212.2.3 2007/07/31 19:53:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 14f1f1a10f4..75b67e8879f 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.217 2006/10/04 00:29:54 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.217.2.1 2007/07/31 19:53:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 4d5bffdb7b1..2a3a14ae6b1 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.83 2006/10/04 00:29:55 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.83.2.1 2007/07/31 19:53:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 9176ae1680c..ae114f65509 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.49 2006/10/04 00:29:55 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.49.2.1 2007/07/31 19:53:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 db24c4989db..c9639a2c059 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.38 2006/10/04 00:30:09 momjian Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.38.2.1 2007/07/31 19:53:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 8b6716def81..3b7bdd9cbb3 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 8e7e4de0141..f1bf4b9af26 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 d3433effd11..ad8957cd6e3 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;