Skip to content

Commit db80acf

Browse files
committed
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
1 parent 7cd0fd6 commit db80acf

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

src/backend/executor/nodeAgg.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,16 +1575,19 @@ finalize_aggregates(AggState *aggstate,
15751575
Datum *aggvalues = econtext->ecxt_aggvalues;
15761576
bool *aggnulls = econtext->ecxt_aggnulls;
15771577
int aggno;
1578+
int transno;
15781579

15791580
Assert(currentSet == 0 ||
15801581
((Agg *) aggstate->ss.ps.plan)->aggstrategy != AGG_HASHED);
15811582

15821583
aggstate->current_set = currentSet;
15831584

1584-
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1585+
/*
1586+
* If there were any DISTINCT and/or ORDER BY aggregates, sort their
1587+
* inputs and run the transition functions.
1588+
*/
1589+
for (transno = 0; transno < aggstate->numtrans; transno++)
15851590
{
1586-
AggStatePerAgg peragg = &peraggs[aggno];
1587-
int transno = peragg->transno;
15881591
AggStatePerTrans pertrans = &aggstate->pertrans[transno];
15891592
AggStatePerGroup pergroupstate;
15901593

@@ -1603,6 +1606,18 @@ finalize_aggregates(AggState *aggstate,
16031606
pertrans,
16041607
pergroupstate);
16051608
}
1609+
}
1610+
1611+
/*
1612+
* Run the final functions.
1613+
*/
1614+
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1615+
{
1616+
AggStatePerAgg peragg = &peraggs[aggno];
1617+
int transno = peragg->transno;
1618+
AggStatePerGroup pergroupstate;
1619+
1620+
pergroupstate = &pergroup[transno + (currentSet * (aggstate->numtrans))];
16061621

16071622
if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
16081623
finalize_partialaggregate(aggstate, peragg, pergroupstate,

src/test/regress/expected/aggregates.out

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,6 +1816,15 @@ NOTICE: avg_transfn called with 3
18161816
2 | 4
18171817
(1 row)
18181818

1819+
-- same as previous one, but with DISTINCT, which requires sorting the input.
1820+
select my_avg(distinct one),my_sum(distinct one) from (values(1),(3),(1)) t(one);
1821+
NOTICE: avg_transfn called with 1
1822+
NOTICE: avg_transfn called with 3
1823+
my_avg | my_sum
1824+
--------+--------
1825+
2 | 4
1826+
(1 row)
1827+
18191828
-- shouldn't share states due to the distinctness not matching.
18201829
select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one);
18211830
NOTICE: avg_transfn called with 1

src/test/regress/sql/aggregates.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,9 @@ select my_avg(one),my_avg(one) from (values(1),(3)) t(one);
727727
-- aggregate state should be shared as transfn is the same for both aggs.
728728
select my_avg(one),my_sum(one) from (values(1),(3)) t(one);
729729

730+
-- same as previous one, but with DISTINCT, which requires sorting the input.
731+
select my_avg(distinct one),my_sum(distinct one) from (values(1),(3),(1)) t(one);
732+
730733
-- shouldn't share states due to the distinctness not matching.
731734
select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one);
732735

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy