溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么使用PostgreSQL的ExprEvalStep

發(fā)布時間:2021-11-09 14:38:28 來源:億速云 閱讀:154 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫

本篇內(nèi)容介紹了“怎么使用PostgreSQL的ExprEvalStep”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

ExprEvalStep
表達(dá)式解析步驟結(jié)構(gòu)體

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).
     * 待執(zhí)行指令.
     * 在指令準(zhǔn)備期間這是枚舉型的ExprEvalOp,
     *   但后續(xù)會被改變?yōu)槟承┢渌愋?比如用于goto的指針,因此被定義為intprt_t類型
     */
    intptr_t    opcode;
    /* where to store the result of this step */
    //存儲該步驟的結(jié)果
    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).
     * 操作的內(nèi)聯(lián)數(shù)據(jù).
     * 內(nèi)聯(lián)數(shù)據(jù)用于更快的訪問,但同時會導(dǎo)致指令的盤膨脹.
     * 聯(lián)合體在64-bit系統(tǒng)上應(yīng)保持在40字節(jié)范圍內(nèi)
     * (因此整個結(jié)構(gòu)體不應(yīng)大于64字節(jié),普通系統(tǒng)上的單個緩存線大小)
     */
    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是常規(guī)VAR的attr number - 1
            /* but it's just the normal (negative) attr number for SYSVAR */
            //對于SYSVAR,該值是常規(guī)的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
        {
            //函數(shù)的檢索數(shù)據(jù)
            FmgrInfo   *finfo;  /* function's lookup data */
            //參數(shù)信息等
            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
在函數(shù)通過fmgr調(diào)用前,該結(jié)構(gòu)體持有系統(tǒng)目錄(字典)信息,用于檢索相關(guān)信息.
如果相同的函數(shù)將被調(diào)用多次,檢索只需要完成一次即可,該結(jié)構(gòu)體會緩存多次使用.

/*
 * 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.
 * 在函數(shù)通過fmgr調(diào)用前,該結(jié)構(gòu)體持有系統(tǒng)目錄(字典)信息,用于檢索相關(guān)信息.
 * 如果相同的函數(shù)將被調(diào)用多次,檢索只需要完成一次即可,該結(jié)構(gòu)體會緩存多次使用.
 *
 * 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實際上是關(guān)于參數(shù)的解析時確定的信息,而不是函數(shù)自身.
 * 但fn_expr在這里存儲而不是FunctionCallInfoData中存儲,因為從邏輯上來說,它就應(yīng)該屬于那.
 *
 * 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可用于被調(diào)用函數(shù)的使用;所有其他字段應(yīng)該在結(jié)構(gòu)體創(chuàng)建后被處理為只讀.
 */
typedef struct FmgrInfo
{
    //指向函數(shù)或者將被調(diào)用的處理器
    PGFunction  fn_addr;        /* pointer to function or handler to be called */
    //函數(shù)的oid
    Oid         fn_oid;         /* OID of function (NOT of handler, if any) */
    //輸入?yún)?shù)的個數(shù),0..FUNC_MAX_ARGS
    short       fn_nargs;       /* number of input args (0..FUNC_MAX_ARGS) */
    //函數(shù)是否嚴(yán)格(strict),輸入NULL,輸出NULL
    bool        fn_strict;      /* function is "strict" (NULL in => NULL out) */
    //函數(shù)是否返回集合
    bool        fn_retset;      /* function returns a set */
    //如track_functions > this,則收集統(tǒng)計信息
    unsigned char fn_stats;     /* collect stats if track_functions > this */
    //handler使用的額外空間
    void       *fn_extra;       /* extra space for use by handler */
    //存儲fn_extra的內(nèi)存上下文
    MemoryContext fn_mcxt;      /* memory context to store fn_extra in */
    //表達(dá)式解析樹,或者為NULL
    fmNodePtr   fn_expr;        /* expression parse tree for call, or NULL */
} FmgrInfo;
typedef struct Node *fmNodePtr;

FunctionCallInfoData
該結(jié)構(gòu)體存儲了實際傳遞給fmgr-called函數(shù)的參數(shù)

/*
 * This struct is the data actually passed to an fmgr-called function.
 * 該結(jié)構(gòu)體存儲了實際傳遞給fmgr-called函數(shù)的參數(shù)
 *
 * 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.)
 * 被調(diào)用的函數(shù)期望設(shè)置isnull以及可能的resultinfo或者resultinfo指向的域字段.
 * 不應(yīng)該改變其他字段.
 * (特別的,在參數(shù)數(shù)組上亂寫是個壞主意,因為某些調(diào)用者假定它們可以使用相同的參數(shù)重復(fù)調(diào)用)
 */
typedef struct FunctionCallInfoData
{
    //指向該調(diào)用的檢索信息
    FmgrInfo   *flinfo;         /* ptr to lookup info used for this call */
    //調(diào)用上下文
    fmNodePtr   context;        /* pass info about context of call */
    //傳遞或返回關(guān)于結(jié)果的特別信息
    fmNodePtr   resultinfo;     /* pass or return extra info about result */
    //函數(shù)的collation
    Oid         fncollation;    /* collation for function to use */
#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4
    //如結(jié)果為NULL,則必須設(shè)置為T
    bool        isnull;         /* function must set true if result is NULL */
    //實際傳遞的參數(shù)個數(shù)
    short       nargs;          /* # arguments actually passed */
#define FIELDNO_FUNCTIONCALLINFODATA_ARG 6
    //傳遞給函數(shù)的參數(shù)
    Datum       arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
#define FIELDNO_FUNCTIONCALLINFODATA_ARGNULL 7
    //如arg[i]為NULL,則對應(yīng)的值為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.)
 * 所有函數(shù)可以通過fmgr直接調(diào)用,但必須持有簽名.
 * (其他函數(shù)可通過使用handler的方式調(diào)用,也有此簽名)
 */
typedef struct FunctionCallInfoData *FunctionCallInfo;

二、源碼解讀

ExecInitFunc函數(shù)為類函數(shù)表達(dá)式的執(zhí)行配置步驟,在*state的steps中追加參數(shù)解析步驟,同時設(shè)置*scratch以便可以push到步驟中.
其主要邏輯如下:
1.檢查調(diào)用函數(shù)的權(quán)限
2.檢查nargs是否合法
3.為該調(diào)用分配函數(shù)檢索數(shù)據(jù)和參數(shù)空間
4.配置主要的fmgr檢索信息
5.初始化函數(shù)調(diào)用參數(shù)結(jié)構(gòu)體
6.解析參數(shù)直接存儲到fcinfo結(jié)構(gòu)體中
7.根據(jù)函數(shù)的嚴(yán)格性和統(tǒng)計級別插入相應(yīng)的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.
 * 為類函數(shù)表達(dá)式的執(zhí)行配置步驟,在*state的steps中追加參數(shù)解析步驟,
 *   同時設(shè)置*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,以便調(diào)用者可以覆蓋opcode,這在DISTINCT這類操作時很有用.
 */
static void
ExecInitFunc(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 */
    //檢查調(diào)用函數(shù)的權(quán)限
    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.在通常的環(huán)境下,這不會出現(xiàn)異常.
     * 但如果服務(wù)器使用FUNC_MAX_ARGS宏定義比某些在pg_proc中定義的函數(shù)要小時會出現(xiàn)問題.
     */
    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 */
    //為該調(diào)用分配函數(shù)檢索數(shù)據(jù)和參數(shù)空間
    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 */
    //初始化函數(shù)調(diào)用參數(shù)結(jié)構(gòu)體
    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函數(shù)
    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 */
    //解析參數(shù)直接存儲到fcinfo結(jié)構(gòu)體中
    argno = 0;
    foreach(lc, args)
    {
        //遍歷參數(shù)
        Expr       *arg = (Expr *) lfirst(lc);
        if (IsA(arg, Const))
        {
            //常量
            /*
             * Don't evaluate const arguments every round; especially
             * interesting for constants in comparisons.
             * 不要每輪都對常量參數(shù)進行解析,只需要關(guān)注在對比中感興趣的常量即可.
             */
            Const      *con = (Const *) arg;
            fcinfo->arg[argno] = con->constvalue;
            fcinfo->argnull[argno] = con->constisnull;
        }
        else
        {
            //非常量,則遞歸調(diào)用
            ExecInitExprRec(arg, state,
                            &fcinfo->arg[argno], &fcinfo->argnull[argno]);
        }
        argno++;
    }
    /* Insert appropriate opcode depending on strictness and stats level */
    //根據(jù)函數(shù)的嚴(yán)格性和統(tǒng)計級別插入相應(yīng)的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;

設(shè)置斷點,跟蹤

(gdb) b ExecInitFunc
Breakpoint 1 at 0x6c8c33: file execExpr.c, line 2160.
(gdb) c
Continuing.
Breakpoint 1, ExecInitFunc (scratch=0x7ffd862de730, node=0x2e675d8, args=0x2e67520, funcid=177, inputcollid=0, 
    state=0x2f228c0) at execExpr.c:2160
2160        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)

輸入?yún)?shù)

(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節(jié)點
$3 = {xpr = {type = T_OpExpr}, opno = 551, opfuncid = 177, opresulttype = 23, opretset = false, opcollid = 0, 
  inputcollid = 0, args = 0x2e67520, location = 8}
testdb=# \x
Expanded display is on.
testdb=# select * from pg_proc where oid=177; --> opfuncid = 177對應(yīng)的系統(tǒng)proc
-[ RECORD 1 ]---+-------
proname         | int4pl
pronamespace    | 11
proowner        | 10
prolang         | 12
procost         | 1
prorows         | 0
provariadic     | 0
protransform    | -
prokind         | f
prosecdef       | f
proleakproof    | f
proisstrict     | t
proretset       | f
provolatile     | i
proparallel     | s
pronargs        | 2
pronargdefaults | 0
prorettype      | 23
proargtypes     | 23 23
proallargtypes  | 
proargmodes     | 
proargnames     | 
proargdefaults  | 
protrftypes     | 
prosrc          | int4pl
probin          | 
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.檢查調(diào)用函數(shù)的權(quán)限

(gdb) n
2168        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.為該調(diào)用分配函數(shù)檢索數(shù)據(jù)和參數(shù)空間

(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 <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.初始化函數(shù)調(diào)用參數(shù)結(jié)構(gòu)體

(gdb) 
2198        InitFunctionCallInfoData(*fcinfo, flinfo,
(gdb) n
2202        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 <int4pl>
(gdb) p *fcinfo
$11 = {flinfo = 0x2f226b0, context = 0x0, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {
    0 <repeats 100 times>}, argnull = {false <repeats 100 times>}}
(gdb) p scratch->d.func
$12 = {finfo = 0x2f226b0, fcinfo_data = 0x2f22dc8, fn_addr = 0x93d60c <int4pl>, nargs = 2}
(gdb)

6.循環(huán)解析參數(shù)args直接存儲到fcinfo結(jié)構(gòu)體中
第1個參數(shù),是常量1

(gdb) n
2218            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) n
2226                Const      *con = (Const *) arg;
(gdb) 
2228                fcinfo->arg[argno] = con->constvalue;
(gdb) 
2229                fcinfo->argnull[argno] = con->constisnull;
(gdb) 
2236            argno++;
(gdb)

第2個參數(shù),是Var,遞歸調(diào)用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) n
2236            argno++;
(gdb) 
(gdb) n
2216        foreach(lc, args)
(gdb)

7.根據(jù)函數(shù)的嚴(yán)格性和統(tǒng)計級別插入相應(yīng)的opcode

2240        if (pgstat_track_functions <= flinfo->fn_stats)
(gdb) n
2242            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

完成調(diào)用

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

“怎么使用PostgreSQL的ExprEvalStep”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI