本节介绍ExecModifyTable函数。
typedef struct ModifyTableState
{
PlanState ps;
CmdType operation;
bool canSetTag;
bool mt_done;
PlanState **mt_plans;
int mt_nplans;
int mt_whichplan;
TupleTableSlot **mt_scans;
ResultRelInfo *resultRelInfo;
ResultRelInfo *rootResultRelInfo;
List **mt_arowmarks;
EPQState mt_epqstate;
bool fireBSTriggers;
List *mt_excludedtlist;
TupleTableSlot *mt_root_tuple_slot;
struct PartitionTupleRouting *mt_partition_tuple_routing;
struct TransitionCaptureState *mt_transition_capture;
struct TransitionCaptureState *mt_oc_transition_capture;
TupleConversionMap **mt_per_subplan_tupconv_maps;
} ModifyTableState;
static TupleTableSlot *
ExecModifyTable(PlanState *pstate);
CHECK_FOR_INTERRUPTS();
if (estate->es_epq_active != NULL)
elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
if (node->mt_done)
return NULL;
if (node->fireBSTriggers)
{
fireBSTriggers(node);
node->fireBSTriggers = false;
}
resultRelInfo = node->resultRelInfo + node->mt_whichplan;
subplanstate = node->mt_plans[node->mt_whichplan];
junkfilter = resultRelInfo->ri_junkFilter;
saved_resultRelInfo = estate->es_result_relation_info;
estate->es_result_relation_info = resultRelInfo;
for (;;)
{
ResetPerTupleExprContext(estate);
if (pstate->ps_ExprContext)
ResetExprContext(pstate->ps_ExprContext);
planSlot = ExecProcNode(subplanstate);
if (TupIsNull(planSlot))
{
node->mt_whichplan++;
if (node->mt_whichplan < node->mt_nplans)
{
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]);
if (node->mt_transition_capture != NULL)
{
node->mt_transition_capture->tcs_map =
tupconv_map_for_subplan(node, node->mt_whichplan);
}
if (node->mt_oc_transition_capture != NULL)
{
node->mt_oc_transition_capture->tcs_map =
tupconv_map_for_subplan(node, node->mt_whichplan);
}
continue;
}
else
break;
}
if (resultRelInfo->ri_usesFdwDirectModify)
{
Assert(resultRelInfo->ri_projectReturning);
slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
estate->es_result_relation_info = saved_resultRelInfo;
return slot;
}
EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
slot = planSlot;
tupleid = NULL;
oldtuple = NULL;
if (junkfilter != NULL)
{
if (operation == CMD_UPDATE || operation == CMD_DELETE)
{
relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
{
datum = ExecGetJunkAttribute(slot,
junkfilter->jf_junkAttNo,
&isNull);
if (isNull)
elog(ERROR, "ctid is NULL");
tupleid = (ItemPointer) DatumGetPointer(datum);
tuple_ctid = *tupleid;
tupleid = &tuple_ctid;
}
else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
{
datum = ExecGetJunkAttribute(slot,
junkfilter->jf_junkAttNo,
&isNull);
if (isNull)
elog(ERROR, "wholerow is NULL");
oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
oldtupdata.t_len =
HeapTupleHeaderGetDatumLength(oldtupdata.t_data);
ItemPointerSetInvalid(&(oldtupdata.t_self));
oldtupdata.t_tableOid =
(relkind == RELKIND_VIEW) ? InvalidOid :
RelationGetRelid(resultRelInfo->ri_RelationDesc);
oldtuple = &oldtupdata;
}
else
Assert(relkind == RELKIND_FOREIGN_TABLE);
}
if (operation != CMD_DELETE)
slot = ExecFilterJunk(junkfilter, slot);
}
switch (operation)
{
case CMD_INSERT:
if (proute)
slot = ExecPrepareTupleRouting(node, estate, proute,
resultRelInfo, slot);
slot = ExecInsert(node, slot, planSlot,
estate, node->canSetTag);
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);
break;
case CMD_DELETE:
slot = ExecDelete(node, tupleid, oldtuple, planSlot,
&node->mt_epqstate, estate,
true, node->canSetTag,
false , NULL, NULL);
break;
default:
elog(ERROR, "unknown operation");
break;
}
if (slot)
{
estate->es_result_relation_info = saved_resultRelInfo;
return slot;
}
}
estate->es_result_relation_info = saved_resultRelInfo;
fireASTriggers(node);
node->mt_done = true;
return NULL;