Tender Wang <tndrw...@gmail.com> 于2025年5月25日周日 19:17写道:
> > > Álvaro Herrera <alvhe...@alvh.no-ip.org> 于2025年5月24日周六 17:11写道: > >> On 2025-May-21, Andres Freund wrote: >> >> > Hi, >> > >> > In [1] I added some verification to projection building, to check if the >> > tupleslot passed to ExecBuildProjectionInfo() is compatible with the >> target >> > list. One query in merge.sql [2] got flagged. >> > >> > Trying to debug that issue, I found another problem. This leaves us >> with: >> > >> > 1) w/ inheritance INSERTed rows are not returned by RETURNING. This >> seems to >> > just generally not work with MERGE >> >> Hmm, curious. One thing to observe is that the original source tuple is >> in the child table, but the tuple inserted by MERGE ends up in the >> parent table. I'm guessing that the code gets confused as to the >> relation that the tuple in the returned slot comes from, and that >> somehow makes it somehow not "see" the tuple to process for RETURNING? >> I dunno. CC'ing Dean, who is more familiar with this code than I am. >> > > In ExecMergeNotMatched(), we passed the mtstate->rootResultRelInfo to > ExecInsert(). > In this case, the ri_projectReturning of mtstate->rootResultRelInfo is > NULL, in ExecInsert(), > the "if (resultRelInfo->ri_projectReturning)" branch will not run, so > inheritance INSERTed rows are not returned by RETURNING. > > The mtstate->rootResultRelInfo assigned in ExecInitModifyTable() is only > here: > if (node->rootRelation > 0) > { > Assert(bms_is_member(node->rootRelation, estate->es_unpruned_relids)); > mtstate->rootResultRelInfo = makeNode(ResultRelInfo); > ExecInitResultRelation(estate, mtstate->rootResultRelInfo, > node->rootRelation); > } > The ri_projectReturning is not assigned. > > I try to pass resultRelInfo to ExecInsert, the inherited INSERTed rows are > returned by RETURNING. > But some test cases in regression failed. > For a partitioned table, we must pass rootResultRelInfo to ExecInsert(). I added the check before calling ExecInsert() If it is a partitioned table, we continue to pass rootResultRelInfo. Otherwise, we pass resultRelInfo. Please see the attached diff file. The patch passed all regression test cases. -- Thanks, Tender Wang
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 2bc89bf84dc..443d4523789 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -3612,6 +3612,7 @@ ExecMergeNotMatched(ModifyTableContext *context, ResultRelInfo *resultRelInfo, MergeActionState *action = (MergeActionState *) lfirst(l); CmdType commandType = action->mas_action->commandType; TupleTableSlot *newslot; + char relkind; /* * Test condition, if any. @@ -3635,9 +3636,15 @@ ExecMergeNotMatched(ModifyTableContext *context, ResultRelInfo *resultRelInfo, */ newslot = ExecProject(action->mas_proj); mtstate->mt_merge_action = action; + relkind = mtstate->rootResultRelInfo->ri_RelationDesc->rd_rel->relkind; - rslot = ExecInsert(context, mtstate->rootResultRelInfo, + if (relkind == RELKIND_PARTITIONED_TABLE) + rslot = ExecInsert(context, mtstate->rootResultRelInfo, newslot, canSetTag, NULL, NULL); + else + rslot = ExecInsert(context, resultRelInfo, + newslot, canSetTag, NULL, NULL); + mtstate->mt_merge_inserted += 1; break; case CMD_NOTHING: