]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeAgg.c
Fix nodeAgg coredump in case where lower-level plan has
[postgresql] / src / backend / executor / nodeAgg.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeAgg.c
4  *        Routines to handle aggregate nodes.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * NOTE
10  *        The implementation of Agg node has been reworked to handle legal
11  *        SQL aggregates. (Do not expect POSTQUEL semantics.)    -- ay 2/95
12  *
13  * IDENTIFICATION
14  *        $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.56 1999/09/28 02:03:19 tgl Exp $
15  *
16  *-------------------------------------------------------------------------
17  */
18
19 #include "postgres.h"
20
21 #include "access/heapam.h"
22 #include "catalog/pg_aggregate.h"
23 #include "executor/executor.h"
24 #include "executor/nodeAgg.h"
25 #include "optimizer/clauses.h"
26 #include "parser/parse_type.h"
27 #include "utils/syscache.h"
28
29 /*
30  * AggStatePerAggData - per-aggregate working state for the Agg scan
31  */
32 typedef struct AggStatePerAggData
33 {
34         /*
35          * These values are set up during ExecInitAgg() and do not change
36          * thereafter:
37          */
38
39         /* Oids of transfer functions */
40         Oid                     xfn1_oid;
41         Oid                     xfn2_oid;
42         Oid                     finalfn_oid;
43         /*
44          * fmgr lookup data for transfer functions --- only valid when
45          * corresponding oid is not InvalidOid
46          */
47         FmgrInfo        xfn1;
48         FmgrInfo        xfn2;
49         FmgrInfo        finalfn;
50         /*
51          * initial values from pg_aggregate entry
52          */
53         Datum           initValue1;             /* for transtype1 */
54         Datum           initValue2;             /* for transtype2 */
55         bool            initValue1IsNull,
56                                 initValue2IsNull;
57         /*
58          * We need the len and byval info for the agg's transition status types
59          * in order to know how to copy/delete values.
60          */
61         int                     transtype1Len,
62                                 transtype2Len;
63         bool            transtype1ByVal,
64                                 transtype2ByVal;
65
66         /*
67          * These values are working state that is initialized at the start
68          * of an input tuple group and updated for each input tuple:
69          */
70
71         Datum           value1,                 /* current transfer values 1 and 2 */
72                                 value2;
73         bool            value1IsNull,
74                                 value2IsNull;
75         bool            noInitValue;    /* true if value1 not set yet */
76         /*
77          * Note: right now, noInitValue always has the same value as value1IsNull.
78          * But we should keep them separate because once the fmgr interface is
79          * fixed, we'll need to distinguish a null returned by transfn1 from
80          * a null we haven't yet replaced with an input value.
81          */
82 } AggStatePerAggData;
83
84
85 /*
86  * Helper routine to make a copy of a Datum.
87  *
88  * NB: input had better not be a NULL; might cause null-pointer dereference.
89  */
90 static Datum
91 copyDatum(Datum val, int typLen, bool typByVal)
92 {
93         if (typByVal)
94                 return val;
95         else
96         {
97                 char   *newVal;
98
99                 if (typLen == -1)               /* variable length type? */
100                         typLen = VARSIZE((struct varlena *) DatumGetPointer(val));
101                 newVal = (char *) palloc(typLen);
102                 memcpy(newVal, DatumGetPointer(val), typLen);
103                 return PointerGetDatum(newVal);
104         }
105 }
106
107
108 /* ---------------------------------------
109  *
110  * ExecAgg -
111  *
112  *        ExecAgg receives tuples from its outer subplan and aggregates over
113  *        the appropriate attribute for each aggregate function use (Aggref
114  *        node) appearing in the targetlist or qual of the node.  The number
115  *        of tuples to aggregate over depends on whether a GROUP BY clause is
116  *        present.  We can produce an aggregate result row per group, or just
117  *        one for the whole query.  The value of each aggregate is stored in
118  *        the expression context to be used when ExecProject evaluates the
119  *        result tuple.
120  *
121  *        ExecAgg evaluates each aggregate in the following steps: (initcond1,
122  *        initcond2 are the initial values and sfunc1, sfunc2, and finalfunc are
123  *        the transition functions.)
124  *
125  *               value1 = initcond1
126  *               value2 = initcond2
127  *               foreach tuple do
128  *                      value1 = sfunc1(value1, aggregated_value)
129  *                      value2 = sfunc2(value2)
130  *               value1 = finalfunc(value1, value2)
131  *
132  *        If initcond1 is NULL then the first non-NULL aggregated_value is
133  *        assigned directly to value1.  sfunc1 isn't applied until value1
134  *        is non-NULL.
135  *
136  *        sfunc1 is never applied when the current tuple's aggregated_value
137  *        is NULL.  sfunc2 is applied for each tuple if the aggref is marked
138  *        'usenulls', otherwise it is only applied when aggregated_value is
139  *        not NULL.  (usenulls is normally set only for the case of COUNT(*),
140  *        since according to the SQL92 standard that is the only aggregate
141  *        that considers nulls in its input.  SQL92 requires COUNT(*) and
142  *        COUNT(field) to behave differently --- the latter doesn't count nulls
143  *        --- so we can't make this flag a column of pg_aggregate but must
144  *        set it according to usage.  Ugh.)
145  *
146  *        If the outer subplan is a Group node, ExecAgg returns as many tuples
147  *        as there are groups.
148  *
149  * ------------------------------------------
150  */
151 TupleTableSlot *
152 ExecAgg(Agg *node)
153 {
154         AggState   *aggstate;
155         EState     *estate;
156         Plan       *outerPlan;
157         ExprContext *econtext;
158         ProjectionInfo *projInfo;
159         Datum      *aggvalues;
160         bool       *aggnulls;
161         AggStatePerAgg  peragg;
162         TupleTableSlot *resultSlot;
163         HeapTuple       inputTuple;
164         int                     aggno;
165         List       *alist;
166         bool            isDone;
167         bool            isNull;
168
169         /* ---------------------
170          *      get state info from node
171          * ---------------------
172          */
173         aggstate = node->aggstate;
174         estate = node->plan.state;
175         outerPlan = outerPlan(node);
176         econtext = aggstate->csstate.cstate.cs_ExprContext;
177         aggvalues = econtext->ecxt_aggvalues;
178         aggnulls = econtext->ecxt_aggnulls;
179         projInfo = aggstate->csstate.cstate.cs_ProjInfo;
180         peragg = aggstate->peragg;
181
182         /*
183          * We loop retrieving groups until we find one matching
184          * node->plan.qual
185          */
186         do
187         {
188                 if (aggstate->agg_done)
189                         return NULL;
190
191                 /*
192                  * Initialize working state for a new input tuple group
193                  */
194                 aggno = -1;
195                 foreach(alist, aggstate->aggs)
196                 {
197                         AggStatePerAgg  peraggstate = &peragg[++aggno];
198
199                         /*
200                          * (Re)set value1 and value2 to their initial values.
201                          */
202                         if (OidIsValid(peraggstate->xfn1_oid) &&
203                                 ! peraggstate->initValue1IsNull)
204                                 peraggstate->value1 = copyDatum(peraggstate->initValue1, 
205                                                                                                 peraggstate->transtype1Len,
206                                                                                                 peraggstate->transtype1ByVal);
207                         else
208                                 peraggstate->value1 = (Datum) NULL;
209                         peraggstate->value1IsNull = peraggstate->initValue1IsNull;
210
211                         if (OidIsValid(peraggstate->xfn2_oid) &&
212                                 ! peraggstate->initValue2IsNull)
213                                 peraggstate->value2 = copyDatum(peraggstate->initValue2, 
214                                                                                                 peraggstate->transtype2Len,
215                                                                                                 peraggstate->transtype2ByVal);
216                         else
217                                 peraggstate->value2 = (Datum) NULL;
218                         peraggstate->value2IsNull = peraggstate->initValue2IsNull;
219
220                         /* ------------------------------------------
221                          * If the initial value for the first transition function
222                          * doesn't exist in the pg_aggregate table then we will let
223                          * the first value returned from the outer procNode become
224                          * the initial value. (This is useful for aggregates like
225                          * max{} and min{}.)  The noInitValue flag signals that we
226                          * still need to do this.
227                          * ------------------------------------------
228                          */
229                         peraggstate->noInitValue = peraggstate->initValue1IsNull;
230                 }
231
232                 inputTuple = NULL;              /* no saved input tuple yet */
233
234                 /* ----------------
235                  *       for each tuple from the outer plan, update all the aggregates
236                  * ----------------
237                  */
238                 for (;;)
239                 {
240                         TupleTableSlot *outerslot;
241
242                         outerslot = ExecProcNode(outerPlan, (Plan *) node);
243                         if (TupIsNull(outerslot))
244                                 break;
245                         econtext->ecxt_scantuple = outerslot;
246
247                         aggno = -1;
248                         foreach(alist, aggstate->aggs)
249                         {
250                                 Aggref             *aggref = (Aggref *) lfirst(alist);
251                                 AggStatePerAgg  peraggstate = &peragg[++aggno];
252                                 Datum                   newVal;
253                                 Datum                   args[2];
254
255                                 newVal = ExecEvalExpr(aggref->target, econtext,
256                                                                           &isNull, &isDone);
257
258                                 if (isNull && !aggref->usenulls)
259                                         continue;       /* ignore this tuple for this agg */
260
261                                 if (OidIsValid(peraggstate->xfn1_oid) && !isNull)
262                                 {
263                                         if (peraggstate->noInitValue)
264                                         {
265                                                 /*
266                                                  * value1 has not been initialized. This is the
267                                                  * first non-NULL input value. We use it as the
268                                                  * initial value for value1.  XXX We assume,
269                                                  * without having checked, that the agg's input type
270                                                  * is binary-compatible with its transtype1!
271                                                  *
272                                                  * We have to copy the datum since the tuple from
273                                                  * which it came will be freed on the next iteration
274                                                  * of the scan.  
275                                                  */
276                                                 peraggstate->value1 = copyDatum(newVal,
277                                                                                                 peraggstate->transtype1Len,
278                                                                                                 peraggstate->transtype1ByVal);
279                                                 peraggstate->value1IsNull = false;
280                                                 peraggstate->noInitValue = false;
281                                         }
282                                         else
283                                         {
284                                                 /* apply transition function 1 */
285                                                 args[0] = peraggstate->value1;
286                                                 args[1] = newVal;
287                                                 newVal = (Datum) fmgr_c(&peraggstate->xfn1,
288                                                                                                 (FmgrValues *) args,
289                                                                                                 &isNull);
290                                                 if (! peraggstate->transtype1ByVal)
291                                                         pfree(peraggstate->value1);
292                                                 peraggstate->value1 = newVal;
293                                         }
294                                 }
295
296                                 if (OidIsValid(peraggstate->xfn2_oid))
297                                 {
298                                         /* apply transition function 2 */
299                                         args[0] = peraggstate->value2;
300                                         isNull = false; /* value2 cannot be null, currently */
301                                         newVal = (Datum) fmgr_c(&peraggstate->xfn2,
302                                                                                         (FmgrValues *) args,
303                                                                                         &isNull);
304                                         if (! peraggstate->transtype2ByVal)
305                                                 pfree(peraggstate->value2);
306                                         peraggstate->value2 = newVal;
307                                 }
308                         }
309
310                         /*
311                          * Keep a copy of the first input tuple for the projection.
312                          * (We only need one since only the GROUP BY columns in it
313                          * can be referenced, and these will be the same for all
314                          * tuples aggregated over.)
315                          */
316                         if (!inputTuple)
317                                 inputTuple = heap_copytuple(outerslot->val);
318                 }
319
320                 /*
321                  * Done scanning input tuple group.
322                  * Finalize each aggregate calculation.
323                  */
324                 aggno = -1;
325                 foreach(alist, aggstate->aggs)
326                 {
327                         AggStatePerAgg  peraggstate = &peragg[++aggno];
328                         char               *args[2];
329
330                         /*
331                          * XXX For now, only apply finalfn if we got at least one
332                          * non-null input value.  This prevents zero divide in AVG().
333                          * If we had cleaner handling of null inputs/results in functions,
334                          * we could probably take out this hack and define the result
335                          * for no inputs as whatever finalfn returns for null input.
336                          */
337                         if (OidIsValid(peraggstate->finalfn_oid) &&
338                                 ! peraggstate->noInitValue)
339                         {
340                                 if (peraggstate->finalfn.fn_nargs > 1)
341                                 {
342                                         args[0] = (char *) peraggstate->value1;
343                                         args[1] = (char *) peraggstate->value2;
344                                 }
345                                 else if (OidIsValid(peraggstate->xfn1_oid))
346                                         args[0] = (char *) peraggstate->value1;
347                                 else if (OidIsValid(peraggstate->xfn2_oid))
348                                         args[0] = (char *) peraggstate->value2;
349                                 else
350                                         elog(ERROR, "ExecAgg: no valid transition functions??");
351                                 aggnulls[aggno] = false;
352                                 aggvalues[aggno] = (Datum) fmgr_c(&peraggstate->finalfn,
353                                                                                                   (FmgrValues *) args,
354                                                                                                   &(aggnulls[aggno]));
355                         }
356                         else if (OidIsValid(peraggstate->xfn1_oid))
357                         {
358                                 /* Return value1 */
359                                 aggvalues[aggno] = peraggstate->value1;
360                                 aggnulls[aggno] = peraggstate->value1IsNull;
361                                 /* prevent pfree below */
362                                 peraggstate->value1IsNull = true;
363                         }
364                         else if (OidIsValid(peraggstate->xfn2_oid))
365                         {
366                                 /* Return value2 */
367                                 aggvalues[aggno] = peraggstate->value2;
368                                 aggnulls[aggno] = peraggstate->value2IsNull;
369                                 /* prevent pfree below */
370                                 peraggstate->value2IsNull = true;
371                         }
372                         else
373                                 elog(ERROR, "ExecAgg: no valid transition functions??");
374
375                         /*
376                          * Release any per-group working storage, unless we're passing
377                          * it back as the result of the aggregate.
378                          */
379                         if (OidIsValid(peraggstate->xfn1_oid) &&
380                                 ! peraggstate->value1IsNull &&
381                                 ! peraggstate->transtype1ByVal)
382                                 pfree(peraggstate->value1);
383
384                         if (OidIsValid(peraggstate->xfn2_oid) &&
385                                 ! peraggstate->value2IsNull &&
386                                 ! peraggstate->transtype2ByVal)
387                                 pfree(peraggstate->value2);
388                 }
389
390                 /*
391                  * If the outerPlan is a Group node, we will reach here after each
392                  * group.  We are not done unless the Group node is done (a little
393                  * ugliness here while we reach into the Group's state to find out).
394                  * Furthermore, when grouping we return nothing at all unless we
395                  * had some input tuple(s).  By the nature of Group, there are
396                  * no empty groups, so if we get here with no input the whole scan
397                  * is empty.
398                  *
399                  * If the outerPlan isn't a Group, we are done when we get here,
400                  * and we will emit a (single) tuple even if there were no input
401                  * tuples.
402                  */
403                 if (IsA(outerPlan, Group))
404                 {
405                         /* aggregation over groups */
406                         aggstate->agg_done = ((Group *) outerPlan)->grpstate->grp_done;
407                         /* check for no groups */
408                         if (inputTuple == NULL)
409                                 return NULL;
410                 }
411                 else
412                         aggstate->agg_done = true;
413
414                 /*
415                  * We used to create a dummy all-nulls input tuple here if
416                  * inputTuple == NULL (ie, the outerPlan didn't return anything).
417                  * However, now that we don't return a bogus tuple in Group mode,
418                  * we can only get here with inputTuple == NULL in non-Group mode.
419                  * So, if the parser has done its job right, the projected output
420                  * tuple's targetList must not contain any direct references to
421                  * input columns, and so it's a waste of time to create an
422                  * all-nulls input tuple.  We just let the tuple slot get set
423                  * to NULL instead.  The values returned for the aggregates will
424                  * be the initial values of the transition functions.
425                  */
426
427                 /*
428                  * Store the representative input tuple (or NULL, if none)
429                  * in the tuple table slot reserved for it.
430                  */
431                 ExecStoreTuple(inputTuple,
432                                            aggstate->csstate.css_ScanTupleSlot,
433                                            InvalidBuffer,
434                                            true);
435                 econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot;
436
437                 /*
438                  * Form a projection tuple using the aggregate results and the
439                  * representative input tuple.  Store it in the result tuple slot,
440                  * and return it if it meets my qual condition.
441                  */
442                 resultSlot = ExecProject(projInfo, &isDone);
443
444                 /*
445                  * If the completed tuple does not match the qualifications,
446                  * it is ignored and we loop back to try to process another group.
447                  */
448         }
449         while (! ExecQual(node->plan.qual, econtext));
450
451         return resultSlot;
452 }
453
454 /* -----------------
455  * ExecInitAgg
456  *
457  *      Creates the run-time information for the agg node produced by the
458  *      planner and initializes its outer subtree
459  * -----------------
460  */
461 bool
462 ExecInitAgg(Agg *node, EState *estate, Plan *parent)
463 {
464         AggState           *aggstate;
465         AggStatePerAgg  peragg;
466         Plan               *outerPlan;
467         ExprContext        *econtext;
468         int                             numaggs,
469                                         aggno;
470         List               *alist;
471
472         /*
473          * assign the node's execution state
474          */
475         node->plan.state = estate;
476
477         /*
478          * create state structure
479          */
480         aggstate = makeNode(AggState);
481         node->aggstate = aggstate;
482         aggstate->agg_done = false;
483
484         /*
485          * find aggregates in targetlist and quals
486          */
487         aggstate->aggs = nconc(pull_agg_clause((Node *) node->plan.targetlist),
488                                                    pull_agg_clause((Node *) node->plan.qual));
489         aggstate->numaggs = numaggs = length(aggstate->aggs);
490         if (numaggs <= 0)
491         {
492                 /*
493                  * This used to be treated as an error, but we can't do that anymore
494                  * because constant-expression simplification could optimize away
495                  * all of the Aggrefs in the targetlist and qual.  So, just make a
496                  * debug note, and force numaggs positive so that palloc()s below
497                  * don't choke.
498                  */
499                 elog(DEBUG, "ExecInitAgg: could not find any aggregate functions");
500                 numaggs = 1;
501         }
502
503         /*
504          * assign node's base id and create expression context
505          */
506         ExecAssignNodeBaseInfo(estate, &aggstate->csstate.cstate, (Plan *) parent);
507         ExecAssignExprContext(estate, &aggstate->csstate.cstate);
508
509 #define AGG_NSLOTS 2
510
511         /*
512          * tuple table initialization
513          */
514         ExecInitScanTupleSlot(estate, &aggstate->csstate);
515         ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
516
517         /*
518          * Set up aggregate-result storage in the expr context,
519          * and also allocate my private per-agg working storage
520          */
521         econtext = aggstate->csstate.cstate.cs_ExprContext;
522         econtext->ecxt_aggvalues = (Datum *) palloc(sizeof(Datum) * numaggs);
523         MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * numaggs);
524         econtext->ecxt_aggnulls = (bool *) palloc(sizeof(bool) * numaggs);
525         MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * numaggs);
526
527         peragg = (AggStatePerAgg) palloc(sizeof(AggStatePerAggData) * numaggs);
528         MemSet(peragg, 0, sizeof(AggStatePerAggData) * numaggs);
529         aggstate->peragg = peragg;
530
531         /*
532          * initialize child nodes
533          */
534         outerPlan = outerPlan(node);
535         ExecInitNode(outerPlan, estate, (Plan *) node);
536
537         /*
538          * Result runs in its own context, but make it use our aggregates fix
539          * for 'select sum(2+2)'
540          */
541         if (IsA(outerPlan, Result))
542         {
543                 ((Result *) outerPlan)->resstate->cstate.cs_ProjInfo->pi_exprContext->ecxt_aggvalues =
544                         econtext->ecxt_aggvalues;
545                 ((Result *) outerPlan)->resstate->cstate.cs_ProjInfo->pi_exprContext->ecxt_aggnulls =
546                         econtext->ecxt_aggnulls;
547         }
548
549         /* ----------------
550          *      initialize tuple type.
551          * ----------------
552          */
553         ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
554
555         /*
556          * Initialize tuple type for both result and scan. This node does no
557          * projection
558          */
559         ExecAssignResultTypeFromTL((Plan *) node, &aggstate->csstate.cstate);
560         ExecAssignProjectionInfo((Plan *) node, &aggstate->csstate.cstate);
561
562         /*
563          * Perform lookups of aggregate function info, and initialize the
564          * unchanging fields of the per-agg data
565          */
566         aggno = -1;
567         foreach(alist, aggstate->aggs)
568         {
569                 Aggref             *aggref = (Aggref *) lfirst(alist);
570                 AggStatePerAgg  peraggstate = &peragg[++aggno];
571                 char               *aggname = aggref->aggname;
572                 HeapTuple               aggTuple;
573                 Form_pg_aggregate aggform;
574                 Type                    typeInfo;
575                 Oid                             xfn1_oid,
576                                                 xfn2_oid,
577                                                 finalfn_oid;
578
579                 /* Mark Aggref node with its associated index in the result array */
580                 aggref->aggno = aggno;
581
582                 aggTuple = SearchSysCacheTuple(AGGNAME,
583                                                                            PointerGetDatum(aggname),
584                                                                            ObjectIdGetDatum(aggref->basetype),
585                                                                            0, 0);
586                 if (!HeapTupleIsValid(aggTuple))
587                         elog(ERROR, "ExecAgg: cache lookup failed for aggregate %s(%s)",
588                                  aggname,
589                                  typeidTypeName(aggref->basetype));
590                 aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
591
592                 peraggstate->initValue1 = (Datum)
593                         AggNameGetInitVal(aggname,
594                                                           aggform->aggbasetype,
595                                                           1,
596                                                           &peraggstate->initValue1IsNull);
597
598                 peraggstate->initValue2 = (Datum)
599                         AggNameGetInitVal(aggname,
600                                                           aggform->aggbasetype,
601                                                           2,
602                                                           &peraggstate->initValue2IsNull);
603
604                 peraggstate->xfn1_oid = xfn1_oid = aggform->aggtransfn1;
605                 peraggstate->xfn2_oid = xfn2_oid = aggform->aggtransfn2;
606                 peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
607
608                 if (OidIsValid(xfn1_oid))
609                 {
610                         fmgr_info(xfn1_oid, &peraggstate->xfn1);
611                         /* If a transfn1 is specified, transtype1 had better be, too */
612                         typeInfo = typeidType(aggform->aggtranstype1);
613                         peraggstate->transtype1Len = typeLen(typeInfo);
614                         peraggstate->transtype1ByVal = typeByVal(typeInfo);
615                 }
616
617                 if (OidIsValid(xfn2_oid))
618                 {
619                         fmgr_info(xfn2_oid, &peraggstate->xfn2);
620                         /* If a transfn2 is specified, transtype2 had better be, too */
621                         typeInfo = typeidType(aggform->aggtranstype2);
622                         peraggstate->transtype2Len = typeLen(typeInfo);
623                         peraggstate->transtype2ByVal = typeByVal(typeInfo);
624                         /* ------------------------------------------
625                          * If there is a second transition function, its initial
626                          * value must exist -- as it does not depend on data values,
627                          * we have no other way of determining an initial value.
628                          * ------------------------------------------
629                          */
630                         if (peraggstate->initValue2IsNull)
631                                 elog(ERROR, "ExecInitAgg: agginitval2 is null");
632                 }
633
634                 if (OidIsValid(finalfn_oid))
635                 {
636                         fmgr_info(finalfn_oid, &peraggstate->finalfn);
637                 }
638         }
639
640         return TRUE;
641 }
642
643 int
644 ExecCountSlotsAgg(Agg *node)
645 {
646         return ExecCountSlotsNode(outerPlan(node)) +
647         ExecCountSlotsNode(innerPlan(node)) +
648         AGG_NSLOTS;
649 }
650
651 void
652 ExecEndAgg(Agg *node)
653 {
654         AggState   *aggstate = node->aggstate;
655         Plan       *outerPlan;
656
657         ExecFreeProjectionInfo(&aggstate->csstate.cstate);
658
659         outerPlan = outerPlan(node);
660         ExecEndNode(outerPlan, (Plan *) node);
661
662         /* clean up tuple table */
663         ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
664 }
665
666 void
667 ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
668 {
669         AggState   *aggstate = node->aggstate;
670         ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
671
672         aggstate->agg_done = false;
673         MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * aggstate->numaggs);
674         MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * aggstate->numaggs);
675
676         /*
677          * if chgParam of subnode is not null then plan will be re-scanned by
678          * first ExecProcNode.
679          */
680         if (((Plan *) node)->lefttree->chgParam == NULL)
681                 ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
682
683 }