Interpretation of PostgreSQL Source Code-query # 106 (aggregate function # 11-finalize_aggregate)
Fn_strict & & anynull) {/ * don't call a strict function with NULL inputs * / / do not pass the NULL parameter * resultVal = (Datum) 0 when calling a strict function; * resultIsNull = true;} else {/ / call the function and get the result value * resultVal = FunctionCallInvoke (& fcinfo) * resultIsNull = fcinfo.isnull;} aggstate- > curperagg = NULL;} else {/ * Don't need MakeExpandedObjectReadOnly; datumCopy will copy it * / / the data will be copied without MakeExpandedObjectReadOnly,datumCopy. * resultVal = pergroupstate- > transValue; * resultIsNull = pergroupstate- > transValueIsNull;} / * * If result is pass-by-ref, make sure it is in the right context. * if the result is passed by reference, make sure it is in the correct context. * / if (! peragg- > resulttypeByVal & &! * resultIsNull & &! MemoryContextContains (CurrentMemoryContext, DatumGetPointer (* resultVal)) * resultVal = datumCopy (* resultVal, peragg- > resulttypeByVal, peragg- > resulttypeLen); MemoryContextSwitchTo (oldContext);} III. Tracking analysis
Test script
-- disable parallel set max_parallel_workers_per_gather=0;select bh,avg (C1), min (C1), max (c2) from t_agg_simple group by bh
Tracking and analysis
(gdb) b finalize_aggregateBreakpoint 1 at 0x6ed256: file nodeAgg.c, line 901. (gdb) cContinuing.Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e390, pergroupstate=0x155f850, resultVal=0x154c0c8, resultIsNull=0x154c100) at nodeAgg.c:901901 bool anynull = false; (gdb)
Input parameters
(gdb) p * aggstate$1 = {ss = {ps = {type = T_AggState, plan = 0x1575890, state = 0x154a428, ExecProcNode = 0x6ee438, ExecProcNodeReal = 0x6ee438, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x154abb0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x154b7b0, ps_ExprContext = 0x154aaf0, 0x154aaf0 = 0x0, ps_ResultTupleSlot = 0x154b7b0, ps_ExprContext = 0x154aaf0, 0x154aaf0 = ps_ProjInfo, 0x154b8f0 = 0x154b8f0}, 0x154b8f0 = 0x154b8f0, scandesc =} Aggs = 0x154be00, numaggs = 3, numtrans = 3, aggstrategy = AGG_HASHED, aggsplit = AGGSPLIT_SIMPLE, phase = 0x154bef8, numphases = 1, current_phase = 0, peragg = 0x154e390, pertrans = 0x15673e0, hashcontext = 0x154aa30, aggcontexts = 0x154a858, tmpcontext = 0x154a878, curaggcontext = 0x154aa30, curperagg = 0x0, curpertrans = 0x1568c70, input_done = false, agg_done = false, projected_set =-1, current_set = 0, grouped_cols = 0x154c028, all_grouped_cols = all_grouped_cols, all_grouped_cols = 1, 0x154c090 = 0x154c090, 0x154c090 = 0x154c090 Sort_out = 0x0, sort_slot = 0x0, pergroups = 0x0, grp_firstTuple = 0x0, table_filled = true, num_hashes = 1, perhash = 0x154bf50, hash_pergroup = 0x154e5a8, all_pergroups = 0x154e5a8, combinedproj = 0x0} (gdb) p * peragg$2 = {aggref = 0x155b6e8, 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 = fn_extra Fn_mcxt = 0x0, fn_expr = 0x0}, numFinalArgs = 1, aggdirectargs = 0x0, resulttypeLen = 4, resulttypeByVal = true, shareable = true} (gdb) p * pergroupstate$3 = {transValue = 5, transValueIsNull = false, noTransValue = false} (gdb) p * resultVal$4 = 0 (gdb) p * resultIsNull$5 = false (gdb)
Get the conversion function, switch the context
(gdb) n905 AggStatePerTrans pertrans = & aggstate- > pertranst [peragg-> transno]; (gdb) 907 oldContext = MemoryContextSwitchTo (aggstate- > ss.ps.ps_ExprContext- > ecxt_per_tuple_memory); (gdb) 915I = 1 (gdb) p * pertrans$6 = {aggref = 0x155b6e8, 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 = 0x154a310, fn_expr = 0x157a580}, serialfn = {fn_addr = 0x0, fn_oid = 0 Fn_nargs = 0, fn_strict = false, fn_retset = false, fn_stats = 0'\ 000mm, 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'\ 000mm, 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'\ 000mm, 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 = uniqslot, 0x0 = 0x0, 0x0 = sortdesc, sortdesc = sortdesc Context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {40,50,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, nargs = {0} Argnull = {false} (gdb)
Parse all direct parameters (none).
(gdb) n916 foreach (lc, peragg- > aggdirectargs) (gdb) p peragg- > aggdirectargs$7 = (List *) 0x0 (gdb) n930 if (OidIsValid (peragg- > finalfn_oid)) (gdb)
Invalid finalfn, direct assignment (this is max aggregation)
(gdb) n930 if (OidIsValid (peragg- > finalfn_oid)) (gdb) p peragg- > finalfn_oid$8 = 0 (gdb) n973 * resultVal = pergroupstate- > transValue; (gdb) 974 * resultIsNull = pergroupstate- > transValueIsNull; (gdb) (gdb) p * resultVal$9 = 5
Switch back to the original context
(gdb) n980 if (! peragg- > resulttypeByVal &! * resultIsNull & & (gdb) 987 MemoryContextSwitchTo (oldContext); (gdb) 988}
The second aggregation is min, and there is no finalfn
(gdb) nfinalize_aggregates (aggstate=0x154a640, peraggs=0x154e390, pergroup=0x155f850) at nodeAgg.c:11601160 for (aggno = 0; aggno
< aggstate->Numaggs; aggno++) (gdb) cContinuing.Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e3e8, pergroupstate=0x155f860, resultVal=0x154c0d0, resultIsNull=0x154c101) at nodeAgg.c:901901 bool anynull = false; (gdb) n905 AggStatePerTrans pertrans = & aggstate- > pertrans [peragg-> transno] (gdb) p * peragg$10 = {aggref = 0x155b460, transno = 1, finalfn_oid = 0, finalfn = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0, fn_strict = false, fn_retset = false, fn_stats = 0'\ 000mm, fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, numFinalArgs = 1, aggdirectargs = 0x0, resulttypeLen = 4, resulttypeByVal = true Shareable = true} (gdb) n907 oldContext = MemoryContextSwitchTo (aggstate- > ss.ps.ps_ExprContext- > ecxt_per_tuple_memory) (gdb) p * pertrans$11 = {aggref = 0x155b460, 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 = 0x154a310, fn_expr = 0x157a6d0}, serialfn = {fn_addr = 0x0, fn_oid = 0 Fn_nargs = 0, fn_strict = false, fn_retset = false, fn_stats = 0'\ 000mm, 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'\ 000mm, 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'\ 000mm, 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 = uniqslot, 0x0 = 0x0, 0x0 = sortdesc, sortdesc = sortdesc Context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {2,50,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, nargs = {0} Argnull = {false} (gdb)
The third aggregate operation is avg, and there is a finalfn
(gdb) cContinuing.Breakpoint 1, finalize_aggregate (aggstate=0x154a640, peragg=0x154e440, pergroupstate=0x155f870, resultVal=0x154c0d8, resultIsNull=0x154c102) at nodeAgg.c:901901 bool anynull = false; (gdb) n905 AggStatePerTrans pertrans = & aggstate- > peragg-> transno]; (gdb) 907 oldContext = MemoryContextSwitchTo (aggstate- > ss.ps.ps_ExprContext- > ecxt_per_tuple_memory) (gdb) p * pertrans$12 = {aggref = 0x155b1d8, 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 = 0x154a310, fn_expr = 0x157aa40}, serialfn = {fn_addr = 0x0, fn_oid = 0 Fn_nargs = 0, fn_strict = false, fn_retset = false, fn_stats = 0'\ 000mm, 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'\ 000mm, 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'\ 000mm, fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, equalfnMulti = 0x0, initValue = 22522136, initValueIsNull = false, inputtypeLen = 0, transtypeLen =-1, inputtypeByVal = false, transtypeByVal = false, sortslot = 0x0, uniqslot = uniqslot, 0x0 = 0x0, 0x0 = 0x0 Transfn_fcinfo = {flinfo = 0x1568c98, context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {22410736, 50,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 = isnull, isnull = 0 Arg = {0}, argnull = {false}} (gdb) p * peragg$13 = {aggref = 0x155b1d8, 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 = 0x154a310, fn_expr = 0x157a7c0}, numFinalArgs = 1, aggdirectargs = 0x0, resulttypeLen =-1, resulttypeByVal = false, shareable = true} (gdb)
There is finalfn (int4_avg_accum)
(gdb) n915 I = 1; (gdb) 916 foreach (lc, peragg- > aggdirectargs) (gdb) 930 if (OidIsValid (peragg- > finalfn_oid)) (gdb) p peragg- > finalfn_oid$14 = 1964 (gdb)
Initialize function call information & populate the transition status value & use nulls to populate other remaining parameters
(gdb) n932 int numFinalArgs = peragg- > numFinalArgs; (gdb) 935 aggstate- > curperagg = peragg; (gdb) p numFinalArgs$15 = 1 (gdb) n937 InitFunctionCallInfoData (fcinfo, & peragg- > finalfn, (gdb) 943 fcinfo.arg [0] = MakeExpandedObjectReadOnly (pergroupstate- > transValue, (gdb) 946 fcinfo.argnull [0] = pergroupstate- > transValueIsNull; (gdb) 947 anynull | = pergroupstate- > transValueIsNull; (gdb) n950 for (; I)
< numFinalArgs; i++)(gdb) p fcinfo$17 = {flinfo = 0x154e450, context = 0x154a640, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 1, arg = { 22411432, 4696688, 70368744179327, 262183, 0, 22291296, 22291800, 72057594037927952, 139949568947584, 532575944705, 139949566113024, 11508082471248244084, 139950313735104, 22291264, 140735692522224, 8884187, 0, 0, 481036337152, 22088784, 140735692522064, 22324800, 22522520, 22522520, 1, 22519768, 16302624, 140735692522192, 16302624, 139950284069640, 1, 22519768, 140735692522160, 22341032, 140735692522224, 4696688, 140735692525536, 0, 0, 7135662, 12884901892, 22326664, 7124177, 139950314519480, 139949574157416, 139949574157415, 0, 139949574157392, 0, 22449600, 139950314519224, 22410736, 140735692522336, 9928139, 140735692522336, 22449600, 125, 22291296, 4317427920, 536893372416, 140735692522368, 10923480, 536887362208, 22291264, 140735692522432, 8890594, 4294967296, 139949568947584, 22449600, 22410680, 16450208, 9441796618804569664, 140735692522548, 139949568947608, 125, 72057594060219232, 140735692522512, 8881213, 140735692522512, 16450208, 140735692522548, 139949568947608, 140735692522576, 8891011, 4317417729, 139949568947584, 9441796623099544216, 9441796618782244874, 16450208, 536893253520, 140735692522608, 8899958, 139949574149760, 536893253368, 140735692522640, 7227524, 4317293960, 22326664, 140735692522720, 7406960}, argnull = {false, 197, 245, 148, 255, 127, false, false, 176, 171, 84, true, false, false, false, false, 48, false, false, false, true, false , 136, 173, 84, true, false, false, false, false, 232, 132, 87, true, true, false, false, false, 40, 164, 84, true, false, false, false, false, 104, 176, 87, true, false, false, false, false, 48, 197, 245, 148, 255, 127, false, false, 67, 35, 110, false, false, false, false, false, 32, 174, 84, true, false, false, false, false, 118, 5, 113, false, false, false, false, false, 171, 4, 113, false}}(gdb) (gdb) n957 if (fcinfo.flinfo->Fn_strict & & anynull) (gdb)
Call the function to get the result value
(gdb) n965 * resultVal = FunctionCallInvoke (& fcinfo); (gdb) p * fcinfo.flinfo$18 = {fn_addr = 0x978251, fn_oid = 1964, fn_nargs = 1, fn_strict = true, fn_retset = false, fn_stats = 2'\ 002, fn_extra = 0x0, fn_mcxt = 0x154a310, fn_expr = 0x157a7c0} (gdb) p * fcinfo.flinfo- > fn_expr$19 = {type = T_FuncExpr} (gdb) b int8_avgBreakpoint 2 at 0x97825d: file numeric.c, line 5426. (gdb)
Enter int8_avg
(gdb) cContinuing.Breakpoint 2, int8_avg (fcinfo=0x7fff94f5c160) at numeric.c:54265426 ArrayType * transarray = PG_GETARG_ARRAYTYPE_P (0); (gdb) n5431 if (ARR_HASNULL (transarray) | | (gdb) 5432 ARR_SIZE (transarray)! = ARR_OVERHEAD_NONULLS (1) + sizeof (Int8TransTypeData)) (gdb) 5431 if (ARR_HASNULL (transarray) | | (gdb) 5434 transdata = (Int8TransTypeData *) ARR_DATA_PTR (transarray)) (gdb) n5437 if (transdata- > count = 0) (gdb) p * transarray$1 = {vl_len_ = 160, ndim = 1, dataoffset = 0, elemtype = 20} (gdb) p * transdata$2 = {count = 2, sum = 55} (gdb)
Prepare the parameters and call the numeric_div function
(gdb) n5440 countd = DirectFunctionCall1 (int8_numeric, (gdb) 5442 sumd = DirectFunctionCall1 (int8_numeric, (gdb) 5445 PG_RETURN_DATUM (DirectFunctionCall2 (numeric_div, sumd, countd)); (gdb) x/1xg countd0x1572780: 0x0002800000000020 (gdb) x/1xg sumd0x15727a0: 0x0037800000000020
After the call, go back to finalize_aggregate
Gdb) n5446} (gdb) finalize_aggregate (aggstate=0x1578960, peragg=0x157a730, pergroupstate=0x1570b40, resultVal=0x157a3f8, resultIsNull=0x157a422) at nodeAgg.c:966966 * resultIsNull= fcinfo.isnull; (gdb) (gdb) p * resultVal$10 = 22489080 (gdb) p resultVal$11 = (Datum *) 0x157a3f8 (gdb) x/1xg resultVal0x157a3f8: 0x00000000015727f8 (gdb) x/1fg resultVal0x157a3f8: 1.1111081834575461e-316 (gdb) x/1fw resultVal0x157a3f8: 3.95179395e-38
DONE!
IV. Reference materials
PostgreSQL Source Code interpretation (178)-query # 95 (aggregate function) # 1 related data structures