PostgreSQL源码学习插入数据#6

database

本节介绍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

回到顶部