static Node *extract_strong_not_arg(Node *clause);
static bool clause_is_strict_for(Node *clause, Node *subexpr);
static bool operator_predicate_proof(Expr *predicate, Node *clause,
- bool refute_it);
+ bool refute_it, bool weak);
static bool operator_same_subexprs_proof(Oid pred_op, Oid clause_op,
bool refute_it);
static bool operator_same_subexprs_lookup(Oid pred_op, Oid clause_op,
}
/* Else try operator-related knowledge */
- return operator_predicate_proof(predicate, clause, false);
+ return operator_predicate_proof(predicate, clause, false, weak);
}
/*----------
}
/* Else try operator-related knowledge */
- return operator_predicate_proof(predicate, clause, true);
+ return operator_predicate_proof(predicate, clause, true, weak);
}
* values, since then the operators aren't being given identical inputs. But
* we only support that for btree operators, for which we can assume that all
* non-null inputs result in non-null outputs, so that it doesn't matter which
- * two non-null constants we consider. Currently the code below just reports
- * "proof failed" if either constant is NULL, but in some cases we could be
- * smarter (and that likely would require checking strong vs. weak proofs).
+ * two non-null constants we consider. If either constant is NULL, we have
+ * to think harder, but sometimes the proof still works, as explained below.
*
* We can make proofs involving several expression forms (here "foo" and "bar"
* represent subexpressions that are identical according to equal()):
* and we dare not make deductions with those.
*/
static bool
-operator_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
+operator_predicate_proof(Expr *predicate, Node *clause,
+ bool refute_it, bool weak)
{
OpExpr *pred_opexpr,
*clause_opexpr;
* We have two identical subexpressions, and two other subexpressions that
* are not identical but are both Consts; and we have commuted the
* operators if necessary so that the Consts are on the right. We'll need
- * to compare the Consts' values. If either is NULL, fail.
- *
- * Future work: in some cases the desired proof might hold even with NULL
- * constants. But beware that we've not yet identified the operators as
- * btree ops, so for instance it'd be quite unsafe to assume they are
- * strict without checking.
+ * to compare the Consts' values. If either is NULL, we can't do that, so
+ * usually the proof fails ... but in some cases we can claim success.
*/
- if (pred_const->constisnull)
- return false;
if (clause_const->constisnull)
+ {
+ /* If clause_op isn't strict, we can't prove anything */
+ if (!op_strict(clause_op))
+ return false;
+
+ /*
+ * At this point we know that the clause returns NULL. For proof
+ * types that assume truth of the clause, this means the proof is
+ * vacuously true (a/k/a "false implies anything"). That's all proof
+ * types except weak implication.
+ */
+ if (!(weak && !refute_it))
+ return true;
+
+ /*
+ * For weak implication, it's still possible for the proof to succeed,
+ * if the predicate can also be proven NULL. In that case we've got
+ * NULL => NULL which is valid for this proof type.
+ */
+ if (pred_const->constisnull && op_strict(pred_op))
+ return true;
+ /* Else the proof fails */
+ return false;
+ }
+ if (pred_const->constisnull)
+ {
+ /*
+ * If the pred_op is strict, we know the predicate yields NULL, which
+ * means the proof succeeds for either weak implication or weak
+ * refutation.
+ */
+ if (weak && op_strict(pred_op))
+ return true;
+ /* Else the proof fails */
return false;
+ }
/*
* Lookup the constant-comparison operator using the system catalogs and