On Mon, Nov 24, 2025 at 10:45 PM Peter Eisentraut <[email protected]> wrote:
>
> On 10.03.25 19:37, Alvaro Herrera wrote:
> >
> > I had forgotten this thread, and I ended up implementing a different
> > solution for this issue, which I just posted at
> >    https://postgr.es/m/[email protected]
> >
> > I like my patch better than this approach because it allows us to solve
> > the same problem as it appears in other parts of the grammar, and also
> > because it avoids the bit fiddling which is harder to maintain later on.
> > If you'd care to have a look at it, I'd appreciate it.
>
> Where are we on this?  Which of the two patches should we pursue?
>

hi.

if you go to this link
https://postgr.es/m/[email protected]
check v2-0001-Improve-processCASbits-API-with-a-seen-struct.patch
you will find that it added a struct CAS_flags to processCASbits.

+typedef struct CAS_flags
+{
+ bool seen_deferrability;
+ bool seen_enforced;
+ bool seen_valid;
+ bool seen_inherit;
+} CAS_flags;

In v2-0001, most of the case processCASbits just pass a NULL CAS_flags(seen).
CAS_flags are not used in table constraints at all.
but CAS_flags indeed used for error message handling in ALTER DOMAIN
ADD CONSTRAINT.

(IMHO, it looks like big efforts to solve the same problem, also these bit
fiddling for domain constraint unlikely to change in the future, e.g. we are
unlike to add DEFERRABLE, INITIALLY DEFERRED, NO INHERIT constraints to domain.)

anyway, both patches are attached.
this thread: v5-0001-ALTER-DOMAIN-ADD-CONSTRAINT-error-message-enhance.patch

thread: https://postgr.es/m/[email protected]
v5-0001-Improve-processCASbits-API-with-a-seen-struct.no-cfbot
v5-0002-handle-constraints-on-domains-too.no-cfbot


--
jian
https://www.enterprisedb.com
From 6e9815976016c3aea10f929f7a66251e1d0a57fd Mon Sep 17 00:00:00 2001
From: jian he <[email protected]>
Date: Wed, 26 Nov 2025 12:26:49 +0800
Subject: [PATCH v5 1/1] ALTER DOMAIN ADD CONSTRAINT error message enhance

DomainConstraintElem syntax in gram.y can specify constraint properties such as
([ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE | NO INHERIT ] [ENFORCED | NOT ENFORCED])

ALTER DOMAIN synopsis section indicate none of these properties are allowed.
These properties (DomainConstraintElem) are wrapped up as a separate individual
Constraints node (see DefineDomain).

However, AlterDomainAddConstraint can only cope with a single Constraints node.
therefore, error out at AlterDomainAddConstraint is not possible, so error
message handling stay at gram.y.

discussion: https://postgr.es/m/cacjufxhitd5lglbssapshhtdwxt0vivkthinkyw-skbx93t...@mail.gmail.com
---
 src/backend/parser/gram.y            | 53 +++++++++++++++++++++++++---
 src/test/regress/expected/domain.out | 42 ++++++++++++++++++++--
 src/test/regress/sql/domain.sql      | 12 +++++++
 3 files changed, 101 insertions(+), 6 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c3a0a354a9c..920e611cfb9 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4447,8 +4447,28 @@ DomainConstraintElem:
 					n->raw_expr = $3;
 					n->cooked_expr = NULL;
 					processCASbits($5, @5, "CHECK",
-								   NULL, NULL, NULL, &n->skip_validation,
-								   &n->is_no_inherit, yyscanner);
+								   &n->deferrable, &n->initdeferred, &n->is_enforced,
+								   &n->skip_validation, &n->is_no_inherit, yyscanner);
+
+					if ($5 & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE | CAS_INITIALLY_IMMEDIATE |
+							  CAS_INITIALLY_DEFERRED))
+						ereport(ERROR,
+							errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("specifying constraint deferrability not supported for domains"),
+							parser_errposition(@5));
+
+					if ($5 & (CAS_NOT_ENFORCED | CAS_ENFORCED))
+						ereport(ERROR,
+							errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("specifying constraint enforceability not supported for domains"),
+							parser_errposition(@5));
+
+					if (n->is_no_inherit)
+						ereport(ERROR,
+							errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("check constraints for domains cannot be marked %s", "NO INHERIT"),
+							parser_errposition(@5));
+
 					n->is_enforced = true;
 					n->initially_valid = !n->skip_validation;
 					$$ = (Node *) n;
@@ -4462,8 +4482,33 @@ DomainConstraintElem:
 					n->keys = list_make1(makeString("value"));
 					/* no NOT VALID, NO INHERIT support */
 					processCASbits($3, @3, "NOT NULL",
-								   NULL, NULL, NULL,
-								   NULL, NULL, yyscanner);
+								   &n->deferrable, &n->initdeferred, &n->is_enforced,
+								   &n->skip_validation, &n->is_no_inherit, yyscanner);
+					if (($3 & CAS_NOT_VALID) != 0)
+						ereport(ERROR,
+								errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								errmsg("not-null constraints on domains cannot be marked %s", "NOT VALID"),
+								parser_errposition(@3));
+
+					if ($3 & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE | CAS_INITIALLY_IMMEDIATE |
+							  CAS_INITIALLY_DEFERRED))
+						ereport(ERROR,
+							errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("specifying constraint deferrability not supported for domains"),
+							parser_errposition(@3));
+
+					if ($3 & (CAS_NOT_ENFORCED | CAS_ENFORCED))
+						ereport(ERROR,
+							errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("specifying constraint enforceability not supported for domains"),
+							parser_errposition(@3));
+
+					if (n->is_no_inherit)
+						ereport(ERROR,
+							errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("not-null constraints on domains cannot be marked %s", "NO INHERIT"),
+							parser_errposition(@3));
+
 					n->initially_valid = true;
 					$$ = (Node *) n;
 				}
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 62a48a523a2..357dac1f555 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -68,6 +68,44 @@ create domain d_fail as int4 constraint cc check (values > 1) deferrable;
 ERROR:  specifying constraint deferrability not supported for domains
 LINE 1: ...n d_fail as int4 constraint cc check (values > 1) deferrable...
                                                              ^
+create domain d_int as int4;
+alter domain d_int add constraint nn not null not valid;
+ERROR:  not-null constraints on domains cannot be marked NOT VALID
+LINE 1: alter domain d_int add constraint nn not null not valid;
+                                                      ^
+alter domain d_int add constraint nn not null no inherit;
+ERROR:  not-null constraints on domains cannot be marked NO INHERIT
+LINE 1: alter domain d_int add constraint nn not null no inherit;
+                                                      ^
+alter domain d_int add constraint nn not null not enforced;
+ERROR:  specifying constraint enforceability not supported for domains
+LINE 1: alter domain d_int add constraint nn not null not enforced;
+                                                      ^
+alter domain d_int add constraint nn not null not deferrable initially immediate;
+ERROR:  specifying constraint deferrability not supported for domains
+LINE 1: alter domain d_int add constraint nn not null not deferrable...
+                                                      ^
+alter domain d_int add constraint cc check(value > 1) no inherit;
+ERROR:  check constraints for domains cannot be marked NO INHERIT
+LINE 1: ...r domain d_int add constraint cc check(value > 1) no inherit...
+                                                             ^
+alter domain d_int add constraint cc check(value > 1) not enforced;
+ERROR:  specifying constraint enforceability not supported for domains
+LINE 1: ...r domain d_int add constraint cc check(value > 1) not enforc...
+                                                             ^
+alter domain d_int add constraint cc check(value > 1) enforced;
+ERROR:  specifying constraint enforceability not supported for domains
+LINE 1: ...er domain d_int add constraint cc check(value > 1) enforced;
+                                                              ^
+alter domain d_int add constraint cc check(value > 1) not deferrable initially immediate;
+ERROR:  specifying constraint deferrability not supported for domains
+LINE 1: ...r domain d_int add constraint cc check(value > 1) not deferr...
+                                                             ^
+alter domain d_int add constraint cc check(value > 1) deferrable initially deferred;
+ERROR:  specifying constraint deferrability not supported for domains
+LINE 1: ...r domain d_int add constraint cc check(value > 1) deferrable...
+                                                             ^
+drop domain d_int;
 -- Test domain input.
 -- Note: the point of checking both INSERT and COPY FROM is that INSERT
 -- exercises CoerceToDomain while COPY exercises domain_in.
@@ -1369,11 +1407,11 @@ LINE 1: ...S int CONSTRAINT the_constraint CHECK (value > 0) NOT ENFORC...
 CREATE DOMAIN constraint_enforced_dom AS int;
 -- XXX misleading error messages
 ALTER DOMAIN constraint_enforced_dom ADD CONSTRAINT the_constraint CHECK (value > 0) ENFORCED;
-ERROR:  CHECK constraints cannot be marked ENFORCED
+ERROR:  specifying constraint enforceability not supported for domains
 LINE 1: ...om ADD CONSTRAINT the_constraint CHECK (value > 0) ENFORCED;
                                                               ^
 ALTER DOMAIN constraint_enforced_dom ADD CONSTRAINT the_constraint CHECK (value > 0) NOT ENFORCED;
-ERROR:  CHECK constraints cannot be marked NOT ENFORCED
+ERROR:  specifying constraint enforceability not supported for domains
 LINE 1: ...m ADD CONSTRAINT the_constraint CHECK (value > 0) NOT ENFORC...
                                                              ^
 DROP DOMAIN constraint_enforced_dom;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index b8f5a639712..b0c13a75e3a 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -31,6 +31,18 @@ create domain d_fail as int4 constraint cc generated by default as identity;
 create domain d_fail as int4 constraint cc check (values > 1) no inherit;
 create domain d_fail as int4 constraint cc check (values > 1) deferrable;
 
+create domain d_int as int4;
+alter domain d_int add constraint nn not null not valid;
+alter domain d_int add constraint nn not null no inherit;
+alter domain d_int add constraint nn not null not enforced;
+alter domain d_int add constraint nn not null not deferrable initially immediate;
+alter domain d_int add constraint cc check(value > 1) no inherit;
+alter domain d_int add constraint cc check(value > 1) not enforced;
+alter domain d_int add constraint cc check(value > 1) enforced;
+alter domain d_int add constraint cc check(value > 1) not deferrable initially immediate;
+alter domain d_int add constraint cc check(value > 1) deferrable initially deferred;
+drop domain d_int;
+
 -- Test domain input.
 
 -- Note: the point of checking both INSERT and COPY FROM is that INSERT
-- 
2.34.1

Attachment: v5-0001-Improve-processCASbits-API-with-a-seen-struct.no-cfbot
Description: Binary data

Attachment: v5-0002-handle-constraints-on-domains-too.no-cfbot
Description: Binary data

Reply via email to