PostgreSQL源码学习插入数据#6
本节介绍ExecModifyTable函数。
相关数据结构
typedef struct ModifyTableState{
PlanState ps; /* its first field is NodeTag */
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
bool mt_done; /* are we done? */
PlanState **mt_plans; /* subplans (one per target rel) */
int mt_nplans; /* number of plans in the array */
int mt_whichplan; /* which one is being executed (0..n-1) */
TupleTableSlot **mt_scans; /* input tuple corresponding to underlying
* plans */
ResultRelInfo *resultRelInfo; /* per-subplan target relations */
ResultRelInfo *rootResultRelInfo; /* root target relation (partitioned
* table root) */
List **mt_arowmarks; /* per-subplan ExecAuxRowMark lists */
EPQState mt_epqstate; /* for evaluating EvalPlanQual rechecks */
bool fireBSTriggers; /* do we need to fire stmt triggers? */
List *mt_excludedtlist; /* the excluded pseudo relation"s tlist */
/*
* Slot for storing tuples in the root partitioned table"s rowtype during
* an UPDATE of a partitioned table.
*/
TupleTableSlot *mt_root_tuple_slot;
/* Tuple-routing support info */
struct PartitionTupleRouting *mt_partition_tuple_routing;
/* controls transition table population for specified operation */
struct TransitionCaptureState *mt_transition_capture;
/* controls transition table population for INSERT...ON CONFLICT UPDATE */
struct TransitionCaptureState *mt_oc_transition_capture;
/* Per plan map for tuple conversion from child to root */
TupleConversionMap **mt_per_subplan_tupconv_maps;
} ModifyTableState;
ExecModifyTable函数
static TupleTableSlot *ExecModifyTable(PlanState *pstate);
/* 检查是否有中断信号 */CHECK_FOR_INTERRUPTS();
/* ModifyTable不应该在EvalPlanQual操作中执行 */
if (estate->es_epq_active != NULL)
elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
/* 是否已经完成 */
if (node->mt_done)
return NULL;
/* 启动BEFORE STATEMENT触发器 */
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;
/* es_result_relation_info应该指向当前活动的relation */
saved_resultRelInfo = estate->es_result_relation_info;
estate->es_result_relation_info = resultRelInfo;
/* 从子计划中获取rows,并且对每行执行所需的表修改操作 */
for (;;)
{
/* 重置每个输出元组的expr上下文 */
ResetPerTupleExprContext(estate);
/* 重置用于处理冲突和返回子句的每行元组的内存上下文,
* 以释放在前一个周期中分配的任何表达式求值存储 */
if (pstate->ps_ExprContext)
ResetExprContext(pstate->ps_ExprContext);
/* 获取子计划返回的slot */
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]);
/* 获取此子计划的元组转换map */
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;
}
/* 若是fdwDirectModify,接下来只需要计算RETURNING表达式就执行完成了 */
if (resultRelInfo->ri_usesFdwDirectModify)
{
Assert(resultRelInfo->ri_projectReturning);
slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
estate->es_result_relation_info = saved_resultRelInfo;
return slot;
}
/* 设置子plan的slot */
EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
slot = planSlot;
tupleid = NULL;
oldtuple = NULL;
/* 过滤一些属性 */
if (junkfilter != NULL)
{
/* 提取"ctd"或"wholerow"这些“垃圾”属性 */
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);
/* shouldn"t ever get a null result... */
if (isNull)
elog(ERROR, "ctid is NULL");
tupleid = (ItemPointer) DatumGetPointer(datum);
tuple_ctid = *tupleid; /* be sure we don"t free ctid!! */
tupleid = &tuple_ctid;
}
/* 使用wholerow属性(如果可用)重建旧的关系元组。*/
else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
{
datum = ExecGetJunkAttribute(slot,
junkfilter->jf_junkAttNo,
&isNull);
/* shouldn"t ever get a null result... */
if (isNull)
elog(ERROR, "wholerow is NULL");
oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
oldtupdata.t_len =
HeapTupleHeaderGetDatumLength(oldtupdata.t_data);
ItemPointerSetInvalid(&(oldtupdata.t_self));
/* 历史原因,试图触发器会看到非法的t_tableOid. */
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);
/* 还原ExecPrepareTupleRouting的状态更改 */
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 /* changingPart */ , NULL, NULL);
break;
default:
elog(ERROR, "unknown operation");
break;
}
/* 如果有返回结果,返回给调用者。下此调用本函数时会继续执行 */
if (slot)
{
estate->es_result_relation_info = saved_resultRelInfo;
return slot;
}
}
/* 结束函数前恢复es_result_relation_info */
estate->es_result_relation_info = saved_resultRelInfo;
/* 启动AFTER STATEMENT触发器 */
fireASTriggers(node);
node->mt_done = true;
return NULL;
以上是 PostgreSQL源码学习插入数据#6 的全部内容, 来源链接: utcz.com/z/534037.html