PostgreSQL源码学习–插入数据#6[亲测有效]

PostgreSQL源码学习–插入数据#6[亲测有效]本节介绍ExecModifyTable函数。 相关数据结构 typedef struct ModifyTableState { PlanState ps; /* its first field is…

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;

代码100分

ExecModifyTable函数

代码100分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;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/8024.html

(0)
上一篇 2023-03-09
下一篇 2023-03-09

相关推荐

  • mybatisplus代码生成工具_魔兽lua代码一键生成

    mybatisplus代码生成工具_魔兽lua代码一键生成Mybatis-Plus一键生成代码 一、闲言碎语 闲来无事看了看了MP的官网看到一键生成的代码更新了! 整个Ui风格都变了,遂决定瞅一眼新的代码生成器 官网地址~~ 二、引入依赖 新的代码生成只有在

    2023-05-02
    149
  • mysql 使用 limit ,从指定条数读取完,-1失效「建议收藏」

    mysql 使用 limit ,从指定条数读取完,-1失效「建议收藏」SELECT * FROM `wit_honor` order by `order` limit 15,-1 原因很简单这种写法本身就是错的,虽然它可以在之前的版本中运行(低优先级),新版本的mysq

    2023-01-31
    164
  • Redis阻塞_redis订阅发布堵塞问题

    Redis阻塞_redis订阅发布堵塞问题可能存在问题 内在原因:API或数据结构使用不合理、CPU饱和、持久化阻塞等 外在原因:CPU竞争、内存交换、网络问题等 问题处理: API或数据结构使用不合理,可能存在慢查询或者大对象: 发现慢查…

    2023-04-01
    162
  • 使用Python的PDFkit生成PDF文件

    使用Python的PDFkit生成PDF文件在现代生活中,PDF文件被广泛应用于文档展示、电子书籍、证书以及合同等多种场合。使用Python的PDFkit生成PDF文件是一种高效的方法,可以增加用户交互性和文档性能,同时降低了开发难度。接下来,我们将详细介绍如何使用Python的PDFkit生成PDF文件。

    2024-05-18
    62
  • 前端工程化之H5性能优化篇

    前端工程化之H5性能优化篇  导读:从粗糙到精致,从简单到复杂,全球互联网Web App(网页应用)平均体积已增压到1.6Mb,随着音视频等富媒体内容的流量池膨胀,终端设备上的用户对网页装载速度尤其敏感。页面不能做到秒开,就…

    2023-04-13
    156
  • 关于几岁可以开始学python的信息

    关于几岁可以开始学python的信息python十岁适合学。

    2023-10-29
    149
  • ClickHouse(09)ClickHouse合并树MergeTree家族表引擎之MergeTree详细解析[通俗易懂]

    ClickHouse(09)ClickHouse合并树MergeTree家族表引擎之MergeTree详细解析[通俗易懂]Clickhouse中最强大的表引擎当属MergeTree(合并树)引擎及该系列(MergeTree)中的其他引擎。MergeTree系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片

    2023-06-13
    149
  • Python的锚点用法

    Python的锚点用法在网页设计中,锚点是指将文本或图像与文档中其他部分相关联的一种超链接,通常用于快速定位到网页的特定部分。Python语言作为一种广泛应用的编程语言,其内置的a href=”#anchor”锚点功能/a可以帮助我们更好地管理和组织代码,提高代码的可读性和可维护性。

    2023-12-17
    116

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注