Re: Teaching planner to short-circuit empty UNION/EXCEPT/INTERSECT inputs
Richard Guo <guofenglinux@gmail.com>
From: Richard Guo <guofenglinux@gmail.com>
To: Alexander Lakhin <exclusion@gmail.com>
Cc: David Rowley <dgrowleyml@gmail.com>, Tom Lane <tgl@sss.pgh.pa.us>, PostgreSQL Developers <pgsql-hackers@lists.postgresql.org>
Date: 2025-11-04T10:02:18Z
Lists: pgsql-hackers
Attachments
- v1-0001-Fix-generate_union_paths.patch (application/octet-stream)
On Tue, Nov 4, 2025 at 6:19 PM Richard Guo <guofenglinux@gmail.com> wrote: > On Tue, Nov 4, 2025 at 5:00 PM Alexander Lakhin <exclusion@gmail.com> wrote: > > Please look at a new anomaly, introduced with 03d40e4b5: > > CREATE TABLE t(i integer); > > CREATE TABLE pt(i integer) PARTITION BY LIST(i); > > > > SET enable_seqscan = 'off'; > > SELECT * FROM t UNION SELECT * FROM t > > UNION ALL > > SELECT * FROM pt; > > produces: > > ERROR: XX000: unrecognized node type: 0 > > LOCATION: create_plan_recurse, createplan.c:538 > > I looked into this. The child relation with relid 3 (the scan on the > partitioned table) is a dummy, so it is skipped in > generate_union_paths(). As a result, the final setop relation ends up > the same as the child relation with relid set to (1, 2). Then, > generate_union_paths() creates an Append path using this relation's > cheapest path as its subpath. Somehow, add_path() determines that > this new Append path dominates the original cheapest path, causing the > original cheapest path to be freed. This leads to the final Append > path referencing a subpath that has already been freed. I think a quick fix is to always include the involved child relids when building the relid set for the setop relation, even if the child is dummy. A dummy child does not yield any rows, but theoretically it is still a relation that we should account for. - Richard