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 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 ,
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) 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 , 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) 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 , 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) 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 , 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) 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 , 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 , 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相关数据结构
名称栏目:PostgreSQL源码解读(190)-查询#106(聚合函数#11-finalize_aggregate)
文章地址:http://ybzwz.com/article/pcepoc.html