Remove es_result_relation_info from EState.
authorHeikki Linnakangas <[email protected]>
Wed, 14 Oct 2020 08:41:40 +0000 (11:41 +0300)
committerHeikki Linnakangas <[email protected]>
Wed, 14 Oct 2020 08:41:40 +0000 (11:41 +0300)
Maintaining 'es_result_relation_info' correctly at all times has become
cumbersome, especially with partitioning where each partition gets its
own result relation info. Having to set and reset it across arbitrary
operations has caused bugs in the past.

This changes all the places that used 'es_result_relation_info', to
receive the currently active ResultRelInfo via function parameters
instead.

Author: Amit Langote
Discussion: https://www.postgresql.org/message-id/CA%2BHiwqGEmiib8FLiHMhKB%2BCH5dRgHSLc5N5wnvc4kym%2BZYpQEQ%40mail.gmail.com

13 files changed:
src/backend/commands/copy.c
src/backend/commands/tablecmds.c
src/backend/executor/execIndexing.c
src/backend/executor/execMain.c
src/backend/executor/execReplication.c
src/backend/executor/execUtils.c
src/backend/executor/nodeModifyTable.c
src/backend/replication/logical/worker.c
src/include/executor/executor.h
src/include/executor/nodeModifyTable.h
src/include/nodes/execnodes.h
src/test/regress/expected/insert.out
src/test/regress/sql/insert.sql

index 71d48d45743b6564b7bdbba06e260ac37ca06493..531bd7c73a52d6b6bdcebac943649c18641722c8 100644 (file)
@@ -2489,9 +2489,6 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo,
    ResultRelInfo *resultRelInfo = buffer->resultRelInfo;
    TupleTableSlot **slots = buffer->slots;
 
-   /* Set es_result_relation_info to the ResultRelInfo we're flushing. */
-   estate->es_result_relation_info = resultRelInfo;
-
    /*
     * Print error context information correctly, if one of the operations
     * below fail.
@@ -2524,7 +2521,8 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo,
 
            cstate->cur_lineno = buffer->linenos[i];
            recheckIndexes =
-               ExecInsertIndexTuples(buffer->slots[i], estate, false, NULL,
+               ExecInsertIndexTuples(resultRelInfo,
+                                     buffer->slots[i], estate, false, NULL,
                                      NIL);
            ExecARInsertTriggers(estate, resultRelInfo,
                                 slots[i], recheckIndexes,
@@ -2839,8 +2837,6 @@ CopyFrom(CopyState cstate)
 
    ExecOpenIndices(resultRelInfo, false);
 
-   estate->es_result_relation_info = resultRelInfo;
-
    /*
     * Set up a ModifyTableState so we can let FDW(s) init themselves for
     * foreign-table result relation(s).
@@ -3108,11 +3104,6 @@ CopyFrom(CopyState cstate)
                prevResultRelInfo = resultRelInfo;
            }
 
-           /*
-            * For ExecInsertIndexTuples() to work on the partition's indexes
-            */
-           estate->es_result_relation_info = resultRelInfo;
-
            /*
             * If we're capturing transition tuples, we might need to convert
             * from the partition rowtype to root rowtype.
@@ -3217,7 +3208,8 @@ CopyFrom(CopyState cstate)
                /* Compute stored generated columns */
                if (resultRelInfo->ri_RelationDesc->rd_att->constr &&
                    resultRelInfo->ri_RelationDesc->rd_att->constr->has_generated_stored)
-                   ExecComputeStoredGenerated(estate, myslot, CMD_INSERT);
+                   ExecComputeStoredGenerated(resultRelInfo, estate, myslot,
+                                              CMD_INSERT);
 
                /*
                 * If the target is a plain table, check the constraints of
@@ -3288,7 +3280,8 @@ CopyFrom(CopyState cstate)
                                           myslot, mycid, ti_options, bistate);
 
                        if (resultRelInfo->ri_NumIndices > 0)
-                           recheckIndexes = ExecInsertIndexTuples(myslot,
+                           recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
+                                                                  myslot,
                                                                   estate,
                                                                   false,
                                                                   NULL,
index 80fedad5e045bbab15e942ce4104a9048abf7f29..511f015a861cfd87527a02b3e1e596d1b9368528 100644 (file)
@@ -1820,7 +1820,6 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
    resultRelInfo = resultRelInfos;
    foreach(cell, rels)
    {
-       estate->es_result_relation_info = resultRelInfo;
        ExecBSTruncateTriggers(estate, resultRelInfo);
        resultRelInfo++;
    }
@@ -1950,7 +1949,6 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
    resultRelInfo = resultRelInfos;
    foreach(cell, rels)
    {
-       estate->es_result_relation_info = resultRelInfo;
        ExecASTruncateTriggers(estate, resultRelInfo);
        resultRelInfo++;
    }
index 1862af621be0d6c942123002ecabe3e4baca993c..c6b5bcba7b47fe0c49bdded77b6931b7e6799696 100644 (file)
@@ -270,7 +270,8 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
  * ----------------------------------------------------------------
  */
 List *
-ExecInsertIndexTuples(TupleTableSlot *slot,
+ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
+                     TupleTableSlot *slot,
                      EState *estate,
                      bool noDupErr,
                      bool *specConflict,
@@ -278,7 +279,6 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 {
    ItemPointer tupleid = &slot->tts_tid;
    List       *result = NIL;
-   ResultRelInfo *resultRelInfo;
    int         i;
    int         numIndices;
    RelationPtr relationDescs;
@@ -293,7 +293,6 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
    /*
     * Get information from the result relation info structure.
     */
-   resultRelInfo = estate->es_result_relation_info;
    numIndices = resultRelInfo->ri_NumIndices;
    relationDescs = resultRelInfo->ri_IndexRelationDescs;
    indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
@@ -479,11 +478,10 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
  * ----------------------------------------------------------------
  */
 bool
-ExecCheckIndexConstraints(TupleTableSlot *slot,
+ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
                          EState *estate, ItemPointer conflictTid,
                          List *arbiterIndexes)
 {
-   ResultRelInfo *resultRelInfo;
    int         i;
    int         numIndices;
    RelationPtr relationDescs;
@@ -501,7 +499,6 @@ ExecCheckIndexConstraints(TupleTableSlot *slot,
    /*
     * Get information from the result relation info structure.
     */
-   resultRelInfo = estate->es_result_relation_info;
    numIndices = resultRelInfo->ri_NumIndices;
    relationDescs = resultRelInfo->ri_IndexRelationDescs;
    indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
index 783eecbc13375da8baaf540e3b63a1691794821c..293f53d07c9d1f562e05c1c472b3dec448b89db0 100644 (file)
@@ -827,9 +827,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
 
    estate->es_plannedstmt = plannedstmt;
 
-   /* es_result_relation_info is NULL except when within ModifyTable */
-   estate->es_result_relation_info = NULL;
-
    /*
     * Next, build the ExecRowMark array from the PlanRowMark(s), if any.
     */
@@ -2694,7 +2691,6 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
     * subplans themselves are initialized.
     */
    parentestate->es_result_relations = NULL;
-   /* es_result_relation_info must NOT be copied */
    /* es_trig_target_relations must NOT be copied */
    rcestate->es_top_eflags = parentestate->es_top_eflags;
    rcestate->es_instrument = parentestate->es_instrument;
index b29db7bf4f9566f7e8f563ca3f9bcb43bc25359b..01d26881e770c0eb7f771fe2947136cd3f013c86 100644 (file)
@@ -404,10 +404,10 @@ retry:
  * Caller is responsible for opening the indexes.
  */
 void
-ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
+ExecSimpleRelationInsert(ResultRelInfo *resultRelInfo,
+                        EState *estate, TupleTableSlot *slot)
 {
    bool        skip_tuple = false;
-   ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
    Relation    rel = resultRelInfo->ri_RelationDesc;
 
    /* For now we support only tables. */
@@ -430,7 +430,8 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
        /* Compute stored generated columns */
        if (rel->rd_att->constr &&
            rel->rd_att->constr->has_generated_stored)
-           ExecComputeStoredGenerated(estate, slot, CMD_INSERT);
+           ExecComputeStoredGenerated(resultRelInfo, estate, slot,
+                                      CMD_INSERT);
 
        /* Check the constraints of the tuple */
        if (rel->rd_att->constr)
@@ -442,7 +443,8 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
        simple_table_tuple_insert(resultRelInfo->ri_RelationDesc, slot);
 
        if (resultRelInfo->ri_NumIndices > 0)
-           recheckIndexes = ExecInsertIndexTuples(slot, estate, false, NULL,
+           recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
+                                                  slot, estate, false, NULL,
                                                   NIL);
 
        /* AFTER ROW INSERT Triggers */
@@ -466,11 +468,11 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
  * Caller is responsible for opening the indexes.
  */
 void
-ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
+ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo,
+                        EState *estate, EPQState *epqstate,
                         TupleTableSlot *searchslot, TupleTableSlot *slot)
 {
    bool        skip_tuple = false;
-   ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
    Relation    rel = resultRelInfo->ri_RelationDesc;
    ItemPointer tid = &(searchslot->tts_tid);
 
@@ -496,7 +498,8 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
        /* Compute stored generated columns */
        if (rel->rd_att->constr &&
            rel->rd_att->constr->has_generated_stored)
-           ExecComputeStoredGenerated(estate, slot, CMD_UPDATE);
+           ExecComputeStoredGenerated(resultRelInfo, estate, slot,
+                                      CMD_UPDATE);
 
        /* Check the constraints of the tuple */
        if (rel->rd_att->constr)
@@ -508,7 +511,8 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
                                  &update_indexes);
 
        if (resultRelInfo->ri_NumIndices > 0 && update_indexes)
-           recheckIndexes = ExecInsertIndexTuples(slot, estate, false, NULL,
+           recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
+                                                  slot, estate, false, NULL,
                                                   NIL);
 
        /* AFTER ROW UPDATE Triggers */
@@ -527,11 +531,11 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
  * Caller is responsible for opening the indexes.
  */
 void
-ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
+ExecSimpleRelationDelete(ResultRelInfo *resultRelInfo,
+                        EState *estate, EPQState *epqstate,
                         TupleTableSlot *searchslot)
 {
    bool        skip_tuple = false;
-   ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
    Relation    rel = resultRelInfo->ri_RelationDesc;
    ItemPointer tid = &searchslot->tts_tid;
 
index 6d8c112e2fe4acfcf8b0db4bf95b87e597bbabdb..071a0007ebcd8679e6322a896c58fdcf43d76b25 100644 (file)
@@ -125,7 +125,6 @@ CreateExecutorState(void)
 
    estate->es_result_relations = NULL;
    estate->es_opened_result_relations = NIL;
-   estate->es_result_relation_info = NULL;
    estate->es_tuple_routing_result_relations = NIL;
    estate->es_trig_target_relations = NIL;
 
index b3f7012e38699448926f8272926f831f431a5ad7..6782a2dcd2838797d59557820fc565e94d62100c 100644 (file)
@@ -70,7 +70,8 @@ static TupleTableSlot *ExecPrepareTupleRouting(ModifyTableState *mtstate,
                                               EState *estate,
                                               PartitionTupleRouting *proute,
                                               ResultRelInfo *targetRelInfo,
-                                              TupleTableSlot *slot);
+                                              TupleTableSlot *slot,
+                                              ResultRelInfo **partRelInfo);
 static ResultRelInfo *getTargetResultRelInfo(ModifyTableState *node);
 static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate);
 static TupleConversionMap *tupconv_map_for_subplan(ModifyTableState *node,
@@ -246,9 +247,10 @@ ExecCheckTIDVisible(EState *estate,
  * Compute stored generated columns for a tuple
  */
 void
-ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot, CmdType cmdtype)
+ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo,
+                          EState *estate, TupleTableSlot *slot,
+                          CmdType cmdtype)
 {
-   ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
    Relation    rel = resultRelInfo->ri_RelationDesc;
    TupleDesc   tupdesc = RelationGetDescr(rel);
    int         natts = tupdesc->natts;
@@ -366,32 +368,48 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot, CmdType cmdtype
  *     ExecInsert
  *
  *     For INSERT, we have to insert the tuple into the target relation
- *     and insert appropriate tuples into the index relations.
+ *     (or partition thereof) and insert appropriate tuples into the index
+ *     relations.
  *
  *     Returns RETURNING result if any, otherwise NULL.
+ *
+ *     This may change the currently active tuple conversion map in
+ *     mtstate->mt_transition_capture, so the callers must take care to
+ *     save the previous value to avoid losing track of it.
  * ----------------------------------------------------------------
  */
 static TupleTableSlot *
 ExecInsert(ModifyTableState *mtstate,
+          ResultRelInfo *resultRelInfo,
           TupleTableSlot *slot,
           TupleTableSlot *planSlot,
           EState *estate,
           bool canSetTag)
 {
-   ResultRelInfo *resultRelInfo;
    Relation    resultRelationDesc;
    List       *recheckIndexes = NIL;
    TupleTableSlot *result = NULL;
    TransitionCaptureState *ar_insert_trig_tcs;
    ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
    OnConflictAction onconflict = node->onConflictAction;
-
-   ExecMaterializeSlot(slot);
+   PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
 
    /*
-    * get information on the (current) result relation
+    * If the input result relation is a partitioned table, find the leaf
+    * partition to insert the tuple into.
     */
-   resultRelInfo = estate->es_result_relation_info;
+   if (proute)
+   {
+       ResultRelInfo *partRelInfo;
+
+       slot = ExecPrepareTupleRouting(mtstate, estate, proute,
+                                      resultRelInfo, slot,
+                                      &partRelInfo);
+       resultRelInfo = partRelInfo;
+   }
+
+   ExecMaterializeSlot(slot);
+
    resultRelationDesc = resultRelInfo->ri_RelationDesc;
 
    /*
@@ -424,7 +442,8 @@ ExecInsert(ModifyTableState *mtstate,
         */
        if (resultRelationDesc->rd_att->constr &&
            resultRelationDesc->rd_att->constr->has_generated_stored)
-           ExecComputeStoredGenerated(estate, slot, CMD_INSERT);
+           ExecComputeStoredGenerated(resultRelInfo, estate, slot,
+                                      CMD_INSERT);
 
        /*
         * insert into foreign table: let the FDW do it
@@ -459,7 +478,8 @@ ExecInsert(ModifyTableState *mtstate,
         */
        if (resultRelationDesc->rd_att->constr &&
            resultRelationDesc->rd_att->constr->has_generated_stored)
-           ExecComputeStoredGenerated(estate, slot, CMD_INSERT);
+           ExecComputeStoredGenerated(resultRelInfo, estate, slot,
+                                      CMD_INSERT);
 
        /*
         * Check any RLS WITH CHECK policies.
@@ -521,8 +541,8 @@ ExecInsert(ModifyTableState *mtstate,
             */
    vlock:
            specConflict = false;
-           if (!ExecCheckIndexConstraints(slot, estate, &conflictTid,
-                                          arbiterIndexes))
+           if (!ExecCheckIndexConstraints(resultRelInfo, slot, estate,
+                                          &conflictTid, arbiterIndexes))
            {
                /* committed conflict tuple found */
                if (onconflict == ONCONFLICT_UPDATE)
@@ -582,7 +602,8 @@ ExecInsert(ModifyTableState *mtstate,
                                           specToken);
 
            /* insert index entries for tuple */
-           recheckIndexes = ExecInsertIndexTuples(slot, estate, true,
+           recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
+                                                  slot, estate, true,
                                                   &specConflict,
                                                   arbiterIndexes);
 
@@ -621,8 +642,9 @@ ExecInsert(ModifyTableState *mtstate,
 
            /* insert index entries for tuple */
            if (resultRelInfo->ri_NumIndices > 0)
-               recheckIndexes = ExecInsertIndexTuples(slot, estate, false, NULL,
-                                                      NIL);
+               recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
+                                                      slot, estate, false,
+                                                      NULL, NIL);
        }
    }
 
@@ -707,6 +729,7 @@ ExecInsert(ModifyTableState *mtstate,
  */
 static TupleTableSlot *
 ExecDelete(ModifyTableState *mtstate,
+          ResultRelInfo *resultRelInfo,
           ItemPointer tupleid,
           HeapTuple oldtuple,
           TupleTableSlot *planSlot,
@@ -718,8 +741,7 @@ ExecDelete(ModifyTableState *mtstate,
           bool *tupleDeleted,
           TupleTableSlot **epqreturnslot)
 {
-   ResultRelInfo *resultRelInfo;
-   Relation    resultRelationDesc;
+   Relation    resultRelationDesc = resultRelInfo->ri_RelationDesc;
    TM_Result   result;
    TM_FailureData tmfd;
    TupleTableSlot *slot = NULL;
@@ -728,12 +750,6 @@ ExecDelete(ModifyTableState *mtstate,
    if (tupleDeleted)
        *tupleDeleted = false;
 
-   /*
-    * get information on the (current) result relation
-    */
-   resultRelInfo = estate->es_result_relation_info;
-   resultRelationDesc = resultRelInfo->ri_RelationDesc;
-
    /* BEFORE ROW DELETE Triggers */
    if (resultRelInfo->ri_TrigDesc &&
        resultRelInfo->ri_TrigDesc->trig_delete_before_row)
@@ -1067,6 +1083,7 @@ ldelete:;
  */
 static TupleTableSlot *
 ExecUpdate(ModifyTableState *mtstate,
+          ResultRelInfo *resultRelInfo,
           ItemPointer tupleid,
           HeapTuple oldtuple,
           TupleTableSlot *slot,
@@ -1075,12 +1092,10 @@ ExecUpdate(ModifyTableState *mtstate,
           EState *estate,
           bool canSetTag)
 {
-   ResultRelInfo *resultRelInfo;
-   Relation    resultRelationDesc;
+   Relation    resultRelationDesc = resultRelInfo->ri_RelationDesc;
    TM_Result   result;
    TM_FailureData tmfd;
    List       *recheckIndexes = NIL;
-   TupleConversionMap *saved_tcs_map = NULL;
 
    /*
     * abort the operation if not running transactions
@@ -1090,12 +1105,6 @@ ExecUpdate(ModifyTableState *mtstate,
 
    ExecMaterializeSlot(slot);
 
-   /*
-    * get information on the (current) result relation
-    */
-   resultRelInfo = estate->es_result_relation_info;
-   resultRelationDesc = resultRelInfo->ri_RelationDesc;
-
    /* BEFORE ROW UPDATE Triggers */
    if (resultRelInfo->ri_TrigDesc &&
        resultRelInfo->ri_TrigDesc->trig_update_before_row)
@@ -1120,7 +1129,8 @@ ExecUpdate(ModifyTableState *mtstate,
         */
        if (resultRelationDesc->rd_att->constr &&
            resultRelationDesc->rd_att->constr->has_generated_stored)
-           ExecComputeStoredGenerated(estate, slot, CMD_UPDATE);
+           ExecComputeStoredGenerated(resultRelInfo, estate, slot,
+                                      CMD_UPDATE);
 
        /*
         * update in foreign table: let the FDW do it
@@ -1157,7 +1167,8 @@ ExecUpdate(ModifyTableState *mtstate,
         */
        if (resultRelationDesc->rd_att->constr &&
            resultRelationDesc->rd_att->constr->has_generated_stored)
-           ExecComputeStoredGenerated(estate, slot, CMD_UPDATE);
+           ExecComputeStoredGenerated(resultRelInfo, estate, slot,
+                                      CMD_UPDATE);
 
        /*
         * Check any RLS UPDATE WITH CHECK policies
@@ -1207,6 +1218,7 @@ lreplace:;
            PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
            int         map_index;
            TupleConversionMap *tupconv_map;
+           TupleConversionMap *saved_tcs_map = NULL;
 
            /*
             * Disallow an INSERT ON CONFLICT DO UPDATE that causes the
@@ -1232,9 +1244,12 @@ lreplace:;
             * Row movement, part 1.  Delete the tuple, but skip RETURNING
             * processing. We want to return rows from INSERT.
             */
-           ExecDelete(mtstate, tupleid, oldtuple, planSlot, epqstate,
-                      estate, false, false /* canSetTag */ ,
-                      true /* changingPart */ , &tuple_deleted, &epqslot);
+           ExecDelete(mtstate, resultRelInfo, tupleid, oldtuple, planSlot,
+                      epqstate, estate,
+                      false,   /* processReturning */
+                      false,   /* canSetTag */
+                      true,    /* changingPart */
+                      &tuple_deleted, &epqslot);
 
            /*
             * For some reason if DELETE didn't happen (e.g. trigger prevented
@@ -1274,16 +1289,6 @@ lreplace:;
                }
            }
 
-           /*
-            * Updates set the transition capture map only when a new subplan
-            * is chosen.  But for inserts, it is set for each row. So after
-            * INSERT, we need to revert back to the map created for UPDATE;
-            * otherwise the next UPDATE will incorrectly use the one created
-            * for INSERT.  So first save the one created for UPDATE.
-            */
-           if (mtstate->mt_transition_capture)
-               saved_tcs_map = mtstate->mt_transition_capture->tcs_map;
-
            /*
             * resultRelInfo is one of the per-subplan resultRelInfos.  So we
             * should convert the tuple into root's tuple descriptor, since
@@ -1301,18 +1306,18 @@ lreplace:;
                                             mtstate->mt_root_tuple_slot);
 
            /*
-            * Prepare for tuple routing, making it look like we're inserting
-            * into the root.
+            * ExecInsert() may scribble on mtstate->mt_transition_capture, so
+            * save the currently active map.
             */
-           Assert(mtstate->rootResultRelInfo != NULL);
-           slot = ExecPrepareTupleRouting(mtstate, estate, proute,
-                                          mtstate->rootResultRelInfo, slot);
+           if (mtstate->mt_transition_capture)
+               saved_tcs_map = mtstate->mt_transition_capture->tcs_map;
 
-           ret_slot = ExecInsert(mtstate, slot, planSlot,
-                                 estate, canSetTag);
+           /* Tuple routing starts from the root table. */
+           Assert(mtstate->rootResultRelInfo != NULL);
+           ret_slot = ExecInsert(mtstate, mtstate->rootResultRelInfo, slot,
+                                 planSlot, estate, canSetTag);
 
-           /* Revert ExecPrepareTupleRouting's node change. */
-           estate->es_result_relation_info = resultRelInfo;
+           /* Clear the INSERT's tuple and restore the saved map. */
            if (mtstate->mt_transition_capture)
            {
                mtstate->mt_transition_capture->tcs_original_insert_tuple = NULL;
@@ -1476,7 +1481,9 @@ lreplace:;
 
        /* insert index entries for tuple if necessary */
        if (resultRelInfo->ri_NumIndices > 0 && update_indexes)
-           recheckIndexes = ExecInsertIndexTuples(slot, estate, false, NULL, NIL);
+           recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
+                                                  slot, estate, false,
+                                                  NULL, NIL);
    }
 
    if (canSetTag)
@@ -1715,7 +1722,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
     */
 
    /* Execute UPDATE with projection */
-   *returning = ExecUpdate(mtstate, conflictTid, NULL,
+   *returning = ExecUpdate(mtstate, resultRelInfo, conflictTid, NULL,
                            resultRelInfo->ri_onConflict->oc_ProjSlot,
                            planSlot,
                            &mtstate->mt_epqstate, mtstate->ps.state,
@@ -1872,19 +1879,19 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
  * ExecPrepareTupleRouting --- prepare for routing one tuple
  *
  * Determine the partition in which the tuple in slot is to be inserted,
- * and modify mtstate and estate to prepare for it.
- *
- * Caller must revert the estate changes after executing the insertion!
- * In mtstate, transition capture changes may also need to be reverted.
+ * and return its ResultRelInfo in *partRelInfo.  The return value is
+ * a slot holding the tuple of the partition rowtype.
  *
- * Returns a slot holding the tuple of the partition rowtype.
+ * This also sets the transition table information in mtstate based on the
+ * selected partition.
  */
 static TupleTableSlot *
 ExecPrepareTupleRouting(ModifyTableState *mtstate,
                        EState *estate,
                        PartitionTupleRouting *proute,
                        ResultRelInfo *targetRelInfo,
-                       TupleTableSlot *slot)
+                       TupleTableSlot *slot,
+                       ResultRelInfo **partRelInfo)
 {
    ResultRelInfo *partrel;
    PartitionRoutingInfo *partrouteinfo;
@@ -1901,11 +1908,6 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
    partrouteinfo = partrel->ri_PartitionInfo;
    Assert(partrouteinfo != NULL);
 
-   /*
-    * Make it look like we are inserting into the partition.
-    */
-   estate->es_result_relation_info = partrel;
-
    /*
     * If we're capturing transition tuples, we might need to convert from the
     * partition rowtype to root partitioned table's rowtype.
@@ -1950,6 +1952,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
        slot = execute_attr_map_slot(map->attrMap, slot, new_slot);
    }
 
+   *partRelInfo = partrel;
    return slot;
 }
 
@@ -2016,10 +2019,8 @@ static TupleTableSlot *
 ExecModifyTable(PlanState *pstate)
 {
    ModifyTableState *node = castNode(ModifyTableState, pstate);
-   PartitionTupleRouting *proute = node->mt_partition_tuple_routing;
    EState     *estate = node->ps.state;
    CmdType     operation = node->operation;
-   ResultRelInfo *saved_resultRelInfo;
    ResultRelInfo *resultRelInfo;
    PlanState  *subplanstate;
    JunkFilter *junkfilter;
@@ -2067,17 +2068,6 @@ ExecModifyTable(PlanState *pstate)
    subplanstate = node->mt_plans[node->mt_whichplan];
    junkfilter = resultRelInfo->ri_junkFilter;
 
-   /*
-    * es_result_relation_info must point to the currently active result
-    * relation while we are within this ModifyTable node.  Even though
-    * ModifyTable nodes can't be nested statically, they can be nested
-    * dynamically (since our subplan could include a reference to a modifying
-    * CTE).  So we have to save and restore the caller's value.
-    */
-   saved_resultRelInfo = estate->es_result_relation_info;
-
-   estate->es_result_relation_info = resultRelInfo;
-
    /*
     * Fetch rows from subplan(s), and execute the required table modification
     * for each row.
@@ -2111,7 +2101,6 @@ ExecModifyTable(PlanState *pstate)
                resultRelInfo++;
                subplanstate = node->mt_plans[node->mt_whichplan];
                junkfilter = resultRelInfo->ri_junkFilter;
-               estate->es_result_relation_info = resultRelInfo;
                EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
                                    node->mt_arowmarks[node->mt_whichplan]);
                /* Prepare to convert transition tuples from this child. */
@@ -2156,7 +2145,6 @@ ExecModifyTable(PlanState *pstate)
             */
            slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
 
-           estate->es_result_relation_info = saved_resultRelInfo;
            return slot;
        }
 
@@ -2239,25 +2227,21 @@ ExecModifyTable(PlanState *pstate)
        switch (operation)
        {
            case CMD_INSERT:
-               /* Prepare for tuple routing if needed. */
-               if (proute)
-                   slot = ExecPrepareTupleRouting(node, estate, proute,
-                                                  resultRelInfo, slot);
-               slot = ExecInsert(node, slot, planSlot,
+               slot = ExecInsert(node, resultRelInfo, slot, planSlot,
                                  estate, node->canSetTag);
-               /* Revert ExecPrepareTupleRouting's state change. */
-               if (proute)
-                   estate->es_result_relation_info = resultRelInfo;
                break;
            case CMD_UPDATE:
-               slot = ExecUpdate(node, tupleid, oldtuple, slot, planSlot,
-                                 &node->mt_epqstate, estate, node->canSetTag);
+               slot = ExecUpdate(node, resultRelInfo, tupleid, oldtuple, slot,
+                                 planSlot, &node->mt_epqstate, estate,
+                                 node->canSetTag);
                break;
            case CMD_DELETE:
-               slot = ExecDelete(node, tupleid, oldtuple, planSlot,
-                                 &node->mt_epqstate, estate,
-                                 true, node->canSetTag,
-                                 false /* changingPart */ , NULL, NULL);
+               slot = ExecDelete(node, resultRelInfo, tupleid, oldtuple,
+                                 planSlot, &node->mt_epqstate, estate,
+                                 true, /* processReturning */
+                                 node->canSetTag,
+                                 false,    /* changingPart */
+                                 NULL, NULL);
                break;
            default:
                elog(ERROR, "unknown operation");
@@ -2269,15 +2253,9 @@ ExecModifyTable(PlanState *pstate)
         * the work on next call.
         */
        if (slot)
-       {
-           estate->es_result_relation_info = saved_resultRelInfo;
            return slot;
-       }
    }
 
-   /* Restore es_result_relation_info before exiting */
-   estate->es_result_relation_info = saved_resultRelInfo;
-
    /*
     * We're done, but fire AFTER STATEMENT triggers before exiting.
     */
@@ -2298,7 +2276,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
    ModifyTableState *mtstate;
    CmdType     operation = node->operation;
    int         nplans = list_length(node->plans);
-   ResultRelInfo *saved_resultRelInfo;
    ResultRelInfo *resultRelInfo;
    Plan       *subplan;
    ListCell   *l,
@@ -2346,14 +2323,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
     * call ExecInitNode on each of the plans to be executed and save the
     * results into the array "mt_plans".  This is also a convenient place to
     * verify that the proposed target relations are valid and open their
-    * indexes for insertion of new index entries.  Note we *must* set
-    * estate->es_result_relation_info correctly while we initialize each
-    * sub-plan; external modules such as FDWs may depend on that (see
-    * contrib/postgres_fdw/postgres_fdw.c: postgresBeginDirectModify() as one
-    * example).
+    * indexes for insertion of new index entries.
     */
-   saved_resultRelInfo = estate->es_result_relation_info;
-
    resultRelInfo = mtstate->resultRelInfo;
    i = 0;
    forboth(l, node->resultRelations, l1, node->plans)
@@ -2400,7 +2371,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
            update_tuple_routing_needed = true;
 
        /* Now init the plan for this result rel */
-       estate->es_result_relation_info = resultRelInfo;
        mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
        mtstate->mt_scans[i] =
            ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
@@ -2424,8 +2394,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
        i++;
    }
 
-   estate->es_result_relation_info = saved_resultRelInfo;
-
    /* Get the target relation */
    rel = (getTargetResultRelInfo(mtstate))->ri_RelationDesc;
 
index 8d5d9e05b3c0474a41d237efe74e8fcead41f2c8..4f32dc74c867e250c9c1591cce34de80f9be729e 100644 (file)
@@ -1174,7 +1174,6 @@ apply_handle_insert(StringInfo s)
                                        &TTSOpsVirtual);
    resultRelInfo = makeNode(ResultRelInfo);
    InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
-   estate->es_result_relation_info = resultRelInfo;
 
    /* Input functions may need an active snapshot, so get one */
    PushActiveSnapshot(GetTransactionSnapshot());
@@ -1214,7 +1213,7 @@ apply_handle_insert_internal(ResultRelInfo *relinfo,
    ExecOpenIndices(relinfo, false);
 
    /* Do the insert. */
-   ExecSimpleRelationInsert(estate, remoteslot);
+   ExecSimpleRelationInsert(relinfo, estate, remoteslot);
 
    /* Cleanup. */
    ExecCloseIndices(relinfo);
@@ -1300,7 +1299,6 @@ apply_handle_update(StringInfo s)
                                        &TTSOpsVirtual);
    resultRelInfo = makeNode(ResultRelInfo);
    InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
-   estate->es_result_relation_info = resultRelInfo;
 
    /*
     * Populate updatedCols so that per-column triggers can fire.  This could
@@ -1392,7 +1390,8 @@ apply_handle_update_internal(ResultRelInfo *relinfo,
        EvalPlanQualSetSlot(&epqstate, remoteslot);
 
        /* Do the actual update. */
-       ExecSimpleRelationUpdate(estate, &epqstate, localslot, remoteslot);
+       ExecSimpleRelationUpdate(relinfo, estate, &epqstate, localslot,
+                                remoteslot);
    }
    else
    {
@@ -1455,7 +1454,6 @@ apply_handle_delete(StringInfo s)
                                        &TTSOpsVirtual);
    resultRelInfo = makeNode(ResultRelInfo);
    InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
-   estate->es_result_relation_info = resultRelInfo;
 
    PushActiveSnapshot(GetTransactionSnapshot());
 
@@ -1508,7 +1506,7 @@ apply_handle_delete_internal(ResultRelInfo *relinfo, EState *estate,
        EvalPlanQualSetSlot(&epqstate, localslot);
 
        /* Do the actual delete. */
-       ExecSimpleRelationDelete(estate, &epqstate, localslot);
+       ExecSimpleRelationDelete(relinfo, estate, &epqstate, localslot);
    }
    else
    {
@@ -1616,7 +1614,6 @@ apply_handle_tuple_routing(ResultRelInfo *relinfo,
    }
    MemoryContextSwitchTo(oldctx);
 
-   estate->es_result_relation_info = partrelinfo;
    switch (operation)
    {
        case CMD_INSERT:
@@ -1697,8 +1694,8 @@ apply_handle_tuple_routing(ResultRelInfo *relinfo,
                    ExecOpenIndices(partrelinfo, false);
 
                    EvalPlanQualSetSlot(&epqstate, remoteslot_part);
-                   ExecSimpleRelationUpdate(estate, &epqstate, localslot,
-                                            remoteslot_part);
+                   ExecSimpleRelationUpdate(partrelinfo, estate, &epqstate,
+                                            localslot, remoteslot_part);
                    ExecCloseIndices(partrelinfo);
                    EvalPlanQualEnd(&epqstate);
                }
@@ -1739,7 +1736,6 @@ apply_handle_tuple_routing(ResultRelInfo *relinfo,
                    Assert(partrelinfo_new != partrelinfo);
 
                    /* DELETE old tuple found in the old partition. */
-                   estate->es_result_relation_info = partrelinfo;
                    apply_handle_delete_internal(partrelinfo, estate,
                                                 localslot,
                                                 &relmapentry->remoterel);
@@ -1771,7 +1767,6 @@ apply_handle_tuple_routing(ResultRelInfo *relinfo,
                        slot_getallattrs(remoteslot);
                    }
                    MemoryContextSwitchTo(oldctx);
-                   estate->es_result_relation_info = partrelinfo_new;
                    apply_handle_insert_internal(partrelinfo_new, estate,
                                                 remoteslot_part);
                }
index c283bf14541cc8128c23ef263248b2477a5b14f5..b7978cd22ebc6fad72a36a56b0cbc3e4bea12f0c 100644 (file)
@@ -576,10 +576,14 @@ extern TupleTableSlot *ExecGetReturningSlot(EState *estate, ResultRelInfo *relIn
  */
 extern void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative);
 extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
-extern List *ExecInsertIndexTuples(TupleTableSlot *slot, EState *estate, bool noDupErr,
+extern List *ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
+                                  TupleTableSlot *slot, EState *estate,
+                                  bool noDupErr,
                                   bool *specConflict, List *arbiterIndexes);
-extern bool ExecCheckIndexConstraints(TupleTableSlot *slot, EState *estate,
-                                     ItemPointer conflictTid, List *arbiterIndexes);
+extern bool ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo,
+                                     TupleTableSlot *slot,
+                                     EState *estate, ItemPointer conflictTid,
+                                     List *arbiterIndexes);
 extern void check_exclusion_constraint(Relation heap, Relation index,
                                       IndexInfo *indexInfo,
                                       ItemPointer tupleid,
@@ -596,10 +600,13 @@ extern bool RelationFindReplTupleByIndex(Relation rel, Oid idxoid,
 extern bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
                                     TupleTableSlot *searchslot, TupleTableSlot *outslot);
 
-extern void ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot);
-extern void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
+extern void ExecSimpleRelationInsert(ResultRelInfo *resultRelInfo,
+                                    EState *estate, TupleTableSlot *slot);
+extern void ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo,
+                                    EState *estate, EPQState *epqstate,
                                     TupleTableSlot *searchslot, TupleTableSlot *slot);
-extern void ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
+extern void ExecSimpleRelationDelete(ResultRelInfo *resultRelInfo,
+                                    EState *estate, EPQState *epqstate,
                                     TupleTableSlot *searchslot);
 extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd);
 
index 4ec4ebdabc13e81cac9fb3d04e313fc0a89a2247..46a2dc95118897f42fb1eb5fbc7c37b79067a765 100644 (file)
@@ -15,7 +15,9 @@
 
 #include "nodes/execnodes.h"
 
-extern void ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot, CmdType cmdtype);
+extern void ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo,
+                                      EState *estate, TupleTableSlot *slot,
+                                      CmdType cmdtype);
 
 extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
 extern void ExecEndModifyTable(ModifyTableState *node);
index d9b09c592068610612a361d2923f9bcc10983b64..b7e9e5d539de3ba32e984b717c0f896701cffa30 100644 (file)
@@ -525,7 +525,6 @@ typedef struct EState
    List       *es_opened_result_relations; /* List of non-NULL entries in
                                             * es_result_relations in no
                                             * specific order */
-   ResultRelInfo *es_result_relation_info; /* currently active array elt */
 
    PartitionDirectory es_partition_directory;  /* for PartitionDesc lookup */
 
index eb9d45be5e5f46981f2537310e41e3e027d21a9a..da50ee3b670aa65003dce563e8866c33b471614d 100644 (file)
@@ -818,9 +818,7 @@ drop role regress_coldesc_role;
 drop table inserttest3;
 drop table brtrigpartcon;
 drop function brtrigpartcon1trigf();
--- check that "do nothing" BR triggers work with tuple-routing (this checks
--- that estate->es_result_relation_info is appropriately set/reset for each
--- routed tuple)
+-- check that "do nothing" BR triggers work with tuple-routing
 create table donothingbrtrig_test (a int, b text) partition by list (a);
 create table donothingbrtrig_test1 (b text, a int);
 create table donothingbrtrig_test2 (c text, b text, a int);
index ffd4aacbc48b1ce180e5c7270e19d591087b7b03..963faa1614c6b8487e890efd9c820f326e9d4e4a 100644 (file)
@@ -542,9 +542,7 @@ drop table inserttest3;
 drop table brtrigpartcon;
 drop function brtrigpartcon1trigf();
 
--- check that "do nothing" BR triggers work with tuple-routing (this checks
--- that estate->es_result_relation_info is appropriately set/reset for each
--- routed tuple)
+-- check that "do nothing" BR triggers work with tuple-routing
 create table donothingbrtrig_test (a int, b text) partition by list (a);
 create table donothingbrtrig_test1 (b text, a int);
 create table donothingbrtrig_test2 (c text, b text, a int);