aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeAgg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r--src/backend/executor/nodeAgg.c151
1 files changed, 84 insertions, 67 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index f60f499e6be..e0f50bd66d1 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -19,7 +19,7 @@
* The agg's input type and transtype must be the same in this case!
*
* If transfunc is marked "strict" then NULL input_values are skipped,
- * keeping the previous transvalue. If transfunc is not strict then it
+ * keeping the previous transvalue. If transfunc is not strict then it
* is called for every input tuple and must deal with NULL initcond
* or NULL input_value for itself.
*
@@ -34,7 +34,7 @@
* are not allowed to accumulate until end of query. We do this by
* "ping-ponging" between two memory contexts; successive calls to the
* transfunc are executed in alternate contexts, passing the previous
- * transvalue that is in the other context. At the beginning of each
+ * transvalue that is in the other context. At the beginning of each
* tuple cycle we can reset the current output context to avoid memory
* usage growth. Note: we must use MemoryContextContains() to check
* whether the transfunc has perhaps handed us back one of its input
@@ -46,7 +46,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.75 2001/02/16 03:16:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.76 2001/03/22 03:59:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -130,8 +130,8 @@ typedef struct AggStatePerAggData
* an input tuple group and updated for each input tuple.
*
* For a simple (non DISTINCT) aggregate, we just feed the input values
- * straight to the transition function. If it's DISTINCT, we pass
- * the input values into a Tuplesort object; then at completion of the
+ * straight to the transition function. If it's DISTINCT, we pass the
+ * input values into a Tuplesort object; then at completion of the
* input tuple group, we scan the sorted values, eliminate duplicates,
* and run the transition function on the rest.
*/
@@ -144,20 +144,21 @@ typedef struct AggStatePerAggData
bool noTransValue; /* true if transValue not set yet */
/*
- * Note: noTransValue initially has the same value as transValueIsNull,
- * and if true both are cleared to false at the same time. They are
- * not the same though: if transfn later returns a NULL, we want to
- * keep that NULL and not auto-replace it with a later input value.
- * Only the first non-NULL input will be auto-substituted.
+ * Note: noTransValue initially has the same value as
+ * transValueIsNull, and if true both are cleared to false at the same
+ * time. They are not the same though: if transfn later returns a
+ * NULL, we want to keep that NULL and not auto-replace it with a
+ * later input value. Only the first non-NULL input will be
+ * auto-substituted.
*/
} AggStatePerAggData;
static void initialize_aggregate(AggStatePerAgg peraggstate);
static void advance_transition_function(AggStatePerAgg peraggstate,
- Datum newVal, bool isNull);
+ Datum newVal, bool isNull);
static void process_sorted_aggregate(AggState *aggstate,
- AggStatePerAgg peraggstate);
+ AggStatePerAgg peraggstate);
static void finalize_aggregate(AggStatePerAgg peraggstate,
Datum *resultVal, bool *resultIsNull);
@@ -195,8 +196,8 @@ initialize_aggregate(AggStatePerAgg peraggstate)
* (Re)set transValue to the initial value.
*
* Note that when the initial value is pass-by-ref, we just reuse it
- * without copying for each group. Hence, transition function
- * had better not scribble on its input, or it will fail for GROUP BY!
+ * without copying for each group. Hence, transition function had
+ * better not scribble on its input, or it will fail for GROUP BY!
*/
peraggstate->transValue = peraggstate->initValue;
peraggstate->transValueIsNull = peraggstate->initValueIsNull;
@@ -222,50 +223,55 @@ static void
advance_transition_function(AggStatePerAgg peraggstate,
Datum newVal, bool isNull)
{
- FunctionCallInfoData fcinfo;
+ FunctionCallInfoData fcinfo;
if (peraggstate->transfn.fn_strict)
{
if (isNull)
{
+
/*
- * For a strict transfn, nothing happens at a NULL input tuple;
- * we just keep the prior transValue. However, if the transtype
- * is pass-by-ref, we have to copy it into the new context
- * because the old one is going to get reset.
+ * For a strict transfn, nothing happens at a NULL input
+ * tuple; we just keep the prior transValue. However, if the
+ * transtype is pass-by-ref, we have to copy it into the new
+ * context because the old one is going to get reset.
*/
if (!peraggstate->transValueIsNull)
peraggstate->transValue = datumCopy(peraggstate->transValue,
- peraggstate->transtypeByVal,
- peraggstate->transtypeLen);
+ peraggstate->transtypeByVal,
+ peraggstate->transtypeLen);
return;
}
if (peraggstate->noTransValue)
{
+
/*
- * transValue has not been initialized. This is the first non-NULL
- * input value. We use it as the initial value for transValue.
- * (We already checked that the agg's input type is binary-
- * compatible with its transtype, so straight copy here is OK.)
+ * transValue has not been initialized. This is the first
+ * non-NULL input value. We use it as the initial value for
+ * transValue. (We already checked that the agg's input type
+ * is binary- compatible with its transtype, so straight copy
+ * here is OK.)
*
- * We had better copy the datum if it is pass-by-ref, since
- * the given pointer may be pointing into a scan tuple that
- * will be freed on the next iteration of the scan.
+ * We had better copy the datum if it is pass-by-ref, since the
+ * given pointer may be pointing into a scan tuple that will
+ * be freed on the next iteration of the scan.
*/
peraggstate->transValue = datumCopy(newVal,
- peraggstate->transtypeByVal,
- peraggstate->transtypeLen);
+ peraggstate->transtypeByVal,
+ peraggstate->transtypeLen);
peraggstate->transValueIsNull = false;
peraggstate->noTransValue = false;
return;
}
if (peraggstate->transValueIsNull)
{
+
/*
* Don't call a strict function with NULL inputs. Note it is
- * possible to get here despite the above tests, if the transfn
- * is strict *and* returned a NULL on a prior cycle. If that
- * happens we will propagate the NULL all the way to the end.
+ * possible to get here despite the above tests, if the
+ * transfn is strict *and* returned a NULL on a prior cycle.
+ * If that happens we will propagate the NULL all the way to
+ * the end.
*/
return;
}
@@ -283,14 +289,14 @@ advance_transition_function(AggStatePerAgg peraggstate,
newVal = FunctionCallInvoke(&fcinfo);
/*
- * If the transition function was uncooperative, it may have
- * given us a pass-by-ref result that points at the scan tuple
- * or the prior-cycle working memory. Copy it into the active
- * context if it doesn't look right.
+ * If the transition function was uncooperative, it may have given us
+ * a pass-by-ref result that points at the scan tuple or the
+ * prior-cycle working memory. Copy it into the active context if it
+ * doesn't look right.
*/
if (!peraggstate->transtypeByVal && !fcinfo.isnull &&
- ! MemoryContextContains(CurrentMemoryContext,
- DatumGetPointer(newVal)))
+ !MemoryContextContains(CurrentMemoryContext,
+ DatumGetPointer(newVal)))
newVal = datumCopy(newVal,
peraggstate->transtypeByVal,
peraggstate->transtypeLen);
@@ -302,7 +308,7 @@ advance_transition_function(AggStatePerAgg peraggstate,
/*
* Run the transition function for a DISTINCT aggregate. This is called
* after we have completed entering all the input values into the sort
- * object. We complete the sort, read out the values in sorted order,
+ * object. We complete the sort, read out the values in sorted order,
* and run the transition function on each non-duplicate value.
*
* When called, CurrentMemoryContext should be the per-query context.
@@ -321,19 +327,21 @@ process_sorted_aggregate(AggState *aggstate,
/*
* Note: if input type is pass-by-ref, the datums returned by the sort
- * are freshly palloc'd in the per-query context, so we must be careful
- * to pfree them when they are no longer needed.
+ * are freshly palloc'd in the per-query context, so we must be
+ * careful to pfree them when they are no longer needed.
*/
while (tuplesort_getdatum(peraggstate->sortstate, true,
&newVal, &isNull))
{
+
/*
* DISTINCT always suppresses nulls, per SQL spec, regardless of
* the transition function's strictness.
*/
if (isNull)
continue;
+
/*
* Clear and select the current working context for evaluation of
* the equality function and transition function.
@@ -349,6 +357,7 @@ process_sorted_aggregate(AggState *aggstate,
/* equal to prior, so forget this one */
if (!peraggstate->inputtypeByVal)
pfree(DatumGetPointer(newVal));
+
/*
* note we do NOT flip contexts in this case, so no need to
* copy prior transValue to other context.
@@ -357,6 +366,7 @@ process_sorted_aggregate(AggState *aggstate,
else
{
advance_transition_function(peraggstate, newVal, false);
+
/*
* Make the other context current so that this transition
* result is preserved.
@@ -389,12 +399,13 @@ static void
finalize_aggregate(AggStatePerAgg peraggstate,
Datum *resultVal, bool *resultIsNull)
{
+
/*
* Apply the agg's finalfn if one is provided, else return transValue.
*/
if (OidIsValid(peraggstate->finalfn_oid))
{
- FunctionCallInfoData fcinfo;
+ FunctionCallInfoData fcinfo;
MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &peraggstate->finalfn;
@@ -422,9 +433,9 @@ finalize_aggregate(AggStatePerAgg peraggstate,
/*
* If result is pass-by-ref, make sure it is in the right context.
*/
- if (!peraggstate->resulttypeByVal && ! *resultIsNull &&
- ! MemoryContextContains(CurrentMemoryContext,
- DatumGetPointer(*resultVal)))
+ if (!peraggstate->resulttypeByVal && !*resultIsNull &&
+ !MemoryContextContains(CurrentMemoryContext,
+ DatumGetPointer(*resultVal)))
*resultVal = datumCopy(*resultVal,
peraggstate->resulttypeByVal,
peraggstate->resulttypeLen);
@@ -480,7 +491,8 @@ ExecAgg(Agg *node)
peragg = aggstate->peragg;
/*
- * We loop retrieving groups until we find one matching node->plan.qual
+ * We loop retrieving groups until we find one matching
+ * node->plan.qual
*/
do
{
@@ -578,19 +590,19 @@ ExecAgg(Agg *node)
* calculation, and stash results in the per-output-tuple context.
*
* This is a bit tricky when there are both DISTINCT and plain
- * aggregates: we must first finalize all the plain aggs and then all
- * the DISTINCT ones. This is needed because the last transition
- * values for the plain aggs are stored in the not-current working
- * context, and we have to evaluate those aggs (and stash the results
- * in the output tup_cxt!) before we start flipping contexts again
- * in process_sorted_aggregate.
+ * aggregates: we must first finalize all the plain aggs and then
+ * all the DISTINCT ones. This is needed because the last
+ * transition values for the plain aggs are stored in the
+ * not-current working context, and we have to evaluate those aggs
+ * (and stash the results in the output tup_cxt!) before we start
+ * flipping contexts again in process_sorted_aggregate.
*/
oldContext = MemoryContextSwitchTo(aggstate->tup_cxt);
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
{
AggStatePerAgg peraggstate = &peragg[aggno];
- if (! peraggstate->aggref->aggdistinct)
+ if (!peraggstate->aggref->aggdistinct)
finalize_aggregate(peraggstate,
&aggvalues[aggno], &aggnulls[aggno]);
}
@@ -766,21 +778,22 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
/*
- * We actually need three separate expression memory contexts: one
- * for calculating per-output-tuple values (ie, the finished aggregate
+ * We actually need three separate expression memory contexts: one for
+ * calculating per-output-tuple values (ie, the finished aggregate
* results), and two that we ping-pong between for per-input-tuple
* evaluation of input expressions and transition functions. The
- * context made by ExecAssignExprContext() is used as the output context.
+ * context made by ExecAssignExprContext() is used as the output
+ * context.
*/
aggstate->tup_cxt =
aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory;
- aggstate->agg_cxt[0] =
+ aggstate->agg_cxt[0] =
AllocSetContextCreate(CurrentMemoryContext,
"AggExprContext1",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
- aggstate->agg_cxt[1] =
+ aggstate->agg_cxt[1] =
AllocSetContextCreate(CurrentMemoryContext,
"AggExprContext2",
ALLOCSET_DEFAULT_MINSIZE,
@@ -882,30 +895,32 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
/*
* If the transfn is strict and the initval is NULL, make sure
* input type and transtype are the same (or at least binary-
- * compatible), so that it's OK to use the first input value
- * as the initial transValue. This should have been checked at
- * agg definition time, but just in case...
+ * compatible), so that it's OK to use the first input value as
+ * the initial transValue. This should have been checked at agg
+ * definition time, but just in case...
*/
if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
{
+
/*
- * Note: use the type from the input expression here,
- * not aggform->aggbasetype, because the latter might be 0.
+ * Note: use the type from the input expression here, not
+ * aggform->aggbasetype, because the latter might be 0.
* (Consider COUNT(*).)
*/
Oid inputType = exprType(aggref->target);
if (inputType != aggform->aggtranstype &&
- ! IS_BINARY_COMPATIBLE(inputType, aggform->aggtranstype))
+ !IS_BINARY_COMPATIBLE(inputType, aggform->aggtranstype))
elog(ERROR, "Aggregate %s needs to have compatible input type and transition type",
aggname);
}
if (aggref->aggdistinct)
{
+
/*
- * Note: use the type from the input expression here,
- * not aggform->aggbasetype, because the latter might be 0.
+ * Note: use the type from the input expression here, not
+ * aggform->aggbasetype, because the latter might be 0.
* (Consider COUNT(*).)
*/
Oid inputType = exprType(aggref->target);
@@ -947,12 +962,14 @@ ExecEndAgg(Agg *node)
Plan *outerPlan;
ExecFreeProjectionInfo(&aggstate->csstate.cstate);
+
/*
* Make sure ExecFreeExprContext() frees the right expr context...
*/
aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory =
aggstate->tup_cxt;
ExecFreeExprContext(&aggstate->csstate.cstate);
+
/*
* ... and I free the others.
*/