From 6e5c499cad8a703d48062f0103d0adbde1ed65c4 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Wed, 13 May 2015 21:03:16 +0200 Subject: [PATCH] Separate out initialize_aggregate from initialize_aggregates. --- src/backend/executor/nodeAgg.c | 155 +++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 67 deletions(-) diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index fc1759f832..9b93a0ec85 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -387,6 +387,90 @@ static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate); static Datum GetAggInitVal(Datum textInitVal, Oid transtype); +/* + * (Re)Initialize an individual aggregate. + * + * This function handles only one grouping set (already set in + * aggstate->current_set). + * + * When called, CurrentMemoryContext should be the per-query context. + */ +static void +initialize_aggregate(AggState *aggstate, AggStatePerAgg peraggstate, + AggStatePerGroup pergroupstate) +{ + /* + * Start a fresh sort operation for each DISTINCT/ORDER BY aggregate. + */ + if (peraggstate->numSortCols > 0) + { + /* + * In case of rescan, maybe there could be an uncompleted sort + * operation? Clean it up if so. + */ + if (peraggstate->sortstates[aggstate->current_set]) + tuplesort_end(peraggstate->sortstates[aggstate->current_set]); + + + /* + * We use a plain Datum sorter when there's a single input column; + * otherwise sort the full tuple. (See comments for + * process_ordered_aggregate_single.) + * + * In the future, we should consider forcing the + * tuplesort_begin_heap() case when the abbreviated key optimization + * can thereby be used, even when numInputs is 1. + */ + if (peraggstate->numInputs == 1) + peraggstate->sortstates[aggstate->current_set] = + tuplesort_begin_datum(peraggstate->evaldesc->attrs[0]->atttypid, + peraggstate->sortOperators[0], + peraggstate->sortCollations[0], + peraggstate->sortNullsFirst[0], + work_mem, false); + else + peraggstate->sortstates[aggstate->current_set] = + tuplesort_begin_heap(peraggstate->evaldesc, + peraggstate->numSortCols, + peraggstate->sortColIdx, + peraggstate->sortOperators, + peraggstate->sortCollations, + peraggstate->sortNullsFirst, + work_mem, false); + } + + /* + * (Re)set transValue to the initial value. + * + * Note that when the initial value is pass-by-ref, we must copy + * it (into the aggcontext) since we will pfree the transValue + * later. + */ + if (peraggstate->initValueIsNull) + pergroupstate->transValue = peraggstate->initValue; + else + { + MemoryContext oldContext; + + oldContext = MemoryContextSwitchTo( + aggstate->aggcontexts[aggstate->current_set]->ecxt_per_tuple_memory); + pergroupstate->transValue = datumCopy(peraggstate->initValue, + peraggstate->transtypeByVal, + peraggstate->transtypeLen); + MemoryContextSwitchTo(oldContext); + } + pergroupstate->transValueIsNull = peraggstate->initValueIsNull; + + /* + * If the initial value for the transition state doesn't exist in + * the pg_aggregate table then we will let the first non-NULL + * value returned from the outer procNode become the initial + * value. (This is useful for aggregates like max() and min().) + * The noTransValue flag signals that we still need to do this. + */ + pergroupstate->noTransValue = peraggstate->initValueIsNull; +} + /* * Initialize all aggregates for a new group of input values. * @@ -414,78 +498,15 @@ initialize_aggregates(AggState *aggstate, { AggStatePerAgg peraggstate = &peragg[aggno]; - /* - * Start a fresh sort operation for each DISTINCT/ORDER BY aggregate. - */ - if (peraggstate->numSortCols > 0) - { - for (setno = 0; setno < numReset; setno++) - { - /* - * In case of rescan, maybe there could be an uncompleted sort - * operation? Clean it up if so. - */ - if (peraggstate->sortstates[setno]) - tuplesort_end(peraggstate->sortstates[setno]); - - /* - * We use a plain Datum sorter when there's a single input column; - * otherwise sort the full tuple. (See comments for - * process_ordered_aggregate_single.) - * - * In the future, we should consider forcing the - * tuplesort_begin_heap() case when the abbreviated key - * optimization can thereby be used, even when numInputs is 1. - */ - peraggstate->sortstates[setno] = - (peraggstate->numInputs == 1) ? - tuplesort_begin_datum(peraggstate->evaldesc->attrs[0]->atttypid, - peraggstate->sortOperators[0], - peraggstate->sortCollations[0], - peraggstate->sortNullsFirst[0], - work_mem, false) : - tuplesort_begin_heap(peraggstate->evaldesc, - peraggstate->numSortCols, - peraggstate->sortColIdx, - peraggstate->sortOperators, - peraggstate->sortCollations, - peraggstate->sortNullsFirst, - work_mem, false); - } - } - for (setno = 0; setno < numReset; setno++) { - AggStatePerGroup pergroupstate = &pergroup[aggno + (setno * (aggstate->numaggs))]; + AggStatePerGroup pergroupstate; - /* - * (Re)set transValue to the initial value. - * - * Note that when the initial value is pass-by-ref, we must copy it - * (into the aggcontext) since we will pfree the transValue later. - */ - if (peraggstate->initValueIsNull) - pergroupstate->transValue = peraggstate->initValue; - else - { - MemoryContext oldContext; + pergroupstate = &pergroup[aggno + (setno * (aggstate->numaggs))]; - oldContext = MemoryContextSwitchTo(aggstate->aggcontexts[setno]->ecxt_per_tuple_memory); - pergroupstate->transValue = datumCopy(peraggstate->initValue, - peraggstate->transtypeByVal, - peraggstate->transtypeLen); - MemoryContextSwitchTo(oldContext); - } - pergroupstate->transValueIsNull = peraggstate->initValueIsNull; + aggstate->current_set = setno; - /* - * If the initial value for the transition state doesn't exist in the - * pg_aggregate table then we will let the first non-NULL value - * returned from the outer procNode become the initial value. (This is - * useful for aggregates like max() and min().) The noTransValue flag - * signals that we still need to do this. - */ - pergroupstate->noTransValue = peraggstate->initValueIsNull; + initialize_aggregate(aggstate, peraggstate, pergroupstate); } } } -- 2.39.5