Re: Teaching planner to short-circuit empty UNION/EXCEPT/INTERSECT inputs - Mailing list pgsql-hackers

From Richard Guo
Subject Re: Teaching planner to short-circuit empty UNION/EXCEPT/INTERSECT inputs
Date
Msg-id CAMbWs49yA=Z+x8PMWBCyJa5L+AmK+SWV-52Smwxv8U_7=PyVMA@mail.gmail.com
Whole thread Raw
In response to Re: Teaching planner to short-circuit empty UNION/EXCEPT/INTERSECT inputs  (Richard Guo <guofenglinux@gmail.com>)
List pgsql-hackers
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

Attachment

pgsql-hackers by date:

Previous
From: David Rowley
Date:
Subject: Re: Teaching planner to short-circuit empty UNION/EXCEPT/INTERSECT inputs
Next
From: Nishant Sharma
Date:
Subject: Re: [PATCH] Add pg_get_tablespace_ddl() function to reconstruct CREATE TABLESPACE statement