PostgreSQL 소스 코드 해독 (181) - 조회 \ # 97 (집합 함수 \ # 2 - ExecInitAgg)

82039 단어
이 절 은 PostgreSQL 이 취 합 함 수 를 실행 할 때의 초기 화 작업 을 간단하게 소개 하 였 으 며, 주요 실현 함 수 는 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/

좋은 웹페이지 즐겨찾기