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函数
函数
数据
生成
语句
跟踪
参数
元素
全过程
结构
循环
查询
输入
再次
实际
数据结构
类型
重点
准备
过程
多态
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
员工办理开户存款数据库模型
联想sr658服务器怎么联网
长春市宏程网络技术怎么样
计算机网络安全技术指标
商骐网络技术
大疆飞行安全数据库删除
软件开发人员必备的技能
藏锋者网络安全网
登录系统转移怎么重新连接数据库
软件开发的前景和认识
国内的网络安全评价标准
栾城区节能软件开发服务供应
私人卖服务器违法么
计算机网络技术容不容易学
高级筛选怎么选多不同数据库
服务器硬盘raid 报警修复
软件开发项目变更
网络安全法新司法解释
维护数据库安全性有哪些措施
华为服务器心跳故障灯红色
软件开发网站推广
数据库第三章测验题
账务处理数据库
美国自身网络安全吗
海南网络安全培训班住宿
服务器cpu装到家用机上
醉牛互联网科技
地理数据库设计
家园卫士部落服务器
在软件开发中什么是需求