WIP-refactor-predicate_implied_by_simple_clause.patch
text/x-diff
Filename: WIP-refactor-predicate_implied_by_simple_clause.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/optimizer/util/predtest.c | 98 | 74 |
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index fe83e45311..a9accbed53 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -1087,38 +1087,12 @@ arrayexpr_cleanup_fn(PredIterInfo info)
}
-/*----------
+/*
* predicate_implied_by_simple_clause
* Does the predicate implication test for a "simple clause" predicate
* and a "simple clause" restriction.
*
* We return true if able to prove the implication, false if not.
- *
- * We have several 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, and for either implication definition. (Actually,
- * there is an implied assumption that the functions in the expression are
- * immutable --- but this was checked for the predicate by the caller.)
- *
- * Another way that always works is that for boolean x, "x = TRUE" is
- * equivalent to "x", likewise "x = FALSE" is equivalent to "NOT x".
- * These can be worth checking because, while we preferentially simplify
- * boolean comparisons down to "x" and "NOT x", the other form has to be
- * dealt with anyway in the context of index conditions.
- *
- * If the predicate is of the form "foo IS NOT NULL", and we are considering
- * strong implication, we can conclude that the predicate is implied if the
- * clause is strict for "foo", i.e., it must yield false or NULL when "foo"
- * is NULL. In that case truth of the clause ensures that "foo" isn't NULL.
- * (Again, this is a safe conclusion because "foo" must be immutable.)
- * This doesn't work for weak implication, though.
- *
- * Finally, if both clauses are binary operator expressions, we may be able
- * to prove something using the system's knowledge about operators; those
- * proof rules are encapsulated in operator_predicate_proof().
- *----------
*/
static bool
predicate_implied_by_simple_clause(Expr *predicate, Node *clause,
@@ -1127,65 +1101,115 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause,
/* Allow interrupting long proof attempts */
CHECK_FOR_INTERRUPTS();
- /* First try the equal() test */
+ /*
+ * A simple and general rule is that a clause implies itself, hence we
+ * check if they are equal(); this works for any kind of expression, and
+ * for either implication definition. (Actually, there is an implied
+ * assumption that the functions in the expression are immutable --- but
+ * this was checked for the predicate by the caller.)
+ */
if (equal((Node *) predicate, clause))
return true;
- /* Next see if clause is boolean equality to a constant */
- if (is_opclause(clause) &&
- ((OpExpr *) clause)->opno == BooleanEqualOperator)
+ /* Our remaining strategies are all clause-type-specific */
+ switch (nodeTag(clause))
{
- OpExpr *op = (OpExpr *) clause;
- Node *rightop;
-
- Assert(list_length(op->args) == 2);
- rightop = lsecond(op->args);
- /* We might never see a null Const here, but better check anyway */
- if (rightop && IsA(rightop, Const) &&
- !((Const *) rightop)->constisnull)
- {
- Node *leftop = linitial(op->args);
-
- if (DatumGetBool(((Const *) rightop)->constvalue))
+ case T_OpExpr:
{
- /* X = true implies X */
- if (equal(predicate, leftop))
- return true;
+ OpExpr *op = (OpExpr *) clause;
+
+ /*----------
+ * For boolean x, "x = TRUE" is equivalent to "x", likewise
+ * "x = FALSE" is equivalent to "NOT x". These can be worth
+ * checking because, while we preferentially simplify boolean
+ * comparisons down to "x" and "NOT x", the other form has to
+ * be dealt with anyway in the context of index conditions.
+ *
+ * We could likewise check whether the predicate is boolean
+ * equality to a constant; but there are no known use-cases
+ * for that at the moment, assuming that the predicate has
+ * been through constant-folding.
+ *----------
+ */
+ if (op->opno == BooleanEqualOperator)
+ {
+ Node *rightop;
+
+ Assert(list_length(op->args) == 2);
+ rightop = lsecond(op->args);
+
+ /*
+ * We might never see a null Const here, but better check
+ * anyway
+ */
+ if (rightop && IsA(rightop, Const) &&
+ !((Const *) rightop)->constisnull)
+ {
+ Node *leftop = linitial(op->args);
+
+ if (DatumGetBool(((Const *) rightop)->constvalue))
+ {
+ /* X = true implies X */
+ if (equal(predicate, leftop))
+ return true;
+ }
+ else
+ {
+ /* X = false implies NOT X */
+ if (is_notclause(predicate) &&
+ equal(get_notclausearg(predicate), leftop))
+ return true;
+ }
+ }
+ }
}
- else
+ break;
+ default:
+ break;
+ }
+
+ /* ... or predicate-type-specific */
+ switch (nodeTag(predicate))
+ {
+ case T_NullTest:
{
- /* X = false implies NOT X */
- if (is_notclause(predicate) &&
- equal(get_notclausearg(predicate), leftop))
- return true;
+ NullTest *ntest = (NullTest *) predicate;
+
+ switch (ntest->nulltesttype)
+ {
+ case IS_NOT_NULL:
+
+ /*
+ * If the predicate is of the form "foo IS NOT NULL",
+ * and we are considering strong implication, we can
+ * conclude that the predicate is implied if the
+ * clause is strict for "foo", i.e., it must yield
+ * false or NULL when "foo" is NULL. In that case
+ * truth of the clause ensures that "foo" isn't NULL.
+ * (Again, this is a safe conclusion because "foo"
+ * must be immutable.) This doesn't work for weak
+ * implication, though. Also, "row IS NOT NULL" does
+ * not act in the simple way we have in mind.
+ */
+ if (!weak &&
+ !ntest->argisrow &&
+ clause_is_strict_for(clause, (Node *) ntest->arg, true))
+ return true;
+ break;
+ default:
+ break;
+ }
}
- }
+ break;
+ default:
+ break;
}
/*
- * We could likewise check whether the predicate is boolean equality to a
- * constant; but there are no known use-cases for that at the moment,
- * assuming that the predicate has been through constant-folding.
+ * If both clauses are binary operator expressions, we may be able to
+ * prove something using the system's knowledge about operators; those
+ * proof rules are encapsulated in operator_predicate_proof().
*/
-
- /* Next try the IS NOT NULL case */
- if (!weak &&
- predicate && IsA(predicate, NullTest))
- {
- NullTest *ntest = (NullTest *) predicate;
-
- /* row IS NOT NULL does not act in the simple way we have in mind */
- if (ntest->nulltesttype == IS_NOT_NULL &&
- !ntest->argisrow)
- {
- /* strictness of clause for foo implies foo IS NOT NULL */
- if (clause_is_strict_for(clause, (Node *) ntest->arg, true))
- return true;
- }
- return false; /* we can't succeed below... */
- }
-
- /* Else try operator-related knowledge */
return operator_predicate_proof(predicate, clause, false, weak);
}