Extend DomainHasConstraints() to optionally check constraint volatility

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
This commit is contained in:
Andrew Dunstan 2026-03-12 17:52:33 -04:00
parent a630ac5c20
commit 487cf2cbd2
7 changed files with 32 additions and 9 deletions

View 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);
}
}

View 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;
}

View 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);
}

View 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)

View 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;

View 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;
}

View 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);