1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-05 09:19:17 +03:00

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.
This commit is contained in:
Tom Lane 2007-07-31 19:53:50 +00:00
parent 5bd7b83426
commit 1be62b532b
8 changed files with 95 additions and 9 deletions

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 = remove_redundant_join_clauses(root,
clause_list, clause_list,
outer_relids,
rel->relids,
isouterjoin); isouterjoin);
} }

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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, select_nonredundant_join_clauses(root,
joinrestrictclauses, joinrestrictclauses,
innerpath->indexclauses, 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)) else if (IsA(best_path->innerjoinpath, BitmapHeapPath))
@ -1430,7 +1432,9 @@ create_nestloop_plan(PlannerInfo *root,
select_nonredundant_join_clauses(root, select_nonredundant_join_clauses(root,
joinrestrictclauses, joinrestrictclauses,
bitmapclauses, bitmapclauses,
IS_OUTER_JOIN(best_path->jointype)); best_path->outerjoinpath->parent->relids,
best_path->innerjoinpath->parent->relids,
IS_OUTER_JOIN(best_path->jointype));
} }
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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. * omit the redundant clause from the result list.
*/ */
result = remove_redundant_join_clauses(root, rlist, result = remove_redundant_join_clauses(root, rlist,
outer_rel->relids,
inner_rel->relids,
IS_OUTER_JOIN(jointype)); IS_OUTER_JOIN(jointype));
list_free(rlist); list_free(rlist);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
RestrictInfo *rinfo, RestrictInfo *rinfo,
List *reference_list, List *reference_list,
Relids outer_relids,
Relids inner_relids,
bool isouterjoin); bool isouterjoin);
@ -546,6 +548,8 @@ extract_actual_join_clauses(List *restrictinfo_list,
*/ */
List * List *
remove_redundant_join_clauses(PlannerInfo *root, List *restrictinfo_list, remove_redundant_join_clauses(PlannerInfo *root, List *restrictinfo_list,
Relids outer_relids,
Relids inner_relids,
bool isouterjoin) bool isouterjoin)
{ {
List *result = NIL; List *result = NIL;
@ -572,7 +576,9 @@ remove_redundant_join_clauses(PlannerInfo *root, List *restrictinfo_list,
RestrictInfo *prevrinfo; RestrictInfo *prevrinfo;
/* is it redundant with any prior clause? */ /* 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) if (prevrinfo == NULL)
{ {
/* no, so add it to result list */ /* no, so add it to result list */
@ -608,6 +614,8 @@ List *
select_nonredundant_join_clauses(PlannerInfo *root, select_nonredundant_join_clauses(PlannerInfo *root,
List *restrictinfo_list, List *restrictinfo_list,
List *reference_list, List *reference_list,
Relids outer_relids,
Relids inner_relids,
bool isouterjoin) bool isouterjoin)
{ {
List *result = NIL; List *result = NIL;
@ -618,7 +626,9 @@ select_nonredundant_join_clauses(PlannerInfo *root,
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item); RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
/* drop it if redundant with any reference clause */ /* 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; continue;
/* otherwise, add it to result list */ /* 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 * of the latter, even though they might seem redundant by the pathkey
* membership test. * 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 * 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, * except one is pushed down into an outer join and the other isn't,
* then they're not really redundant, because one constrains the * then they're not really redundant, because one constrains the
@ -660,6 +676,8 @@ static RestrictInfo *
join_clause_is_redundant(PlannerInfo *root, join_clause_is_redundant(PlannerInfo *root,
RestrictInfo *rinfo, RestrictInfo *rinfo,
List *reference_list, List *reference_list,
Relids outer_relids,
Relids inner_relids,
bool isouterjoin) bool isouterjoin)
{ {
ListCell *refitem; ListCell *refitem;
@ -681,6 +699,14 @@ join_clause_is_redundant(PlannerInfo *root,
bms_is_empty(rinfo->right_relids)) bms_is_empty(rinfo->right_relids))
return NULL; /* var = const, so not redundant */ 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); cache_mergeclause_pathkeys(root, rinfo);
foreach(refitem, reference_list) foreach(refitem, reference_list)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); List **otherquals);
extern List *remove_redundant_join_clauses(PlannerInfo *root, extern List *remove_redundant_join_clauses(PlannerInfo *root,
List *restrictinfo_list, List *restrictinfo_list,
Relids outer_relids,
Relids inner_relids,
bool isouterjoin); bool isouterjoin);
extern List *select_nonredundant_join_clauses(PlannerInfo *root, extern List *select_nonredundant_join_clauses(PlannerInfo *root,
List *restrictinfo_list, List *restrictinfo_list,
List *reference_list, List *reference_list,
Relids outer_relids,
Relids inner_relids,
bool isouterjoin); bool isouterjoin);
#endif /* RESTRICTINFO_H */ #endif /* RESTRICTINFO_H */

View File

@ -2250,3 +2250,19 @@ WHERE d.f1 IS NULL;
9999 9999
(3 rows) (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)

View File

@ -2250,3 +2250,19 @@ WHERE d.f1 IS NULL;
9999 9999
(3 rows) (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)

View File

@ -424,3 +424,19 @@ LEFT JOIN (
WHERE c.f1 IS NULL WHERE c.f1 IS NULL
) AS d ON (a.f1 = d.f1) ) AS d ON (a.f1 = d.f1)
WHERE d.f1 IS NULL; 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;