@@ -235,6 +235,14 @@ typedef struct AggStatePerAggData
235235 */
236236
237237Tuplesortstate * sortstate ;/* sort object, if DISTINCT or ORDER BY */
238+
239+ /*
240+ * This field is a pre-initialized FunctionCallInfo struct used for
241+ * calling this aggregate's transfn. We save a few cycles per row by not
242+ * re-initializing the unchanging fields; which isn't much, but it seems
243+ * worth the extra space consumption.
244+ */
245+ FunctionCallInfoData transfn_fcinfo ;
238246}AggStatePerAggData ;
239247
240248/*
@@ -290,8 +298,7 @@ static void initialize_aggregates(AggState *aggstate,
290298AggStatePerGroup pergroup );
291299static void advance_transition_function (AggState * aggstate ,
292300AggStatePerAgg peraggstate ,
293- AggStatePerGroup pergroupstate ,
294- FunctionCallInfoData * fcinfo );
301+ AggStatePerGroup pergroupstate );
295302static void advance_aggregates (AggState * aggstate ,AggStatePerGroup pergroup );
296303static void process_ordered_aggregate_single (AggState * aggstate ,
297304AggStatePerAgg peraggstate ,
@@ -399,28 +406,30 @@ initialize_aggregates(AggState *aggstate,
399406 * Given new input value(s), advance the transition function of an aggregate.
400407 *
401408 * The new values (and null flags) have been preloaded into argument positions
402- * 1 and up in fcinfo, so that we needn't copy them again to pass to the
403- * transition function. No other fields of fcinfo are assumed valid.
409+ * 1 and up in peraggstate->transfn_fcinfo, so that we needn't copy them again
410+ * to pass to the transition function.We also expect that the static fields
411+ * of the fcinfo are already initialized; that was done by ExecInitAgg().
404412 *
405413 * It doesn't matter which memory context this is called in.
406414 */
407415static void
408416advance_transition_function (AggState * aggstate ,
409417AggStatePerAgg peraggstate ,
410- AggStatePerGroup pergroupstate ,
411- FunctionCallInfoData * fcinfo )
418+ AggStatePerGroup pergroupstate )
412419{
413- int numTransInputs = peraggstate -> numTransInputs ;
420+ FunctionCallInfo fcinfo = & peraggstate -> transfn_fcinfo ;
414421MemoryContext oldContext ;
415422Datum newVal ;
416- int i ;
417423
418424if (peraggstate -> transfn .fn_strict )
419425{
420426/*
421427 * For a strict transfn, nothing happens when there's a NULL input; we
422428 * just keep the prior transValue.
423429 */
430+ int numTransInputs = peraggstate -> numTransInputs ;
431+ int i ;
432+
424433for (i = 1 ;i <=numTransInputs ;i ++ )
425434{
426435if (fcinfo -> argnull [i ])
@@ -467,12 +476,9 @@ advance_transition_function(AggState *aggstate,
467476/*
468477 * OK to call the transition function
469478 */
470- InitFunctionCallInfoData (* fcinfo ,& (peraggstate -> transfn ),
471- numTransInputs + 1 ,
472- peraggstate -> aggCollation ,
473- (void * )aggstate ,NULL );
474479fcinfo -> arg [0 ]= pergroupstate -> transValue ;
475480fcinfo -> argnull [0 ]= pergroupstate -> transValueIsNull ;
481+ fcinfo -> isnull = false;/* just in case transfn doesn't set it */
476482
477483newVal = FunctionCallInvoke (fcinfo );
478484
@@ -574,19 +580,18 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
574580else
575581{
576582/* We can apply the transition function immediately */
577- FunctionCallInfoData fcinfo ;
583+ FunctionCallInfo fcinfo = & peraggstate -> transfn_fcinfo ;
578584
579585/* Load values into fcinfo */
580586/* Start from 1, since the 0th arg will be the transition value */
581587Assert (slot -> tts_nvalid >=numTransInputs );
582588for (i = 0 ;i < numTransInputs ;i ++ )
583589{
584- fcinfo . arg [i + 1 ]= slot -> tts_values [i ];
585- fcinfo . argnull [i + 1 ]= slot -> tts_isnull [i ];
590+ fcinfo -> arg [i + 1 ]= slot -> tts_values [i ];
591+ fcinfo -> argnull [i + 1 ]= slot -> tts_isnull [i ];
586592}
587593
588- advance_transition_function (aggstate ,peraggstate ,pergroupstate ,
589- & fcinfo );
594+ advance_transition_function (aggstate ,peraggstate ,pergroupstate );
590595}
591596}
592597}
@@ -622,17 +627,17 @@ process_ordered_aggregate_single(AggState *aggstate,
622627MemoryContext workcontext = aggstate -> tmpcontext -> ecxt_per_tuple_memory ;
623628MemoryContext oldContext ;
624629bool isDistinct = (peraggstate -> numDistinctCols > 0 );
630+ FunctionCallInfo fcinfo = & peraggstate -> transfn_fcinfo ;
625631Datum * newVal ;
626632bool * isNull ;
627- FunctionCallInfoData fcinfo ;
628633
629634Assert (peraggstate -> numDistinctCols < 2 );
630635
631636tuplesort_performsort (peraggstate -> sortstate );
632637
633638/* Load the column into argument 1 (arg 0 will be transition value) */
634- newVal = fcinfo . arg + 1 ;
635- isNull = fcinfo . argnull + 1 ;
639+ newVal = fcinfo -> arg + 1 ;
640+ isNull = fcinfo -> argnull + 1 ;
636641
637642/*
638643 * Note: if input type is pass-by-ref, the datums returned by the sort are
@@ -668,8 +673,7 @@ process_ordered_aggregate_single(AggState *aggstate,
668673}
669674else
670675{
671- advance_transition_function (aggstate ,peraggstate ,pergroupstate ,
672- & fcinfo );
676+ advance_transition_function (aggstate ,peraggstate ,pergroupstate );
673677/* forget the old value, if any */
674678if (!oldIsNull && !peraggstate -> inputtypeByVal )
675679pfree (DatumGetPointer (oldVal ));
@@ -704,7 +708,7 @@ process_ordered_aggregate_multi(AggState *aggstate,
704708AggStatePerGroup pergroupstate )
705709{
706710MemoryContext workcontext = aggstate -> tmpcontext -> ecxt_per_tuple_memory ;
707- FunctionCallInfoData fcinfo ;
711+ FunctionCallInfo fcinfo = & peraggstate -> transfn_fcinfo ;
708712TupleTableSlot * slot1 = peraggstate -> evalslot ;
709713TupleTableSlot * slot2 = peraggstate -> uniqslot ;
710714int numTransInputs = peraggstate -> numTransInputs ;
@@ -739,12 +743,11 @@ process_ordered_aggregate_multi(AggState *aggstate,
739743/* Start from 1, since the 0th arg will be the transition value */
740744for (i = 0 ;i < numTransInputs ;i ++ )
741745{
742- fcinfo . arg [i + 1 ]= slot1 -> tts_values [i ];
743- fcinfo . argnull [i + 1 ]= slot1 -> tts_isnull [i ];
746+ fcinfo -> arg [i + 1 ]= slot1 -> tts_values [i ];
747+ fcinfo -> argnull [i + 1 ]= slot1 -> tts_isnull [i ];
744748}
745749
746- advance_transition_function (aggstate ,peraggstate ,pergroupstate ,
747- & fcinfo );
750+ advance_transition_function (aggstate ,peraggstate ,pergroupstate );
748751
749752if (numDistinctCols > 0 )
750753{
@@ -1799,6 +1802,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
17991802& transfnexpr ,
18001803& finalfnexpr );
18011804
1805+ /* set up infrastructure for calling the transfn and finalfn */
18021806fmgr_info (transfn_oid ,& peraggstate -> transfn );
18031807fmgr_info_set_expr ((Node * )transfnexpr ,& peraggstate -> transfn );
18041808
@@ -1810,6 +1814,13 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
18101814
18111815peraggstate -> aggCollation = aggref -> inputcollid ;
18121816
1817+ InitFunctionCallInfoData (peraggstate -> transfn_fcinfo ,
1818+ & peraggstate -> transfn ,
1819+ peraggstate -> numTransInputs + 1 ,
1820+ peraggstate -> aggCollation ,
1821+ (void * )aggstate ,NULL );
1822+
1823+ /* get info about relevant datatypes */
18131824get_typlenbyval (aggref -> aggtype ,
18141825& peraggstate -> resulttypeLen ,
18151826& peraggstate -> resulttypeByVal );