@@ -268,7 +268,12 @@ typedef struct AggStatePerTransData
268
268
*/
269
269
int numInputs ;
270
270
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
+ */
272
277
int inputoff ;
273
278
274
279
/*
@@ -2799,10 +2804,11 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
2799
2804
/*
2800
2805
* initialize child expressions
2801
2806
*
2802
- * We rely on the parser to have checked that no aggs contain other agg
2803
- * calls in their arguments. This would make no sense under SQL semantics
2804
- * (and it's forbidden by the spec). Because it is true, we don't need to
2805
- * worry about evaluating the aggs in any particular order.
2807
+ * We expect the parser to have checked that no aggs contain other agg
2808
+ * calls in their arguments (and just to be sure, we verify it again while
2809
+ * initializing the plan node). This would make no sense under SQL
2810
+ * semantics, and it's forbidden by the spec. Because it is true, we
2811
+ * don't need to worry about evaluating the aggs in any particular order.
2806
2812
*
2807
2813
* Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
2808
2814
* nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
@@ -2841,17 +2847,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
2841
2847
*/
2842
2848
numaggs = aggstate -> numaggs ;
2843
2849
Assert (numaggs == list_length (aggstate -> aggs ));
2844
- if (numaggs <= 0 )
2845
- {
2846
- /*
2847
- * This is not an error condition: we might be using the Agg node just
2848
- * to do hash-based grouping. Even in the regular case,
2849
- * constant-expression simplification could optimize away all of the
2850
- * Aggrefs in the targetlist and qual. So keep going, but force local
2851
- * copy of numaggs positive so that palloc()s below don't choke.
2852
- */
2853
- numaggs = 1 ;
2854
- }
2855
2850
2856
2851
/*
2857
2852
* For each phase, prepare grouping set data and fmgr lookup data for
@@ -3343,19 +3338,19 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3343
3338
}
3344
3339
3345
3340
/*
3346
- * Update numaggs to match the number of unique aggregates found. Also set
3347
- * numstates to the number of unique aggregate states found.
3341
+ * Update aggstate-> numaggs to be the number of unique aggregates found.
3342
+ * Also set numstates to the number of unique transition states found.
3348
3343
*/
3349
3344
aggstate -> numaggs = aggno + 1 ;
3350
3345
aggstate -> numtrans = transno + 1 ;
3351
3346
3352
3347
/*
3353
3348
* Build a single projection computing the aggregate arguments for all
3354
- * aggregates at once, that 's considerably faster than doing it separately
3355
- * for each.
3349
+ * aggregates at once; if there 's more than one, that's considerably
3350
+ * faster than doing it separately for each.
3356
3351
*
3357
- * First create a targetlist combining the targetlist of all the
3358
- * transitions .
3352
+ * First create a targetlist combining the targetlists of all the
3353
+ * per-trans states .
3359
3354
*/
3360
3355
combined_inputeval = NIL ;
3361
3356
column_offset = 0 ;
@@ -3364,10 +3359,14 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3364
3359
AggStatePerTrans pertrans = & pertransstates [transno ];
3365
3360
ListCell * arg ;
3366
3361
3362
+ /*
3363
+ * Mark this per-trans state with its starting column in the combined
3364
+ * slot.
3365
+ */
3367
3366
pertrans -> inputoff = column_offset ;
3368
3367
3369
3368
/*
3370
- * Adjust resno in a copied target entries, to point into the combined
3369
+ * Adjust resnos in the copied target entries to match the combined
3371
3370
* slot.
3372
3371
*/
3373
3372
foreach (arg , pertrans -> aggref -> args )
@@ -3384,7 +3383,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3384
3383
column_offset += list_length (pertrans -> aggref -> args );
3385
3384
}
3386
3385
3387
- /* and then create a projection for that targetlist */
3386
+ /* Now create a projection for the combined targetlist */
3388
3387
aggstate -> evaldesc = ExecTypeFromTL (combined_inputeval , false);
3389
3388
aggstate -> evalslot = ExecInitExtraTupleSlot (estate );
3390
3389
aggstate -> evalproj = ExecBuildProjectionInfo (combined_inputeval ,
@@ -3394,6 +3393,21 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3394
3393
NULL );
3395
3394
ExecSetSlotDescriptor (aggstate -> evalslot , aggstate -> evaldesc );
3396
3395
3396
+ /*
3397
+ * Last, check whether any more aggregates got added onto the node while
3398
+ * we processed the expressions for the aggregate arguments (including not
3399
+ * only the regular arguments handled immediately above, but any FILTER
3400
+ * expressions and direct arguments we might've handled earlier). If so,
3401
+ * we have nested aggregate functions, which is semantically nonsensical,
3402
+ * so complain. (This should have been caught by the parser, so we don't
3403
+ * need to work hard on a helpful error message; but we defend against it
3404
+ * here anyway, just to be sure.)
3405
+ */
3406
+ if (numaggs != list_length (aggstate -> aggs ))
3407
+ ereport (ERROR ,
3408
+ (errcode (ERRCODE_GROUPING_ERROR ),
3409
+ errmsg ("aggregate function calls cannot be nested" )));
3410
+
3397
3411
return aggstate ;
3398
3412
}
3399
3413
@@ -3423,7 +3437,6 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
3423
3437
List * sortlist ;
3424
3438
int numSortCols ;
3425
3439
int numDistinctCols ;
3426
- int naggs ;
3427
3440
int i ;
3428
3441
3429
3442
/* Begin filling in the pertrans data */
@@ -3565,22 +3578,11 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
3565
3578
}
3566
3579
3567
3580
/* Initialize the input and FILTER expressions */
3568
- naggs = aggstate -> numaggs ;
3569
3581
pertrans -> aggfilter = ExecInitExpr (aggref -> aggfilter ,
3570
3582
(PlanState * ) aggstate );
3571
3583
pertrans -> aggdirectargs = ExecInitExprList (aggref -> aggdirectargs ,
3572
3584
(PlanState * ) aggstate );
3573
3585
3574
- /*
3575
- * Complain if the aggregate's arguments contain any aggregates; nested
3576
- * agg functions are semantically nonsensical. (This should have been
3577
- * caught earlier, but we defend against it here anyway.)
3578
- */
3579
- if (naggs != aggstate -> numaggs )
3580
- ereport (ERROR ,
3581
- (errcode (ERRCODE_GROUPING_ERROR ),
3582
- errmsg ("aggregate function calls cannot be nested" )));
3583
-
3584
3586
/*
3585
3587
* If we're doing either DISTINCT or ORDER BY for a plain agg, then we
3586
3588
* have a list of SortGroupClause nodes; fish out the data in them and
0 commit comments