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
语荣软件开发有限公司怎么样
如何把软件安装在云服务器
高邑标准软件开发服务供应
软件开发行业饱和
新乡市邦胜网络技术有限公司
云计算属于计算机网络技术吗
网络安全第四十七条
贵州中西部服务器虚拟主机
网络技术服务费怎么做账
软件开发程序员任职资格
本地服务器无法连接数据库
无限宝服务器错误
网络安全工作协调会商机制
手机账号服务器异常怎么解决
网络安全宣传周活动全面启动
幻塔服务器红石塔
外国十大热门网络安全公司
广东调度服务器安装虚拟主机
软件开发师职业分析
软件开发方案设计范文下载