@@ -268,7 +268,12 @@ typedef struct AggStatePerTransData
268268 */
269269 int numInputs ;
270270
271- /* offset of input columns in AggState->evalslot */
271+ /*
272+ * At each input row, we evaluate all argument expressions needed for all
273+ * the aggregates in this Agg node in a single ExecProject call. inputoff
274+ * is the starting index of this aggregate's argument expressions in the
275+ * resulting tuple (in AggState->evalslot).
276+ */
272277 int inputoff ;
273278
274279 /*
@@ -2809,10 +2814,11 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
28092814 /*
28102815 * initialize child expressions
28112816 *
2812- * We rely on the parser to have checked that no aggs contain other agg
2813- * calls in their arguments. This would make no sense under SQL semantics
2814- * (and it's forbidden by the spec). Because it is true, we don't need to
2815- * worry about evaluating the aggs in any particular order.
2817+ * We expect the parser to have checked that no aggs contain other agg
2818+ * calls in their arguments (and just to be sure, we verify it again while
2819+ * initializing the plan node). This would make no sense under SQL
2820+ * semantics, and it's forbidden by the spec. Because it is true, we
2821+ * don't need to worry about evaluating the aggs in any particular order.
28162822 *
28172823 * Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
28182824 * nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
@@ -2851,17 +2857,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
28512857 */
28522858 numaggs = aggstate -> numaggs ;
28532859 Assert (numaggs == list_length (aggstate -> aggs ));
2854- if (numaggs <= 0 )
2855- {
2856- /*
2857- * This is not an error condition: we might be using the Agg node just
2858- * to do hash-based grouping. Even in the regular case,
2859- * constant-expression simplification could optimize away all of the
2860- * Aggrefs in the targetlist and qual. So keep going, but force local
2861- * copy of numaggs positive so that palloc()s below don't choke.
2862- */
2863- numaggs = 1 ;
2864- }
28652860
28662861 /*
28672862 * For each phase, prepare grouping set data and fmgr lookup data for
@@ -3364,19 +3359,19 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
33643359 }
33653360
33663361 /*
3367- * Update numaggs to match the number of unique aggregates found. Also set
3368- * numstates to the number of unique aggregate states found.
3362+ * Update aggstate-> numaggs to be the number of unique aggregates found.
3363+ * Also set numstates to the number of unique transition states found.
33693364 */
33703365 aggstate -> numaggs = aggno + 1 ;
33713366 aggstate -> numtrans = transno + 1 ;
33723367
33733368 /*
33743369 * Build a single projection computing the aggregate arguments for all
3375- * aggregates at once, that 's considerably faster than doing it separately
3376- * for each.
3370+ * aggregates at once; if there 's more than one, that's considerably
3371+ * faster than doing it separately for each.
33773372 *
3378- * First create a targetlist combining the targetlist of all the
3379- * transitions .
3373+ * First create a targetlist combining the targetlists of all the
3374+ * per-trans states .
33803375 */
33813376 combined_inputeval = NIL ;
33823377 column_offset = 0 ;
@@ -3385,10 +3380,14 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
33853380 AggStatePerTrans pertrans = & pertransstates [transno ];
33863381 ListCell * arg ;
33873382
3383+ /*
3384+ * Mark this per-trans state with its starting column in the combined
3385+ * slot.
3386+ */
33883387 pertrans -> inputoff = column_offset ;
33893388
33903389 /*
3391- * Adjust resno in a copied target entries, to point into the combined
3390+ * Adjust resnos in the copied target entries to match the combined
33923391 * slot.
33933392 */
33943393 foreach (arg , pertrans -> aggref -> args )
@@ -3405,7 +3404,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
34053404 column_offset += list_length (pertrans -> aggref -> args );
34063405 }
34073406
3408- /* and then create a projection for that targetlist */
3407+ /* Now create a projection for the combined targetlist */
34093408 aggstate -> evaldesc = ExecTypeFromTL (combined_inputeval , false);
34103409 aggstate -> evalslot = ExecInitExtraTupleSlot (estate );
34113410 aggstate -> evalproj = ExecBuildProjectionInfo (combined_inputeval ,
@@ -3415,6 +3414,21 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
34153414 NULL );
34163415 ExecSetSlotDescriptor (aggstate -> evalslot , aggstate -> evaldesc );
34173416
3417+ /*
3418+ * Last, check whether any more aggregates got added onto the node while
3419+ * we processed the expressions for the aggregate arguments (including not
3420+ * only the regular arguments handled immediately above, but any FILTER
3421+ * expressions and direct arguments we might've handled earlier). If so,
3422+ * we have nested aggregate functions, which is semantically nonsensical,
3423+ * so complain. (This should have been caught by the parser, so we don't
3424+ * need to work hard on a helpful error message; but we defend against it
3425+ * here anyway, just to be sure.)
3426+ */
3427+ if (numaggs != list_length (aggstate -> aggs ))
3428+ ereport (ERROR ,
3429+ (errcode (ERRCODE_GROUPING_ERROR ),
3430+ errmsg ("aggregate function calls cannot be nested" )));
3431+
34183432 return aggstate ;
34193433}
34203434
@@ -3444,7 +3458,6 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
34443458 List * sortlist ;
34453459 int numSortCols ;
34463460 int numDistinctCols ;
3447- int naggs ;
34483461 int i ;
34493462
34503463 /* Begin filling in the pertrans data */
@@ -3586,22 +3599,11 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
35863599 }
35873600
35883601 /* Initialize the input and FILTER expressions */
3589- naggs = aggstate -> numaggs ;
35903602 pertrans -> aggfilter = ExecInitExpr (aggref -> aggfilter ,
35913603 (PlanState * ) aggstate );
35923604 pertrans -> aggdirectargs = ExecInitExprList (aggref -> aggdirectargs ,
35933605 (PlanState * ) aggstate );
35943606
3595- /*
3596- * Complain if the aggregate's arguments contain any aggregates; nested
3597- * agg functions are semantically nonsensical. (This should have been
3598- * caught earlier, but we defend against it here anyway.)
3599- */
3600- if (naggs != aggstate -> numaggs )
3601- ereport (ERROR ,
3602- (errcode (ERRCODE_GROUPING_ERROR ),
3603- errmsg ("aggregate function calls cannot be nested" )));
3604-
36053607 /*
36063608 * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
36073609 * have a list of SortGroupClause nodes; fish out the data in them and
0 commit comments