]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Extend DomainHasConstraints() to optionally check constraint volatility
authorAndrew Dunstan <andrew@dunslane.net>
Thu, 12 Mar 2026 21:52:33 +0000 (17:52 -0400)
committerAndrew Dunstan <andrew@dunslane.net>
Thu, 12 Mar 2026 22:04:16 +0000 (18:04 -0400)
Add an optional bool *has_volatile output parameter to
DomainHasConstraints().  When non-NULL, the function checks whether any
CHECK constraint contains a volatile expression.  Callers that don't
need this information pass NULL and get the same behavior as before.

This is needed by a subsequent commit that enables the fast default
optimization for domains with non-volatile constraints: we can safely
evaluate such constraints once at ALTER TABLE time, but volatile
constraints require a full table rewrite.

Author: Jian He <jian.universality@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>
Reviewed-by: Viktor Holmberg <viktor.holmberg@aiven.io>
Discussion: https://postgr.es/m/CACJufxE_+iZBR1i49k_AHigppPwLTJi6km8NOsC7FWvKdEmmXg@mail.gmail.com

src/backend/commands/copyfrom.c
src/backend/commands/tablecmds.c
src/backend/executor/execExpr.c
src/backend/optimizer/util/clauses.c
src/backend/parser/parse_expr.c
src/backend/utils/cache/typcache.c
src/include/utils/typcache.h

index 2f42f55e2291d5cd87570404db8d77fb81b717fa..0ece40557c8628efa4459a07f2191186ac6d8635 100644 (file)
@@ -1653,7 +1653,7 @@ BeginCopyFrom(ParseState *pstate,
 
                        Form_pg_attribute att = TupleDescAttr(tupDesc, attno - 1);
 
-                       cstate->domain_with_constraint[i] = DomainHasConstraints(att->atttypid);
+                       cstate->domain_with_constraint[i] = DomainHasConstraints(att->atttypid, NULL);
                }
        }
 
index a7c32679b22823c382dc4ce92f18c1806f293dc1..54d93d0a0de2a845be041f725625ceeedb14da5d 100644 (file)
@@ -7531,7 +7531,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
                        defval = (Expr *) build_column_default(rel, attribute->attnum);
 
                /* Build CoerceToDomain(NULL) expression if needed */
-               has_domain_constraints = DomainHasConstraints(attribute->atttypid);
+               has_domain_constraints = DomainHasConstraints(attribute->atttypid, NULL);
                if (!defval && has_domain_constraints)
                {
                        Oid                     baseTypeId;
@@ -14893,7 +14893,7 @@ ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
                {
                        CoerceToDomain *d = (CoerceToDomain *) expr;
 
-                       if (DomainHasConstraints(d->resulttype))
+                       if (DomainHasConstraints(d->resulttype, NULL))
                                return true;
                        expr = (Node *) d->arg;
                }
index 088eca24021dd0e70c8676fdecbcbe6701adc407..b96eb0c55cc7693030923adaca85b1c11eb335d8 100644 (file)
@@ -5061,6 +5061,6 @@ ExecInitJsonCoercion(ExprState *state, JsonReturning *returning,
        scratch.d.jsonexpr_coercion.exists_cast_to_int = exists_coerce &&
                getBaseType(returning->typid) == INT4OID;
        scratch.d.jsonexpr_coercion.exists_check_domain = exists_coerce &&
-               DomainHasConstraints(returning->typid);
+               DomainHasConstraints(returning->typid, NULL);
        ExprEvalPushStep(state, &scratch);
 }
index f0f8e2515ecd4cab3bc1a3701c82a36fc38d9f97..9fb266d089dfcc8b0d7d7eb9a8229ed0dc961f31 100644 (file)
@@ -4039,7 +4039,7 @@ eval_const_expressions_mutator(Node *node,
                                arg = eval_const_expressions_mutator((Node *) cdomain->arg,
                                                                                                         context);
                                if (context->estimate ||
-                                       !DomainHasConstraints(cdomain->resulttype))
+                                       !DomainHasConstraints(cdomain->resulttype, NULL))
                                {
                                        /* Record dependency, if this isn't estimation mode */
                                        if (context->root && !context->estimate)
index dcfe1acc4c3221118e49d1bf771f72185ce41210..96991cae764dd43e351fe18284b5651b6974caeb 100644 (file)
@@ -4628,7 +4628,7 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
                        if (jsexpr->returning->typid != TEXTOID)
                        {
                                if (get_typtype(jsexpr->returning->typid) == TYPTYPE_DOMAIN &&
-                                       DomainHasConstraints(jsexpr->returning->typid))
+                                       DomainHasConstraints(jsexpr->returning->typid, NULL))
                                        jsexpr->use_json_coercion = true;
                                else
                                        jsexpr->use_io_coercion = true;
index 627e534609ab2097455bbc1f08e279869ffbfabd..cebe7a916fbf927e686059d2af36bb9fdb80bfd4 100644 (file)
@@ -1485,10 +1485,14 @@ UpdateDomainConstraintRef(DomainConstraintRef *ref)
 /*
  * DomainHasConstraints --- utility routine to check if a domain has constraints
  *
+ * Returns true if the domain has any constraints at all.  If has_volatile
+ * is not NULL, also checks whether any CHECK constraint contains a volatile
+ * expression and sets *has_volatile accordingly.
+ *
  * This is defined to return false, not fail, if type is not a domain.
  */
 bool
-DomainHasConstraints(Oid type_id)
+DomainHasConstraints(Oid type_id, bool *has_volatile)
 {
        TypeCacheEntry *typentry;
 
@@ -1498,7 +1502,26 @@ DomainHasConstraints(Oid type_id)
         */
        typentry = lookup_type_cache(type_id, TYPECACHE_DOMAIN_CONSTR_INFO);
 
-       return (typentry->domainData != NULL);
+       if (typentry->domainData == NULL)
+               return false;
+
+       if (has_volatile)
+       {
+               *has_volatile = false;
+
+               foreach_node(DomainConstraintState, constrstate,
+                                        typentry->domainData->constraints)
+               {
+                       if (constrstate->constrainttype == DOM_CONSTRAINT_CHECK &&
+                               contain_volatile_functions((Node *) constrstate->check_expr))
+                       {
+                               *has_volatile = true;
+                               break;
+                       }
+               }
+       }
+
+       return true;
 }
 
 
index 0e3945aa2443894177966ad67efbe26bb668681a..5a4aa9ec840ebb443fa751ef0165fdbebc52621c 100644 (file)
@@ -183,7 +183,7 @@ extern void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref,
 
 extern void UpdateDomainConstraintRef(DomainConstraintRef *ref);
 
-extern bool DomainHasConstraints(Oid type_id);
+extern bool DomainHasConstraints(Oid type_id, bool *has_volatile);
 
 extern TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod);