Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wSQXk-003AuF-0d for pgsql-hackers@arkaria.postgresql.org; Thu, 28 May 2026 02:32:20 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wSQXg-00AkFB-1R for pgsql-hackers@arkaria.postgresql.org; Thu, 28 May 2026 02:32:17 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wSQXg-00AkF2-0C for pgsql-hackers@lists.postgresql.org; Thu, 28 May 2026 02:32:17 +0000 Received: from mail-vk1-xa32.google.com ([2607:f8b0:4864:20::a32]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wSQXe-00000001mxQ-0hsE for pgsql-hackers@lists.postgresql.org; Thu, 28 May 2026 02:32:16 +0000 Received: by mail-vk1-xa32.google.com with SMTP id 71dfb90a1353d-575320e6f2aso9923741e0c.0 for ; Wed, 27 May 2026 19:32:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1779935532; cv=none; d=google.com; s=arc-20240605; b=A+67RmisEQujK859QxIf307LtHSAdohT/h53+3QIwPiIa8cNM+XgdTrgj+Mf94CGPK o925gaJrKeStzdI6OJ3dwfDgozqetQBORvkgpUOwf4ZFFAyEJVAKIFMqxfLyXvhD2n6c yyT2gtPddEyDr5WwB5DRzK6St1k5kluoGUkFfZbe5GYed2lNKNV3K8JW/V87ieFU2LuE /lpkDPPstfVeE1bt7QYM9XFGpYdNnr+QshYyJg7GkXN0Iej8adKjSVGGrzlR1R8jPqvF RCTKJ6ZRB/nh3yke1NNCJTXnHHfJkFU3+M6RCEjoq8ZoJv65+ouYFDBCgAzEp1FOAQeD UZbQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=byr9FXTTaj5e3h/FDvYuQr3z/5y3lAx9Z524dKfKxJY=; fh=r57ysL4P5jJvgxsf2MGm0L578+q67dyAUhVDu5aK7hk=; b=Bi0wUcb+pJyijF4iPa3AYcb6cFy6LlIb7TTposxIN7rTCzroZXls/vuXQ2lvEfkWmu LTIncJkb8r8Iil0u/2/NLYjqZNM9IGECxnM2+0zn4ClDLpT8AyWGftaz25/+wtJoeLZc ODLbDt9lX7UFoubCs7reiLkKTb4E6jf4dXmDq+zAemUNRkcaClRzMSoqVcPTKHOUY98m GsaRg288WmneVz57L8PSVsD7bppUz/+BQTh+uaX7XJj+HECCDkNAoneQwclGFOk34hr/ xaF9qtmKJxXN4VdaMvE8D5UrAuR1Xpm3ojRlViI2wXNvIjCQNG8bP7GSo+rO4fBniat5 RHKw==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779935532; x=1780540332; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=byr9FXTTaj5e3h/FDvYuQr3z/5y3lAx9Z524dKfKxJY=; b=bWhRJ55htbgXivsy4z2qATTjdFVphQvhknKdIPzh6bn7hKZE6f+OSDsDJ7yZrrIgw0 qiepteDiihv8zYgh0N2ECcQOcMna46MX+BeGRBI/OjTU5iPc3SOlBinj7a/1jxzqfgyr V1MO4Apwqip/9jagQr2re4FN0RUwvG4rIPOZCsX7rN2vktAX39sWTlAkcfnEyl7y0MVD ME6KTkv5vAafbtV5Nd9tpKNfyebkUbVGDQlBGKK3j5f/ptEX9vWoRxI1gFVEBfEoRU65 fg9G4hic3dJpHzO6Hfm3A0uTecsxFsp/BXSF8FH003k0ClYesjuIlArGgYq4DuIXAyV3 CWjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779935532; x=1780540332; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=byr9FXTTaj5e3h/FDvYuQr3z/5y3lAx9Z524dKfKxJY=; b=Z/iDmnoj2xeyeODc+Ef7U2s6iZFshkP4rDzIjQoOHSbVLG26AjfR8HwgUmSUOhzBBk xCml98VPVJB7qqbVnbcOZVstm169nLCs7CgGmciSKOCl+y146eoEbj8+mcxiXjvgEWDg 6lcvb2p9MGQZfRwqb+franqiFtfiqnhxcprR/8Pbpb6NXwsRvCU8vAfFDHURz5afI4lo crhW6GGc0SwolBqNMaKVevVMdF5HAykx0OWrdFWTlU4ledfe+BBN8sJJmoJzz565biuZ e7GPSaL1PazKxaMUe2tp+dh703W7CluKEmI3OWgNu6ae3BQqRJIKbRensgpqc3UfC9WU c76g== X-Forwarded-Encrypted: i=1; AFNElJ+PvysN2N/seU0lv1C8x9tStLVpezsr5ImKItbhZPe5zI4Oh4jVqm3/VDR0Nyg3LrS56yCp4p9FXyMneC1z@lists.postgresql.org X-Gm-Message-State: AOJu0YyE/xJC6RUxVjImbjh8+HDFQHWLCDFmpHWH7dJ6r9rPueequAl5 QmUZImN9CsDJrLREB25H9GIUnG825K/1NFgarRHZytupaL3lgzHDiay3qN49jNzXsGPhVs/m5YH BUoZaSqW7ixX9NKlr5kELSHy2hX0P3BI= X-Gm-Gg: Acq92OHVJR800GMcjyb3fLalNSeksW8FngGVAJG7HpOfzAEbd/SUcDr+/PzSYWODAa+ kOl+KgxCxEOYzsZFun0W/maPucQqFUP289jG+xDu0BNsTaYkf0MjVUogvRibJF/xYsGBTthuEgP gaoc5LTOlloADyiePLUbklj+83ad9TnSfEMGx5yM/cGJMPUhRGDeYYmfHdkbtEylwMlCwa6dakq Tc5k6BoItli8Hxmu4FETPV9Y6NuRdisoBX9SuZHrG/64DOMrXo2Oi778FlozPL2et3+b2FJv0KG hHv/C+qAFXu1h5XUClnaYHDZoMgeBRmvAZUQfDNar2cajfi2fowMkLOET7zfJYDyY4NdG4/+cSD s4Pv/Gqr80zI6vgLXw8s4TmcJKHr/UAukBUcqcP445mtHq63rtdD5OIEBXwKjEZ06RP+vzzFe8J T3gW8t+CSLz9cs5Cjomlhu0zJndLBqGUM= X-Received: by 2002:a05:6122:c93:b0:56b:579c:82e with SMTP id 71dfb90a1353d-586606b79a4mr13880033e0c.5.1779935532063; Wed, 27 May 2026 19:32:12 -0700 (PDT) MIME-Version: 1.0 References: <33E9C4C2-B6A8-4FCC-BEEA-461EA5FB98C8@gmail.com> <7F0EA98A-6DBC-436A-8FF4-4A511A05ABE6@gmail.com> In-Reply-To: <7F0EA98A-6DBC-436A-8FF4-4A511A05ABE6@gmail.com> From: jian he Date: Thu, 28 May 2026 10:31:35 +0800 X-Gm-Features: AVHnY4L_ZHebtXyIYG1zJvSlf-foNG8iZUBNueqBnLHT_-YIeTeQwPqQ0x9JNAw Message-ID: Subject: Re: Fix bug of CHECK constraint enforceability recursion To: Chao Li Cc: =?UTF-8?Q?=C3=81lvaro_Herrera?= , "L. pgsql-hackers" , Andrew Dunstan Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Wed, May 27, 2026 at 2:20=E2=80=AFPM Chao Li wr= ote: > > 4. It cannot handle some complicated inheritance hierarchies. For example= , the following test passes with your v1: > ``` > evantest=3D# CREATE TABLE p1 (a int CONSTRAINT c CHECK (a > 0) ENFORCED); > CREATE TABLE > evantest=3D# CREATE TABLE p2 (a int CONSTRAINT c CHECK (a > 0) ENFORCED); > CREATE TABLE > evantest=3D# > evantest=3D# CREATE TABLE ch () INHERITS (p1, p2); > NOTICE: merging multiple inherited definitions of column "a" > CREATE TABLE > evantest=3D# ALTER TABLE p1 ALTER CONSTRAINT c NOT ENFORCED; > ALTER TABLE > ``` > > I originally thought this should fail, but it now changes ch.c to NOT ENF= ORCED, so it breaks the rule because its parent p2 is still ENFORCED: > ``` > evantest=3D# SELECT conrelid::regclass, conname, conenforced, coninhcount= , conislocal > evantest-# FROM pg_constraint WHERE conname =3D 'c'; > conrelid | conname | conenforced | coninhcount | conislocal > ----------+---------+-------------+-------------+------------ > p1 | c | f | 0 | t > p2 | c | t | 0 | t > ch | c | f | 2 | f > (3 rows) > ``` > > Then I realized that the initial CREATE TABLE case passes: > ``` > evantest=3D# CREATE TABLE p1 (a int CONSTRAINT c CHECK (a > 0) NOT ENFORC= ED); > CREATE TABLE > evantest=3D# CREATE TABLE p2 (a int CONSTRAINT c CHECK (a > 0) ENFORCED); > CREATE TABLE > evantest=3D# CREATE TABLE ch () INHERITS (p1, p2); > NOTICE: merging multiple inherited definitions of column "a" > CREATE TABLE > evantest=3D# SELECT conrelid::regclass, conname, conenforced, coninhcount= , conislocal > evantest-# FROM pg_constraint WHERE conname =3D =E2=80=98c'; > conrelid | conname | conenforced | coninhcount | conislocal > ----------+---------+-------------+-------------+------------ > ch | c | t | 2 | f > p1 | c | f | 0 | t > p2 | c | t | 0 | t > (3 rows) > ``` > > When the two parents have different enforceability, the stricter one is a= pplied to the child. So I think the test above in item 4 should also perfor= m similar merge logic rather than fail. This seems to uncover a new issue i= n the original feature patch. > > For the fix, my design is: > > * Directly reject changing an inherited child CHECK constraint to NOT ENF= ORCED if an equivalent parent constraint remains ENFORCED. > * Changing a child to ENFORCED is allowed. > * During recursing, if a child also inherits an equivalent ENFORCED const= raint from another parent outside the current ALTER, the child keeps the st= ricter ENFORCED state. > > Please see my implementation in the attached v2 patch. CREATE TABLE p1 (a int CONSTRAINT c CHECK (a > 0) ENFORCED); CREATE TABLE p2 (a int CONSTRAINT c CHECK (a > 0) ENFORCED); CREATE TABLE ch () INHERITS (p1, p2); ALTER TABLE p1 ALTER CONSTRAINT c NOT ENFORCED; The v2 patch marks check constraint c on table ch as ENFORCED, which seems to contradict the documentation's wording: https://www.postgresql.org/docs/devel/ddl-inherit.html <<>> ALTER TABLE will propagate any changes in column data definitions and check constraints down the inheritance hierarchy. Again, dropping columns that ar= e depended on by other tables is only possible when using the CASCADE option. ALTER TABLE follows the same rules for duplicate column merging and rejecti= on that apply during CREATE TABLE <<>> The wording (https://www.postgresql.org/docs/devel/ddl-inherit.html) below also discourages directly altering check constraints on child tables. <<>> A parent table cannot be dropped while any of its children remain. Neither = can columns or check constraints of child tables be dropped or altered if they = are inherited from any parent tables. If you wish to remove a table and all of = its descendants, one easy way is to drop the parent table with the CASCADE opti= on (see Section 5.17). <<>> -- jian https://www.enterprisedb.com/