溫馨提示×

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

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

PostgreSQL如何解析表達(dá)式.

發(fā)布時(shí)間:2021-11-09 14:32:57 來(lái)源:億速云 閱讀:469 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫(kù)

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


SQL樣例腳本.

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

一、數(shù)據(jù)結(jié)構(gòu)

FmgrInfo
在函數(shù)通過(guò)fmgr調(diào)用前,該結(jié)構(gòu)體持有系統(tǒng)目錄(字典)信息,用于檢索相關(guān)信息.
如果相同的函數(shù)將被調(diào)用多次,檢索只需要完成一次即可,該結(jié)構(gòu)體會(huì)緩存多次使用.

/*
 * 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ù)通過(guò)fmgr調(diào)用前,該結(jié)構(gòu)體持有系統(tǒng)目錄(字典)信息,用于檢索相關(guān)信息.
 * 如果相同的函數(shù)將被調(diào)用多次,檢索只需要完成一次即可,該結(jié)構(gòu)體會(huì)緩存多次使用.
 *
 * 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實(shí)際上是關(guān)于參數(shù)的解析時(shí)確定的信息,而不是函數(shù)自身.
 * 但fn_expr在這里存儲(chǔ)而不是FunctionCallInfoData中存儲(chǔ),因?yàn)閺倪壿嬌蟻?lái)說(shuō),它就應(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ù)的個(gè)數(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)計(jì)信息
    unsigned char fn_stats;     /* collect stats if track_functions > this */
    //handler使用的額外空間
    void       *fn_extra;       /* extra space for use by handler */
    //存儲(chǔ)fn_extra的內(nèi)存上下文
    MemoryContext fn_mcxt;      /* memory context to store fn_extra in */
    //表達(dá)式解析樹(shù),或者為NULL
    fmNodePtr   fn_expr;        /* expression parse tree for call, or NULL */
} FmgrInfo;
typedef struct Node *fmNodePtr;

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

/*
 * This struct is the data actually passed to an fmgr-called function.
 * 該結(jié)構(gòu)體存儲(chǔ)了實(shí)際傳遞給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ù)組上亂寫(xiě)是個(gè)壞主意,因?yàn)槟承┱{(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ù)個(gè)數(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,則對(duì)應(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ù)可以通過(guò)fmgr直接調(diào)用,但必須持有簽名.
 * (其他函數(shù)可通過(guò)使用handler的方式調(diào)用,也有此簽名)
 */
typedef struct FunctionCallInfoData *FunctionCallInfo;

二、源碼解讀

ExecInterpExpr
ExecInterpExpr中與表達(dá)式求值相關(guān)的代碼片段如下:

EEO_CASE(EEOP_FUNCEXPR)
        {
            FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
            Datum       d;
            fcinfo->isnull = false;
            d = op->d.func.fn_addr(fcinfo);
            *op->resvalue = d;
            *op->resnull = fcinfo->isnull;
            EEO_NEXT();
        }

如為函數(shù)表達(dá)式,則從ExecInitFunc初始化的步驟信息中獲取統(tǒng)一的調(diào)用參數(shù)fcinfo,然后通過(guò)函數(shù)指針(用于封裝)調(diào)用實(shí)際的函數(shù)進(jìn)行表達(dá)式求值.通過(guò)統(tǒng)一的參數(shù),統(tǒng)一的返回值,做到了實(shí)現(xiàn)的統(tǒng)一,體現(xiàn)了面向?qū)ο驩O中多態(tài)的思想,這再次說(shuō)明了OO是思想,用過(guò)程性語(yǔ)言一樣可以實(shí)現(xiàn).

int4pl
SQL樣例腳本相應(yīng)的實(shí)現(xiàn)函數(shù)是int4pl,其實(shí)現(xiàn)代碼如下:

Datum
int4pl(PG_FUNCTION_ARGS)
{
    int32       arg1 = PG_GETARG_INT32(0);
    int32       arg2 = PG_GETARG_INT32(1);
    int32       result;
    if (unlikely(pg_add_s32_overflow(arg1, arg2, &result)))
        ereport(ERROR,
                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                 errmsg("integer out of range")));
    PG_RETURN_INT32(result);
}
/*
 * If a + b overflows, return true, otherwise store the result of a + b into
 * *result. The content of *result is implementation defined in case of
 * overflow.
 */
static inline bool
pg_add_s32_overflow(int32 a, int32 b, int32 *result)
{
#if defined(HAVE__BUILTIN_OP_OVERFLOW)
    return __builtin_add_overflow(a, b, result);
#else
    int64       res = (int64) a + (int64) b;
    if (res > PG_INT32_MAX || res < PG_INT32_MIN)
    {
        *result = 0x5EED;       /* to avoid spurious warnings */
        return true;
    }
    *result = (int32) res;
    return false;
#endif
}

函數(shù)實(shí)現(xiàn)相對(duì)比較簡(jiǎn)單,兩個(gè)數(shù)簡(jiǎn)單相加,如溢出則返回T,否則返回F.

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

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

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

AI