Re: Fix bug of CHECK constraint enforceability recursion - Mailing list pgsql-hackers

From Chao Li
Subject Re: Fix bug of CHECK constraint enforceability recursion
Date
Msg-id 92CAD935-5ECE-46D8-B7D7-D8E3C991CC10@gmail.com
Whole thread
In response to Re: Fix bug of CHECK constraint enforceability recursion  (Zsolt Parragi <zsolt.parragi@percona.com>)
Responses Re: Fix bug of CHECK constraint enforceability recursion
List pgsql-hackers

> On Jun 3, 2026, at 22:36, Zsolt Parragi <zsolt.parragi@percona.com> wrote:
>
> Hello
>
> After a bit more testing, I think there's still a remaining issue with
> the latest patch:
>
> create table root_t (a int constraint c check (a > 0) enforced);
> create table p2     (a int constraint c check (a > 0) enforced);
> create table d () inherits (root_t, p2);
> create table e () inherits (d);
> create table f () inherits (e);
> alter table root_t alter constraint c not enforced;
> insert into e values (-5); -- succeeds
>
> d remains enforced as it should, but e and f doesn't.
>
>

Thanks for your testing. Yeah, inheritance cases are really complicated. find_all_inheritors() returns a list of the
rootplus its descendants, but it cannot ensure that a parent always appears before its child. For example: 
```
create table gp(a int constraint c check (a > 0) enforced);
create table d() inherits (gp);
create table p1() inherits (gp);
alter table d inherit p1;
```

In this case, d is a child of both gp and p1. But because d is created before p1, d has a smaller OID than p1. So even
thoughp1 is a parent of d, d can still appear before p1 in the list, like gp -> d -> p1. 

That’s why I built the changing_conids list in the implementation. But I wrongly assumed that all constraints in the
listwould be updated to NOT ENFORCED. Your test case uncovered that this assumption is wrong. So when a parent appears
inchanging_conids, we have to recurse upward to see if there is a parent outside the current ALTER TABLE that may
affectthe result. The fix is in ATCheckCheckConstrHasEnforcedParent(). 

See attached v7 for details. With v7, your test case passes. I have added this test case to the regression tests, and
madeit even more complicated. 
```
evantest=# create table root_t (a int constraint c check (a > 0) enforced);
CREATE TABLE
evantest=# create table p2     (a int constraint c check (a > 0) enforced);
CREATE TABLE
evantest=# create table d () inherits (root_t, p2);
NOTICE:  merging multiple inherited definitions of column "a"
CREATE TABLE
evantest=# create table e () inherits (d);
CREATE TABLE
evantest=# create table f () inherits (e);
CREATE TABLE
evantest=# alter table root_t alter constraint c not enforced;
ALTER TABLE
evantest=#
evantest=# select conrelid::regclass as tbl, conenforced from pg_constraint where  conname = 'c';
  tbl   | conenforced
--------+-------------
 d      | YES
 e      | YES
 f      | YES
 root_t | NO
 p2     | YES
(5 rows)
```
Now, both e and f remain ENFORCE.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/





Attachment

pgsql-hackers by date:

Previous
From: Alexander Nestorov
Date:
Subject: Re: [PATCH] btree_gist: add cross-type integer operator support for GiST
Next
From: "Joel Jacobson"
Date:
Subject: Re: PostgreSQL 19 Beta 1 release announcement draft