PostgreSQL 聚合函数的实现教程
本篇内容主要讲解“PostgreSQL 聚合函数的实现教程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL 聚合函数的实现教程”吧!
一、数据结构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)二、源码解读
advance_aggregates函数最终会调用ExecInterpExpr函数(先前已介绍),通过一系列的步骤得到结果.
/**Advanceeachaggregatetransitionstateforoneinputtuple.Theinput*tuplehasbeenstoredintmpcontext->ecxt_outertuple,sothatitis*accessibletoExecEvalExpr.*为每一个输入tuple推进每个聚合转换状态.*输入元组已存储在tmpcontext->ecxt_outertuple中,因此可访问ExecEvalExpr.**Wehavetwosetsoftransitionstatestohandle:oneforsortedaggregation*andoneforhashed;wedothembothhere,toavoidmultipleevaluationof*theinputs.*我们有两个转换状态集合需要处理:一个是已排序聚合,一个是已哈希聚合.*在这里同时进行处理,以避免输入的多种解析.**Whencalled,CurrentMemoryContextshouldbetheper-querycontext.*一旦完成调用,CurrentMemoryContext应为per-query上下文.*/staticvoidadvance_aggregates(AggState*aggstate){booldummynull;ExecEvalExprSwitchContext(aggstate->phase->evaltrans,aggstate->tmpcontext,&dummynull);}/**ExecEvalExprSwitchContext**SameasExecEvalExpr,butgetintotherightallocationcontextexplicitly.*与ExecEvalExpr一样,只是显式的进入内存上下文.*/#ifndefFRONTENDstaticinlineDatumExecEvalExprSwitchContext(ExprState*state,ExprContext*econtext,bool*isNull){DatumretDatum;MemoryContextoldContext;oldContext=MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);retDatum=state->evalfunc(state,econtext,isNull);MemoryContextSwitchTo(oldContext);returnretDatum;}#endif/**Expressionevaluationcallbackthatperformsextrachecksbeforeexecuting*theexpression.Declaredexternsoothermethodsofexecutioncanuseit*too.*表达式解析回调函数,在执行表达式解析前执行额外的检查.*声明为extern以便其他方法可以使用.*/DatumExecInterpExprStillValid(ExprState*state,ExprContext*econtext,bool*isNull){/**Firsttimethrough,checkwhetherattributematchesVar.Mightnotbe*okanymore,duetoschemachanges.*第一次,需检查属性是否与Var匹配.*由于模式的变化,有可能会出问题.*/CheckExprStillValid(state,econtext);/*skipthecheckduringfurtherexecutions*///在后续的执行中,跳过检查.state->evalfunc=(ExprStateEvalFunc)state->evalfunc_private;/*andactuallyexecute*///执行解析函数,获取结果returnstate->evalfunc(state,econtext,isNull);}//evalfunc_private-->ExecInterpExpr
ExecInterpExpr
解析给定”econtext”在执行上下文中通过”state”标识的表达式.
//evalfunc_private-->ExecInterpExpr/**Evaluateexpressionidentifiedby"state"intheexecutioncontext*givenby"econtext".*isnullissettotheis-nullflagfortheresult,*andtheDatumvalueisthefunctionresult.*解析给定"econtext"在执行上下文中通过"state"标识的表达式.**isnull用于设置结果是否为null,Datum是函数执行的结果.**Asaspecialcase,returnthedispatchtable'saddressifstateisNULL.*ThisisusedbyExecInitInterpretertosetupthedispatch_tableglobal.*(OnlyapplieswhenEEO_USE_COMPUTED_GOTOisdefined.)*作为一个特别的情况,如state为NULL,返回分发器表的地址.*这个情况用于ExecInitInterpreter配置dispatch_table.*(只是在定义了EEO_USE_COMPUTED_GOTO时才应用)*/staticDatumExecInterpExpr(ExprState*state,ExprContext*econtext,bool*isnull){ExprEvalStep*op;TupleTableSlot*resultslot;TupleTableSlot*innerslot;TupleTableSlot*outerslot;TupleTableSlot*scanslot;/**ThisarrayhastobeinthesameorderasenumExprEvalOp.*该数组在枚举类型ExprEvalOp中具有同样的顺序*/#ifdefined(EEO_USE_COMPUTED_GOTO)staticconstvoid*constdispatch_table[]={&&CASE_EEOP_DONE,&&CASE_EEOP_INNER_FETCHSOME,&&CASE_EEOP_OUTER_FETCHSOME,&&CASE_EEOP_SCAN_FETCHSOME,&&CASE_EEOP_INNER_VAR,&&CASE_EEOP_OUTER_VAR,&&CASE_EEOP_SCAN_VAR,&&CASE_EEOP_INNER_SYSVAR,&&CASE_EEOP_OUTER_SYSVAR,&&CASE_EEOP_SCAN_SYSVAR,&&CASE_EEOP_WHOLEROW,&&CASE_EEOP_ASSIGN_INNER_VAR,&&CASE_EEOP_ASSIGN_OUTER_VAR,&&CASE_EEOP_ASSIGN_SCAN_VAR,&&CASE_EEOP_ASSIGN_TMP,&&CASE_EEOP_ASSIGN_TMP_MAKE_RO,&&CASE_EEOP_CONST,&&CASE_EEOP_FUNCEXPR,&&CASE_EEOP_FUNCEXPR_STRICT,&&CASE_EEOP_FUNCEXPR_FUSAGE,&&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,&&CASE_EEOP_BOOL_AND_STEP_FIRST,&&CASE_EEOP_BOOL_AND_STEP,&&CASE_EEOP_BOOL_AND_STEP_LAST,&&CASE_EEOP_BOOL_OR_STEP_FIRST,&&CASE_EEOP_BOOL_OR_STEP,&&CASE_EEOP_BOOL_OR_STEP_LAST,&&CASE_EEOP_BOOL_NOT_STEP,&&CASE_EEOP_QUAL,&&CASE_EEOP_JUMP,&&CASE_EEOP_JUMP_IF_NULL,&&CASE_EEOP_JUMP_IF_NOT_NULL,&&CASE_EEOP_JUMP_IF_NOT_TRUE,&&CASE_EEOP_NULLTEST_ISNULL,&&CASE_EEOP_NULLTEST_ISNOTNULL,&&CASE_EEOP_NULLTEST_ROWISNULL,&&CASE_EEOP_NULLTEST_ROWISNOTNULL,&&CASE_EEOP_BOOLTEST_IS_TRUE,&&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,&&CASE_EEOP_BOOLTEST_IS_FALSE,&&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,&&CASE_EEOP_PARAM_EXEC,&&CASE_EEOP_PARAM_EXTERN,&&CASE_EEOP_PARAM_CALLBACK,&&CASE_EEOP_CASE_TESTVAL,&&CASE_EEOP_MAKE_READONLY,&&CASE_EEOP_IOCOERCE,&&CASE_EEOP_DISTINCT,&&CASE_EEOP_NOT_DISTINCT,&&CASE_EEOP_NULLIF,&&CASE_EEOP_SQLVALUEFUNCTION,&&CASE_EEOP_CURRENTOFEXPR,&&CASE_EEOP_NEXTVALUEEXPR,&&CASE_EEOP_ARRAYEXPR,&&CASE_EEOP_ARRAYCOERCE,&&CASE_EEOP_ROW,&&CASE_EEOP_ROWCOMPARE_STEP,&&CASE_EEOP_ROWCOMPARE_FINAL,&&CASE_EEOP_MINMAX,&&CASE_EEOP_FIELDSELECT,&&CASE_EEOP_FIELDSTORE_DEFORM,&&CASE_EEOP_FIELDSTORE_FORM,&&CASE_EEOP_ARRAYREF_SUBSCRIPT,&&CASE_EEOP_ARRAYREF_OLD,&&CASE_EEOP_ARRAYREF_ASSIGN,&&CASE_EEOP_ARRAYREF_FETCH,&&CASE_EEOP_DOMAIN_TESTVAL,&&CASE_EEOP_DOMAIN_NOTNULL,&&CASE_EEOP_DOMAIN_CHECK,&&CASE_EEOP_CONVERT_ROWTYPE,&&CASE_EEOP_SCALARARRAYOP,&&CASE_EEOP_XMLEXPR,&&CASE_EEOP_AGGREF,&&CASE_EEOP_GROUPING_FUNC,&&CASE_EEOP_WINDOW_FUNC,&&CASE_EEOP_SUBPLAN,&&CASE_EEOP_ALTERNATIVE_SUBPLAN,&&CASE_EEOP_AGG_STRICT_DESERIALIZE,&&CASE_EEOP_AGG_DESERIALIZE,&&CASE_EEOP_AGG_STRICT_INPUT_CHECK,&&CASE_EEOP_AGG_INIT_TRANS,&&CASE_EEOP_AGG_STRICT_TRANS_CHECK,&&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,&&CASE_EEOP_AGG_PLAIN_TRANS,&&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,&&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,&&CASE_EEOP_LAST};StaticAssertStmt(EEOP_LAST+1==lengthof(dispatch_table),"dispatch_tableoutofwhackwithExprEvalOp");if(unlikely(state==NULL))//如state==NULL,则调用PointerGetDatumreturnPointerGetDatum(dispatch_table);#elseAssert(state!=NULL);#endif/*EEO_USE_COMPUTED_GOTO*//*setupstate*///配置状态变量op=state->steps;resultslot=state->resultslot;innerslot=econtext->ecxt_innertuple;outerslot=econtext->ecxt_outertuple;scanslot=econtext->ecxt_scantuple;#ifdefined(EEO_USE_COMPUTED_GOTO)EEO_DISPATCH();//分发#endifEEO_SWITCH(){EEO_CASE(EEOP_DONE){gotoout;}EEO_CASE(EEOP_INNER_FETCHSOME){/*XXX:worthwhiletochecktts_nvalidinlinefirst?*/slot_getsomeattrs(innerslot,op->d.fetch.last_var);EEO_NEXT();}EEO_CASE(EEOP_OUTER_FETCHSOME){slot_getsomeattrs(outerslot,op->d.fetch.last_var);EEO_NEXT();}EEO_CASE(EEOP_SCAN_FETCHSOME){slot_getsomeattrs(scanslot,op->d.fetch.last_var);EEO_NEXT();}EEO_CASE(EEOP_INNER_VAR){intattnum=op->d.var.attnum;/**Sincewealreadyextractedallreferencedcolumnsfromthe*tuplewithaFETCHSOMEstep,wecanjustgrabthevalue*directlyoutoftheslot'sdecomposed-dataarrays.Butlet's*haveanAsserttocheckthatthatdidhappen.*/Assert(attnum>=0&&attnum<innerslot->tts_nvalid);*op->resvalue=innerslot->tts_values[attnum];*op->resnull=innerslot->tts_isnull[attnum];EEO_NEXT();}EEO_CASE(EEOP_OUTER_VAR){intattnum=op->d.var.attnum;/*SeeEEOP_INNER_VARcomments*/Assert(attnum>=0&&attnum<outerslot->tts_nvalid);*op->resvalue=outerslot->tts_values[attnum];*op->resnull=outerslot->tts_isnull[attnum];EEO_NEXT();}EEO_CASE(EEOP_SCAN_VAR){intattnum=op->d.var.attnum;/*SeeEEOP_INNER_VARcomments*/Assert(attnum>=0&&attnum<scanslot->tts_nvalid);*op->resvalue=scanslot->tts_values[attnum];*op->resnull=scanslot->tts_isnull[attnum];EEO_NEXT();}EEO_CASE(EEOP_INNER_SYSVAR){intattnum=op->d.var.attnum;Datumd;/*theseassertsmustmatchdefensesinslot_getattr*/Assert(innerslot->tts_tuple!=NULL);Assert(innerslot->tts_tuple!=&(innerslot->tts_minhdr));/*heap_getsysattrhassufficientdefensesagainstbadattnums*/d=heap_getsysattr(innerslot->tts_tuple,attnum,innerslot->tts_tupleDescriptor,op->resnull);*op->resvalue=d;EEO_NEXT();}EEO_CASE(EEOP_OUTER_SYSVAR){intattnum=op->d.var.attnum;Datumd;/*theseassertsmustmatchdefensesinslot_getattr*/Assert(outerslot->tts_tuple!=NULL);Assert(outerslot->tts_tuple!=&(outerslot->tts_minhdr));/*heap_getsysattrhassufficientdefensesagainstbadattnums*/d=heap_getsysattr(outerslot->tts_tuple,attnum,outerslot->tts_tupleDescriptor,op->resnull);*op->resvalue=d;EEO_NEXT();}EEO_CASE(EEOP_SCAN_SYSVAR){intattnum=op->d.var.attnum;Datumd;/*theseassertsmustmatchdefensesinslot_getattr*/Assert(scanslot->tts_tuple!=NULL);Assert(scanslot->tts_tuple!=&(scanslot->tts_minhdr));/*heap_getsysattrhassufficientdefensesagainstbadattnums*/d=heap_getsysattr(scanslot->tts_tuple,attnum,scanslot->tts_tupleDescriptor,op->resnull);*op->resvalue=d;EEO_NEXT();}EEO_CASE(EEOP_WHOLEROW){/*toocomplexforaninlineimplementation*/ExecEvalWholeRowVar(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_ASSIGN_INNER_VAR){intresultnum=op->d.assign_var.resultnum;intattnum=op->d.assign_var.attnum;/**WedonotneedCheckVarSlotCompatibilityhere;thatwastaken*careofatcompilationtime.ButseeEEOP_INNER_VARcomments.*/Assert(attnum>=0&&attnum<innerslot->tts_nvalid);resultslot->tts_values[resultnum]=innerslot->tts_values[attnum];resultslot->tts_isnull[resultnum]=innerslot->tts_isnull[attnum];EEO_NEXT();}EEO_CASE(EEOP_ASSIGN_OUTER_VAR){intresultnum=op->d.assign_var.resultnum;intattnum=op->d.assign_var.attnum;/**WedonotneedCheckVarSlotCompatibilityhere;thatwastaken*careofatcompilationtime.ButseeEEOP_INNER_VARcomments.*/Assert(attnum>=0&&attnum<outerslot->tts_nvalid);resultslot->tts_values[resultnum]=outerslot->tts_values[attnum];resultslot->tts_isnull[resultnum]=outerslot->tts_isnull[attnum];EEO_NEXT();}EEO_CASE(EEOP_ASSIGN_SCAN_VAR){intresultnum=op->d.assign_var.resultnum;intattnum=op->d.assign_var.attnum;/**WedonotneedCheckVarSlotCompatibilityhere;thatwastaken*careofatcompilationtime.ButseeEEOP_INNER_VARcomments.*/Assert(attnum>=0&&attnum<scanslot->tts_nvalid);resultslot->tts_values[resultnum]=scanslot->tts_values[attnum];resultslot->tts_isnull[resultnum]=scanslot->tts_isnull[attnum];EEO_NEXT();}EEO_CASE(EEOP_ASSIGN_TMP){intresultnum=op->d.assign_tmp.resultnum;resultslot->tts_values[resultnum]=state->resvalue;resultslot->tts_isnull[resultnum]=state->resnull;EEO_NEXT();}EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO){intresultnum=op->d.assign_tmp.resultnum;resultslot->tts_isnull[resultnum]=state->resnull;if(!resultslot->tts_isnull[resultnum])resultslot->tts_values[resultnum]=MakeExpandedObjectReadOnlyInternal(state->resvalue);elseresultslot->tts_values[resultnum]=state->resvalue;EEO_NEXT();}EEO_CASE(EEOP_CONST){*op->resnull=op->d.constval.isnull;*op->resvalue=op->d.constval.value;EEO_NEXT();}/**Function-callimplementations.Argumentshavepreviouslybeen*evaluateddirectlyintofcinfo->args.**AsbothSTRICTchecksandfunction-usagearenoticeableperformance*wise,andfunctioncallsareaveryhot-path(theyalsoback*operators!),it'sworthhavingsomanyseparateopcodes.**Note:thereasonforusingatemporaryvariable"d",hereandin*otherplaces,isthatsomecompilersthink"*op->resvalue=f();"*requiresthemtoevaluateop->resvalueintoaregisterbefore*callingf(),justincasef()isabletomodifyop->resvalue*somehow.Theextralineofcodecansaveauselessregisterspill*andreloadacrossthefunctioncall.*/EEO_CASE(EEOP_FUNCEXPR){FunctionCallInfofcinfo=op->d.func.fcinfo_data;Datumd;fcinfo->isnull=false;d=op->d.func.fn_addr(fcinfo);*op->resvalue=d;*op->resnull=fcinfo->isnull;EEO_NEXT();}EEO_CASE(EEOP_FUNCEXPR_STRICT){FunctionCallInfofcinfo=op->d.func.fcinfo_data;bool*argnull=fcinfo->argnull;intargno;Datumd;/*strictfunction,socheckforNULLargs*/for(argno=0;argno<op->d.func.nargs;argno++){if(argnull[argno]){*op->resnull=true;gotostrictfail;}}fcinfo->isnull=false;d=op->d.func.fn_addr(fcinfo);*op->resvalue=d;*op->resnull=fcinfo->isnull;strictfail:EEO_NEXT();}EEO_CASE(EEOP_FUNCEXPR_FUSAGE){/*notcommonenoughtoinline*/ExecEvalFuncExprFusage(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE){/*notcommonenoughtoinline*/ExecEvalFuncExprStrictFusage(state,op,econtext);EEO_NEXT();}/**IfanyofitsclausesisFALSE,anAND'sresultisFALSEregardless*ofthestatesoftherestoftheclauses,sowecanstopevaluating*andreturnFALSEimmediately.IfnoneareFALSEandoneormoreis*NULL,wereturnNULL;otherwisewereturnTRUE.Thismakessense*whenyouinterpretNULLas"don'tknow":perhapsoneofthe"don't*knows"wouldhavebeenFALSEifwe'dknownitsvalue.Onlywhen*alltheinputsareknowntobeTRUEcanwestateconfidentlythat*theAND'sresultisTRUE.*/EEO_CASE(EEOP_BOOL_AND_STEP_FIRST){*op->d.boolexpr.anynull=false;/**EEOP_BOOL_AND_STEP_FIRSTresetsanynull,otherwiseit'sthe*sameasEEOP_BOOL_AND_STEP-sofallthroughtothat.*//*FALLTHROUGH*/}EEO_CASE(EEOP_BOOL_AND_STEP){if(*op->resnull){*op->d.boolexpr.anynull=true;}elseif(!DatumGetBool(*op->resvalue)){/*resultisalreadysettoFALSE,neednotchangeit*//*bailoutearly*/EEO_JUMP(op->d.boolexpr.jumpdone);}EEO_NEXT();}EEO_CASE(EEOP_BOOL_AND_STEP_LAST){if(*op->resnull){/*resultisalreadysettoNULL,neednotchangeit*/}elseif(!DatumGetBool(*op->resvalue)){/*resultisalreadysettoFALSE,neednotchangeit*//**Nopointjumpingearlytojumpdone-wouldbesametarget*(asthisisthelastargumenttotheANDexpression),*exceptmoreexpensive.*/}elseif(*op->d.boolexpr.anynull){*op->resvalue=(Datum)0;*op->resnull=true;}else{/*resultisalreadysettoTRUE,neednotchangeit*/}EEO_NEXT();}/**IfanyofitsclausesisTRUE,anOR'sresultisTRUEregardlessof*thestatesoftherestoftheclauses,sowecanstopevaluating*andreturnTRUEimmediately.IfnoneareTRUEandoneormoreis*NULL,wereturnNULL;otherwisewereturnFALSE.Thismakessense*whenyouinterpretNULLas"don'tknow":perhapsoneofthe"don't*knows"wouldhavebeenTRUEifwe'dknownitsvalue.Onlywhenall*theinputsareknowntobeFALSEcanwestateconfidentlythatthe*OR'sresultisFALSE.*/EEO_CASE(EEOP_BOOL_OR_STEP_FIRST){*op->d.boolexpr.anynull=false;/**EEOP_BOOL_OR_STEP_FIRSTresetsanynull,otherwiseit'sthesame*asEEOP_BOOL_OR_STEP-sofallthroughtothat.*//*FALLTHROUGH*/}EEO_CASE(EEOP_BOOL_OR_STEP){if(*op->resnull){*op->d.boolexpr.anynull=true;}elseif(DatumGetBool(*op->resvalue)){/*resultisalreadysettoTRUE,neednotchangeit*//*bailoutearly*/EEO_JUMP(op->d.boolexpr.jumpdone);}EEO_NEXT();}EEO_CASE(EEOP_BOOL_OR_STEP_LAST){if(*op->resnull){/*resultisalreadysettoNULL,neednotchangeit*/}elseif(DatumGetBool(*op->resvalue)){/*resultisalreadysettoTRUE,neednotchangeit*//**Nopointjumpingtojumpdone-wouldbesametarget(as*thisisthelastargumenttotheANDexpression),except*moreexpensive.*/}elseif(*op->d.boolexpr.anynull){*op->resvalue=(Datum)0;*op->resnull=true;}else{/*resultisalreadysettoFALSE,neednotchangeit*/}EEO_NEXT();}EEO_CASE(EEOP_BOOL_NOT_STEP){/**Evaluationof'not'issimple...ifexprisfalse,thenreturn*'true'andviceversa.It'ssafetodothisevenona*nominallynullvalue,soweignoreresnull;thatmeansthat*NULLinproducesNULLout,whichiswhatwewant.*/*op->resvalue=BoolGetDatum(!DatumGetBool(*op->resvalue));EEO_NEXT();}EEO_CASE(EEOP_QUAL){/*simplifiedversionofBOOL_AND_STEPforusebyExecQual()*//*Ifargument(alsoresult)isfalseornull...*/if(*op->resnull||!DatumGetBool(*op->resvalue)){/*...bailoutearly,returningFALSE*/*op->resnull=false;*op->resvalue=BoolGetDatum(false);EEO_JUMP(op->d.qualexpr.jumpdone);}/**Otherwise,leavetheTRUEvalueinplace,incasethisisthe*lastqual.Then,TRUEisthecorrectanswer.*/EEO_NEXT();}EEO_CASE(EEOP_JUMP){/*Unconditionallyjumptotargetstep*/EEO_JUMP(op->d.jump.jumpdone);}EEO_CASE(EEOP_JUMP_IF_NULL){/*Transfercontrolifcurrentresultisnull*/if(*op->resnull)EEO_JUMP(op->d.jump.jumpdone);EEO_NEXT();}EEO_CASE(EEOP_JUMP_IF_NOT_NULL){/*Transfercontrolifcurrentresultisnon-null*/if(!*op->resnull)EEO_JUMP(op->d.jump.jumpdone);EEO_NEXT();}EEO_CASE(EEOP_JUMP_IF_NOT_TRUE){/*Transfercontrolifcurrentresultisnullorfalse*/if(*op->resnull||!DatumGetBool(*op->resvalue))EEO_JUMP(op->d.jump.jumpdone);EEO_NEXT();}EEO_CASE(EEOP_NULLTEST_ISNULL){*op->resvalue=BoolGetDatum(*op->resnull);*op->resnull=false;EEO_NEXT();}EEO_CASE(EEOP_NULLTEST_ISNOTNULL){*op->resvalue=BoolGetDatum(!*op->resnull);*op->resnull=false;EEO_NEXT();}EEO_CASE(EEOP_NULLTEST_ROWISNULL){/*outoflineimplementation:toolarge*/ExecEvalRowNull(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL){/*outoflineimplementation:toolarge*/ExecEvalRowNotNull(state,op,econtext);EEO_NEXT();}/*BooleanTestimplementationsforallbooltesttypes*/EEO_CASE(EEOP_BOOLTEST_IS_TRUE){if(*op->resnull){*op->resvalue=BoolGetDatum(false);*op->resnull=false;}/*else,inputvalueisthecorrectoutputaswell*/EEO_NEXT();}EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE){if(*op->resnull){*op->resvalue=BoolGetDatum(true);*op->resnull=false;}else*op->resvalue=BoolGetDatum(!DatumGetBool(*op->resvalue));EEO_NEXT();}EEO_CASE(EEOP_BOOLTEST_IS_FALSE){if(*op->resnull){*op->resvalue=BoolGetDatum(false);*op->resnull=false;}else*op->resvalue=BoolGetDatum(!DatumGetBool(*op->resvalue));EEO_NEXT();}EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE){if(*op->resnull){*op->resvalue=BoolGetDatum(true);*op->resnull=false;}/*else,inputvalueisthecorrectoutputaswell*/EEO_NEXT();}EEO_CASE(EEOP_PARAM_EXEC){/*outoflineimplementation:toolarge*/ExecEvalParamExec(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_PARAM_EXTERN){/*outoflineimplementation:toolarge*/ExecEvalParamExtern(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_PARAM_CALLBACK){/*allowanextensionmoduletosupplyaPARAM_EXTERNvalue*/op->d.cparam.paramfunc(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_CASE_TESTVAL){/**Normallyupperpartsoftheexpressiontreehavesetupthe*valuestobereturnedhere,butsomepartsofthesystem*currentlymisuse{caseValue,domainValue}_{datum,isNull}toset*run-timedata.Soifnovalueshavebeenset-up,use*ExprContext's.Thisisn'tpretty,butalsonot*that*ugly,*andthisisunlikelytobeperformancesensitiveenoughto*worryaboutanextrabranch.*/if(op->d.casetest.value){*op->resvalue=*op->d.casetest.value;*op->resnull=*op->d.casetest.isnull;}else{*op->resvalue=econtext->caseValue_datum;*op->resnull=econtext->caseValue_isNull;}EEO_NEXT();}EEO_CASE(EEOP_DOMAIN_TESTVAL){/**SeeEEOP_CASE_TESTVALcomment.*/if(op->d.casetest.value){*op->resvalue=*op->d.casetest.value;*op->resnull=*op->d.casetest.isnull;}else{*op->resvalue=econtext->domainValue_datum;*op->resnull=econtext->domainValue_isNull;}EEO_NEXT();}EEO_CASE(EEOP_MAKE_READONLY){/**ForceavarlenavaluethatmightbereadmultipletimestoR/O*/if(!*op->d.make_readonly.isnull)*op->resvalue=MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);*op->resnull=*op->d.make_readonly.isnull;EEO_NEXT();}EEO_CASE(EEOP_IOCOERCE){/**EvaluateaCoerceViaIOnode.Thiscanbequiteahotpath,so*inlineasmuchworkaspossible.Thesourcevalueisinour*resultvariable.*/char*str;/*calloutputfunction(similartoOutputFunctionCall)*/if(*op->resnull){/*outputfunctionsarenotcalledonnulls*/str=NULL;}else{FunctionCallInfofcinfo_out;fcinfo_out=op->d.iocoerce.fcinfo_data_out;fcinfo_out->arg[0]=*op->resvalue;fcinfo_out->argnull[0]=false;fcinfo_out->isnull=false;str=DatumGetCString(FunctionCallInvoke(fcinfo_out));/*OutputFunctionCallassumesresultisn'tnull*/Assert(!fcinfo_out->isnull);}/*callinputfunction(similartoInputFunctionCall)*/if(!op->d.iocoerce.finfo_in->fn_strict||str!=NULL){FunctionCallInfofcinfo_in;Datumd;fcinfo_in=op->d.iocoerce.fcinfo_data_in;fcinfo_in->arg[0]=PointerGetDatum(str);fcinfo_in->argnull[0]=*op->resnull;/*secondandthirdargumentsarealreadysetup*/fcinfo_in->isnull=false;d=FunctionCallInvoke(fcinfo_in);*op->resvalue=d;/*ShouldgetnullresultifandonlyifstrisNULL*/if(str==NULL){Assert(*op->resnull);Assert(fcinfo_in->isnull);}else{Assert(!*op->resnull);Assert(!fcinfo_in->isnull);}}EEO_NEXT();}EEO_CASE(EEOP_DISTINCT){/**ISDISTINCTFROMmustevaluatearguments(alreadydoneinto*fcinfo->arg/argnull)todeterminewhethertheyareNULL;if*eitherisNULLthentheresultisdetermined.Ifneitheris*NULL,thenproceedtoevaluatethecomparisonfunction,which*isjustthetype'sstandardequalityoperator.Weneednot*carewhetherthatfunctionisstrict.Becausethehandlingof*nullsisdifferent,wecan'tjustreuseEEOP_FUNCEXPR.*/FunctionCallInfofcinfo=op->d.func.fcinfo_data;/*checkfunctionargumentsforNULLness*/if(fcinfo->argnull[0]&&fcinfo->argnull[1]){/*BothNULL?Thenisnotdistinct...*/*op->resvalue=BoolGetDatum(false);*op->resnull=false;}elseif(fcinfo->argnull[0]||fcinfo->argnull[1]){/*OnlyoneisNULL?Thenisdistinct...*/*op->resvalue=BoolGetDatum(true);*op->resnull=false;}else{/*Neithernull,soapplytheequalityfunction*/Datumeqresult;fcinfo->isnull=false;eqresult=op->d.func.fn_addr(fcinfo);/*Mustinvertresultof"=";safetodoevenifnull*/*op->resvalue=BoolGetDatum(!DatumGetBool(eqresult));*op->resnull=fcinfo->isnull;}EEO_NEXT();}/*seeEEOP_DISTINCTforcomments,thisisjustinverted*/EEO_CASE(EEOP_NOT_DISTINCT){FunctionCallInfofcinfo=op->d.func.fcinfo_data;if(fcinfo->argnull[0]&&fcinfo->argnull[1]){*op->resvalue=BoolGetDatum(true);*op->resnull=false;}elseif(fcinfo->argnull[0]||fcinfo->argnull[1]){*op->resvalue=BoolGetDatum(false);*op->resnull=false;}else{Datumeqresult;fcinfo->isnull=false;eqresult=op->d.func.fn_addr(fcinfo);*op->resvalue=eqresult;*op->resnull=fcinfo->isnull;}EEO_NEXT();}EEO_CASE(EEOP_NULLIF){/**Theargumentsarealreadyevaluatedintofcinfo->arg/argnull.*/FunctionCallInfofcinfo=op->d.func.fcinfo_data;/*ifeitherargumentisNULLtheycan'tbeequal*/if(!fcinfo->argnull[0]&&!fcinfo->argnull[1]){Datumresult;fcinfo->isnull=false;result=op->d.func.fn_addr(fcinfo);/*iftheargumentsareequalreturnnull*/if(!fcinfo->isnull&&DatumGetBool(result)){*op->resvalue=(Datum)0;*op->resnull=true;EEO_NEXT();}}/*Argumentsaren'tequal,soreturnthefirstone*/*op->resvalue=fcinfo->arg[0];*op->resnull=fcinfo->argnull[0];EEO_NEXT();}EEO_CASE(EEOP_SQLVALUEFUNCTION){/**Doesn'tseemworthwhiletohaveaninlineimplementation*efficiency-wise.*/ExecEvalSQLValueFunction(state,op);EEO_NEXT();}EEO_CASE(EEOP_CURRENTOFEXPR){/*errorinvocationusesspace,andshouldn'teveroccur*/ExecEvalCurrentOfExpr(state,op);EEO_NEXT();}EEO_CASE(EEOP_NEXTVALUEEXPR){/**Doesn'tseemworthwhiletohaveaninlineimplementation*efficiency-wise.*/ExecEvalNextValueExpr(state,op);EEO_NEXT();}EEO_CASE(EEOP_ARRAYEXPR){/*toocomplexforaninlineimplementation*/ExecEvalArrayExpr(state,op);EEO_NEXT();}EEO_CASE(EEOP_ARRAYCOERCE){/*toocomplexforaninlineimplementation*/ExecEvalArrayCoerce(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_ROW){/*toocomplexforaninlineimplementation*/ExecEvalRow(state,op);EEO_NEXT();}EEO_CASE(EEOP_ROWCOMPARE_STEP){FunctionCallInfofcinfo=op->d.rowcompare_step.fcinfo_data;Datumd;/*forceNULLresultifstrictfnandNULLinput*/if(op->d.rowcompare_step.finfo->fn_strict&&(fcinfo->argnull[0]||fcinfo->argnull[1])){*op->resnull=true;EEO_JUMP(op->d.rowcompare_step.jumpnull);}/*Applycomparisonfunction*/fcinfo->isnull=false;d=op->d.rowcompare_step.fn_addr(fcinfo);*op->resvalue=d;/*forceNULLresultifNULLfunctionresult*/if(fcinfo->isnull){*op->resnull=true;EEO_JUMP(op->d.rowcompare_step.jumpnull);}*op->resnull=false;/*Ifunequal,noneedtocompareremainingcolumns*/if(DatumGetInt32(*op->resvalue)!=0){EEO_JUMP(op->d.rowcompare_step.jumpdone);}EEO_NEXT();}EEO_CASE(EEOP_ROWCOMPARE_FINAL){int32cmpresult=DatumGetInt32(*op->resvalue);RowCompareTyperctype=op->d.rowcompare_final.rctype;*op->resnull=false;switch(rctype){/*EQandNEcasesaren'tallowedhere*/caseROWCOMPARE_LT:*op->resvalue=BoolGetDatum(cmpresult<0);break;caseROWCOMPARE_LE:*op->resvalue=BoolGetDatum(cmpresult<=0);break;caseROWCOMPARE_GE:*op->resvalue=BoolGetDatum(cmpresult>=0);break;caseROWCOMPARE_GT:*op->resvalue=BoolGetDatum(cmpresult>0);break;default:Assert(false);break;}EEO_NEXT();}EEO_CASE(EEOP_MINMAX){/*toocomplexforaninlineimplementation*/ExecEvalMinMax(state,op);EEO_NEXT();}EEO_CASE(EEOP_FIELDSELECT){/*toocomplexforaninlineimplementation*/ExecEvalFieldSelect(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_FIELDSTORE_DEFORM){/*toocomplexforaninlineimplementation*/ExecEvalFieldStoreDeForm(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_FIELDSTORE_FORM){/*toocomplexforaninlineimplementation*/ExecEvalFieldStoreForm(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT){/*Processanarraysubscript*//*toocomplexforaninlineimplementation*/if(ExecEvalArrayRefSubscript(state,op)){EEO_NEXT();}else{/*Subscriptisnull,short-circuitArrayReftoNULL*/EEO_JUMP(op->d.arrayref_subscript.jumpdone);}}EEO_CASE(EEOP_ARRAYREF_OLD){/**Fetchtheoldvalueinanarrayrefassignment,incaseit's*referenced(viaaCaseTestExpr)insidetheassignment*expression.*//*toocomplexforaninlineimplementation*/ExecEvalArrayRefOld(state,op);EEO_NEXT();}/**PerformArrayRefassignment*/EEO_CASE(EEOP_ARRAYREF_ASSIGN){/*toocomplexforaninlineimplementation*/ExecEvalArrayRefAssign(state,op);EEO_NEXT();}/**Fetchsubsetofanarray.*/EEO_CASE(EEOP_ARRAYREF_FETCH){/*toocomplexforaninlineimplementation*/ExecEvalArrayRefFetch(state,op);EEO_NEXT();}EEO_CASE(EEOP_CONVERT_ROWTYPE){/*toocomplexforaninlineimplementation*/ExecEvalConvertRowtype(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_SCALARARRAYOP){/*toocomplexforaninlineimplementation*/ExecEvalScalarArrayOp(state,op);EEO_NEXT();}EEO_CASE(EEOP_DOMAIN_NOTNULL){/*toocomplexforaninlineimplementation*/ExecEvalConstraintNotNull(state,op);EEO_NEXT();}EEO_CASE(EEOP_DOMAIN_CHECK){/*toocomplexforaninlineimplementation*/ExecEvalConstraintCheck(state,op);EEO_NEXT();}EEO_CASE(EEOP_XMLEXPR){/*toocomplexforaninlineimplementation*/ExecEvalXmlExpr(state,op);EEO_NEXT();}EEO_CASE(EEOP_AGGREF){/**ReturnsaDatumwhosevalueistheprecomputedaggregatevalue*foundinthegivenexpressioncontext.*/AggrefExprState*aggref=op->d.aggref.astate;Assert(econtext->ecxt_aggvalues!=NULL);*op->resvalue=econtext->ecxt_aggvalues[aggref->aggno];*op->resnull=econtext->ecxt_aggnulls[aggref->aggno];EEO_NEXT();}EEO_CASE(EEOP_GROUPING_FUNC){/*toocomplex/uncommonforaninlineimplementation*/ExecEvalGroupingFunc(state,op);EEO_NEXT();}EEO_CASE(EEOP_WINDOW_FUNC){/**LikeAggref,justreturnaprecomputedvaluefromtheecontext.*/WindowFuncExprState*wfunc=op->d.window_func.wfstate;Assert(econtext->ecxt_aggvalues!=NULL);*op->resvalue=econtext->ecxt_aggvalues[wfunc->wfuncno];*op->resnull=econtext->ecxt_aggnulls[wfunc->wfuncno];EEO_NEXT();}EEO_CASE(EEOP_SUBPLAN){/*toocomplexforaninlineimplementation*/ExecEvalSubPlan(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN){/*toocomplexforaninlineimplementation*/ExecEvalAlternativeSubPlan(state,op,econtext);EEO_NEXT();}/*evaluateastrictaggregatedeserializationfunction*/EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE){bool*argnull=op->d.agg_deserialize.fcinfo_data->argnull;/*Don'tcallastrictdeserializationfunctionwithNULLinput*/if(argnull[0])EEO_JUMP(op->d.agg_deserialize.jumpnull);/*fallthrough*/}/*evaluateaggregatedeserializationfunction(non-strictportion)*/EEO_CASE(EEOP_AGG_DESERIALIZE){FunctionCallInfofcinfo=op->d.agg_deserialize.fcinfo_data;AggState*aggstate=op->d.agg_deserialize.aggstate;MemoryContextoldContext;/**Werunthedeserializationfunctionsinper-input-tuplememory*context.*/oldContext=MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);fcinfo->isnull=false;*op->resvalue=FunctionCallInvoke(fcinfo);*op->resnull=fcinfo->isnull;MemoryContextSwitchTo(oldContext);EEO_NEXT();}/**Checkthatastrictaggregatetransition/combinationfunction's*inputisnotNULL.*/EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK){intargno;bool*nulls=op->d.agg_strict_input_check.nulls;intnargs=op->d.agg_strict_input_check.nargs;for(argno=0;argno<nargs;argno++){if(nulls[argno])EEO_JUMP(op->d.agg_strict_input_check.jumpnull);}EEO_NEXT();}/**Initializeanaggregate'sfirstvalueifnecessary.*/EEO_CASE(EEOP_AGG_INIT_TRANS){AggState*aggstate;AggStatePerGrouppergroup;aggstate=op->d.agg_init_trans.aggstate;pergroup=&aggstate->all_pergroups[op->d.agg_init_trans.setoff][op->d.agg_init_trans.transno];/*IftransValuehasnotyetbeeninitialized,dosonow.*/if(pergroup->noTransValue){AggStatePerTranspertrans=op->d.agg_init_trans.pertrans;aggstate->curaggcontext=op->d.agg_init_trans.aggcontext;aggstate->current_set=op->d.agg_init_trans.setno;ExecAggInitGroup(aggstate,pertrans,pergroup);/*copiedtransvaluefrominput,donethisround*/EEO_JUMP(op->d.agg_init_trans.jumpnull);}EEO_NEXT();}/*checkthatastrictaggregate'sinputisn'tNULL*/EEO_CASE(EEOP_AGG_STRICT_TRANS_CHECK){AggState*aggstate;AggStatePerGrouppergroup;aggstate=op->d.agg_strict_trans_check.aggstate;pergroup=&aggstate->all_pergroups[op->d.agg_strict_trans_check.setoff][op->d.agg_strict_trans_check.transno];if(unlikely(pergroup->transValueIsNull))EEO_JUMP(op->d.agg_strict_trans_check.jumpnull);EEO_NEXT();}/**Evaluateaggregatetransition/combinefunctionthathasa*by-valuetransitiontype.That'saseperatecasefromthe*by-referenceimplementationbecauseit'sabitsimpler.*/EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL){AggState*aggstate;AggStatePerTranspertrans;AggStatePerGrouppergroup;FunctionCallInfofcinfo;MemoryContextoldContext;DatumnewVal;aggstate=op->d.agg_trans.aggstate;pertrans=op->d.agg_trans.pertrans;pergroup=&aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];Assert(pertrans->transtypeByVal);fcinfo=&pertrans->transfn_fcinfo;/*cf.select_current_set()*/aggstate->curaggcontext=op->d.agg_trans.aggcontext;aggstate->current_set=op->d.agg_trans.setno;/*setupaggstate->curpertransforAggGetAggref()*/aggstate->curpertrans=pertrans;/*invoketransitionfunctioninper-tuplecontext*/oldContext=MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);fcinfo->arg[0]=pergroup->transValue;fcinfo->argnull[0]=pergroup->transValueIsNull;fcinfo->isnull=false;/*justincasetransfndoesn'tsetit*/newVal=FunctionCallInvoke(fcinfo);pergroup->transValue=newVal;pergroup->transValueIsNull=fcinfo->isnull;MemoryContextSwitchTo(oldContext);EEO_NEXT();}/**Evaluateaggregatetransition/combinefunctionthathasa*by-referencetransitiontype.**Couldoptimizeabitfurtherbysplittingoffby-reference*fixed-lengthtypes,butcurrentlythatdoesn'tseemworthit.*/EEO_CASE(EEOP_AGG_PLAIN_TRANS){AggState*aggstate;AggStatePerTranspertrans;AggStatePerGrouppergroup;FunctionCallInfofcinfo;MemoryContextoldContext;DatumnewVal;aggstate=op->d.agg_trans.aggstate;pertrans=op->d.agg_trans.pertrans;pergroup=&aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];Assert(!pertrans->transtypeByVal);fcinfo=&pertrans->transfn_fcinfo;/*cf.select_current_set()*/aggstate->curaggcontext=op->d.agg_trans.aggcontext;aggstate->current_set=op->d.agg_trans.setno;/*setupaggstate->curpertransforAggGetAggref()*/aggstate->curpertrans=pertrans;/*invoketransitionfunctioninper-tuplecontext*/oldContext=MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);fcinfo->arg[0]=pergroup->transValue;fcinfo->argnull[0]=pergroup->transValueIsNull;fcinfo->isnull=false;/*justincasetransfndoesn'tsetit*/newVal=FunctionCallInvoke(fcinfo);/**Forpass-by-refdatatype,mustcopythenewvalueinto*aggcontextandfreethepriortransValue.Butiftransfn*returnedapointertoitsfirstinput,wedon'tneedtodo*anything.Also,iftransfnreturnedapointertoaR/W*expandedobjectthatisalreadyachildoftheaggcontext,*assumewecanadoptthatvaluewithoutcopyingit.*/if(DatumGetPointer(newVal)!=DatumGetPointer(pergroup->transValue))newVal=ExecAggTransReparent(aggstate,pertrans,newVal,fcinfo->isnull,pergroup->transValue,pergroup->transValueIsNull);pergroup->transValue=newVal;pergroup->transValueIsNull=fcinfo->isnull;MemoryContextSwitchTo(oldContext);EEO_NEXT();}/*processsingle-columnorderedaggregatedatum*/EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM){/*toocomplexforaninlineimplementation*/ExecEvalAggOrderedTransDatum(state,op,econtext);EEO_NEXT();}/*processmulti-columnorderedaggregatetuple*/EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE){/*toocomplexforaninlineimplementation*/ExecEvalAggOrderedTransTuple(state,op,econtext);EEO_NEXT();}EEO_CASE(EEOP_LAST){/*unreachable*/Assert(false);gotoout;}}out:*isnull=state->resnull;returnstate->resvalue;}
到此,相信大家对“PostgreSQL 聚合函数的实现教程”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。