@@ -461,10 +461,11 @@ static void hashagg_tapeinfo_release(HashTapeInfo *tapeinfo, int tapenum);
461461static Datum GetAggInitVal (Datum textInitVal , Oid transtype );
462462static 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 */
40464110static void
40474111build_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 {
0 commit comments