Hi Andrey-san,
Thanks for the revision. The patch looks good except for the following two items. (18) + if (target_resultRelInfo->ri_FdwRoutine != NULL) + { + if (target_resultRelInfo->ri_usesMultiInsert) + { + Assert(target_resultRelInfo->ri_FdwRoutine->BeginForeignCopy != NULL); + target_resultRelInfo->ri_FdwRoutine->BeginForeignCopy(mtstate, + resultRelInfo); + } > > (14) > > @@ -1205,10 +1209,18 @@ ExecCleanupTupleRouting(ModifyTableState > *mtstate, > > ResultRelInfo *resultRelInfo = proute->partitions[i]; > > > > /* Allow any FDWs to shut down */ > > - if (resultRelInfo->ri_FdwRoutine != NULL && > > - resultRelInfo->ri_FdwRoutine->EndForeignInsert != > NULL) > > - > resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state, > > - > resultRelInfo); > > + if (resultRelInfo->ri_FdwRoutine != NULL) > > + { > > + if (resultRelInfo->ri_usesMultiInsert) > > + { > > + > Assert(resultRelInfo->ri_FdwRoutine->EndForeignCopy != NULL); > > + > resultRelInfo->ri_FdwRoutine->EndForeignCopy(mtstate->ps.state, > > + > resultRelInfo); > > + } > > + else if > (resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL) > > + > resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state, > > + > resultRelInfo); > > + } > > > > EndForeignCopy() is an optional function, isn't it? That is, it's called > > if it's > defined. > > > ri_usesMultiInsert must guarantee that we will use multi-insertions. And we > use only assertions to control this. The code appears to require both BeginForeignCopy and EndForeignCopy, while the following documentation says they are optional. Which is correct? (I suppose the latter is correct just like other existing Begin/End functions are optional.) + If the <function>BeginForeignCopy</function> pointer is set to + <literal>NULL</literal>, no action is taken for the initialization. + If the <function>EndForeignCopy</function> pointer is set to + <literal>NULL</literal>, no action is taken for the termination. > > (2) > > + Assert(rri->ri_usesMultiInsert == false); > > > > As the above assertion represents, I'm afraid the semantics of > ExecRelationAllowsMultiInsert() and ResultRelInfo->ri_usesMultiInsert are > unclear. In CopyFrom(), ri_usesMultiInsert is set by also considering the > COPY-specific conditions: > > > > + if (!cstate->volatile_defexprs && > > + !contain_volatile_functions(cstate->whereClause) && > > + ExecRelationAllowsMultiInsert(target_resultRelInfo, NULL)) > > + target_resultRelInfo->ri_usesMultiInsert = true; > > > > On the other hand, in below ExecInitPartitionInfo(), ri_usesMultiInsert is > > set > purely based on the relation's characteristics. > > > > + leaf_part_rri->ri_usesMultiInsert = > > + ExecRelationAllowsMultiInsert(leaf_part_rri, > rootResultRelInfo); > > > > In addition to these differences, I think it's a bit confusing that the > > function > itself doesn't record the check result in ri_usesMultiInsert. > > > > It's probably easy to understand to not add ri_usesMultiInsert, and the > function just encapsulates the check logic based solely on the relation > characteristics and returns the result. So, the argument is just one > ResultRelInfo. The caller (e.g. COPY) combines the function result with other > specific conditions. > I can't fully agreed with this suggestion. We do so because in the future > anyone > can call this code from another subsystem for another purposes. And we want > all the relation-related restrictions contains in one routine. > CopyState-related > restrictions used in copy.c only and taken out of this function. I'm sorry if I'm misinterpreting you, but I think the following simply serves its role sufficiently and cleanly without using ri_usesMultiInsert. bool ExecRelationAllowsMultiInsert(RelationRelInfo *rri) { check if the relation allows multiinsert based on its characteristics; return true or false; } I'm concerned that if one subsystem sets ri_usesMultiInsert to true based on its additional specific conditions, it might lead to another subsystem's misjudgment. For example, when subsystem A and B want to do different things respectively: [Subsystem A] if (ExecRelationAllowsMultiInsert(rri) && {A's conditions}) rri->ri_usesMultiInsert = true; ... if (rri->ri_usesMultiInsert) do A's business; [Subsystem B] if (rri->ri_usesMultiInsert) do B's business; Here, what if subsystem A and B don't want each other's specific conditions to hold true? That is, A wants to do A's business only if B's specific conditions don't hold true. If A sets rri->ri_usesMultiInsert to true and passes rri to B, then B wrongly does B's business despite that A's specific conditions are true. (I think this is due to some form of violation of encapsulation.) Regards Takayuki Tsunakawa