aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/predtest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/predtest.c')
-rw-r--r--src/backend/optimizer/util/predtest.c100
1 files changed, 57 insertions, 43 deletions
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index a6a28f10e7f..4a1a6056e3b 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.18 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.19 2008/01/12 00:11:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -82,7 +82,6 @@ static Node *arrayexpr_next_fn(PredIterInfo info);
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 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,
@@ -129,6 +128,14 @@ predicate_implied_by(List *predicate_list, List *restrictinfo_list)
* This is NOT the same as !(predicate_implied_by), though it is similar
* in the technique and structure of the code.
*
+ * An important fine point is that truth of the clauses must imply that
+ * the predicate returns FALSE, not that it does not return TRUE. This
+ * is normally used to try to refute CHECK constraints, and the only
+ * thing we can assume about a CHECK constraint is that it didn't return
+ * FALSE --- a NULL result isn't a violation per the SQL spec. (Someday
+ * perhaps this code should be extended to support both "strong" and
+ * "weak" refutation, but for now we only need "strong".)
+ *
* The top-level List structure of each list corresponds to an AND list.
* We assume that eval_const_expressions() has been applied and so there
* are no un-flattened ANDs or ORs (e.g., no AND immediately within an AND,
@@ -408,10 +415,11 @@ predicate_implied_by_recurse(Node *clause, Node *predicate)
*
* 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.
+ * Unfortunately we *cannot* use
+ * NOT A R=> B if: B => A
+ * because this type of reasoning fails to prove that B doesn't yield NULL.
*
* Other comments are as for predicate_implied_by_recurse().
*----------
@@ -595,13 +603,21 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate)
case CLASS_ATOM:
+#ifdef NOT_USED
/*
* If A is a NOT-clause, A R=> B if B => A's arg
+ *
+ * Unfortunately not: this would only prove that B is not-TRUE,
+ * not that it's not NULL either. Keep this code as a comment
+ * because it would be useful if we ever had a need for the
+ * weak form of refutation.
*/
not_arg = extract_not_arg(clause);
if (not_arg &&
predicate_implied_by_recurse(predicate, not_arg))
return true;
+#endif
+
switch (pclass)
{
case CLASS_AND:
@@ -990,9 +1006,11 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
* 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
* that has "foo" as an input (see notes for implication case), or if the
- * clause is "foo IS NOT NULL". Conversely a clause "foo IS NULL" refutes
- * predicates of those types. (The motivation for covering these cases is
- * to support using IS NULL/IS NOT NULL as partition-defining constraints.)
+ * clause is "foo IS NOT NULL". A clause "foo IS NULL" refutes a predicate
+ * "foo IS NOT NULL", but unfortunately does not refute strict predicates,
+ * because we are looking for strong refutation. (The motivation for covering
+ * these cases is to support using IS NULL/IS NOT NULL as partition-defining
+ * constraints.)
*
* Finally, we may be able to deduce something using knowledge about btree
* operator families; this is encapsulated in btree_predicate_proof().
@@ -1010,8 +1028,28 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
if (predicate && IsA(predicate, NullTest) &&
((NullTest *) predicate)->nulltesttype == IS_NULL)
{
- if (is_null_contradicts((NullTest *) predicate, clause))
+ Expr *isnullarg = ((NullTest *) predicate)->arg;
+
+ /* row IS NULL does not act in the simple way we have in mind */
+ if (type_is_rowtype(exprType((Node *) isnullarg)))
+ return false;
+
+ /* Any strict op/func on foo refutes foo IS NULL */
+ if (is_opclause(clause) &&
+ list_member_strip(((OpExpr *) clause)->args, isnullarg) &&
+ op_strict(((OpExpr *) clause)->opno))
+ return true;
+ if (is_funcclause(clause) &&
+ list_member_strip(((FuncExpr *) clause)->args, isnullarg) &&
+ func_strict(((FuncExpr *) clause)->funcid))
return true;
+
+ /* foo IS NOT NULL refutes foo IS NULL */
+ if (clause && IsA(clause, NullTest) &&
+ ((NullTest *) clause)->nulltesttype == IS_NOT_NULL &&
+ equal(((NullTest *) clause)->arg, isnullarg))
+ return true;
+
return false; /* we can't succeed below... */
}
@@ -1019,8 +1057,18 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
if (clause && IsA(clause, NullTest) &&
((NullTest *) clause)->nulltesttype == IS_NULL)
{
- if (is_null_contradicts((NullTest *) clause, (Node *) predicate))
+ Expr *isnullarg = ((NullTest *) clause)->arg;
+
+ /* row IS NULL does not act in the simple way we have in mind */
+ if (type_is_rowtype(exprType((Node *) isnullarg)))
+ return false;
+
+ /* foo IS NULL refutes foo IS NOT NULL */
+ if (predicate && IsA(predicate, NullTest) &&
+ ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL &&
+ equal(((NullTest *) predicate)->arg, isnullarg))
return true;
+
return false; /* we can't succeed below... */
}
@@ -1030,40 +1078,6 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
/*
- * Check whether a "foo IS NULL" test contradicts clause. (We say
- * "contradicts" rather than "refutes" because the refutation goes
- * both ways.)
- */
-static bool
-is_null_contradicts(NullTest *ntest, Node *clause)
-{
- Expr *isnullarg = ntest->arg;
-
- /* row IS NULL does not act in the simple way we have in mind */
- if (type_is_rowtype(exprType((Node *) isnullarg)))
- return false;
-
- /* foo IS NULL contradicts any strict op/func on foo */
- if (is_opclause(clause) &&
- list_member_strip(((OpExpr *) clause)->args, isnullarg) &&
- op_strict(((OpExpr *) clause)->opno))
- return true;
- if (is_funcclause(clause) &&
- list_member_strip(((FuncExpr *) clause)->args, isnullarg) &&
- func_strict(((FuncExpr *) clause)->funcid))
- return true;
-
- /* foo IS NULL contradicts foo IS NOT NULL */
- if (clause && IsA(clause, NullTest) &&
- ((NullTest *) clause)->nulltesttype == IS_NOT_NULL &&
- equal(((NullTest *) clause)->arg, isnullarg))
- return true;
-
- return false;
-}
-
-
-/*
* If clause asserts the non-truth of a subclause, return that subclause;
* otherwise return NULL.
*/