千家信息网

PostgreSQL ExecAgg中调用的函数是什么

发表于:2025-01-24 作者:千家信息网编辑
千家信息网最后更新 2025年01月24日,本篇内容主要讲解"PostgreSQL ExecAgg中调用的函数是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"PostgreSQL ExecAgg
千家信息网最后更新 2025年01月24日PostgreSQL ExecAgg中调用的函数是什么

本篇内容主要讲解"PostgreSQL ExecAgg中调用的函数是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"PostgreSQL ExecAgg中调用的函数是什么"吧!

一、数据结构

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)

二、源码解读

ExecAgg接收从outer子计划返回的元组合适的属性上为每一个聚合函数(出现在投影列或节点表达式)执行聚合.需要聚合的元组数量依赖于是否已分组或者选择普通聚合.在已分组的聚合操作宏,为每一个组产生结果行;普通聚合,整个查询只有一个结果行.
不管哪种情况,每一个聚合结果值都会存储在表达式上下文中(ExecProject会解析结果元组)

/* * ExecAgg - * *      ExecAgg receives tuples from its outer subplan and aggregates over *      the appropriate attribute for each aggregate function use (Aggref *      node) appearing in the targetlist or qual of the node.  The number *      of tuples to aggregate over depends on whether grouped or plain *      aggregation is selected.  In grouped aggregation, we produce a result *      row for each group; in plain aggregation there's a single result row *      for the whole query.  In either case, the value of each aggregate is *      stored in the expression context to be used when ExecProject evaluates *      the result tuple. *       ExecAgg接收从outer子计划返回的元组合适的属性上为每一个聚合函数(出现在投影列或节点表达式)执行聚合. *    需要聚合的元组数量依赖于是否已分组或者选择普通聚合. *    在已分组的聚合操作宏,为每一个组产生结果行;普通聚合,整个查询只有一个结果行. *    不管哪种情况,每一个聚合结果值都会存储在表达式上下文中(ExecProject会解析结果元组) */static TupleTableSlot *ExecAgg(PlanState *pstate){    AggState   *node = castNode(AggState, pstate);    TupleTableSlot *result = NULL;    CHECK_FOR_INTERRUPTS();    if (!node->agg_done)    {        /* Dispatch based on strategy */        //基于策略进行分发        switch (node->phase->aggstrategy)        {            case AGG_HASHED:                if (!node->table_filled)                    agg_fill_hash_table(node);                /* FALLTHROUGH */                //填充后,执行MIXED            case AGG_MIXED:                result = agg_retrieve_hash_table(node);                break;            case AGG_PLAIN:            case AGG_SORTED:                result = agg_retrieve_direct(node);                break;        }        if (!TupIsNull(result))            return result;    }    return NULL;}

agg_retrieve_hash_table
ExecAgg(Hash实现版本):在hash表中检索组
大体实现逻辑如下:
1.初始化相关变量,如上下文/peragg等
2.未完成,循环
2.1从perhash数据结构中获取slot
2.2调用ScanTupleHashTable获取条目
2.3如返回的条目为NULL,切换到下一个set,如已完成检索,则设置标记,退出
2.4如返回的条目不为NULL,则:
2.4.1重置内econtext上下文
2.4.2存储最小化元组
2.4.3重置firstSlot,存储该虚拟元组
2.4.4准备投影slot并执行最终的聚合运算,投影后如结果不为NULL,则返回此结果.

/* * ExecAgg for hashed case: retrieving groups from hash table * ExecAgg(Hash实现版本):在hash表中检索组 */static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate){    ExprContext *econtext;    AggStatePerAgg peragg;    AggStatePerGroup pergroup;    TupleHashEntryData *entry;    TupleTableSlot *firstSlot;    TupleTableSlot *result;    AggStatePerHash perhash;    /*     * get state info from node.     * 从node节点中获取状态信息.     *     * econtext is the per-output-tuple expression context.     * econtext是per-output-tuple表达式上下文.     */    econtext = aggstate->ss.ps.ps_ExprContext;    peragg = aggstate->peragg;    firstSlot = aggstate->ss.ss_ScanTupleSlot;    /*     * Note that perhash (and therefore anything accessed through it) can     * change inside the loop, as we change between grouping sets.     * 注意,在分组之间切换时,perhash在循环中可能会改变     */    perhash = &aggstate->perhash[aggstate->current_set];    /*     * We loop retrieving groups until we find one satisfying     * aggstate->ss.ps.qual     * 循环检索groups,直至检索到一个符合aggstate->ss.ps.qual条件的组.     */    while (!aggstate->agg_done)    {        //------------- 选好        //获取Slot        TupleTableSlot *hashslot = perhash->hashslot;        int            i;        //检查中断        CHECK_FOR_INTERRUPTS();        /*         * Find the next entry in the hash table         * 检索hash表的下一个条目         */        entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);        if (entry == NULL)        {            //条目为NULL,切换到下一个set            int            nextset = aggstate->current_set + 1;            if (nextset < aggstate->num_hashes)            {                /*                 * Switch to next grouping set, reinitialize, and restart the                 * loop.                 * 切换至下一个grouping set,重新初始化并重启循环                 */                select_current_set(aggstate, nextset, true);                perhash = &aggstate->perhash[aggstate->current_set];                ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);                continue;            }            else            {                /* No more hashtables, so done */                //已完成检索,设置标记,退出                aggstate->agg_done = true;                return NULL;            }        }        /*         * Clear the per-output-tuple context for each group         * 为每一个group清除per-output-tuple上下文         *         * We intentionally don't use ReScanExprContext here; if any aggs have         * registered shutdown callbacks, they mustn't be called yet, since we         * might not be done with that agg.         * 在这里不会用到ReScanExprContext,如果存在aggs注册了shutdown回调,         *   那应该还没有调用,因为我们可能还没有完成该agg的处理.         */        ResetExprContext(econtext);        /*         * Transform representative tuple back into one with the right         * columns.         * 将典型元组转回具有正确列的元组.         */        ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);        slot_getallattrs(hashslot);        //清理元组        //重置firstSlot        ExecClearTuple(firstSlot);        memset(firstSlot->tts_isnull, true,               firstSlot->tts_tupleDescriptor->natts * sizeof(bool));        for (i = 0; i < perhash->numhashGrpCols; i++)        {            //重置firstSlot            int            varNumber = perhash->hashGrpColIdxInput[i] - 1;            firstSlot->tts_values[varNumber] = hashslot->tts_values[i];            firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];        }        ExecStoreVirtualTuple(firstSlot);        pergroup = (AggStatePerGroup) entry->additional;        /*         * Use the representative input tuple for any references to         * non-aggregated input columns in the qual and tlist.         * 为qual和tlist中的非聚合输入列依赖使用典型输入元组         */        econtext->ecxt_outertuple = firstSlot;        //准备投影slot        prepare_projection_slot(aggstate,                                econtext->ecxt_outertuple,                                aggstate->current_set);        //最终的聚合操作        finalize_aggregates(aggstate, peragg, pergroup);        //投影        result = project_aggregates(aggstate);        if (result)            return result;    }    /* No more groups */    //没有更多的groups了,返回NULL    return NULL;}#define ScanTupleHashTable(htable, iter) \    tuplehash_iterate(htable->hashtab, iter)/* -------------------------------- *        ExecStoreMinimalTuple * *        Like ExecStoreTuple, but insert a "minimal" tuple into the slot. *        与ExecStoreTuple类似,不同的是插入一个"最小化"的元组到slot中. * * No 'buffer' parameter since minimal tuples are never stored in relations. * 不需要"buffer"参数,因为最小化元组不会存储到relations中. * -------------------------------- */TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup,                      TupleTableSlot *slot,                      bool shouldFree){    /*     * sanity checks     * 一致性校验     */    Assert(mtup != NULL);    Assert(slot != NULL);    Assert(slot->tts_tupleDescriptor != NULL);    /*     * Free any old physical tuple belonging to the slot.     * 释放归属于该slot的旧物理元组     */    if (slot->tts_shouldFree)        heap_freetuple(slot->tts_tuple);    if (slot->tts_shouldFreeMin)        heap_free_minimal_tuple(slot->tts_mintuple);    /*     * Drop the pin on the referenced buffer, if there is one.     * 清除已依赖buffer的pin标记     */    if (BufferIsValid(slot->tts_buffer))        ReleaseBuffer(slot->tts_buffer);    slot->tts_buffer = InvalidBuffer;    /*     * Store the new tuple into the specified slot.     * 存储新tuple到指定的slot中     */    slot->tts_isempty = false;    slot->tts_shouldFree = false;    slot->tts_shouldFreeMin = shouldFree;    slot->tts_tuple = &slot->tts_minhdr;    slot->tts_mintuple = mtup;    slot->tts_minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;    slot->tts_minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);    /* no need to set t_self or t_tableOid since we won't allow access */    //因为不允许访问,因此无需设置t_sefl或者t_tableOid    /* Mark extracted state invalid */    //标记已提取状态无效    slot->tts_nvalid = 0;    return slot;}/* -------------------------------- *        ExecStoreVirtualTuple *            Mark a slot as containing a virtual tuple. *            标记slot包含虚拟元组 * * The protocol for loading a slot with virtual tuple data is: *        * Call ExecClearTuple to mark the slot empty. *        * Store data into the Datum/isnull arrays. *        * Call ExecStoreVirtualTuple to mark the slot valid. * This is a bit unclean but it avoids one round of data copying. * 使用虚拟元组数据的协议如下: *         * 调用ExecClearTuple标记slot为空 *        * 存储数据到Datum/isnull数组中 *        * 调用ExecStoreVirtualTuple标记slot有效 * -------------------------------- */TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot){    /*     * sanity checks     * 一致性检查     */    Assert(slot != NULL);    Assert(slot->tts_tupleDescriptor != NULL);    Assert(slot->tts_isempty);    slot->tts_isempty = false;    slot->tts_nvalid = slot->tts_tupleDescriptor->natts;    return slot;}

三、跟踪分析

测试脚本

-- 创建数据表,插入测试数据drop table  if exists t_agg_simple;create table t_agg_simple(bh varchar(20),c1 int,c2 int,c3 int,c4 int,c5 int,c6 int);insert into t_agg_simple select 'GZ01',col,col,col,col,col,col from generate_series(1,1) as col;insert into t_agg_simple select 'GZ02',col,col,col,col,col,col from generate_series(2,2) as col;insert into t_agg_simple select 'GZ03',col,col,col,col,col,col from generate_series(3,3) as col;insert into t_agg_simple select 'GZ04',col,col,col,col,col,col from generate_series(4,4) as col;insert into t_agg_simple select 'GZ05',col,col,col,col,col,col from generate_series(5,5) as col;-- 禁用并行set max_parallel_workers_per_gather=0;select bh,avg(c1),min(c1),max(c2) from t_agg_simple group by bh;

跟踪分析

Breakpoint 1, agg_retrieve_hash_table (aggstate=0x2929640) at nodeAgg.c:19691969        econtext = aggstate->ss.ps.ps_ExprContext;(gdb)

输入参数

(gdb) p *aggstate$1 = {ss = {ps = {type = T_AggState, plan = 0x2849a30, state = 0x2929428, ExecProcNode = 0x6ee438 ,       ExecProcNodeReal = 0x6ee438 , instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0,       qual = 0x0, lefttree = 0x2929bb0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0,       ps_ResultTupleSlot = 0x292a7b0, ps_ExprContext = 0x2929af0, ps_ProjInfo = 0x292a8f0, scandesc = 0x2929f00},     ss_currentRelation = 0x0, ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x292a458}, aggs = 0x292ae00, numaggs = 3,   numtrans = 3, aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE, phase = 0x292aef8, numphases = 1, current_phase = 0,   peragg = 0x29463e0, pertrans = 0x29483f0, hashcontext = 0x2929a30, aggcontexts = 0x2929858, tmpcontext = 0x2929878,   curaggcontext = 0x2929a30, curperagg = 0x0, curpertrans = 0x2949c80, input_done = false, agg_done = false,   projected_set = -1, current_set = 0, grouped_cols = 0x0, all_grouped_cols = 0x292b090, maxsets = 1, phases = 0x292aef8,   sort_in = 0x0, sort_out = 0x0, sort_slot = 0x0, pergroups = 0x0, grp_firstTuple = 0x0, table_filled = true,   num_hashes = 1, perhash = 0x292af50, hash_pergroup = 0x29465f8, all_pergroups = 0x29465f8, combinedproj = 0x0}(gdb)

1.初始化相关变量,如上下文/peragg等

(gdb) n1970        peragg = aggstate->peragg;(gdb) 1971        firstSlot = aggstate->ss.ss_ScanTupleSlot;(gdb) 1977        perhash = &aggstate->perhash[aggstate->current_set];(gdb) 1983        while (!aggstate->agg_done)(gdb) p *peragg$2 = {aggref = 0x293a458, 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 *peragg->aggref$3 = {xpr = {type = T_Aggref}, aggfnoid = 2116, aggtype = 23, aggcollid = 0, inputcollid = 0, aggtranstype = 23,   aggargtypes = 0x293a518, aggdirectargs = 0x0, args = 0x293a628, aggorder = 0x0, aggdistinct = 0x0, aggfilter = 0x0,   aggstar = false, aggvariadic = false, aggkind = 110 'n', agglevelsup = 0, aggsplit = AGGSPLIT_SIMPLE, location = 26}(gdb) p *perhash$4 = {hashtable = 0x2946890, hashiter = {cur = 0, end = 0, done = false}, hashslot = 0x292b238, hashfunctions = 0x292b2d0,   eqfuncoids = 0x2946700, numCols = 1, numhashGrpCols = 1, largestGrpColIdx = 1, hashGrpColIdxInput = 0x2946660,   hashGrpColIdxHash = 0x2946680, aggnode = 0x2849a30}(gdb) p aggstate->current_set$5 = 0(gdb)

2.未完成,循环
2.1从perhash数据结构中获取slot

(gdb) n1985            TupleTableSlot *hashslot = perhash->hashslot;(gdb) 1988            CHECK_FOR_INTERRUPTS();(gdb) p *hashslot$6 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false,   tts_tuple = 0x0, tts_tupleDescriptor = 0x292b120, tts_mcxt = 0x2929310, tts_buffer = 0, tts_nvalid = 1,   tts_values = 0x292b298, tts_isnull = 0x292b2a0, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {        bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}(gdb)

2.2调用ScanTupleHashTable获取条目

(gdb) n1993            entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);(gdb) p perhash->hashiter$7 = {cur = 0, end = 0, done = false}(gdb) steptuplehash_iterate (tb=0x2946720, iter=0x292af58) at ../../../src/include/lib/simplehash.h:829829        while (!iter->done)(gdb) n833            elem = &tb->data[iter->cur];(gdb) p *tb$8 = {size = 256, members = 5, sizemask = 255, grow_threshold = 230, data = 0x2950a00, ctx = 0x2929310,   private_data = 0x2946890}(gdb) p *tb->data$9 = {firstTuple = 0x0, additional = 0x0, status = 0, hash = 0}(gdb) p *iter$10 = {cur = 0, end = 0, done = false}(gdb) n836            iter->cur = (iter->cur - 1) & tb->sizemask;(gdb) n838            if ((iter->cur & tb->sizemask) == (iter->end & tb->sizemask))(gdb) p iter->cur$11 = 255(gdb) $12 = 255(gdb) p iter->cur & tb->sizemask$13 = 255(gdb) p iter->end & tb->sizemask$14 = 0(gdb) n840            if (elem->status == SH_STATUS_IN_USE)(gdb) p *elem$15 = {firstTuple = 0x0, additional = 0x0, status = 0, hash = 0}(gdb) n829        while (!iter->done)(gdb) 833            elem = &tb->data[iter->cur];(gdb) 836            iter->cur = (iter->cur - 1) & tb->sizemask;(gdb) 838            if ((iter->cur & tb->sizemask) == (iter->end & tb->sizemask))(gdb) 840            if (elem->status == SH_STATUS_IN_USE)(gdb) 829        while (!iter->done)(gdb) finishRun till exit from #0  tuplehash_iterate (tb=0x2946720, iter=0x292af58) at ../../../src/include/lib/simplehash.h:8290x00000000006eed70 in agg_retrieve_hash_table (aggstate=0x2929640) at nodeAgg.c:19931993            entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);Value returned is $16 = (TupleHashEntryData *) 0x2951d08(gdb)

2.3如返回的条目为NULL,切换到下一个set,如已完成检索,则设置标记,退出
2.4如返回的条目不为NULL,则:
2.4.1重置内econtext上下文
2.4.2存储最小化元组
2.4.3重置firstSlot,存储该虚拟元组
2.4.4准备投影slot并执行最终的聚合运算,投影后如结果不为NULL,则返回此结果.

(gdb) n1994            if (entry == NULL)(gdb) 2027            ResetExprContext(econtext);(gdb) 2033            ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);(gdb) 2034            slot_getallattrs(hashslot);(gdb) 2036            ExecClearTuple(firstSlot);(gdb) 2038                   firstSlot->tts_tupleDescriptor->natts * sizeof(bool));(gdb) 2037            memset(firstSlot->tts_isnull, true,(gdb) 2040            for (i = 0; i < perhash->numhashGrpCols; i++)(gdb) x/21x entry->firstTuple->t_bits0x2942a87:    0x5a470b00    0x7f7e3530    0x7f7f7f7f    0x7f7f7f7f0x2942a97:    0x0000407f    0x00000000    0x00003000    0x000000000x2942aa7:    0x9425c000    0x00000002    0x00000500    0x000000000x2942ab7:    0x7f000000    0x7f7f7f7f    0x0000057f    0x000000000x2942ac7:    0x7f000000    0x7f7f7f7f    0x942b087f    0x000000020x2942ad7:    0x7f000000(gdb) x/21c entry->firstTuple->t_bits0x2942a87:    0 '\000'    11 '\v'    71 'G'    90 'Z'    48 '0'    53 '5'    126 '~'    127 '\177'0x2942a8f:    127 '\177'    127 '\177'    127 '\177'    127 '\177'    127 '\177'    127 '\177'    127 '\177'  127 '\177'0x2942a97:    127 '\177'    64 '@'    0 '\000'    0 '\000'    0 '\000'(gdb) n2042                int            varNumber = perhash->hashGrpColIdxInput[i] - 1;(gdb) 2044                firstSlot->tts_values[varNumber] = hashslot->tts_values[i];(gdb) 2045                firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];(gdb) 2040            for (i = 0; i < perhash->numhashGrpCols; i++)(gdb) 2047            ExecStoreVirtualTuple(firstSlot);(gdb) 2049            pergroup = (AggStatePerGroup) entry->additional;(gdb) p *entry$1 = {firstTuple = 0x2942a78, additional = 0x2942ab0, status = 1, hash = 1229618635}(gdb) p *entry->firstTuple$2 = {t_len = 21, mt_padding = "\000\000\000\000\000", t_infomask2 = 1, t_infomask = 2, t_hoff = 24 '\030',   t_bits = 0x2942a87 ""}(gdb)

获取结果

(gdb) n2055            econtext->ecxt_outertuple = firstSlot;(gdb) p *pergroup$3 = {transValue = 5, transValueIsNull = false, noTransValue = false}(gdb) n2057            prepare_projection_slot(aggstate,(gdb) 2061            finalize_aggregates(aggstate, peragg, pergroup);(gdb) 2063            result = project_aggregates(aggstate);(gdb) 2064            if (result)(gdb) p result$4 = (TupleTableSlot *) 0x2927920(gdb) p *result$5 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false,   tts_tuple = 0x0, tts_tupleDescriptor = 0x2927708, tts_mcxt = 0x2926480, tts_buffer = 0, tts_nvalid = 4,   tts_values = 0x2927980, tts_isnull = 0x29279a0, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {        bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}(gdb) p *result->tts_values$6 = 43264648(gdb) p *result->tts_tupleDescriptor$7 = {natts = 4, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x2927728}(gdb) x/32x result->tts_values0x2927980:    0x88    0x2a    0x94    0x02    0x00    0x00    0x00    0x000x2927988:    0x88    0x47    0x94    0x02    0x00    0x00    0x00    0x000x2927990:    0x05    0x00    0x00    0x00    0x00    0x00    0x00    0x000x2927998:    0x05    0x00    0x00    0x00    0x00    0x00    0x00    0x00(gdb) p *result->tts_tupleDescriptor->attrs$8 = {attrelid = 0, attname = {data = "bh", '\000' }, atttypid = 1043, attstattarget = -1, attlen = -1,   attnum = 1, attndims = 0, attcacheoff = -1, atttypmod = 24, attbyval = false, attstorage = 120 'x', attalign = 105 'i',   attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0 '\000', attisdropped = false,   attislocal = true, attinhcount = 0, attcollation = 100}(gdb) p result->tts_tupleDescriptor->attrs[1]$9 = {attrelid = 0, attname = {data = "avg", '\000' }, atttypid = 1700, attstattarget = -1, attlen = -1,   attnum = 2, attndims = 0, attcacheoff = -1, atttypmod = -1, attbyval = false, attstorage = 109 'm', attalign = 105 'i',   attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0 '\000', attisdropped = false,   attislocal = true, attinhcount = 0, attcollation = 0}(gdb) p result->tts_tupleDescriptor->attrs[2]$10 = {attrelid = 0, attname = {data = "min", '\000' }, atttypid = 23, attstattarget = -1, attlen = 4,   attnum = 3, attndims = 0, attcacheoff = -1, atttypmod = -1, attbyval = true, attstorage = 112 'p', attalign = 105 'i',   attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0 '\000', attisdropped = false,   attislocal = true, attinhcount = 0, attcollation = 0}(gdb) p result->tts_tupleDescriptor->attrs[3]$11 = {attrelid = 0, attname = {data = "max", '\000' }, atttypid = 23, attstattarget = -1, attlen = 4,   attnum = 4, attndims = 0, attcacheoff = -1, atttypmod = -1, attbyval = true, attstorage = 112 'p', attalign = 105 'i',   attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0 '\000', attisdropped = false,   attislocal = true, attinhcount = 0, attcollation = 0}

到此,相信大家对"PostgreSQL ExecAgg中调用的函数是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0