]> granicus.if.org Git - postgresql/commitdiff
Simplify overcomplicated (and overly restrictive) test to see whether an
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Feb 2009 00:01:03 +0000 (00:01 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Feb 2009 00:01:03 +0000 (00:01 +0000)
IS NULL condition is rendered redundant by detection of an antijoin.
If we know that a join is an antijoin, then *any* Var coming out of its
righthand side must be NULL, not only the joining column(s).  Also,
it's still gonna be null after being passed up through higher joins,
whether they're outer joins or not.  I was misled by a faulty analogy
to reduce_outer_joins() in the original coding.  But consider

select * from a left join b on a.x = b.y where b.y is null and b.z is null;

The first IS NULL condition justifies deciding that the join is an antijoin
(if the = is strict) and then the second one is just plain redundant.

src/backend/optimizer/plan/initsplan.c

index d8639a67e4c3729dcca69f6d2a9148348377fa44..1b3296f971aac49f4c0ef080208c819fcecec79b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.146 2009/01/01 17:23:44 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.147 2009/02/20 00:01:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -725,6 +725,9 @@ make_outerjoininfo(PlannerInfo *root,
  * 'qualscope' identifies what level of JOIN the qual came from syntactically.
  * 'ojscope' is needed if we decide to force the qual up to the outer-join
  * level, which will be ojscope not necessarily qualscope.
+ *
+ * At the time this is called, root->join_info_list must contain entries for
+ * all and only those special joins that are syntactically below this qual.
  */
 static void
 distribute_qual_to_rels(PlannerInfo *root, Node *clause,
@@ -1209,7 +1212,6 @@ check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
 {
        Var                *forced_null_var;
        Index           forced_null_rel;
-       SpecialJoinInfo *match_sjinfo = NULL;
        ListCell   *lc;
 
        /* Check for IS NULL, and identify the Var forced to NULL */
@@ -1219,47 +1221,19 @@ check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
        forced_null_rel = forced_null_var->varno;
 
        /*
-        * Search to see if there's a matching antijoin that is not masked by
-        * a higher outer join.  Because we have to scan the join info bottom-up,
-        * we have to continue looking after finding a match to check for masking
-        * joins.  This logic should agree with reduce_outer_joins's code
-        * to detect antijoins on the basis of IS NULL clauses.  (It's tempting
-        * to consider adding some data structures to avoid redundant work,
-        * but in practice this code shouldn't get executed often enough to
-        * make it worth the trouble.)
+        * If the Var comes from the nullable side of a lower antijoin, the
+        * IS NULL condition is necessarily true.
         */
        foreach(lc, root->join_info_list)
        {
                SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
 
-               /* Check for match ... */
                if (sjinfo->jointype == JOIN_ANTI &&
                        bms_is_member(forced_null_rel, sjinfo->syn_righthand))
-               {
-                       List   *nonnullable_vars;
-
-                       nonnullable_vars = find_nonnullable_vars((Node *) sjinfo->join_quals);
-                       if (list_member(nonnullable_vars, forced_null_var))
-                       {
-                               match_sjinfo = sjinfo;
-                               continue;
-                       }
-               }
-               /*
-                * Else, if we had a lower match, check to see if the target var is
-                * from the nullable side of this OJ.  If so, this OJ masks the
-                * lower one and we can no longer consider the IS NULL as redundant
-                * with the lower antijoin.
-                */
-               if (!match_sjinfo)
-                       continue;
-               if (bms_is_member(forced_null_rel, sjinfo->syn_righthand) ||
-                       (sjinfo->jointype == JOIN_FULL &&
-                        bms_is_member(forced_null_rel, sjinfo->syn_lefthand)))
-                       match_sjinfo = NULL;
+                       return true;
        }
 
-       return (match_sjinfo != NULL);
+       return false;
 }
 
 /*