千家信息网

怎么使用PostgreSQL的ExprEvalStep

发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,本篇内容介绍了"怎么使用PostgreSQL的ExprEvalStep"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读
千家信息网最后更新 2025年01月20日怎么使用PostgreSQL的ExprEvalStep

本篇内容介绍了"怎么使用PostgreSQL的ExprEvalStep"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

ExprEvalStep
表达式解析步骤结构体

typedef struct ExprEvalStep{    /*     * Instruction to be executed.  During instruction preparation this is an     * enum ExprEvalOp, but later it can be changed to some other type, e.g. a     * pointer for computed goto (that's why it's an intptr_t).     * 待执行指令.     * 在指令准备期间这是枚举型的ExprEvalOp,     *   但后续会被改变为某些其他类型,比如用于goto的指针,因此被定义为intprt_t类型     */    intptr_t    opcode;    /* where to store the result of this step */    //存储该步骤的结果    Datum      *resvalue;    bool       *resnull;    /*     * Inline data for the operation.  Inline data is faster to access, but     * also bloats the size of all instructions.  The union should be kept to     * no more than 40 bytes on 64-bit systems (so that the entire struct is     * no more than 64 bytes, a single cacheline on common systems).     * 操作的内联数据.     * 内联数据用于更快的访问,但同时会导致指令的盘膨胀.     * 联合体在64-bit系统上应保持在40字节范围内     * (因此整个结构体不应大于64字节,普通系统上的单个缓存线大小)     */    union    {        /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */        //用于EEOP_INNER/OUTER/SCAN_FETCHSOME        struct        {            /* attribute number up to which to fetch (inclusive) */            //获取到的属性编号            int         last_var;            TupleDesc   known_desc;        }           fetch;        /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */        struct        {            /* attnum is attr number - 1 for regular VAR ... */            //attnum是常规VAR的attr number - 1            /* but it's just the normal (negative) attr number for SYSVAR */            //对于SYSVAR,该值是常规的attr number            int         attnum;            Oid         vartype;    /* type OID of variable */        }           var;        /* for EEOP_WHOLEROW */        struct        {            Var        *var;    /* original Var node in plan tree */            bool        first;  /* first time through, need to initialize? */            bool        slow;   /* need runtime check for nulls? */            TupleDesc   tupdesc;    /* descriptor for resulting tuples */            JunkFilter *junkFilter; /* JunkFilter to remove resjunk cols */        }           wholerow;        /* for EEOP_ASSIGN_*_VAR */        struct        {            /* target index in ExprState->resultslot->tts_values/nulls */            int         resultnum;            /* source attribute number - 1 */            int         attnum;        }           assign_var;        /* for EEOP_ASSIGN_TMP[_MAKE_RO] */        struct        {            /* target index in ExprState->resultslot->tts_values/nulls */            int         resultnum;        }           assign_tmp;        /* for EEOP_CONST */        struct        {            /* constant's value */            Datum       value;            bool        isnull;        }           constval;        /* for EEOP_FUNCEXPR_* / NULLIF / DISTINCT */        //对于EEOP_FUNCEXPR_* / NULLIF / DISTINCT        struct        {            //函数的检索数据            FmgrInfo   *finfo;  /* function's lookup data */            //参数信息等            FunctionCallInfo fcinfo_data;   /* arguments etc */            /* faster to access without additional indirection: */            //无需额外的指向,更快速的访问            PGFunction  fn_addr;    /* actual call address */            int         nargs;  /* number of arguments */        }           func;        /* for EEOP_BOOL_*_STEP */        struct        {            bool       *anynull;    /* track if any input was NULL */            int         jumpdone;   /* jump here if result determined */        }           boolexpr;        /* for EEOP_QUAL */        struct        {            int         jumpdone;   /* jump here on false or null */        }           qualexpr;        /* for EEOP_JUMP[_CONDITION] */        struct        {            int         jumpdone;   /* target instruction's index */        }           jump;        /* for EEOP_NULLTEST_ROWIS[NOT]NULL */        struct        {            /* cached tupdesc pointer - filled at runtime */            TupleDesc   argdesc;        }           nulltest_row;        /* for EEOP_PARAM_EXEC/EXTERN */        struct        {            int         paramid;    /* numeric ID for parameter */            Oid         paramtype;  /* OID of parameter's datatype */        }           param;        /* for EEOP_PARAM_CALLBACK */        struct        {            ExecEvalSubroutine paramfunc;   /* add-on evaluation subroutine */            void       *paramarg;   /* private data for same */            int         paramid;    /* numeric ID for parameter */            Oid         paramtype;  /* OID of parameter's datatype */        }           cparam;        /* for EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */        struct        {            Datum      *value;  /* value to return */            bool       *isnull;        }           casetest;        /* for EEOP_MAKE_READONLY */        struct        {            Datum      *value;  /* value to coerce to read-only */            bool       *isnull;        }           make_readonly;        /* for EEOP_IOCOERCE */        struct        {            /* lookup and call info for source type's output function */            FmgrInfo   *finfo_out;            FunctionCallInfo fcinfo_data_out;            /* lookup and call info for result type's input function */            FmgrInfo   *finfo_in;            FunctionCallInfo fcinfo_data_in;        }           iocoerce;        /* for EEOP_SQLVALUEFUNCTION */        struct        {            SQLValueFunction *svf;        }           sqlvaluefunction;        /* for EEOP_NEXTVALUEEXPR */        //EEOP_NEXTVALUEEXPR        struct        {            Oid         seqid;            Oid         seqtypid;        }           nextvalueexpr;        /* for EEOP_ARRAYEXPR */        struct        {            Datum      *elemvalues; /* element values get stored here */            bool       *elemnulls;            int         nelems; /* length of the above arrays */            Oid         elemtype;   /* array element type */            int16       elemlength; /* typlen of the array element type */            bool        elembyval;  /* is the element type pass-by-value? */            char        elemalign;  /* typalign of the element type */            bool        multidims;  /* is array expression multi-D? */        }           arrayexpr;        /* for EEOP_ARRAYCOERCE */        struct        {            ExprState  *elemexprstate;  /* null if no per-element work */            Oid         resultelemtype; /* element type of result array */            struct ArrayMapState *amstate;  /* workspace for array_map */        }           arraycoerce;        /* for EEOP_ROW */        struct        {            TupleDesc   tupdesc;    /* descriptor for result tuples */            /* workspace for the values constituting the row: */            Datum      *elemvalues;            bool       *elemnulls;        }           row;        /* for EEOP_ROWCOMPARE_STEP */        struct        {            /* lookup and call data for column comparison function */            FmgrInfo   *finfo;            FunctionCallInfo fcinfo_data;            PGFunction  fn_addr;            /* target for comparison resulting in NULL */            int         jumpnull;            /* target for comparison yielding inequality */            int         jumpdone;        }           rowcompare_step;        /* for EEOP_ROWCOMPARE_FINAL */        struct        {            RowCompareType rctype;        }           rowcompare_final;        /* for EEOP_MINMAX */        struct        {            /* workspace for argument values */            Datum      *values;            bool       *nulls;            int         nelems;            /* is it GREATEST or LEAST? */            MinMaxOp    op;            /* lookup and call data for comparison function */            FmgrInfo   *finfo;            FunctionCallInfo fcinfo_data;        }           minmax;        /* for EEOP_FIELDSELECT */        struct        {            AttrNumber  fieldnum;   /* field number to extract */            Oid         resulttype; /* field's type */            /* cached tupdesc pointer - filled at runtime */            TupleDesc   argdesc;        }           fieldselect;        /* for EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */        struct        {            /* original expression node */            FieldStore *fstore;            /* cached tupdesc pointer - filled at runtime */            /* note that a DEFORM and FORM pair share the same tupdesc */            TupleDesc  *argdesc;            /* workspace for column values */            Datum      *values;            bool       *nulls;            int         ncolumns;        }           fieldstore;        /* for EEOP_ARRAYREF_SUBSCRIPT */        struct        {            /* too big to have inline */            struct ArrayRefState *state;            int         off;    /* 0-based index of this subscript */            bool        isupper;    /* is it upper or lower subscript? */            int         jumpdone;   /* jump here on null */        }           arrayref_subscript;        /* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */        struct        {            /* too big to have inline */            struct ArrayRefState *state;        }           arrayref;        /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */        struct        {            /* name of constraint */            char       *constraintname;            /* where the result of a CHECK constraint will be stored */            Datum      *checkvalue;            bool       *checknull;            /* OID of domain type */            Oid         resulttype;        }           domaincheck;        /* for EEOP_CONVERT_ROWTYPE */        struct        {            ConvertRowtypeExpr *convert;    /* original expression */            /* these three fields are filled at runtime: */            TupleDesc   indesc; /* tupdesc for input type */            TupleDesc   outdesc;    /* tupdesc for output type */            TupleConversionMap *map;    /* column mapping */            bool        initialized;    /* initialized for current types? */        }           convert_rowtype;        /* for EEOP_SCALARARRAYOP */        struct        {            /* element_type/typlen/typbyval/typalign are filled at runtime */            Oid         element_type;   /* InvalidOid if not yet filled */            bool        useOr;  /* use OR or AND semantics? */            int16       typlen; /* array element type storage info */            bool        typbyval;            char        typalign;            FmgrInfo   *finfo;  /* function's lookup data */            FunctionCallInfo fcinfo_data;   /* arguments etc */            /* faster to access without additional indirection: */            PGFunction  fn_addr;    /* actual call address */        }           scalararrayop;        /* for EEOP_XMLEXPR */        struct        {            XmlExpr    *xexpr;  /* original expression node */            /* workspace for evaluating named args, if any */            Datum      *named_argvalue;            bool       *named_argnull;            /* workspace for evaluating unnamed args, if any */            Datum      *argvalue;            bool       *argnull;        }           xmlexpr;        /* for EEOP_AGGREF */        struct        {            /* out-of-line state, modified by nodeAgg.c */            AggrefExprState *astate;        }           aggref;        /* for EEOP_GROUPING_FUNC */        struct        {            AggState   *parent; /* parent Agg */            List       *clauses;    /* integer list of column numbers */        }           grouping_func;        /* for EEOP_WINDOW_FUNC */        struct        {            /* out-of-line state, modified by nodeWindowFunc.c */            WindowFuncExprState *wfstate;        }           window_func;        /* for EEOP_SUBPLAN */        struct        {            /* out-of-line state, created by nodeSubplan.c */            SubPlanState *sstate;        }           subplan;        /* for EEOP_ALTERNATIVE_SUBPLAN */        struct        {            /* out-of-line state, created by nodeSubplan.c */            AlternativeSubPlanState *asstate;        }           alternative_subplan;        /* for EEOP_AGG_*DESERIALIZE */        struct        {            AggState   *aggstate;            FunctionCallInfo fcinfo_data;            int         jumpnull;        }           agg_deserialize;        /* for EEOP_AGG_STRICT_INPUT_CHECK */        struct        {            bool       *nulls;            int         nargs;            int         jumpnull;        }           agg_strict_input_check;        /* for EEOP_AGG_INIT_TRANS */        struct        {            AggState   *aggstate;            AggStatePerTrans pertrans;            ExprContext *aggcontext;            int         setno;            int         transno;            int         setoff;            int         jumpnull;        }           agg_init_trans;        /* for EEOP_AGG_STRICT_TRANS_CHECK */        struct        {            AggState   *aggstate;            int         setno;            int         transno;            int         setoff;            int         jumpnull;        }           agg_strict_trans_check;        /* for EEOP_AGG_{PLAIN,ORDERED}_TRANS* */        struct        {            AggState   *aggstate;            AggStatePerTrans pertrans;            ExprContext *aggcontext;            int         setno;            int         transno;            int         setoff;        }           agg_trans;    }           d;} ExprEvalStep;

FmgrInfo
在函数通过fmgr调用前,该结构体持有系统目录(字典)信息,用于检索相关信息.
如果相同的函数将被调用多次,检索只需要完成一次即可,该结构体会缓存多次使用.

/* * This struct holds the system-catalog information that must be looked up * before a function can be called through fmgr.  If the same function is * to be called multiple times, the lookup need be done only once and the * info struct saved for re-use. * 在函数通过fmgr调用前,该结构体持有系统目录(字典)信息,用于检索相关信息. * 如果相同的函数将被调用多次,检索只需要完成一次即可,该结构体会缓存多次使用. * * Note that fn_expr really is parse-time-determined information about the * arguments, rather than about the function itself.  But it's convenient * to store it here rather than in FunctionCallInfoData, where it might more * logically belong. * 注意,fn_expr实际上是关于参数的解析时确定的信息,而不是函数自身. * 但fn_expr在这里存储而不是FunctionCallInfoData中存储,因为从逻辑上来说,它就应该属于那. * * fn_extra is available for use by the called function; all other fields * should be treated as read-only after the struct is created. * fn_extra可用于被调用函数的使用;所有其他字段应该在结构体创建后被处理为只读. */typedef struct FmgrInfo{    //指向函数或者将被调用的处理器    PGFunction  fn_addr;        /* pointer to function or handler to be called */    //函数的oid    Oid         fn_oid;         /* OID of function (NOT of handler, if any) */    //输入参数的个数,0..FUNC_MAX_ARGS    short       fn_nargs;       /* number of input args (0..FUNC_MAX_ARGS) */    //函数是否严格(strict),输入NULL,输出NULL    bool        fn_strict;      /* function is "strict" (NULL in => NULL out) */    //函数是否返回集合    bool        fn_retset;      /* function returns a set */    //如track_functions > this,则收集统计信息    unsigned char fn_stats;     /* collect stats if track_functions > this */    //handler使用的额外空间    void       *fn_extra;       /* extra space for use by handler */    //存储fn_extra的内存上下文    MemoryContext fn_mcxt;      /* memory context to store fn_extra in */    //表达式解析树,或者为NULL    fmNodePtr   fn_expr;        /* expression parse tree for call, or NULL */} FmgrInfo;typedef struct Node *fmNodePtr;

FunctionCallInfoData
该结构体存储了实际传递给fmgr-called函数的参数

/* * This struct is the data actually passed to an fmgr-called function. * 该结构体存储了实际传递给fmgr-called函数的参数 * * The called function is expected to set isnull, and possibly resultinfo or * fields in whatever resultinfo points to.  It should not change any other * fields.  (In particular, scribbling on the argument arrays is a bad idea, * since some callers assume they can re-call with the same arguments.) * 被调用的函数期望设置isnull以及可能的resultinfo或者resultinfo指向的域字段. * 不应该改变其他字段. * (特别的,在参数数组上乱写是个坏主意,因为某些调用者假定它们可以使用相同的参数重复调用) */typedef struct FunctionCallInfoData{    //指向该调用的检索信息    FmgrInfo   *flinfo;         /* ptr to lookup info used for this call */    //调用上下文    fmNodePtr   context;        /* pass info about context of call */    //传递或返回关于结果的特别信息    fmNodePtr   resultinfo;     /* pass or return extra info about result */    //函数的collation    Oid         fncollation;    /* collation for function to use */#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4    //如结果为NULL,则必须设置为T    bool        isnull;         /* function must set true if result is NULL */    //实际传递的参数个数    short       nargs;          /* # arguments actually passed */#define FIELDNO_FUNCTIONCALLINFODATA_ARG 6    //传递给函数的参数    Datum       arg[FUNC_MAX_ARGS]; /* Arguments passed to function */#define FIELDNO_FUNCTIONCALLINFODATA_ARGNULL 7    //如arg[i]为NULL,则对应的值为T    bool        argnull[FUNC_MAX_ARGS]; /* T if arg[i] is actually NULL */} FunctionCallInfoData;/* * All functions that can be called directly by fmgr must have this signature. * (Other functions can be called by using a handler that does have this * signature.) * 所有函数可以通过fmgr直接调用,但必须持有签名. * (其他函数可通过使用handler的方式调用,也有此签名) */typedef struct FunctionCallInfoData *FunctionCallInfo;

二、源码解读

ExecInitFunc函数为类函数表达式的执行配置步骤,在*state的steps中追加参数解析步骤,同时设置*scratch以便可以push到步骤中.
其主要逻辑如下:
1.检查调用函数的权限
2.检查nargs是否合法
3.为该调用分配函数检索数据和参数空间
4.配置主要的fmgr检索信息
5.初始化函数调用参数结构体
6.解析参数直接存储到fcinfo结构体中
7.根据函数的严格性和统计级别插入相应的opcode

/* * Perform setup necessary for the evaluation of a function-like expression, * appending argument evaluation steps to the steps list in *state, and * setting up *scratch so it is ready to be pushed. * 为类函数表达式的执行配置步骤,在*state的steps中追加参数解析步骤, *   同时设置*scratch以便可以push到步骤中. * * *scratch is not pushed here, so that callers may override the opcode, * which is useful for function-like cases like DISTINCT. * *scratch不在这里push,以便调用者可以覆盖opcode,这在DISTINCT这类操作时很有用. */static voidExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,             Oid inputcollid, ExprState *state){    int         nargs = list_length(args);    AclResult   aclresult;    FmgrInfo   *flinfo;    FunctionCallInfo fcinfo;    int         argno;    ListCell   *lc;    /* Check permission to call function */    //检查调用函数的权限    aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);    if (aclresult != ACLCHECK_OK)        aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));    InvokeFunctionExecuteHook(funcid);    /*     * Safety check on nargs.  Under normal circumstances this should never     * fail, as parser should check sooner.  But possibly it might fail if     * server has been compiled with FUNC_MAX_ARGS smaller than some functions     * declared in pg_proc?     * 检查nargs.在通常的环境下,这不会出现异常.     * 但如果服务器使用FUNC_MAX_ARGS宏定义比某些在pg_proc中定义的函数要小时会出现问题.     */    if (nargs > FUNC_MAX_ARGS)        ereport(ERROR,                (errcode(ERRCODE_TOO_MANY_ARGUMENTS),                 errmsg_plural("cannot pass more than %d argument to a function",                               "cannot pass more than %d arguments to a function",                               FUNC_MAX_ARGS,                               FUNC_MAX_ARGS)));    /* Allocate function lookup data and parameter workspace for this call */    //为该调用分配函数检索数据和参数空间    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;    /* Set up the primary fmgr lookup information */    //配置主要的fmgr检索信息    fmgr_info(funcid, flinfo);    fmgr_info_set_expr((Node *) node, flinfo);    /* Initialize function call parameter structure too */    //初始化函数调用参数结构体    InitFunctionCallInfoData(*fcinfo, flinfo,                             nargs, inputcollid, NULL, NULL);    /* Keep extra copies of this info to save an indirection at runtime */    //保留此信息的额外副本,以便在运行时保存间接信息    scratch->d.func.fn_addr = flinfo->fn_addr;    scratch->d.func.nargs = nargs;    /* We only support non-set functions here */    //只支持non-set函数    if (flinfo->fn_retset)        ereport(ERROR,                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),                 errmsg("set-valued function called in context that cannot accept a set"),                 state->parent ?                 executor_errposition(state->parent->state,                                      exprLocation((Node *) node)) : 0));    /* Build code to evaluate arguments directly into the fcinfo struct */    //解析参数直接存储到fcinfo结构体中    argno = 0;    foreach(lc, args)    {        //遍历参数        Expr       *arg = (Expr *) lfirst(lc);        if (IsA(arg, Const))        {            //常量            /*             * Don't evaluate const arguments every round; especially             * interesting for constants in comparisons.             * 不要每轮都对常量参数进行解析,只需要关注在对比中感兴趣的常量即可.             */            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++;    }    /* Insert appropriate opcode depending on strictness and stats level */    //根据函数的严格性和统计级别插入相应的opcode    if (pgstat_track_functions <= flinfo->fn_stats)    {        if (flinfo->fn_strict && nargs > 0)            scratch->opcode = EEOP_FUNCEXPR_STRICT;        else            scratch->opcode = EEOP_FUNCEXPR;    }    else    {        if (flinfo->fn_strict && nargs > 0)            scratch->opcode = EEOP_FUNCEXPR_STRICT_FUSAGE;        else            scratch->opcode = EEOP_FUNCEXPR_FUSAGE;    }}

三、跟踪分析

测试脚本

testdb=# select 1+id,c2 from t_expr where id < 3;

设置断点,跟踪

(gdb) b ExecInitFuncBreakpoint 1 at 0x6c8c33: file execExpr.c, line 2160.(gdb) cContinuing.Breakpoint 1, ExecInitFunc (scratch=0x7ffd862de730, node=0x2e675d8, args=0x2e67520, funcid=177, inputcollid=0,     state=0x2f228c0) at execExpr.c:21602160        int         nargs = list_length(args);(gdb) bt#0  ExecInitFunc (scratch=0x7ffd862de730, node=0x2e675d8, args=0x2e67520, funcid=177, inputcollid=0, state=0x2f228c0)    at execExpr.c:2160#1  0x00000000006c6200 in ExecInitExprRec (node=0x2e675d8, state=0x2f228c0, resv=0x2f228c8, resnull=0x2f228c5)    at execExpr.c:893#2  0x00000000006c55bc in ExecBuildProjectionInfo (targetList=0x2f2a348, econtext=0x2f223a8, slot=0x2f22820,     parent=0x2f22190, inputDesc=0x7ff79b051ab8) at execExpr.c:452#3  0x00000000006e60d5 in ExecAssignProjectionInfo (planstate=0x2f22190, inputDesc=0x7ff79b051ab8) at execUtils.c:468#4  0x00000000006e613c in ExecConditionalAssignProjectionInfo (planstate=0x2f22190, inputDesc=0x7ff79b051ab8, varno=1)    at execUtils.c:493#5  0x00000000006e23f5 in ExecAssignScanProjectionInfo (node=0x2f22190) at execScan.c:240#6  0x0000000000700afc in ExecInitIndexScan (node=0x2e425f0, estate=0x2f21f78, eflags=16) at nodeIndexscan.c:962#7  0x00000000006e00cc in ExecInitNode (node=0x2e425f0, estate=0x2f21f78, eflags=16) at execProcnode.c:217#8  0x00000000006d6abe in InitPlan (queryDesc=0x2e65688, eflags=16) at execMain.c:1046#9  0x00000000006d58ad in standard_ExecutorStart (queryDesc=0x2e65688, eflags=16) at execMain.c:265#10 0x00000000006d5649 in ExecutorStart (queryDesc=0x2e65688, eflags=0) at execMain.c:147#11 0x00000000008c18d6 in PortalStart (portal=0x2eaf608, params=0x0, eflags=0, snapshot=0x0) at pquery.c:520#12 0x00000000008bbe1b in exec_simple_query (query_string=0x2e40d78 "select 1+id,c2 from t_expr where id < 3;")    at postgres.c:1106#13 0x00000000008c0191 in PostgresMain (argc=1, argv=0x2e6ecb8, dbname=0x2e6eb20 "testdb", username=0x2e3da98 "xdb")    at postgres.c:4182#14 0x000000000081e06c in BackendRun (port=0x2e62ae0) at postmaster.c:4361#15 0x000000000081d7df in BackendStartup (port=0x2e62ae0) at postmaster.c:4033#16 0x0000000000819bd9 in ServerLoop () at postmaster.c:1706#17 0x000000000081948f in PostmasterMain (argc=1, argv=0x2e3ba50) at postmaster.c:1379#18 0x0000000000742931 in main (argc=1, argv=0x2e3ba50) at main.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=# \xExpanded display is on.testdb=# select * from pg_proc where oid=177; --> opfuncid = 177对应的系统proc-[ RECORD 1 ]---+-------proname         | int4plpronamespace    | 11proowner        | 10prolang         | 12procost         | 1prorows         | 0provariadic     | 0protransform    | -prokind         | fprosecdef       | fproleakproof    | fproisstrict     | tproretset       | fprovolatile     | iproparallel     | spronargs        | 2pronargdefaults | 0prorettype      | 23proargtypes     | 23 23proallargtypes  | 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) n2168        aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);(gdb) 2169        if (aclresult != ACLCHECK_OK)(gdb) 2171        InvokeFunctionExecuteHook(funcid);(gdb)

2.检查nargs是否合法

(gdb) 2179        if (nargs > FUNC_MAX_ARGS)(gdb)

3.为该调用分配函数检索数据和参数空间

(gdb) 2188        scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));(gdb) 2189        scratch->d.func.fcinfo_data = palloc0(sizeof(FunctionCallInfoData));(gdb)

4.配置主要的fmgr检索信息

(gdb) 2194        fmgr_info(funcid, flinfo);(gdb) 2195        fmgr_info_set_expr((Node *) node, flinfo);(gdb) (gdb) p *flinfo$6 = {fn_addr = 0x93d60c , 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) 2198        InitFunctionCallInfoData(*fcinfo, flinfo,(gdb) n2202        scratch->d.func.fn_addr = flinfo->fn_addr;(gdb) 2203        scratch->d.func.nargs = nargs;(gdb) 2206        if (flinfo->fn_retset)(gdb) 2215        argno = 0;(gdb) 2216        foreach(lc, args)(gdb) p nargs$9 = 2(gdb) p flinfo->fn_addr$10 = (PGFunction) 0x93d60c (gdb) p *fcinfo$11 = {flinfo = 0x2f226b0, context = 0x0, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {    0 }, argnull = {false }}(gdb) p scratch->d.func$12 = {finfo = 0x2f226b0, fcinfo_data = 0x2f22dc8, fn_addr = 0x93d60c , nargs = 2}(gdb)

6.循环解析参数args直接存储到fcinfo结构体中
第1个参数,是常量1

(gdb) n2218            Expr       *arg = (Expr *) lfirst(lc);(gdb) 2220            if (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) n2226                Const      *con = (Const *) arg;(gdb) 2228                fcinfo->arg[argno] = con->constvalue;(gdb) 2229                fcinfo->argnull[argno] = con->constisnull;(gdb) 2236            argno++;(gdb)

第2个参数,是Var,递归调用ExecInitExprRec解析

(gdb) 2216        foreach(lc, args)(gdb) 2218            Expr       *arg = (Expr *) lfirst(lc);(gdb) 2220            if (IsA(arg, Const))(gdb) 2233                ExecInitExprRec(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) n2236            argno++;(gdb) (gdb) n2216        foreach(lc, args)(gdb)

7.根据函数的严格性和统计级别插入相应的opcode

2240        if (pgstat_track_functions <= flinfo->fn_stats)(gdb) n2242            if (flinfo->fn_strict && nargs > 0)(gdb) 2243                scratch->opcode = EEOP_FUNCEXPR_STRICT;(gdb) p pgstat_track_functions$17 = 0(gdb) p flinfo->fn_stats$18 = 2 '\002'(gdb) n

完成调用

2254    }(gdb) ExecInitExprRec (node=0x2e675d8, state=0x2f228c0, resv=0x2f228c8, resnull=0x2f228c5) at execExpr.c:896896                 ExprEvalPushStep(state, &scratch);(gdb)

"怎么使用PostgreSQL的ExprEvalStep"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0