@@ -235,6 +235,14 @@ typedef struct AggStatePerAggData
235235 */
236236
237237 Tuplesortstate * 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,
290298 AggStatePerGroup pergroup );
291299static void advance_transition_function (AggState * aggstate ,
292300 AggStatePerAgg 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 ,
297304 AggStatePerAgg 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 ,
409417 AggStatePerAgg peraggstate ,
410- AggStatePerGroup pergroupstate ,
411- FunctionCallInfoData * fcinfo )
418+ AggStatePerGroup pergroupstate )
412419{
413- int numTransInputs = peraggstate -> numTransInputs ;
420+ FunctionCallInfo fcinfo = & peraggstate -> transfn_fcinfo ;
414421 MemoryContext oldContext ;
415422 Datum newVal ;
416- int i ;
417423
418424 if (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+
424433 for (i = 1 ; i <= numTransInputs ; i ++ )
425434 {
426435 if (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 );
474479 fcinfo -> arg [0 ] = pergroupstate -> transValue ;
475480 fcinfo -> argnull [0 ] = pergroupstate -> transValueIsNull ;
481+ fcinfo -> isnull = false; /* just in case transfn doesn't set it */
476482
477483 newVal = FunctionCallInvoke (fcinfo );
478484
@@ -574,19 +580,18 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
574580 else
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 */
581587 Assert (slot -> tts_nvalid >= numTransInputs );
582588 for (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,
622627 MemoryContext workcontext = aggstate -> tmpcontext -> ecxt_per_tuple_memory ;
623628 MemoryContext oldContext ;
624629 bool isDistinct = (peraggstate -> numDistinctCols > 0 );
630+ FunctionCallInfo fcinfo = & peraggstate -> transfn_fcinfo ;
625631 Datum * newVal ;
626632 bool * isNull ;
627- FunctionCallInfoData fcinfo ;
628633
629634 Assert (peraggstate -> numDistinctCols < 2 );
630635
631636 tuplesort_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 }
669674 else
670675 {
671- advance_transition_function (aggstate , peraggstate , pergroupstate ,
672- & fcinfo );
676+ advance_transition_function (aggstate , peraggstate , pergroupstate );
673677 /* forget the old value, if any */
674678 if (!oldIsNull && !peraggstate -> inputtypeByVal )
675679 pfree (DatumGetPointer (oldVal ));
@@ -704,7 +708,7 @@ process_ordered_aggregate_multi(AggState *aggstate,
704708 AggStatePerGroup pergroupstate )
705709{
706710 MemoryContext workcontext = aggstate -> tmpcontext -> ecxt_per_tuple_memory ;
707- FunctionCallInfoData fcinfo ;
711+ FunctionCallInfo fcinfo = & peraggstate -> transfn_fcinfo ;
708712 TupleTableSlot * slot1 = peraggstate -> evalslot ;
709713 TupleTableSlot * slot2 = peraggstate -> uniqslot ;
710714 int 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 */
740744 for (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
749752 if (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 */
18021806 fmgr_info (transfn_oid , & peraggstate -> transfn );
18031807 fmgr_info_set_expr ((Node * ) transfnexpr , & peraggstate -> transfn );
18041808
@@ -1810,6 +1814,13 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
18101814
18111815 peraggstate -> 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 */
18131824 get_typlenbyval (aggref -> aggtype ,
18141825 & peraggstate -> resulttypeLen ,
18151826 & peraggstate -> resulttypeByVal );
0 commit comments