PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么
发表于:2025-01-21 作者:千家信息网编辑
千家信息网最后更新 2025年01月21日,这篇文章主要讲解了"PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,
千家信息网最后更新 2025年01月21日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); } #endif
2、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安全错误
数据库的锁怎样保障安全
列入安全隐患数据库
网络安全工程师在哪报名
白水法院网络安全
贵阳数据库碎片修复
网络安全营口赛区
重庆软件开发定制近期价格
软件开发技术证书
哈尔滨乐淘网络技术
杭州有型网络技术有限公司
新洲定制软件开发公司
花生壳软件开发
如何买到一台mc服务器
关于教学和数据库的使用心得
信息安全网络安全专业排名
数据库动态加载
怀柔区管理网络技术服务怎么样
图像并行处理服务器
家里怎么安装路由服务器
软件开发培训改革
广东百望服务器连接异常
中文科技期刊数据库的出版单位
周鸿祎网络安全战
竞彩软件开发哪家好
弘瑞网络技术公司改套餐
鼎盛数据库
如何买到一台mc服务器
dnf私服没有服务器喇叭
医保获取数据库参数出错
response对象在服务器端
工艺数据库技术方案