aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/nodeAgg.c48
-rw-r--r--src/backend/executor/nodeWindowAgg.c33
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);