Re: BUG #18830: ExecInitMerge Segfault on MERGE

Tender Wang <tndrwang@gmail.com>

From: Tender Wang <tndrwang@gmail.com>
To: Dean Rasheed <dean.a.rasheed@gmail.com>
Cc: Amit Langote <amitlangote09@gmail.com>, David Rowley <dgrowleyml@gmail.com>, pgsql-bugs@lists.postgresql.org, tharakan@gmail.com
Date: 2025-03-12T16:11:24Z
Lists: pgsql-bugs
Dean Rasheed <dean.a.rasheed@gmail.com> 于2025年3月12日周三 22:59写道:

> On Wed, 12 Mar 2025 at 12:24, Amit Langote <amitlangote09@gmail.com>
> wrote:
> >
> > Thanks -- I’ve studied the code and I agree with the conclusion: when
> > all result relations are pruned, we still need to lock and process the
> > first one to preserve executor invariants.
> >
> > Your examples with ExecMerge() and ExecInitPartitionInfo() make the
> > consequences of missing resultRelInfo[0] pretty clear. Locking and
> > including the first result relation, even if pruned, seems like the
> > most straightforward way to maintain correctness without deeper
> > structural changes.
> >
> > I've come up with the attached. I'll still need to add a test case.
>
> Hmm, this isn't quite sufficient.
>
> In ExecDoInitialPruning(), stmt->resultRelations contains all the
> result relations plus the root relation (if set) of each ModifyTable
> node in the planned stmt (see set_plan_refs()). Therefore, just adding
> the first result relation in that list may not be sufficient to ensure
> that every ModifyTable node ends up with at least one unpruned result
> relation.
>
> For example, consider:
>
> create table foo (a int);
> create table part_abc (a int, b text, c bool) partition by list (a);
> create table part_abc_1 (b text, c bool, a int);
> create table part_abc_2 (b text, a int, c bool);
> alter table part_abc attach partition part_abc_1 for values in (1);
> alter table part_abc attach partition part_abc_2 for values in (2);
> insert into part_abc_1 values ('b', true, 1);
> insert into part_abc_2 values ('c', 2, true);
> create function stable_one() returns int as
>   $$ begin return 1; end; $$ language plpgsql stable;
>
> with t as (
>   merge into part_abc pt using (values(1)) v(a) on pt.a = stable_one() + 2
>     when not matched then insert values (v.a, 'd', false)
>     returning pt.*
> )
> insert into foo select a from t;
>
> ERROR:  trying to open a pruned relation
>

Nice catch.   The above case can be another test case.

 I can find another same error in the below query:

with t as (update part_abc set c = true  where a = stable_one() +2
returning a) insert into foo select a from t;

-- 
Thanks,
Tender Wang

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Ensure first ModifyTable rel initialized if all are pruned

  2. Don't lock partitions pruned by initial pruning

  3. Fix an oversight in cbc127917 to handle MERGE correctly

  4. Remove some unnecessary fields from Plan trees.