On Mon, May 26, 2025 at 4:11 AM Dean Rasheed <dean.a.rash...@gmail.com> wrote:
>
> On Sun, 25 May 2025 at 13:41, Dean Rasheed <dean.a.rash...@gmail.com> wrote:
> >
>
> 2. ExecInitModifyTable() does not initialize the WCO lists or
> RETURNING list for rootResultRelInfo, so those never get executed.
>
> As it happens, it is possible to construct cases where (1) causes a
> crash, even without WCO's or a RETURNING list (see the first test case
> in the attached patch), so this bug goes all the way back to v15,
> where MERGE was introduced.
>
> So I think we need to do something like the attached.
>
> There is perhaps scope to reduce the code duplication between this and
> ExecInitPartitionInfo(), but that'd likely make the patch bigger, so I
> think it's best to leave that for now.

+ Relation rootRelation = rootRelInfo->ri_RelationDesc;
+ Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
+ int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;

firstResultRel may equal (==) to rootRelation,
in that case, we don't need to call map_variable_attnos?

we can
        returningList = linitial(node->returningLists);
        if (rel != firstResultRel)
        {
            /* Convert any Vars in it to contain the root's attno's */
            part_attmap =
                build_attrmap_by_name(RelationGetDescr(rel),
                                      RelationGetDescr(firstResultRel),
                                      false);
            returningList = (List *)
                map_variable_attnos((Node *) returningList,
                                    firstVarno, 0,
                                    part_attmap,
                                    RelationGetForm(rel)->reltype,
                                    &found_whole_row);
        }
(i am not sure that will make code less readable).


we can unconditionally call ExecBuildProjectionInfo for rootRelInfo
within ExecInitModifyTable instead of in ExecInitMerge.
right after

        /*
         * Build a projection for each result rel.
         */
        resultRelInfo = mtstate->resultRelInfo;
        foreach(l, returningLists)
        {
            List       *rlist = (List *) lfirst(l);
            resultRelInfo->ri_returningList = rlist;
            resultRelInfo->ri_projectReturning =
                ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
                                        resultRelInfo->ri_RelationDesc->rd_att);
            resultRelInfo++;
        }

This would make related initiation logic stay together, also harmless (i think).
what do you think?


Reply via email to