]> granicus.if.org Git - postgresql/commitdiff
When testing usability of a partial index, recognize that an index
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 7 Mar 2004 05:43:53 +0000 (05:43 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 7 Mar 2004 05:43:53 +0000 (05:43 +0000)
predicate of the form 'foo IS NOT NULL' is implied by a WHERE clause
that uses 'foo' in any strict operator or function.  Per suggestion
and preliminary implementation by John Siracusa; some further hacking
by moi.

src/backend/optimizer/path/indxpath.c

index ecd126da7ffebf7a33e54403058cc09b5e53574c..7d04ef14b7d5fe12e3e7e7cdd26bafd7a8d110a7 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.156 2004/01/07 22:02:48 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.157 2004/03/07 05:43:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -965,24 +965,38 @@ static const StrategyNumber
 };
 
 
-/*
+/*----------
  * pred_test_simple_clause
  *       Does the "predicate inclusion test" for a "simple clause" predicate
  *       and a "simple clause" restriction.
  *
- *       We have two strategies for determining whether one simple clause
- *       implies another.      A simple and general way is to see if they are
- *       equal(); this works for any kind of expression.  (Actually, there
- *       is an implied assumption that the functions in the expression are
- *       immutable, ie dependent only on their input arguments --- but this
- *       was checked for the predicate by CheckPredicate().)
+ * We have three strategies for determining whether one simple clause
+ * implies another:
+ *
+ * A simple and general way is to see if they are equal(); this works for any
+ * kind of expression.  (Actually, there is an implied assumption that the
+ * functions in the expression are immutable, ie dependent only on their input
+ * arguments --- but this was checked for the predicate by CheckPredicate().)
  *
- *       Our other way works only for (binary boolean) operators that are
- *       in some btree operator class.  We use the above operator implication
- *       table to be able to derive implications between nonidentical clauses.
+ * When the predicate is of the form "foo IS NOT NULL", we can conclude that
+ * the predicate is implied if the clause is a strict operator or function
+ * that has "foo" as an input.  In this case the clause must yield NULL when
+ * "foo" is NULL, which we can take as equivalent to FALSE because we know
+ * we are within an AND/OR subtree of a WHERE clause.  (Again, "foo" is
+ * already known immutable, so the clause will certainly always fail.)
  *
- *       Eventually, rtree operators could also be handled by defining an
- *       appropriate "RT_implic_table" array.
+ * Our other way works only for binary boolean opclauses of the form
+ * "foo op constant", where "foo" is the same in both clauses.  The operators
+ * and constants can be different but the operators must be in the same btree
+ * operator class.  We use the above operator implication table to be able to
+ * derive implications between nonidentical clauses.  (Note: "foo" is known
+ * immutable, and constants are surely immutable, and we assume that operators
+ * that are in btree opclasses are immutable, so there's no need to do extra
+ * mutability checks in this case either.)
+ *
+ * Eventually, rtree operators could also be handled by defining an
+ * appropriate "RT_implic_table" array.
+ *----------
  */
 static bool
 pred_test_simple_clause(Expr *predicate, Node *clause)
@@ -1020,6 +1034,23 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
        if (equal((Node *) predicate, clause))
                return true;
 
+       /* Next try the IS NOT NULL case */
+       if (predicate && IsA(predicate, NullTest) &&
+               ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL)
+       {
+               Expr *nonnullarg = ((NullTest *) predicate)->arg;
+
+               if (is_opclause(clause) &&
+                       member(nonnullarg, ((OpExpr *) clause)->args) &&
+                       op_strict(((OpExpr *) clause)->opno))
+                       return true;
+               if (is_funcclause(clause) &&
+                       member(nonnullarg, ((FuncExpr *) clause)->args) &&
+                       func_strict(((FuncExpr *) clause)->funcid))
+                       return true;
+               return false;                   /* we can't succeed below... */
+       }
+
        /*
         * Can't do anything more unless they are both binary opclauses with a
         * Const on one side, and identical subexpressions on the other sides.