diff options
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 93add27dbe2..79613622805 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1361,6 +1361,17 @@ contain_nonstrict_functions_walker(Node *node, void *context) return true; if (IsA(node, FieldStore)) return true; + if (IsA(node, ArrayCoerceExpr)) + { + /* + * ArrayCoerceExpr is strict at the array level, regardless of what + * the per-element expression is; so we should ignore elemexpr and + * recurse only into the arg. + */ + return expression_tree_walker((Node *) ((ArrayCoerceExpr *) node)->arg, + contain_nonstrict_functions_walker, + context); + } if (IsA(node, CaseExpr)) return true; if (IsA(node, ArrayExpr)) @@ -1380,14 +1391,11 @@ contain_nonstrict_functions_walker(Node *node, void *context) if (IsA(node, BooleanTest)) return true; - /* - * Check other function-containing nodes; but ArrayCoerceExpr is strict at - * the array level, regardless of elemfunc. - */ - if (!IsA(node, ArrayCoerceExpr) && - check_functions_in_node(node, contain_nonstrict_functions_checker, + /* Check other function-containing nodes */ + if (check_functions_in_node(node, contain_nonstrict_functions_checker, context)) return true; + return expression_tree_walker(node, contain_nonstrict_functions_walker, context); } @@ -1757,7 +1765,7 @@ find_nonnullable_rels_walker(Node *node, bool top_level) } else if (IsA(node, ArrayCoerceExpr)) { - /* ArrayCoerceExpr is strict at the array level */ + /* ArrayCoerceExpr is strict at the array level; ignore elemexpr */ ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; result = find_nonnullable_rels_walker((Node *) expr->arg, top_level); @@ -1965,7 +1973,7 @@ find_nonnullable_vars_walker(Node *node, bool top_level) } else if (IsA(node, ArrayCoerceExpr)) { - /* ArrayCoerceExpr is strict at the array level */ + /* ArrayCoerceExpr is strict at the array level; ignore elemexpr */ ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; result = find_nonnullable_vars_walker((Node *) expr->arg, top_level); @@ -3005,32 +3013,38 @@ eval_const_expressions_mutator(Node *node, { ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; Expr *arg; + Expr *elemexpr; ArrayCoerceExpr *newexpr; /* - * Reduce constants in the ArrayCoerceExpr's argument, then - * build a new ArrayCoerceExpr. + * Reduce constants in the ArrayCoerceExpr's argument and + * per-element expressions, then build a new ArrayCoerceExpr. */ arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg, context); + elemexpr = (Expr *) eval_const_expressions_mutator((Node *) expr->elemexpr, + context); newexpr = makeNode(ArrayCoerceExpr); newexpr->arg = arg; - newexpr->elemfuncid = expr->elemfuncid; + newexpr->elemexpr = elemexpr; newexpr->resulttype = expr->resulttype; newexpr->resulttypmod = expr->resulttypmod; newexpr->resultcollid = expr->resultcollid; - newexpr->isExplicit = expr->isExplicit; newexpr->coerceformat = expr->coerceformat; newexpr->location = expr->location; /* - * If constant argument and it's a binary-coercible or - * immutable conversion, we can simplify it to a constant. + * If constant argument and per-element expression is + * immutable, we can simplify the whole thing to a constant. + * Exception: although contain_mutable_functions considers + * CoerceToDomain immutable for historical reasons, let's not + * do so here; this ensures coercion to an array-over-domain + * does not apply the domain's constraints until runtime. */ if (arg && IsA(arg, Const) && - (!OidIsValid(newexpr->elemfuncid) || - func_volatile(newexpr->elemfuncid) == PROVOLATILE_IMMUTABLE)) + elemexpr && !IsA(elemexpr, CoerceToDomain) && + !contain_mutable_functions((Node *) elemexpr)) return (Node *) evaluate_expr((Expr *) newexpr, newexpr->resulttype, newexpr->resulttypmod, |