跟我一起读postgresql源码(十六)——Executor(查询执行模块之——control节点(下)) (3)

(1)首先要将需要插入的tuple从slot中取出,本地化。why?因为这个slot在随后的操作heap_insert函数中可能不安全,因此将其提前取出来。这个工作由ExecMaterializeSlot函数完成。

(2)从全局状态中estate->es_result_relation_info获取信息,判断result relation是否需要一个oid。如果需要,则先将tuple中的oid字段设为0。

(3)处理BEFORE ROW INSERT Triggers。这里我们要注意这个触发器是ROW级别的,而BEFORE STATEMENT triggers是语句级别的,他们不一样。

(4)处理INSTEAD OF ROW INSERT Triggers。如果存在则调用ExecIRInsertTriggers函数去处理并直接返回,不进行INSERT操作。

(5)处理foreign table的情况,为其初始化ri_FdwRoutine。调用foreign server的API去处理该条元组的插入并获取返回的slot

(6)处理WITH CHECK OPTION中的条件(ExecWithCheckOptions函数)和唯一性约束(ExecConstraints函数)ON ONCONFLICT OPTION。

(7)如果存在ON ONCONFLICT OPTION条件,则先获得speculative insertion lock,调用heap_insert函数将元组插入到堆表中。如果插入成功,不发生冲突则正常释放该lock。否则强制释放lock,并执行ON ONCONFLICT DO UPDATE(如果有的话)。

(8)不存在(7)中的条件,我们正常地调用heap_insert函数将元组插入到堆表中。同时调用ExecInsertIndexTuples函数插入相应的索引元组。

(9)调用ExecARInsertTriggers函数处理AFTER ROW INSERT Triggers。类似(3)的处理。

(10)还记得上面提到的CREATE VIEW中的WITH CHECK OPTION么?这里调用ExecWithCheckOptions函数做处理,不满足则报错退出。

(11)如果存在RETURNING子句,我们调用ExecProcessReturning函数处理之。

2.ExecDelete

ExecDelete函数相对简单,他只需要将元组删除即可,不需要针对索引做任何操作。

(1)从全局状态中estate->es_result_relation_info获取信息。

(2)处理BEFORE ROW DELETE Triggers。这里我们要注意这个触发器是ROW级别的,而BEFORE STATEMENT triggers是语句级别的,他们不一样。

(3)处理INSTEAD OF ROW DELETE Triggers。如果存在则调用ExecIRDeleteTriggers函数去处理并直接返回,不进行INSERT操作。

(4)处理foreign table的情况,为其初始化ri_FdwRoutine。调用foreign server的API去处理该条元组的删除并获取返回的slot。

(5)我们正常地调用heap_delete函数执行DELETE操作。如果返回值不是HeapTupleMayBeUpdated则说明操作失败,根据失败的错误代码执行相应的处理。

(6)调用ExecARDeleteTriggers函数处理AFTER ROW DELETE Triggers。类似(2)的处理。

(7)如果存在RETURNING子句,我们调用ExecProcessReturning函数处理之。

3.ExecUpdate

ExecUpdate函数实际上执行的是"INSERT"操作。因为postgres内部是MVCC机制,多版本并发控制。旧的元组实际上没有删除,只是不再引用。同时,UPDATE操作在数据库内部也是要在"transaction"中的,否则postgres会不停的将新增的updated元组看成是需要update的元组,循环下去。

(1)判断当前是否属于BootstrapProcessing模式,在该模式下所有的transaction id都被设置为1。这个时候才能保证不循环更新。

(2)首先要将需要插入的tuple从slot中取出,本地化。why?因为这个slot在随后的操作heap_update函数中可能不安全,因此将其提前取出来。这个工作由ExecMaterializeSlot函数完成。

(3)处理BEFORE ROW UPDATE Triggers。

(4)处理INSTEAD OF ROW UPDATE Triggers。如果存在则调用ExecIRUpdateTriggers函数去处理并直接返回,不进行INSERT操作。

(5)处理foreign table的情况,为其初始化ri_FdwRoutine。调用foreign server的API去处理该条元组的更新并获取返回的slot。

(6)处理WITH CHECK OPTION中的条件(ExecWithCheckOptions函数)和唯一性约束(ExecConstraints函数)ON ONCONFLICT OPTION。

(7)我们正常地调用heap_update函数执行UPDATE、操作。如果返回值不是HeapTupleMayBeUpdated则说明操作失败,根据失败的错误代码执行相应的处理。如果成功,则调用ExecInsertIndexTuples函数向索引中插入索引元组。

(8)调用ExecARUpdateTriggers函数处理AFTER ROW UPDATE Triggers。

(9)针对表的上层VIEW再次执行WITH CHECK OPTION。

(10)如果存在RETURNING子句,我们调用ExecProcessReturning函数处理之。

ModifyTable节点的清理简单些了(ExecEndModifyTable函数)。除了常规的清理工作,清理可能存在FDW结构,清理初始化中额外初始化的那些subplans节点。

control节点到此结束。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdgxf.html