1 /*-------------------------------------------------------------------------
4 * Routines to handle aggregate nodes.
6 * ExecAgg evaluates each aggregate in the following steps:
8 * transvalue = initcond
9 * foreach input_value do
10 * transvalue = transfunc(transvalue, input_value)
11 * result = finalfunc(transvalue)
13 * If a finalfunc is not supplied then the result is just the ending
14 * value of transvalue.
16 * If transfunc is marked "strict" in pg_proc and initcond is NULL,
17 * then the first non-NULL input_value is assigned directly to transvalue,
18 * and transfunc isn't applied until the second non-NULL input_value.
19 * The agg's input type and transtype must be the same in this case!
21 * If transfunc is marked "strict" then NULL input_values are skipped,
22 * keeping the previous transvalue. If transfunc is not strict then it
23 * is called for every input tuple and must deal with NULL initcond
24 * or NULL input_value for itself.
26 * If finalfunc is marked "strict" then it is not called when the
27 * ending transvalue is NULL, instead a NULL result is created
28 * automatically (this is just the usual handling of strict functions,
29 * of course). A non-strict finalfunc can make its own choice of
30 * what to return for a NULL ending transvalue.
32 * When the transvalue datatype is pass-by-reference, we have to be
33 * careful to ensure that the values survive across tuple cycles yet
34 * are not allowed to accumulate until end of query. We do this by
35 * "ping-ponging" between two memory contexts; successive calls to the
36 * transfunc are executed in alternate contexts, passing the previous
37 * transvalue that is in the other context. At the beginning of each
38 * tuple cycle we can reset the current output context to avoid memory
39 * usage growth. Note: we must use MemoryContextContains() to check
40 * whether the transfunc has perhaps handed us back one of its input
41 * values rather than a freshly palloc'd value; if so, we copy the value
42 * to the context we want it in.
45 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
46 * Portions Copyright (c) 1994, Regents of the University of California
49 * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.91 2002/11/06 00:00:43 tgl Exp $
51 *-------------------------------------------------------------------------
56 #include "access/heapam.h"
57 #include "catalog/pg_aggregate.h"
58 #include "catalog/pg_operator.h"
59 #include "executor/executor.h"
60 #include "executor/nodeAgg.h"
61 #include "executor/nodeGroup.h"
62 #include "miscadmin.h"
63 #include "optimizer/clauses.h"
64 #include "parser/parse_coerce.h"
65 #include "parser/parse_expr.h"
66 #include "parser/parse_oper.h"
67 #include "utils/acl.h"
68 #include "utils/builtins.h"
69 #include "utils/lsyscache.h"
70 #include "utils/syscache.h"
71 #include "utils/tuplesort.h"
72 #include "utils/datum.h"
76 * AggStatePerAggData - per-aggregate working state for the Agg scan
78 typedef struct AggStatePerAggData
81 * These values are set up during ExecInitAgg() and do not change
85 /* Link to Aggref node this working state is for */
88 /* Oids of transfer functions */
90 Oid finalfn_oid; /* may be InvalidOid */
93 * fmgr lookup data for transfer functions --- only valid when
94 * corresponding oid is not InvalidOid. Note in particular that
95 * fn_strict flags are kept here.
101 * Type of input data and Oid of sort operator to use for it; only
102 * set/used when aggregate has DISTINCT flag. (These are not used
103 * directly by nodeAgg, but must be passed to the Tuplesort object.)
109 * fmgr lookup data for input type's equality operator --- only
110 * set/used when aggregate has DISTINCT flag.
115 * initial value from pg_aggregate entry
118 bool initValueIsNull;
121 * We need the len and byval info for the agg's input, result, and
122 * transition data types in order to know how to copy/delete values.
132 * These values are working state that is initialized at the start of
133 * an input tuple group and updated for each input tuple.
135 * For a simple (non DISTINCT) aggregate, we just feed the input values
136 * straight to the transition function. If it's DISTINCT, we pass the
137 * input values into a Tuplesort object; then at completion of the
138 * input tuple group, we scan the sorted values, eliminate duplicates,
139 * and run the transition function on the rest.
142 Tuplesortstate *sortstate; /* sort object, if a DISTINCT agg */
145 bool transValueIsNull;
147 bool noTransValue; /* true if transValue not set yet */
150 * Note: noTransValue initially has the same value as
151 * transValueIsNull, and if true both are cleared to false at the same
152 * time. They are not the same though: if transfn later returns a
153 * NULL, we want to keep that NULL and not auto-replace it with a
154 * later input value. Only the first non-NULL input will be
157 } AggStatePerAggData;
160 static void initialize_aggregate(AggStatePerAgg peraggstate);
161 static void advance_transition_function(AggStatePerAgg peraggstate,
162 Datum newVal, bool isNull);
163 static void advance_aggregates(AggState *aggstate, ExprContext *econtext);
164 static void process_sorted_aggregate(AggState *aggstate,
165 AggStatePerAgg peraggstate);
166 static void finalize_aggregate(AggStatePerAgg peraggstate,
167 Datum *resultVal, bool *resultIsNull);
168 static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
172 * Initialize one aggregate for a new set of input values.
174 * When called, CurrentMemoryContext should be the per-query context.
177 initialize_aggregate(AggStatePerAgg peraggstate)
179 Aggref *aggref = peraggstate->aggref;
182 * Start a fresh sort operation for each DISTINCT aggregate.
184 if (aggref->aggdistinct)
187 * In case of rescan, maybe there could be an uncompleted sort
188 * operation? Clean it up if so.
190 if (peraggstate->sortstate)
191 tuplesort_end(peraggstate->sortstate);
193 peraggstate->sortstate =
194 tuplesort_begin_datum(peraggstate->inputType,
195 peraggstate->sortOperator,
200 * (Re)set transValue to the initial value.
202 * Note that when the initial value is pass-by-ref, we just reuse it
203 * without copying for each group. Hence, transition function had
204 * better not scribble on its input, or it will fail for GROUP BY!
206 peraggstate->transValue = peraggstate->initValue;
207 peraggstate->transValueIsNull = peraggstate->initValueIsNull;
210 * If the initial value for the transition state doesn't exist in the
211 * pg_aggregate table then we will let the first non-NULL value
212 * returned from the outer procNode become the initial value. (This is
213 * useful for aggregates like max() and min().) The noTransValue flag
214 * signals that we still need to do this.
216 peraggstate->noTransValue = peraggstate->initValueIsNull;
220 * Given a new input value, advance the transition function of an aggregate.
222 * When called, CurrentMemoryContext should be the context we want the
223 * transition function result to be delivered into on this cycle.
226 advance_transition_function(AggStatePerAgg peraggstate,
227 Datum newVal, bool isNull)
229 FunctionCallInfoData fcinfo;
231 if (peraggstate->transfn.fn_strict)
236 * For a strict transfn, nothing happens at a NULL input
237 * tuple; we just keep the prior transValue. However, if the
238 * transtype is pass-by-ref, we have to copy it into the new
239 * context because the old one is going to get reset.
241 if (!peraggstate->transValueIsNull)
242 peraggstate->transValue = datumCopy(peraggstate->transValue,
243 peraggstate->transtypeByVal,
244 peraggstate->transtypeLen);
247 if (peraggstate->noTransValue)
250 * transValue has not been initialized. This is the first
251 * non-NULL input value. We use it as the initial value for
252 * transValue. (We already checked that the agg's input type
253 * is binary-compatible with its transtype, so straight copy
256 * We had better copy the datum if it is pass-by-ref, since the
257 * given pointer may be pointing into a scan tuple that will
258 * be freed on the next iteration of the scan.
260 peraggstate->transValue = datumCopy(newVal,
261 peraggstate->transtypeByVal,
262 peraggstate->transtypeLen);
263 peraggstate->transValueIsNull = false;
264 peraggstate->noTransValue = false;
267 if (peraggstate->transValueIsNull)
270 * Don't call a strict function with NULL inputs. Note it is
271 * possible to get here despite the above tests, if the
272 * transfn is strict *and* returned a NULL on a prior cycle.
273 * If that happens we will propagate the NULL all the way to
281 * OK to call the transition function
283 * This is heavily-used code, so manually zero just the necessary fields
284 * instead of using MemSet(). Compare FunctionCall2().
287 /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */
288 fcinfo.context = NULL;
289 fcinfo.resultinfo = NULL;
290 fcinfo.isnull = false;
292 fcinfo.flinfo = &peraggstate->transfn;
294 fcinfo.arg[0] = peraggstate->transValue;
295 fcinfo.argnull[0] = peraggstate->transValueIsNull;
296 fcinfo.arg[1] = newVal;
297 fcinfo.argnull[1] = isNull;
299 newVal = FunctionCallInvoke(&fcinfo);
302 * If the transition function was uncooperative, it may have given us
303 * a pass-by-ref result that points at the scan tuple or the
304 * prior-cycle working memory. Copy it into the active context if it
305 * doesn't look right.
307 if (!peraggstate->transtypeByVal && !fcinfo.isnull &&
308 !MemoryContextContains(CurrentMemoryContext,
309 DatumGetPointer(newVal)))
310 newVal = datumCopy(newVal,
311 peraggstate->transtypeByVal,
312 peraggstate->transtypeLen);
314 peraggstate->transValue = newVal;
315 peraggstate->transValueIsNull = fcinfo.isnull;
319 * Advance all the aggregates for one input tuple. The input tuple
320 * has been stored in econtext->ecxt_scantuple, so that it is accessible
323 * When called, CurrentMemoryContext should be the per-query context.
326 advance_aggregates(AggState *aggstate, ExprContext *econtext)
328 MemoryContext oldContext;
332 * Clear and select the current working context for evaluation
333 * of the input expressions and transition functions at this
336 econtext->ecxt_per_tuple_memory = aggstate->agg_cxt[aggstate->which_cxt];
337 ResetExprContext(econtext);
338 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
340 for (aggno = 0; aggno < aggstate->numaggs; aggno++)
342 AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
343 Aggref *aggref = peraggstate->aggref;
347 newVal = ExecEvalExpr(aggref->target, econtext, &isNull, NULL);
349 if (aggref->aggdistinct)
351 /* in DISTINCT mode, we may ignore nulls */
354 /* putdatum has to be called in per-query context */
355 MemoryContextSwitchTo(oldContext);
356 tuplesort_putdatum(peraggstate->sortstate, newVal, isNull);
357 MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
361 advance_transition_function(peraggstate, newVal, isNull);
366 * Make the other context current so that these transition
367 * results are preserved.
369 aggstate->which_cxt = 1 - aggstate->which_cxt;
371 MemoryContextSwitchTo(oldContext);
375 * Run the transition function for a DISTINCT aggregate. This is called
376 * after we have completed entering all the input values into the sort
377 * object. We complete the sort, read out the values in sorted order,
378 * and run the transition function on each non-duplicate value.
380 * When called, CurrentMemoryContext should be the per-query context.
383 process_sorted_aggregate(AggState *aggstate,
384 AggStatePerAgg peraggstate)
386 Datum oldVal = (Datum) 0;
387 bool haveOldVal = false;
388 MemoryContext oldContext;
392 tuplesort_performsort(peraggstate->sortstate);
395 * Note: if input type is pass-by-ref, the datums returned by the sort
396 * are freshly palloc'd in the per-query context, so we must be
397 * careful to pfree them when they are no longer needed.
400 while (tuplesort_getdatum(peraggstate->sortstate, true,
404 * DISTINCT always suppresses nulls, per SQL spec, regardless of
405 * the transition function's strictness.
411 * Clear and select the current working context for evaluation of
412 * the equality function and transition function.
414 MemoryContextReset(aggstate->agg_cxt[aggstate->which_cxt]);
416 MemoryContextSwitchTo(aggstate->agg_cxt[aggstate->which_cxt]);
419 DatumGetBool(FunctionCall2(&peraggstate->equalfn,
422 /* equal to prior, so forget this one */
423 if (!peraggstate->inputtypeByVal)
424 pfree(DatumGetPointer(newVal));
427 * note we do NOT flip contexts in this case, so no need to
428 * copy prior transValue to other context.
433 advance_transition_function(peraggstate, newVal, false);
436 * Make the other context current so that this transition
437 * result is preserved.
439 aggstate->which_cxt = 1 - aggstate->which_cxt;
440 /* forget the old value, if any */
441 if (haveOldVal && !peraggstate->inputtypeByVal)
442 pfree(DatumGetPointer(oldVal));
447 MemoryContextSwitchTo(oldContext);
450 if (haveOldVal && !peraggstate->inputtypeByVal)
451 pfree(DatumGetPointer(oldVal));
453 tuplesort_end(peraggstate->sortstate);
454 peraggstate->sortstate = NULL;
458 * Compute the final value of one aggregate.
460 * When called, CurrentMemoryContext should be the context where we want
461 * final values delivered (ie, the per-output-tuple expression context).
464 finalize_aggregate(AggStatePerAgg peraggstate,
465 Datum *resultVal, bool *resultIsNull)
468 * Apply the agg's finalfn if one is provided, else return transValue.
470 if (OidIsValid(peraggstate->finalfn_oid))
472 FunctionCallInfoData fcinfo;
474 MemSet(&fcinfo, 0, sizeof(fcinfo));
475 fcinfo.flinfo = &peraggstate->finalfn;
477 fcinfo.arg[0] = peraggstate->transValue;
478 fcinfo.argnull[0] = peraggstate->transValueIsNull;
479 if (fcinfo.flinfo->fn_strict && peraggstate->transValueIsNull)
481 /* don't call a strict function with NULL inputs */
482 *resultVal = (Datum) 0;
483 *resultIsNull = true;
487 *resultVal = FunctionCallInvoke(&fcinfo);
488 *resultIsNull = fcinfo.isnull;
493 *resultVal = peraggstate->transValue;
494 *resultIsNull = peraggstate->transValueIsNull;
498 * If result is pass-by-ref, make sure it is in the right context.
500 if (!peraggstate->resulttypeByVal && !*resultIsNull &&
501 !MemoryContextContains(CurrentMemoryContext,
502 DatumGetPointer(*resultVal)))
503 *resultVal = datumCopy(*resultVal,
504 peraggstate->resulttypeByVal,
505 peraggstate->resulttypeLen);
512 * ExecAgg receives tuples from its outer subplan and aggregates over
513 * the appropriate attribute for each aggregate function use (Aggref
514 * node) appearing in the targetlist or qual of the node. The number
515 * of tuples to aggregate over depends on whether grouped or plain
516 * aggregation is selected. In grouped aggregation, we produce a result
517 * row for each group; in plain aggregation there's a single result row
518 * for the whole query. In either case, the value of each aggregate is
519 * stored in the expression context to be used when ExecProject evaluates
528 ExprContext *econtext;
529 ProjectionInfo *projInfo;
532 AggStatePerAgg peragg;
533 MemoryContext oldContext;
534 TupleTableSlot *outerslot;
535 TupleTableSlot *firstSlot;
536 TupleTableSlot *resultSlot;
540 * get state info from node
542 aggstate = node->aggstate;
543 estate = node->plan.state;
544 outerPlan = outerPlan(node);
545 econtext = aggstate->csstate.cstate.cs_ExprContext;
546 aggvalues = econtext->ecxt_aggvalues;
547 aggnulls = econtext->ecxt_aggnulls;
548 projInfo = aggstate->csstate.cstate.cs_ProjInfo;
549 peragg = aggstate->peragg;
550 firstSlot = aggstate->csstate.css_ScanTupleSlot;
553 * We loop retrieving groups until we find one matching
558 if (aggstate->agg_done)
562 * If we don't already have the first tuple of the new group,
563 * fetch it from the outer plan.
565 if (aggstate->grp_firstTuple == NULL)
567 outerslot = ExecProcNode(outerPlan, (Plan *) node);
568 if (!TupIsNull(outerslot))
571 * Make a copy of the first input tuple; we will use this
572 * for comparisons (in group mode) and for projection.
574 aggstate->grp_firstTuple = heap_copytuple(outerslot->val);
578 /* outer plan produced no tuples at all */
579 aggstate->agg_done = true;
580 /* If we are grouping, we should produce no tuples too */
581 if (node->aggstrategy != AGG_PLAIN)
587 * Clear the per-output-tuple context for each group
589 MemoryContextReset(aggstate->tup_cxt);
592 * Initialize working state for a new input tuple group
594 for (aggno = 0; aggno < aggstate->numaggs; aggno++)
596 AggStatePerAgg peraggstate = &peragg[aggno];
598 initialize_aggregate(peraggstate);
601 if (aggstate->grp_firstTuple != NULL)
604 * Store the copied first input tuple in the tuple table slot
605 * reserved for it. The tuple will be deleted when it is
606 * cleared from the slot.
608 ExecStoreTuple(aggstate->grp_firstTuple,
612 aggstate->grp_firstTuple = NULL; /* don't keep two pointers */
614 /* set up for first advance_aggregates call */
615 econtext->ecxt_scantuple = firstSlot;
618 * Process each outer-plan tuple, and then fetch the next one,
619 * until we exhaust the outer plan or cross a group boundary.
623 advance_aggregates(aggstate, econtext);
625 outerslot = ExecProcNode(outerPlan, (Plan *) node);
626 if (TupIsNull(outerslot))
628 /* no more outer-plan tuples available */
629 aggstate->agg_done = true;
632 /* set up for next advance_aggregates call */
633 econtext->ecxt_scantuple = outerslot;
636 * If we are grouping, check whether we've crossed a group
639 if (node->aggstrategy == AGG_SORTED)
641 if (!execTuplesMatch(firstSlot->val,
643 firstSlot->ttc_tupleDescriptor,
644 node->numCols, node->grpColIdx,
645 aggstate->eqfunctions,
646 aggstate->agg_cxt[aggstate->which_cxt]))
649 * Save the first input tuple of the next group.
651 aggstate->grp_firstTuple = heap_copytuple(outerslot->val);
659 * Done scanning input tuple group. Finalize each aggregate
660 * calculation, and stash results in the per-output-tuple context.
662 * This is a bit tricky when there are both DISTINCT and plain
663 * aggregates: we must first finalize all the plain aggs and then
664 * all the DISTINCT ones. This is needed because the last
665 * transition values for the plain aggs are stored in the
666 * not-current working context, and we have to evaluate those aggs
667 * (and stash the results in the output tup_cxt!) before we start
668 * flipping contexts again in process_sorted_aggregate.
670 oldContext = MemoryContextSwitchTo(aggstate->tup_cxt);
671 for (aggno = 0; aggno < aggstate->numaggs; aggno++)
673 AggStatePerAgg peraggstate = &peragg[aggno];
675 if (!peraggstate->aggref->aggdistinct)
676 finalize_aggregate(peraggstate,
677 &aggvalues[aggno], &aggnulls[aggno]);
679 MemoryContextSwitchTo(oldContext);
680 for (aggno = 0; aggno < aggstate->numaggs; aggno++)
682 AggStatePerAgg peraggstate = &peragg[aggno];
684 if (peraggstate->aggref->aggdistinct)
686 process_sorted_aggregate(aggstate, peraggstate);
687 oldContext = MemoryContextSwitchTo(aggstate->tup_cxt);
688 finalize_aggregate(peraggstate,
689 &aggvalues[aggno], &aggnulls[aggno]);
690 MemoryContextSwitchTo(oldContext);
695 * If we have no first tuple (ie, the outerPlan didn't return
696 * anything), create a dummy all-nulls input tuple for use by
697 * ExecProject. 99.44% of the time this is a waste of cycles,
698 * because ordinarily the projected output tuple's targetlist
699 * cannot contain any direct (non-aggregated) references to
700 * input columns, so the dummy tuple will not be referenced.
701 * However there are special cases where this isn't so --- in
702 * particular an UPDATE involving an aggregate will have a
703 * targetlist reference to ctid. We need to return a null for
704 * ctid in that situation, not coredump.
706 * The values returned for the aggregates will be the initial
707 * values of the transition functions.
709 if (TupIsNull(firstSlot))
713 /* Should only happen in non-grouped mode */
714 Assert(node->aggstrategy == AGG_PLAIN);
715 Assert(aggstate->agg_done);
717 tupType = firstSlot->ttc_tupleDescriptor;
718 /* watch out for zero-column input tuples, though... */
719 if (tupType && tupType->natts > 0)
721 HeapTuple nullsTuple;
725 dvalues = (Datum *) palloc(sizeof(Datum) * tupType->natts);
726 dnulls = (char *) palloc(sizeof(char) * tupType->natts);
727 MemSet(dvalues, 0, sizeof(Datum) * tupType->natts);
728 MemSet(dnulls, 'n', sizeof(char) * tupType->natts);
729 nullsTuple = heap_formtuple(tupType, dvalues, dnulls);
730 ExecStoreTuple(nullsTuple,
740 * Do projection and qual check in the per-output-tuple context.
742 econtext->ecxt_per_tuple_memory = aggstate->tup_cxt;
745 * Form a projection tuple using the aggregate results and the
746 * representative input tuple. Store it in the result tuple slot.
747 * Note we do not support aggregates returning sets ...
749 econtext->ecxt_scantuple = firstSlot;
750 resultSlot = ExecProject(projInfo, NULL);
753 * If the completed tuple does not match the qualifications, it is
754 * ignored and we loop back to try to process another group.
755 * Otherwise, return the tuple.
758 while (!ExecQual(node->plan.qual, econtext, false));
766 * Creates the run-time information for the agg node produced by the
767 * planner and initializes its outer subtree
771 ExecInitAgg(Agg *node, EState *estate, Plan *parent)
774 AggStatePerAgg peragg;
776 ExprContext *econtext;
782 * assign the node's execution state
784 node->plan.state = estate;
787 * create state structure
789 aggstate = makeNode(AggState);
790 node->aggstate = aggstate;
791 aggstate->eqfunctions = NULL;
792 aggstate->grp_firstTuple = NULL;
793 aggstate->agg_done = false;
796 * find aggregates in targetlist and quals
798 * Note: pull_agg_clauses also checks that no aggs contain other agg
799 * calls in their arguments. This would make no sense under SQL
800 * semantics anyway (and it's forbidden by the spec). Because that is
801 * true, we don't need to worry about evaluating the aggs in any
804 aggstate->aggs = nconc(pull_agg_clause((Node *) node->plan.targetlist),
805 pull_agg_clause((Node *) node->plan.qual));
806 aggstate->numaggs = numaggs = length(aggstate->aggs);
810 * This is not an error condition: we might be using the Agg node just
811 * to do hash-based grouping. Even in the regular case,
812 * constant-expression simplification could optimize away all of the
813 * Aggrefs in the targetlist and qual. So keep going, but force local
814 * copy of numaggs positive so that palloc()s below don't choke.
820 * Create expression context
822 ExecAssignExprContext(estate, &aggstate->csstate.cstate);
825 * We actually need three separate expression memory contexts: one for
826 * calculating per-output-tuple values (ie, the finished aggregate
827 * results), and two that we ping-pong between for per-input-tuple
828 * evaluation of input expressions and transition functions. The
829 * context made by ExecAssignExprContext() is used as the output
833 aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory;
834 aggstate->agg_cxt[0] =
835 AllocSetContextCreate(CurrentMemoryContext,
837 ALLOCSET_DEFAULT_MINSIZE,
838 ALLOCSET_DEFAULT_INITSIZE,
839 ALLOCSET_DEFAULT_MAXSIZE);
840 aggstate->agg_cxt[1] =
841 AllocSetContextCreate(CurrentMemoryContext,
843 ALLOCSET_DEFAULT_MINSIZE,
844 ALLOCSET_DEFAULT_INITSIZE,
845 ALLOCSET_DEFAULT_MAXSIZE);
846 aggstate->which_cxt = 0;
851 * tuple table initialization
853 ExecInitScanTupleSlot(estate, &aggstate->csstate);
854 ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
857 * Set up aggregate-result storage in the expr context, and also
858 * allocate my private per-agg working storage
860 econtext = aggstate->csstate.cstate.cs_ExprContext;
861 econtext->ecxt_aggvalues = (Datum *) palloc(sizeof(Datum) * numaggs);
862 MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * numaggs);
863 econtext->ecxt_aggnulls = (bool *) palloc(sizeof(bool) * numaggs);
864 MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * numaggs);
866 peragg = (AggStatePerAgg) palloc(sizeof(AggStatePerAggData) * numaggs);
867 MemSet(peragg, 0, sizeof(AggStatePerAggData) * numaggs);
868 aggstate->peragg = peragg;
871 * initialize child nodes
873 outerPlan = outerPlan(node);
874 ExecInitNode(outerPlan, estate, (Plan *) node);
877 * initialize source tuple type.
879 ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
882 * Initialize result tuple type and projection info.
884 ExecAssignResultTypeFromTL((Plan *) node, &aggstate->csstate.cstate);
885 ExecAssignProjectionInfo((Plan *) node, &aggstate->csstate.cstate);
888 * If we are grouping, precompute fmgr lookup data for inner loop
890 if (node->numCols > 0)
892 aggstate->eqfunctions =
893 execTuplesMatchPrepare(ExecGetScanType(&aggstate->csstate),
899 * Perform lookups of aggregate function info, and initialize the
900 * unchanging fields of the per-agg data
903 foreach(alist, aggstate->aggs)
905 Aggref *aggref = (Aggref *) lfirst(alist);
906 AggStatePerAgg peraggstate = &peragg[++aggno];
908 Form_pg_aggregate aggform;
914 /* Mark Aggref node with its associated index in the result array */
915 aggref->aggno = aggno;
917 /* Fill in the peraggstate data */
918 peraggstate->aggref = aggref;
920 aggTuple = SearchSysCache(AGGFNOID,
921 ObjectIdGetDatum(aggref->aggfnoid),
923 if (!HeapTupleIsValid(aggTuple))
924 elog(ERROR, "ExecAgg: cache lookup failed for aggregate %u",
926 aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
928 /* Check permission to call aggregate function */
929 aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
931 if (aclresult != ACLCHECK_OK)
932 aclcheck_error(aclresult, get_func_name(aggref->aggfnoid));
934 get_typlenbyval(aggref->aggtype,
935 &peraggstate->resulttypeLen,
936 &peraggstate->resulttypeByVal);
937 get_typlenbyval(aggform->aggtranstype,
938 &peraggstate->transtypeLen,
939 &peraggstate->transtypeByVal);
942 * initval is potentially null, so don't try to access it as a
943 * struct field. Must do it the hard way with SysCacheGetAttr.
945 textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
946 Anum_pg_aggregate_agginitval,
947 &peraggstate->initValueIsNull);
949 if (peraggstate->initValueIsNull)
950 peraggstate->initValue = (Datum) 0;
952 peraggstate->initValue = GetAggInitVal(textInitVal,
953 aggform->aggtranstype);
955 peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
956 peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
958 fmgr_info(transfn_oid, &peraggstate->transfn);
959 if (OidIsValid(finalfn_oid))
960 fmgr_info(finalfn_oid, &peraggstate->finalfn);
963 * If the transfn is strict and the initval is NULL, make sure
964 * input type and transtype are the same (or at least binary-
965 * compatible), so that it's OK to use the first input value as
966 * the initial transValue. This should have been checked at agg
967 * definition time, but just in case...
969 if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
972 * Note: use the type from the input expression here, not from
973 * pg_proc.proargtypes, because the latter might be 0.
974 * (Consider COUNT(*).)
976 Oid inputType = exprType(aggref->target);
978 if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
979 elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
983 if (aggref->aggdistinct)
986 * Note: use the type from the input expression here, not from
987 * pg_proc.proargtypes, because the latter might be 0.
988 * (Consider COUNT(*).)
990 Oid inputType = exprType(aggref->target);
993 peraggstate->inputType = inputType;
994 get_typlenbyval(inputType,
995 &peraggstate->inputtypeLen,
996 &peraggstate->inputtypeByVal);
998 eq_function = compatible_oper_funcid(makeList1(makeString("=")),
999 inputType, inputType,
1001 if (!OidIsValid(eq_function))
1002 elog(ERROR, "Unable to identify an equality operator for type %s",
1003 format_type_be(inputType));
1004 fmgr_info(eq_function, &(peraggstate->equalfn));
1005 peraggstate->sortOperator = any_ordering_op(inputType);
1006 peraggstate->sortstate = NULL;
1009 ReleaseSysCache(aggTuple);
1016 GetAggInitVal(Datum textInitVal, Oid transtype)
1024 strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
1026 tup = SearchSysCache(TYPEOID,
1027 ObjectIdGetDatum(transtype),
1029 if (!HeapTupleIsValid(tup))
1030 elog(ERROR, "GetAggInitVal: cache lookup failed on aggregate transition function return type %u", transtype);
1032 typinput = ((Form_pg_type) GETSTRUCT(tup))->typinput;
1033 typelem = ((Form_pg_type) GETSTRUCT(tup))->typelem;
1034 ReleaseSysCache(tup);
1036 initVal = OidFunctionCall3(typinput,
1037 CStringGetDatum(strInitVal),
1038 ObjectIdGetDatum(typelem),
1046 ExecCountSlotsAgg(Agg *node)
1048 return ExecCountSlotsNode(outerPlan(node)) +
1049 ExecCountSlotsNode(innerPlan(node)) +
1054 ExecEndAgg(Agg *node)
1056 AggState *aggstate = node->aggstate;
1059 ExecFreeProjectionInfo(&aggstate->csstate.cstate);
1062 * Make sure ExecFreeExprContext() frees the right expr context...
1064 aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory =
1066 ExecFreeExprContext(&aggstate->csstate.cstate);
1069 * ... and I free the others.
1071 MemoryContextDelete(aggstate->agg_cxt[0]);
1072 MemoryContextDelete(aggstate->agg_cxt[1]);
1074 outerPlan = outerPlan(node);
1075 ExecEndNode(outerPlan, (Plan *) node);
1077 /* clean up tuple table */
1078 ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
1079 if (aggstate->grp_firstTuple != NULL)
1081 heap_freetuple(aggstate->grp_firstTuple);
1082 aggstate->grp_firstTuple = NULL;
1087 ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
1089 AggState *aggstate = node->aggstate;
1090 ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
1092 aggstate->agg_done = false;
1093 if (aggstate->grp_firstTuple != NULL)
1095 heap_freetuple(aggstate->grp_firstTuple);
1096 aggstate->grp_firstTuple = NULL;
1098 MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * aggstate->numaggs);
1099 MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * aggstate->numaggs);
1102 * if chgParam of subnode is not null then plan will be re-scanned by
1103 * first ExecProcNode.
1105 if (((Plan *) node)->lefttree->chgParam == NULL)
1106 ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
1110 * aggregate_dummy - dummy execution routine for aggregate functions
1112 * This function is listed as the implementation (prosrc field) of pg_proc
1113 * entries for aggregate functions. Its only purpose is to throw an error
1114 * if someone mistakenly executes such a function in the normal way.
1116 * Perhaps someday we could assign real meaning to the prosrc field of
1120 aggregate_dummy(PG_FUNCTION_ARGS)
1122 elog(ERROR, "Aggregate function %u called as normal function",
1123 fcinfo->flinfo->fn_oid);
1124 return (Datum) 0; /* keep compiler quiet */