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:

Reply via email to