@ -160,7 +160,8 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
static TupleTableSlot *
ExecInsert ( TupleTableSlot * slot ,
TupleTableSlot * planSlot ,
EState * estate )
EState * estate ,
bool canSetTag )
{
HeapTuple tuple ;
ResultRelInfo * resultRelInfo ;
@ -247,9 +248,12 @@ ExecInsert(TupleTableSlot *slot,
estate ) ;
}
( estate - > es_processed ) + + ;
estate - > es_lastoid = newId ;
setLastTid ( & ( tuple - > t_self ) ) ;
if ( canSetTag )
{
( estate - > es_processed ) + + ;
estate - > es_lastoid = newId ;
setLastTid ( & ( tuple - > t_self ) ) ;
}
/* AFTER ROW INSERT Triggers */
ExecARInsertTriggers ( estate , resultRelInfo , tuple , recheckIndexes ) ;
@ -283,7 +287,8 @@ ExecDelete(ItemPointer tupleid,
HeapTupleHeader oldtuple ,
TupleTableSlot * planSlot ,
EPQState * epqstate ,
EState * estate )
EState * estate ,
bool canSetTag )
{
ResultRelInfo * resultRelInfo ;
Relation resultRelationDesc ;
@ -393,7 +398,8 @@ ldelete:;
*/
}
( estate - > es_processed ) + + ;
if ( canSetTag )
( estate - > es_processed ) + + ;
/* AFTER ROW DELETE Triggers */
ExecARDeleteTriggers ( estate , resultRelInfo , tupleid ) ;
@ -467,7 +473,8 @@ ExecUpdate(ItemPointer tupleid,
TupleTableSlot * slot ,
TupleTableSlot * planSlot ,
EPQState * epqstate ,
EState * estate )
EState * estate ,
bool canSetTag )
{
HeapTuple tuple ;
ResultRelInfo * resultRelInfo ;
@ -621,7 +628,8 @@ lreplace:;
estate ) ;
}
( estate - > es_processed ) + + ;
if ( canSetTag )
( estate - > es_processed ) + + ;
/* AFTER ROW UPDATE Triggers */
ExecARUpdateTriggers ( estate , resultRelInfo , tupleid , tuple ,
@ -647,16 +655,13 @@ fireBSTriggers(ModifyTableState *node)
switch ( node - > operation )
{
case CMD_INSERT :
ExecBSInsertTriggers ( node - > ps . state ,
node - > ps . state - > es_result_relations ) ;
ExecBSInsertTriggers ( node - > ps . state , node - > resultRelInfo ) ;
break ;
case CMD_UPDATE :
ExecBSUpdateTriggers ( node - > ps . state ,
node - > ps . state - > es_result_relations ) ;
ExecBSUpdateTriggers ( node - > ps . state , node - > resultRelInfo ) ;
break ;
case CMD_DELETE :
ExecBSDeleteTriggers ( node - > ps . state ,
node - > ps . state - > es_result_relations ) ;
ExecBSDeleteTriggers ( node - > ps . state , node - > resultRelInfo ) ;
break ;
default :
elog ( ERROR , " unknown operation " ) ;
@ -673,16 +678,13 @@ fireASTriggers(ModifyTableState *node)
switch ( node - > operation )
{
case CMD_INSERT :
ExecASInsertTriggers ( node - > ps . state ,
node - > ps . state - > es_result_relations ) ;
ExecASInsertTriggers ( node - > ps . state , node - > resultRelInfo ) ;
break ;
case CMD_UPDATE :
ExecASUpdateTriggers ( node - > ps . state ,
node - > ps . state - > es_result_relations ) ;
ExecASUpdateTriggers ( node - > ps . state , node - > resultRelInfo ) ;
break ;
case CMD_DELETE :
ExecASDeleteTriggers ( node - > ps . state ,
node - > ps . state - > es_result_relations ) ;
ExecASDeleteTriggers ( node - > ps . state , node - > resultRelInfo ) ;
break ;
default :
elog ( ERROR , " unknown operation " ) ;
@ -703,6 +705,8 @@ ExecModifyTable(ModifyTableState *node)
{
EState * estate = node - > ps . state ;
CmdType operation = node - > operation ;
ResultRelInfo * saved_resultRelInfo ;
ResultRelInfo * resultRelInfo ;
PlanState * subplanstate ;
JunkFilter * junkfilter ;
TupleTableSlot * slot ;
@ -711,6 +715,15 @@ ExecModifyTable(ModifyTableState *node)
ItemPointerData tuple_ctid ;
HeapTupleHeader oldtuple = NULL ;
/*
* If we ' ve already completed processing , don ' t try to do more . We need
* this test because ExecPostprocessPlan might call us an extra time , and
* our subplan ' s nodes aren ' t necessarily robust against being called
* extra times .
*/
if ( node - > mt_done )
return NULL ;
/*
* On first call , fire BEFORE STATEMENT triggers before proceeding .
*/
@ -720,17 +733,21 @@ ExecModifyTable(ModifyTableState *node)
node - > fireBSTriggers = false ;
}
/* Preload local variables */
resultRelInfo = node - > resultRelInfo + node - > mt_whichplan ;
subplanstate = node - > mt_plans [ node - > mt_whichplan ] ;
junkfilter = resultRelInfo - > ri_junkFilter ;
/*
* es_result_relation_info must point to the currently active result
* relation . ( Note we assume that ModifyTable nodes can ' t be nested . ) We
* want it to be NULL whenever we ' re not within ModifyTable , though .
* 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 .
*/
estate - > es_result_relation_info =
estate - > es_result_relations + node - > mt_whichplan ;
saved_resultRelInfo = estate - > es_result_relation_info ;
/* Preload local variables */
subplanstate = node - > mt_plans [ node - > mt_whichplan ] ;
junkfilter = estate - > es_result_relation_info - > ri_junkFilter ;
estate - > es_result_relation_info = resultRelInfo ;
/*
* Fetch rows from subplan ( s ) , and execute the required table modification
@ -754,9 +771,10 @@ ExecModifyTable(ModifyTableState *node)
node - > mt_whichplan + + ;
if ( node - > mt_whichplan < node - > mt_nplans )
{
estate - > es_result_relation_i nfo+ + ;
resultRelI nfo+ + ;
subplanstate = node - > mt_plans [ node - > mt_whichplan ] ;
junkfilter = estate - > es_result_relation_info - > ri_junkFilter ;
junkfilter = resultRelInfo - > ri_junkFilter ;
estate - > es_result_relation_info = resultRelInfo ;
EvalPlanQualSetPlan ( & node - > mt_epqstate , subplanstate - > plan ,
node - > mt_arowmarks [ node - > mt_whichplan ] ) ;
continue ;
@ -778,7 +796,7 @@ ExecModifyTable(ModifyTableState *node)
Datum datum ;
bool isNull ;
if ( estate - > es_result_relation_i nfo- > ri_RelationDesc - > rd_rel - > relkind = = RELKIND_RELATION )
if ( resultRelI nfo- > ri_RelationDesc - > rd_rel - > relkind = = RELKIND_RELATION )
{
datum = ExecGetJunkAttribute ( slot ,
junkfilter - > jf_junkAttNo ,
@ -814,15 +832,15 @@ ExecModifyTable(ModifyTableState *node)
switch ( operation )
{
case CMD_INSERT :
slot = ExecInsert ( slot , planSlot , estate ) ;
slot = ExecInsert ( slot , planSlot , estate , node - > canSetTag ) ;
break ;
case CMD_UPDATE :
slot = ExecUpdate ( tupleid , oldtuple , slot , planSlot ,
& node - > mt_epqstate , estate ) ;
& node - > mt_epqstate , estate , node - > canSetTag ) ;
break ;
case CMD_DELETE :
slot = ExecDelete ( tupleid , oldtuple , planSlot ,
& node - > mt_epqstate , estate ) ;
& node - > mt_epqstate , estate , node - > canSetTag ) ;
break ;
default :
elog ( ERROR , " unknown operation " ) ;
@ -835,19 +853,21 @@ ExecModifyTable(ModifyTableState *node)
*/
if ( slot )
{
estate - > es_result_relation_info = NULL ;
estate - > es_result_relation_info = saved_resultRelInfo ;
return slot ;
}
}
/* Rese t es_result_relation_info before exiting */
estate - > es_result_relation_info = NULL ;
/* Restore es_result_relation_info before exiting */
estate - > es_result_relation_info = saved_resultRelInfo ;
/*
* We ' re done , but fire AFTER STATEMENT triggers before exiting .
*/
fireASTriggers ( node ) ;
node - > mt_done = true ;
return NULL ;
}
@ -861,6 +881,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
ModifyTableState * mtstate ;
CmdType operation = node - > operation ;
int nplans = list_length ( node - > plans ) ;
ResultRelInfo * saved_resultRelInfo ;
ResultRelInfo * resultRelInfo ;
TupleDesc tupDesc ;
Plan * subplan ;
@ -886,32 +907,59 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate - > ps . state = estate ;
mtstate - > ps . targetlist = NIL ; /* not actually used */
mtstate - > operation = operation ;
mtstate - > canSetTag = node - > canSetTag ;
mtstate - > mt_done = false ;
mtstate - > mt_plans = ( PlanState * * ) palloc0 ( sizeof ( PlanState * ) * nplans ) ;
mtstate - > resultRelInfo = estate - > es_result_relations + node - > resultRelIndex ;
mtstate - > mt_arowmarks = ( List * * ) palloc0 ( sizeof ( List * ) * nplans ) ;
mtstate - > mt_nplans = nplans ;
mtstate - > operation = operation ;
/* set up epqstate with dummy subplan data for the moment */
EvalPlanQualInit ( & mtstate - > mt_epqstate , estate , NULL , NIL , node - > epqParam ) ;
mtstate - > fireBSTriggers = true ;
/* For the moment, assume our targets are exactly the global result rels */
/*
* call ExecInitNode on each of the plans to be executed and save the
* results into the array " mt_plans " . Note we * must * set
* 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 ; ExecContextForcesOids depends on that !
*/
estate - > es_result_relation_info = estate - > es_result_relations ;
saved_resultRelInfo = estate - > es_result_relation_info ;
resultRelInfo = mtstate - > resultRelInfo ;
i = 0 ;
foreach ( l , node - > plans )
{
subplan = ( Plan * ) lfirst ( l ) ;
/*
* Verify result relation is a valid target for the current operation
*/
CheckValidResultRel ( resultRelInfo - > ri_RelationDesc , operation ) ;
/*
* If there are indices on the result relation , open them and save
* descriptors in the result relation info , so that we can add new
* index entries for the tuples we add / update . We need not do this
* for a DELETE , however , since deletion doesn ' t affect indexes .
*/
if ( resultRelInfo - > ri_RelationDesc - > rd_rel - > relhasindex & &
operation ! = CMD_DELETE )
ExecOpenIndices ( resultRelInfo ) ;
/* Now init the plan for this result rel */
estate - > es_result_relation_info = resultRelInfo ;
mtstate - > mt_plans [ i ] = ExecInitNode ( subplan , estate , eflags ) ;
estate - > es_result_relation_info + + ;
resultRelInfo + + ;
i + + ;
}
estate - > es_result_relation_info = NULL ;
estate - > es_result_relation_info = saved_resultRelInfo ;
/*
* Initialize RETURNING projections if needed .
@ -940,8 +988,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/*
* Build a projection for each result rel .
*/
Assert ( list_length ( node - > returningLists ) = = estate - > es_num_result_relations ) ;
resultRelInfo = estate - > es_result_relations ;
resultRelInfo = mtstate - > resultRelInfo ;
foreach ( l , node - > returningLists )
{
List * rlist = ( List * ) lfirst ( l ) ;
@ -1045,7 +1092,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if ( junk_filter_needed )
{
resultRelInfo = estate - > es_result_relations ;
resultRelInfo = mtstate - > resultRelInfo ;
for ( i = 0 ; i < nplans ; i + + )
{
JunkFilter * j ;
@ -1083,7 +1130,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
else
{
if ( operation = = CMD_INSERT )
ExecCheckPlanOutput ( estate - > es_result_relations - > ri_RelationDesc ,
ExecCheckPlanOutput ( mtstate - > resultRelInfo - > ri_RelationDesc ,
subplan - > targetlist ) ;
}
}
@ -1096,6 +1143,16 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if ( estate - > es_trig_tuple_slot = = NULL )
estate - > es_trig_tuple_slot = ExecInitExtraTupleSlot ( estate ) ;
/*
* Lastly , if this is not the primary ( canSetTag ) ModifyTable node , add it
* to estate - > es_auxmodifytables so that it will be run to completion by
* ExecPostprocessPlan . ( It ' d actually work fine to add the primary
* ModifyTable node too , but there ' s no need . )
*/
if ( ! mtstate - > canSetTag )
estate - > es_auxmodifytables = lappend ( estate - > es_auxmodifytables ,
mtstate ) ;
return mtstate ;
}