千家信息网

PostgreSQL 源码解读(15)- Insert语句(执行过程跟踪)

发表于:2024-10-01 作者:千家信息网编辑
千家信息网最后更新 2024年10月01日,本文简单介绍了PG INSERT语句的执行全过程,包括使用gdb跟踪调试的全过程,重点的数据结构等。一、调用栈INSERT语句的函数调用栈:(gdb) bt#0 PageAddItemExtende
千家信息网最后更新 2024年10月01日PostgreSQL 源码解读(15)- Insert语句(执行过程跟踪)

本文简单介绍了PG INSERT语句的执行全过程,包括使用gdb跟踪调试的全过程,重点的数据结构等。

一、调用栈

INSERT语句的函数调用栈:

(gdb) bt#0  PageAddItemExtended (page=0x7feaaefac300 "\001", item=0x29859f8 "2\234\030", size=61, offsetNumber=0, flags=2) at bufpage.c:196#1  0x00000000004cf4f9 in RelationPutHeapTuple (relation=0x7feac6e2ccb8, buffer=141, tuple=0x29859e0, token=false) at hio.c:53#2  0x00000000004c34ec in heap_insert (relation=0x7feac6e2ccb8, tup=0x29859e0, cid=0, options=0, bistate=0x0) at heapam.c:2487#3  0x00000000006c076b in ExecInsert (mtstate=0x2984c10, slot=0x2985250, planSlot=0x2985250, estate=0x29848c0, canSetTag=true) at nodeModifyTable.c:529#4  0x00000000006c29f3 in ExecModifyTable (pstate=0x2984c10) at nodeModifyTable.c:2126#5  0x000000000069a7d8 in ExecProcNodeFirst (node=0x2984c10) at execProcnode.c:445#6  0x0000000000690994 in ExecProcNode (node=0x2984c10) at ../../../src/include/executor/executor.h:237#7  0x0000000000692e5e in ExecutePlan (estate=0x29848c0, planstate=0x2984c10, use_parallel_mode=false, operation=CMD_INSERT, sendTuples=false, numberTuples=0, direction=ForwardScanDirection,     dest=0x2990dc8, execute_once=true) at execMain.c:1726#8  0x0000000000690e58 in standard_ExecutorRun (queryDesc=0x2981020, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:363#9  0x0000000000690cef in ExecutorRun (queryDesc=0x2981020, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:306#10 0x0000000000851d84 in ProcessQuery (plan=0x2990c68, sourceText=0x28c5ef0 "insert into t_insert values(9,'11','12','13');", params=0x0, queryEnv=0x0, dest=0x2990dc8, completionTag=0x7ffdbc052d10 "")    at pquery.c:161#11 0x00000000008534f4 in PortalRunMulti (portal=0x292b490, isTopLevel=true, setHoldSnapshot=false, dest=0x2990dc8, altdest=0x2990dc8, completionTag=0x7ffdbc052d10 "") at pquery.c:1286#12 0x0000000000852b32 in PortalRun (portal=0x292b490, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x2990dc8, altdest=0x2990dc8, completionTag=0x7ffdbc052d10 "") at pquery.c:799#13 0x000000000084cebc in exec_simple_query (query_string=0x28c5ef0 "insert into t_insert values(9,'11','12','13');") at postgres.c:1122#14 0x0000000000850f3c in PostgresMain (argc=1, argv=0x28efaa8, dbname=0x28ef990 "testdb", username=0x28ef978 "xdb") at postgres.c:4153#15 0x00000000007c0168 in BackendRun (port=0x28e7970) at postmaster.c:4361#16 0x00000000007bf8fc in BackendStartup (port=0x28e7970) at postmaster.c:4033#17 0x00000000007bc139 in ServerLoop () at postmaster.c:1706#18 0x00000000007bb9f9 in PostmasterMain (argc=1, argv=0x28c0b60) at postmaster.c:1379#19 0x00000000006f19e8 in main (argc=1, argv=0x28c0b60) at main.c:228

二、跟踪分析

插入测试数据:

testdb=# -- 获取pidtestdb=# select pg_backend_pid(); pg_backend_pid ----------------           1610(1 row)testdb=# -- 插入1行testdb=# insert into t_insert values(25,'insert','insert','insert');(挂起)

启动gdb,跟踪调试:

[root@localhost ~]# gdb -p 3294GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7Copyright (C) 2013 Free Software Foundation, Inc....#设置断点(gdb) b PostgresMain Breakpoint 1 at 0x8507bb: file postgres.c, line 3631.(gdb) b exec_simple_query Breakpoint 2 at 0x84cad8: file postgres.c, line 893.(gdb) b PortalRunMulti Breakpoint 3 at 0x8533df: file pquery.c, line 1210.…(gdb) cContinuing.Breakpoint 2, exec_simple_query (    query_string=0x219cef0 "insert into t_insert values(25,'insert','insert','insert');") at postgres.c:893893     CommandDest dest = whereToSendOutput;#PostmasterMain 的调试需要使用fork process的方式进行,不是重点,暂时不作介绍#进入exec_simple_query#输入参数:query_string=0x219cef0 "insert into t_insert values(25,'insert','insert','insert');"#生成解析列表,解析列表parsetree_list中的元素类型为RawStmt#INSERT语句,RawStmt的NodeType=T_InsertStmt(gdb) 944     parsetree_list = pg_parse_query(query_string);(gdb) p *parsetree_list$11 = {type = T_List, length = 1, head = 0x219dce0, tail = 0x219dce0}(gdb) p *(RawStmt *)(parsetree_list->head->data.ptr_value)$12 = {type = T_RawStmt, stmt = 0x219dc60, stmt_location = 0, stmt_len = 58}(gdb) p *((RawStmt *)(parsetree_list->head->data.ptr_value))->stmt$13 = {type = T_InsertStmt}#生成查询列表querytree_list,其中的元素为Query(gdb) 1047            querytree_list = pg_analyze_and_rewrite(parsetree, query_string,(gdb) p *(Query *)(querytree_list->head->data.ptr_value)$14 = {type = T_Query, commandType = CMD_INSERT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true,   utilityStmt = 0x0, resultRelation = 1, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false,   hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false,   hasForUpdate = false, hasRowSecurity = false, cteList = 0x0, rtable = 0x219e260, jointree = 0x21c2a50,   targetList = 0x21c2ad0, override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0,   groupClause = 0x0, groupingSets = 0x0, havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0,   sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, rowMarks = 0x0, setOperations = 0x0,   constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = 0, stmt_len = 58}(gdb) p *querytree_list$15 = {type = T_List, length = 1, head = 0x21c2b80, tail = 0x21c2b80}#查看Query中的元素#rtable,List中的实际类型为RangeTblEntry,可以理解为实际的数据表(gdb) p *((Query *)(querytree_list->head->data.ptr_value))->rtable$16 = {type = T_List, length = 1, head = 0x219e240, tail = 0x219e240}(gdb) p *(RangeTblEntry *)((Query *)(querytree_list->head->data.ptr_value))->rtable->head->data.ptr_value$17 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 26731, relkind = 114 'r', tablesample = 0x0,   subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0,   funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0,   self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0,   enrtuples = 0, alias = 0x0, eref = 0x219e060, lateral = false, inh = false, inFromCl = false,   requiredPerms = 1, checkAsUser = 0, selectedCols = 0x0, insertedCols = 0x21c28e8, updatedCols = 0x0,   securityQuals = 0x0}#jointree为NULL(gdb)  p *((Query *)(querytree_list->head->data.ptr_value))->jointree$18 = {type = T_FromExpr, fromlist = 0x0, quals = 0x0}#targetList是输出的目标Entry(数据列)(gdb) p *(TargetEntry *)((Query *)(querytree_list->head->data.ptr_value))->targetList->head->data.ptr_value$20 = {xpr = {type = T_TargetEntry}, expr = 0x219e590, resno = 1, resname = 0x219e2e0 "id",   ressortgroupref = 0, resorigtbl = 0, resorigcol = 0, resjunk = false}(gdb) n1054            if (snapshot_set)#生成PlannedStmt列表(gdb) p *plantree_list$21 = {type = T_List, length = 1, head = 0x225e488, tail = 0x225e488}(gdb)  p *(PlannedStmt *)(plantree_list->head->data.ptr_value)$22 = {type = T_PlannedStmt, commandType = CMD_INSERT, queryId = 0, hasReturning = false,   hasModifyingCTE = false, canSetTag = true, transientPlan = false, dependsOnRole = false,   parallelModeNeeded = false, jitFlags = 0, planTree = 0x225dfe8, rtable = 0x225e2a8,   resultRelations = 0x225e348, nonleafResultRelations = 0x0, rootResultRelations = 0x0, subplans = 0x0,   rewindPlanIDs = 0x0, rowMarks = 0x0, relationOids = 0x225e2f8, invalItems = 0x0,   paramExecTypes = 0x21c4320, utilityStmt = 0x0, stmt_location = 0, stmt_len = 58}#查看planTree(执行计划树)(gdb)  p *((PlannedStmt *)(plantree_list->head->data.ptr_value))->planTree$23 = {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}...#继续执行,进入PortalRunMulti(gdb) cContinuing.Breakpoint 3, PortalRunMulti (portal=0x2202490, isTopLevel=true, setHoldSnapshot=false, dest=0x225e4d8,     altdest=0x225e4d8, completionTag=0x7ffd6452f100 "") at pquery.c:12101210        bool        active_snapshot_set = false;#portal参数,其中stmts是已生成的PlannedStmt(gdb) p *portal$25 = {name = 0x2205e98 "", prepStmtName = 0x0, portalContext = 0x2252460, resowner = 0x21cdd10,   cleanup = 0x62f15c , createSubid = 1, activeSubid = 1,   sourceText = 0x219cef0 "insert into t_insert values(25,'insert','insert','insert');",   commandTag = 0xb50908 "INSERT", stmts = 0x225e4a8, cplan = 0x0, portalParams = 0x0, queryEnv = 0x0,   strategy = PORTAL_MULTI_QUERY, cursorOptions = 4, run_once = true, status = PORTAL_ACTIVE,   portalPinned = false, autoHeld = false, queryDesc = 0x0, tupDesc = 0x0, formats = 0x0, holdStore = 0x0,   holdContext = 0x0, holdSnapshot = 0x0, atStart = true, atEnd = true, portalPos = 0,   creation_time = 587211499048183, visible = false}(gdb) p *(portal->stmts)$26 = {type = T_List, length = 1, head = 0x225e488, tail = 0x225e488}(gdb) p *(PlannedStmt *)(portal->stmts->head.data->ptr_value)$27 = {type = T_PlannedStmt, commandType = CMD_INSERT, queryId = 0, hasReturning = false,   hasModifyingCTE = false, canSetTag = true, transientPlan = false, dependsOnRole = false,   parallelModeNeeded = false, jitFlags = 0, planTree = 0x225dfe8, rtable = 0x225e2a8,   resultRelations = 0x225e348, nonleafResultRelations = 0x0, rootResultRelations = 0x0, subplans = 0x0,   rewindPlanIDs = 0x0, rowMarks = 0x0, relationOids = 0x225e2f8, invalItems = 0x0,   paramExecTypes = 0x21c4320, utilityStmt = 0x0, stmt_location = 0, stmt_len = 58}#进入ProcessQuery(gdb) cContinuing.Breakpoint 4, ProcessQuery (plan=0x225e378,     sourceText=0x219cef0 "insert into t_insert values(26,'insert','insert','insert');", params=0x0,     queryEnv=0x0, dest=0x225e4d8, completionTag=0x7ffd6452f100 "") at pquery.c:149149     queryDesc = CreateQueryDesc(plan, sourceText,#输入参数,plan=PlannedStmt变量(gdb) p *plan$29 = {type = T_PlannedStmt, commandType = CMD_INSERT, queryId = 0, hasReturning = false,   hasModifyingCTE = false, canSetTag = true, transientPlan = false, dependsOnRole = false,   parallelModeNeeded = false, jitFlags = 0, planTree = 0x225dfe8, rtable = 0x225e2a8,   resultRelations = 0x225e348, nonleafResultRelations = 0x0, rootResultRelations = 0x0, subplans = 0x0,   rewindPlanIDs = 0x0, rowMarks = 0x0, relationOids = 0x225e2f8, invalItems = 0x0,   paramExecTypes = 0x21c4320, utilityStmt = 0x0, stmt_location = 0, stmt_len = 58}#QueryDesc查询描述符结构体,plannedstmt为先前生成的PlannedStmt(gdb) p *queryDesc$30 = {operation = CMD_INSERT, plannedstmt = 0x225e378,   sourceText = 0x219cef0 "insert into t_insert values(26,'insert','insert','insert');",   snapshot = 0x21c0920, crosscheck_snapshot = 0x0, dest = 0x225e4d8, params = 0x0, queryEnv = 0x0,   instrument_options = 0, tupDesc = 0x0, estate = 0x0, planstate = 0x0, already_executed = false,   totaltime = 0x0}#进入standard_ExecutorRun,queryDesc为查询描述符(gdb) cContinuing.Breakpoint 5, standard_ExecutorRun (queryDesc=0x2252570, direction=ForwardScanDirection, count=0,     execute_once=true) at execMain.c:322322     estate = queryDesc->estate;#ProcessQuery函数构建了PlanState/EState(ExecutorState)/tupDesc,为Execute作准备(gdb) p *queryDesc$31 = {operation = CMD_INSERT, plannedstmt = 0x225e378,   sourceText = 0x219cef0 "insert into t_insert values(26,'insert','insert','insert');",   snapshot = 0x21c0920, crosscheck_snapshot = 0x0, dest = 0x225e4d8, params = 0x0, queryEnv = 0x0,   instrument_options = 0, tupDesc = 0x2254d50, estate = 0x2253c80, planstate = 0x2253fd0,   already_executed = false, totaltime = 0x0}(gdb) p *(queryDesc->estate)$32 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x21c0920,   es_crosscheck_snapshot = 0x0, es_range_table = 0x225e2a8, es_plannedstmt = 0x225e378,   es_sourceText = 0x219cef0 "insert into t_insert values(26,'insert','insert','insert');",   es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x2253ec0, 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 = 0x2254e30,   es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0,   es_param_exec_vals = 0x2253e90, es_queryEnv = 0x0, es_query_cxt = 0x2253b70, es_tupleTable = 0x2254880,   es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0,   es_finished = false, es_exprcontexts = 0x2254230, 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}(gdb) p *(queryDesc->planstate)$33 = {type = T_ModifyTableState, plan = 0x225dfe8, state = 0x2253c80,   ExecProcNode = 0x69a78b , ExecProcNodeReal = 0x6c2485 ,   instrument = 0x0, worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0,   subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2254d80, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,   scandesc = 0x0}(gdb) p *(queryDesc->tupDesc)$34 = {natts = 0, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0,   attrs = 0x2254d70}#进入ExecutePlan(gdb) cContinuing.Breakpoint 6, ExecutePlan (estate=0x2253c80, planstate=0x2253fd0, use_parallel_mode=false,     operation=CMD_INSERT, sendTuples=false, numberTuples=0, direction=ForwardScanDirection, dest=0x225e4d8,     execute_once=true) at execMain.c:16971697        current_tuple_count = 0;#输入参数,EState/PlanState,准备执行SQL(gdb) p *estate$35 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x21c0920,   es_crosscheck_snapshot = 0x0, es_range_table = 0x225e2a8, es_plannedstmt = 0x225e378,   es_sourceText = 0x219cef0 "insert into t_insert values(26,'insert','insert','insert');",   es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x2253ec0, 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 = 0x2254e30,   es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0,   es_param_exec_vals = 0x2253e90, es_queryEnv = 0x0, es_query_cxt = 0x2253b70, es_tupleTable = 0x2254880,   es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0,   es_finished = false, es_exprcontexts = 0x2254230, 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}(gdb) p *planstate$36 = {type = T_ModifyTableState, plan = 0x225dfe8, state = 0x2253c80,   ExecProcNode = 0x69a78b , ExecProcNodeReal = 0x6c2485 ,   instrument = 0x0, worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0,   subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2254d80, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,   scandesc = 0x0}#在ExecutePlan函数中执行ExecProcNode,直至ExecProcNode函数返回的TupleTableSlot为空才退出循环1726            slot = ExecProcNode(planstate);(gdb) #进入ExecProcNode#执行PlanState的ExecProcNode函数,即ExecProcNodeFirstBreakpoint 7, ExecProcNode (node=0x2253fd0) at ../../../src/include/executor/executor.h:234234     if (node->chgParam != NULL) /* something changed? */(gdb) 237     return node->ExecProcNode(node);(gdb) #进入ExecProcNodeFirstBreakpoint 8, ExecProcNodeFirst (node=0x2253fd0) at execProcnode.c:433433     check_stack_depth();#执行node的ExecProcNode函数,即ExecModifyTable(注:PlanState中的ExecProcNodeReal)(gdb) p *node$37 = {type = T_ModifyTableState, plan = 0x225dfe8, state = 0x2253c80,   ExecProcNode = 0x6c2485 , ExecProcNodeReal = 0x6c2485 ,   instrument = 0x0, worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0,   subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2254d80, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,   scandesc = 0x0}...#在for循环中执行subplanstate的ExecProcNode,同样的,如果返回的Slot为NULL则退出(gdb) p subplanstate$38 = (PlanState *) 0x22543a0(gdb) p *subplanstate #node->mt_plans[node->mt_whichplan];//执行计划的State$39 = {type = T_ResultState, plan = 0x21c44e0, state = 0x2253c80,   ExecProcNode = 0x69a78b , ExecProcNodeReal = 0x6c5094 , instrument = 0x0,   worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0,   chgParam = 0x0, ps_ResultTupleSlot = 0x2254750, ps_ExprContext = 0x22544b0, ps_ProjInfo = 0x22548b0,   scandesc = 0x0}(gdb) p *node$40 = {ps = {type = T_ModifyTableState, plan = 0x225dfe8, state = 0x2253c80,     ExecProcNode = 0x6c2485 , ExecProcNodeReal = 0x6c2485 ,     instrument = 0x0, worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0,     subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2254d80, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,     scandesc = 0x0}, operation = CMD_INSERT, canSetTag = true, mt_done = false, mt_plans = 0x22541e0,   mt_nplans = 1, mt_whichplan = 0, resultRelInfo = 0x2253ec0, rootResultRelInfo = 0x0,   mt_arowmarks = 0x22541f8, mt_epqstate = {estate = 0x0, planstate = 0x0, origslot = 0x0, plan = 0x21c44e0,     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) n1974        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) Breakpoint 7, ExecProcNode (node=0x22543a0) at ../../../src/include/executor/executor.h:234234     if (node->chgParam != NULL) /* something changed? */(gdb) 237     return node->ExecProcNode(node);(gdb) #再次进入ExecProcNodeFirst,Node变为T_ResultStateBreakpoint 8, ExecProcNodeFirst (node=0x22543a0) at execProcnode.c:433433     check_stack_depth();(gdb) 440     if (node->instrument)(gdb) 443         node->ExecProcNode = node->ExecProcNodeReal;(gdb) 445     return node->ExecProcNode(node);(gdb) p *node$41 = {type = T_ResultState, plan = 0x21c44e0, state = 0x2253c80, ExecProcNode = 0x6c5094 ,   ExecProcNodeReal = 0x6c5094 , instrument = 0x0, worker_instrument = 0x0, qual = 0x0,   lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0,   ps_ResultTupleSlot = 0x2254750, ps_ExprContext = 0x22544b0, ps_ProjInfo = 0x22548b0, scandesc = 0x0}(gdb) #进入ExecInsert2126                    slot = ExecInsert(node, slot, planSlot,(gdb) Breakpoint 10, ExecInsert (mtstate=0x2253fd0, slot=0x2254750, planSlot=0x2254750, estate=0x2253c80,     canSetTag=true) at nodeModifyTable.c:273273     List       *recheckIndexes = NIL;#调用heap_insert等函数插入数据(gdb) cContinuing.Breakpoint 11, heap_insert (relation=0x7f1a5655b378, tup=0x2254ee0, cid=0, options=0, bistate=0x0)    at heapam.c:24442444        TransactionId xid = GetCurrentTransactionId();(gdb) cContinuing.Breakpoint 12, RelationPutHeapTuple (relation=0x7f1a5655b378, buffer=95, tuple=0x2254ee0, token=false)    at hio.c:5151      pageHeader = BufferGetPage(buffer);(gdb) cContinuing.Breakpoint 13, PageAddItemExtended (page=0x7f1a3e6a3300 "\001", item=0x2254ef8 "g\234\030", size=49,     offsetNumber=0, flags=2) at bufpage.c:196196     PageHeader  phdr = (PageHeader) page;(gdb) finishRun till exit from #0  PageAddItemExtended (page=0x7f1a3e6a3300 "\001", item=0x2254ef8 "g\234\030", size=49,     offsetNumber=0, flags=2) at bufpage.c:1960x00000000004cf4f9 in RelationPutHeapTuple (relation=0x7f1a5655b378, buffer=95, tuple=0x2254ee0, token=false)    at hio.c:5353      offnum = PageAddItem(pageHeader, (Item) tuple->t_data,Value returned is $42 = 41...#再次执行ExecProcNode(实质为ExecResult),返回NULL,退出循环,结束(gdb) cContinuing.Breakpoint 7, ExecProcNode (node=0x22543a0) at ../../../src/include/executor/executor.h:234234     if (node->chgParam != NULL) /* something changed? */(gdb) p *node$48 = {type = T_ResultState, plan = 0x21c44e0, state = 0x2253c80, ExecProcNode = 0x6c5094 ,   ExecProcNodeReal = 0x6c5094 , instrument = 0x0, worker_instrument = 0x0, qual = 0x0,   lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0,   ps_ResultTupleSlot = 0x2254750, ps_ExprContext = 0x22544b0, ps_ProjInfo = 0x22548b0, scandesc = 0x0}(gdb) cContinuing.

三、小结

1.执行过程:使用gdb跟踪INSERT语句执行的全过程;
2.数据结构:如PlannedStmt/PlanState/EState等
3."多态":ExecProcNode函数

0