v3-0003-Teach-expr_is_nonnullable-to-handle-more-expressi.patch
application/octet-stream
Filename: v3-0003-Teach-expr_is_nonnullable-to-handle-more-expressi.patch
Type: application/octet-stream
Part: 2
From edf52acd1f6b08c33d54e1e4378428c47ed9a67c Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Mon, 1 Dec 2025 16:14:53 +0900
Subject: [PATCH v3 3/3] Teach expr_is_nonnullable() to handle more expression
types
---
src/backend/optimizer/util/clauses.c | 105 +++++++++++++++++++++++----
1 file changed, 90 insertions(+), 15 deletions(-)
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 933ac38d62e..712f071a389 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -4333,24 +4333,99 @@ var_is_nonnullable(PlannerInfo *root, Var *var, bool use_rel_info)
bool
expr_is_nonnullable(PlannerInfo *root, Expr *expr, bool use_rel_info)
{
- if (IsA(expr, Var) && root)
- return var_is_nonnullable(root, (Var *) expr, use_rel_info);
- if (IsA(expr, Const))
- return !((Const *) expr)->constisnull;
- if (IsA(expr, CoalesceExpr))
+ switch (nodeTag(expr))
{
- /*
- * A CoalesceExpr returns NULL if and only if all its arguments are
- * NULL. Therefore, we can determine that a CoalesceExpr cannot be
- * NULL if at least one of its arguments can be proven non-nullable.
- */
- CoalesceExpr *coalesceexpr = (CoalesceExpr *) expr;
+ case T_Var:
+ {
+ if (root)
+ return var_is_nonnullable(root, (Var *) expr, use_rel_info);
+ }
+ break;
+ case T_Const:
+ return !((Const *) expr)->constisnull;
+ case T_CoalesceExpr:
+ {
+ /*
+ * A CoalesceExpr returns NULL if and only if all its
+ * arguments are NULL. Therefore, we can determine that a
+ * CoalesceExpr cannot be NULL if at least one of its
+ * arguments can be proven non-nullable.
+ */
+ CoalesceExpr *coalesceexpr = (CoalesceExpr *) expr;
- foreach_ptr(Expr, arg, coalesceexpr->args)
- {
- if (expr_is_nonnullable(root, arg, use_rel_info))
+ foreach_ptr(Expr, arg, coalesceexpr->args)
+ {
+ if (expr_is_nonnullable(root, arg, use_rel_info))
+ return true;
+ }
+ }
+ break;
+ case T_MinMaxExpr:
+ {
+ /*
+ * Like CoalesceExpr, a MinMaxExpr returns NULL only if all
+ * its arguments evaluate to NULL.
+ */
+ MinMaxExpr *minmaxexpr = (MinMaxExpr *) expr;
+
+ foreach_ptr(Expr, arg, minmaxexpr->args)
+ {
+ if (expr_is_nonnullable(root, arg, use_rel_info))
+ return true;
+ }
+ }
+ break;
+ case T_ArrayExpr:
+ {
+ /*
+ * An ARRAY[] expression always returns a valid Array object,
+ * even if it is empty (ARRAY[]) or contains NULLs
+ * (ARRAY[NULL]). It never evaluates to a SQL NULL.
+ */
return true;
- }
+ }
+ case T_NullTest:
+ {
+ /*
+ * An IS NULL / IS NOT NULL expression always returns a
+ * boolean value. It never returns SQL NULL.
+ */
+ return true;
+ }
+ case T_BooleanTest:
+ {
+ /*
+ * A BooleanTest expression always evaluates to a boolean
+ * value. It never returns SQL NULL.
+ */
+ return true;
+ }
+ case T_CaseExpr:
+ {
+ /*
+ * A CASE expression is non-nullable if all branch results are
+ * non-nullable. We must also verify that the default result
+ * (ELSE) exists and is non-nullable.
+ */
+ CaseExpr *caseexpr = (CaseExpr *) expr;
+
+ /* The default result must be present and non-nullable */
+ if (caseexpr->defresult == NULL ||
+ !expr_is_nonnullable(root, caseexpr->defresult, use_rel_info))
+ return false;
+
+ /* All branch results must be non-nullable */
+ foreach_ptr(CaseWhen, casewhen, caseexpr->args)
+ {
+ if (!expr_is_nonnullable(root, casewhen->result, use_rel_info))
+ return false;
+ }
+
+ return true;
+ }
+ break;
+ default:
+ break;
}
return false;
--
2.39.5 (Apple Git-154)