怎么使用PostgreSQL的ExprEvalStep
本篇内容介绍了“怎么使用PostgreSQL的ExprEvalStep”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
ExprEvalStep
表达式解析步骤结构体
typedefstructExprEvalStep{/**Instructiontobeexecuted.Duringinstructionpreparationthisisan*enumExprEvalOp,butlateritcanbechangedtosomeothertype,e.g.a*pointerforcomputedgoto(that'swhyit'sanintptr_t).*待执行指令.*在指令准备期间这是枚举型的ExprEvalOp,*但后续会被改变为某些其他类型,比如用于goto的指针,因此被定义为intprt_t类型*/intptr_topcode;/*wheretostoretheresultofthisstep*///存储该步骤的结果Datum*resvalue;bool*resnull;/**Inlinedatafortheoperation.Inlinedataisfastertoaccess,but*alsobloatsthesizeofallinstructions.Theunionshouldbekeptto*nomorethan40byteson64-bitsystems(sothattheentirestructis*nomorethan64bytes,asinglecachelineoncommonsystems).*操作的内联数据.*内联数据用于更快的访问,但同时会导致指令的盘膨胀.*联合体在64-bit系统上应保持在40字节范围内*(因此整个结构体不应大于64字节,普通系统上的单个缓存线大小)*/union{/*forEEOP_INNER/OUTER/SCAN_FETCHSOME*///用于EEOP_INNER/OUTER/SCAN_FETCHSOMEstruct{/*attributenumberuptowhichtofetch(inclusive)*///获取到的属性编号intlast_var;TupleDescknown_desc;}fetch;/*forEEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST]*/struct{/*attnumisattrnumber-1forregularVAR...*///attnum是常规VAR的attrnumber-1/*butit'sjustthenormal(negative)attrnumberforSYSVAR*///对于SYSVAR,该值是常规的attrnumberintattnum;Oidvartype;/*typeOIDofvariable*/}var;/*forEEOP_WHOLEROW*/struct{Var*var;/*originalVarnodeinplantree*/boolfirst;/*firsttimethrough,needtoinitialize?*/boolslow;/*needruntimecheckfornulls?*/TupleDesctupdesc;/*descriptorforresultingtuples*/JunkFilter*junkFilter;/*JunkFiltertoremoveresjunkcols*/}wholerow;/*forEEOP_ASSIGN_*_VAR*/struct{/*targetindexinExprState->resultslot->tts_values/nulls*/intresultnum;/*sourceattributenumber-1*/intattnum;}assign_var;/*forEEOP_ASSIGN_TMP[_MAKE_RO]*/struct{/*targetindexinExprState->resultslot->tts_values/nulls*/intresultnum;}assign_tmp;/*forEEOP_CONST*/struct{/*constant'svalue*/Datumvalue;boolisnull;}constval;/*forEEOP_FUNCEXPR_*/NULLIF/DISTINCT*///对于EEOP_FUNCEXPR_*/NULLIF/DISTINCTstruct{//函数的检索数据FmgrInfo*finfo;/*function'slookupdata*///参数信息等FunctionCallInfofcinfo_data;/*argumentsetc*//*fastertoaccesswithoutadditionalindirection:*///无需额外的指向,更快速的访问PGFunctionfn_addr;/*actualcalladdress*/intnargs;/*numberofarguments*/}func;/*forEEOP_BOOL_*_STEP*/struct{bool*anynull;/*trackifanyinputwasNULL*/intjumpdone;/*jumphereifresultdetermined*/}boolexpr;/*forEEOP_QUAL*/struct{intjumpdone;/*jumphereonfalseornull*/}qualexpr;/*forEEOP_JUMP[_CONDITION]*/struct{intjumpdone;/*targetinstruction'sindex*/}jump;/*forEEOP_NULLTEST_ROWIS[NOT]NULL*/struct{/*cachedtupdescpointer-filledatruntime*/TupleDescargdesc;}nulltest_row;/*forEEOP_PARAM_EXEC/EXTERN*/struct{intparamid;/*numericIDforparameter*/Oidparamtype;/*OIDofparameter'sdatatype*/}param;/*forEEOP_PARAM_CALLBACK*/struct{ExecEvalSubroutineparamfunc;/*add-onevaluationsubroutine*/void*paramarg;/*privatedataforsame*/intparamid;/*numericIDforparameter*/Oidparamtype;/*OIDofparameter'sdatatype*/}cparam;/*forEEOP_CASE_TESTVAL/DOMAIN_TESTVAL*/struct{Datum*value;/*valuetoreturn*/bool*isnull;}casetest;/*forEEOP_MAKE_READONLY*/struct{Datum*value;/*valuetocoercetoread-only*/bool*isnull;}make_readonly;/*forEEOP_IOCOERCE*/struct{/*lookupandcallinfoforsourcetype'soutputfunction*/FmgrInfo*finfo_out;FunctionCallInfofcinfo_data_out;/*lookupandcallinfoforresulttype'sinputfunction*/FmgrInfo*finfo_in;FunctionCallInfofcinfo_data_in;}iocoerce;/*forEEOP_SQLVALUEFUNCTION*/struct{SQLValueFunction*svf;}sqlvaluefunction;/*forEEOP_NEXTVALUEEXPR*///EEOP_NEXTVALUEEXPRstruct{Oidseqid;Oidseqtypid;}nextvalueexpr;/*forEEOP_ARRAYEXPR*/struct{Datum*elemvalues;/*elementvaluesgetstoredhere*/bool*elemnulls;intnelems;/*lengthoftheabovearrays*/Oidelemtype;/*arrayelementtype*/int16elemlength;/*typlenofthearrayelementtype*/boolelembyval;/*istheelementtypepass-by-value?*/charelemalign;/*typalignoftheelementtype*/boolmultidims;/*isarrayexpressionmulti-D?*/}arrayexpr;/*forEEOP_ARRAYCOERCE*/struct{ExprState*elemexprstate;/*nullifnoper-elementwork*/Oidresultelemtype;/*elementtypeofresultarray*/structArrayMapState*amstate;/*workspaceforarray_map*/}arraycoerce;/*forEEOP_ROW*/struct{TupleDesctupdesc;/*descriptorforresulttuples*//*workspaceforthevaluesconstitutingtherow:*/Datum*elemvalues;bool*elemnulls;}row;/*forEEOP_ROWCOMPARE_STEP*/struct{/*lookupandcalldataforcolumncomparisonfunction*/FmgrInfo*finfo;FunctionCallInfofcinfo_data;PGFunctionfn_addr;/*targetforcomparisonresultinginNULL*/intjumpnull;/*targetforcomparisonyieldinginequality*/intjumpdone;}rowcompare_step;/*forEEOP_ROWCOMPARE_FINAL*/struct{RowCompareTyperctype;}rowcompare_final;/*forEEOP_MINMAX*/struct{/*workspaceforargumentvalues*/Datum*values;bool*nulls;intnelems;/*isitGREATESTorLEAST?*/MinMaxOpop;/*lookupandcalldataforcomparisonfunction*/FmgrInfo*finfo;FunctionCallInfofcinfo_data;}minmax;/*forEEOP_FIELDSELECT*/struct{AttrNumberfieldnum;/*fieldnumbertoextract*/Oidresulttype;/*field'stype*//*cachedtupdescpointer-filledatruntime*/TupleDescargdesc;}fieldselect;/*forEEOP_FIELDSTORE_DEFORM/FIELDSTORE_FORM*/struct{/*originalexpressionnode*/FieldStore*fstore;/*cachedtupdescpointer-filledatruntime*//*notethataDEFORMandFORMpairsharethesametupdesc*/TupleDesc*argdesc;/*workspaceforcolumnvalues*/Datum*values;bool*nulls;intncolumns;}fieldstore;/*forEEOP_ARRAYREF_SUBSCRIPT*/struct{/*toobigtohaveinline*/structArrayRefState*state;intoff;/*0-basedindexofthissubscript*/boolisupper;/*isitupperorlowersubscript?*/intjumpdone;/*jumphereonnull*/}arrayref_subscript;/*forEEOP_ARRAYREF_OLD/ASSIGN/FETCH*/struct{/*toobigtohaveinline*/structArrayRefState*state;}arrayref;/*forEEOP_DOMAIN_NOTNULL/DOMAIN_CHECK*/struct{/*nameofconstraint*/char*constraintname;/*wheretheresultofaCHECKconstraintwillbestored*/Datum*checkvalue;bool*checknull;/*OIDofdomaintype*/Oidresulttype;}domaincheck;/*forEEOP_CONVERT_ROWTYPE*/struct{ConvertRowtypeExpr*convert;/*originalexpression*//*thesethreefieldsarefilledatruntime:*/TupleDescindesc;/*tupdescforinputtype*/TupleDescoutdesc;/*tupdescforoutputtype*/TupleConversionMap*map;/*columnmapping*/boolinitialized;/*initializedforcurrenttypes?*/}convert_rowtype;/*forEEOP_SCALARARRAYOP*/struct{/*element_type/typlen/typbyval/typalignarefilledatruntime*/Oidelement_type;/*InvalidOidifnotyetfilled*/booluseOr;/*useORorANDsemantics?*/int16typlen;/*arrayelementtypestorageinfo*/booltypbyval;chartypalign;FmgrInfo*finfo;/*function'slookupdata*/FunctionCallInfofcinfo_data;/*argumentsetc*//*fastertoaccesswithoutadditionalindirection:*/PGFunctionfn_addr;/*actualcalladdress*/}scalararrayop;/*forEEOP_XMLEXPR*/struct{XmlExpr*xexpr;/*originalexpressionnode*//*workspaceforevaluatingnamedargs,ifany*/Datum*named_argvalue;bool*named_argnull;/*workspaceforevaluatingunnamedargs,ifany*/Datum*argvalue;bool*argnull;}xmlexpr;/*forEEOP_AGGREF*/struct{/*out-of-linestate,modifiedbynodeAgg.c*/AggrefExprState*astate;}aggref;/*forEEOP_GROUPING_FUNC*/struct{AggState*parent;/*parentAgg*/List*clauses;/*integerlistofcolumnnumbers*/}grouping_func;/*forEEOP_WINDOW_FUNC*/struct{/*out-of-linestate,modifiedbynodeWindowFunc.c*/WindowFuncExprState*wfstate;}window_func;/*forEEOP_SUBPLAN*/struct{/*out-of-linestate,createdbynodeSubplan.c*/SubPlanState*sstate;}subplan;/*forEEOP_ALTERNATIVE_SUBPLAN*/struct{/*out-of-linestate,createdbynodeSubplan.c*/AlternativeSubPlanState*asstate;}alternative_subplan;/*forEEOP_AGG_*DESERIALIZE*/struct{AggState*aggstate;FunctionCallInfofcinfo_data;intjumpnull;}agg_deserialize;/*forEEOP_AGG_STRICT_INPUT_CHECK*/struct{bool*nulls;intnargs;intjumpnull;}agg_strict_input_check;/*forEEOP_AGG_INIT_TRANS*/struct{AggState*aggstate;AggStatePerTranspertrans;ExprContext*aggcontext;intsetno;inttransno;intsetoff;intjumpnull;}agg_init_trans;/*forEEOP_AGG_STRICT_TRANS_CHECK*/struct{AggState*aggstate;intsetno;inttransno;intsetoff;intjumpnull;}agg_strict_trans_check;/*forEEOP_AGG_{PLAIN,ORDERED}_TRANS**/struct{AggState*aggstate;AggStatePerTranspertrans;ExprContext*aggcontext;intsetno;inttransno;intsetoff;}agg_trans;}d;}ExprEvalStep;
FmgrInfo
在函数通过fmgr调用前,该结构体持有系统目录(字典)信息,用于检索相关信息.
如果相同的函数将被调用多次,检索只需要完成一次即可,该结构体会缓存多次使用.
/**Thisstructholdsthesystem-cataloginformationthatmustbelookedup*beforeafunctioncanbecalledthroughfmgr.Ifthesamefunctionis*tobecalledmultipletimes,thelookupneedbedoneonlyonceandthe*infostructsavedforre-use.*在函数通过fmgr调用前,该结构体持有系统目录(字典)信息,用于检索相关信息.*如果相同的函数将被调用多次,检索只需要完成一次即可,该结构体会缓存多次使用.**Notethatfn_exprreallyisparse-time-determinedinformationaboutthe*arguments,ratherthanaboutthefunctionitself.Butit'sconvenient*tostoreithereratherthaninFunctionCallInfoData,whereitmightmore*logicallybelong.*注意,fn_expr实际上是关于参数的解析时确定的信息,而不是函数自身.*但fn_expr在这里存储而不是FunctionCallInfoData中存储,因为从逻辑上来说,它就应该属于那.**fn_extraisavailableforusebythecalledfunction;allotherfields*shouldbetreatedasread-onlyafterthestructiscreated.*fn_extra可用于被调用函数的使用;所有其他字段应该在结构体创建后被处理为只读.*/typedefstructFmgrInfo{//指向函数或者将被调用的处理器PGFunctionfn_addr;/*pointertofunctionorhandlertobecalled*///函数的oidOidfn_oid;/*OIDoffunction(NOTofhandler,ifany)*///输入参数的个数,0..FUNC_MAX_ARGSshortfn_nargs;/*numberofinputargs(0..FUNC_MAX_ARGS)*///函数是否严格(strict),输入NULL,输出NULLboolfn_strict;/*functionis"strict"(NULLin=>NULLout)*///函数是否返回集合boolfn_retset;/*functionreturnsaset*///如track_functions>this,则收集统计信息unsignedcharfn_stats;/*collectstatsiftrack_functions>this*///handler使用的额外空间void*fn_extra;/*extraspaceforusebyhandler*///存储fn_extra的内存上下文MemoryContextfn_mcxt;/*memorycontexttostorefn_extrain*///表达式解析树,或者为NULLfmNodePtrfn_expr;/*expressionparsetreeforcall,orNULL*/}FmgrInfo;typedefstructNode*fmNodePtr;
FunctionCallInfoData
该结构体存储了实际传递给fmgr-called函数的参数
/**Thisstructisthedataactuallypassedtoanfmgr-calledfunction.*该结构体存储了实际传递给fmgr-called函数的参数**Thecalledfunctionisexpectedtosetisnull,andpossiblyresultinfoor*fieldsinwhateverresultinfopointsto.Itshouldnotchangeanyother*fields.(Inparticular,scribblingontheargumentarraysisabadidea,*sincesomecallersassumetheycanre-callwiththesamearguments.)*被调用的函数期望设置isnull以及可能的resultinfo或者resultinfo指向的域字段.*不应该改变其他字段.*(特别的,在参数数组上乱写是个坏主意,因为某些调用者假定它们可以使用相同的参数重复调用)*/typedefstructFunctionCallInfoData{//指向该调用的检索信息FmgrInfo*flinfo;/*ptrtolookupinfousedforthiscall*///调用上下文fmNodePtrcontext;/*passinfoaboutcontextofcall*///传递或返回关于结果的特别信息fmNodePtrresultinfo;/*passorreturnextrainfoaboutresult*///函数的collationOidfncollation;/*collationforfunctiontouse*/#defineFIELDNO_FUNCTIONCALLINFODATA_ISNULL4//如结果为NULL,则必须设置为Tboolisnull;/*functionmustsettrueifresultisNULL*///实际传递的参数个数shortnargs;/*#argumentsactuallypassed*/#defineFIELDNO_FUNCTIONCALLINFODATA_ARG6//传递给函数的参数Datumarg[FUNC_MAX_ARGS];/*Argumentspassedtofunction*/#defineFIELDNO_FUNCTIONCALLINFODATA_ARGNULL7//如arg[i]为NULL,则对应的值为Tboolargnull[FUNC_MAX_ARGS];/*Tifarg[i]isactuallyNULL*/}FunctionCallInfoData;/**Allfunctionsthatcanbecalleddirectlybyfmgrmusthavethissignature.*(Otherfunctionscanbecalledbyusingahandlerthatdoeshavethis*signature.)*所有函数可以通过fmgr直接调用,但必须持有签名.*(其他函数可通过使用handler的方式调用,也有此签名)*/typedefstructFunctionCallInfoData*FunctionCallInfo;二、源码解读
ExecInitFunc函数为类函数表达式的执行配置步骤,在*state的steps中追加参数解析步骤,同时设置*scratch以便可以push到步骤中.
其主要逻辑如下:
1.检查调用函数的权限
2.检查nargs是否合法
3.为该调用分配函数检索数据和参数空间
4.配置主要的fmgr检索信息
5.初始化函数调用参数结构体
6.解析参数直接存储到fcinfo结构体中
7.根据函数的严格性和统计级别插入相应的opcode
/**Performsetupnecessaryfortheevaluationofafunction-likeexpression,*appendingargumentevaluationstepstothestepslistin*state,and*settingup*scratchsoitisreadytobepushed.*为类函数表达式的执行配置步骤,在*state的steps中追加参数解析步骤,*同时设置*scratch以便可以push到步骤中.***scratchisnotpushedhere,sothatcallersmayoverridetheopcode,*whichisusefulforfunction-likecaseslikeDISTINCT.**scratch不在这里push,以便调用者可以覆盖opcode,这在DISTINCT这类操作时很有用.*/staticvoidExecInitFunc(ExprEvalStep*scratch,Expr*node,List*args,Oidfuncid,Oidinputcollid,ExprState*state){intnargs=list_length(args);AclResultaclresult;FmgrInfo*flinfo;FunctionCallInfofcinfo;intargno;ListCell*lc;/*Checkpermissiontocallfunction*///检查调用函数的权限aclresult=pg_proc_aclcheck(funcid,GetUserId(),ACL_EXECUTE);if(aclresult!=ACLCHECK_OK)aclcheck_error(aclresult,OBJECT_FUNCTION,get_func_name(funcid));InvokeFunctionExecuteHook(funcid);/**Safetycheckonnargs.Undernormalcircumstancesthisshouldnever*fail,asparsershouldchecksooner.Butpossiblyitmightfailif*serverhasbeencompiledwithFUNC_MAX_ARGSsmallerthansomefunctions*declaredinpg_proc?*检查nargs.在通常的环境下,这不会出现异常.*但如果服务器使用FUNC_MAX_ARGS宏定义比某些在pg_proc中定义的函数要小时会出现问题.*/if(nargs>FUNC_MAX_ARGS)ereport(ERROR,(errcode(ERRCODE_TOO_MANY_ARGUMENTS),errmsg_plural("cannotpassmorethan%dargumenttoafunction","cannotpassmorethan%dargumentstoafunction",FUNC_MAX_ARGS,FUNC_MAX_ARGS)));/*Allocatefunctionlookupdataandparameterworkspaceforthiscall*///为该调用分配函数检索数据和参数空间scratch->d.func.finfo=palloc0(sizeof(FmgrInfo));scratch->d.func.fcinfo_data=palloc0(sizeof(FunctionCallInfoData));flinfo=scratch->d.func.finfo;fcinfo=scratch->d.func.fcinfo_data;/*Setuptheprimaryfmgrlookupinformation*///配置主要的fmgr检索信息fmgr_info(funcid,flinfo);fmgr_info_set_expr((Node*)node,flinfo);/*Initializefunctioncallparameterstructuretoo*///初始化函数调用参数结构体InitFunctionCallInfoData(*fcinfo,flinfo,nargs,inputcollid,NULL,NULL);/*Keepextracopiesofthisinfotosaveanindirectionatruntime*///保留此信息的额外副本,以便在运行时保存间接信息scratch->d.func.fn_addr=flinfo->fn_addr;scratch->d.func.nargs=nargs;/*Weonlysupportnon-setfunctionshere*///只支持non-set函数if(flinfo->fn_retset)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("set-valuedfunctioncalledincontextthatcannotacceptaset"),state->parent?executor_errposition(state->parent->state,exprLocation((Node*)node)):0));/*Buildcodetoevaluateargumentsdirectlyintothefcinfostruct*///解析参数直接存储到fcinfo结构体中argno=0;foreach(lc,args){//遍历参数Expr*arg=(Expr*)lfirst(lc);if(IsA(arg,Const)){//常量/**Don'tevaluateconstargumentseveryround;especially*interestingforconstantsincomparisons.*不要每轮都对常量参数进行解析,只需要关注在对比中感兴趣的常量即可.*/Const*con=(Const*)arg;fcinfo->arg[argno]=con->constvalue;fcinfo->argnull[argno]=con->constisnull;}else{//非常量,则递归调用ExecInitExprRec(arg,state,&fcinfo->arg[argno],&fcinfo->argnull[argno]);}argno++;}/*Insertappropriateopcodedependingonstrictnessandstatslevel*///根据函数的严格性和统计级别插入相应的opcodeif(pgstat_track_functions<=flinfo->fn_stats){if(flinfo->fn_strict&&nargs>0)scratch->opcode=EEOP_FUNCEXPR_STRICT;elsescratch->opcode=EEOP_FUNCEXPR;}else{if(flinfo->fn_strict&&nargs>0)scratch->opcode=EEOP_FUNCEXPR_STRICT_FUSAGE;elsescratch->opcode=EEOP_FUNCEXPR_FUSAGE;}}三、跟踪分析
测试脚本
testdb=#select1+id,c2fromt_exprwhereid<3;
设置断点,跟踪
(gdb)bExecInitFuncBreakpoint1at0x6c8c33:fileexecExpr.c,line2160.(gdb)cContinuing.Breakpoint1,ExecInitFunc(scratch=0x7ffd862de730,node=0x2e675d8,args=0x2e67520,funcid=177,inputcollid=0,state=0x2f228c0)atexecExpr.c:21602160intnargs=list_length(args);(gdb)bt#0ExecInitFunc(scratch=0x7ffd862de730,node=0x2e675d8,args=0x2e67520,funcid=177,inputcollid=0,state=0x2f228c0)atexecExpr.c:2160#10x00000000006c6200inExecInitExprRec(node=0x2e675d8,state=0x2f228c0,resv=0x2f228c8,resnull=0x2f228c5)atexecExpr.c:893#20x00000000006c55bcinExecBuildProjectionInfo(targetList=0x2f2a348,econtext=0x2f223a8,slot=0x2f22820,parent=0x2f22190,inputDesc=0x7ff79b051ab8)atexecExpr.c:452#30x00000000006e60d5inExecAssignProjectionInfo(planstate=0x2f22190,inputDesc=0x7ff79b051ab8)atexecUtils.c:468#40x00000000006e613cinExecConditionalAssignProjectionInfo(planstate=0x2f22190,inputDesc=0x7ff79b051ab8,varno=1)atexecUtils.c:493#50x00000000006e23f5inExecAssignScanProjectionInfo(node=0x2f22190)atexecScan.c:240#60x0000000000700afcinExecInitIndexScan(node=0x2e425f0,estate=0x2f21f78,eflags=16)atnodeIndexscan.c:962#70x00000000006e00ccinExecInitNode(node=0x2e425f0,estate=0x2f21f78,eflags=16)atexecProcnode.c:217#80x00000000006d6abeinInitPlan(queryDesc=0x2e65688,eflags=16)atexecMain.c:1046#90x00000000006d58adinstandard_ExecutorStart(queryDesc=0x2e65688,eflags=16)atexecMain.c:265#100x00000000006d5649inExecutorStart(queryDesc=0x2e65688,eflags=0)atexecMain.c:147#110x00000000008c18d6inPortalStart(portal=0x2eaf608,params=0x0,eflags=0,snapshot=0x0)atpquery.c:520#120x00000000008bbe1binexec_simple_query(query_string=0x2e40d78"select1+id,c2fromt_exprwhereid<3;")atpostgres.c:1106#130x00000000008c0191inPostgresMain(argc=1,argv=0x2e6ecb8,dbname=0x2e6eb20"testdb",username=0x2e3da98"xdb")atpostgres.c:4182#140x000000000081e06cinBackendRun(port=0x2e62ae0)atpostmaster.c:4361#150x000000000081d7dfinBackendStartup(port=0x2e62ae0)atpostmaster.c:4033#160x0000000000819bd9inServerLoop()atpostmaster.c:1706#170x000000000081948finPostmasterMain(argc=1,argv=0x2e3ba50)atpostmaster.c:1379#180x0000000000742931inmain(argc=1,argv=0x2e3ba50)atmain.c:228(gdb)
输入参数
(gdb)p*scratch-->步骤$1={opcode=0,resvalue=0x2f228c8,resnull=0x2f228c5,d={fetch={last_var=0,known_desc=0x0},var={attnum=0,vartype=0},wholerow={var=0x0,first=false,slow=false,tupdesc=0x0,junkFilter=0x0},assign_var={resultnum=0,attnum=0},assign_tmp={resultnum=0},constval={value=0,isnull=false},func={finfo=0x0,fcinfo_data=0x0,fn_addr=0x0,nargs=0},boolexpr={anynull=0x0,jumpdone=0},qualexpr={jumpdone=0},jump={jumpdone=0},nulltest_row={argdesc=0x0},param={paramid=0,paramtype=0},cparam={paramfunc=0x0,paramarg=0x0,paramid=0,paramtype=0},casetest={value=0x0,isnull=0x0},make_readonly={value=0x0,isnull=0x0},iocoerce={finfo_out=0x0,fcinfo_data_out=0x0,finfo_in=0x0,fcinfo_data_in=0x0},sqlvaluefunction={svf=0x0},nextvalueexpr={seqid=0,seqtypid=0},arrayexpr={elemvalues=0x0,elemnulls=0x0,nelems=0,elemtype=0,elemlength=0,elembyval=false,elemalign=0'\000',multidims=false},arraycoerce={elemexprstate=0x0,resultelemtype=0,amstate=0x0},row={tupdesc=0x0,elemvalues=0x0,elemnulls=0x0},rowcompare_step={finfo=0x0,fcinfo_data=0x0,fn_addr=0x0,jumpnull=0,jumpdone=0},rowcompare_final={rctype=0},minmax={values=0x0,nulls=0x0,nelems=0,op=IS_GREATEST,finfo=0x0,fcinfo_data=0x0},fieldselect={fieldnum=0,resulttype=0,argdesc=0x0},fieldstore={fstore=0x0,argdesc=0x0,values=0x0,nulls=0x0,ncolumns=0},arrayref_subscript={state=0x0,off=0,isupper=false,jumpdone=0},arrayref={state=0x0},domaincheck={constraintname=0x0,checkvalue=0x0,checknull=0x0,resulttype=0},convert_rowtype={convert=0x0,indesc=0x0,outdesc=0x0,map=0x0,initialized=false},scalararrayop={element_type=0,useOr=false,typlen=0,typbyval=false,typalign=0'\000',finfo=0x0,fcinfo_data=0x0,fn_addr=0x0},xmlexpr={xexpr=0x0,named_argvalue=0x0,named_argnull=0x0,argvalue=0x0,argnull=0x0},aggref={astate=0x0},grouping_func={parent=0x0,clauses=0x0},window_func={wfstate=0x0},subplan={sstate=0x0},alternative_subplan={asstate=0x0},agg_deserialize={aggstate=0x0,fcinfo_data=0x0,jumpnull=0},agg_strict_input_check={nulls=0x0,nargs=0,jumpnull=0},agg_init_trans={aggstate=0x0,pertrans=0x0,aggcontext=0x0,setno=0,transno=0,setoff=0,jumpnull=0},agg_strict_trans_check={aggstate=0x0,setno=0,transno=0,setoff=0,jumpnull=0},agg_trans={aggstate=0x0,pertrans=0x0,aggcontext=0x0,setno=0,transno=0,setoff=0}}}#########################################(gdb)p*node$2={type=T_OpExpr}(gdb)p*(OpExpr*)node-->OpExpr节点$3={xpr={type=T_OpExpr},opno=551,opfuncid=177,opresulttype=23,opretset=false,opcollid=0,inputcollid=0,args=0x2e67520,location=8}testdb=#\xExpandeddisplayison.testdb=#select*frompg_procwhereoid=177;-->opfuncid=177对应的系统proc-[RECORD1]---+-------proname|int4plpronamespace|11proowner|10prolang|12procost|1prorows|0provariadic|0protransform|-prokind|fprosecdef|fproleakproof|fproisstrict|tproretset|fprovolatile|iproparallel|spronargs|2pronargdefaults|0prorettype|23proargtypes|2323proallargtypes|proargmodes|proargnames|proargdefaults|protrftypes|prosrc|int4plprobin|proconfig|proacl|#########################################(gdb)p*args$4={type=T_List,length=2,head=0x2e674f8,tail=0x2e675b0}#########################################(gdb)p*state-->ExprState$5={tag={type=T_ExprState},flags=0'\000',resnull=false,resvalue=0,resultslot=0x2f22820,steps=0x2f229b0,evalfunc=0x0,expr=0x2f2a348,evalfunc_private=0x0,steps_len=1,steps_alloc=16,parent=0x2f22190,ext_params=0x0,innermost_caseval=0x0,innermost_casenull=0x0,innermost_domainval=0x0,innermost_domainnull=0x0}
1.检查调用函数的权限
(gdb)n2168aclresult=pg_proc_aclcheck(funcid,GetUserId(),ACL_EXECUTE);(gdb)2169if(aclresult!=ACLCHECK_OK)(gdb)2171InvokeFunctionExecuteHook(funcid);(gdb)
2.检查nargs是否合法
(gdb)2179if(nargs>FUNC_MAX_ARGS)(gdb)
3.为该调用分配函数检索数据和参数空间
(gdb)2188scratch->d.func.finfo=palloc0(sizeof(FmgrInfo));(gdb)2189scratch->d.func.fcinfo_data=palloc0(sizeof(FunctionCallInfoData));(gdb)
4.配置主要的fmgr检索信息
(gdb)2194fmgr_info(funcid,flinfo);(gdb)2195fmgr_info_set_expr((Node*)node,flinfo);(gdb)(gdb)p*flinfo$6={fn_addr=0x93d60c<int4pl>,fn_oid=177,fn_nargs=2,fn_strict=true,fn_retset=false,fn_stats=2'\002',fn_extra=0x0,fn_mcxt=0x2f21e60,fn_expr=0x2e675d8}(gdb)p*node$7={type=T_OpExpr}(gdb)p*(OpExpr*)node$8={xpr={type=T_OpExpr},opno=551,opfuncid=177,opresulttype=23,opretset=false,opcollid=0,inputcollid=0,args=0x2e67520,location=8}(gdb)
5.初始化函数调用参数结构体
(gdb)2198InitFunctionCallInfoData(*fcinfo,flinfo,(gdb)n2202scratch->d.func.fn_addr=flinfo->fn_addr;(gdb)2203scratch->d.func.nargs=nargs;(gdb)2206if(flinfo->fn_retset)(gdb)2215argno=0;(gdb)2216foreach(lc,args)(gdb)pnargs$9=2(gdb)pflinfo->fn_addr$10=(PGFunction)0x93d60c<int4pl>(gdb)p*fcinfo$11={flinfo=0x2f226b0,context=0x0,resultinfo=0x0,fncollation=0,isnull=false,nargs=2,arg={0<repeats100times>},argnull={false<repeats100times>}}(gdb)pscratch->d.func$12={finfo=0x2f226b0,fcinfo_data=0x2f22dc8,fn_addr=0x93d60c<int4pl>,nargs=2}(gdb)
6.循环解析参数args直接存储到fcinfo结构体中
第1个参数,是常量1
(gdb)n2218Expr*arg=(Expr*)lfirst(lc);(gdb)2220if(IsA(arg,Const))(gdb)p*arg$13={type=T_Const}(gdb)p*(Const*)arg$14={xpr={type=T_Const},consttype=23,consttypmod=-1,constcollid=0,constlen=4,constvalue=1,constisnull=false,constbyval=true,location=7}(gdb)n2226Const*con=(Const*)arg;(gdb)2228fcinfo->arg[argno]=con->constvalue;(gdb)2229fcinfo->argnull[argno]=con->constisnull;(gdb)2236argno++;(gdb)
第2个参数,是Var,递归调用ExecInitExprRec解析
(gdb)2216foreach(lc,args)(gdb)2218Expr*arg=(Expr*)lfirst(lc);(gdb)2220if(IsA(arg,Const))(gdb)2233ExecInitExprRec(arg,state,(gdb)p*arg$15={type=T_Var}(gdb)p*(Var*)arg$16={xpr={type=T_Var},varno=1,varattno=1,vartype=23,vartypmod=-1,varcollid=0,varlevelsup=0,varnoold=1,varoattno=1,location=9}(gdb)n2236argno++;(gdb)(gdb)n2216foreach(lc,args)(gdb)
7.根据函数的严格性和统计级别插入相应的opcode
2240if(pgstat_track_functions<=flinfo->fn_stats)(gdb)n2242if(flinfo->fn_strict&&nargs>0)(gdb)2243scratch->opcode=EEOP_FUNCEXPR_STRICT;(gdb)ppgstat_track_functions$17=0(gdb)pflinfo->fn_stats$18=2'\002'(gdb)n
完成调用
2254}(gdb)ExecInitExprRec(node=0x2e675d8,state=0x2f228c0,resv=0x2f228c8,resnull=0x2f228c5)atexecExpr.c:896896ExprEvalPushStep(state,&scratch);(gdb)
“怎么使用PostgreSQL的ExprEvalStep”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。