PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么
发表于:2025-11-08 作者:千家信息网编辑
千家信息网最后更新 2025年11月08日,这篇文章主要讲解了"PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,
千家信息网最后更新 2025年11月08日PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么
这篇文章主要讲解了"PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么"吧!
一、基础信息
ExecProcNode/ExecProcNodeFirst函数使用的数据结构、宏定义以及依赖的函数等。
数据结构/宏定义
1、ExecProcNodeMtd
ExecProcNodeMtd是一个函数指针类型,指向的函数输入参数是PlanState结构体指针,输出参数是TupleTableSlot 结构体指针
/* ---------------- * ExecProcNodeMtd * * This is the method called by ExecProcNode to return the next tuple * from an executor node. It returns NULL, or an empty TupleTableSlot, * if no more tuples are available. * ---------------- */ typedef TupleTableSlot *(*ExecProcNodeMtd) (struct PlanState *pstate);
依赖的函数
1、check_stack_depth
//检查stack的深度,如超出系统限制,则主动报错 /* * check_stack_depth/stack_is_too_deep: check for excessively deep recursion * * This should be called someplace in any recursive routine that might possibly * recurse deep enough to overflow the stack. Most Unixen treat stack * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves * before hitting the hardware limit. * * check_stack_depth() just throws an error summarily. stack_is_too_deep() * can be used by code that wants to handle the error condition itself. */ void check_stack_depth(void) { if (stack_is_too_deep()) { ereport(ERROR, (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), errmsg("stack depth limit exceeded"), errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), " "after ensuring the platform's stack depth limit is adequate.", max_stack_depth))); } } bool stack_is_too_deep(void) { char stack_top_loc; long stack_depth; /* * Compute distance from reference point to my local variables */ stack_depth = (long) (stack_base_ptr - &stack_top_loc); /* * Take abs value, since stacks grow up on some machines, down on others */ if (stack_depth < 0) stack_depth = -stack_depth; /* * Trouble? * * The test on stack_base_ptr prevents us from erroring out if called * during process setup or in a non-backend process. Logically it should * be done first, but putting it here avoids wasting cycles during normal * cases. */ if (stack_depth > max_stack_depth_bytes && stack_base_ptr != NULL) return true; /* * On IA64 there is a separate "register" stack that requires its own * independent check. For this, we have to measure the change in the * "BSP" pointer from PostgresMain to here. Logic is just as above, * except that we know IA64's register stack grows up. * * Note we assume that the same max_stack_depth applies to both stacks. */ #if defined(__ia64__) || defined(__ia64) stack_depth = (long) (ia64_get_bsp() - register_stack_base_ptr); if (stack_depth > max_stack_depth_bytes && register_stack_base_ptr != NULL) return true; #endif /* IA64 */ return false; }2、ExecProcNodeInstr
/* * ExecProcNode wrapper that performs instrumentation calls. By keeping * this a separate function, we avoid overhead in the normal case where * no instrumentation is wanted. */ static TupleTableSlot * ExecProcNodeInstr(PlanState *node) { TupleTableSlot *result; InstrStartNode(node->instrument); result = node->ExecProcNodeReal(node); InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0); return result; }二、源码解读
1、ExecProcNode
//外部调用者可通过改变node实现遍历 /* ---------------------------------------------------------------- * ExecProcNode * * Execute the given node to return a(nother) tuple. * ---------------------------------------------------------------- */ #ifndef FRONTEND static inline TupleTableSlot * ExecProcNode(PlanState *node) { if (node->chgParam != NULL) /* something changed? */ ExecReScan(node); /* let ReScan handle this */ return node->ExecProcNode(node); } #endif2、ExecProcNodeFirst
/* * ExecProcNode wrapper that performs some one-time checks, before calling * the relevant node method (possibly via an instrumentation wrapper). *//*输入: node-PlanState指针输出: 存储Tuple的Slot*/static TupleTableSlot *ExecProcNodeFirst(PlanState *node){ /* * Perform stack depth check during the first execution of the node. We * only do so the first time round because it turns out to not be cheap on * some common architectures (eg. x86). This relies on the assumption * that ExecProcNode calls for a given plan node will always be made at * roughly the same stack depth. */ //检查Stack是否超深 check_stack_depth(); /* * If instrumentation is required, change the wrapper to one that just * does instrumentation. Otherwise we can dispense with all wrappers and * have ExecProcNode() directly call the relevant function from now on. */ //如果instrument(TODO) if (node->instrument) node->ExecProcNode = ExecProcNodeInstr; else node->ExecProcNode = node->ExecProcNodeReal; //执行该Node的处理过程 return node->ExecProcNode(node);}三、跟踪分析
插入测试数据:
testdb=# -- 获取pidtestdb=# select pg_backend_pid(); pg_backend_pid ---------------- 2835(1 row)testdb=# -- 插入1行testdb=# insert into t_insert values(14,'ExecProcNodeFirst','ExecProcNodeFirst','ExecProcNodeFirst');(挂起)
启动gdb分析:
[root@localhost ~]# gdb -p 2835GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7Copyright (C) 2013 Free Software Foundation, Inc....(gdb) b ExecProcNodeFirstBreakpoint 1 at 0x69a797: file execProcnode.c, line 433.(gdb) cContinuing.Breakpoint 1, ExecProcNodeFirst (node=0x2cca790) at execProcnode.c:433433 check_stack_depth();#查看输入参数(gdb) p *node$1 = {type = T_ModifyTableState, plan = 0x2c1d028, state = 0x2cca440, ExecProcNode = 0x69a78b , ExecProcNodeReal = 0x6c2485 , instrument = 0x0, worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2ccb6a0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x0}#ExecProcNode 实际对应的函数是ExecProcNodeFirst#ExecProcNodeReal 实际对应的函数是ExecModifyTable(上一章节已粗略解析)(gdb) next440 if (node->instrument)(gdb) #实际调用ExecModifyTable函数(这个函数由更高层的调用函数植入)443 node->ExecProcNode = node->ExecProcNodeReal;(gdb) 445 return node->ExecProcNode(node);(gdb) next#第二次调用(TODO)Breakpoint 1, ExecProcNodeFirst (node=0x2ccac80) at execProcnode.c:433433 check_stack_depth();(gdb) next440 if (node->instrument)(gdb) next443 node->ExecProcNode = node->ExecProcNodeReal;(gdb) next445 return node->ExecProcNode(node);(gdb) next446 }(gdb) nextExecProcNode (node=0x2ccac80) at ../../../src/include/executor/executor.h:238238 }#第二次调用的参数(gdb) p *node$2 = {type = T_ResultState, plan = 0x2cd0488, state = 0x2cca440, ExecProcNode = 0x6c5094 , ExecProcNodeReal = 0x6c5094 , instrument = 0x0, worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2ccad90, ps_ExprContext = 0x2ccab30, ps_ProjInfo = 0x2ccabc0, scandesc = 0x0}#ExecProcNode对应的实际函数是ExecResult(gdb) 感谢各位的阅读,以上就是"PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么"的内容了,经过本文的学习后,相信大家对PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
函数
逻辑
参数
实际
指针
结构
数据
学习
输入
内容
数据结构
分析
检查
输出
粗略
主动
信息
基础
就是
思路
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
hp服务器开机无画面
c能做什么软件开发
选择数据库的4 C原则是内
2007年服务器架构
js控制数据库
网络安全法规定了
我的世界手机版服务器有几个
我国网络安全风险缺口
拥有三个以上硬盘的存储服务器
宠物在线诊疗软件开发
数据库中连接查询语句
网络安全测评做什么
数据库查询不区分全半角
融媒体中心网络安全推进会
ggmplus重力数据库
服务器密码更改
广州格利网络技术有限公司
物理服务器迁移新服务器
网络安全防范工作规定
数据库等级证书
c语言服务器开发遇到的bug
c能做什么软件开发
网络安全应急处理制度
网络安全项目服务方案
工业软件开发的难点
中北大学图书馆数据库
部分迁移数据库数据
中国水稻数据库中心龙粳1424
医疗行业网络安全政策
软件开发公司怎么营销