1 /*-------------------------------------------------------------------------
4 * Routines to handle aggregate nodes.
6 * Copyright (c) 1994, Regents of the University of California
10 * The implementation of Agg node has been reworked to handle legal
11 * SQL aggregates. (Do not expect POSTQUEL semantics.) -- ay 2/95
14 * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.56 1999/09/28 02:03:19 tgl Exp $
16 *-------------------------------------------------------------------------
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"
30 * AggStatePerAggData - per-aggregate working state for the Agg scan
32 typedef struct AggStatePerAggData
35 * These values are set up during ExecInitAgg() and do not change
39 /* Oids of transfer functions */
44 * fmgr lookup data for transfer functions --- only valid when
45 * corresponding oid is not InvalidOid
51 * initial values from pg_aggregate entry
53 Datum initValue1; /* for transtype1 */
54 Datum initValue2; /* for transtype2 */
55 bool initValue1IsNull,
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.
67 * These values are working state that is initialized at the start
68 * of an input tuple group and updated for each input tuple:
71 Datum value1, /* current transfer values 1 and 2 */
75 bool noInitValue; /* true if value1 not set yet */
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.
86 * Helper routine to make a copy of a Datum.
88 * NB: input had better not be a NULL; might cause null-pointer dereference.
91 copyDatum(Datum val, int typLen, bool typByVal)
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);
108 /* ---------------------------------------
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
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.)
128 * value1 = sfunc1(value1, aggregated_value)
129 * value2 = sfunc2(value2)
130 * value1 = finalfunc(value1, value2)
132 * If initcond1 is NULL then the first non-NULL aggregated_value is
133 * assigned directly to value1. sfunc1 isn't applied until value1
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.)
146 * If the outer subplan is a Group node, ExecAgg returns as many tuples
147 * as there are groups.
149 * ------------------------------------------
157 ExprContext *econtext;
158 ProjectionInfo *projInfo;
161 AggStatePerAgg peragg;
162 TupleTableSlot *resultSlot;
163 HeapTuple inputTuple;
169 /* ---------------------
170 * get state info from node
171 * ---------------------
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;
183 * We loop retrieving groups until we find one matching
188 if (aggstate->agg_done)
192 * Initialize working state for a new input tuple group
195 foreach(alist, aggstate->aggs)
197 AggStatePerAgg peraggstate = &peragg[++aggno];
200 * (Re)set value1 and value2 to their initial values.
202 if (OidIsValid(peraggstate->xfn1_oid) &&
203 ! peraggstate->initValue1IsNull)
204 peraggstate->value1 = copyDatum(peraggstate->initValue1,
205 peraggstate->transtype1Len,
206 peraggstate->transtype1ByVal);
208 peraggstate->value1 = (Datum) NULL;
209 peraggstate->value1IsNull = peraggstate->initValue1IsNull;
211 if (OidIsValid(peraggstate->xfn2_oid) &&
212 ! peraggstate->initValue2IsNull)
213 peraggstate->value2 = copyDatum(peraggstate->initValue2,
214 peraggstate->transtype2Len,
215 peraggstate->transtype2ByVal);
217 peraggstate->value2 = (Datum) NULL;
218 peraggstate->value2IsNull = peraggstate->initValue2IsNull;
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 * ------------------------------------------
229 peraggstate->noInitValue = peraggstate->initValue1IsNull;
232 inputTuple = NULL; /* no saved input tuple yet */
235 * for each tuple from the outer plan, update all the aggregates
240 TupleTableSlot *outerslot;
242 outerslot = ExecProcNode(outerPlan, (Plan *) node);
243 if (TupIsNull(outerslot))
245 econtext->ecxt_scantuple = outerslot;
248 foreach(alist, aggstate->aggs)
250 Aggref *aggref = (Aggref *) lfirst(alist);
251 AggStatePerAgg peraggstate = &peragg[++aggno];
255 newVal = ExecEvalExpr(aggref->target, econtext,
258 if (isNull && !aggref->usenulls)
259 continue; /* ignore this tuple for this agg */
261 if (OidIsValid(peraggstate->xfn1_oid) && !isNull)
263 if (peraggstate->noInitValue)
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!
272 * We have to copy the datum since the tuple from
273 * which it came will be freed on the next iteration
276 peraggstate->value1 = copyDatum(newVal,
277 peraggstate->transtype1Len,
278 peraggstate->transtype1ByVal);
279 peraggstate->value1IsNull = false;
280 peraggstate->noInitValue = false;
284 /* apply transition function 1 */
285 args[0] = peraggstate->value1;
287 newVal = (Datum) fmgr_c(&peraggstate->xfn1,
290 if (! peraggstate->transtype1ByVal)
291 pfree(peraggstate->value1);
292 peraggstate->value1 = newVal;
296 if (OidIsValid(peraggstate->xfn2_oid))
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,
304 if (! peraggstate->transtype2ByVal)
305 pfree(peraggstate->value2);
306 peraggstate->value2 = newVal;
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.)
317 inputTuple = heap_copytuple(outerslot->val);
321 * Done scanning input tuple group.
322 * Finalize each aggregate calculation.
325 foreach(alist, aggstate->aggs)
327 AggStatePerAgg peraggstate = &peragg[++aggno];
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.
337 if (OidIsValid(peraggstate->finalfn_oid) &&
338 ! peraggstate->noInitValue)
340 if (peraggstate->finalfn.fn_nargs > 1)
342 args[0] = (char *) peraggstate->value1;
343 args[1] = (char *) peraggstate->value2;
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;
350 elog(ERROR, "ExecAgg: no valid transition functions??");
351 aggnulls[aggno] = false;
352 aggvalues[aggno] = (Datum) fmgr_c(&peraggstate->finalfn,
356 else if (OidIsValid(peraggstate->xfn1_oid))
359 aggvalues[aggno] = peraggstate->value1;
360 aggnulls[aggno] = peraggstate->value1IsNull;
361 /* prevent pfree below */
362 peraggstate->value1IsNull = true;
364 else if (OidIsValid(peraggstate->xfn2_oid))
367 aggvalues[aggno] = peraggstate->value2;
368 aggnulls[aggno] = peraggstate->value2IsNull;
369 /* prevent pfree below */
370 peraggstate->value2IsNull = true;
373 elog(ERROR, "ExecAgg: no valid transition functions??");
376 * Release any per-group working storage, unless we're passing
377 * it back as the result of the aggregate.
379 if (OidIsValid(peraggstate->xfn1_oid) &&
380 ! peraggstate->value1IsNull &&
381 ! peraggstate->transtype1ByVal)
382 pfree(peraggstate->value1);
384 if (OidIsValid(peraggstate->xfn2_oid) &&
385 ! peraggstate->value2IsNull &&
386 ! peraggstate->transtype2ByVal)
387 pfree(peraggstate->value2);
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
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
403 if (IsA(outerPlan, Group))
405 /* aggregation over groups */
406 aggstate->agg_done = ((Group *) outerPlan)->grpstate->grp_done;
407 /* check for no groups */
408 if (inputTuple == NULL)
412 aggstate->agg_done = true;
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.
428 * Store the representative input tuple (or NULL, if none)
429 * in the tuple table slot reserved for it.
431 ExecStoreTuple(inputTuple,
432 aggstate->csstate.css_ScanTupleSlot,
435 econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot;
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.
442 resultSlot = ExecProject(projInfo, &isDone);
445 * If the completed tuple does not match the qualifications,
446 * it is ignored and we loop back to try to process another group.
449 while (! ExecQual(node->plan.qual, econtext));
457 * Creates the run-time information for the agg node produced by the
458 * planner and initializes its outer subtree
462 ExecInitAgg(Agg *node, EState *estate, Plan *parent)
465 AggStatePerAgg peragg;
467 ExprContext *econtext;
473 * assign the node's execution state
475 node->plan.state = estate;
478 * create state structure
480 aggstate = makeNode(AggState);
481 node->aggstate = aggstate;
482 aggstate->agg_done = false;
485 * find aggregates in targetlist and quals
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);
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
499 elog(DEBUG, "ExecInitAgg: could not find any aggregate functions");
504 * assign node's base id and create expression context
506 ExecAssignNodeBaseInfo(estate, &aggstate->csstate.cstate, (Plan *) parent);
507 ExecAssignExprContext(estate, &aggstate->csstate.cstate);
512 * tuple table initialization
514 ExecInitScanTupleSlot(estate, &aggstate->csstate);
515 ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
518 * Set up aggregate-result storage in the expr context,
519 * and also allocate my private per-agg working storage
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);
527 peragg = (AggStatePerAgg) palloc(sizeof(AggStatePerAggData) * numaggs);
528 MemSet(peragg, 0, sizeof(AggStatePerAggData) * numaggs);
529 aggstate->peragg = peragg;
532 * initialize child nodes
534 outerPlan = outerPlan(node);
535 ExecInitNode(outerPlan, estate, (Plan *) node);
538 * Result runs in its own context, but make it use our aggregates fix
539 * for 'select sum(2+2)'
541 if (IsA(outerPlan, Result))
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;
550 * initialize tuple type.
553 ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
556 * Initialize tuple type for both result and scan. This node does no
559 ExecAssignResultTypeFromTL((Plan *) node, &aggstate->csstate.cstate);
560 ExecAssignProjectionInfo((Plan *) node, &aggstate->csstate.cstate);
563 * Perform lookups of aggregate function info, and initialize the
564 * unchanging fields of the per-agg data
567 foreach(alist, aggstate->aggs)
569 Aggref *aggref = (Aggref *) lfirst(alist);
570 AggStatePerAgg peraggstate = &peragg[++aggno];
571 char *aggname = aggref->aggname;
573 Form_pg_aggregate aggform;
579 /* Mark Aggref node with its associated index in the result array */
580 aggref->aggno = aggno;
582 aggTuple = SearchSysCacheTuple(AGGNAME,
583 PointerGetDatum(aggname),
584 ObjectIdGetDatum(aggref->basetype),
586 if (!HeapTupleIsValid(aggTuple))
587 elog(ERROR, "ExecAgg: cache lookup failed for aggregate %s(%s)",
589 typeidTypeName(aggref->basetype));
590 aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
592 peraggstate->initValue1 = (Datum)
593 AggNameGetInitVal(aggname,
594 aggform->aggbasetype,
596 &peraggstate->initValue1IsNull);
598 peraggstate->initValue2 = (Datum)
599 AggNameGetInitVal(aggname,
600 aggform->aggbasetype,
602 &peraggstate->initValue2IsNull);
604 peraggstate->xfn1_oid = xfn1_oid = aggform->aggtransfn1;
605 peraggstate->xfn2_oid = xfn2_oid = aggform->aggtransfn2;
606 peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
608 if (OidIsValid(xfn1_oid))
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);
617 if (OidIsValid(xfn2_oid))
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 * ------------------------------------------
630 if (peraggstate->initValue2IsNull)
631 elog(ERROR, "ExecInitAgg: agginitval2 is null");
634 if (OidIsValid(finalfn_oid))
636 fmgr_info(finalfn_oid, &peraggstate->finalfn);
644 ExecCountSlotsAgg(Agg *node)
646 return ExecCountSlotsNode(outerPlan(node)) +
647 ExecCountSlotsNode(innerPlan(node)) +
652 ExecEndAgg(Agg *node)
654 AggState *aggstate = node->aggstate;
657 ExecFreeProjectionInfo(&aggstate->csstate.cstate);
659 outerPlan = outerPlan(node);
660 ExecEndNode(outerPlan, (Plan *) node);
662 /* clean up tuple table */
663 ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
667 ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
669 AggState *aggstate = node->aggstate;
670 ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
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);
677 * if chgParam of subnode is not null then plan will be re-scanned by
678 * first ExecProcNode.
680 if (((Plan *) node)->lefttree->chgParam == NULL)
681 ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);