aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/copy.c19
-rw-r--r--src/backend/commands/tablecmds.c2
-rw-r--r--src/backend/executor/execIndexing.c9
-rw-r--r--src/backend/executor/execMain.c4
-rw-r--r--src/backend/executor/execReplication.c24
-rw-r--r--src/backend/executor/execUtils.c1
-rw-r--r--src/backend/executor/nodeModifyTable.c200
-rw-r--r--src/backend/replication/logical/worker.c17
-rw-r--r--src/include/executor/executor.h19
-rw-r--r--src/include/executor/nodeModifyTable.h4
-rw-r--r--src/include/nodes/execnodes.h1
-rw-r--r--src/test/regress/expected/insert.out4
-rw-r--r--src/test/regress/sql/insert.sql4
13 files changed, 131 insertions, 177 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 71d48d45743..531bd7c73a5 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -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).
@@ -3109,11 +3105,6 @@ CopyFrom(CopyState cstate)
}
/*
- * 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,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 80fedad5e04..511f015a861 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -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++;
}
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 1862af621be..c6b5bcba7b4 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -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;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 783eecbc133..293f53d07c9 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -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;
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index b29db7bf4f9..01d26881e77 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -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;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 6d8c112e2fe..071a0007ebc 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -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;
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b3f7012e386..6782a2dcd28 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -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
@@ -1275,16 +1290,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
* ExecInsert() starts the search from root. The tuple conversion
@@ -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;
@@ -1902,11 +1909,6 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
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;
@@ -2068,17 +2069,6 @@ ExecModifyTable(PlanState *pstate)
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;
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 8d5d9e05b3c..4f32dc74c86 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -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);
}
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index c283bf14541..b7978cd22eb 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -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);
diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h
index 4ec4ebdabc1..46a2dc95118 100644
--- a/src/include/executor/nodeModifyTable.h
+++ b/src/include/executor/nodeModifyTable.h
@@ -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);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index d9b09c59206..b7e9e5d539d 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -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 */
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index eb9d45be5e5..da50ee3b670 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -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);
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index ffd4aacbc48..963faa1614c 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -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);