@ -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 ;