溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PostgreSQL ExecAgg中調(diào)用的函數(shù)是什么

發(fā)布時(shí)間:2021-11-09 14:03:35 來源:億速云 閱讀:129 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫

本篇內(nèi)容主要講解“PostgreSQL ExecAgg中調(diào)用的函數(shù)是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“PostgreSQL ExecAgg中調(diào)用的函數(shù)是什么”吧!

一、數(shù)據(jù)結(jié)構(gòu)

AggState
聚合函數(shù)執(zhí)行時(shí)狀態(tài)結(jié)構(gòu)體,內(nèi)含AggStatePerAgg等結(jié)構(gòu)體

/* ---------------------
 *    AggState information
 *
 *    ss.ss_ScanTupleSlot refers to output of underlying plan.
 *  ss.ss_ScanTupleSlot指的是基礎(chǔ)計(jì)劃的輸出.
 *    (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數(shù)組,
 *      這兩個(gè)數(shù)組保存了在計(jì)算agg節(jié)點(diǎn)的輸出元組時(shí)當(dāng)前輸入組已計(jì)算的agg值.
 * ---------------------
 */
/* these structs are private in nodeAgg.c: */
//在nodeAgg.c中私有的結(jié)構(gòu)體
typedef struct AggStatePerAggData *AggStatePerAgg;
typedef struct AggStatePerTransData *AggStatePerTrans;
typedef struct AggStatePerGroupData *AggStatePerGroup;
typedef struct AggStatePerPhaseData *AggStatePerPhase;
typedef struct AggStatePerHashData *AggStatePerHash;
typedef struct AggState
{
    //第一個(gè)字段是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 */
    //指向當(dāng)前步驟數(shù)據(jù)的指針
    AggStatePerPhase phase;        /* pointer to current phase data */
    //步驟數(shù)(包括0)
    int            numphases;        /* number of phases (including phase 0) */
    //當(dāng)前步驟
    int            current_phase;    /* current phase number */
    //per-Aggref信息
    AggStatePerAgg peragg;        /* per-Aggref information */
    //per-Trans狀態(tài)信息
    AggStatePerTrans pertrans;    /* per-Trans state information */
    //長生命周期數(shù)據(jù)的ExprContexts(hashtable)
    ExprContext *hashcontext;    /* econtexts for long-lived data (hashtable) */
    ////長生命周期數(shù)據(jù)的ExprContexts(每一個(gè)GS使用)
    ExprContext **aggcontexts;    /* econtexts for long-lived data (per GS) */
    //輸入表達(dá)式的ExprContext
    ExprContext *tmpcontext;    /* econtext for input expressions */
#define FIELDNO_AGGSTATE_CURAGGCONTEXT 14
    //當(dāng)前活躍的aggcontext
    ExprContext *curaggcontext; /* currently active aggcontext */
    //當(dāng)前活躍的aggregate(如存在)
    AggStatePerAgg curperagg;    /* currently active aggregate, if any */
#define FIELDNO_AGGSTATE_CURPERTRANS 16
    //當(dāng)前活躍的trans state
    AggStatePerTrans curpertrans;    /* currently active trans state, if any */
    //輸入結(jié)束?
    bool        input_done;        /* indicates end of input */
    //Agg掃描結(jié)束?
    bool        agg_done;        /* indicates completion of Agg scan */
    //最后一個(gè)grouping set
    int            projected_set;    /* The last projected grouping set */
#define FIELDNO_AGGSTATE_CURRENT_SET 20
    //將要解析的當(dāng)前grouping set
    int            current_set;    /* The current grouping set being evaluated */
    //當(dāng)前投影操作的分組列
    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步驟數(shù)據(jù)
    //所有步驟中最大的sets大小
    int            maxsets;        /* The max number of sets in any phase */
    //所有步驟的數(shù)組
    AggStatePerPhase phases;    /* array of all phases */
    //對于phases > 1,已排序的輸入信息
    Tuplesortstate *sort_in;    /* sorted input to phases > 1 */
    //對于下一個(gè)步驟,輸入已拷貝
    Tuplesortstate *sort_out;    /* input is copied here for next phase */
    //排序結(jié)果的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編號數(shù)組
    AggStatePerGroup *pergroups;    /* grouping set indexed array of per-group
                                     * pointers */
    //當(dāng)前組的第一個(gè)元組拷貝
    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桶數(shù)?
    int            num_hashes;
    //相應(yīng)的哈希表數(shù)據(jù)數(shù)組
    AggStatePerHash perhash;    /* array of per-hashtable data */
    //per-group指針的grouping set編號數(shù)組
    AggStatePerGroup *hash_pergroup;    /* grouping set indexed array of
                                         * per-group pointers */
    /* support for evaluation of agg input expressions: */
    //---------- agg輸入表達(dá)式解析支持
#define FIELDNO_AGGSTATE_ALL_PERGROUPS 34
    //首先是->pergroups,然后是hash_pergroup
    AggStatePerGroup *all_pergroups;    /* array of first ->pergroups, than
                                         * ->hash_pergroup */
    //投影實(shí)現(xiàn)機(jī)制
    ProjectionInfo *combinedproj;    /* projection machinery */
} AggState;
/* Primitive options supported by nodeAgg.c: */
//nodeag .c支持的基本選項(xiàng)
#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選擇了哪些基本選項(xiàng)
#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子計(jì)劃返回的元組合適的屬性上為每一個(gè)聚合函數(shù)(出現(xiàn)在投影列或節(jié)點(diǎn)表達(dá)式)執(zhí)行聚合.需要聚合的元組數(shù)量依賴于是否已分組或者選擇普通聚合.在已分組的聚合操作宏,為每一個(gè)組產(chǎn)生結(jié)果行;普通聚合,整個(gè)查詢只有一個(gè)結(jié)果行.
不管哪種情況,每一個(gè)聚合結(jié)果值都會存儲在表達(dá)式上下文中(ExecProject會解析結(jié)果元組)

/*
 * 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子計(jì)劃返回的元組合適的屬性上為每一個(gè)聚合函數(shù)(出現(xiàn)在投影列或節(jié)點(diǎn)表達(dá)式)執(zhí)行聚合.
 *    需要聚合的元組數(shù)量依賴于是否已分組或者選擇普通聚合.
 *    在已分組的聚合操作宏,為每一個(gè)組產(chǎn)生結(jié)果行;普通聚合,整個(gè)查詢只有一個(gè)結(jié)果行.
 *    不管哪種情況,每一個(gè)聚合結(jié)果值都會存儲在表達(dá)式上下文中(ExecProject會解析結(jié)果元組)
 */
static TupleTableSlot *
ExecAgg(PlanState *pstate)
{
    AggState   *node = castNode(AggState, pstate);
    TupleTableSlot *result = NULL;
    CHECK_FOR_INTERRUPTS();
    if (!node->agg_done)
    {
        /* Dispatch based on strategy */
        //基于策略進(jìn)行分發(fā)
        switch (node->phase->aggstrategy)
        {
            case AGG_HASHED:
                if (!node->table_filled)
                    agg_fill_hash_table(node);
                /* FALLTHROUGH */
                //填充后,執(zhí)行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實(shí)現(xiàn)版本):在hash表中檢索組
大體實(shí)現(xiàn)邏輯如下:
1.初始化相關(guān)變量,如上下文/peragg等
2.未完成,循環(huán)
2.1從perhash數(shù)據(jù)結(jié)構(gòu)中獲取slot
2.2調(diào)用ScanTupleHashTable獲取條目
2.3如返回的條目為NULL,切換到下一個(gè)set,如已完成檢索,則設(shè)置標(biāo)記,退出
2.4如返回的條目不為NULL,則:
  2.4.1重置內(nèi)econtext上下文
  2.4.2存儲最小化元組
  2.4.3重置firstSlot,存儲該虛擬元組
  2.4.4準(zhǔn)備投影slot并執(zhí)行最終的聚合運(yùn)算,投影后如結(jié)果不為NULL,則返回此結(jié)果.

/*
 * ExecAgg for hashed case: retrieving groups from hash table
 * ExecAgg(Hash實(shí)現(xiàn)版本):在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節(jié)點(diǎn)中獲取狀態(tài)信息.
     *
     * econtext is the per-output-tuple expression context.
     * econtext是per-output-tuple表達(dá)式上下文.
     */
    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.
     * 注意,在分組之間切換時(shí),perhash在循環(huán)中可能會改變
     */
    perhash = &aggstate->perhash[aggstate->current_set];
    /*
     * We loop retrieving groups until we find one satisfying
     * aggstate->ss.ps.qual
     * 循環(huán)檢索groups,直至檢索到一個(gè)符合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表的下一個(gè)條目
         */
        entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
        if (entry == NULL)
        {
            //條目為NULL,切換到下一個(gè)set
            int            nextset = aggstate->current_set + 1;
            if (nextset < aggstate->num_hashes)
            {
                /*
                 * Switch to next grouping set, reinitialize, and restart the
                 * loop.
                 * 切換至下一個(gè)grouping set,重新初始化并重啟循環(huán)
                 */
                select_current_set(aggstate, nextset, true);
                perhash = &aggstate->perhash[aggstate->current_set];
                ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
                continue;
            }
            else
            {
                /* No more hashtables, so done */
                //已完成檢索,設(shè)置標(biāo)記,退出
                aggstate->agg_done = true;
                return NULL;
            }
        }
        /*
         * Clear the per-output-tuple context for each group
         * 為每一個(gè)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回調(diào),
         *   那應(yīng)該還沒有調(diào)用,因?yàn)槲覀兛赡苓€沒有完成該agg的處理.
         */
        ResetExprContext(econtext);
        /*
         * Transform representative tuple back into one with the right
         * columns.
         * 將典型元組轉(zhuǎn)回具有正確列的元組.
         */
        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;
        //準(zhǔn)備投影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類似,不同的是插入一個(gè)"最小化"的元組到slot中.
 *
 * No 'buffer' parameter since minimal tuples are never stored in relations.
 * 不需要"buffer"參數(shù),因?yàn)樽钚』M不會存儲到relations中.
 * --------------------------------
 */
TupleTableSlot *
ExecStoreMinimalTuple(MinimalTuple mtup,
                      TupleTableSlot *slot,
                      bool shouldFree)
{
    /*
     * sanity checks
     * 一致性校驗(yàn)
     */
    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標(biāo)記
     */
    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 */
    //因?yàn)椴辉试S訪問,因此無需設(shè)置t_sefl或者t_tableOid
    /* Mark extracted state invalid */
    //標(biāo)記已提取狀態(tài)無效
    slot->tts_nvalid = 0;
    return slot;
}
/* --------------------------------
 *        ExecStoreVirtualTuple
 *            Mark a slot as containing a virtual tuple.
 *            標(biāo)記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.
 * 使用虛擬元組數(shù)據(jù)的協(xié)議如下:
 *         * 調(diào)用ExecClearTuple標(biāo)記slot為空
 *        * 存儲數(shù)據(jù)到Datum/isnull數(shù)組中
 *        * 調(diào)用ExecStoreVirtualTuple標(biāo)記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;
}

三、跟蹤分析

測試腳本

-- 創(chuàng)建數(shù)據(jù)表,插入測試數(shù)據(jù)
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:1969
1969        econtext = aggstate->ss.ps.ps_ExprContext;
(gdb)

輸入?yún)?shù)

(gdb) p *aggstate
$1 = {ss = {ps = {type = T_AggState, plan = 0x2849a30, state = 0x2929428, ExecProcNode = 0x6ee438 <ExecAgg>, 
      ExecProcNodeReal = 0x6ee438 <ExecAgg>, 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.初始化相關(guān)變量,如上下文/peragg等

(gdb) n
1970        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.未完成,循環(huán)
2.1從perhash數(shù)據(jù)結(jié)構(gòu)中獲取slot

(gdb) n
1985            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調(diào)用ScanTupleHashTable獲取條目

(gdb) n
1993            entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
(gdb) p perhash->hashiter
$7 = {cur = 0, end = 0, done = false}
(gdb) step
tuplehash_iterate (tb=0x2946720, iter=0x292af58) at ../../../src/include/lib/simplehash.h:829
829        while (!iter->done)
(gdb) n
833            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) n
836            iter->cur = (iter->cur - 1) & tb->sizemask;
(gdb) n
838            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) n
840            if (elem->status == SH_STATUS_IN_USE)
(gdb) p *elem
$15 = {firstTuple = 0x0, additional = 0x0, status = 0, hash = 0}
(gdb) n
829        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) finish
Run till exit from #0  tuplehash_iterate (tb=0x2946720, iter=0x292af58) at ../../../src/include/lib/simplehash.h:829
0x00000000006eed70 in agg_retrieve_hash_table (aggstate=0x2929640) at nodeAgg.c:1993
1993            entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
Value returned is $16 = (TupleHashEntryData *) 0x2951d08
(gdb)

2.3如返回的條目為NULL,切換到下一個(gè)set,如已完成檢索,則設(shè)置標(biāo)記,退出
2.4如返回的條目不為NULL,則:
  2.4.1重置內(nèi)econtext上下文
  2.4.2存儲最小化元組
  2.4.3重置firstSlot,存儲該虛擬元組
  2.4.4準(zhǔn)備投影slot并執(zhí)行最終的聚合運(yùn)算,投影后如結(jié)果不為NULL,則返回此結(jié)果.

(gdb) n
1994            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_bits
0x2942a87:    0x5a470b00    0x7f7e3530    0x7f7f7f7f    0x7f7f7f7f
0x2942a97:    0x0000407f    0x00000000    0x00003000    0x00000000
0x2942aa7:    0x9425c000    0x00000002    0x00000500    0x00000000
0x2942ab7:    0x7f000000    0x7f7f7f7f    0x0000057f    0x00000000
0x2942ac7:    0x7f000000    0x7f7f7f7f    0x942b087f    0x00000002
0x2942ad7:    0x7f000000
(gdb) x/21c entry->firstTuple->t_bits
0x2942a87:    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) n
2042                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)

獲取結(jié)果

(gdb) n
2055            econtext->ecxt_outertuple = firstSlot;
(gdb) p *pergroup
$3 = {transValue = 5, transValueIsNull = false, noTransValue = false}
(gdb) n
2057            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_values
0x2927980:    0x88    0x2a    0x94    0x02    0x00    0x00    0x00    0x00
0x2927988:    0x88    0x47    0x94    0x02    0x00    0x00    0x00    0x00
0x2927990:    0x05    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x2927998:    0x05    0x00    0x00    0x00    0x00    0x00    0x00    0x00
(gdb) p *result->tts_tupleDescriptor->attrs
$8 = {attrelid = 0, attname = {data = "bh", '\000' <repeats 61 times>}, 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' <repeats 60 times>}, 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' <repeats 60 times>}, 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' <repeats 60 times>}, 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中調(diào)用的函數(shù)是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI