mirror of
https://github.com/postgres/postgres.git
synced 2025-05-11 05:41:32 +03:00
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
This commit is contained in:
parent
3f07eff104
commit
ce92fc4e25
@ -1565,16 +1565,19 @@ finalize_aggregates(AggState *aggstate,
|
|||||||
Datum *aggvalues = econtext->ecxt_aggvalues;
|
Datum *aggvalues = econtext->ecxt_aggvalues;
|
||||||
bool *aggnulls = econtext->ecxt_aggnulls;
|
bool *aggnulls = econtext->ecxt_aggnulls;
|
||||||
int aggno;
|
int aggno;
|
||||||
|
int transno;
|
||||||
|
|
||||||
Assert(currentSet == 0 ||
|
Assert(currentSet == 0 ||
|
||||||
((Agg *) aggstate->ss.ps.plan)->aggstrategy != AGG_HASHED);
|
((Agg *) aggstate->ss.ps.plan)->aggstrategy != AGG_HASHED);
|
||||||
|
|
||||||
aggstate->current_set = currentSet;
|
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];
|
AggStatePerTrans pertrans = &aggstate->pertrans[transno];
|
||||||
AggStatePerGroup pergroupstate;
|
AggStatePerGroup pergroupstate;
|
||||||
|
|
||||||
@ -1593,6 +1596,18 @@ finalize_aggregates(AggState *aggstate,
|
|||||||
pertrans,
|
pertrans,
|
||||||
pergroupstate);
|
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))
|
if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
|
||||||
finalize_partialaggregate(aggstate, peragg, pergroupstate,
|
finalize_partialaggregate(aggstate, peragg, pergroupstate,
|
||||||
|
@ -1816,6 +1816,15 @@ NOTICE: avg_transfn called with 3
|
|||||||
2 | 4
|
2 | 4
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- same as previous one, but with DISTINCT, which requires sorting the input.
|
||||||
|
select my_avg(distinct one),my_sum(distinct one) from (values(1),(3),(1)) t(one);
|
||||||
|
NOTICE: avg_transfn called with 1
|
||||||
|
NOTICE: avg_transfn called with 3
|
||||||
|
my_avg | my_sum
|
||||||
|
--------+--------
|
||||||
|
2 | 4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- shouldn't share states due to the distinctness not matching.
|
-- shouldn't share states due to the distinctness not matching.
|
||||||
select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one);
|
select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one);
|
||||||
NOTICE: avg_transfn called with 1
|
NOTICE: avg_transfn called with 1
|
||||||
|
@ -727,6 +727,9 @@ select my_avg(one),my_avg(one) from (values(1),(3)) t(one);
|
|||||||
-- aggregate state should be shared as transfn is the same for both aggs.
|
-- aggregate state should be shared as transfn is the same for both aggs.
|
||||||
select my_avg(one),my_sum(one) from (values(1),(3)) t(one);
|
select my_avg(one),my_sum(one) from (values(1),(3)) t(one);
|
||||||
|
|
||||||
|
-- same as previous one, but with DISTINCT, which requires sorting the input.
|
||||||
|
select my_avg(distinct one),my_sum(distinct one) from (values(1),(3),(1)) t(one);
|
||||||
|
|
||||||
-- shouldn't share states due to the distinctness not matching.
|
-- shouldn't share states due to the distinctness not matching.
|
||||||
select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one);
|
select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user