千家信息网

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

发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,本节继续介绍聚合函数的实现,主要介绍了agg_retrieve_hash_table函数中与投影相关的实现逻辑,主要是finalize_aggregates->finalize_aggregate.一
千家信息网最后更新 2025年01月20日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相关数据结构

函数 参数 步骤 数据 结果 输入 数组 状态 信息 模式 结构 上下 上下文 源码 位置 大小 拷贝 指针 状态值 面的 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 县级网络安全应急中心建设 浙江网络技术转让参考价 网络安全工程师有编制吗 32核图形处理器和服务器哪个快 软件开发研究生社招进国企 一般数据库cpu使用率 数据库相关的职业岗位有哪些 西甲数据库 怎么对服务器进行网络扫描 数据库应用机考0003 语荣软件开发有限公司怎么样 如何把软件安装在云服务器 高邑标准软件开发服务供应 软件开发行业饱和 新乡市邦胜网络技术有限公司 云计算属于计算机网络技术吗 网络安全第四十七条 贵州中西部服务器虚拟主机 网络技术服务费怎么做账 软件开发程序员任职资格 本地服务器无法连接数据库 无限宝服务器错误 网络安全工作协调会商机制 手机账号服务器异常怎么解决 网络安全宣传周活动全面启动 幻塔服务器红石塔 外国十大热门网络安全公司 广东调度服务器安装虚拟主机 软件开发师职业分析 软件开发方案设计范文下载
0