Re: BUG #18830: ExecInitMerge Segfault on MERGE
Tender Wang <tndrwang@gmail.com>
From: Tender Wang <tndrwang@gmail.com>
To: pgsql-bugs@lists.postgresql.org, Amit Langote <amitlangote09@gmail.com>
Cc: tharakan@gmail.com
Date: 2025-03-04T06:58:01Z
Lists: pgsql-bugs
Tender Wang <tndrwang@gmail.com> 于2025年3月3日周一 23:46写道:
>
> Thanks for reporting.
> I can reproduce this crash. On HEAD 3f1db99bfa, crash on a different
> place due to the commit 75dfde1.
> But cbc127917e is the root cause commit.
>
> MERGE INTO e USING h ON a = xmlserialize WHEN NOT MATCHED THEN INSERT
> VALUES (CAST(NULL AS text));
> The plan of the above query looks as below:
> QUERY PLAN
> ------------------------------------------------------------------
> Merge on e (cost=0.00..58.29 rows=0 width=0)
> -> Nested Loop Left Join (cost=0.00..58.29 rows=12 width=10)
> -> Result (cost=0.00..0.01 rows=1 width=0)
> -> Append (cost=0.00..58.16 rows=12 width=10)
> Subplans Removed: 2
>
> You can see that all partitions are pruned. After cbc127917e, we only
> consider unpruned relations, then the list resultRelations is empty.
> the estate->es_unpruned_relids contains (1,2), the node->resultRelations
> contains (5,6).
>
> nrels = list_length(resultRelations);
> ...
> mtstate->resultRelInfo = (ResultRelInfo *)
> palloc(nrels * sizeof(ResultRelInfo));
>
> The memory of mtstate->resultRelInfo point to is undefined. When we access
> its memory in ExecInitMerge(),
>
> relationDesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
>
> crash happened.
>
> After 75dfde1, mergeActionLists list is empty, so in ExecInitMerge() we
> don't enter the foreach(lc, mergeActionLists),
> and the mtstate->ps.ps_ExprContext has no chance to initialize. So
> in ExecMergeNotMatched(), econtext is NULL.
> econtext->ecxt_scantuple = NULL;
> The above statement can trigger a segment fault.
>
> For Merge command NOT MATCH, should we need the logic that only consider
> unpruned relations in ExecInitModifyTable()?
>
> Merge command seems more complex than update and delete. Can we consider
> the unpruned relations in ExecInitModifyTable()
> according to the command type. For merge, we do the logic before
> cbc127917e, for now?
>
>
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.
--
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