您好,登錄后才能下訂單哦!
本篇內容主要講解“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:1969 1969 econtext = aggstate->ss.ps.ps_ExprContext; (gdb)
輸入參數
(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.初始化相關變量,如上下文/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.未完成,循環
2.1從perhash數據結構中獲取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調用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,切換到下一個set,如已完成檢索,則設置標記,退出
2.4如返回的條目不為NULL,則:
2.4.1重置內econtext上下文
2.4.2存儲最小化元組
2.4.3重置firstSlot,存儲該虛擬元組
2.4.4準備投影slot并執行最終的聚合運算,投影后如結果不為NULL,則返回此結果.
(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)
獲取結果
(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中調用的函數是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。