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 clausetypespecific */
+ 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 usecases
+ * for that at the moment, assuming that the predicate has
+ * been through constantfolding.
+ *
+ */
+ 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 predicatetypespecific */
+ 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 usecases for that at the moment,
 * assuming that the predicate has been through constantfolding.
+ * 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 operatorrelated knowledge */
return operator_predicate_proof(predicate, clause, false, weak);
}