PostgreSQL 源码解读(15)- Insert语句(执行过程跟踪)
发表于:2025-01-21 作者:千家信息网编辑
千家信息网最后更新 2025年01月21日,本文简单介绍了PG INSERT语句的执行全过程,包括使用gdb跟踪调试的全过程,重点的数据结构等。一、调用栈INSERT语句的函数调用栈:(gdb) bt#0 PageAddItemExtende
千家信息网最后更新 2025年01月21日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函数
函数
数据
生成
语句
跟踪
参数
元素
全过程
结构
循环
查询
输入
再次
实际
数据结构
类型
重点
准备
过程
多态
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
郭大舰网络安全竞赛
服务器崩溃后怎么维护
elsevier集团数据库
网络技术最全理解
相亲数据库
博山快消品软件开发定制
用美国id用的什么服务器
序列数据库植物
江苏城管通软件开发公司
武昌区软件开发公司
江苏大型软件开发概念设计
火影不同的服务器可以组队吗
江苏潮流软件开发标准
生化分析仪数据库查询失败
网络安全的预防PPT图片
分布式远程数据库怎么查
网络安全手抄报文字内容 短语
软件开发技术和应用
网络安全必须学编程吗
品质软件开发有哪些
南大建设的数据库
sql备份数据库失败364
农村网络安全工作责任制
关于网络安全的街访问题
mc服务器域名名字注册
网络技术转型
国际服怎么开启服务器模式
c 数据库 没有数据
mysol数据库链接地址
山大万德数据库2022年还有吗