From d5e95eb188634453c7e310e5358573c2e674f487 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Fri, 9 Oct 2026 00:04:00 -0400 Subject: [PATCH v2 1/3] Reject enforcing a parent CHECK over a NOT VALID child ALTER CONSTRAINT ... ENFORCED on a parent marked the parent validated, but skipped a child whose constraint was ENFORCED and NOT VALID. Constraint exclusion could then drop the child's bad rows. Raise the same error that ALTER TABLE ... INHERIT raises in this case. --- src/backend/commands/tablecmds.c | 12 ++++++++++++ src/test/regress/expected/inherit.out | 21 +++++++++++++++++++++ src/test/regress/sql/inherit.sql | 14 ++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 93ad49e59fd..a69b21e8f58 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -12727,6 +12727,18 @@ ATExecAlterCheckConstrEnforceability(List **wqueue, ATAlterConstraint *cmdcon, target_enforced = true; } + /* + * The constraint is about to be marked validated, so a descendant that is + * enforced but not yet valid conflicts with it, as in ALTER TABLE ... + * INHERIT. + */ + if (recursing && cmdcon->is_enforced && + currcon->conenforced && !currcon->convalidated) + ereport(ERROR, + errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"", + NameStr(currcon->conname), RelationGetRelationName(rel))); + /* * Update to the merged enforceability if needed. This may differ from the * requested enforceability when another matching parent constraint diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 0136aa53c96..97a8facac4d 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1479,6 +1479,27 @@ NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to table p1_c1 drop cascades to table p1_c2 drop cascades to table p1_c3 +-- ALTER CONSTRAINT ... ENFORCED on a parent cannot mark the parent validated +-- while a child's constraint is enforced but NOT VALID +create table p1(f1 int constraint inh_check_constraint check (f1 > 0) not enforced); +create table p1_c1(f1 int); +alter table p1_c1 add constraint inh_check_constraint check (f1 > 0) not valid; +alter table p1_c1 inherit p1; +alter table p1 alter constraint inh_check_constraint enforced; --error +ERROR: constraint "inh_check_constraint" conflicts with NOT VALID constraint on child table "p1_c1" +alter table p1_c1 validate constraint inh_check_constraint; +alter table p1 alter constraint inh_check_constraint enforced; --ok +select conrelid::regclass, conenforced, convalidated +from pg_constraint where conname = 'inh_check_constraint' +order by conrelid::regclass::text collate "C"; + conrelid | conenforced | convalidated +----------+-------------+-------------- + p1 | t | t + p1_c1 | t | t +(2 rows) + +drop table p1 cascade; +NOTICE: drop cascades to table p1_c1 -- an inherited CHECK constraint cannot be NOT ENFORCED under an ENFORCED parent create table p1(f1 int constraint p1_a_check check (f1 > 0) enforced); create table p1_c1() inherits(p1); diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index 072fca13c13..adbbbe10b9d 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -535,6 +535,20 @@ where conname = 'inh_check_constraint3' and contype = 'c' order by conrelid::regclass::text collate "C"; drop table p1 cascade; +-- ALTER CONSTRAINT ... ENFORCED on a parent cannot mark the parent validated +-- while a child's constraint is enforced but NOT VALID +create table p1(f1 int constraint inh_check_constraint check (f1 > 0) not enforced); +create table p1_c1(f1 int); +alter table p1_c1 add constraint inh_check_constraint check (f1 > 0) not valid; +alter table p1_c1 inherit p1; +alter table p1 alter constraint inh_check_constraint enforced; --error +alter table p1_c1 validate constraint inh_check_constraint; +alter table p1 alter constraint inh_check_constraint enforced; --ok +select conrelid::regclass, conenforced, convalidated +from pg_constraint where conname = 'inh_check_constraint' +order by conrelid::regclass::text collate "C"; +drop table p1 cascade; + -- an inherited CHECK constraint cannot be NOT ENFORCED under an ENFORCED parent create table p1(f1 int constraint p1_a_check check (f1 > 0) enforced); create table p1_c1() inherits(p1); -- 2.37.1 (Apple Git-137.1)