千家信息网

PostgreSQL 源码解读(190)- 查询#106(聚合函数#11 - finalize_aggregate)

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,本节继续介绍聚合函数的实现,主要介绍了agg_retrieve_hash_table函数中与投影相关的实现逻辑,主要是finalize_aggregates->finalize_aggregate.一
千家信息网最后更新 2025年11月07日PostgreSQL 源码解读(190)- 查询#106(聚合函数#11 - finalize_aggregate)

本节继续介绍聚合函数的实现,主要介绍了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 voidfinalize_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_aggregateBreakpoint 1 at 0x6ed256: file nodeAgg.c, line 901.(gdb) cContinuing.Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e390, pergroupstate=0x155f850, resultVal=0x154c0c8,     resultIsNull=0x154c100) at nodeAgg.c:901901        bool        anynull = false;(gdb)

输入参数

(gdb) p *aggstate$1 = {ss = {ps = {type = T_AggState, plan = 0x1575890, state = 0x154a428, ExecProcNode = 0x6ee438 ,       ExecProcNodeReal = 0x6ee438 , 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) n905        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 , 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 }, argnull = {false }}, serialfn_fcinfo = {flinfo = 0x0, context = 0x0,     resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 0, arg = {0 }, argnull = {      false }}, deserialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0, fncollation = 0,     isnull = false, nargs = 0, arg = {0 }, argnull = {false }}}(gdb)

解析所有的直接参数(无).

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

非有效的finalfn,直接赋值(这是max聚合)

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

切换回原上下文

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

第2个聚合是min,同样没有finalfn

(gdb) nfinalize_aggregates (aggstate=0x154a640, peraggs=0x154e390, pergroup=0x155f850) at nodeAgg.c:11601160        for (aggno = 0; aggno < aggstate->numaggs; aggno++)(gdb) cContinuing.Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e3e8, pergroupstate=0x155f860, resultVal=0x154c0d0,     resultIsNull=0x154c101) at nodeAgg.c:901901        bool        anynull = false;(gdb) n905        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) n907        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 , 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 },     argnull = {false }}, serialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0,     fncollation = 0, isnull = false, nargs = 0, arg = {0 }, argnull = {false }},   deserialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 0, arg = {      0 }, argnull = {false }}}(gdb)

第3个聚合运算是avg,存在finalfn

(gdb) cContinuing.Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e440, pergroupstate=0x155f870, resultVal=0x154c0d8,     resultIsNull=0x154c102) at nodeAgg.c:901901        bool        anynull = false;(gdb) n905        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 , 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 }, argnull = {false }}, serialfn_fcinfo = {flinfo = 0x0, context = 0x0,     resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 0, arg = {0 }, argnull = {      false }}, deserialfn_fcinfo = {flinfo = 0x0, context = 0x0, resultinfo = 0x0, fncollation = 0,     isnull = false, nargs = 0, arg = {0 }, argnull = {false }}}(gdb) p *peragg$13 = {aggref = 0x155b1d8, transno = 2, finalfn_oid = 1964, finalfn = {fn_addr = 0x978251 , 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) n915        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) n932            int            numFinalArgs = peragg->numFinalArgs;(gdb) 935            aggstate->curperagg = peragg;(gdb) p numFinalArgs$15 = 1(gdb) n937            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) n950            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 , 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) n957            if (fcinfo.flinfo->fn_strict && anynull)(gdb)

调用函数,获取结果值

(gdb) n965                *resultVal = FunctionCallInvoke(&fcinfo);(gdb) p *fcinfo.flinfo$18 = {fn_addr = 0x978251 , 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_avgBreakpoint 2 at 0x97825d: file numeric.c, line 5426.(gdb)

进入int8_avg

(gdb) cContinuing.Breakpoint 2, int8_avg (fcinfo=0x7fff94f5c160) at numeric.c:54265426        ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);(gdb) n5431        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) n5437        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) n5440        countd = DirectFunctionCall1(int8_numeric,(gdb) 5442        sumd = DirectFunctionCall1(int8_numeric,(gdb) 5445        PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));(gdb) x/1xg countd0x1572780:    0x0002800000000020(gdb) x/1xg sumd0x15727a0:    0x0037800000000020

调用完毕,回到finalize_aggregate

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

DONE!

四、参考资料

PostgreSQL 源码解读(178)- 查询#95(聚合函数)#1相关数据结构

0