这篇文章主要讲解了“PostgreSQL中ExecModifyTable函数的实现逻辑是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL中ExecModifyTable函数的实现逻辑是什么”吧!
一、基础信息
ExecModifyTable函数使用的数据结构、宏定义以及依赖的函数等。
数据结构/宏定义
1、PartitionTupleRouting
//分区表相关的数据结构,再续解读分区表处理时再行更新
typedef struct PartitionTupleRouting
{
PartitionDispatch *partition_dispatch_info;
int num_dispatch;
Oid *partition_oids;
ResultRelInfo **partitions;
int num_partitions;
TupleConversionMap **parent_child_tupconv_maps;
TupleConversionMap **child_parent_tupconv_maps;
bool *child_parent_map_not_required;
int *subplan_partition_offsets;
int num_subplan_partition_offsets;
TupleTableSlot *partition_tuple_slot;
TupleTableSlot *root_tuple_slot;
} PartitionTupleRouting;
2、CmdType
//命令类型,DDL命令都归到CMD_UTILITY里面了
typedef enum CmdType
{
CMD_UNKNOWN,
CMD_SELECT,
CMD_UPDATE,
CMD_INSERT,
CMD_DELETE,
CMD_UTILITY,
CMD_NOTHING
} CmdType;
3、JunkFilter
//运行期需要的Attribute成为junk attribute,实际的Tuple需要使用JunkFilter过滤这些属性
typedef struct JunkFilter
{
NodeTag type;
List *jf_targetList;
TupleDesc jf_cleanTupType;
AttrNumber *jf_cleanMap;
TupleTableSlot *jf_resultSlot;
AttrNumber jf_junkAttNo;
} JunkFilter;
4、Datum
//实际类型为unsigned long int ,无符号长整型整数
typedef uintptr_t Datum;
uintptr_t unsigned integer type capable of holding a pointer,defined in header <stdint.h>
typedef unsigned long int uintptr_t;
5、CHECK_FOR_INTERRUPTS
/ * The CHECK_FOR_INTERRUPTS() macro is called at strategically located spots
* where it is normally safe to accept a cancel or die interrupt. In some
* cases, we invoke CHECK_FOR_INTERRUPTS() inside low-level subroutines that
* might sometimes be called in contexts that do *not* want to allow a cancel
* or die interrupt. The HOLD_INTERRUPTS() and RESUME_INTERRUPTS() macros
* allow code to ensure that no cancel or die interrupt will be accepted,
* even if CHECK_FOR_INTERRUPTS() gets called in a subroutine. The interrupt
* will be held off until CHECK_FOR_INTERRUPTS() is done outside any
* HOLD_INTERRUPTS() ... RESUME_INTERRUPTS() section.
*/
#define CHECK_FOR_INTERRUPTS() \
do { \
if (InterruptPending) \
ProcessInterrupts(); \
} while(0)
依赖的函数
1、fireBSTriggers
//触发语句级的触发器
static void
fireBSTriggers(ModifyTableState *node)
{
ModifyTable *plan = (ModifyTable *) node->ps.plan;
ResultRelInfo *resultRelInfo = node->resultRelInfo;
if (node->rootResultRelInfo != NULL)
resultRelInfo = node->rootResultRelInfo;
switch (node->operation)
{
case CMD_INSERT:
ExecBSInsertTriggers(node->ps.state, resultRelInfo);
if (plan->onConflictAction == ONCONFLICT_UPDATE)
ExecBSUpdateTriggers(node->ps.state,
resultRelInfo);
break;
case CMD_UPDATE:
ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
break;
case CMD_DELETE:
ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
break;
default:
elog(ERROR, "unknown operation");
break;
}
}
2、ResetPerTupleExprContext
#define ResetPerTupleExprContext(estate) \
do { \
if ((estate)->es_per_tuple_exprcontext) \
ResetExprContext((estate)->es_per_tuple_exprcontext); \
} while (0)
3、ExecProcNode
//执行子计划时使用,这个函数同时也是高N级的函数,后续再行解读
4、TupIsNull
//判断TupleTableSlot 是否为Null(包括Empty)
#define TupIsNull(slot) \
((slot) == NULL || (slot)->tts_isempty)
5、EvalPlanQualSetPlan
//TODO
void
EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
{
EvalPlanQualEnd(epqstate);
epqstate->plan = subplan;
epqstate->arowMarks = auxrowmarks;
}
6、tupconv_map_for_subplan
//分区表使用,后续再行解析
//TODO
static TupleConversionMap *
tupconv_map_for_subplan(ModifyTableState *mtstate, int whichplan)
{
if (mtstate->mt_per_subplan_tupconv_maps == NULL)
{
int leaf_index;
PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
Assert(proute && proute->subplan_partition_offsets != NULL &&
whichplan < proute->num_subplan_partition_offsets);
leaf_index = proute->subplan_partition_offsets[whichplan];
return TupConvMapForLeaf(proute, getTargetResultRelInfo(mtstate),
leaf_index);
}
else
{
Assert(whichplan >= 0 && whichplan < mtstate->mt_nplans);
return mtstate->mt_per_subplan_tupconv_maps[whichplan];
}
}
7、ExecProcessReturning
//返回结果Tuple
//更详细的解读有待执行查询语句时的分析解读
static TupleTableSlot *
ExecProcessReturning(ResultRelInfo *resultRelInfo,
TupleTableSlot *tupleSlot,
TupleTableSlot *planSlot)
{
ProjectionInfo *projectReturning = resultRelInfo->ri_projectReturning;
ExprContext *econtext = projectReturning->pi_exprContext;
ResetExprContext(econtext);
if (tupleSlot)
econtext->ecxt_scantuple = tupleSlot;
else
{
HeapTuple tuple;
Assert(!TupIsNull(econtext->ecxt_scantuple));
tuple = ExecMaterializeSlot(econtext->ecxt_scantuple);
tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
}
econtext->ecxt_outertuple = planSlot;
return ExecProject(projectReturning);
}
typedef struct ProjectionInfo
{
NodeTag type;
ExprState pi_state;
ExprContext *pi_exprContext;
} ProjectionInfo;
typedef struct ExprContext
{
NodeTag type;
#define FIELDNO_EXPRCONTEXT_SCANTUPLE 1
TupleTableSlot *ecxt_scantuple;
#define FIELDNO_EXPRCONTEXT_INNERTUPLE 2
TupleTableSlot *ecxt_innertuple;
#define FIELDNO_EXPRCONTEXT_OUTERTUPLE 3
TupleTableSlot *ecxt_outertuple;
MemoryContext ecxt_per_query_memory;
MemoryContext ecxt_per_tuple_memory;
ParamExecData *ecxt_param_exec_vals;
ParamListInfo ecxt_param_list_info;
#define FIELDNO_EXPRCONTEXT_AGGVALUES 8
Datum *ecxt_aggvalues;
#define FIELDNO_EXPRCONTEXT_AGGNULLS 9
bool *ecxt_aggnulls;
#define FIELDNO_EXPRCONTEXT_CASEDATUM 10
Datum caseValue_datum;
#define FIELDNO_EXPRCONTEXT_CASENULL 11
bool caseValue_isNull;
#define FIELDNO_EXPRCONTEXT_DOMAINDATUM 12
Datum domainValue_datum;
#define FIELDNO_EXPRCONTEXT_DOMAINNULL 13
bool domainValue_isNull;
struct EState *ecxt_estate;
ExprContext_CB *ecxt_callbacks;
} ExprContext;
#ifndef FRONTEND
static inline TupleTableSlot *
ExecProject(ProjectionInfo *projInfo)
{
ExprContext *econtext = projInfo->pi_exprContext;
ExprState *state = &projInfo->pi_state;
TupleTableSlot *slot = state->resultslot;
bool isnull;
ExecClearTuple(slot);
(void) ExecEvalExprSwitchContext(state, econtext, &isnull);
slot->tts_isempty = false;
slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
return slot;
}
#endif
8、EvalPlanQualSetSlot
#define EvalPlanQualSetSlot(epqstate, slot) ((epqstate)->origslot = (slot))
9、ExecGetJunkAttribute
//获取Junk中的某个属性值
Datum
ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno,
bool *isNull)
{
Assert(attno > 0);
return slot_getattr(slot, attno, isNull);
}
10、DatumGetPointer
// 将无符号长整型转换为指针然后进行传递
#define DatumGetPointer(X) ((Pointer) (X))
11、AttributeNumberIsValid
//判断属性(号)是否合法
#define AttributeNumberIsValid(attributeNumber) \
((bool) ((attributeNumber) != InvalidAttrNumber))
12、DatumGetHeapTupleHeader
#define DatumGetHeapTupleHeader(X) ((HeapTupleHeader) PG_DETOAST_DATUM(X))
13、HeapTupleHeaderGetDatumLength
#define HeapTupleHeaderGetDatumLength(tup) \
VARSIZE(tup)
14、ItemPointerSetInvalid
//块号&块内偏移设置为Invalid
#define ItemPointerSetInvalid(pointer) \
( \
AssertMacro(PointerIsValid(pointer)), \
BlockIdSet(&((pointer)->ip_blkid), InvalidBlockNumber), \
(pointer)->ip_posid = InvalidOffsetNumber \
)
15、ExecFilterJunk
//去掉所有的Junk属性
TupleTableSlot *
ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
{
TupleTableSlot *resultSlot;
AttrNumber *cleanMap;
TupleDesc cleanTupType;
int cleanLength;
int i;
Datum *values;
bool *isnull;
Datum *old_values;
bool *old_isnull;
slot_getallattrs(slot);
old_values = slot->tts_values;
old_isnull = slot->tts_isnull;
cleanTupType = junkfilter->jf_cleanTupType;
cleanLength = cleanTupType->natts;
cleanMap = junkfilter->jf_cleanMap;
resultSlot = junkfilter->jf_resultSlot;
ExecClearTuple(resultSlot);
values = resultSlot->tts_values;
isnull = resultSlot->tts_isnull;
for (i = 0; i < cleanLength; i++)
{
int j = cleanMap[i];
if (j == 0)
{
values[i] = (Datum) 0;
isnull[i] = true;
}
else
{
values[i] = old_values[j - 1];
isnull[i] = old_isnull[j - 1];
}
}
return ExecStoreVirtualTuple(resultSlot);
}
16、ExecPrepareTupleRouting
//分区表使用,后续再行解析
static TupleTableSlot *
ExecPrepareTupleRouting(ModifyTableState *mtstate,
EState *estate,
PartitionTupleRouting *proute,
ResultRelInfo *targetRelInfo,
TupleTableSlot *slot)
{
ModifyTable *node;
int partidx;
ResultRelInfo *partrel;
HeapTuple tuple;
partidx = ExecFindPartition(targetRelInfo,
proute->partition_dispatch_info,
slot,
estate);
Assert(partidx >= 0 && partidx < proute->num_partitions);
partrel = proute->partitions[partidx];
if (partrel == NULL)
partrel = ExecInitPartitionInfo(mtstate, targetRelInfo,
proute, estate,
partidx);
if (!partrel->ri_PartitionReadyForRouting)
{
CheckValidResultRel(partrel, CMD_INSERT);
ExecInitRoutingInfo(mtstate, estate, proute, partrel, partidx);
}
estate->es_result_relation_info = partrel;
tuple = ExecMaterializeSlot(slot);
if (mtstate->mt_transition_capture != NULL)
{
if (partrel->ri_TrigDesc &&
partrel->ri_TrigDesc->trig_insert_before_row)
{
mtstate->mt_transition_capture->tcs_original_insert_tuple = NULL;
mtstate->mt_transition_capture->tcs_map =
TupConvMapForLeaf(proute, targetRelInfo, partidx);
}
else
{
mtstate->mt_transition_capture->tcs_original_insert_tuple = tuple;
mtstate->mt_transition_capture->tcs_map = NULL;
}
}
if (mtstate->mt_oc_transition_capture != NULL)
{
mtstate->mt_oc_transition_capture->tcs_map =
TupConvMapForLeaf(proute, targetRelInfo, partidx);
}
ConvertPartitionTupleSlot(proute->parent_child_tupconv_maps[partidx],
tuple,
proute->partition_tuple_slot,
&slot,
true);
Assert(mtstate != NULL);
node = (ModifyTable *) mtstate->ps.plan;
if (node->onConflictAction == ONCONFLICT_UPDATE)
{
Assert(mtstate->mt_existing != NULL);
ExecSetSlotDescriptor(mtstate->mt_existing,
RelationGetDescr(partrel->ri_RelationDesc));
Assert(mtstate->mt_conflproj != NULL);
ExecSetSlotDescriptor(mtstate->mt_conflproj,
partrel->ri_onConflict->oc_ProjTupdesc);
}
return slot;
}
17、ExecInsert
//上一节已解读
18、ExecUpdate/ExecDelete
//执行更新/删除,在后续实验Update/Delete时再行解析
19、fireASTriggers
//触发执行语句后的触发器(语句级)
static void
fireASTriggers(ModifyTableState *node)
{
ModifyTable *plan = (ModifyTable *) node->ps.plan;
ResultRelInfo *resultRelInfo = getTargetResultRelInfo(node);
switch (node->operation)
{
case CMD_INSERT:
if (plan->onConflictAction == ONCONFLICT_UPDATE)
ExecASUpdateTriggers(node->ps.state,
resultRelInfo,
node->mt_oc_transition_capture);
ExecASInsertTriggers(node->ps.state, resultRelInfo,
node->mt_transition_capture);
break;
case CMD_UPDATE:
ExecASUpdateTriggers(node->ps.state, resultRelInfo,
node->mt_transition_capture);
break;
case CMD_DELETE:
ExecASDeleteTriggers(node->ps.state, resultRelInfo,
node->mt_transition_capture);
break;
default:
elog(ERROR, "unknown operation");
break;
}
}
二、源码解读
static TupleTableSlot *
ExecModifyTable(PlanState *pstate)
{
ModifyTableState *node = castNode(ModifyTableState, pstate);//强制类型转换为ModifyTableState类型
PartitionTupleRouting *proute = node->mt_partition_tuple_routing;//分区表执行
EState *estate = node->ps.state;//执行器Executor状态
CmdType operation = node->operation;//命令类型
ResultRelInfo *saved_resultRelInfo;//结果RelationInfo
ResultRelInfo *resultRelInfo;//同上
PlanState *subplanstate;//子执行计划状态
JunkFilter *junkfilter;//无用属性过滤器
TupleTableSlot *slot;//Tuple存储的Slot指针
TupleTableSlot *planSlot;//Plan存储的Slot指针
ItemPointer tupleid;//Tuple行指针
ItemPointerData tuple_ctid;//Tuple行指针数据(Block号、偏移等)
HeapTupleData oldtupdata;//原Tuple数据
HeapTuple oldtuple;//原Tuple数据指针
CHECK_FOR_INTERRUPTS();//检查中断信号
if (estate->es_epqTuple != NULL)
elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
//已经完成,返回NULL
if (node->mt_done)
return NULL;
//语句级触发器触发
if (node->fireBSTriggers)
{
fireBSTriggers(node);
node->fireBSTriggers = false;
}
//预先构造本地变量
resultRelInfo = node->resultRelInfo + node->mt_whichplan;//设置正在操作的Relation,mt_whichplan是偏移
subplanstate = node->mt_plans[node->mt_whichplan];//执行计划的State
junkfilter = resultRelInfo->ri_junkFilter;//额外(无价值)的信息过滤器
//切换当前活跃的Relation
saved_resultRelInfo = estate->es_result_relation_info;
estate->es_result_relation_info = resultRelInfo;
for (;;)
{
ResetPerTupleExprContext(estate);//设置上下文
planSlot = ExecProcNode(subplanstate);//获取子Plan的Slot(插入数据操作返回值应为NULL)
if (TupIsNull(planSlot))//没有执行计划(执行计划已全部完成)
{
node->mt_whichplan++;//移至下一个执行Plan
if (node->mt_whichplan < node->mt_nplans)
{
resultRelInfo++;//切换至相应的Relation,如果是插入操作,只有一个
subplanstate = node->mt_plans[node->mt_whichplan];//切换至相应的子Plan状态
junkfilter = resultRelInfo->ri_junkFilter;//切换至相应的junkfilter
estate->es_result_relation_info = resultRelInfo;//切换
EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
node->mt_arowmarks[node->mt_whichplan]);//设置子Plan
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;//所有的Plan均已执行,跳出循环
}
//存在子Plan
if (resultRelInfo->ri_usesFdwDirectModify)
{
Assert(resultRelInfo->ri_projectReturning);
slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);//FDW,直接返回
estate->es_result_relation_info = saved_resultRelInfo;
return slot;
}
EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);//设置相应的Slot(子Plan Slot)
slot = planSlot;
tupleid = NULL;//Tuple ID
oldtuple = NULL;//原Tuple
if (junkfilter != NULL)//去掉废弃的属性
{
if (operation == CMD_UPDATE || operation == CMD_DELETE)//更新或者删除操作
{
char relkind;
Datum datum;
bool isNull;
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);//准备相应的Tuple 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,
NULL, true, node->canSetTag,
false );
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;
//Insert语句,返回NULL
return NULL;
}
三、跟踪分析
执行测试脚本:
alter table t_insert alter column c1 type varchar(40);
alter table t_insert alter column c2 type varchar(40);
alter table t_insert alter column c3 type varchar(40);
testdb=# select pg_backend_pid();
pg_backend_pid
----------------
1570
(1 row)
testdb=# insert into t_insert values(13,'ExecModifyTable','ExecModifyTable','ExecModifyTable');
(挂起)
启动gdb跟踪:
[root@localhost ~]# gdb -p 1570
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7
Copyright (C) 2013 Free Software Foundation, Inc.
...
(gdb) b ExecModifyTable
Breakpoint 1 at 0x6c2498: file nodeModifyTable.c, line 1915.
(gdb) c
Continuing.
Breakpoint 1, ExecModifyTable (pstate=0x2cde640) at nodeModifyTable.c:1915
1915 ModifyTableState *node = castNode(ModifyTableState, pstate);
#查看参数
(gdb) p *pstate
#PlanState
$1 = {type = T_ModifyTableState, plan = 0x2ce66c8, state = 0x2cde2f0, ExecProcNode = 0x6c2485 <ExecModifyTable>, ExecProcNodeReal = 0x6c2485 <ExecModifyTable>, instrument = 0x0,
worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2cdf3f0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,
scandesc = 0x0}
#执行计划Plan
(gdb) p *(pstate->plan)
$2 = {type = T_ModifyTable, startup_cost = 0, total_cost = 0.01, plan_rows = 1, plan_width = 298, parallel_aware = false, parallel_safe = false, plan_node_id = 0, targetlist = 0x0, qual = 0x0,
lefttree = 0x0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}
#执行计划对应的执行环境(State)
(gdb) p *(pstate->state)
$3 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x2ccac80, es_crosscheck_snapshot = 0x0, es_range_table = 0x2ce6970, es_plannedstmt = 0x2ce6a40,
es_sourceText = 0x2c1bef0 "insert into t_insert values(13,'ExecModifyTable','ExecModifyTable','ExecModifyTable');", es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x2cde530,
es_num_result_relations = 1, es_result_relation_info = 0x0, es_root_result_relations = 0x0, es_num_root_result_relations = 0, es_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0,
es_trig_tuple_slot = 0x2cdf4a0, es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0, es_param_exec_vals = 0x2cde500, es_queryEnv = 0x0, es_query_cxt = 0x2cde1e0,
es_tupleTable = 0x2cdeef0, es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0, es_finished = false, es_exprcontexts = 0x2cde8a0, es_subplanstates = 0x0,
es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epqTuple = 0x0, es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0,
es_jit = 0x0}
#结果Tuple Slot
(gdb) p *(pstate->ps_ResultTupleSlot)
$6 = {type = T_TupleTableSlot, tts_isempty = true, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x2cdf3c0, tts_mcxt = 0x2cde1e0,
tts_buffer = 0, tts_nvalid = 0, tts_values = 0x2cdf450, tts_isnull = 0x2cdf450, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 0},
t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}
#继续执行
#proute应为NULL
(gdb) p proute
$7 = (PartitionTupleRouting *) 0x0
#插入操作
(gdb) p operation
$9 = CMD_INSERT
#查看本地变量
(gdb) p resultRelInfo
$11 = (ResultRelInfo *) 0x2cde530
(gdb) p *resultRelInfo
$12 = {type = T_ResultRelInfo, ri_RangeTableIndex = 1, ri_RelationDesc = 0x7f3c13f56150, ri_NumIndices = 1, ri_IndexRelationDescs = 0x2cde8d0, ri_IndexRelationInfo = 0x2cde8e8, ri_TrigDesc = 0x0,
ri_TrigFunctions = 0x0, ri_TrigWhenExprs = 0x0, ri_TrigInstrument = 0x0, ri_FdwRoutine = 0x0, ri_FdwState = 0x0, ri_usesFdwDirectModify = false, ri_WithCheckOptions = 0x0,
ri_WithCheckOptionExprs = 0x0, ri_ConstraintExprs = 0x0, ri_junkFilter = 0x0, ri_returningList = 0x0, ri_projectReturning = 0x0, ri_onConflictArbiterIndexes = 0x0, ri_onConflict = 0x0,
ri_PartitionCheck = 0x0, ri_PartitionCheckExpr = 0x0, ri_PartitionRoot = 0x0, ri_PartitionReadyForRouting = false}
(gdb) p subplanstate
$13 = (PlanState *) 0x2cdea10
(gdb) p *subplanstate
$14 = {type = T_ResultState, plan = 0x2cd21f8, state = 0x2cde2f0, ExecProcNode = 0x69a78b <ExecProcNodeFirst>, ExecProcNodeReal = 0x6c5094 <ExecResult>, instrument = 0x0, worker_instrument = 0x0,
qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2cdedc0, ps_ExprContext = 0x2cdeb20, ps_ProjInfo = 0x2cdef20, scandesc = 0x0}
(gdb) p *(subplanstate->plan)
$15 = {type = T_Result, startup_cost = 0, total_cost = 0.01, plan_rows = 1, plan_width = 298, parallel_aware = false, parallel_safe = false, plan_node_id = 1, targetlist = 0x2cd22f8, qual = 0x0,
lefttree = 0x0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}
(gdb) p junkfilter
$18 = (JunkFilter *) 0x830
(gdb) p *junkfilter
Cannot access memory at address 0x830
gdb) next
1974 saved_resultRelInfo = estate->es_result_relation_info;
(gdb)
1976 estate->es_result_relation_info = resultRelInfo;
(gdb)
1990 ResetPerTupleExprContext(estate);
(gdb)
1992 planSlot = ExecProcNode(subplanstate);
(gdb) p *planSlot
$19 = {type = T_Invalid, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x3000000000064, tts_tupleDescriptor = 0x2c1dcb8, tts_mcxt = 0x2c,
tts_buffer = 0, tts_nvalid = 0, tts_values = 0x0, tts_isnull = 0x0, tts_mintuple = 0x0, tts_minhdr = {t_len = 512, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 57824}, t_tableOid = 0,
t_data = 0x3c}, tts_off = 47081160, tts_fixedTupleDescriptor = false}
(gdb) next
1994 if (TupIsNull(planSlot))
(gdb) p *planSlot
$20 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x2cdebb0, tts_mcxt = 0x2cde1e0,
tts_buffer = 0, tts_nvalid = 4, tts_values = 0x2cdee20, tts_isnull = 0x2cdee40, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 0},
t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}
(gdb) next
2027 if (resultRelInfo->ri_usesFdwDirectModify)
(gdb)
2043 EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
(gdb)
2044 slot = planSlot;
(gdb)
2046 tupleid = NULL;
(gdb)
2047 oldtuple = NULL;
(gdb)
2048 if (junkfilter != NULL)
(gdb)
2119 switch (operation)
(gdb) p junkfilter
$21 = (JunkFilter *) 0x0
(gdb) next
2123 if (proute)
(gdb)
2127 estate, node->canSetTag);
(gdb)
2126 slot = ExecInsert(node, slot, planSlot,
(gdb)
2129 if (proute)
(gdb) p *slot
Cannot access memory at address 0x0
(gdb) next
2151 if (slot)
(gdb)
2156 }
#进入第2轮循环
(gdb)
1990 ResetPerTupleExprContext(estate);
(gdb)
1992 planSlot = ExecProcNode(subplanstate);
(gdb) p *planSlot
$22 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = true, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x2cdf550, tts_tupleDescriptor = 0x2cdebb0, tts_mcxt = 0x2cde1e0,
tts_buffer = 0, tts_nvalid = 1, tts_values = 0x2cdee20, tts_isnull = 0x2cdee40, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 0},
t_tableOid = 0, t_data = 0x0}, tts_off = 4, tts_fixedTupleDescriptor = true}
(gdb) next
1994 if (TupIsNull(planSlot))
(gdb)
1997 node->mt_whichplan++;
(gdb) next
1998 if (node->mt_whichplan < node->mt_nplans)
(gdb) p *node
$23 = {ps = {type = T_ModifyTableState, plan = 0x2ce66c8, state = 0x2cde2f0, ExecProcNode = 0x6c2485 <ExecModifyTable>, ExecProcNodeReal = 0x6c2485 <ExecModifyTable>, instrument = 0x0,
worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2cdf3f0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,
scandesc = 0x0}, operation = CMD_INSERT, canSetTag = true, mt_done = false, mt_plans = 0x2cde850, mt_nplans = 1, mt_whichplan = 1, resultRelInfo = 0x2cde530, rootResultRelInfo = 0x0,
mt_arowmarks = 0x2cde868, mt_epqstate = {estate = 0x0, planstate = 0x0, origslot = 0x2cdedc0, plan = 0x2cd21f8, arowMarks = 0x0, epqParam = 0}, fireBSTriggers = false, mt_existing = 0x0,
mt_excludedtlist = 0x0, mt_conflproj = 0x0, mt_partition_tuple_routing = 0x0, mt_transition_capture = 0x0, mt_oc_transition_capture = 0x0, mt_per_subplan_tupconv_maps = 0x0}
//执行完毕,跳出循环
(gdb) next
2020 break;
(gdb) p *slot
Cannot access memory at address 0x0
(gdb) next
2159 estate->es_result_relation_info = saved_resultRelInfo;
(gdb) p saved_resultRelInfo
$24 = (ResultRelInfo *) 0x0
(gdb) next
2164 fireASTriggers(node);
(gdb) next
2166 node->mt_done = true;
(gdb)
#执行成功,返回NULL(Insert语句)
2168 return NULL;
感谢各位的阅读,以上就是“PostgreSQL中ExecModifyTable函数的实现逻辑是什么”的内容了,经过本文的学习后,相信大家对PostgreSQL中ExecModifyTable函数的实现逻辑是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!