Skip to content

Commit 63b1af9

Browse files
committed
Cleanup some aggregate code in the executor
Here we alter the code that calls build_pertrans_for_aggref() so that the function no longer needs to special-case whether it's dealing with an aggtransfn or an aggcombinefn. This allows us to reuse the build_aggregate_transfn_expr() function and just get rid of the build_aggregate_combinefn_expr() completely. All of the special case code that was in build_pertrans_for_aggref() has been moved up to the calling functions. This saves about a dozen lines of code in nodeAgg.c and a few dozen more in parse_agg.c Also, rename a few variables in nodeAgg.c to try to make it more clear that we're working with either a aggtransfn or an aggcombinefn. Some of the old names would have you believe that we were always working with an aggtransfn. Discussion: https://postgr.es/m/CAApHDvptMQ9FmF0D67zC_w88yVnoNVR2+kkOQGUrCmdxWxLULQ@mail.gmail.com
1 parent 7922595 commit 63b1af9

File tree

3 files changed

+118
-155
lines changed

3 files changed

+118
-155
lines changed

src/backend/executor/nodeAgg.c

Lines changed: 113 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,11 @@ static void hashagg_tapeinfo_release(HashTapeInfo *tapeinfo, int tapenum);
461461
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
462462
static void build_pertrans_for_aggref(AggStatePerTrans pertrans,
463463
AggState *aggstate, EState *estate,
464-
Aggref *aggref, Oid aggtransfn, Oid aggtranstype,
465-
Oid aggserialfn, Oid aggdeserialfn,
466-
Datum initValue, bool initValueIsNull,
467-
Oid *inputTypes, int numArguments);
464+
Aggref *aggref, Oid transfn_oid,
465+
Oid aggtranstype, Oid aggserialfn,
466+
Oid aggdeserialfn, Datum initValue,
467+
bool initValueIsNull, Oid *inputTypes,
468+
int numArguments);
468469

469470

470471
/*
@@ -3724,8 +3725,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
37243725
Aggref *aggref = lfirst(l);
37253726
AggStatePerAgg peragg;
37263727
AggStatePerTrans pertrans;
3727-
Oid inputTypes[FUNC_MAX_ARGS];
3728-
int numArguments;
3728+
Oid aggTransFnInputTypes[FUNC_MAX_ARGS];
3729+
int numAggTransFnArgs;
37293730
int numDirectArgs;
37303731
HeapTuple aggTuple;
37313732
Form_pg_aggregate aggform;
@@ -3859,14 +3860,15 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
38593860
* could be different from the agg's declared input types, when the
38603861
* agg accepts ANY or a polymorphic type.
38613862
*/
3862-
numArguments = get_aggregate_argtypes(aggref, inputTypes);
3863+
numAggTransFnArgs = get_aggregate_argtypes(aggref,
3864+
aggTransFnInputTypes);
38633865

38643866
/* Count the "direct" arguments, if any */
38653867
numDirectArgs = list_length(aggref->aggdirectargs);
38663868

38673869
/* Detect how many arguments to pass to the finalfn */
38683870
if (aggform->aggfinalextra)
3869-
peragg->numFinalArgs = numArguments + 1;
3871+
peragg->numFinalArgs = numAggTransFnArgs + 1;
38703872
else
38713873
peragg->numFinalArgs = numDirectArgs + 1;
38723874

@@ -3880,7 +3882,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
38803882
*/
38813883
if (OidIsValid(finalfn_oid))
38823884
{
3883-
build_aggregate_finalfn_expr(inputTypes,
3885+
build_aggregate_finalfn_expr(aggTransFnInputTypes,
38843886
peragg->numFinalArgs,
38853887
aggtranstype,
38863888
aggref->aggtype,
@@ -3911,7 +3913,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
39113913
/*
39123914
* If this aggregation is performing state combines, then instead
39133915
* of using the transition function, we'll use the combine
3914-
* function
3916+
* function.
39153917
*/
39163918
if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
39173919
{
@@ -3924,8 +3926,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
39243926
else
39253927
transfn_oid = aggform->aggtransfn;
39263928

3927-
aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
3928-
ACL_EXECUTE);
3929+
aclresult = pg_proc_aclcheck(transfn_oid, aggOwner, ACL_EXECUTE);
39293930
if (aclresult != ACLCHECK_OK)
39303931
aclcheck_error(aclresult, OBJECT_FUNCTION,
39313932
get_func_name(transfn_oid));
@@ -3943,11 +3944,72 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
39433944
else
39443945
initValue = GetAggInitVal(textInitVal, aggtranstype);
39453946

3946-
build_pertrans_for_aggref(pertrans, aggstate, estate,
3947-
aggref, transfn_oid, aggtranstype,
3948-
serialfn_oid, deserialfn_oid,
3949-
initValue, initValueIsNull,
3950-
inputTypes, numArguments);
3947+
if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3948+
{
3949+
Oid combineFnInputTypes[] = {aggtranstype,
3950+
aggtranstype};
3951+
3952+
/*
3953+
* When combining there's only one input, the to-be-combined
3954+
* transition value. The transition value is not counted
3955+
* here.
3956+
*/
3957+
pertrans->numTransInputs = 1;
3958+
3959+
/* aggcombinefn always has two arguments of aggtranstype */
3960+
build_pertrans_for_aggref(pertrans, aggstate, estate,
3961+
aggref, transfn_oid, aggtranstype,
3962+
serialfn_oid, deserialfn_oid,
3963+
initValue, initValueIsNull,
3964+
combineFnInputTypes, 2);
3965+
3966+
/*
3967+
* Ensure that a combine function to combine INTERNAL states
3968+
* is not strict. This should have been checked during CREATE
3969+
* AGGREGATE, but the strict property could have been changed
3970+
* since then.
3971+
*/
3972+
if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
3973+
ereport(ERROR,
3974+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3975+
errmsg("combine function with transition type %s must not be declared STRICT",
3976+
format_type_be(aggtranstype))));
3977+
}
3978+
else
3979+
{
3980+
/* Detect how many arguments to pass to the transfn */
3981+
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3982+
pertrans->numTransInputs = list_length(aggref->args);
3983+
else
3984+
pertrans->numTransInputs = numAggTransFnArgs;
3985+
3986+
build_pertrans_for_aggref(pertrans, aggstate, estate,
3987+
aggref, transfn_oid, aggtranstype,
3988+
serialfn_oid, deserialfn_oid,
3989+
initValue, initValueIsNull,
3990+
aggTransFnInputTypes,
3991+
numAggTransFnArgs);
3992+
3993+
/*
3994+
* If the transfn is strict and the initval is NULL, make sure
3995+
* input type and transtype are the same (or at least
3996+
* binary-compatible), so that it's OK to use the first
3997+
* aggregated input value as the initial transValue. This
3998+
* should have been checked at agg definition time, but we
3999+
* must check again in case the transfn's strictness property
4000+
* has been changed.
4001+
*/
4002+
if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4003+
{
4004+
if (numAggTransFnArgs <= numDirectArgs ||
4005+
!IsBinaryCoercible(aggTransFnInputTypes[numDirectArgs],
4006+
aggtranstype))
4007+
ereport(ERROR,
4008+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4009+
errmsg("aggregate %u needs to have compatible input type and transition type",
4010+
aggref->aggfnoid)));
4011+
}
4012+
}
39514013
}
39524014
else
39534015
pertrans->aggshared = true;
@@ -4039,20 +4101,24 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
40394101
* Build the state needed to calculate a state value for an aggregate.
40404102
*
40414103
* This initializes all the fields in 'pertrans'. 'aggref' is the aggregate
4042-
* to initialize the state for. 'aggtransfn', 'aggtranstype', and the rest
4104+
* to initialize the state for. 'transfn_oid', 'aggtranstype', and the rest
40434105
* of the arguments could be calculated from 'aggref', but the caller has
40444106
* calculated them already, so might as well pass them.
4107+
*
4108+
* 'transfn_oid' may be either the Oid of the aggtransfn or the aggcombinefn.
40454109
*/
40464110
static void
40474111
build_pertrans_for_aggref(AggStatePerTrans pertrans,
40484112
AggState *aggstate, EState *estate,
40494113
Aggref *aggref,
4050-
Oid aggtransfn, Oid aggtranstype,
4114+
Oid transfn_oid, Oid aggtranstype,
40514115
Oid aggserialfn, Oid aggdeserialfn,
40524116
Datum initValue, bool initValueIsNull,
40534117
Oid *inputTypes, int numArguments)
40544118
{
40554119
int numGroupingSets = Max(aggstate->maxsets, 1);
4120+
Expr *transfnexpr;
4121+
int numTransArgs;
40564122
Expr *serialfnexpr = NULL;
40574123
Expr *deserialfnexpr = NULL;
40584124
ListCell *lc;
@@ -4067,7 +4133,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
40674133
pertrans->aggref = aggref;
40684134
pertrans->aggshared = false;
40694135
pertrans->aggCollation = aggref->inputcollid;
4070-
pertrans->transfn_oid = aggtransfn;
4136+
pertrans->transfn_oid = transfn_oid;
40714137
pertrans->serialfn_oid = aggserialfn;
40724138
pertrans->deserialfn_oid = aggdeserialfn;
40734139
pertrans->initValue = initValue;
@@ -4081,111 +4147,34 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
40814147

40824148
pertrans->aggtranstype = aggtranstype;
40834149

4150+
/* account for the current transition state */
4151+
numTransArgs = pertrans->numTransInputs + 1;
4152+
40844153
/*
4085-
* When combining states, we have no use at all for the aggregate
4086-
* function's transfn. Instead we use the combinefn. In this case, the
4087-
* transfn and transfn_oid fields of pertrans refer to the combine
4088-
* function rather than the transition function.
4154+
* Set up infrastructure for calling the transfn. Note that invtrans is
4155+
* not needed here.
40894156
*/
4090-
if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
4091-
{
4092-
Expr *combinefnexpr;
4093-
size_t numTransArgs;
4094-
4095-
/*
4096-
* When combining there's only one input, the to-be-combined added
4097-
* transition value from below (this node's transition value is
4098-
* counted separately).
4099-
*/
4100-
pertrans->numTransInputs = 1;
4101-
4102-
/* account for the current transition state */
4103-
numTransArgs = pertrans->numTransInputs + 1;
4104-
4105-
build_aggregate_combinefn_expr(aggtranstype,
4106-
aggref->inputcollid,
4107-
aggtransfn,
4108-
&combinefnexpr);
4109-
fmgr_info(aggtransfn, &pertrans->transfn);
4110-
fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
4111-
4112-
pertrans->transfn_fcinfo =
4113-
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(2));
4114-
InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
4115-
&pertrans->transfn,
4116-
numTransArgs,
4117-
pertrans->aggCollation,
4118-
(void *) aggstate, NULL);
4119-
4120-
/*
4121-
* Ensure that a combine function to combine INTERNAL states is not
4122-
* strict. This should have been checked during CREATE AGGREGATE, but
4123-
* the strict property could have been changed since then.
4124-
*/
4125-
if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
4126-
ereport(ERROR,
4127-
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4128-
errmsg("combine function with transition type %s must not be declared STRICT",
4129-
format_type_be(aggtranstype))));
4130-
}
4131-
else
4132-
{
4133-
Expr *transfnexpr;
4134-
size_t numTransArgs;
4135-
4136-
/* Detect how many arguments to pass to the transfn */
4137-
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4138-
pertrans->numTransInputs = numInputs;
4139-
else
4140-
pertrans->numTransInputs = numArguments;
4157+
build_aggregate_transfn_expr(inputTypes,
4158+
numArguments,
4159+
numDirectArgs,
4160+
aggref->aggvariadic,
4161+
aggtranstype,
4162+
aggref->inputcollid,
4163+
transfn_oid,
4164+
InvalidOid,
4165+
&transfnexpr,
4166+
NULL);
41414167

4142-
/* account for the current transition state */
4143-
numTransArgs = pertrans->numTransInputs + 1;
4168+
fmgr_info(transfn_oid, &pertrans->transfn);
4169+
fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
41444170

4145-
/*
4146-
* Set up infrastructure for calling the transfn. Note that
4147-
* invtransfn is not needed here.
4148-
*/
4149-
build_aggregate_transfn_expr(inputTypes,
4150-
numArguments,
4151-
numDirectArgs,
4152-
aggref->aggvariadic,
4153-
aggtranstype,
4154-
aggref->inputcollid,
4155-
aggtransfn,
4156-
InvalidOid,
4157-
&transfnexpr,
4158-
NULL);
4159-
fmgr_info(aggtransfn, &pertrans->transfn);
4160-
fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4161-
4162-
pertrans->transfn_fcinfo =
4163-
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(numTransArgs));
4164-
InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
4165-
&pertrans->transfn,
4166-
numTransArgs,
4167-
pertrans->aggCollation,
4168-
(void *) aggstate, NULL);
4169-
4170-
/*
4171-
* If the transfn is strict and the initval is NULL, make sure input
4172-
* type and transtype are the same (or at least binary-compatible), so
4173-
* that it's OK to use the first aggregated input value as the initial
4174-
* transValue. This should have been checked at agg definition time,
4175-
* but we must check again in case the transfn's strictness property
4176-
* has been changed.
4177-
*/
4178-
if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4179-
{
4180-
if (numArguments <= numDirectArgs ||
4181-
!IsBinaryCoercible(inputTypes[numDirectArgs],
4182-
aggtranstype))
4183-
ereport(ERROR,
4184-
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4185-
errmsg("aggregate %u needs to have compatible input type and transition type",
4186-
aggref->aggfnoid)));
4187-
}
4188-
}
4171+
pertrans->transfn_fcinfo =
4172+
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(numTransArgs));
4173+
InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
4174+
&pertrans->transfn,
4175+
numTransArgs,
4176+
pertrans->aggCollation,
4177+
(void *) aggstate, NULL);
41894178

41904179
/* get info about the state value's datatype */
41914180
get_typlenbyval(aggtranstype,
@@ -4276,6 +4265,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
42764265
*/
42774266
Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
42784267

4268+
/* ORDER BY aggregates are not supported with partial aggregation */
4269+
Assert(!DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
4270+
42794271
/* If we have only one input, we need its len/byval info. */
42804272
if (numInputs == 1)
42814273
{

src/backend/parser/parse_agg.c

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,11 @@ resolve_aggregate_transtype(Oid aggfuncid,
19591959
* latter may be InvalidOid, however if invtransfn_oid is set then
19601960
* transfn_oid must also be set.
19611961
*
1962+
* transfn_oid may also be passed as the aggcombinefn when the *transfnexpr is
1963+
* to be used for a combine aggregate phase. We expect invtransfn_oid to be
1964+
* InvalidOid in this case since there is no such thing as an inverse
1965+
* combinefn.
1966+
*
19621967
* Pointers to the constructed trees are returned into *transfnexpr,
19631968
* *invtransfnexpr. If there is no invtransfn, the respective pointer is set
19641969
* to NULL. Since use of the invtransfn is optional, NULL may be passed for
@@ -2021,35 +2026,6 @@ build_aggregate_transfn_expr(Oid *agg_input_types,
20212026
}
20222027
}
20232028

2024-
/*
2025-
* Like build_aggregate_transfn_expr, but creates an expression tree for the
2026-
* combine function of an aggregate, rather than the transition function.
2027-
*/
2028-
void
2029-
build_aggregate_combinefn_expr(Oid agg_state_type,
2030-
Oid agg_input_collation,
2031-
Oid combinefn_oid,
2032-
Expr **combinefnexpr)
2033-
{
2034-
Node *argp;
2035-
List *args;
2036-
FuncExpr *fexpr;
2037-
2038-
/* combinefn takes two arguments of the aggregate state type */
2039-
argp = make_agg_arg(agg_state_type, agg_input_collation);
2040-
2041-
args = list_make2(argp, argp);
2042-
2043-
fexpr = makeFuncExpr(combinefn_oid,
2044-
agg_state_type,
2045-
args,
2046-
InvalidOid,
2047-
agg_input_collation,
2048-
COERCE_EXPLICIT_CALL);
2049-
/* combinefn is currently never treated as variadic */
2050-
*combinefnexpr = (Expr *) fexpr;
2051-
}
2052-
20532029
/*
20542030
* Like build_aggregate_transfn_expr, but creates an expression tree for the
20552031
* serialization function of an aggregate.

src/include/parser/parse_agg.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,6 @@ extern void build_aggregate_transfn_expr(Oid *agg_input_types,
4646
Expr **transfnexpr,
4747
Expr **invtransfnexpr);
4848

49-
extern void build_aggregate_combinefn_expr(Oid agg_state_type,
50-
Oid agg_input_collation,
51-
Oid combinefn_oid,
52-
Expr **combinefnexpr);
53-
5449
extern void build_aggregate_serialfn_expr(Oid serialfn_oid,
5550
Expr **serialfnexpr);
5651

0 commit comments

Comments
 (0)