static List *pull_ands(List *andlist);
 static List *pull_ors(List *orlist);
-static Expr *find_duplicate_ors(Expr *qual);
+static Expr *find_duplicate_ors(Expr *qual, bool is_check);
 static Expr *process_duplicate_ors(List *orlist);
 
 
  * canonicalize_qual
  *   Convert a qualification expression to the most useful form.
  *
+ * Backwards-compatibility wrapper for use by external code that hasn't
+ * been updated.
+ */
+Expr *
+canonicalize_qual(Expr *qual)
+{
+   return canonicalize_qual_ext(qual, false);
+}
+
+/*
+ * canonicalize_qual_ext
+ *   Convert a qualification expression to the most useful form.
+ *
+ * This is primarily intended to be used on top-level WHERE (or JOIN/ON)
+ * clauses.  It can also be used on top-level CHECK constraints, for which
+ * pass is_check = true.  DO NOT call it on any expression that is not known
+ * to be one or the other, as it might apply inappropriate simplifications.
+ *
  * The name of this routine is a holdover from a time when it would try to
  * force the expression into canonical AND-of-ORs or OR-of-ANDs form.
  * Eventually, we recognized that that had more theoretical purity than
  * Returns the modified qualification.
  */
 Expr *
-canonicalize_qual(Expr *qual)
+canonicalize_qual_ext(Expr *qual, bool is_check)
 {
    Expr       *newqual;
 
     * within the top-level AND/OR structure; there's no point in looking
     * deeper.  Also remove any NULL constants in the top-level structure.
     */
-   newqual = find_duplicate_ors(qual);
+   newqual = find_duplicate_ors(qual, is_check);
 
    return newqual;
 }
  *   Only the top-level AND/OR structure is searched.
  *
  * While at it, we remove any NULL constants within the top-level AND/OR
- * structure, eg "x OR NULL::boolean" is reduced to "x".  In general that
- * would change the result, so eval_const_expressions can't do it; but at
- * top level of WHERE, we don't need to distinguish between FALSE and NULL
- * results, so it's valid to treat NULL::boolean the same as FALSE and then
- * simplify AND/OR accordingly.
+ * structure, eg in a WHERE clause, "x OR NULL::boolean" is reduced to "x".
+ * In general that would change the result, so eval_const_expressions can't
+ * do it; but at top level of WHERE, we don't need to distinguish between
+ * FALSE and NULL results, so it's valid to treat NULL::boolean the same
+ * as FALSE and then simplify AND/OR accordingly.  Conversely, in a top-level
+ * CHECK constraint, we may treat a NULL the same as TRUE.
  *
  * Returns the modified qualification.  AND/OR flatness is preserved.
  */
 static Expr *
-find_duplicate_ors(Expr *qual)
+find_duplicate_ors(Expr *qual, bool is_check)
 {
    if (or_clause((Node *) qual))
    {
        {
            Expr       *arg = (Expr *) lfirst(temp);
 
-           arg = find_duplicate_ors(arg);
+           arg = find_duplicate_ors(arg, is_check);
 
            /* Get rid of any constant inputs */
            if (arg && IsA(arg, Const))
            {
                Const      *carg = (Const *) arg;
 
-               /* Drop constant FALSE or NULL */
-               if (carg->constisnull || !DatumGetBool(carg->constvalue))
-                   continue;
-               /* constant TRUE, so OR reduces to TRUE */
-               return arg;
+               if (is_check)
+               {
+                   /* Within OR in CHECK, drop constant FALSE */
+                   if (!carg->constisnull && !DatumGetBool(carg->constvalue))
+                       continue;
+                   /* Constant TRUE or NULL, so OR reduces to TRUE */
+                   return (Expr *) makeBoolConst(true, false);
+               }
+               else
+               {
+                   /* Within OR in WHERE, drop constant FALSE or NULL */
+                   if (carg->constisnull || !DatumGetBool(carg->constvalue))
+                       continue;
+                   /* Constant TRUE, so OR reduces to TRUE */
+                   return arg;
+               }
            }
 
            orlist = lappend(orlist, arg);
        {
            Expr       *arg = (Expr *) lfirst(temp);
 
-           arg = find_duplicate_ors(arg);
+           arg = find_duplicate_ors(arg, is_check);
 
            /* Get rid of any constant inputs */
            if (arg && IsA(arg, Const))
            {
                Const      *carg = (Const *) arg;
 
-               /* Drop constant TRUE */
-               if (!carg->constisnull && DatumGetBool(carg->constvalue))
-                   continue;
-               /* constant FALSE or NULL, so AND reduces to FALSE */
-               return (Expr *) makeBoolConst(false, false);
+               if (is_check)
+               {
+                   /* Within AND in CHECK, drop constant TRUE or NULL */
+                   if (carg->constisnull || DatumGetBool(carg->constvalue))
+                       continue;
+                   /* Constant FALSE, so AND reduces to FALSE */
+                   return arg;
+               }
+               else
+               {
+                   /* Within AND in WHERE, drop constant TRUE */
+                   if (!carg->constisnull && DatumGetBool(carg->constvalue))
+                       continue;
+                   /* Constant FALSE or NULL, so AND reduces to FALSE */
+                   return (Expr *) makeBoolConst(false, false);
+               }
            }
 
            andlist = lappend(andlist, arg);