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

一、数据结构

AggState
聚合函数执行时状态结构体,内含AggStatePerAgg等结构体

/*---------------------*AggStateinformation**ss.ss_ScanTupleSlotreferstooutputofunderlyingplan.*ss.ss_ScanTupleSlot指的是基础计划的输出.*(ss=ScanState,ps=PlanState)**Note:ss.ps.ps_ExprContextcontainsecxt_aggvaluesand*ecxt_aggnullsarrays,whichholdthecomputedaggvaluesforthecurrent*inputgroupduringevaluationofanAggnode'soutputtuple(s).We*createasecondExprContext,tmpcontext,inwhichtoevaluateinput*expressionsandruntheaggregatetransitionfunctions.*注意:ss.ps.ps_ExprContext包含了ecxt_aggvalues和ecxt_aggnulls数组,*这两个数组保存了在计算agg节点的输出元组时当前输入组已计算的agg值.*---------------------*//*thesestructsareprivateinnodeAgg.c:*///在nodeAgg.c中私有的结构体typedefstructAggStatePerAggData*AggStatePerAgg;typedefstructAggStatePerTransData*AggStatePerTrans;typedefstructAggStatePerGroupData*AggStatePerGroup;typedefstructAggStatePerPhaseData*AggStatePerPhase;typedefstructAggStatePerHashData*AggStatePerHash;typedefstructAggState{//第一个字段是NodeTag(继承自ScanState)ScanStatess;/*itsfirstfieldisNodeTag*///targetlist和quals中所有的AggrefList*aggs;/*allAggrefnodesintargetlist&quals*///链表的大小(可以为0)intnumaggs;/*lengthoflist(couldbezero!)*///pertrans条目大小intnumtrans;/*numberofpertransitems*///Agg策略模式AggStrategyaggstrategy;/*strategymode*///agg-splitting模式,参见nodes.hAggSplitaggsplit;/*agg-splittingmode,seenodes.h*///指向当前步骤数据的指针AggStatePerPhasephase;/*pointertocurrentphasedata*///步骤数(包括0)intnumphases;/*numberofphases(includingphase0)*///当前步骤intcurrent_phase;/*currentphasenumber*///per-Aggref信息AggStatePerAggperagg;/*per-Aggrefinformation*///per-Trans状态信息AggStatePerTranspertrans;/*per-Transstateinformation*///长生命周期数据的ExprContexts(hashtable)ExprContext*hashcontext;/*econtextsforlong-liveddata(hashtable)*/////长生命周期数据的ExprContexts(每一个GS使用)ExprContext**aggcontexts;/*econtextsforlong-liveddata(perGS)*///输入表达式的ExprContextExprContext*tmpcontext;/*econtextforinputexpressions*/#defineFIELDNO_AGGSTATE_CURAGGCONTEXT14//当前活跃的aggcontextExprContext*curaggcontext;/*currentlyactiveaggcontext*///当前活跃的aggregate(如存在)AggStatePerAggcurperagg;/*currentlyactiveaggregate,ifany*/#defineFIELDNO_AGGSTATE_CURPERTRANS16//当前活跃的transstateAggStatePerTranscurpertrans;/*currentlyactivetransstate,ifany*///输入结束?boolinput_done;/*indicatesendofinput*///Agg扫描结束?boolagg_done;/*indicatescompletionofAggscan*///最后一个groupingsetintprojected_set;/*Thelastprojectedgroupingset*/#defineFIELDNO_AGGSTATE_CURRENT_SET20//将要解析的当前groupingsetintcurrent_set;/*Thecurrentgroupingsetbeingevaluated*///当前投影操作的分组列Bitmapset*grouped_cols;/*groupedcolsincurrentprojection*///倒序的分组列链表List*all_grouped_cols;/*listofallgroupedcolsinDESCorder*//*Thesefieldsareforgroupingsetphasedata*///--------下面的列用于groupingset步骤数据//所有步骤中最大的sets大小intmaxsets;/*Themaxnumberofsetsinanyphase*///所有步骤的数组AggStatePerPhasephases;/*arrayofallphases*///对于phases>1,已排序的输入信息Tuplesortstate*sort_in;/*sortedinputtophases>1*///对于下一个步骤,输入已拷贝Tuplesortstate*sort_out;/*inputiscopiedherefornextphase*///排序结果的slotTupleTableSlot*sort_slot;/*slotforsortresults*//*thesefieldsareusedinAGG_PLAINandAGG_SORTEDmodes:*///-------下面的列用于AGG_PLAIN和AGG_SORTED模式://per-group指针的groupingset编号数组AggStatePerGroup*pergroups;/*groupingsetindexedarrayofper-group*pointers*///当前组的第一个元组拷贝HeapTuplegrp_firstTuple;/*copyoffirsttupleofcurrentgroup*//*thesefieldsareusedinAGG_HASHEDandAGG_MIXEDmodes:*///---------下面的列用于AGG_HASHED和AGG_MIXED模式://是否已填充hash表?booltable_filled;/*hashtablefilledyet?*///hash桶数?intnum_hashes;//相应的哈希表数据数组AggStatePerHashperhash;/*arrayofper-hashtabledata*///per-group指针的groupingset编号数组AggStatePerGroup*hash_pergroup;/*groupingsetindexedarrayof*per-grouppointers*//*supportforevaluationofagginputexpressions:*///----------agg输入表达式解析支持#defineFIELDNO_AGGSTATE_ALL_PERGROUPS34//首先是->pergroups,然后是hash_pergroupAggStatePerGroup*all_pergroups;/*arrayoffirst->pergroups,than*->hash_pergroup*///投影实现机制ProjectionInfo*combinedproj;/*projectionmachinery*/}AggState;/*PrimitiveoptionssupportedbynodeAgg.c:*///nodeag.c支持的基本选项#defineAGGSPLITOP_COMBINE0x01/*substitutecombinefnfortransfn*/#defineAGGSPLITOP_SKIPFINAL0x02/*skipfinalfn,returnstateas-is*/#defineAGGSPLITOP_SERIALIZE0x04/*applyserializefntooutput*/#defineAGGSPLITOP_DESERIALIZE0x08/*applydeserializefntoinput*//*Supportedoperatingmodes(i.e.,usefulcombinationsoftheseoptions):*///支持的操作模式typedefenumAggSplit{/*Basic,non-splitaggregation:*///基本:非split聚合AGGSPLIT_SIMPLE=0,/*Initialphaseofpartialaggregation,withserialization:*///部分聚合的初始步骤,序列化AGGSPLIT_INITIAL_SERIAL=AGGSPLITOP_SKIPFINAL|AGGSPLITOP_SERIALIZE,/*Finalphaseofpartialaggregation,withdeserialization:*///部分聚合的最终步骤,反序列化AGGSPLIT_FINAL_DESERIAL=AGGSPLITOP_COMBINE|AGGSPLITOP_DESERIALIZE}AggSplit;/*TestwhetheranAggSplitvalueselectseachprimitiveoption:*///测试AggSplit选择了哪些基本选项#defineDO_AGGSPLIT_COMBINE(as)(((as)&AGGSPLITOP_COMBINE)!=0)#defineDO_AGGSPLIT_SKIPFINAL(as)(((as)&AGGSPLITOP_SKIPFINAL)!=0)#defineDO_AGGSPLIT_SERIALIZE(as)(((as)&AGGSPLITOP_SERIALIZE)!=0)#defineDO_AGGSPLIT_DESERIALIZE(as)(((as)&AGGSPLITOP_DESERIALIZE)!=0)二、源码解读

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

/**ExecAgg-**ExecAggreceivestuplesfromitsoutersubplanandaggregatesover*theappropriateattributeforeachaggregatefunctionuse(Aggref*node)appearinginthetargetlistorqualofthenode.Thenumber*oftuplestoaggregateoverdependsonwhethergroupedorplain*aggregationisselected.Ingroupedaggregation,weproducearesult*rowforeachgroup;inplainaggregationthere'sasingleresultrow*forthewholequery.Ineithercase,thevalueofeachaggregateis*storedintheexpressioncontexttobeusedwhenExecProjectevaluates*theresulttuple.*ExecAgg接收从outer子计划返回的元组合适的属性上为每一个聚合函数(出现在投影列或节点表达式)执行聚合.*需要聚合的元组数量依赖于是否已分组或者选择普通聚合.*在已分组的聚合操作宏,为每一个组产生结果行;普通聚合,整个查询只有一个结果行.*不管哪种情况,每一个聚合结果值都会存储在表达式上下文中(ExecProject会解析结果元组)*/staticTupleTableSlot*ExecAgg(PlanState*pstate){AggState*node=castNode(AggState,pstate);TupleTableSlot*result=NULL;CHECK_FOR_INTERRUPTS();if(!node->agg_done){/*Dispatchbasedonstrategy*///基于策略进行分发switch(node->phase->aggstrategy){caseAGG_HASHED:if(!node->table_filled)agg_fill_hash_table(node);/*FALLTHROUGH*///填充后,执行MIXEDcaseAGG_MIXED:result=agg_retrieve_hash_table(node);break;caseAGG_PLAIN:caseAGG_SORTED:result=agg_retrieve_direct(node);break;}if(!TupIsNull(result))returnresult;}returnNULL;}

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

/**ExecAggforhashedcase:retrievinggroupsfromhashtable*ExecAgg(Hash实现版本):在hash表中检索组*/staticTupleTableSlot*agg_retrieve_hash_table(AggState*aggstate){ExprContext*econtext;AggStatePerAggperagg;AggStatePerGrouppergroup;TupleHashEntryData*entry;TupleTableSlot*firstSlot;TupleTableSlot*result;AggStatePerHashperhash;/**getstateinfofromnode.*从node节点中获取状态信息.**econtextistheper-output-tupleexpressioncontext.*econtext是per-output-tuple表达式上下文.*/econtext=aggstate->ss.ps.ps_ExprContext;peragg=aggstate->peragg;firstSlot=aggstate->ss.ss_ScanTupleSlot;/**Notethatperhash(andthereforeanythingaccessedthroughit)can*changeinsidetheloop,aswechangebetweengroupingsets.*注意,在分组之间切换时,perhash在循环中可能会改变*/perhash=&aggstate->perhash[aggstate->current_set];/**Weloopretrievinggroupsuntilwefindonesatisfying*aggstate->ss.ps.qual*循环检索groups,直至检索到一个符合aggstate->ss.ps.qual条件的组.*/while(!aggstate->agg_done){//-------------选好//获取SlotTupleTableSlot*hashslot=perhash->hashslot;inti;//检查中断CHECK_FOR_INTERRUPTS();/**Findthenextentryinthehashtable*检索hash表的下一个条目*/entry=ScanTupleHashTable(perhash->hashtable,&perhash->hashiter);if(entry==NULL){//条目为NULL,切换到下一个setintnextset=aggstate->current_set+1;if(nextset<aggstate->num_hashes){/**Switchtonextgroupingset,reinitialize,andrestartthe*loop.*切换至下一个groupingset,重新初始化并重启循环*/select_current_set(aggstate,nextset,true);perhash=&aggstate->perhash[aggstate->current_set];ResetTupleHashIterator(perhash->hashtable,&perhash->hashiter);continue;}else{/*Nomorehashtables,sodone*///已完成检索,设置标记,退出aggstate->agg_done=true;returnNULL;}}/**Cleartheper-output-tuplecontextforeachgroup*为每一个group清除per-output-tuple上下文**Weintentionallydon'tuseReScanExprContexthere;ifanyaggshave*registeredshutdowncallbacks,theymustn'tbecalledyet,sincewe*mightnotbedonewiththatagg.*在这里不会用到ReScanExprContext,如果存在aggs注册了shutdown回调,*那应该还没有调用,因为我们可能还没有完成该agg的处理.*/ResetExprContext(econtext);/**Transformrepresentativetuplebackintoonewiththeright*columns.*将典型元组转回具有正确列的元组.*/ExecStoreMinimalTuple(entry->firstTuple,hashslot,false);slot_getallattrs(hashslot);//清理元组//重置firstSlotExecClearTuple(firstSlot);memset(firstSlot->tts_isnull,true,firstSlot->tts_tupleDescriptor->natts*sizeof(bool));for(i=0;i<perhash->numhashGrpCols;i++){//重置firstSlotintvarNumber=perhash->hashGrpColIdxInput[i]-1;firstSlot->tts_values[varNumber]=hashslot->tts_values[i];firstSlot->tts_isnull[varNumber]=hashslot->tts_isnull[i];}ExecStoreVirtualTuple(firstSlot);pergroup=(AggStatePerGroup)entry->additional;/**Usetherepresentativeinputtupleforanyreferencesto*non-aggregatedinputcolumnsinthequalandtlist.*为qual和tlist中的非聚合输入列依赖使用典型输入元组*/econtext->ecxt_outertuple=firstSlot;//准备投影slotprepare_projection_slot(aggstate,econtext->ecxt_outertuple,aggstate->current_set);//最终的聚合操作finalize_aggregates(aggstate,peragg,pergroup);//投影result=project_aggregates(aggstate);if(result)returnresult;}/*Nomoregroups*///没有更多的groups了,返回NULLreturnNULL;}#defineScanTupleHashTable(htable,iter)\tuplehash_iterate(htable->hashtab,iter)/*--------------------------------*ExecStoreMinimalTuple**LikeExecStoreTuple,butinserta"minimal"tupleintotheslot.*与ExecStoreTuple类似,不同的是插入一个"最小化"的元组到slot中.**No'buffer'parametersinceminimaltuplesareneverstoredinrelations.*不需要"buffer"参数,因为最小化元组不会存储到relations中.*--------------------------------*/TupleTableSlot*ExecStoreMinimalTuple(MinimalTuplemtup,TupleTableSlot*slot,boolshouldFree){/**sanitychecks*一致性校验*/Assert(mtup!=NULL);Assert(slot!=NULL);Assert(slot->tts_tupleDescriptor!=NULL);/**Freeanyoldphysicaltuplebelongingtotheslot.*释放归属于该slot的旧物理元组*/if(slot->tts_shouldFree)heap_freetuple(slot->tts_tuple);if(slot->tts_shouldFreeMin)heap_free_minimal_tuple(slot->tts_mintuple);/**Dropthepinonthereferencedbuffer,ifthereisone.*清除已依赖buffer的pin标记*/if(BufferIsValid(slot->tts_buffer))ReleaseBuffer(slot->tts_buffer);slot->tts_buffer=InvalidBuffer;/**Storethenewtupleintothespecifiedslot.*存储新tuple到指定的slot中*/slot->tts_isempty=false;slot->tts_shouldFree=false;slot->tts_shouldFreeMin=shouldFree;slot->tts_tuple=&slot->tts_minhdr;slot->tts_mintuple=mtup;slot->tts_minhdr.t_len=mtup->t_len+MINIMAL_TUPLE_OFFSET;slot->tts_minhdr.t_data=(HeapTupleHeader)((char*)mtup-MINIMAL_TUPLE_OFFSET);/*noneedtosett_selfort_tableOidsincewewon'tallowaccess*///因为不允许访问,因此无需设置t_sefl或者t_tableOid/*Markextractedstateinvalid*///标记已提取状态无效slot->tts_nvalid=0;returnslot;}/*--------------------------------*ExecStoreVirtualTuple*Markaslotascontainingavirtualtuple.*标记slot包含虚拟元组**Theprotocolforloadingaslotwithvirtualtupledatais:**CallExecClearTupletomarktheslotempty.**StoredataintotheDatum/isnullarrays.**CallExecStoreVirtualTupletomarktheslotvalid.*Thisisabituncleanbutitavoidsoneroundofdatacopying.*使用虚拟元组数据的协议如下:**调用ExecClearTuple标记slot为空**存储数据到Datum/isnull数组中**调用ExecStoreVirtualTuple标记slot有效*--------------------------------*/TupleTableSlot*ExecStoreVirtualTuple(TupleTableSlot*slot){/**sanitychecks*一致性检查*/Assert(slot!=NULL);Assert(slot->tts_tupleDescriptor!=NULL);Assert(slot->tts_isempty);slot->tts_isempty=false;slot->tts_nvalid=slot->tts_tupleDescriptor->natts;returnslot;}三、跟踪分析

测试脚本

--创建数据表,插入测试数据droptableifexistst_agg_simple;createtablet_agg_simple(bhvarchar(20),c1int,c2int,c3int,c4int,c5int,c6int);insertintot_agg_simpleselect'GZ01',col,col,col,col,col,colfromgenerate_series(1,1)ascol;insertintot_agg_simpleselect'GZ02',col,col,col,col,col,colfromgenerate_series(2,2)ascol;insertintot_agg_simpleselect'GZ03',col,col,col,col,col,colfromgenerate_series(3,3)ascol;insertintot_agg_simpleselect'GZ04',col,col,col,col,col,colfromgenerate_series(4,4)ascol;insertintot_agg_simpleselect'GZ05',col,col,col,col,col,colfromgenerate_series(5,5)ascol;--禁用并行setmax_parallel_workers_per_gather=0;selectbh,avg(c1),min(c1),max(c2)fromt_agg_simplegroupbybh;

跟踪分析

Breakpoint1,agg_retrieve_hash_table(aggstate=0x2929640)atnodeAgg.c:19691969econtext=aggstate->ss.ps.ps_ExprContext;(gdb)

输入参数

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

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

(gdb)n1970peragg=aggstate->peragg;(gdb)1971firstSlot=aggstate->ss.ss_ScanTupleSlot;(gdb)1977perhash=&aggstate->perhash[aggstate->current_set];(gdb)1983while(!aggstate->agg_done)(gdb)p*peragg$2={aggref=0x293a458,transno=0,finalfn_oid=0,finalfn={fn_addr=0x0,fn_oid=0,fn_nargs=0,fn_strict=false,fn_retset=false,fn_stats=0'\000',fn_extra=0x0,fn_mcxt=0x0,fn_expr=0x0},numFinalArgs=1,aggdirectargs=0x0,resulttypeLen=4,resulttypeByVal=true,shareable=true}(gdb)p*peragg->aggref$3={xpr={type=T_Aggref},aggfnoid=2116,aggtype=23,aggcollid=0,inputcollid=0,aggtranstype=23,aggargtypes=0x293a518,aggdirectargs=0x0,args=0x293a628,aggorder=0x0,aggdistinct=0x0,aggfilter=0x0,aggstar=false,aggvariadic=false,aggkind=110'n',agglevelsup=0,aggsplit=AGGSPLIT_SIMPLE,location=26}(gdb)p*perhash$4={hashtable=0x2946890,hashiter={cur=0,end=0,done=false},hashslot=0x292b238,hashfunctions=0x292b2d0,eqfuncoids=0x2946700,numCols=1,numhashGrpCols=1,largestGrpColIdx=1,hashGrpColIdxInput=0x2946660,hashGrpColIdxHash=0x2946680,aggnode=0x2849a30}(gdb)paggstate->current_set$5=0(gdb)

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

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

2.2调用ScanTupleHashTable获取条目

(gdb)n1993entry=ScanTupleHashTable(perhash->hashtable,&perhash->hashiter);(gdb)pperhash->hashiter$7={cur=0,end=0,done=false}(gdb)steptuplehash_iterate(tb=0x2946720,iter=0x292af58)at../../../src/include/lib/simplehash.h:829829while(!iter->done)(gdb)n833elem=&tb->data[iter->cur];(gdb)p*tb$8={size=256,members=5,sizemask=255,grow_threshold=230,data=0x2950a00,ctx=0x2929310,private_data=0x2946890}(gdb)p*tb->data$9={firstTuple=0x0,additional=0x0,status=0,hash=0}(gdb)p*iter$10={cur=0,end=0,done=false}(gdb)n836iter->cur=(iter->cur-1)&tb->sizemask;(gdb)n838if((iter->cur&tb->sizemask)==(iter->end&tb->sizemask))(gdb)piter->cur$11=255(gdb)$12=255(gdb)piter->cur&tb->sizemask$13=255(gdb)piter->end&tb->sizemask$14=0(gdb)n840if(elem->status==SH_STATUS_IN_USE)(gdb)p*elem$15={firstTuple=0x0,additional=0x0,status=0,hash=0}(gdb)n829while(!iter->done)(gdb)833elem=&tb->data[iter->cur];(gdb)836iter->cur=(iter->cur-1)&tb->sizemask;(gdb)838if((iter->cur&tb->sizemask)==(iter->end&tb->sizemask))(gdb)840if(elem->status==SH_STATUS_IN_USE)(gdb)829while(!iter->done)(gdb)finishRuntillexitfrom#0tuplehash_iterate(tb=0x2946720,iter=0x292af58)at../../../src/include/lib/simplehash.h:8290x00000000006eed70inagg_retrieve_hash_table(aggstate=0x2929640)atnodeAgg.c:19931993entry=ScanTupleHashTable(perhash->hashtable,&perhash->hashiter);Valuereturnedis$16=(TupleHashEntryData*)0x2951d08(gdb)

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

(gdb)n1994if(entry==NULL)(gdb)2027ResetExprContext(econtext);(gdb)2033ExecStoreMinimalTuple(entry->firstTuple,hashslot,false);(gdb)2034slot_getallattrs(hashslot);(gdb)2036ExecClearTuple(firstSlot);(gdb)2038firstSlot->tts_tupleDescriptor->natts*sizeof(bool));(gdb)2037memset(firstSlot->tts_isnull,true,(gdb)2040for(i=0;i<perhash->numhashGrpCols;i++)(gdb)x/21xentry->firstTuple->t_bits0x2942a87:0x5a470b000x7f7e35300x7f7f7f7f0x7f7f7f7f0x2942a97:0x0000407f0x000000000x000030000x000000000x2942aa7:0x9425c0000x000000020x000005000x000000000x2942ab7:0x7f0000000x7f7f7f7f0x0000057f0x000000000x2942ac7:0x7f0000000x7f7f7f7f0x942b087f0x000000020x2942ad7:0x7f000000(gdb)x/21centry->firstTuple->t_bits0x2942a87:0'\000'11'\v'71'G'90'Z'48'0'53'5'126'~'127'\177'0x2942a8f:127'\177'127'\177'127'\177'127'\177'127'\177'127'\177'127'\177'127'\177'0x2942a97:127'\177'64'@'0'\000'0'\000'0'\000'(gdb)n2042intvarNumber=perhash->hashGrpColIdxInput[i]-1;(gdb)2044firstSlot->tts_values[varNumber]=hashslot->tts_values[i];(gdb)2045firstSlot->tts_isnull[varNumber]=hashslot->tts_isnull[i];(gdb)2040for(i=0;i<perhash->numhashGrpCols;i++)(gdb)2047ExecStoreVirtualTuple(firstSlot);(gdb)2049pergroup=(AggStatePerGroup)entry->additional;(gdb)p*entry$1={firstTuple=0x2942a78,additional=0x2942ab0,status=1,hash=1229618635}(gdb)p*entry->firstTuple$2={t_len=21,mt_padding="\000\000\000\000\000",t_infomask2=1,t_infomask=2,t_hoff=24'\030',t_bits=0x2942a87""}(gdb)

获取结果

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

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