aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeModifyTable.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r--src/backend/executor/nodeModifyTable.c200
1 files changed, 84 insertions, 116 deletions
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;