Re: BUG #18830: ExecInitMerge Segfault on MERGE
Tender Wang <tndrwang@gmail.com>
From: Tender Wang <tndrwang@gmail.com>
To: David Rowley <dgrowleyml@gmail.com>
Cc: pgsql-bugs@lists.postgresql.org, Amit Langote <amitlangote09@gmail.com>, tharakan@gmail.com
Date: 2025-03-04T09:45:57Z
Lists: pgsql-bugs
David Rowley <dgrowleyml@gmail.com> 于2025年3月4日周二 17:30写道: > On Tue, 4 Mar 2025 at 19:58, Tender Wang <tndrwang@gmail.com> wrote: > > I found the partition_prune.sql does not cover merge into ... not match > case, and I found an easy reproduce step, seeing below: > > > > postgres=# merge into part_abc_view pt > > using (select stable_one() + 2 as pid) as q join part_abc_1 pt1 on > (true) on pt.a = stable_one() +2 > > when not matched then insert values(1, 'd', false); > > server closed the connection unexpectedly > > This probably means the server terminated abnormally > > before or while processing the request. > > The connection to the server was lost. Attempting reset: Succeeded. > > It looks like this is happening because ExecInitModifyTable() skips > adding mergeActionsList items when bms_is_member(rti, > estate->es_unpruned_relids) is false for all resultRelations. This > results in an empty actions list. Because the MERGE is performing a > LEFT JOIN for the NOT MATCHED, ExecMerge() gets a row and runs > ExecMergeNotMatched(), which crashes on "econtext->ecxt_scantuple = > NULL;" because of a NULL econtext. econtext is NULL because > ExecInitMerge() skips calling ExecAssignExprContext() when > mergeActionLists is empty. > > There are a couple of ways I can see to fix this, 1) would be to move > the ExecAssignExprContext() above the "if (mergeActionLists == NIL)" > in ExecInitMerge(), or 2) add code to return NULL in > ExecMergeNotMatched() if actionStates is NULL. > > I think maybe #1 is the better option as #2 adds additional code that > executes on every ExecMergeNotMatched() call. The patch does #1. We > should probably add your test case too. > > Hmm, apply your patch, I get different results when set enable_partition_pruning = off, seeing below: postgres=# merge into part_abc_view pt using (select stable_one() + 2 as pid) as q join part_abc_1 pt1 on (true) on pt.a = stable_one() +2 when not matched then insert values(1, 'd', false); MERGE 0 postgres=# set enable_partition_pruning = off; SET postgres=# merge into part_abc_view pt using (select stable_one() + 2 as pid) as q join part_abc_1 pt1 on (true) on pt.a = stable_one() +2 when not matched then insert values(1, 'd', false); MERGE 1 if all partitions are pruned, the resultRelation's mergeActions has no chance to be set. -- 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 →
-
Ensure first ModifyTable rel initialized if all are pruned
- 28317de723b6 18.0 landed
-
Don't lock partitions pruned by initial pruning
- 525392d5727f 18.0 cited
-
Fix an oversight in cbc127917 to handle MERGE correctly
- 75dfde13639a 18.0 cited
-
Remove some unnecessary fields from Plan trees.
- 52ed730d511b 12.0 cited