Thread

  1. Re: Teaching planner to short-circuit empty UNION/EXCEPT/INTERSECT inputs

    Richard Guo <guofenglinux@gmail.com> — 2025-11-04T10:02:18Z

    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