@@ -461,10 +461,11 @@ static void hashagg_tapeinfo_release(HashTapeInfo *tapeinfo, int tapenum);
461
461
static Datum GetAggInitVal (Datum textInitVal , Oid transtype );
462
462
static void build_pertrans_for_aggref (AggStatePerTrans pertrans ,
463
463
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 );
468
469
469
470
470
471
/*
@@ -3724,8 +3725,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3724
3725
Aggref * aggref = lfirst (l );
3725
3726
AggStatePerAgg peragg ;
3726
3727
AggStatePerTrans pertrans ;
3727
- Oid inputTypes [FUNC_MAX_ARGS ];
3728
- int numArguments ;
3728
+ Oid aggTransFnInputTypes [FUNC_MAX_ARGS ];
3729
+ int numAggTransFnArgs ;
3729
3730
int numDirectArgs ;
3730
3731
HeapTuple aggTuple ;
3731
3732
Form_pg_aggregate aggform ;
@@ -3859,14 +3860,15 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3859
3860
* could be different from the agg's declared input types, when the
3860
3861
* agg accepts ANY or a polymorphic type.
3861
3862
*/
3862
- numArguments = get_aggregate_argtypes (aggref , inputTypes );
3863
+ numAggTransFnArgs = get_aggregate_argtypes (aggref ,
3864
+ aggTransFnInputTypes );
3863
3865
3864
3866
/* Count the "direct" arguments, if any */
3865
3867
numDirectArgs = list_length (aggref -> aggdirectargs );
3866
3868
3867
3869
/* Detect how many arguments to pass to the finalfn */
3868
3870
if (aggform -> aggfinalextra )
3869
- peragg -> numFinalArgs = numArguments + 1 ;
3871
+ peragg -> numFinalArgs = numAggTransFnArgs + 1 ;
3870
3872
else
3871
3873
peragg -> numFinalArgs = numDirectArgs + 1 ;
3872
3874
@@ -3880,7 +3882,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3880
3882
*/
3881
3883
if (OidIsValid (finalfn_oid ))
3882
3884
{
3883
- build_aggregate_finalfn_expr (inputTypes ,
3885
+ build_aggregate_finalfn_expr (aggTransFnInputTypes ,
3884
3886
peragg -> numFinalArgs ,
3885
3887
aggtranstype ,
3886
3888
aggref -> aggtype ,
@@ -3911,7 +3913,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3911
3913
/*
3912
3914
* If this aggregation is performing state combines, then instead
3913
3915
* of using the transition function, we'll use the combine
3914
- * function
3916
+ * function.
3915
3917
*/
3916
3918
if (DO_AGGSPLIT_COMBINE (aggstate -> aggsplit ))
3917
3919
{
@@ -3924,8 +3926,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3924
3926
else
3925
3927
transfn_oid = aggform -> aggtransfn ;
3926
3928
3927
- aclresult = pg_proc_aclcheck (transfn_oid , aggOwner ,
3928
- ACL_EXECUTE );
3929
+ aclresult = pg_proc_aclcheck (transfn_oid , aggOwner , ACL_EXECUTE );
3929
3930
if (aclresult != ACLCHECK_OK )
3930
3931
aclcheck_error (aclresult , OBJECT_FUNCTION ,
3931
3932
get_func_name (transfn_oid ));
@@ -3943,11 +3944,72 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3943
3944
else
3944
3945
initValue = GetAggInitVal (textInitVal , aggtranstype );
3945
3946
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
+ }
3951
4013
}
3952
4014
else
3953
4015
pertrans -> aggshared = true;
@@ -4039,20 +4101,24 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
4039
4101
* Build the state needed to calculate a state value for an aggregate.
4040
4102
*
4041
4103
* 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
4043
4105
* of the arguments could be calculated from 'aggref', but the caller has
4044
4106
* calculated them already, so might as well pass them.
4107
+ *
4108
+ * 'transfn_oid' may be either the Oid of the aggtransfn or the aggcombinefn.
4045
4109
*/
4046
4110
static void
4047
4111
build_pertrans_for_aggref (AggStatePerTrans pertrans ,
4048
4112
AggState * aggstate , EState * estate ,
4049
4113
Aggref * aggref ,
4050
- Oid aggtransfn , Oid aggtranstype ,
4114
+ Oid transfn_oid , Oid aggtranstype ,
4051
4115
Oid aggserialfn , Oid aggdeserialfn ,
4052
4116
Datum initValue , bool initValueIsNull ,
4053
4117
Oid * inputTypes , int numArguments )
4054
4118
{
4055
4119
int numGroupingSets = Max (aggstate -> maxsets , 1 );
4120
+ Expr * transfnexpr ;
4121
+ int numTransArgs ;
4056
4122
Expr * serialfnexpr = NULL ;
4057
4123
Expr * deserialfnexpr = NULL ;
4058
4124
ListCell * lc ;
@@ -4067,7 +4133,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
4067
4133
pertrans -> aggref = aggref ;
4068
4134
pertrans -> aggshared = false;
4069
4135
pertrans -> aggCollation = aggref -> inputcollid ;
4070
- pertrans -> transfn_oid = aggtransfn ;
4136
+ pertrans -> transfn_oid = transfn_oid ;
4071
4137
pertrans -> serialfn_oid = aggserialfn ;
4072
4138
pertrans -> deserialfn_oid = aggdeserialfn ;
4073
4139
pertrans -> initValue = initValue ;
@@ -4081,111 +4147,34 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
4081
4147
4082
4148
pertrans -> aggtranstype = aggtranstype ;
4083
4149
4150
+ /* account for the current transition state */
4151
+ numTransArgs = pertrans -> numTransInputs + 1 ;
4152
+
4084
4153
/*
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.
4089
4156
*/
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 );
4141
4167
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 ) ;
4144
4170
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 );
4189
4178
4190
4179
/* get info about the state value's datatype */
4191
4180
get_typlenbyval (aggtranstype ,
@@ -4276,6 +4265,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
4276
4265
*/
4277
4266
Assert (aggstate -> aggstrategy != AGG_HASHED && aggstate -> aggstrategy != AGG_MIXED );
4278
4267
4268
+ /* ORDER BY aggregates are not supported with partial aggregation */
4269
+ Assert (!DO_AGGSPLIT_COMBINE (aggstate -> aggsplit ));
4270
+
4279
4271
/* If we have only one input, we need its len/byval info. */
4280
4272
if (numInputs == 1 )
4281
4273
{
0 commit comments