这篇文章主要讲解了“PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么”吧!

一、基础信息

ExecProcNode/ExecProcNodeFirst函数使用的数据结构、宏定义以及依赖的函数等。
数据结构/宏定义
1、ExecProcNodeMtd
ExecProcNodeMtd是一个函数指针类型,指向的函数输入参数是PlanState结构体指针,输出参数是TupleTableSlot 结构体指针

/*----------------*ExecProcNodeMtd**ThisisthemethodcalledbyExecProcNodetoreturnthenexttuple*fromanexecutornode.ItreturnsNULL,oranemptyTupleTableSlot,*ifnomoretuplesareavailable.*----------------*/typedefTupleTableSlot*(*ExecProcNodeMtd)(structPlanState*pstate);

依赖的函数
1、check_stack_depth

//检查stack的深度,如超出系统限制,则主动报错/**check_stack_depth/stack_is_too_deep:checkforexcessivelydeeprecursion**Thisshouldbecalledsomeplaceinanyrecursiveroutinethatmightpossibly*recursedeepenoughtooverflowthestack.MostUnixentreatstack*overflowasanunrecoverableSIGSEGV,sowewanttoerroroutourselves*beforehittingthehardwarelimit.**check_stack_depth()justthrowsanerrorsummarily.stack_is_too_deep()*canbeusedbycodethatwantstohandletheerrorconditionitself.*/voidcheck_stack_depth(void){if(stack_is_too_deep()){ereport(ERROR,(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),errmsg("stackdepthlimitexceeded"),errhint("Increasetheconfigurationparameter\"max_stack_depth\"(currently%dkB),""afterensuringtheplatform'sstackdepthlimitisadequate.",max_stack_depth)));}}boolstack_is_too_deep(void){charstack_top_loc;longstack_depth;/**Computedistancefromreferencepointtomylocalvariables*/stack_depth=(long)(stack_base_ptr-&stack_top_loc);/**Takeabsvalue,sincestacksgrowuponsomemachines,downonothers*/if(stack_depth<0)stack_depth=-stack_depth;/**Trouble?**Thetestonstack_base_ptrpreventsusfromerroringoutifcalled*duringprocesssetuporinanon-backendprocess.Logicallyitshould*bedonefirst,butputtingithereavoidswastingcyclesduringnormal*cases.*/if(stack_depth>max_stack_depth_bytes&&stack_base_ptr!=NULL)returntrue;/**OnIA64thereisaseparate"register"stackthatrequiresitsown*independentcheck.Forthis,wehavetomeasurethechangeinthe*"BSP"pointerfromPostgresMaintohere.Logicisjustasabove,*exceptthatweknowIA64'sregisterstackgrowsup.**Noteweassumethatthesamemax_stack_depthappliestobothstacks.*/#ifdefined(__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)returntrue;#endif/*IA64*/returnfalse;}

2、ExecProcNodeInstr

/**ExecProcNodewrapperthatperformsinstrumentationcalls.Bykeeping*thisaseparatefunction,weavoidoverheadinthenormalcasewhere*noinstrumentationiswanted.*/staticTupleTableSlot*ExecProcNodeInstr(PlanState*node){TupleTableSlot*result;InstrStartNode(node->instrument);result=node->ExecProcNodeReal(node);InstrStopNode(node->instrument,TupIsNull(result)?0.0:1.0);returnresult;}二、源码解读

1、ExecProcNode

//外部调用者可通过改变node实现遍历/*----------------------------------------------------------------*ExecProcNode**Executethegivennodetoreturna(nother)tuple.*----------------------------------------------------------------*/#ifndefFRONTENDstaticinlineTupleTableSlot*ExecProcNode(PlanState*node){if(node->chgParam!=NULL)/*somethingchanged?*/ExecReScan(node);/*letReScanhandlethis*/returnnode->ExecProcNode(node);}#endif

2、ExecProcNodeFirst

/**ExecProcNodewrapperthatperformssomeone-timechecks,beforecalling*therelevantnodemethod(possiblyviaaninstrumentationwrapper).*//*输入:node-PlanState指针输出:存储Tuple的Slot*/staticTupleTableSlot*ExecProcNodeFirst(PlanState*node){/**Performstackdepthcheckduringthefirstexecutionofthenode.We*onlydosothefirsttimeroundbecauseitturnsouttonotbecheapon*somecommonarchitectures(eg.x86).Thisreliesontheassumption*thatExecProcNodecallsforagivenplannodewillalwaysbemadeat*roughlythesamestackdepth.*///检查Stack是否超深check_stack_depth();/**Ifinstrumentationisrequired,changethewrappertoonethatjust*doesinstrumentation.Otherwisewecandispensewithallwrappersand*haveExecProcNode()directlycalltherelevantfunctionfromnowon.*///如果instrument(TODO)if(node->instrument)node->ExecProcNode=ExecProcNodeInstr;elsenode->ExecProcNode=node->ExecProcNodeReal;//执行该Node的处理过程returnnode->ExecProcNode(node);}三、跟踪分析

插入测试数据:

testdb=#--获取pidtestdb=#selectpg_backend_pid();pg_backend_pid----------------2835(1row)testdb=#--插入1行testdb=#insertintot_insertvalues(14,'ExecProcNodeFirst','ExecProcNodeFirst','ExecProcNodeFirst');(挂起)

启动gdb分析:

[root@localhost~]#gdb-p2835GNUgdb(GDB)RedHatEnterpriseLinux7.6.1-100.el7Copyright(C)2013FreeSoftwareFoundation,Inc....(gdb)bExecProcNodeFirstBreakpoint1at0x69a797:fileexecProcnode.c,line433.(gdb)cContinuing.Breakpoint1,ExecProcNodeFirst(node=0x2cca790)atexecProcnode.c:433433check_stack_depth();#查看输入参数(gdb)p*node$1={type=T_ModifyTableState,plan=0x2c1d028,state=0x2cca440,ExecProcNode=0x69a78b<ExecProcNodeFirst>,ExecProcNodeReal=0x6c2485<ExecModifyTable>,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)next440if(node->instrument)(gdb)#实际调用ExecModifyTable函数(这个函数由更高层的调用函数植入)443node->ExecProcNode=node->ExecProcNodeReal;(gdb)445returnnode->ExecProcNode(node);(gdb)next#第二次调用(TODO)Breakpoint1,ExecProcNodeFirst(node=0x2ccac80)atexecProcnode.c:433433check_stack_depth();(gdb)next440if(node->instrument)(gdb)next443node->ExecProcNode=node->ExecProcNodeReal;(gdb)next445returnnode->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<ExecResult>,ExecProcNodeReal=0x6c5094<ExecResult>,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函数的实现逻辑是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!