hi. CREATE COLLATION case_insensitive (provider = icu, locale = '@colStrength=secondary', deterministic = false); SELECT 'a' = 'A' COLLATE case_insensitive; CREATE DOMAIN d1 as text collate case_insensitive check (value <> 'a'); SELECT 'A'::d1;
``SELECT 'A'::d1`` should error out as domain check constraint not satisfied? If so, attached is the POC trying to implement it.
From 8d0b94976c5c1c0cf16f70f7d740ea4f37698340 Mon Sep 17 00:00:00 2001 From: jian he <jian.universal...@gmail.com> Date: Mon, 14 Jul 2025 16:14:32 +0800 Subject: [PATCH v1 1/1] CoerceToDomainValue should use domain's collation --- src/backend/commands/typecmds.c | 15 ++++++++----- .../regress/expected/collate.icu.utf8.out | 21 +++++++++++++++++++ src/test/regress/sql/collate.icu.utf8.sql | 10 +++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 26d985193ae..529001d7bfc 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -133,7 +133,8 @@ static void checkEnumOwner(HeapTuple tup); static char *domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, - const char *domainName, ObjectAddress *constrAddr); + const char *domainName, Oid domaincoll, + ObjectAddress *constrAddr); static Node *replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref); static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, @@ -1145,7 +1146,7 @@ DefineDomain(ParseState *pstate, CreateDomainStmt *stmt) case CONSTR_CHECK: domainAddCheckConstraint(address.objectId, domainNamespace, basetypeoid, basetypeMod, - constr, domainName, NULL); + constr, domainName, domaincoll, NULL); break; case CONSTR_NOTNULL: @@ -2937,6 +2938,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint, { TypeName *typename; Oid domainoid; + Oid domaincoll; Relation typrel; HeapTuple tup; Form_pg_type typTup; @@ -2948,6 +2950,8 @@ AlterDomainAddConstraint(List *names, Node *newConstraint, typename = makeTypeNameFromNameList(names); domainoid = typenameTypeId(NULL, typename); + domaincoll = get_typcollation(domainoid); + /* Look up the domain in the type table */ typrel = table_open(TypeRelationId, RowExclusiveLock); @@ -2977,7 +2981,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint, ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace, typTup->typbasetype, typTup->typtypmod, - constr, NameStr(typTup->typname), constrAddr); + constr, NameStr(typTup->typname), domaincoll, constrAddr); /* @@ -3504,7 +3508,8 @@ checkDomainOwner(HeapTuple tup) static char * domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, - const char *domainName, ObjectAddress *constrAddr) + const char *domainName, Oid domaincoll, + ObjectAddress *constrAddr) { Node *expr; char *ccbin; @@ -3549,7 +3554,7 @@ domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, domVal = makeNode(CoerceToDomainValue); domVal->typeId = baseTypeOid; domVal->typeMod = typMod; - domVal->collation = get_typcollation(baseTypeOid); + domVal->collation = domaincoll; domVal->location = -1; /* will be set when/if used */ pstate->p_pre_columnref_hook = replace_domain_constraint_value; diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out index 69805d4b9ec..002e61c1e0e 100644 --- a/src/test/regress/expected/collate.icu.utf8.out +++ b/src/test/regress/expected/collate.icu.utf8.out @@ -1459,6 +1459,27 @@ CREATE COLLATION case_sensitive (provider = icu, locale = ''); NOTICE: using standard form "und" for ICU locale "" CREATE COLLATION case_insensitive (provider = icu, locale = '@colStrength=secondary', deterministic = false); NOTICE: using standard form "und-u-ks-level2" for ICU locale "@colStrength=secondary" +--domain with check constraints +CREATE DOMAIN d0 as text COLLATE "C" check (value <> 'a'); +CREATE DOMAIN d1 as d0 COLLATE case_insensitive check (value <> 'b'); +CREATE DOMAIN d2 as d0 COLLATE case_insensitive; +SELECT 'A'::d1; --ok + d1 +---- + A +(1 row) + +SELECT 'a'::d1; --error +ERROR: value for domain d1 violates check constraint "d0_check" +SELECT 'B'::d1; --error +ERROR: value for domain d1 violates check constraint "d1_check" +SELECT 'A'::d2; --ok + d2 +---- + A +(1 row) + +DROP DOMAIN d0, d1, d2; SELECT 'abc' <= 'ABC' COLLATE case_sensitive, 'abc' >= 'ABC' COLLATE case_sensitive; ?column? | ?column? ----------+---------- diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql index dbc190227d0..d50f75fb819 100644 --- a/src/test/regress/sql/collate.icu.utf8.sql +++ b/src/test/regress/sql/collate.icu.utf8.sql @@ -561,6 +561,16 @@ SELECT * FROM test6a WHERE b = ARRAY['äbc'] COLLATE ctest_nondet; CREATE COLLATION case_sensitive (provider = icu, locale = ''); CREATE COLLATION case_insensitive (provider = icu, locale = '@colStrength=secondary', deterministic = false); +--domain with check constraints +CREATE DOMAIN d0 as text COLLATE "C" check (value <> 'a'); +CREATE DOMAIN d1 as d0 COLLATE case_insensitive check (value <> 'b'); +CREATE DOMAIN d2 as d0 COLLATE case_insensitive; +SELECT 'A'::d1; --ok +SELECT 'a'::d1; --error +SELECT 'B'::d1; --error +SELECT 'A'::d2; --ok +DROP DOMAIN d0, d1, d2; + SELECT 'abc' <= 'ABC' COLLATE case_sensitive, 'abc' >= 'ABC' COLLATE case_sensitive; SELECT 'abc' <= 'ABC' COLLATE case_insensitive, 'abc' >= 'ABC' COLLATE case_insensitive; -- 2.34.1