Fix a bug in the original implementation of redundant-join-clause removal:
authorTom Lane <[email protected]>
Tue, 31 Jul 2007 19:53:50 +0000 (19:53 +0000)
committerTom Lane <[email protected]>
Tue, 31 Jul 2007 19:53:50 +0000 (19:53 +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 96a3353ac42cc30e1a22fac1fec120f73e7c9f5f..1bec7780e87d5d348892200ab6f687d1e0212217 100644 (file)
@@ -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);
        }
 
index c66bfe830af456ef2f245138a8ac677a40413196..019ca8c78f4302cf6488fb4c6bbe6e4e7808dfa3 100644 (file)
@@ -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));
                }
        }
 
index f7ab684b6f0f1b531a8bbf0087ca1f6bb1ce7de2..3ba0ac6d474344bd7c11b03430e39f1828eef3ca 100644 (file)
@@ -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);
index ad036358b351af64f144fc70029f88bba23c036f..8e96d17be0738890bc915d5c2e17757b0ba20c8e 100644 (file)
@@ -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)
index 6e2a0c00cf978c170dc8df4d8dada955385eb730..1584cf67f405468fa8e46e12dfa1d5ac2b6fafec 100644 (file)
@@ -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 */
index 8b6716def814c2b0ca67e46c8b503c60ec7fbf83..3b7bdd9cbb321f9b0aa125b0b169746947ab1321 100644 (file)
@@ -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)
+
index 8e7e4de014147c73114e525638f78e23a1d32d43..f1bf4b9af269b25781478148296430ddbcfeecaf 100644 (file)
@@ -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)
+
index d3433effd11c884817faeb3270518ba993464674..ad8957cd6e3a3675e2471460df34880cf1bb06b8 100644 (file)
@@ -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;