From eb6112c7e81eb2de0027b016ae27e08abf86447a Mon Sep 17 00:00:00 2001 From: Nitin Motiani Date: Mon, 28 Sep 2026 12:49:33 +0000 Subject: [PATCH v2 1/3] Fix ALTER TYPE ... ALTER ATTRIBUTE on types used in domain constraints. Commit af20e2d72 updated ALTER TABLE / TYPE to rebuild domain constraints when an attribute of a composite type is altered. However, it assumed that the domain's base type was always the composite type being altered, calling get_typ_typrelid(getBaseType(con->contypid)). If the domain was defined over a scalar type (such as int or float8) whose CHECK expression referenced the composite type, get_typ_typrelid() returned InvalidOid, triggering an internal "could not identify relation associated with constraint" error. Fix by attaching the deferred domain constraint rebuild command to the table being altered (tab->relid) rather than attempting to derive a relation OID from the domain's base type. Domains do not have pg_class relations of their own, and the rebuild command (AlterDomainStmt) is self-contained. Reported-by: Alexander Lakhin Bug: #19724 --- src/backend/commands/tablecmds.c | 10 +++--- src/test/regress/expected/domain.out | 50 ++++++++++++++++++++++++++++ src/test/regress/sql/domain.sql | 33 ++++++++++++++++++ 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 0274d892f2e..c8bc193a2ab 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -16141,10 +16141,12 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) relid = con->conrelid; else { - /* must be a domain constraint */ - relid = get_typ_typrelid(getBaseType(con->contypid)); - if (!OidIsValid(relid)) - elog(ERROR, "could not identify relation associated with constraint %u", oldId); + /* + * Must be a domain constraint. Domains don't have their own + * relations, so attach the rebuild step to the table being + * altered. + */ + relid = tab->relid; } confrelid = con->confrelid; conislocal = con->conislocal; diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out index 62a48a523a2..de60a90c045 100644 --- a/src/test/regress/expected/domain.out +++ b/src/test/regress/expected/domain.out @@ -432,6 +432,56 @@ select conname, obj_description(oid, 'pg_constraint') from pg_constraint drop type comptype cascade; NOTICE: drop cascades to type dcomptype +-- regression tests for bug #19724 +-- test scenario from bug report, plus failure when changing int to text +create type rt as (i int); +create domain dt as int check ((row(value)::rt).i > 0); +alter type rt alter attribute i type text; -- fail +ERROR: operator does not exist: text > integer +DETAIL: No operator of that name accepts the given argument types. +HINT: You might need to add explicit type casts. +alter type rt alter attribute i type bigint; +select 1::dt; + dt +---- + 1 +(1 row) + +select (-1)::dt; -- fail +ERROR: value for domain dt violates check constraint "dt_check" +drop domain dt; +drop type rt cascade; +-- test silly example from Tom Lane's 2017 email (domain over float8) +create type comptype as (r float8, i float8); +create domain silly as float8 check ((row(value, 0)::comptype).r > 0); +alter type comptype alter attribute r type bigint; +select 1.0::silly; + silly +------- + 1 +(1 row) + +select (-1.0)::silly; -- fail +ERROR: value for domain silly violates check constraint "silly_check" +drop domain silly; +drop type comptype cascade; +-- test domain constraint referencing multiple composite types +create type r1 as (a int); +create type r2 as (b int); +create domain dt_multi as int check ((row(value)::r1).a > 0 and (row(value)::r2).b > 0); +alter type r1 alter attribute a type bigint; +alter type r2 alter attribute b type bigint; +select 1::dt_multi; + dt_multi +---------- + 1 +(1 row) + +select (-1)::dt_multi; -- fail +ERROR: value for domain dt_multi violates check constraint "dt_multi_check" +drop domain dt_multi; +drop type r1 cascade; +drop type r2 cascade; -- Test domains over arrays of composite create type comptype as (r float8, i float8); create domain dcomptypea as comptype[]; diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql index b8f5a639712..1240f9422bd 100644 --- a/src/test/regress/sql/domain.sql +++ b/src/test/regress/sql/domain.sql @@ -219,6 +219,39 @@ select conname, obj_description(oid, 'pg_constraint') from pg_constraint drop type comptype cascade; +-- regression tests for bug #19724 + +-- test scenario from bug report, plus failure when changing int to text +create type rt as (i int); +create domain dt as int check ((row(value)::rt).i > 0); +alter type rt alter attribute i type text; -- fail +alter type rt alter attribute i type bigint; +select 1::dt; +select (-1)::dt; -- fail +drop domain dt; +drop type rt cascade; + +-- test silly example from Tom Lane's 2017 email (domain over float8) +create type comptype as (r float8, i float8); +create domain silly as float8 check ((row(value, 0)::comptype).r > 0); +alter type comptype alter attribute r type bigint; +select 1.0::silly; +select (-1.0)::silly; -- fail +drop domain silly; +drop type comptype cascade; + +-- test domain constraint referencing multiple composite types +create type r1 as (a int); +create type r2 as (b int); +create domain dt_multi as int check ((row(value)::r1).a > 0 and (row(value)::r2).b > 0); +alter type r1 alter attribute a type bigint; +alter type r2 alter attribute b type bigint; +select 1::dt_multi; +select (-1)::dt_multi; -- fail +drop domain dt_multi; +drop type r1 cascade; +drop type r2 cascade; + -- Test domains over arrays of composite -- 2.50.1 (Apple Git-155)