*
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.7 2006/07/14 14:52:21 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.8 2006/08/05 00:21:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 static void arrayexpr_cleanup_fn(PredIterInfo info);
 static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause);
 static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause);
+static Node *extract_not_arg(Node *clause);
 static bool btree_predicate_proof(Expr *predicate, Node *clause,
                                          bool refute_it);
 
  *     OR-expr A R=> AND-expr B iff:   each of A's components R=> any of B's
  *     OR-expr A R=> OR-expr B iff:    A R=> each of B's components
  *
+ * In addition, if the predicate is a NOT-clause then we can use
+ *     A R=> NOT B if:                                 A => B
+ * while if the restriction clause is a NOT-clause then we can use
+ *     NOT A R=> B if:                                 B => A
+ * This works for several different SQL constructs that assert the non-truth
+ * of their argument, ie NOT, IS FALSE, IS NOT TRUE, IS UNKNOWN.
+ *
  * Other comments are as for predicate_implied_by_recurse().
  *----------
  */
        PredIterInfoData clause_info;
        PredIterInfoData pred_info;
        PredClass       pclass;
+       Node       *not_arg;
        bool            result;
 
        /* skip through RestrictInfo */
                                        return result;
 
                                case CLASS_ATOM:
+                                       /*
+                                        * If B is a NOT-clause, A R=> B if A => B's arg
+                                        */
+                                       not_arg = extract_not_arg(predicate);
+                                       if (not_arg &&
+                                               predicate_implied_by_recurse(clause, not_arg))
+                                               return true;
                                        /*
                                         * AND-clause R=> atom if any of A's items refutes B
                                         */
                                        return result;
 
                                case CLASS_ATOM:
+                                       /*
+                                        * If B is a NOT-clause, A R=> B if A => B's arg
+                                        */
+                                       not_arg = extract_not_arg(predicate);
+                                       if (not_arg &&
+                                               predicate_implied_by_recurse(clause, not_arg))
+                                               return true;
                                        /*
                                         * OR-clause R=> atom if each of A's items refutes B
                                         */
                        break;
 
                case CLASS_ATOM:
+                       /*
+                        * If A is a NOT-clause, A R=> B if B => A's arg
+                        */
+                       not_arg = extract_not_arg(clause);
+                       if (not_arg &&
+                               predicate_implied_by_recurse(predicate, not_arg))
+                               return true;
                        switch (pclass)
                        {
                                case CLASS_AND:
                                        return result;
 
                                case CLASS_ATOM:
+                                       /*
+                                        * If B is a NOT-clause, A R=> B if A => B's arg
+                                        */
+                                       not_arg = extract_not_arg(predicate);
+                                       if (not_arg &&
+                                               predicate_implied_by_recurse(clause, not_arg))
+                                               return true;
                                        /*
                                         * atom R=> atom is the base case
                                         */
  * We return TRUE if able to prove the refutation, FALSE if not.
  *
  * Unlike the implication case, checking for equal() clauses isn't
- * helpful.  (XXX is it worth looking at "x vs NOT x" cases?  Probably
- * not seeing that canonicalization tries to get rid of NOTs.)
+ * helpful.
  *
  * When the predicate is of the form "foo IS NULL", we can conclude that
  * the predicate is refuted if the clause is a strict operator or function
 static bool
 predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
 {
-       /* First try the IS NULL case */
+       /* A simple clause can't refute itself */
+       /* Worth checking because of relation_excluded_by_constraints() */
+       if ((Node *) predicate == clause)
+               return false;
+
+       /* Try the IS NULL case */
        if (predicate && IsA(predicate, NullTest) &&
                ((NullTest *) predicate)->nulltesttype == IS_NULL)
        {
 }
 
 
+/*
+ * If clause asserts the non-truth of a subclause, return that subclause;
+ * otherwise return NULL.
+ */
+static Node *
+extract_not_arg(Node *clause)
+{
+       if (clause == NULL)
+               return NULL;
+       if (IsA(clause, BoolExpr))
+       {
+               BoolExpr   *bexpr = (BoolExpr *) clause;
+
+               if (bexpr->boolop == NOT_EXPR)
+                       return (Node *) linitial(bexpr->args);
+       }
+       else if (IsA(clause, BooleanTest))
+       {
+               BooleanTest *btest = (BooleanTest *) clause;
+
+               if (btest->booltesttype == IS_NOT_TRUE ||
+                       btest->booltesttype == IS_FALSE ||
+                       btest->booltesttype == IS_UNKNOWN)
+                       return (Node *) btest->arg;
+       }
+       return NULL;
+}
+
+
 /*
  * Define an "operator implication table" for btree operators ("strategies"),
  * and a similar table for refutation.