OSDN Git Service

Fix predicate-proving logic to cope with binary-compatibility cases when
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 24 Jul 2007 17:22:07 +0000 (17:22 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 24 Jul 2007 17:22:07 +0000 (17:22 +0000)
checking whether an IS NULL/IS NOT NULL clause is implied or refuted by
a strict function.  Per example from Dawid Kuroczko.
Backpatch to 8.2 since this is arguably a performance bug.

src/backend/optimizer/util/predtest.c

index 9bdef7a..3280612 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.15 2007/05/12 19:22:35 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.16 2007/07/24 17:22:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,6 +84,7 @@ static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause);
 static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause);
 static bool is_null_contradicts(NullTest *ntest, Node *clause);
 static Node *extract_not_arg(Node *clause);
+static bool list_member_strip(List *list, Expr *datum);
 static bool btree_predicate_proof(Expr *predicate, Node *clause,
                                          bool refute_it);
 
@@ -961,11 +962,11 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
                if (!type_is_rowtype(exprType((Node *) nonnullarg)))
                {
                        if (is_opclause(clause) &&
-                               list_member(((OpExpr *) clause)->args, nonnullarg) &&
+                               list_member_strip(((OpExpr *) clause)->args, nonnullarg) &&
                                op_strict(((OpExpr *) clause)->opno))
                                return true;
                        if (is_funcclause(clause) &&
-                               list_member(((FuncExpr *) clause)->args, nonnullarg) &&
+                               list_member_strip(((FuncExpr *) clause)->args, nonnullarg) &&
                                func_strict(((FuncExpr *) clause)->funcid))
                                return true;
                }
@@ -1044,11 +1045,11 @@ is_null_contradicts(NullTest *ntest, Node *clause)
 
        /* foo IS NULL contradicts any strict op/func on foo */
        if (is_opclause(clause) &&
-               list_member(((OpExpr *) clause)->args, isnullarg) &&
+               list_member_strip(((OpExpr *) clause)->args, isnullarg) &&
                op_strict(((OpExpr *) clause)->opno))
                return true;
        if (is_funcclause(clause) &&
-               list_member(((FuncExpr *) clause)->args, isnullarg) &&
+               list_member_strip(((FuncExpr *) clause)->args, isnullarg) &&
                func_strict(((FuncExpr *) clause)->funcid))
                return true;
 
@@ -1092,6 +1093,36 @@ extract_not_arg(Node *clause)
 
 
 /*
+ * Check whether an Expr is equal() to any member of a list, ignoring
+ * any top-level RelabelType nodes.  This is legitimate for the purposes
+ * we use it for (matching IS [NOT] NULL arguments to arguments of strict
+ * functions) because RelabelType doesn't change null-ness.  It's helpful
+ * for cases such as a varchar argument of a strict function on text.
+ */
+static bool
+list_member_strip(List *list, Expr *datum)
+{
+       ListCell   *cell;
+
+       if (datum && IsA(datum, RelabelType))
+               datum = ((RelabelType *) datum)->arg;
+
+       foreach(cell, list)
+       {
+               Expr *elem = (Expr *) lfirst(cell);
+
+               if (elem && IsA(elem, RelabelType))
+                       elem = ((RelabelType *) elem)->arg;
+
+               if (equal(elem, datum))
+                       return true;
+       }
+
+       return false;
+}
+
+
+/*
  * Define an "operator implication table" for btree operators ("strategies"),
  * and a similar table for refutation.
  *