| From: | PG Bug reporting form <noreply(at)postgresql(dot)org> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | 303677365(at)qq(dot)com |
| Subject: | BUG #19807: CHECK constraint not enforced on partitioned table when partition overrides a virtual generated colu |
| Date: | 2026-10-29 06:17:19 |
| Message-ID: | 19807-9d1d34b611597835@postgresql.org |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
The following bug has been logged on the website:
Bug reference: 19807
Logged by: chunling qin
Email address: 303677365(at)qq(dot)com
PostgreSQL version: 18.6
Operating system: Linux x86_64
Description:
A CHECK constraint declared on a partitioned table is enforced at INSERT
time using the *partition's* version of a virtual generated column when the
partition overrides that column's expression with WITH OPTIONS. Queries
through the parent table, however, evaluate the column with the parent's
expression. As a result, a row that violates the parent's CHECK constraint
is accepted on INSERT and remains visible through the parent.
Test case (self-contained):
CREATE TABLE gp (f2 int,
f3 int GENERATED ALWAYS AS (f2 * 2) VIRTUAL,
CONSTRAINT gp_ck CHECK (f3 > 30))
PARTITION BY RANGE (f2);
CREATE TABLE gp1 PARTITION OF gp FOR VALUES FROM (0) TO (8);
CREATE TABLE gp2 PARTITION OF gp
(f3 WITH OPTIONS GENERATED ALWAYS AS (f2 * 22) VIRTUAL)
FOR VALUES FROM (8) TO (100);
INSERT INTO gp (f2) VALUES (10); -- accepted
Result on 18.6 (official docker image postgres:latest):
SELECT f2, f3 FROM gp; -> (10, 20) parent evaluates f3
= f2*2
SELECT f2, f3 FROM gp WHERE NOT (f3 > 30); -> (10, 20) a row visible
through the parent violates the parent's own CHECK
SELECT f2, f3 FROM gp2; -> (10, 220) the partition
evaluated f3 = f2*22
Baselines - the same constraint rejects the same INSERT as soon as no
expression override is involved:
(1) plain table, same CHECK:
ERROR: new row for relation "plain_t" violates check constraint "plain_ck"
(2) partitioned table without the WITH OPTIONS override:
ERROR: new row for relation "gb2" violates check constraint "gb_ck"
(3) partitioned table with the override: INSERT 0 1
Expected: the INSERT should be rejected, as in both baselines - or the
combination of a parent CHECK referencing a generated column together with a
partition expression override should be rejected at DDL time. A CHECK
constraint defined on the parent must hold for every row visible through the
parent.
Mechanism: constraint checking runs on the leaf partition using the leaf's
generated expression (f2*22 = 220 > 30 passes), while reads through the
parent compute the column with the parent's expression (f2*2 = 20). The two
evaluations disagree, so the constraint the user declared is never applied
to the value the user sees.
Related, same parent/leaf evaluation mismatch: a row-level trigger declared
on the parent with WHEN (OLD.f3 > 30) also fires based on the leaf
expression, i.e. for rows whose parent-visible value is 20.
Notes:
- The WITH OPTIONS clause is the documented syntax for overriding a
generated column's expression in a partition, so this combination is
reachable by ordinary DDL.
| From | Date | Subject | |
|---|---|---|---|
| Next Message | PG Bug reporting form | 2026-10-29 06:20:55 | BUG #19808: NOT NULL NO INHERIT copied by CREATE TABLE (LIKE) not enforced on partitioned table |
| Previous Message | PG Bug reporting form | 2026-10-29 06:14:36 | BUG #19806: Wrong results: HAVING pushed into WHERE for GROUP BY on composite column (nondeterministic field) |