PostgreSQL 소스 코드 해독 (181) - 조회 \ # 97 (집합 함수 \ # 2 - ExecInitAgg)
데이터 구조
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)
2. 소스 코드 해독ExecInitAgg 는 최적화 기 에 생 성 된 agg 노드 에 런 타임 정 보 를 만 들 고 outer 서브 트 리 (왼쪽 트 리) 를 초기 화 합 니 다. 그 주요 실현 논 리 는 다음 과 같 습 니 다. 1. AggState 구조 체 초기 화 2. 계산 은 몇 단계 (Hash vs Group) 로 나 뉘 어 집 니 다. grouping set 가 존재 하면 관련 정 보 를 초기 화 합 니 다. 메모리 컨 텍스트 분배 5. outer plan 서브 노드 초기 화 6. 결과 유형 초기 화,slot 와 투영 7. 초기 화 자 표현 식 8. AggStatePerPhasedata 등 구조 체 에 메모리 할당 9. 각 단계 9.1 컴 퓨 팅 그룹 열 을 순환 적 으로 옮 겨 다 니 며 phasedata - > grouped 에 저 장 됩 니 다.cols 배열 과 allgrouped_cols 에서 9.2 AggState - > phases 배열 초기 화 (배열 요소 에 대응 하 는 구조 체 는 AggStatePerPhase) 9.3 AggState - > perhash 배열 초기 화 (대응 하 는 구조 체 는 AggStatePerHash) 10. all 전환grouped_cols 는 역순 링크 11. 출력 expr 컨 텍스트 에 aggregate - result 저장 소 를 설정 하고 개인 per - agg 작업 저장 소 를 할당 합 니 다. 12. Hash 알고리즘 을 사용 하면 find 를 호출 합 니 다.hash_columns 와 buildhash_table 방법 관련 데이터 초기 화 13. initialize 호출phase/select_current_set 초기 화 단계 데이터 14. 취 합 함수 정 보 를 검색 하고 per - agg 와 per - trans 데이터 가 변 하지 않 는 필드 15 를 초기 화 합 니 다. 한 번 구축 하면 모든 변환 작업 을 완료 하 는 표현 식 입 니 다.
/* -----------------
* ExecInitAgg
*
* Creates the run-time information for the agg node produced by the
* planner and initializes its outer subtree.
* agg outer ( ).
*
* -----------------
*/
AggState *
ExecInitAgg(Agg *node, EState *estate, int eflags)
{
AggState *aggstate;//AggState
AggStatePerAgg peraggs;//AggStatePerAggData
AggStatePerTrans pertransstates;//
AggStatePerGroup *pergroups;//per-aggregate-per-group
Plan *outerPlan;//outer ( )
ExprContext *econtext;//
TupleDesc scanDesc;//
int numaggs,//agg
transno,//
aggno;
int phase;//
int phaseidx;//
ListCell *l;//
Bitmapset *all_grouped_cols = NULL;//
int numGroupingSets = 1;//Grouping Sets
int numPhases;//
int numHashes;//
int i = 0;
int j = 0;
bool use_hashing = (node->aggstrategy == AGG_HASHED ||
node->aggstrategy == AGG_MIXED);// Hash
/* check for unsupported flags */
//
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
* create state structure
* AggState
*/
aggstate = makeNode(AggState);
aggstate->ss.ps.plan = (Plan *) node;
aggstate->ss.ps.state = estate;
aggstate->ss.ps.ExecProcNode = ExecAgg;
aggstate->aggs = NIL;
aggstate->numaggs = 0;
aggstate->numtrans = 0;
aggstate->aggstrategy = node->aggstrategy;
aggstate->aggsplit = node->aggsplit;
aggstate->maxsets = 0;
aggstate->projected_set = -1;
aggstate->current_set = 0;
aggstate->peragg = NULL;
aggstate->pertrans = NULL;
aggstate->curperagg = NULL;
aggstate->curpertrans = NULL;
aggstate->input_done = false;
aggstate->agg_done = false;
aggstate->pergroups = NULL;
aggstate->grp_firstTuple = NULL;
aggstate->sort_in = NULL;
aggstate->sort_out = NULL;
/*
* phases[0] always exists, but is dummy in sorted/plain mode
* phases[0] , sorted/plain " " .
*/
numPhases = (use_hashing ? 1 : 2);
numHashes = (use_hashing ? 1 : 0);
/*
* Calculate the maximum number of grouping sets in any phase; this
* determines the size of some allocations. Also calculate the number of
* phases, since all hashed/mixed nodes contribute to only a single phase.
* grouping sets .
* . , , hashed/mixed .
*/
if (node->groupingSets)
{
// grouping sets
numGroupingSets = list_length(node->groupingSets);
foreach(l, node->chain)
{
Agg *agg = lfirst(l);
numGroupingSets = Max(numGroupingSets,
list_length(agg->groupingSets));
/*
* additional AGG_HASHED aggs become part of phase 0, but all
* others add an extra phase.
*/
if (agg->aggstrategy != AGG_HASHED)
++numPhases;
else
++numHashes;
}
}
//
aggstate->maxsets = numGroupingSets;
aggstate->numphases = numPhases;
aggstate->aggcontexts = (ExprContext **)
palloc0(sizeof(ExprContext *) * numGroupingSets);
/*
* Create expression contexts. We need three or more, one for
* per-input-tuple processing, one for per-output-tuple processing, one
* for all the hashtables, and one for each grouping set. The per-tuple
* memory context of the per-grouping-set ExprContexts (aggcontexts)
* replaces the standalone memory context formerly used to hold transition
* values. We cheat a little by using ExecAssignExprContext() to build
* all of them.
* . , per-input-tuple ,
* per-output-tuple , grouping set.
* per-grouping-set ExprContexts (aggcontexts) per-tuple
* .
*
* NOTE: the details of what is stored in aggcontexts and what is stored
* in the regular per-query memory context are driven by a simple
* decision: we want to reset the aggcontext at group boundaries (if not
* hashing) and in ExecReScanAgg to recover no-longer-wanted space.
* : aggcontexts per-query :
( hashing) aggcontext ExecReScanAgg
*/
//
ExecAssignExprContext(estate, &aggstate->ss.ps);
aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
for (i = 0; i < numGroupingSets; ++i)
{
ExecAssignExprContext(estate, &aggstate->ss.ps);
aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
}
if (use_hashing)
{
ExecAssignExprContext(estate, &aggstate->ss.ps);
aggstate->hashcontext = aggstate->ss.ps.ps_ExprContext;
}
ExecAssignExprContext(estate, &aggstate->ss.ps);
/*
* Initialize child nodes.
*
*
* If we are doing a hashed aggregation then the child plan does not need
* to handle REWIND efficiently; see ExecReScanAgg.
* Hash , REWIND, ExecReScanAgg.
*/
if (node->aggstrategy == AGG_HASHED)
eflags &= ~EXEC_FLAG_REWIND;
// outerPlan
outerPlan = outerPlan(node);
// outerPlan
outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
/*
* initialize source tuple type.
*
*/
ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss);
scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
if (node->chain)
aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc);
/*
* Initialize result type, slot and projection.
* ,slot
*/
ExecInitResultTupleSlotTL(estate, &aggstate->ss.ps);
ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
/*
* initialize child expressions
*
*
* We expect the parser to have checked that no aggs contain other agg
* calls in their arguments (and just to be sure, we verify it again while
* initializing the plan node). This would make no sense under SQL
* semantics, and it's forbidden by the spec. Because it is true, we
* don't need to worry about evaluating the aggs in any particular order.
* agg agg ( , )
* SQL , SQL .
* , agg。
*
* Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
* nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
* in the targetlist are found during ExecAssignProjectionInfo, below.
* :execExpr.c Aggrefs, AggrefExprState aggstate->aggs .
* Aggrefs ,targetlist Aggrefs ExecAssignProjectionInfo .
*/
aggstate->ss.ps.qual =
ExecInitQual(node->plan.qual, (PlanState *) aggstate);
/*
* We should now have found all Aggrefs in the targetlist and quals.
* Aggrefs.
*/
numaggs = aggstate->numaggs;
Assert(numaggs == list_length(aggstate->aggs));
/*
* For each phase, prepare grouping set data and fmgr lookup data for
* compare functions. Accumulate all_grouped_cols in passing.
* grouping set fmgr .
* cols .
*/
//
aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
aggstate->num_hashes = numHashes;
if (numHashes)
{
aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
aggstate->phases[0].numsets = 0;
aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
}
phase = 0;
for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
{
//------------
Agg *aggnode;
Sort *sortnode;
if (phaseidx > 0)
{
// , node
aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
//
sortnode = castNode(Sort, aggnode->plan.lefttree);
}
else
{
// ,
aggnode = node;
sortnode = NULL;
}
Assert(phase <= 1 || sortnode);
if (aggnode->aggstrategy == AGG_HASHED
|| aggnode->aggstrategy == AGG_MIXED)
{
//---------- Hash
//
AggStatePerPhase phasedata = &aggstate->phases[0];
AggStatePerHash perhash;
Bitmapset *cols = NULL;
Assert(phase == 0);
i = phasedata->numsets++;
perhash = &aggstate->perhash[i];
/* phase 0 always points to the "real" Agg in the hash case */
// Hash , 0 " "Agg
phasedata->aggnode = node;
phasedata->aggstrategy = node->aggstrategy;
/* but the actual Agg node representing this hash is saved here */
// Hash Agg
perhash->aggnode = aggnode;
phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
//
for (j = 0; j < aggnode->numCols; ++j)
cols = bms_add_member(cols, aggnode->grpColIdx[j]);
//
phasedata->grouped_cols[i] = cols;
//
all_grouped_cols = bms_add_members(all_grouped_cols, cols);
continue;
}
else
{
// Group
AggStatePerPhase phasedata = &aggstate->phases[++phase];
int num_sets;
phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
if (num_sets)
{
phasedata->gset_lengths = palloc(num_sets * sizeof(int));
phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
i = 0;
foreach(l, aggnode->groupingSets)
{
int current_length = list_length(lfirst(l));
Bitmapset *cols = NULL;
/* planner forces this to be correct */
for (j = 0; j < current_length; ++j)
cols = bms_add_member(cols, aggnode->grpColIdx[j]);
phasedata->grouped_cols[i] = cols;
phasedata->gset_lengths[i] = current_length;
++i;
}
all_grouped_cols = bms_add_members(all_grouped_cols,
phasedata->grouped_cols[0]);
}
else
{
Assert(phaseidx == 0);
phasedata->gset_lengths = NULL;
phasedata->grouped_cols = NULL;
}
/*
* If we are grouping, precompute fmgr lookup data for inner loop.
* GroupAggregate, fmgr
*/
if (aggnode->aggstrategy == AGG_SORTED)
{
int i = 0;
Assert(aggnode->numCols > 0);
/*
* Build a separate function for each subset of columns that
* need to be compared.
*
*/
phasedata->eqfunctions =
(ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
/* for each grouping set */
// grouping set
for (i = 0; i < phasedata->numsets; i++)
{
int length = phasedata->gset_lengths[i];
if (phasedata->eqfunctions[length - 1] != NULL)
continue;
phasedata->eqfunctions[length - 1] =
execTuplesMatchPrepare(scanDesc,
length,
aggnode->grpColIdx,
aggnode->grpOperators,
(PlanState *) aggstate);
}
/* and for all grouped columns, unless already computed */
// ,
if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
{
phasedata->eqfunctions[aggnode->numCols - 1] =
execTuplesMatchPrepare(scanDesc,
aggnode->numCols,
aggnode->grpColIdx,
aggnode->grpOperators,
(PlanState *) aggstate);
}
}
phasedata->aggnode = aggnode;
phasedata->aggstrategy = aggnode->aggstrategy;
phasedata->sortnode = sortnode;
}
}
/*
* Convert all_grouped_cols to a descending-order list.
* all_grouped_cols
*/
i = -1;
while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
/*
* Set up aggregate-result storage in the output expr context, and also
* allocate my private per-agg working storage
* expr aggregate-result , per-agg
*/
econtext = aggstate->ss.ps.ps_ExprContext;
//
econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numaggs);
aggstate->peragg = peraggs;
aggstate->pertrans = pertransstates;
aggstate->all_pergroups =
(AggStatePerGroup *) palloc0(sizeof(AggStatePerGroup)
* (numGroupingSets + numHashes));
pergroups = aggstate->all_pergroups;
if (node->aggstrategy != AGG_HASHED)
{
//---------- Group
for (i = 0; i < numGroupingSets; i++)
{
pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
* numaggs);
}
aggstate->pergroups = pergroups;
pergroups += numGroupingSets;
}
/*
* Hashing can only appear in the initial phase.
* Hashing
*/
if (use_hashing)
{
/* this is an array of pointers, not structures */
// ,
aggstate->hash_pergroup = pergroups;
find_hash_columns(aggstate);
build_hash_table(aggstate);
aggstate->table_filled = false;
}
/*
* Initialize current phase-dependent values to initial phase. The initial
* phase is 1 (first sort pass) for all strategies that use sorting (if
* hashing is being done too, then phase 0 is processed last); but if only
* hashing is being done, then phase 0 is all there is.
* .
* ( hasing, 0 ), 1( )
* hashing, 0.
*/
if (node->aggstrategy == AGG_HASHED)
{
//Hashing
aggstate->current_phase = 0;
initialize_phase(aggstate, 0);
select_current_set(aggstate, 0, true);
}
else
{
// Hashing
aggstate->current_phase = 1;
initialize_phase(aggstate, 1);
select_current_set(aggstate, 0, false);
}
/* -----------------
* Perform lookups of aggregate function info, and initialize the
* unchanging fields of the per-agg and per-trans data.
* , per-agg per-trans
*
* We try to optimize by detecting duplicate aggregate functions so that
* their state and final values are re-used, rather than needlessly being
* re-calculated independently. We also detect aggregates that are not
* the same, but which can share the same transition state.
* , , .
* , .
*
* Scenarios:
* :
*
* 1. Identical aggregate function calls appear in the query:
*
* SELECT SUM(x) FROM ... HAVING SUM(x) > 0
*
* Since these aggregates are identical, we only need to calculate
* the value once. Both aggregates will share the same 'aggno' value.
*
* 1. :
* SELECT SUM(x) FROM ... HAVING SUM(x) > 0
* , . aggno .
*
* 2. Two different aggregate functions appear in the query, but the
* aggregates have the same arguments, transition functions and
* initial values (and, presumably, different final functions):
*
* SELECT AVG(x), STDDEV(x) FROM ...
*
* In this case we must create a new peragg for the varying aggregate,
* and we need to call the final functions separately, but we need
* only run the transition function once. (This requires that the
* final functions be nondestructive of the transition state, but
* that's required anyway for other reasons.)
* 2. , / ( ):
* SELECT AVG(x), STDDEV(x) FROM ...
* , peragg, ,
* .
* ( , , )
*
* For either of these optimizations to be valid, all aggregate properties
* used in the transition phase must be the same, including any modifiers
* such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
* contain any volatile functions.
* , ,
* ORDER BY,DISTINCT FILTER, .
* -----------------
*/
aggno = -1;
transno = -1;
foreach(l, aggstate->aggs)
{
AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
Aggref *aggref = aggrefstate->aggref;
AggStatePerAgg peragg;
AggStatePerTrans pertrans;
int existing_aggno;
int existing_transno;
List *same_input_transnos;
Oid inputTypes[FUNC_MAX_ARGS];
int numArguments;
int numDirectArgs;
HeapTuple aggTuple;
Form_pg_aggregate aggform;
AclResult aclresult;
Oid transfn_oid,
finalfn_oid;
bool shareable;
Oid serialfn_oid,
deserialfn_oid;
Expr *finalfnexpr;
Oid aggtranstype;
Datum textInitVal;
Datum initValue;
bool initValueIsNull;
/* Planner should have assigned aggregate to correct level */
//
Assert(aggref->agglevelsup == 0);
/* ... and the split mode should match */
//
Assert(aggref->aggsplit == aggstate->aggsplit);
/* 1. Check for already processed aggs which can be re-used */
// 1. aggs .
existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
&same_input_transnos);
if (existing_aggno != -1)
{
/*
* Existing compatible agg found. so just point the Aggref to the
* same per-agg struct.
* agg,Aggref per-agg
*/
aggrefstate->aggno = existing_aggno;
continue;
}
/* Mark Aggref state node with assigned index in the result array */
// Aggref
peragg = &peraggs[++aggno];
peragg->aggref = aggref;
aggrefstate->aggno = aggno;
/* Fetch the pg_aggregate row */
// pg_aggregate ( )
aggTuple = SearchSysCache1(AGGFNOID,
ObjectIdGetDatum(aggref->aggfnoid));
if (!HeapTupleIsValid(aggTuple))
elog(ERROR, "cache lookup failed for aggregate %u",
aggref->aggfnoid);
//
aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
/* Check permission to call aggregate function */
//
aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_AGGREGATE,
get_func_name(aggref->aggfnoid));
// InvokeFunctionExecuteHook
InvokeFunctionExecuteHook(aggref->aggfnoid);
/* planner recorded transition state type in the Aggref itself */
// Aggref
aggtranstype = aggref->aggtranstype;
Assert(OidIsValid(aggtranstype));
/*
* If this aggregation is performing state combines, then instead of
* using the transition function, we'll use the combine function
* ,
*/
if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
{
transfn_oid = aggform->aggcombinefn;
/* If not set then the planner messed up */
// ,
if (!OidIsValid(transfn_oid))
elog(ERROR, "combinefn not set for aggregate function");
}
else
transfn_oid = aggform->aggtransfn;
/* Final function only required if we're finalizing the aggregates */
// Final function
if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
peragg->finalfn_oid = finalfn_oid = InvalidOid;
else
peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
/*
* If finalfn is marked read-write, we can't share transition states;
* but it is okay to share states for AGGMODIFY_SHAREABLE aggs. Also,
* if we're not executing the finalfn here, we can share regardless.
* finalfn RW, , AGGMODIFY_SHAREABLE agg .
* , finalfn, .
*/
shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) ||
(finalfn_oid == InvalidOid);
peragg->shareable = shareable;
serialfn_oid = InvalidOid;
deserialfn_oid = InvalidOid;
/*
* Check if serialization/deserialization is required. We only do it
* for aggregates that have transtype INTERNAL.
* / .
*
*/
if (aggtranstype == INTERNALOID)
{
/*
* The planner should only have generated a serialize agg node if
* every aggregate with an INTERNAL state has a serialization
* function. Verify that.
* INTERNAL , agg , !
*/
if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
{
/* serialization only valid when not running finalfn */
// finalfn
Assert(DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
if (!OidIsValid(aggform->aggserialfn))
elog(ERROR, "serialfunc not provided for serialization aggregation");
serialfn_oid = aggform->aggserialfn;
}
/* Likewise for deserialization functions */
//
if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
{
/* deserialization only valid when combining states */
//
Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
if (!OidIsValid(aggform->aggdeserialfn))
elog(ERROR, "deserialfunc not provided for deserialization aggregation");
deserialfn_oid = aggform->aggdeserialfn;
}
}
/* Check that aggregate owner has permission to call component fns */
//
{
HeapTuple procTuple;
Oid aggOwner;
procTuple = SearchSysCache1(PROCOID,
ObjectIdGetDatum(aggref->aggfnoid));
if (!HeapTupleIsValid(procTuple))
elog(ERROR, "cache lookup failed for function %u",
aggref->aggfnoid);
aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
ReleaseSysCache(procTuple);
aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_FUNCTION,
get_func_name(transfn_oid));
InvokeFunctionExecuteHook(transfn_oid);
if (OidIsValid(finalfn_oid))
{
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_FUNCTION,
get_func_name(finalfn_oid));
InvokeFunctionExecuteHook(finalfn_oid);
}
if (OidIsValid(serialfn_oid))
{
aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_FUNCTION,
get_func_name(serialfn_oid));
InvokeFunctionExecuteHook(serialfn_oid);
}
if (OidIsValid(deserialfn_oid))
{
aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_FUNCTION,
get_func_name(deserialfn_oid));
InvokeFunctionExecuteHook(deserialfn_oid);
}
}
/*
* Get actual datatypes of the (nominal) aggregate inputs. These
* could be different from the agg's declared input types, when the
* agg accepts ANY or a polymorphic type.
* .
* agg ANY , agg
*/
numArguments = get_aggregate_argtypes(aggref, inputTypes);
/* Count the "direct" arguments, if any */
// "direct"
numDirectArgs = list_length(aggref->aggdirectargs);
/* Detect how many arguments to pass to the finalfn */
// finalfn
if (aggform->aggfinalextra)
peragg->numFinalArgs = numArguments + 1;
else
peragg->numFinalArgs = numDirectArgs + 1;
/* Initialize any direct-argument expressions */
//
peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
(PlanState *) aggstate);
/*
* build expression trees using actual argument & result types for the
* finalfn, if it exists and is required.
* , finalfn .
*/
if (OidIsValid(finalfn_oid))
{
build_aggregate_finalfn_expr(inputTypes,
peragg->numFinalArgs,
aggtranstype,
aggref->aggtype,
aggref->inputcollid,
finalfn_oid,
&finalfnexpr);
fmgr_info(finalfn_oid, &peragg->finalfn);
fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
}
/* get info about the output value's datatype */
// .
get_typlenbyval(aggref->aggtype,
&peragg->resulttypeLen,
&peragg->resulttypeByVal);
/*
* initval is potentially null, so don't try to access it as a struct
* field. Must do it the hard way with SysCacheGetAttr.
* initval null, .
* SysCacheGetAttr .
*/
textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
Anum_pg_aggregate_agginitval,
&initValueIsNull);
if (initValueIsNull)
initValue = (Datum) 0;
else
initValue = GetAggInitVal(textInitVal, aggtranstype);
/*
* 2. Build working state for invoking the transition function, or
* look up previously initialized working state, if we can share it.
* 2. , ( ).
*
* find_compatible_peragg() already collected a list of shareable
* per-Trans's with the same inputs. Check if any of them have the
* same transition function and initial value.
* find_compatible_peragg() per-Trans .
* per-Trans.
*/
existing_transno = find_compatible_pertrans(aggstate, aggref,
shareable,
transfn_oid, aggtranstype,
serialfn_oid, deserialfn_oid,
initValue, initValueIsNull,
same_input_transnos);
if (existing_transno != -1)
{
/*
* Existing compatible trans found, so just point the 'peragg' to
* the same per-trans struct, and mark the trans state as shared.
* per-Trans, peragg per-trans , trans .
*/
pertrans = &pertransstates[existing_transno];
pertrans->aggshared = true;
peragg->transno = existing_transno;
}
else
{
pertrans = &pertransstates[++transno];
build_pertrans_for_aggref(pertrans, aggstate, estate,
aggref, transfn_oid, aggtranstype,
serialfn_oid, deserialfn_oid,
initValue, initValueIsNull,
inputTypes, numArguments);
peragg->transno = transno;
}
ReleaseSysCache(aggTuple);
}
/*
* Update aggstate->numaggs to be the number of unique aggregates found.
* Also set numstates to the number of unique transition states found.
* aggstate->numaggs .
* numstates .
*/
aggstate->numaggs = aggno + 1;
aggstate->numtrans = transno + 1;
/*
* Last, check whether any more aggregates got added onto the node while
* we processed the expressions for the aggregate arguments (including not
* only the regular arguments and FILTER expressions handled immediately
* above, but any direct arguments we might've handled earlier). If so,
* we have nested aggregate functions, which is semantically nonsensical,
* so complain. (This should have been caught by the parser, so we don't
* need to work hard on a helpful error message; but we defend against it
* here anyway, just to be sure.)
* , .
* ( FILTER , )
* , , , .
* ( , , , )
*/
if (numaggs != list_length(aggstate->aggs))
ereport(ERROR,
(errcode(ERRCODE_GROUPING_ERROR),
errmsg("aggregate function calls cannot be nested")));
/*
* Build expressions doing all the transition work at once. We build a
* different one for each phase, as the number of transition function
* invocation can differ between phases. Note this'll work both for
* transition and combination functions (although there'll only be one
* phase in the latter case).
* .
* , .
* ( )
*/
for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
{
AggStatePerPhase phase = &aggstate->phases[phaseidx];
bool dohash = false;
bool dosort = false;
/* phase 0 doesn't necessarily exist */
//
if (!phase->aggnode)
continue;
if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
{
/*
* Phase one, and only phase one, in a mixed agg performs both
* sorting and aggregation.
* 1, mixed agg, .
*/
dohash = true;
dosort = true;
}
else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
{
/*
* No need to compute a transition function for an AGG_MIXED phase
* 0 - the contents of the hashtables will have been computed
* during phase 1.
* AGG_MIXED 0, .
* 1 .
*/
continue;
}
else if (phase->aggstrategy == AGG_PLAIN ||
phase->aggstrategy == AGG_SORTED)
{
dohash = false;
dosort = true;
}
else if (phase->aggstrategy == AGG_HASHED)
{
dohash = true;
dosort = false;
}
else
Assert(false);
phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash);
}
return aggstate;
}
3. 추적 분석테스트 스 크 립 트
//
testdb=# set max_parallel_workers_per_gather=0;
SET
testdb=# explain verbose select bh,avg(c1),min(c1),max(c2) from t_agg group by bh;
QUERY PLAN
---------------------------------------------------------------------------
HashAggregate (cost=13677.00..13677.06 rows=5 width=45)
Output: bh, avg(c1), min(c1), max(c2)
Group Key: t_agg.bh
-> Seq Scan on public.t_agg (cost=0.00..8677.00 rows=500000 width=13)
Output: bh, c1, c2, c3, c4, c5, c6
(5 rows)
추적 분석
(gdb) b ExecInitAgg
Breakpoint 1 at 0x6eefc9: file nodeAgg.c, line 2096.
(gdb) c
Continuing.
Breakpoint 1, ExecInitAgg (node=0x2d903a0, estate=0x2d52428, eflags=16) at nodeAgg.c:2096
2096 Bitmapset *all_grouped_cols = NULL;
(gdb)
입력 매개 변수
(gdb) p *node
$1 = {plan = {type = T_Agg, startup_cost = 13677, total_cost = 13677.0625, plan_rows = 5, plan_width = 45,
parallel_aware = false, parallel_safe = false, plan_node_id = 0, targetlist = 0x2d631f8, qual = 0x0,
lefttree = 0x2d62cb8, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}, aggstrategy = AGG_HASHED,
aggsplit = AGGSPLIT_SIMPLE, numCols = 1, grpColIdx = 0x2d62fa8, grpOperators = 0x2d62f88, numGroups = 5, aggParams = 0x0,
groupingSets = 0x0, chain = 0x0}
(gdb) p *estate
$2 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x2d00b80, es_crosscheck_snapshot = 0x0,
es_range_table = 0x2d62ff0, es_plannedstmt = 0x2c72530,
es_sourceText = 0x2c70d78 "select bh,avg(c1),min(c1),max(c2) from t_agg group by bh;", es_junkFilter = 0x0,
es_output_cid = 0, es_result_relations = 0x0, es_num_result_relations = 0, es_result_relation_info = 0x0,
es_root_result_relations = 0x0, es_num_root_result_relations = 0, es_tuple_routing_result_relations = 0x0,
es_trig_target_relations = 0x0, es_trig_tuple_slot = 0x0, es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0,
es_param_list_info = 0x0, es_param_exec_vals = 0x0, es_queryEnv = 0x0, es_query_cxt = 0x2d52310, es_tupleTable = 0x0,
es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, es_top_eflags = 16, es_instrument = 0, es_finished = false,
es_exprcontexts = 0x0, es_subplanstates = 0x0, es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0,
es_epqTuple = 0x0, es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0,
es_jit_flags = 0, es_jit = 0x0, es_jit_worker_instr = 0x0}
(gdb)
Hash 알고리즘 으로 계산 하기
(gdb) n
2097 int numGroupingSets = 1;
(gdb)
2100 int i = 0;
(gdb)
2101 int j = 0;
(gdb)
2102 bool use_hashing = (node->aggstrategy == AGG_HASHED ||
(gdb)
2106 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
(gdb) p use_hashing
$3 = true
(gdb)
1. AggState 구조 체 초기 화
(gdb) n
2111 aggstate = makeNode(AggState);
(gdb)
2112 aggstate->ss.ps.plan = (Plan *) node;
(gdb)
2113 aggstate->ss.ps.state = estate;
(gdb)
2114 aggstate->ss.ps.ExecProcNode = ExecAgg;
(gdb)
2116 aggstate->aggs = NIL;
(gdb)
2117 aggstate->numaggs = 0;
(gdb)
2118 aggstate->numtrans = 0;
(gdb)
2119 aggstate->aggstrategy = node->aggstrategy;
(gdb)
2120 aggstate->aggsplit = node->aggsplit;
(gdb)
2121 aggstate->maxsets = 0;
(gdb)
2122 aggstate->projected_set = -1;
(gdb)
2123 aggstate->current_set = 0;
(gdb)
2124 aggstate->peragg = NULL;
(gdb)
2125 aggstate->pertrans = NULL;
(gdb)
2126 aggstate->curperagg = NULL;
(gdb)
2127 aggstate->curpertrans = NULL;
(gdb)
2128 aggstate->input_done = false;
(gdb)
2129 aggstate->agg_done = false;
(gdb)
2130 aggstate->pergroups = NULL;
(gdb)
2131 aggstate->grp_firstTuple = NULL;
(gdb)
2132 aggstate->sort_in = NULL;
(gdb)
2133 aggstate->sort_out = NULL;
(gdb)
(gdb) p *aggstate
$4 = {ss = {ps = {type = T_AggState, plan = 0x2d903a0, state = 0x2d52428, ExecProcNode = 0x6ee438 ,
ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,
lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x0,
ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x0}, ss_currentRelation = 0x0, ss_currentScanDesc = 0x0,
ss_ScanTupleSlot = 0x0}, aggs = 0x0, numaggs = 0, numtrans = 0, aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE,
phase = 0x0, numphases = 0, current_phase = 0, peragg = 0x0, pertrans = 0x0, hashcontext = 0x0, aggcontexts = 0x0,
tmpcontext = 0x0, curaggcontext = 0x0, curperagg = 0x0, curpertrans = 0x0, input_done = false, agg_done = false,
projected_set = -1, current_set = 0, grouped_cols = 0x0, all_grouped_cols = 0x0, maxsets = 0, phases = 0x0,
sort_in = 0x0, sort_out = 0x0, sort_slot = 0x0, pergroups = 0x0, grp_firstTuple = 0x0, table_filled = false,
num_hashes = 0, perhash = 0x0, hash_pergroup = 0x0, all_pergroups = 0x0, combinedproj = 0x0}
(gdb)
2. 계산 은 몇 단계 로 나 뉜 다 (Hash vs Group)
(gdb)
2138 numPhases = (use_hashing ? 1 : 2);
(gdb) p numPhases
$5 = 1
(gdb) p numHashes
$6 = 1
(gdb)
Hash 는 한 단계 만 필요 합 니 다. Hash 를 실행 합 니 다.3. grouping set 가 존재 하면 관련 정 보 를 초기 화 합 니 다.
(gdb) n
2168 aggstate->maxsets = numGroupingSets;
grouping set 가 없습니다. 관련 정 보 를 초기 화 할 필요 가 없습니다.4. 메모리 컨 텍스트 할당
(gdb)
2169 aggstate->numphases = numPhases;
(gdb)
2172 palloc0(sizeof(ExprContext *) * numGroupingSets);
(gdb)
2171 aggstate->aggcontexts = (ExprContext **)
(gdb)
2188 ExecAssignExprContext(estate, &aggstate->ss.ps);
(gdb)
2189 aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
(gdb)
2191 for (i = 0; i < numGroupingSets; ++i)
(gdb)
2193 ExecAssignExprContext(estate, &aggstate->ss.ps);
(gdb)
2194 aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
(gdb)
2191 for (i = 0; i < numGroupingSets; ++i)
(gdb)
2197 if (use_hashing)
(gdb)
2199 ExecAssignExprContext(estate, &aggstate->ss.ps);
(gdb)
2200 aggstate->hashcontext = aggstate->ss.ps.ps_ExprContext;
(gdb)
2203 ExecAssignExprContext(estate, &aggstate->ss.ps);
(gdb)
2211 if (node->aggstrategy == AGG_HASHED)
(gdb)
2212 eflags &= ~EXEC_FLAG_REWIND;
(gdb)
5. outer plan 하위 노드 초기 화
(gdb)
2213 outerPlan = outerPlan(node);
(gdb) n
2214 outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
(gdb) p *outerPlan
$7 = {type = T_SeqScan, startup_cost = 0, total_cost = 8677, plan_rows = 500000, plan_width = 13, parallel_aware = false,
parallel_safe = false, plan_node_id = 1, targetlist = 0x2d62770, qual = 0x0, lefttree = 0x0, righttree = 0x0,
initPlan = 0x0, extParam = 0x0, allParam = 0x0}
outer (왼쪽 트 리) 노드 는 SeqScan 이 고 순서 전체 표 스 캔 입 니 다.6. 결과 유형, slot, 투영 초기 화
(gdb) n
2219 ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss);
(gdb) n
2220 scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
(gdb) n
2221 if (node->chain)
(gdb) p *aggstate
$8 = {ss = {ps = {type = T_AggState, plan = 0x2d903a0, state = 0x2d52428, ExecProcNode = 0x6ee438 ,
ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,
lefttree = 0x2d52bb0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x0,
ps_ExprContext = 0x2d52af0, ps_ProjInfo = 0x0, scandesc = 0x2d52f00}, ss_currentRelation = 0x0,
ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x2d53458}, aggs = 0x0, numaggs = 0, numtrans = 0,
aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE, phase = 0x0, numphases = 1, current_phase = 0, peragg = 0x0,
pertrans = 0x0, hashcontext = 0x2d52a30, aggcontexts = 0x2d52858, tmpcontext = 0x2d52878, curaggcontext = 0x0,
curperagg = 0x0, curpertrans = 0x0, input_done = false, agg_done = false, projected_set = -1, current_set = 0,
grouped_cols = 0x0, all_grouped_cols = 0x0, maxsets = 1, phases = 0x0, sort_in = 0x0, sort_out = 0x0, sort_slot = 0x0,
pergroups = 0x0, grp_firstTuple = 0x0, table_filled = false, num_hashes = 0, perhash = 0x0, hash_pergroup = 0x0,
all_pergroups = 0x0, combinedproj = 0x0}
(gdb)
(gdb) p *scanDesc
$9 = {natts = 7, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x2d52f20}
(gdb) p *aggstate->ss.ps.scandesc
$10 = {natts = 7, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x2d52f20}
(gdb)
(gdb) n
2227 ExecInitResultTupleSlotTL(estate, &aggstate->ss.ps);
(gdb)
2228 ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
(gdb)
2244 ExecInitQual(node->plan.qual, (PlanState *) aggstate);
(gdb) p *aggstate
$11 = {ss = {ps = {type = T_AggState, plan = 0x2d903a0, state = 0x2d52428, ExecProcNode = 0x6ee438 ,
ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,
lefttree = 0x2d52bb0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2d537b0,
ps_ExprContext = 0x2d52af0, ps_ProjInfo = 0x2d538f0, scandesc = 0x2d52f00}, ss_currentRelation = 0x0,
ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x2d53458}, aggs = 0x2d53e00, numaggs = 3, numtrans = 0,
aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE, phase = 0x0, numphases = 1, current_phase = 0, peragg = 0x0,
pertrans = 0x0, hashcontext = 0x2d52a30, aggcontexts = 0x2d52858, tmpcontext = 0x2d52878, curaggcontext = 0x0,
curperagg = 0x0, curpertrans = 0x0, input_done = false, agg_done = false, projected_set = -1, current_set = 0,
grouped_cols = 0x0, all_grouped_cols = 0x0, maxsets = 1, phases = 0x0, sort_in = 0x0, sort_out = 0x0, sort_slot = 0x0,
pergroups = 0x0, grp_firstTuple = 0x0, table_filled = false, num_hashes = 0, perhash = 0x0, hash_pergroup = 0x0,
all_pergroups = 0x0, combinedproj = 0x0}
(gdb) p *aggstate->ss.ps.scandesc
$12 = {natts = 7, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x2d52f20}
#### Slot
(gdb) p *aggstate->ss.ps.ps_ResultTupleSlot
$13 = {type = T_TupleTableSlot, tts_isempty = true, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false,
tts_tuple = 0x0, tts_tupleDescriptor = 0x2d53598, tts_mcxt = 0x2d52310, tts_buffer = 0, tts_nvalid = 0,
tts_values = 0x2d53810, tts_isnull = 0x2d53830, 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 *aggstate->ss.ps.ps_ProjInfo
$14 = {type = T_ProjectionInfo, pi_state = {tag = {type = T_ExprState}, flags = 6 '\006', resnull = false, resvalue = 0,
resultslot = 0x2d537b0, steps = 0x2d53988, evalfunc = 0x6cd882 , expr = 0x2d631f8,
evalfunc_private = 0x6cb43e , steps_len = 9, steps_alloc = 16, parent = 0x2d52640, ext_params = 0x0,
innermost_caseval = 0x0, innermost_casenull = 0x0, innermost_domainval = 0x0, innermost_domainnull = 0x0},
pi_exprContext = 0x2d52af0}
(gdb)
7. 초기 화 서브 표현 식
(gdb) n
2243 aggstate->ss.ps.qual =
(gdb)
2249 numaggs = aggstate->numaggs;
(gdb) p *aggstate->ss.ps.qual
Cannot access memory at address 0x0
(gdb)
(gdb) n
2250 Assert(numaggs == list_length(aggstate->aggs));
(gdb) p aggstate->numaggs
$16 = 3
표현 식 은 NULL 입 니 다. 모두 3 개의 집합 함수 가 있 습 니 다.8. AggStatePerPhasedata / agStatePerHashData 등 구조 체 에 메모리 할당
(gdb) n
2256 aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
(gdb)
2258 aggstate->num_hashes = numHashes;
(gdb)
2259 if (numHashes)
(gdb)
2261 aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
(gdb)
2262 aggstate->phases[0].numsets = 0;
(gdb)
2263 aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
(gdb) n
2264 aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
(gdb)
2267 phase = 0;
(gdb)
(gdb) p aggstate->phases[0]
$17 = {aggstrategy = AGG_PLAIN, numsets = 0, gset_lengths = 0x2d5
9. 각 단계 9.1 컴 퓨 팅 그룹 열 을 반복 하여 phasedata - > grouped 에 저장 합 니 다.cols 배열 과 allgrouped_cols 에서 9.2 AggState - > phases 배열 초기 화 (배열 요소 에 대응 하 는 구조 체 는 AggStatePerPhase) 9.3 AggState - > perhash 배열 초기 화 (대응 하 는 구조 체 는 AggStatePerHash)
(gdb) n
2268 for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
(gdb) p list_length(node->chain)
$18 = 0
(gdb) n
2273 if (phaseidx > 0)
(gdb)
2280 aggnode = node;
(gdb) p *node
$19 = {plan = {type = T_Agg, startup_cost = 13677, total_cost = 13677.0625, plan_rows = 5, plan_width = 45,
parallel_aware = false, parallel_safe = false, plan_node_id = 0, targetlist = 0x2d631f8, qual = 0x0,
lefttree = 0x2d62cb8, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}, aggstrategy = AGG_HASHED,
aggsplit = AGGSPLIT_SIMPLE, numCols = 1, grpColIdx = 0x2d62fa8, grpOperators = 0x2d62f88, numGroups = 5, aggParams = 0x0,
groupingSets = 0x0, chain = 0x0}
(gdb) n
2281 sortnode = NULL;
(gdb)
2284 Assert(phase <= 1 || sortnode);
(gdb)
2286 if (aggnode->aggstrategy == AGG_HASHED
(gdb)
2289 AggStatePerPhase phasedata = &aggstate->phases[0];
(gdb)
2291 Bitmapset *cols = NULL;
(gdb)
2293 Assert(phase == 0);
(gdb)
2294 i = phasedata->numsets++;
(gdb)
2295 perhash = &aggstate->perhash[i];
(gdb)
2298 phasedata->aggnode = node;
(gdb) p *phasedata
$20 = {aggstrategy = AGG_PLAIN, numsets = 1, gset_lengths = 0x2d53fe8, grouped_cols = 0x2d54008, eqfunctions = 0x0,
aggnode = 0x0, sortnode = 0x0, evaltrans = 0x0}
(gdb) p i
$21 = 0
(gdb) n
2299 phasedata->aggstrategy = node->aggstrategy;
(gdb)
2302 perhash->aggnode = aggnode;
(gdb)
2304 phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
(gdb)
2306 for (j = 0; j < aggnode->numCols; ++j)
(gdb) p aggnode->numCols
$22 = 1
(gdb) n
2307 cols = bms_add_member(cols, aggnode->grpColIdx[j]);
(gdb)
2306 for (j = 0; j < aggnode->numCols; ++j)
(gdb)
2309 phasedata->grouped_cols[i] = cols;
(gdb) p cols
$23 = (Bitmapset *) 0x2d54028
(gdb) p *cols
$24 = {nwords = 1, words = 0x2d5402c}
(gdb) p *cols->words
$25 = 2
(gdb) n
2311 all_grouped_cols = bms_add_members(all_grouped_cols, cols);
(gdb)
2312 continue;
(gdb) p all_grouped_cols
$26 = (Bitmapset *) 0x2d54048
(gdb) p *all_grouped_cols
$27 = {nwords = 1, words = 0x2d5404c}
(gdb) p *all_grouped_cols->words
$28 = 2
(gdb) n
2268 for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
(gdb)
2406 i = -1;
10. all 변환grouped_cols 는 역순 링크 입 니 다.
2407 while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
(gdb) p *all_grouped_cols
$29 = {nwords = 1, words = 0x2d5404c}
(gdb) n
2408 aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
(gdb)
2407 while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
(gdb)
11. 출력 expr 컨 텍스트 에 aggregate - result 저장 소 를 설정 하고 개인 per - agg 작업 저장 소 를 할당 합 니 다.
(gdb)
2414 econtext = aggstate->ss.ps.ps_ExprContext;
(gdb)
2415 econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
(gdb)
2416 econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
(gdb)
2418 peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
(gdb)
2419 pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numaggs);
(gdb)
2421 aggstate->peragg = peraggs;
(gdb)
2422 aggstate->pertrans = pertransstates;
(gdb)
2427 * (numGroupingSets + numHashes));
(gdb)
2426 (AggStatePerGroup *) palloc0(sizeof(AggStatePerGroup)
(gdb)
2425 aggstate->all_pergroups =
(gdb)
2428 pergroups = aggstate->all_pergroups;
(gdb)
2430 if (node->aggstrategy != AGG_HASHED)
(gdb)
12. Hash 알고리즘 을 사용 하면 find 호출hash_columns 와 buildhash_table 방법 관련 데이터 초기 화
(gdb)
2445 if (use_hashing)
(gdb)
2448 aggstate->hash_pergroup = pergroups;
(gdb)
2450 find_hash_columns(aggstate);
(gdb)
2451 build_hash_table(aggstate);
(gdb)
2452 aggstate->table_filled = false;
(gdb)
2461 if (node->aggstrategy == AGG_HASHED)
(gdb) p *aggstate
$30 = {ss = {ps = {type = T_AggState, plan = 0x2d903a0, state = 0x2d52428, ExecProcNode = 0x6ee438 ,
ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,
lefttree = 0x2d52bb0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2d537b0,
ps_ExprContext = 0x2d52af0, ps_ProjInfo = 0x2d538f0, scandesc = 0x2d52f00}, ss_currentRelation = 0x0,
ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x2d53458}, aggs = 0x2d53e00, numaggs = 3, numtrans = 0,
aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE, phase = 0x0, numphases = 1, current_phase = 0, peragg = 0x2d54770,
pertrans = 0x2d56780, hashcontext = 0x2d52a30, aggcontexts = 0x2d52858, tmpcontext = 0x2d52878, curaggcontext = 0x0,
curperagg = 0x0, curpertrans = 0x0, input_done = false, agg_done = false, projected_set = -1, current_set = 0,
grouped_cols = 0x0, all_grouped_cols = 0x2d54090, maxsets = 1, phases = 0x2d53ef8, sort_in = 0x0, sort_out = 0x0,
sort_slot = 0x0, pergroups = 0x0, grp_firstTuple = 0x0, table_filled = false, num_hashes = 1, perhash = 0x2d53f50,
hash_pergroup = 0x2d54988, all_pergroups = 0x2d54988, combinedproj = 0x0}
(gdb) p *aggstate->perhash
$31 = {hashtable = 0x2d54ad8, hashiter = {cur = 0, end = 0, done = false}, hashslot = 0x2d54238, hashfunctions = 0x2d542d0,
eqfuncoids = 0x2d54a90, numCols = 1, numhashGrpCols = 1, largestGrpColIdx = 1, hashGrpColIdxInput = 0x2d549f0,
hashGrpColIdxHash = 0x2d54a10, aggnode = 0x2d903a0}
(gdb) p *aggstate->hash_pergroup
$32 = (AggStatePerGroup) 0x0
(gdb) p *aggstate->all_pergroups
$33 = (AggStatePerGroup) 0x0
(gdb) p *aggstate->phases
$34 = {aggstrategy = AGG_HASHED, numsets = 1, gset_lengths = 0x2d53fe8, grouped_cols = 0x2d54008, eqfunctions = 0x0,
aggnode = 0x2d903a0, sortnode = 0x0, evaltrans = 0x0}
(gdb)
13. initialize 호출phase/select_current_set 초기 화 단계 데이터
(gdb) n
2463 aggstate->current_phase = 0;
(gdb)
2464 initialize_phase(aggstate, 0);
(gdb)
2465 select_current_set(aggstate, 0, true);
(gdb)
2510 aggno = -1;
(gdb) p *aggstate->phases
$35 = {aggstrategy = AGG_HASHED, numsets = 1, gset_lengths = 0x2d53fe8, grouped_cols = 0x2d54008, eqfunctions = 0x0,
aggnode = 0x2d903a0, sortnode = 0x0, evaltrans = 0x0}
(gdb)
14. 취 합 함수 정 보 를 검색 하고 per - agg 와 per - trans 데이터 가 변 하지 않 는 필드 를 초기 화 합 니 다.
(gdb) n
2463 aggstate->current_phase = 0;
(gdb)
2464 initialize_phase(aggstate, 0);
(gdb)
2465 select_current_set(aggstate, 0, true);
(gdb)
2510 aggno = -1;
(gdb) p *aggstate->phases
$35 = {aggstrategy = AGG_HASHED, numsets = 1, gset_lengths = 0x2d53fe8, grouped_cols = 0x2d54008, eqfunctions = 0x0,
aggnode = 0x2d903a0, sortnode = 0x0, evaltrans = 0x0}
(gdb) n
2511 transno = -1;
(gdb)
2512 foreach(l, aggstate->aggs)
(gdb)
2514 AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
(gdb)
2515 Aggref *aggref = aggrefstate->aggref;
(gdb)
2539 Assert(aggref->agglevelsup == 0);
(gdb) p aggstate->aggs
$36 = (List *) 0x2d53e00
(gdb) p *aggstate->aggs
$37 = {type = T_List, length = 3, head = 0x2d53ed0, tail = 0x2d53dd8}
(gdb) n
2541 Assert(aggref->aggsplit == aggstate->aggsplit);
(gdb)
2544 existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
(gdb)
2546 if (existing_aggno != -1)
(gdb)
2557 peragg = &peraggs[++aggno];
(gdb)
2558 peragg->aggref = aggref;
(gdb)
2559 aggrefstate->aggno = aggno;
(gdb)
2563 ObjectIdGetDatum(aggref->aggfnoid));
(gdb)
2562 aggTuple = SearchSysCache1(AGGFNOID,
(gdb) p aggref->aggfnoid
$38 = 2116
(gdb) n
2564 if (!HeapTupleIsValid(aggTuple))
(gdb) p *aggTuple
$39 = {t_len = 96, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 17}, t_tableOid = 2600, t_data = 0x7fa0c01f1630}
(gdb) p *aggTuple->t_data
$40 = {t_choice = {t_heap = {t_xmin = 1, t_xmax = 0, t_field3 = {t_cid = 0, t_xvac = 0}}, t_datum = {datum_len_ = 1,
datum_typmod = 0, datum_typeid = 0}}, t_ctid = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 17}, t_infomask2 = 22,
t_infomask = 2305, t_hoff = 32 ' ', t_bits = 0x7fa0c01f1647 "\377\377\017"}
(gdb) n
2567 aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
(gdb)
2570 aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
(gdb) p *aggform
$41 = {aggfnoid = 2116, aggkind = 110 'n', aggnumdirectargs = 0, aggtransfn = 768, aggfinalfn = 0, aggcombinefn = 768,
aggserialfn = 0, aggdeserialfn = 0, aggmtransfn = 0, aggminvtransfn = 0, aggmfinalfn = 0, aggfinalextra = false,
aggmfinalextra = false, aggfinalmodify = 114 'r', aggmfinalmodify = 114 'r', aggsortop = 521, aggtranstype = 23,
aggtransspace = 0, aggmtranstype = 0, aggmtransspace = 0}
(gdb) n
2572 if (aclresult != ACLCHECK_OK)
(gdb)
2575 InvokeFunctionExecuteHook(aggref->aggfnoid);
(gdb)
2578 aggtranstype = aggref->aggtranstype;
(gdb)
2579 Assert(OidIsValid(aggtranstype));
(gdb)
2585 if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
(gdb)
2594 transfn_oid = aggform->aggtransfn;
(gdb)
2597 if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
(gdb) p transfn_oid
$42 = 768
(gdb) n
2600 peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
(gdb)
2607 shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) ||
(gdb) p aggform->aggfinalfn
$43 = 0
(gdb) n
2609 peragg->shareable = shareable;
(gdb)
2611 serialfn_oid = InvalidOid;
(gdb) p shareable
$44 = true
(gdb) n
2612 deserialfn_oid = InvalidOid;
(gdb)
2618 if (aggtranstype == INTERNALOID)
(gdb)
2653 ObjectIdGetDatum(aggref->aggfnoid));
(gdb)
2652 procTuple = SearchSysCache1(PROCOID,
(gdb)
2654 if (!HeapTupleIsValid(procTuple))
(gdb)
2657 aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
(gdb)
2658 ReleaseSysCache(procTuple);
(gdb)
2660 aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
(gdb)
2662 if (aclresult != ACLCHECK_OK)
(gdb)
2665 InvokeFunctionExecuteHook(transfn_oid);
(gdb)
2666 if (OidIsValid(finalfn_oid))
(gdb)
2675 if (OidIsValid(serialfn_oid))
(gdb)
2684 if (OidIsValid(deserialfn_oid))
(gdb)
2700 numArguments = get_aggregate_argtypes(aggref, inputTypes);
(gdb)
2703 numDirectArgs = list_length(aggref->aggdirectargs);
(gdb)
2706 if (aggform->aggfinalextra)
(gdb)
2709 peragg->numFinalArgs = numDirectArgs + 1;
(gdb)
2712 peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
(gdb)
2719 if (OidIsValid(finalfn_oid))
(gdb)
2733 get_typlenbyval(aggref->aggtype,
(gdb)
2741 textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
(gdb)
2744 if (initValueIsNull)
(gdb)
2745 initValue = (Datum) 0;
(gdb)
2757 existing_transno = find_compatible_pertrans(aggstate, aggref,
(gdb)
2763 if (existing_transno != -1)
(gdb)
2775 pertrans = &pertransstates[++transno];
(gdb)
2776 build_pertrans_for_aggref(pertrans, aggstate, estate,
(gdb)
2781 peragg->transno = transno;
(gdb)
2783 ReleaseSysCache(aggTuple);
(gdb)
2512 foreach(l, aggstate->aggs)
(gdb)
########
testdb=# select oid,proname from pg_proc where oid in (2116,768);
oid | proname
------+------------
768 | int4larger
2116 | max
(2 rows)
########
다음 순환
...
(gdb) p *aggref
$45 = {xpr = {type = T_Aggref}, aggfnoid = 2132, aggtype = 23, aggcollid = 0, inputcollid = 0, aggtranstype = 23,
aggargtypes = 0x2d63578, aggdirectargs = 0x0, args = 0x2d63688, aggorder = 0x0, aggdistinct = 0x0, aggfilter = 0x0,
aggstar = false, aggvariadic = false, aggkind = 110 'n', agglevelsup = 0, aggsplit = AGGSPLIT_SIMPLE, location = 18}
...
(gdb) p transfn_oid
$49 = 769
...
testdb=# select oid,proname from pg_proc where oid in (2132,769);
oid | proname
------+-------------
769 | int4smaller
2132 | min
(2 rows)
세 번 째 순환
...
(gdb) p *aggref
$50 = {xpr = {type = T_Aggref}, aggfnoid = 2101, aggtype = 1700, aggcollid = 0, inputcollid = 0, aggtranstype = 1016,
aggargtypes = 0x2d632f0, aggdirectargs = 0x0, args = 0x2d63400, aggorder = 0x0, aggdistinct = 0x0, aggfilter = 0x0,
aggstar = false, aggvariadic = false, aggkind = 110 'n', agglevelsup = 0, aggsplit = AGGSPLIT_SIMPLE, location = 10}
...
(gdb) p transfn_oid
$51 = 1963
...
2512 foreach(l, aggstate->aggs)
(gdb)
#####
testdb=# select oid,proname from pg_proc where oid in (2101,1963);
oid | proname
------+----------------
1963 | int4_avg_accum
2101 | avg
(2 rows)
#####
15. 한 번 구축 하면 모든 변환 작업 을 완성 하 는 표현 식 입 니 다.
(gdb)
2790 aggstate->numaggs = aggno + 1;
(gdb)
2791 aggstate->numtrans = transno + 1;
(gdb)
2803 if (numaggs != list_length(aggstate->aggs))
(gdb)
2815 for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
(gdb)
2817 AggStatePerPhase phase = &aggstate->phases[phaseidx];
(gdb)
2818 bool dohash = false;
(gdb)
2819 bool dosort = false;
(gdb)
2822 if (!phase->aggnode)
(gdb)
2825 if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
(gdb)
2834 else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
(gdb)
2843 else if (phase->aggstrategy == AGG_PLAIN ||
(gdb)
2844 phase->aggstrategy == AGG_SORTED)
(gdb)
2843 else if (phase->aggstrategy == AGG_PLAIN ||
(gdb)
2849 else if (phase->aggstrategy == AGG_HASHED)
(gdb)
2851 dohash = true;
(gdb)
2852 dosort = false;
(gdb)
2857 phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash);
(gdb)
2815 for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
(gdb)
2861 return aggstate;
(gdb)
최종 결과 AggState 구조 체
(gdb) p *aggstate
$52 = {ss = {ps = {type = T_AggState, plan = 0x2d903a0, state = 0x2d52428, ExecProcNode = 0x6ee438 ,
ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,
lefttree = 0x2d52bb0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2d537b0,
ps_ExprContext = 0x2d52af0, ps_ProjInfo = 0x2d538f0, scandesc = 0x2d52f00}, ss_currentRelation = 0x0,
ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x2d53458}, aggs = 0x2d53e00, numaggs = 3, numtrans = 3,
aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE, phase = 0x2d53ef8, numphases = 1, current_phase = 0,
peragg = 0x2d54770, pertrans = 0x2d56780, hashcontext = 0x2d52a30, aggcontexts = 0x2d52858, tmpcontext = 0x2d52878,
curaggcontext = 0x2d52a30, curperagg = 0x0, curpertrans = 0x0, input_done = false, agg_done = false, projected_set = -1,
current_set = 0, grouped_cols = 0x0, all_grouped_cols = 0x2d54090, maxsets = 1, phases = 0x2d53ef8, sort_in = 0x0,
sort_out = 0x0, sort_slot = 0x0, pergroups = 0x0, grp_firstTuple = 0x0, table_filled = false, num_hashes = 1,
perhash = 0x2d53f50, hash_pergroup = 0x2d54988, all_pergroups = 0x2d54988, combinedproj = 0x0}
AggState->phase
(gdb) p *aggstate->phase
$53 = {aggstrategy = AGG_HASHED, numsets = 1, gset_lengths = 0x2d53fe8, grouped_cols = 0x2d54008, eqfunctions = 0x0,
aggnode = 0x2d903a0, sortnode = 0x0, evaltrans = 0x2d55e78}
AggState->peragg
(gdb) p *aggstate->peragg
$54 = {aggref = 0x2d63740, 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 *aggstate->peragg->aggref
$55 = {xpr = {type = T_Aggref}, aggfnoid = 2116, aggtype = 23, aggcollid = 0, inputcollid = 0, aggtranstype = 23,
aggargtypes = 0x2d63800, aggdirectargs = 0x0, args = 0x2d63910, aggorder = 0x0, aggdistinct = 0x0, aggfilter = 0x0,
aggstar = false, aggvariadic = false, aggkind = 110 'n', agglevelsup = 0, aggsplit = AGGSPLIT_SIMPLE, location = 26}
(gdb) p aggstate->peragg[1]
$56 = {aggref = 0x2d634b8, 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) p *aggstate->peragg[1]->aggref
$57 = {xpr = {type = T_Aggref}, aggfnoid = 2132, aggtype = 23, aggcollid = 0, inputcollid = 0, aggtranstype = 23,
aggargtypes = 0x2d63578, aggdirectargs = 0x0, args = 0x2d63688, aggorder = 0x0, aggdistinct = 0x0, aggfilter = 0x0,
aggstar = false, aggvariadic = false, aggkind = 110 'n', agglevelsup = 0, aggsplit = AGGSPLIT_SIMPLE, location = 18}
(gdb) p aggstate->peragg[2]
$58 = {aggref = 0x2d63230, 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 = 0x2d52310,
fn_expr = 0x2d55b80}, numFinalArgs = 1, aggdirectargs = 0x0, resulttypeLen = -1, resulttypeByVal = false,
shareable = true}
(gdb) p *aggstate->peragg[2]->aggref
$59 = {xpr = {type = T_Aggref}, aggfnoid = 2101, aggtype = 1700, aggcollid = 0, inputcollid = 0, aggtranstype = 1016,
aggargtypes = 0x2d632f0, aggdirectargs = 0x0, args = 0x2d63400, aggorder = 0x0, aggdistinct = 0x0, aggfilter = 0x0,
aggstar = false, aggvariadic = false, aggkind = 110 'n', agglevelsup = 0, aggsplit = AGGSPLIT_SIMPLE, location = 10}
AggState->pertrans
(gdb) p aggstate->pertrans[0]
$60 = {aggref = 0x2d63740, 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 = 0x2d52310, fn_expr = 0x2d55940},
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 = 0x2d549b0, transfn_fcinfo = {flinfo = 0x2d567a8,
context = 0x2d52640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {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 aggstate->pertrans[1]
$61 = {aggref = 0x2d634b8, 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 = 0x2d52310, fn_expr = 0x2d55a90},
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 = 0x2d549d0, transfn_fcinfo = {flinfo = 0x2d573f0,
context = 0x2d52640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {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 aggstate->pertrans[2]
$62 = {aggref = 0x2d63230, 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 = 0x2d52310, fn_expr = 0x2d55e20},
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 = 47537400,
initValueIsNull = false, inputtypeLen = 0, transtypeLen = -1, inputtypeByVal = false, transtypeByVal = false,
sortslot = 0x0, uniqslot = 0x0, sortdesc = 0x0, sortstates = 0x2d55bd8, transfn_fcinfo = {flinfo = 0x2d58038,
context = 0x2d52640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {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 }}}
AggState - > 그룹 관련
(gdb) p *aggstate->pergroups
Cannot access memory at address 0x0
(gdb) p *aggstate->hash_pergroup
$65 = (AggStatePerGroup) 0x0
(gdb) p *aggstate->all_pergroups
$66 = (AggStatePerGroup) 0x0
AggState->perhash
(gdb) p *aggstate->perhash
$67 = {hashtable = 0x2d54ad8, hashiter = {cur = 0, end = 0, done = false}, hashslot = 0x2d54238, hashfunctions = 0x2d542d0,
eqfuncoids = 0x2d54a90, numCols = 1, numhashGrpCols = 1, largestGrpColIdx = 1, hashGrpColIdxInput = 0x2d549f0,
hashGrpColIdxHash = 0x2d54a10, aggnode = 0x2d903a0}
(gdb) p *aggstate->perhash->hashtable
$68 = {hashtab = 0x2d54b70, numCols = 1, keyColIdx = 0x2d54a10, tab_hash_funcs = 0x2d542d0, tab_eq_func = 0x2d54e90,
tablecxt = 0x2d7c450, tempcxt = 0x2d90a00, entrysize = 24, tableslot = 0x2d54df8, inputslot = 0x0, in_hash_funcs = 0x0,
cur_eq_func = 0x0, hash_iv = 0, exprcontext = 0x2d557b0}
(gdb) p *aggstate->perhash->hashfunctions
$69 = {fn_addr = 0x4c8a31 , fn_oid = 400, fn_nargs = 1, fn_strict = true, fn_retset = false, fn_stats = 2 '\002',
fn_extra = 0x0, fn_mcxt = 0x2d52310, fn_expr = 0x0}
DONE! 아직도 많은 세부 사항 을 정리 해 야 한다.
참고 자료
N/A
"ITPUB 블 로그" 에서 왔 습 니 다. 링크:http://blog.itpub.net/6906/viewspace-2642887/전재 가 필요 하 다 면 출처 를 밝 혀 주 십시오. 그렇지 않 으 면 법 적 책임 을 추궁 할 것 입 니 다.
다음으로 전송:http://blog.itpub.net/6906/viewspace-2642887/
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.