亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

PostgreSQL 源碼解讀(190)- 查詢#106(聚合函數#11 - finalize_aggregate)

發布時間:2020-08-11 13:21:20 來源:ITPUB博客 閱讀:153 作者:husthxd 欄目:關系型數據庫

本節繼續介紹聚合函數的實現,主要介紹了agg_retrieve_hash_table函數中與投影相關的實現邏輯,主要是finalize_aggregates->finalize_aggregate.

一、數據結構

AggState
聚合函數執行時狀態結構體,內含AggStatePerAgg等結構體


/* ---------------------
 *    AggState information
 *
 *    ss.ss_ScanTupleSlot refers to output of underlying plan.
 *  ss.ss_ScanTupleSlot指的是基礎計劃的輸出.
 *    (ss = ScanState,ps = PlanState)
 *
 *    Note: ss.ps.ps_ExprContext contains ecxt_aggvalues and
 *    ecxt_aggnulls arrays, which hold the computed agg values for the current
 *    input group during evaluation of an Agg node's output tuple(s).  We
 *    create a second ExprContext, tmpcontext, in which to evaluate input
 *    expressions and run the aggregate transition functions.
 *    注意:ss.ps.ps_ExprContext包含了ecxt_aggvalues和ecxt_aggnulls數組,
 *      這兩個數組保存了在計算agg節點的輸出元組時當前輸入組已計算的agg值.
 * ---------------------
 */
/* these structs are private in nodeAgg.c: */
//在nodeAgg.c中私有的結構體
typedef struct AggStatePerAggData *AggStatePerAgg;
typedef struct AggStatePerTransData *AggStatePerTrans;
typedef struct AggStatePerGroupData *AggStatePerGroup;
typedef struct AggStatePerPhaseData *AggStatePerPhase;
typedef struct AggStatePerHashData *AggStatePerHash;
typedef struct AggState
{
    //第一個字段是NodeTag(繼承自ScanState)
    ScanState    ss;                /* its first field is NodeTag */
    //targetlist和quals中所有的Aggref
    List       *aggs;            /* all Aggref nodes in targetlist & quals */
    //鏈表的大小(可以為0)
    int            numaggs;        /* length of list (could be zero!) */
    //pertrans條目大小
    int            numtrans;        /* number of pertrans items */
    //Agg策略模式
    AggStrategy aggstrategy;    /* strategy mode */
    //agg-splitting模式,參見nodes.h
    AggSplit    aggsplit;        /* agg-splitting mode, see nodes.h */
    //指向當前步驟數據的指針
    AggStatePerPhase phase;        /* pointer to current phase data */
    //步驟數(包括0)
    int            numphases;        /* number of phases (including phase 0) */
    //當前步驟
    int            current_phase;    /* current phase number */
    //per-Aggref信息
    AggStatePerAgg peragg;        /* per-Aggref information */
    //per-Trans狀態信息
    AggStatePerTrans pertrans;    /* per-Trans state information */
    //長生命周期數據的ExprContexts(hashtable)
    ExprContext *hashcontext;    /* econtexts for long-lived data (hashtable) */
    ////長生命周期數據的ExprContexts(每一個GS使用)
    ExprContext **aggcontexts;    /* econtexts for long-lived data (per GS) */
    //輸入表達式的ExprContext
    ExprContext *tmpcontext;    /* econtext for input expressions */
#define FIELDNO_AGGSTATE_CURAGGCONTEXT 14
    //當前活躍的aggcontext
    ExprContext *curaggcontext; /* currently active aggcontext */
    //當前活躍的aggregate(如存在)
    AggStatePerAgg curperagg;    /* currently active aggregate, if any */
#define FIELDNO_AGGSTATE_CURPERTRANS 16
    //當前活躍的trans state
    AggStatePerTrans curpertrans;    /* currently active trans state, if any */
    //輸入結束?
    bool        input_done;        /* indicates end of input */
    //Agg掃描結束?
    bool        agg_done;        /* indicates completion of Agg scan */
    //最后一個grouping set
    int            projected_set;    /* The last projected grouping set */
#define FIELDNO_AGGSTATE_CURRENT_SET 20
    //將要解析的當前grouping set
    int            current_set;    /* The current grouping set being evaluated */
    //當前投影操作的分組列
    Bitmapset  *grouped_cols;    /* grouped cols in current projection */
    //倒序的分組列鏈表
    List       *all_grouped_cols;    /* list of all grouped cols in DESC order */
    /* These fields are for grouping set phase data */
    //-------- 下面的列用于grouping set步驟數據
    //所有步驟中最大的sets大小
    int            maxsets;        /* The max number of sets in any phase */
    //所有步驟的數組
    AggStatePerPhase phases;    /* array of all phases */
    //對于phases > 1,已排序的輸入信息
    Tuplesortstate *sort_in;    /* sorted input to phases > 1 */
    //對于下一個步驟,輸入已拷貝
    Tuplesortstate *sort_out;    /* input is copied here for next phase */
    //排序結果的slot
    TupleTableSlot *sort_slot;    /* slot for sort results */
    /* these fields are used in AGG_PLAIN and AGG_SORTED modes: */
    //------- 下面的列用于AGG_PLAIN和AGG_SORTED模式:
    //per-group指針的grouping set編號數組
    AggStatePerGroup *pergroups;    /* grouping set indexed array of per-group
                                     * pointers */
    //當前組的第一個元組拷貝
    HeapTuple    grp_firstTuple; /* copy of first tuple of current group */
    /* these fields are used in AGG_HASHED and AGG_MIXED modes: */
    //--------- 下面的列用于AGG_HASHED和AGG_MIXED模式:
    //是否已填充hash表?
    bool        table_filled;    /* hash table filled yet? */
    //hash桶數?
    int            num_hashes;
    //相應的哈希表數據數組
    AggStatePerHash perhash;    /* array of per-hashtable data */
    //per-group指針的grouping set編號數組
    AggStatePerGroup *hash_pergroup;    /* grouping set indexed array of
                                         * per-group pointers */
    /* support for evaluation of agg input expressions: */
    //---------- agg輸入表達式解析支持
#define FIELDNO_AGGSTATE_ALL_PERGROUPS 34
    //首先是->pergroups,然后是hash_pergroup
    AggStatePerGroup *all_pergroups;    /* array of first ->pergroups, than
                                         * ->hash_pergroup */
    //投影實現機制
    ProjectionInfo *combinedproj;    /* projection machinery */
} AggState;
/* Primitive options supported by nodeAgg.c: */
//nodeag .c支持的基本選項
#define AGGSPLITOP_COMBINE        0x01    /* substitute combinefn for transfn */
#define AGGSPLITOP_SKIPFINAL    0x02    /* skip finalfn, return state as-is */
#define AGGSPLITOP_SERIALIZE    0x04    /* apply serializefn to output */
#define AGGSPLITOP_DESERIALIZE    0x08    /* apply deserializefn to input */
/* Supported operating modes (i.e., useful combinations of these options): */
//支持的操作模式
typedef enum AggSplit
{
    /* Basic, non-split aggregation: */
    //基本 : 非split聚合
    AGGSPLIT_SIMPLE = 0,
    /* Initial phase of partial aggregation, with serialization: */
    //部分聚合的初始步驟,序列化
    AGGSPLIT_INITIAL_SERIAL = AGGSPLITOP_SKIPFINAL | AGGSPLITOP_SERIALIZE,
    /* Final phase of partial aggregation, with deserialization: */
    //部分聚合的最終步驟,反序列化
    AGGSPLIT_FINAL_DESERIAL = AGGSPLITOP_COMBINE | AGGSPLITOP_DESERIALIZE
} AggSplit;
/* Test whether an AggSplit value selects each primitive option: */
//測試AggSplit選擇了哪些基本選項
#define DO_AGGSPLIT_COMBINE(as)        (((as) & AGGSPLITOP_COMBINE) != 0)
#define DO_AGGSPLIT_SKIPFINAL(as)    (((as) & AGGSPLITOP_SKIPFINAL) != 0)
#define DO_AGGSPLIT_SERIALIZE(as)    (((as) & AGGSPLITOP_SERIALIZE) != 0)
#define DO_AGGSPLIT_DESERIALIZE(as) (((as) & AGGSPLITOP_DESERIALIZE) != 0)

二、源碼解讀

finalize_aggregate
finalize_aggregate計算聚合的最終結果,邏輯不復雜,自行查看源碼.


/*
 * Compute the final value of one aggregate.
 * 計算聚合的最終結果
 *
 * This function handles only one grouping set (already set in
 * aggstate->current_set).
 * 該函數只處理一個grouping set(已在aggstate->current_set中設置)
 *
 * The finalfunction will be run, and the result delivered, in the
 * output-tuple context; caller's CurrentMemoryContext does not matter.
 * 將執行finalfunction獲得最終結果并存儲在output-tuple上下文中.
 * 調用者的CurrentMemoryContext并不需要關心.
 *
 * The finalfn uses the state as set in the transno. This also might be
 * being used by another aggregate function, so it's important that we do
 * nothing destructive here.
 * finalfn使用在transno中設置運行狀態.
 * 這可能會被其他聚合函數使用,因此不要做任何的重組.
 */
static void
finalize_aggregate(AggState *aggstate,
                   AggStatePerAgg peragg,
                   AggStatePerGroup pergroupstate,
                   Datum *resultVal, bool *resultIsNull)
{
    FunctionCallInfoData fcinfo;
    bool        anynull = false;
    MemoryContext oldContext;
    int            i;
    ListCell   *lc;
    AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
    oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
    /*
     * Evaluate any direct arguments.  We do this even if there's no finalfn
     * (which is unlikely anyway), so that side-effects happen as expected.
     * The direct arguments go into arg positions 1 and up, leaving position 0
     * for the transition state value.
     * 解析所有的直接參數.
     * 就算沒有任何finalfn(這看起來不太可能)也會做這個事情,因此會如期產生一些其他影響.
     * 直接參數進入arg位置1及以上,留出了位置0作為過渡狀態值的位置。
     */
    i = 1;
    foreach(lc, peragg->aggdirectargs)
    {
        ExprState  *expr = (ExprState *) lfirst(lc);
        //函數調用參數
        fcinfo.arg[i] = ExecEvalExpr(expr,
                                     aggstate->ss.ps.ps_ExprContext,
                                     &fcinfo.argnull[i]);
        anynull |= fcinfo.argnull[i];
        i++;
    }
    /*
     * Apply the agg's finalfn if one is provided, else return transValue.
     * 如有finalfn則執行該函數,否則直接返回transValue
     */
    if (OidIsValid(peragg->finalfn_oid))
    {
        int            numFinalArgs = peragg->numFinalArgs;
        /* set up aggstate->curperagg for AggGetAggref() */
        //為AggGetAggref()設置aggstate->curperagg
        aggstate->curperagg = peragg;
        //初始化函數調用信息
        InitFunctionCallInfoData(fcinfo, &peragg->finalfn,
                                 numFinalArgs,
                                 pertrans->aggCollation,
                                 (void *) aggstate, NULL);
        /* Fill in the transition state value */
        //填充轉換狀態值
        fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
                                                   pergroupstate->transValueIsNull,
                                                   pertrans->transtypeLen);
        fcinfo.argnull[0] = pergroupstate->transValueIsNull;
        anynull |= pergroupstate->transValueIsNull;
        /* Fill any remaining argument positions with nulls */
        //使用nulls填充其他剩余參數
        for (; i < numFinalArgs; i++)
        {
            fcinfo.arg[i] = (Datum) 0;
            fcinfo.argnull[i] = true;
            anynull = true;
        }
        if (fcinfo.flinfo->fn_strict && anynull)
        {
            /* don't call a strict function with NULL inputs */
            //不要在調用嚴格函數時傳遞NULL參數
            *resultVal = (Datum) 0;
            *resultIsNull = true;
        }
        else
        {
            //調用函數,獲取結果值
            *resultVal = FunctionCallInvoke(&fcinfo);
            *resultIsNull = fcinfo.isnull;
        }
        aggstate->curperagg = NULL;
    }
    else
    {
        /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
        //不需要MakeExpandedObjectReadOnly,datumCopy會拷貝該數據.
        *resultVal = pergroupstate->transValue;
        *resultIsNull = pergroupstate->transValueIsNull;
    }
    /*
     * If result is pass-by-ref, make sure it is in the right context.
     * 如果結果通過引用傳遞,確保位于正確的上下文中.
     */
    if (!peragg->resulttypeByVal && !*resultIsNull &&
        !MemoryContextContains(CurrentMemoryContext,
                               DatumGetPointer(*resultVal)))
        *resultVal = datumCopy(*resultVal,
                               peragg->resulttypeByVal,
                               peragg->resulttypeLen);
    MemoryContextSwitchTo(oldContext);
}

三、跟蹤分析

測試腳本


-- 禁用并行
set max_parallel_workers_per_gather=0;
select bh,avg(c1),min(c1),max(c2) from t_agg_simple group by bh;

跟蹤分析


(gdb) b finalize_aggregate
Breakpoint 1 at 0x6ed256: file nodeAgg.c, line 901.
(gdb) c
Continuing.
Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e390, pergroupstate=0x155f850, resultVal=0x154c0c8, 
    resultIsNull=0x154c100) at nodeAgg.c:901
901        bool        anynull = false;
(gdb)

輸入參數


(gdb) p *aggstate
$1 = {ss = {ps = {type = T_AggState, plan = 0x1575890, state = 0x154a428, ExecProcNode = 0x6ee438 <ExecAgg>, 
      ExecProcNodeReal = 0x6ee438 <ExecAgg>, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, 
      qual = 0x0, lefttree = 0x154abb0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, 
      ps_ResultTupleSlot = 0x154b7b0, ps_ExprContext = 0x154aaf0, ps_ProjInfo = 0x154b8f0, scandesc = 0x154af00}, 
    ss_currentRelation = 0x0, ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x154b458}, aggs = 0x154be00, numaggs = 3, 
  numtrans = 3, aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE, phase = 0x154bef8, numphases = 1, current_phase = 0, 
  peragg = 0x154e390, pertrans = 0x15673e0, hashcontext = 0x154aa30, aggcontexts = 0x154a858, tmpcontext = 0x154a878, 
  curaggcontext = 0x154aa30, curperagg = 0x0, curpertrans = 0x1568c70, input_done = false, agg_done = false, 
  projected_set = -1, current_set = 0, grouped_cols = 0x154c028, all_grouped_cols = 0x154c090, maxsets = 1, 
  phases = 0x154bef8, sort_in = 0x0, sort_out = 0x0, sort_slot = 0x0, pergroups = 0x0, grp_firstTuple = 0x0, 
  table_filled = true, num_hashes = 1, perhash = 0x154bf50, hash_pergroup = 0x154e5a8, all_pergroups = 0x154e5a8, 
  combinedproj = 0x0}
(gdb) p *peragg
$2 = {aggref = 0x155b6e8, transno = 0, finalfn_oid = 0, finalfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, 
    fn_strict = false, fn_retset = false, fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, 
  numFinalArgs = 1, aggdirectargs = 0x0, resulttypeLen = 4, resulttypeByVal = true, shareable = true}
(gdb) p *pergroupstate
$3 = {transValue = 5, transValueIsNull = false, noTransValue = false}
(gdb) p *resultVal
$4 = 0
(gdb) p *resultIsNull
$5 = false
(gdb)

獲取轉換函數,切換上下文


(gdb) n
905        AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
(gdb) 
907        oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
(gdb) 
915        i = 1;
(gdb) p *pertrans
$6 = {aggref = 0x155b6e8, aggshared = false, numInputs = 1, numTransInputs = 1, transfn_oid = 768, serialfn_oid = 0, 
  deserialfn_oid = 0, aggtranstype = 23, transfn = {fn_addr = 0x93e877 <int4larger>, fn_oid = 768, fn_nargs = 2, 
    fn_strict = true, fn_retset = false, fn_stats = 2 '\002', fn_extra = 0x0, fn_mcxt = 0x154a310, fn_expr = 0x157a580}, 
  serialfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, fn_strict = false, fn_retset = false, fn_stats = 0 '\000', 
    fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, deserialfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, 
    fn_strict = false, fn_retset = false, fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, 
  aggCollation = 0, numSortCols = 0, numDistinctCols = 0, sortColIdx = 0x0, sortOperators = 0x0, sortCollations = 0x0, 
  sortNullsFirst = 0x0, equalfnOne = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, fn_strict = false, fn_retset = false, 
    fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, equalfnMulti = 0x0, initValue = 0, 
  initValueIsNull = true, inputtypeLen = 0, transtypeLen = 4, inputtypeByVal = false, transtypeByVal = true, 
  sortslot = 0x0, uniqslot = 0x0, sortdesc = 0x0, sortstates = 0x1550348, transfn_fcinfo = {flinfo = 0x1567408, 
    context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {40, 50, 
      0 <repeats 98 times>}, argnull = {false <repeats 100 times>}}, serialfn_fcinfo = {flinfo = 0x0, context = 0x0, 
    resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 0, arg = {0 <repeats 100 times>}, argnull = {
      false <repeats 100 times>}}, deserialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0, fncollation = 0, 
    isnull = false, nargs = 0, arg = {0 <repeats 100 times>}, argnull = {false <repeats 100 times>}}}
(gdb)

解析所有的直接參數(無).


(gdb) n
916        foreach(lc, peragg->aggdirectargs)
(gdb) p peragg->aggdirectargs
$7 = (List *) 0x0
(gdb) n
930        if (OidIsValid(peragg->finalfn_oid))
(gdb)

非有效的finalfn,直接賦值(這是max聚合)


(gdb) n
930        if (OidIsValid(peragg->finalfn_oid))
(gdb) p peragg->finalfn_oid
$8 = 0
(gdb) n
973            *resultVal = pergroupstate->transValue;
(gdb) 
974            *resultIsNull = pergroupstate->transValueIsNull;
(gdb) 
(gdb) p *resultVal
$9 = 5

切換回原上下文


(gdb) n
980        if (!peragg->resulttypeByVal && !*resultIsNull &&
(gdb) 
987        MemoryContextSwitchTo(oldContext);
(gdb) 
988    }

第2個聚合是min,同樣沒有finalfn


(gdb) n
finalize_aggregates (aggstate=0x154a640, peraggs=0x154e390, pergroup=0x155f850) at nodeAgg.c:1160
1160        for (aggno = 0; aggno < aggstate->numaggs; aggno++)
(gdb) c
Continuing.
Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e3e8, pergroupstate=0x155f860, resultVal=0x154c0d0, 
    resultIsNull=0x154c101) at nodeAgg.c:901
901        bool        anynull = false;
(gdb) n
905        AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
(gdb) p *peragg
$10 = {aggref = 0x155b460, transno = 1, finalfn_oid = 0, finalfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, 
    fn_strict = false, fn_retset = false, fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, 
  numFinalArgs = 1, aggdirectargs = 0x0, resulttypeLen = 4, resulttypeByVal = true, shareable = true}
(gdb) n
907        oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
(gdb) p *pertrans
$11 = {aggref = 0x155b460, aggshared = false, numInputs = 1, numTransInputs = 1, transfn_oid = 769, serialfn_oid = 0, 
  deserialfn_oid = 0, aggtranstype = 23, transfn = {fn_addr = 0x93e8a3 <int4smaller>, fn_oid = 769, fn_nargs = 2, 
    fn_strict = true, fn_retset = false, fn_stats = 2 '\002', fn_extra = 0x0, fn_mcxt = 0x154a310, fn_expr = 0x157a6d0}, 
  serialfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, fn_strict = false, fn_retset = false, fn_stats = 0 '\000', 
    fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, deserialfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, 
    fn_strict = false, fn_retset = false, fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, 
  aggCollation = 0, numSortCols = 0, numDistinctCols = 0, sortColIdx = 0x0, sortOperators = 0x0, sortCollations = 0x0, 
  sortNullsFirst = 0x0, equalfnOne = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, fn_strict = false, fn_retset = false, 
    fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, equalfnMulti = 0x0, initValue = 0, 
  initValueIsNull = true, inputtypeLen = 0, transtypeLen = 4, inputtypeByVal = false, transtypeByVal = true, 
  sortslot = 0x0, uniqslot = 0x0, sortdesc = 0x0, sortstates = 0x154e5d0, transfn_fcinfo = {flinfo = 0x1568050, 
    context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {2, 50, 0 <repeats 98 times>}, 
    argnull = {false <repeats 100 times>}}, serialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0, 
    fncollation = 0, isnull = false, nargs = 0, arg = {0 <repeats 100 times>}, argnull = {false <repeats 100 times>}}, 
  deserialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 0, arg = {
      0 <repeats 100 times>}, argnull = {false <repeats 100 times>}}}
(gdb)

第3個聚合運算是avg,存在finalfn


(gdb) c
Continuing.
Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e440, pergroupstate=0x155f870, resultVal=0x154c0d8, 
    resultIsNull=0x154c102) at nodeAgg.c:901
901        bool        anynull = false;
(gdb) n
905        AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
(gdb) 
907        oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
(gdb) p *pertrans
$12 = {aggref = 0x155b1d8, aggshared = false, numInputs = 1, numTransInputs = 1, transfn_oid = 1963, serialfn_oid = 0, 
  deserialfn_oid = 0, aggtranstype = 1016, transfn = {fn_addr = 0x977d8f <int4_avg_accum>, fn_oid = 1963, fn_nargs = 2, 
    fn_strict = true, fn_retset = false, fn_stats = 2 '\002', fn_extra = 0x0, fn_mcxt = 0x154a310, fn_expr = 0x157aa40}, 
  serialfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, fn_strict = false, fn_retset = false, fn_stats = 0 '\000', 
    fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, deserialfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, 
    fn_strict = false, fn_retset = false, fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, 
  aggCollation = 0, numSortCols = 0, numDistinctCols = 0, sortColIdx = 0x0, sortOperators = 0x0, sortCollations = 0x0, 
  sortNullsFirst = 0x0, equalfnOne = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, fn_strict = false, fn_retset = false, 
    fn_stats = 0 '\000', fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, equalfnMulti = 0x0, initValue = 22522136, 
  initValueIsNull = false, inputtypeLen = 0, transtypeLen = -1, inputtypeByVal = false, transtypeByVal = false, 
  sortslot = 0x0, uniqslot = 0x0, sortdesc = 0x0, sortstates = 0x154e5f0, transfn_fcinfo = {flinfo = 0x1568c98, 
    context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {22410736, 50, 
      0 <repeats 98 times>}, argnull = {false <repeats 100 times>}}, serialfn_fcinfo = {flinfo = 0x0, context = 0x0, 
    resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 0, arg = {0 <repeats 100 times>}, argnull = {
      false <repeats 100 times>}}, deserialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0, fncollation = 0, 
    isnull = false, nargs = 0, arg = {0 <repeats 100 times>}, argnull = {false <repeats 100 times>}}}
(gdb) p *peragg
$13 = {aggref = 0x155b1d8, transno = 2, finalfn_oid = 1964, finalfn = {fn_addr = 0x978251 <int8_avg>, fn_oid = 1964, 
    fn_nargs = 1, fn_strict = true, fn_retset = false, fn_stats = 2 '\002', fn_extra = 0x0, fn_mcxt = 0x154a310, 
    fn_expr = 0x157a7c0}, numFinalArgs = 1, aggdirectargs = 0x0, resulttypeLen = -1, resulttypeByVal = false, 
  shareable = true}
(gdb)

存在finalfn(int4_avg_accum)


(gdb) n
915        i = 1;
(gdb) 
916        foreach(lc, peragg->aggdirectargs)
(gdb) 
930        if (OidIsValid(peragg->finalfn_oid))
(gdb) p peragg->finalfn_oid
$14 = 1964
(gdb)

初始化函數調用信息&填充轉換狀態值&使用nulls填充其他剩余參數


(gdb) n
932            int            numFinalArgs = peragg->numFinalArgs;
(gdb) 
935            aggstate->curperagg = peragg;
(gdb) p numFinalArgs
$15 = 1
(gdb) n
937            InitFunctionCallInfoData(fcinfo, &peragg->finalfn,
(gdb) 
943            fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
(gdb) 
946            fcinfo.argnull[0] = pergroupstate->transValueIsNull;
(gdb) 
947            anynull |= pergroupstate->transValueIsNull;
(gdb) n
950            for (; i < numFinalArgs; i++)
(gdb) p fcinfo
$17 = {flinfo = 0x154e450, context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 1, arg = {
    22411432, 4696688, 70368744179327, 262183, 0, 22291296, 22291800, 72057594037927952, 139949568947584, 532575944705, 
    139949566113024, 11508082471248244084, 139950313735104, 22291264, 140735692522224, 8884187, 0, 0, 481036337152, 
    22088784, 140735692522064, 22324800, 22522520, 22522520, 1, 22519768, 16302624, 140735692522192, 16302624, 
    139950284069640, 1, 22519768, 140735692522160, 22341032, 140735692522224, 4696688, 140735692525536, 0, 0, 7135662, 
    12884901892, 22326664, 7124177, 139950314519480, 139949574157416, 139949574157415, 0, 139949574157392, 0, 22449600, 
    139950314519224, 22410736, 140735692522336, 9928139, 140735692522336, 22449600, 125, 22291296, 4317427920, 
    536893372416, 140735692522368, 10923480, 536887362208, 22291264, 140735692522432, 8890594, 4294967296, 139949568947584, 
    22449600, 22410680, 16450208, 9441796618804569664, 140735692522548, 139949568947608, 125, 72057594060219232, 
    140735692522512, 8881213, 140735692522512, 16450208, 140735692522548, 139949568947608, 140735692522576, 8891011, 
    4317417729, 139949568947584, 9441796623099544216, 9441796618782244874, 16450208, 536893253520, 140735692522608, 
    8899958, 139949574149760, 536893253368, 140735692522640, 7227524, 4317293960, 22326664, 140735692522720, 7406960}, 
  argnull = {false, 197, 245, 148, 255, 127, false, false, 176, 171, 84, true, false, false, false, false, 48, false, 
    false, false, true, false <repeats 11 times>, 136, 173, 84, true, false, false, false, false, 232, 132, 87, true, true, 
    false, false, false, 40, 164, 84, true, false, false, false, false, 104, 176, 87, true, false, false, false, false, 48, 
    197, 245, 148, 255, 127, false, false, 67, 35, 110, false, false, false, false, false, 32, 174, 84, true, false, false, 
    false, false, 118, 5, 113, false, false, false, false, false, 171, 4, 113, false}}
(gdb) 
(gdb) n
957            if (fcinfo.flinfo->fn_strict && anynull)
(gdb)

調用函數,獲取結果值


(gdb) n
965                *resultVal = FunctionCallInvoke(&fcinfo);
(gdb) p *fcinfo.flinfo
$18 = {fn_addr = 0x978251 <int8_avg>, fn_oid = 1964, fn_nargs = 1, fn_strict = true, fn_retset = false, 
  fn_stats = 2 '\002', fn_extra = 0x0, fn_mcxt = 0x154a310, fn_expr = 0x157a7c0}
(gdb) p *fcinfo.flinfo->fn_expr
$19 = {type = T_FuncExpr}
(gdb) b int8_avg
Breakpoint 2 at 0x97825d: file numeric.c, line 5426.
(gdb)

進入int8_avg


(gdb) c
Continuing.
Breakpoint 2, int8_avg (fcinfo=0x7fff94f5c160) at numeric.c:5426
5426        ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
(gdb) n
5431        if (ARR_HASNULL(transarray) ||
(gdb) 
5432            ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
(gdb) 
5431        if (ARR_HASNULL(transarray) ||
(gdb) 
5434        transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
(gdb) n
5437        if (transdata->count == 0)
(gdb) p *transarray
$1 = {vl_len_ = 160, ndim = 1, dataoffset = 0, elemtype = 20}
(gdb) p *transdata
$2 = {count = 2, sum = 55}
(gdb)

準備參數,調用numeric_div函數


(gdb) n
5440        countd = DirectFunctionCall1(int8_numeric,
(gdb) 
5442        sumd = DirectFunctionCall1(int8_numeric,
(gdb) 
5445        PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
(gdb) x/1xg countd
0x1572780:    0x0002800000000020
(gdb) x/1xg sumd
0x15727a0:    0x0037800000000020

調用完畢,回到finalize_aggregate


gdb) n
5446    }
(gdb) 
finalize_aggregate (aggstate=0x1578960, peragg=0x157a730, pergroupstate=0x1570b40, resultVal=0x157a3f8, 
    resultIsNull=0x157a422) at nodeAgg.c:966
966                *resultIsNull = fcinfo.isnull;
(gdb) 
(gdb) p *resultVal
$10 = 22489080
(gdb) p resultVal
$11 = (Datum *) 0x157a3f8
(gdb) x/1xg resultVal
0x157a3f8:    0x00000000015727f8
(gdb) x/1fg resultVal
0x157a3f8:    1.1111081834575461e-316
(gdb) x/1fw resultVal
0x157a3f8:    3.95179395e-38

DONE!

四、參考資料

PostgreSQL 源碼解讀(178)- 查詢#95(聚合函數)#1相關數據結構

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

涟水县| 曲阜市| 通山县| 东台市| 岳阳县| 金堂县| 宝兴县| 新巴尔虎左旗| 金塔县| 彰武县| 石楼县| 台南县| 积石山| 扎赉特旗| 鄯善县| 齐齐哈尔市| 九寨沟县| 尤溪县| 阿合奇县| 阳春市| 铁岭市| 佛山市| 香格里拉县| 钦州市| 盐亭县| 洛浦县| 阳西县| 池州市| 射阳县| 常熟市| 两当县| 溆浦县| 项城市| 随州市| 扬州市| 康平县| 库车县| 钦州市| 循化| 南宁市| 平湖市|