diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2016-12-20 09:20:17 +0200 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2016-12-20 09:20:30 +0200 |
commit | ce92fc4e2540d0ce554e498adb27f0ef29199b94 (patch) | |
tree | c45da3496e3f375558e4fa4f046fdf7601383195 /src/backend/executor/nodeAgg.c | |
parent | 3f07eff104793cfd82bfd3e093991695221abfd8 (diff) | |
download | postgresql-ce92fc4e2540d0ce554e498adb27f0ef29199b94.tar.gz postgresql-ce92fc4e2540d0ce554e498adb27f0ef29199b94.zip |
Fix sharing Agg transition state of DISTINCT or ordered aggs.
If a query contained two aggregates that could share the transition value,
we would correctly collect the input into a tuplesort only once, but
incorrectly run the transition function over the accumulated input twice,
in finalize_aggregates(). That caused a crash, when we tried to call
tuplesort_performsort() on an already-freed NULL tuplestore.
Backport to 9.6, where sharing of transition state and this bug were
introduced.
Analysis by Tom Lane.
Discussion: https://www.postgresql.org/message-id/ac5b0b69-744c-9114-6218-8300ac920e61@iki.fi
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r-- | src/backend/executor/nodeAgg.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 89e8c47fec2..16af185c77f 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -1565,16 +1565,19 @@ finalize_aggregates(AggState *aggstate, Datum *aggvalues = econtext->ecxt_aggvalues; bool *aggnulls = econtext->ecxt_aggnulls; int aggno; + int transno; Assert(currentSet == 0 || ((Agg *) aggstate->ss.ps.plan)->aggstrategy != AGG_HASHED); aggstate->current_set = currentSet; - for (aggno = 0; aggno < aggstate->numaggs; aggno++) + /* + * If there were any DISTINCT and/or ORDER BY aggregates, sort their + * inputs and run the transition functions. + */ + for (transno = 0; transno < aggstate->numtrans; transno++) { - AggStatePerAgg peragg = &peraggs[aggno]; - int transno = peragg->transno; AggStatePerTrans pertrans = &aggstate->pertrans[transno]; AggStatePerGroup pergroupstate; @@ -1593,6 +1596,18 @@ finalize_aggregates(AggState *aggstate, pertrans, pergroupstate); } + } + + /* + * Run the final functions. + */ + for (aggno = 0; aggno < aggstate->numaggs; aggno++) + { + AggStatePerAgg peragg = &peraggs[aggno]; + int transno = peragg->transno; + AggStatePerGroup pergroupstate; + + pergroupstate = &pergroup[transno + (currentSet * (aggstate->numtrans))]; if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit)) finalize_partialaggregate(aggstate, peragg, pergroupstate, |