diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/nodeAgg.c | 48 | ||||
-rw-r--r-- | src/backend/executor/nodeWindowAgg.c | 33 |
2 files changed, 56 insertions, 25 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index d60845bcd34..186c319a3a2 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -37,11 +37,12 @@ * * Ordered-set aggregates are treated specially in one other way: we * evaluate any "direct" arguments and pass them to the finalfunc along - * with the transition value. In addition, NULL placeholders are - * provided to match the remaining finalfunc arguments, which correspond - * to the aggregated expressions. (These arguments have no use at - * runtime, but may be needed to allow resolution of a polymorphic - * aggregate's result type.) + * with the transition value. + * + * A finalfunc can have additional arguments beyond the transvalue and + * any "direct" arguments, corresponding to the input arguments of the + * aggregate. These are always just passed as NULL. Such arguments may be + * needed to allow resolution of a polymorphic aggregate's result type. * * We compute aggregate input expressions and run the transition functions * in a temporary econtext (aggstate->tmpcontext). This is reset at @@ -151,6 +152,14 @@ typedef struct AggStatePerAggData */ int numTransInputs; + /* + * Number of arguments to pass to the finalfn. This is always at least 1 + * (the transition state value) plus any ordered-set direct args. If the + * finalfn wants extra args then we pass nulls corresponding to the + * aggregated input columns. + */ + int numFinalArgs; + /* Oids of transfer functions */ Oid transfn_oid; Oid finalfn_oid; /* may be InvalidOid */ @@ -797,6 +806,8 @@ finalize_aggregate(AggState *aggstate, /* * Evaluate any direct arguments. We do this even if there's no finalfn * (which is unlikely anyway), so that side-effects happen as expected. + * The direct arguments go into arg positions 1 and up, leaving position 0 + * for the transition state value. */ i = 1; foreach(lc, peraggstate->aggrefstate->aggdirectargs) @@ -816,19 +827,7 @@ finalize_aggregate(AggState *aggstate, */ if (OidIsValid(peraggstate->finalfn_oid)) { - int numFinalArgs; - - /* - * Identify number of arguments being passed to the finalfn. For a - * plain agg it's just one (the transition state value). For - * ordered-set aggs we also pass the direct argument(s), plus nulls - * corresponding to the aggregate-input columns. - */ - if (AGGKIND_IS_ORDERED_SET(peraggstate->aggref->aggkind)) - numFinalArgs = peraggstate->numArguments + 1; - else - numFinalArgs = 1; - Assert(i <= numFinalArgs); + int numFinalArgs = peraggstate->numFinalArgs; /* set up aggstate->curperagg for AggGetAggref() */ aggstate->curperagg = peraggstate; @@ -844,12 +843,11 @@ finalize_aggregate(AggState *aggstate, anynull |= pergroupstate->transValueIsNull; /* Fill any remaining argument positions with nulls */ - while (i < numFinalArgs) + for (; i < numFinalArgs; i++) { fcinfo.arg[i] = (Datum) 0; fcinfo.argnull[i] = true; anynull = true; - i++; } if (fcinfo.flinfo->fn_strict && anynull) @@ -1776,12 +1774,18 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) numInputs = list_length(aggref->args); peraggstate->numInputs = numInputs; - /* Detect how many columns to pass to the transfn */ + /* Detect how many arguments to pass to the transfn */ if (AGGKIND_IS_ORDERED_SET(aggref->aggkind)) peraggstate->numTransInputs = numInputs; else peraggstate->numTransInputs = numArguments; + /* Detect how many arguments to pass to the finalfn */ + if (aggform->aggfinalextra) + peraggstate->numFinalArgs = numArguments + 1; + else + peraggstate->numFinalArgs = numDirectArgs + 1; + /* resolve actual type of transition state, if polymorphic */ aggtranstype = resolve_aggregate_transtype(aggref->aggfnoid, aggform->aggtranstype, @@ -1792,7 +1796,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) build_aggregate_fnexprs(inputTypes, numArguments, numDirectArgs, - AGGKIND_IS_ORDERED_SET(aggref->aggkind), + peraggstate->numFinalArgs, aggref->aggvariadic, aggtranstype, aggref->aggtype, diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 2fcc630a925..40a925331c9 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -116,6 +116,8 @@ typedef struct WindowStatePerAggData FmgrInfo invtransfn; FmgrInfo finalfn; + int numFinalArgs; /* number of arguments to pass to finalfn */ + /* * initial value from pg_aggregate entry */ @@ -557,14 +559,28 @@ finalize_windowaggregate(WindowAggState *winstate, */ if (OidIsValid(peraggstate->finalfn_oid)) { + int numFinalArgs = peraggstate->numFinalArgs; FunctionCallInfoData fcinfo; + bool anynull; + int i; - InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn), 1, + InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn), + numFinalArgs, perfuncstate->winCollation, (void *) winstate, NULL); fcinfo.arg[0] = peraggstate->transValue; fcinfo.argnull[0] = peraggstate->transValueIsNull; - if (fcinfo.flinfo->fn_strict && peraggstate->transValueIsNull) + anynull = peraggstate->transValueIsNull; + + /* Fill any remaining argument positions with nulls */ + for (i = 1; i < numFinalArgs; i++) + { + fcinfo.arg[i] = (Datum) 0; + fcinfo.argnull[i] = true; + anynull = true; + } + + if (fcinfo.flinfo->fn_strict && anynull) { /* don't call a strict function with NULL inputs */ *result = (Datum) 0; @@ -2089,6 +2105,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, Oid transfn_oid, invtransfn_oid, finalfn_oid; + bool finalextra; Expr *transfnexpr, *invtransfnexpr, *finalfnexpr; @@ -2127,6 +2144,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, peraggstate->transfn_oid = transfn_oid = aggform->aggmtransfn; peraggstate->invtransfn_oid = invtransfn_oid = aggform->aggminvtransfn; peraggstate->finalfn_oid = finalfn_oid = aggform->aggmfinalfn; + finalextra = aggform->aggmfinalextra; aggtranstype = aggform->aggmtranstype; initvalAttNo = Anum_pg_aggregate_aggminitval; } @@ -2135,6 +2153,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn; peraggstate->invtransfn_oid = invtransfn_oid = InvalidOid; peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn; + finalextra = aggform->aggfinalextra; aggtranstype = aggform->aggtranstype; initvalAttNo = Anum_pg_aggregate_agginitval; } @@ -2185,6 +2204,12 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, } } + /* Detect how many arguments to pass to the finalfn */ + if (finalextra) + peraggstate->numFinalArgs = numArguments + 1; + else + peraggstate->numFinalArgs = 1; + /* resolve actual type of transition state, if polymorphic */ aggtranstype = resolve_aggregate_transtype(wfunc->winfnoid, aggtranstype, @@ -2195,7 +2220,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, build_aggregate_fnexprs(inputTypes, numArguments, 0, /* no ordered-set window functions yet */ - false, + peraggstate->numFinalArgs, false, /* no variadic window functions yet */ aggtranstype, wfunc->wintype, @@ -2207,6 +2232,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, &invtransfnexpr, &finalfnexpr); + /* set up infrastructure for calling the transfn(s) and finalfn */ fmgr_info(transfn_oid, &peraggstate->transfn); fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn); @@ -2222,6 +2248,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn); } + /* get info about relevant datatypes */ get_typlenbyval(wfunc->wintype, &peraggstate->resulttypeLen, &peraggstate->resulttypeByVal); |