Fix a bug in the original implementation of redundant-join-clause removal:
authorTom Lane <[email protected]>
Tue, 31 Jul 2007 19:54:11 +0000 (19:54 +0000)
committerTom Lane <[email protected]>
Tue, 31 Jul 2007 19:54:11 +0000 (19:54 +0000)
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
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/util/relnode.c
src/backend/optimizer/util/restrictinfo.c
src/include/optimizer/restrictinfo.h
src/test/regress/expected/join.out
src/test/regress/expected/join_1.out
src/test/regress/sql/join.sql

index b46d2f577ef48884b8f6c168dc15d306f3db3242..3ce3ab88c435411bc82e0edf40d7db77e07cf1d1 100644 (file)
@@ -386,6 +386,8 @@ group_clauses_by_indexkey_for_join(Query *root,
                {
                        clausegroup = remove_redundant_join_clauses(root,
                                                                                                                clausegroup,
+                                                                                                               outer_relids,
+                                                                                                               rel->relids,
                                                                                                                jointype);
                }
 
index e94e3f7479be8bfaef9d894cd4185e65c19b9399..0ecd9ea2992930459cbd4526f342e2588ef06bff 100644 (file)
@@ -955,6 +955,8 @@ create_nestloop_plan(Query *root,
                                select_nonredundant_join_clauses(root,
                                                                                                 joinrestrictclauses,
                                                                                                 linitial(indexclauses),
+                                                                       best_path->outerjoinpath->parent->relids,
+                                                                       best_path->innerjoinpath->parent->relids,
                                                                                                 best_path->jointype);
                }
        }
index 1ac379f4400fef6054a0c4410dc317a249b77c75..e8c041c1d5b6c10545ce63da48231fbfd3901ca3 100644 (file)
@@ -461,7 +461,10 @@ build_joinrel_restrictlist(Query *root,
         * previous clauses (see optimizer/README for discussion).      We detect
         * that case and omit the redundant clause from the result list.
         */
-       result = remove_redundant_join_clauses(root, rlist, jointype);
+       result = remove_redundant_join_clauses(root, rlist,
+                                                                                  outer_rel->relids,
+                                                                                  inner_rel->relids,
+                                                                                  jointype);
 
        list_free(rlist);
 
index 3e2b62888b0e205fddbe477213e9ab091f2cae46..10a0c4c10679c5c7e1f2f2a4d0025ed414df2756 100644 (file)
@@ -31,6 +31,8 @@ static Expr *make_sub_restrictinfos(Expr *clause,
 static RestrictInfo *join_clause_is_redundant(Query *root,
                                                 RestrictInfo *rinfo,
                                                 List *reference_list,
+                                                Relids outer_relids,
+                                                Relids inner_relids,
                                                 JoinType jointype);
 
 
@@ -314,6 +316,8 @@ get_actual_join_clauses(List *restrictinfo_list,
  */
 List *
 remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
+                                                         Relids outer_relids,
+                                                         Relids inner_relids,
                                                          JoinType jointype)
 {
        List       *result = NIL;
@@ -341,7 +345,9 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
                RestrictInfo *prevrinfo;
 
                /* is it redundant with any prior clause? */
-               prevrinfo = join_clause_is_redundant(root, rinfo, result, jointype);
+               prevrinfo = join_clause_is_redundant(root, rinfo, result,
+                                                                                        outer_relids, inner_relids,
+                                                                                        jointype);
                if (prevrinfo == NULL)
                {
                        /* no, so add it to result list */
@@ -377,6 +383,8 @@ List *
 select_nonredundant_join_clauses(Query *root,
                                                                 List *restrictinfo_list,
                                                                 List *reference_list,
+                                                                Relids outer_relids,
+                                                                Relids inner_relids,
                                                                 JoinType jointype)
 {
        List       *result = NIL;
@@ -387,7 +395,9 @@ select_nonredundant_join_clauses(Query *root,
                RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
 
                /* drop it if redundant with any reference clause */
-               if (join_clause_is_redundant(root, rinfo, reference_list, jointype) != NULL)
+               if (join_clause_is_redundant(root, rinfo, reference_list,
+                                                                        outer_relids, inner_relids,
+                                                                        jointype) != NULL)
                        continue;
 
                /* otherwise, add it to result list */
@@ -420,6 +430,12 @@ select_nonredundant_join_clauses(Query *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
@@ -429,6 +445,8 @@ static RestrictInfo *
 join_clause_is_redundant(Query *root,
                                                 RestrictInfo *rinfo,
                                                 List *reference_list,
+                                                Relids outer_relids,
+                                                Relids inner_relids,
                                                 JoinType jointype)
 {
        ListCell   *refitem;
@@ -450,6 +468,14 @@ join_clause_is_redundant(Query *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)
index cfa3373ffc77abaf421fce2faf2015423d40eb54..1de408dfe9176d302f816c72affaa8aeed293138 100644 (file)
@@ -27,10 +27,14 @@ extern void get_actual_join_clauses(List *restrictinfo_list,
                                                List **joinquals, List **otherquals);
 extern List *remove_redundant_join_clauses(Query *root,
                                                          List *restrictinfo_list,
+                                                         Relids outer_relids,
+                                                         Relids inner_relids,
                                                          JoinType jointype);
 extern List *select_nonredundant_join_clauses(Query *root,
                                                                 List *restrictinfo_list,
                                                                 List *reference_list,
+                                                                Relids outer_relids,
+                                                                Relids inner_relids,
                                                                 JoinType jointype);
 
 #endif   /* RESTRICTINFO_H */
index 4540b8fdbc4ad2a4918053baeef8a6b9f1b2c489..8e34ca4da27c3f9f9088e17c479061b1040fd529 100644 (file)
@@ -2147,3 +2147,19 @@ DROP TABLE t2;
 DROP TABLE t3;
 DROP TABLE J1_TBL;
 DROP TABLE J2_TBL;
+--
+-- 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)
+
index 7f8134bee5dd1346c9bd4b2dda71a4f86bd4bc0f..60d0c0832c7e9ecf041e4fc350f854207b32d680 100644 (file)
@@ -2147,3 +2147,19 @@ DROP TABLE t2;
 DROP TABLE t3;
 DROP TABLE J1_TBL;
 DROP TABLE J2_TBL;
+--
+-- 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)
+
index 9bda6f1d00249377bb888ab993d79041f7b7926a..70911408d417423818e51ab04ea003a86984bb49 100644 (file)
@@ -349,3 +349,19 @@ DROP TABLE t3;
 
 DROP TABLE J1_TBL;
 DROP TABLE J2_TBL;
+
+--
+-- 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;