On Wed, Jan 19, 2022 at 4:13 PM Amit Langote <amitlangot...@gmail.com> wrote:
> On Wed, Jan 19, 2022 at 7:29 AM Alvaro Herrera <alvhe...@alvh.no-ip.org> 
> wrote:
> > On 2022-Jan-18, Alvaro Herrera wrote:
> > > On 2022-Jan-18, Amit Langote wrote:
> > >
> > > > Would you like me to update the patch with the above renumbering or
> > > > are you working on a new version yourself?
> > >
> > > I have a few very minor changes apart from that.  Let me see if I can
> > > get this pushed soon; if I'm unable to (there are parts I don't fully
> > > grok yet), I'll post what I have.
> >
> > Here's v13, a series with your patch as 0001 and a few changes from me;
> > the bulk is just pgindent, and there are a few stylistic changes and an
> > unrelated typo fix and I added a couple of comments to your new code.
>
> Thank you.
>
> > I don't like the API change to ExecInsert().  You're adding two output
> > arguments:
> > - the tuple being inserted.  But surely you have this already, because
> > it's in the 'slot' argument you passed in. ExecInsert is even careful to
> > set the ->tts_tableOid argument there.  So ExecInsert's caller doesn't
> > need to receive the inserted tuple as an argument, it can just read
> > 'slot'.
>
> Hmm, ExecInsert()'s input slot belongs to either the source partition
> or the "root" target relation, the latter due to the following stanza
> in ExecCrossPartitionUpdate():
>
>     /*
>      * resultRelInfo is one of the per-relation resultRelInfos.  So we should
>      * convert the tuple into root's tuple descriptor if needed, since
>      * ExecInsert() starts the search from root.
>      */
>     tupconv_map = ExecGetChildToRootMap(resultRelInfo);
>     if (tupconv_map != NULL)
>         slot = execute_attr_map_slot(tupconv_map->attrMap,
>                                      slot,
>                                      mtstate->mt_root_tuple_slot);
>
> Though the slot whose tuple ExecInsert() ultimately inserts may be
> destination partition's ri_PartitionTupleSlot due to the following
> stanza in it:
>
>     /*
>      * If the input result relation is a partitioned table, find the leaf
>      * partition to insert the tuple into.
>      */
>     if (proute)
>     {
>         ResultRelInfo *partRelInfo;
>
>         slot = ExecPrepareTupleRouting(mtstate, estate, proute,
>                                        resultRelInfo, slot,
>                                        &partRelInfo);
>         resultRelInfo = partRelInfo;
>     }
>
> It's not great that ExecInsert()'s existing header comment doesn't
> mention that the slot whose tuple is actually inserted may not be the
> slot it receives from the caller :-(.
>
> > - the relation to which the tuple was inserted.  Can't this be obtained
> > by looking at slot->tts_tableOid?  We should be able to use
> > ExecLookupResultRelByOid() to obtain it, no? (I suppose you may claim
> > that this is wasteful, but I think this is not a common case anyway and
> > it's worth keeping ExecInsert()'s API clean for the sake of the 99.99%
> > of its other calls).
>
> ExecLookupResultRelByOid() is only useful when *all* relevant leaf
> partitions are present in the ModifyTableState.resultRelInfo array
> (due to being present in ModifyTable.resultRelations).  Leaf
> partitions that are only initialized by tuple routing (such as
> destination partitions of cross-partition updates) are only present in
> ModifyTableState.mt_partition_tuple_routing.partitions[] that are not
> discoverable by ExecLookupResultRelByOid().
>
> > I think the argument definition of ExecCrossPartitionUpdateForeignKey is
> > a bit messy.  I propose to move mtstate,estate as two first arguments;
> > IIRC the whole executor does it that way.
>
> Okay, done.
>
> > AfterTriggerSaveEvent determines maybe_crosspart_update (by looking at
> > mtstate->operation -- why doesn't it look at 'event' instead?) and later
> > it determines new_event.ate_flags.  Why can't it use
> > maybe_crosspart_update to simplify part of that?  Or maybe the other way
> > around, not sure.  It looks like something could be made simpler there.
>
> Actually, I remember disliking maybe_crosspart_update for sounding a
> bit fuzzy and also having to add mtstate to a bunch of trigger.c
> interface functions only to calculate that.
>
> I now wonder if passing an is_crosspart_update through
> ExecAR{Update|Delete}Triggers() would not be better.  Both
> ExecDelete() and ExecCrossPartitionUpdateForeignKey() know for sure if
> their ExecAR{Update|Delete}Triggers() invocation is for a
> cross-partition update, so better to just pass that information down
> to AfterTriggerSaveEvent() than pass 'mtstate' and have the latter
> reverse-engineer only a fuzzy guess of whether that's the case.
>
> I like that interface better and have implemented it in the updated version.
>
> I've also merged your changes and made some of my own as mentioned
> above to end up with the attached v14.  I'm also attaching a delta
> patch over v13 (0001+0002) to easily see the changes I made to get
> v14.

Oops, broke the cfbot's patch-applier again.  Delta-diff reattached as txt.

-- 
Amit Langote
EDB: http://www.enterprisedb.com
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index e6aa36a9d8..c2a643e5a8 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -94,15 +94,14 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
                                                                         
FmgrInfo *finfo,
                                                                         
Instrumentation *instr,
                                                                         
MemoryContext per_tuple_context);
-static void AfterTriggerSaveEvent(EState *estate,
-                                                                 
ModifyTableState *mtstate,
-                                                                 ResultRelInfo 
*relinfo,
+static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
                                                                  ResultRelInfo 
*src_partinfo,
                                                                  ResultRelInfo 
*dst_partinfo,
                                                                  int event, 
bool row_trigger,
                                                                  
TupleTableSlot *oldtup, TupleTableSlot *newtup,
                                                                  List 
*recheckIndexes, Bitmapset *modifiedCols,
-                                                                 
TransitionCaptureState *transition_capture);
+                                                                 
TransitionCaptureState *transition_capture,
+                                                                 bool 
is_crosspart_update);
 static void AfterTriggerEnlargeQueryState(void);
 static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType);
 
@@ -2462,10 +2461,10 @@ ExecASInsertTriggers(EState *estate, ResultRelInfo 
*relinfo,
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
        if (trigdesc && trigdesc->trig_insert_after_statement)
-               AfterTriggerSaveEvent(estate, NULL, relinfo,
-                                                         NULL, NULL,
+               AfterTriggerSaveEvent(estate, relinfo, NULL, NULL,
                                                          TRIGGER_EVENT_INSERT,
-                                                         false, NULL, NULL, 
NIL, NULL, transition_capture);
+                                                         false, NULL, NULL, 
NIL, NULL, transition_capture,
+                                                         false);
 }
 
 bool
@@ -2553,12 +2552,12 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo 
*relinfo,
 
        if ((trigdesc && trigdesc->trig_insert_after_row) ||
                (transition_capture && 
transition_capture->tcs_insert_new_table))
-               AfterTriggerSaveEvent(estate, NULL, relinfo,
-                                                         NULL, NULL,
+               AfterTriggerSaveEvent(estate, relinfo, NULL, NULL,
                                                          TRIGGER_EVENT_INSERT,
                                                          true, NULL, slot,
                                                          recheckIndexes, NULL,
-                                                         transition_capture);
+                                                         transition_capture,
+                                                         false);
 }
 
 bool
@@ -2680,10 +2679,10 @@ ExecASDeleteTriggers(EState *estate, ResultRelInfo 
*relinfo,
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
        if (trigdesc && trigdesc->trig_delete_after_statement)
-               AfterTriggerSaveEvent(estate, NULL, relinfo,
-                                                         NULL, NULL,
+               AfterTriggerSaveEvent(estate, relinfo, NULL, NULL,
                                                          TRIGGER_EVENT_DELETE,
-                                                         false, NULL, NULL, 
NIL, NULL, transition_capture);
+                                                         false, NULL, NULL, 
NIL, NULL, transition_capture,
+                                                         false);
 }
 
 /*
@@ -2778,12 +2777,17 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
        return result;
 }
 
+/*
+ * Note: is_crosspart_update must be true if the DELETE is being performed
+ * as part of a cross-partition update.
+ */
 void
-ExecARDeleteTriggers(EState *estate, ModifyTableState *mtstate,
+ExecARDeleteTriggers(EState *estate,
                                         ResultRelInfo *relinfo,
                                         ItemPointer tupleid,
                                         HeapTuple fdw_trigtuple,
-                                        TransitionCaptureState 
*transition_capture)
+                                        TransitionCaptureState 
*transition_capture,
+                                        bool is_crosspart_update)
 {
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
@@ -2804,11 +2808,11 @@ ExecARDeleteTriggers(EState *estate, ModifyTableState 
*mtstate,
                else
                        ExecForceStoreHeapTuple(fdw_trigtuple, slot, false);
 
-               AfterTriggerSaveEvent(estate, mtstate, relinfo,
-                                                         NULL, NULL,
+               AfterTriggerSaveEvent(estate, relinfo, NULL, NULL,
                                                          TRIGGER_EVENT_DELETE,
                                                          true, slot, NULL, 
NIL, NULL,
-                                                         transition_capture);
+                                                         transition_capture,
+                                                         is_crosspart_update);
        }
 }
 
@@ -2927,12 +2931,12 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo 
*relinfo,
        Assert(relinfo->ri_RootResultRelInfo == NULL);
 
        if (trigdesc && trigdesc->trig_update_after_statement)
-               AfterTriggerSaveEvent(estate, NULL, relinfo,
-                                                         NULL, NULL,
+               AfterTriggerSaveEvent(estate, relinfo, NULL, NULL,
                                                          TRIGGER_EVENT_UPDATE,
                                                          false, NULL, NULL, 
NIL,
                                                          
ExecGetAllUpdatedCols(relinfo, estate),
-                                                         transition_capture);
+                                                         transition_capture,
+                                                         false);
 }
 
 bool
@@ -3068,24 +3072,25 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
 }
 
 /*
- * 'src_partinfo' and 'dst_partinfo', when non-NULL, refer to the source and
- * destination partitions, respectively, of a cross-partition update of the
- * root partitioned table mentioned in the query, given by 'relinfo'.
+ * Note: 'src_partinfo' and 'dst_partinfo', when non-NULL, refer to the source
+ * and destination partitions, respectively, of a cross-partition update of
+ * the root partitioned table mentioned in the query, given by 'relinfo'.
  * 'tupleid' in that case refers to the ctid of the "old" tuple in the source
  * partition, and 'newslot' contains the "new" tuple in the destination
  * partition.  This interface allows to support the requirements of
- * ExecCrossPartitionUpdateForeignKey().
+ * ExecCrossPartitionUpdateForeignKey(); is_crosspart_update must be true in
+ * that case.
  */
 void
-ExecARUpdateTriggers(EState *estate, ModifyTableState *mtstate,
-                                        ResultRelInfo *relinfo,
+ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
                                         ResultRelInfo *src_partinfo,
                                         ResultRelInfo *dst_partinfo,
                                         ItemPointer tupleid,
                                         HeapTuple fdw_trigtuple,
                                         TupleTableSlot *newslot,
                                         List *recheckIndexes,
-                                        TransitionCaptureState 
*transition_capture)
+                                        TransitionCaptureState 
*transition_capture,
+                                        bool is_crosspart_update)
 {
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
@@ -3103,6 +3108,9 @@ ExecARUpdateTriggers(EState *estate, ModifyTableState 
*mtstate,
                TupleTableSlot *oldslot;
                ResultRelInfo *tupsrc;
 
+               Assert((src_partinfo != NULL && dst_partinfo != NULL) ||
+                          !is_crosspart_update);
+
                tupsrc = src_partinfo ? src_partinfo : relinfo;
                oldslot = ExecGetTriggerOldSlot(estate, tupsrc);
 
@@ -3119,12 +3127,14 @@ ExecARUpdateTriggers(EState *estate, ModifyTableState 
*mtstate,
                else
                        ExecClearTuple(oldslot);
 
-               AfterTriggerSaveEvent(estate, mtstate, relinfo,
+               AfterTriggerSaveEvent(estate, relinfo,
                                                          src_partinfo, 
dst_partinfo,
                                                          TRIGGER_EVENT_UPDATE,
-                                                         true, oldslot, 
newslot, recheckIndexes,
+                                                         true,
+                                                         oldslot, newslot, 
recheckIndexes,
                                                          
ExecGetAllUpdatedCols(relinfo, estate),
-                                                         transition_capture);
+                                                         transition_capture,
+                                                         is_crosspart_update);
        }
 }
 
@@ -3247,10 +3257,11 @@ ExecASTruncateTriggers(EState *estate, ResultRelInfo 
*relinfo)
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
        if (trigdesc && trigdesc->trig_truncate_after_statement)
-               AfterTriggerSaveEvent(estate, NULL, relinfo,
+               AfterTriggerSaveEvent(estate, relinfo,
                                                          NULL, NULL,
                                                          
TRIGGER_EVENT_TRUNCATE,
-                                                         false, NULL, NULL, 
NIL, NULL, NULL);
+                                                         false, NULL, NULL, 
NIL, NULL, NULL,
+                                                         false);
 }
 
 
@@ -5829,24 +5840,26 @@ AfterTriggerPendingOnRel(Oid relid)
  *     UPDATE; in this case, this function is called with relinfo as the
  *     partitioned table, and src_partinfo and dst_partinfo referring to the
  *     source and target leaf partitions, respectively.
+ *
+ *     is_crosspart_update is true either when a DELETE event is fired on the
+ *     source partition (which is to be ignored) or an UPDATE event is fired on
+ *     the root partitioned table.
  * ----------
  */
 static void
-AfterTriggerSaveEvent(EState *estate, ModifyTableState *mtstate,
-                                         ResultRelInfo *relinfo,
+AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
                                          ResultRelInfo *src_partinfo,
                                          ResultRelInfo *dst_partinfo,
                                          int event, bool row_trigger,
                                          TupleTableSlot *oldslot, 
TupleTableSlot *newslot,
                                          List *recheckIndexes, Bitmapset 
*modifiedCols,
-                                         TransitionCaptureState 
*transition_capture)
+                                         TransitionCaptureState 
*transition_capture,
+                                         bool is_crosspart_update)
 {
        Relation        rel = relinfo->ri_RelationDesc;
-       Relation        rootRel;
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
        AfterTriggerEventData new_event;
        AfterTriggerSharedData new_shared;
-       bool            maybe_crosspart_update;
        char            relkind = rel->rd_rel->relkind;
        int                     tgtype_event;
        int                     tgtype_level;
@@ -5957,16 +5970,9 @@ AfterTriggerSaveEvent(EState *estate, ModifyTableState 
*mtstate,
         * queue an update event on the root target partitioned table, also
         * passing the source and destination partitions and their tuples.
         */
-       rootRel = relinfo->ri_RootResultRelInfo ?
-               relinfo->ri_RootResultRelInfo->ri_RelationDesc : NULL;
-       maybe_crosspart_update =
-               (row_trigger && mtstate &&
-                mtstate->operation == CMD_UPDATE &&
-                (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
-                 (rootRel && rootRel->rd_rel->relkind == 
RELKIND_PARTITIONED_TABLE)));
        Assert(!row_trigger ||
                   rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
-                  (maybe_crosspart_update &&
+                  (is_crosspart_update &&
                        TRIGGER_FIRED_BY_UPDATE(event) &&
                        src_partinfo != NULL && dst_partinfo != NULL));
 
@@ -6161,7 +6167,7 @@ AfterTriggerSaveEvent(EState *estate, ModifyTableState 
*mtstate,
                                         * (partitioned) target table will be 
used to perform the
                                         * necessary foreign key enforcement 
action.
                                         */
-                                       if (maybe_crosspart_update &&
+                                       if (is_crosspart_update &&
                                                TRIGGER_FIRED_BY_DELETE(event) 
&&
                                                trigger->tgisclone)
                                                continue;
diff --git a/src/backend/executor/execReplication.c 
b/src/backend/executor/execReplication.c
index e2a338ba33..f978e28ba9 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -516,10 +516,10 @@ ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo,
                                                                                
                   NULL, NIL);
 
                /* AFTER ROW UPDATE Triggers */
-               ExecARUpdateTriggers(estate, NULL, resultRelInfo,
+               ExecARUpdateTriggers(estate, resultRelInfo,
                                                         NULL, NULL,
                                                         tid, NULL, slot,
-                                                        recheckIndexes, NULL);
+                                                        recheckIndexes, NULL, 
false);
 
                list_free(recheckIndexes);
        }
@@ -557,8 +557,8 @@ ExecSimpleRelationDelete(ResultRelInfo *resultRelInfo,
                simple_table_tuple_delete(rel, tid, estate->es_snapshot);
 
                /* AFTER ROW DELETE Triggers */
-               ExecARDeleteTriggers(estate, NULL, resultRelInfo,
-                                                        tid, NULL, NULL);
+               ExecARDeleteTriggers(estate, resultRelInfo,
+                                                        tid, NULL, NULL, 
false);
        }
 }
 
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index 6a16d0e673..204126a29f 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -962,13 +962,14 @@ ExecInsert(ModifyTableState *mtstate,
        if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture
                && mtstate->mt_transition_capture->tcs_update_new_table)
        {
-               ExecARUpdateTriggers(estate, mtstate, resultRelInfo,
+               ExecARUpdateTriggers(estate, resultRelInfo,
                                                         NULL, NULL,
                                                         NULL,
                                                         NULL,
                                                         slot,
                                                         NULL,
-                                                        
mtstate->mt_transition_capture);
+                                                        
mtstate->mt_transition_capture,
+                                                        false);
 
                /*
                 * We've already captured the NEW TABLE row, so make sure any AR
@@ -1359,13 +1360,14 @@ ldelete:;
        if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture
                && mtstate->mt_transition_capture->tcs_update_old_table)
        {
-               ExecARUpdateTriggers(estate, mtstate, resultRelInfo,
+               ExecARUpdateTriggers(estate, resultRelInfo,
                                                         NULL, NULL,
                                                         tupleid,
                                                         oldtuple,
                                                         NULL,
                                                         NULL,
-                                                        
mtstate->mt_transition_capture);
+                                                        
mtstate->mt_transition_capture,
+                                                        false);
 
                /*
                 * We've already captured the NEW TABLE row, so make sure any AR
@@ -1375,8 +1377,8 @@ ldelete:;
        }
 
        /* AFTER ROW DELETE Triggers */
-       ExecARDeleteTriggers(estate, mtstate, resultRelInfo, tupleid, oldtuple,
-                                                ar_delete_trig_tcs);
+       ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldtuple,
+                                                ar_delete_trig_tcs, 
changingPart);
 
        /* Process RETURNING if present and if requested */
        if (processReturning && resultRelInfo->ri_projectReturning)
@@ -1642,13 +1644,13 @@ GetAncestorResultRels(ResultRelInfo *resultRelInfo)
  * keys pointing into it.
  */
 static void
-ExecCrossPartitionUpdateForeignKey(ResultRelInfo *sourcePartInfo,
+ExecCrossPartitionUpdateForeignKey(ModifyTableState *mtstate,
+                                                                  EState 
*estate,
+                                                                  
ResultRelInfo *sourcePartInfo,
                                                                   
ResultRelInfo *destPartInfo,
                                                                   ItemPointer 
tupleid,
                                                                   
TupleTableSlot *oldslot,
-                                                                  
TupleTableSlot *newslot,
-                                                                  
ModifyTableState *mtstate,
-                                                                  EState 
*estate)
+                                                                  
TupleTableSlot *newslot)
 {
        ListCell   *lc;
        ResultRelInfo *rootRelInfo = sourcePartInfo->ri_RootResultRelInfo;
@@ -1699,10 +1701,9 @@ ExecCrossPartitionUpdateForeignKey(ResultRelInfo 
*sourcePartInfo,
        }
 
        /* Perform the root table's triggers. */
-       ExecARUpdateTriggers(estate, mtstate, rootRelInfo,
-                                                sourcePartInfo, destPartInfo,
-                                                tupleid, NULL,
-                                                newslot, NIL, NULL);
+       ExecARUpdateTriggers(estate,
+                                                rootRelInfo, sourcePartInfo, 
destPartInfo,
+                                                tupleid, NULL, newslot, NIL, 
NULL, true);
 }
 
 /* ----------------------------------------------------------------
@@ -1920,11 +1921,11 @@ lreplace:;
                        if (insert_destrel &&
                                resultRelInfo->ri_TrigDesc &&
                                
resultRelInfo->ri_TrigDesc->trig_update_after_row)
-                               
ExecCrossPartitionUpdateForeignKey(resultRelInfo,
+                               ExecCrossPartitionUpdateForeignKey(mtstate, 
estate,
+                                                                               
                   resultRelInfo,
                                                                                
                   insert_destrel,
                                                                                
                   tupleid, oldslot,
-                                                                               
                   inserted_tuple,
-                                                                               
                   mtstate, estate);
+                                                                               
                   inserted_tuple);
 
                        return returning_slot;
                }
@@ -2105,14 +2106,15 @@ lreplace:;
                (estate->es_processed)++;
 
        /* AFTER ROW UPDATE Triggers */
-       ExecARUpdateTriggers(estate, mtstate, resultRelInfo,
+       ExecARUpdateTriggers(estate, resultRelInfo,
                                                 NULL, NULL,
                                                 tupleid, oldtuple,
                                                 slot,
                                                 recheckIndexes,
                                                 mtstate->operation == 
CMD_INSERT ?
                                                 
mtstate->mt_oc_transition_capture :
-                                                
mtstate->mt_transition_capture);
+                                                mtstate->mt_transition_capture,
+                                                false);
 
        list_free(recheckIndexes);
 
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 1ba3a54499..66bf6c16e3 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -211,11 +211,11 @@ extern bool ExecBRDeleteTriggers(EState *estate,
                                                                 HeapTuple 
fdw_trigtuple,
                                                                 TupleTableSlot 
**epqslot);
 extern void ExecARDeleteTriggers(EState *estate,
-                                                                
ModifyTableState *mtstate,
                                                                 ResultRelInfo 
*relinfo,
                                                                 ItemPointer 
tupleid,
                                                                 HeapTuple 
fdw_trigtuple,
-                                                                
TransitionCaptureState *transition_capture);
+                                                                
TransitionCaptureState *transition_capture,
+                                                                bool 
is_crosspart_update);
 extern bool ExecIRDeleteTriggers(EState *estate,
                                                                 ResultRelInfo 
*relinfo,
                                                                 HeapTuple 
trigtuple);
@@ -231,7 +231,6 @@ extern bool ExecBRUpdateTriggers(EState *estate,
                                                                 HeapTuple 
fdw_trigtuple,
                                                                 TupleTableSlot 
*slot);
 extern void ExecARUpdateTriggers(EState *estate,
-                                                                
ModifyTableState *mtstate,
                                                                 ResultRelInfo 
*relinfo,
                                                                 ResultRelInfo 
*src_partinfo,
                                                                 ResultRelInfo 
*dst_partinfo,
@@ -239,7 +238,8 @@ extern void ExecARUpdateTriggers(EState *estate,
                                                                 HeapTuple 
fdw_trigtuple,
                                                                 TupleTableSlot 
*slot,
                                                                 List 
*recheckIndexes,
-                                                                
TransitionCaptureState *transition_capture);
+                                                                
TransitionCaptureState *transition_capture,
+                                                                bool 
is_crosspart_update);
 extern bool ExecIRUpdateTriggers(EState *estate,
                                                                 ResultRelInfo 
*relinfo,
                                                                 HeapTuple 
trigtuple,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 6c7eef1e54..37ad2b7663 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -530,7 +530,10 @@ typedef struct ResultRelInfo
        /* for use by copyfrom.c when performing multi-inserts */
        struct CopyMultiInsertBuffer *ri_CopyMultiInsertBuffer;
 
-       /* Used during cross-partition updates on partitioned tables. */
+       /*
+        * Used when a leaf partition is involved in a cross-partition update of
+        * one of its ancestors; see ExecCrossPartitionUpdateForeignKey().
+        */
        List       *ri_ancestorResultRels;
 } ResultRelInfo;
 

Attachment: v14-0001-Enforce-foreign-key-correctly-during-cross-parti.patch
Description: Binary data

Reply via email to