| From: | BHUVAN CHILUKUTI <c(dot)bhuvan(at)iitg(dot)ac(dot)in> |
|---|---|
| To: | "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org> |
| Subject: | Assertion failure in dependencies_clauselist_selectivity with two clauses on the same statistics expression |
| Date: | 2026-10-27 19:32:31 |
| Message-ID: | PN0P287MB0903563C70D8E5B81912E855A7602@PN0P287MB0903.INDP287.PROD.OUTLOOK.COM |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
PostgreSQL version: 18.6 (built --enable-cassert); also master 126976a8
Operating system: Ubuntu 24.04, x86_64
With functional-dependency statistics on an expression, a WHERE clause
containing two different clauses that reference the same expression crashes
an assert-enabled server during planning:
CREATE TABLE dt (a int, b int);
INSERT INTO dt SELECT x % 10, x % 10 FROM generate_series(1, 1000) x;
CREATE STATISTICS dt_deps (dependencies) ON a, (b + 1) FROM dt;
ANALYZE dt;
EXPLAIN SELECT * FROM dt WHERE a = 1 AND (b + 1) = 2 AND (b + 1) IN (2, 3);
TRAP: failed Assert("AttrNumberIsForUserDefinedAttr(list_attnums[i]) ||
!bms_is_member(attnum, clauses_attnums)"),
File: "dependencies.c", Line: 1504
The same crash happens with two identical BooleanTest clauses and statistics
on an expression such as (c IS TRUE):
CREATE TABLE dt2 (a int, c bool);
INSERT INTO dt2 SELECT x % 10, x % 10 < 5 FROM generate_series(1, 1000) x;
CREATE STATISTICS dt2_deps (dependencies) ON a, (c IS TRUE) FROM dt2;
ANALYZE dt2;
EXPLAIN SELECT * FROM dt2 WHERE a = 1 AND (c IS TRUE) AND (c IS TRUE);
The columns must be correlated so that ANALYZE stores at least one
dependency. A release (non-assert) build plans the query normally (no wrong
result, no crash), so this is assertion-only.
Root cause: dependencies_clauselist_selectivity() deliberately assigns a
duplicate expression the same (negative) attnum as its first occurrence
("If the expression is duplicate, use the same attnum"), and
clauselist_apply_dependencies() explicitly collects all clauses with the
same attnum and estimates them together. The assertion a few lines later,
which claims "expressions are unique", contradicts both -- it holds for
unique_exprs[], not for the clause list. Plain columns are exempted by the
AttrNumberIsForUserDefinedAttr() half of the assertion, which is why only
the expression branch fires.
Fix: the attached patch removes the incorrect assertion (nothing downstream
relies on it), documents that several clauses may share an attnum, and adds
a regression test to stats_ext.sql. Patched master: make check and
installcheck-parallel pass 239/239; without the patch the new test crashes
the assert-enabled server.
Versions: master 126976a8 and 18.6 (both cassert) crash 3/3 on fresh
databases. The code was added in PostgreSQL 14 by commit a4d75c86bf
("Extended statistics on expressions"), so 14-17 are expected to be affected
as well.
Regards,
Bhuvan Chilukuti
| Attachment | Content-Type | Size |
|---|---|---|
| C-01-dependencies-duplicate-expression-assert.patch | application/octet-stream | 3.0 KB |
| C-01-dependencies-duplicate-expression-assert.sql | application/octet-stream | 856 bytes |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Manu | 2026-10-27 20:03:26 | Re: BUG #19760: CLUSTER loses a row the transaction inserted and then updated in a rolled-back subtransaction |
| Previous Message | Chris St Denis | 2026-10-27 19:04:55 | Re: crash in ltree_compare_distance() in 14.24 |