mirror of
https://github.com/postgres/postgres.git
synced 2026-07-15 04:40:58 -04:00
Fix volatile function evaluation in eager aggregation
Pushing aggregates containing volatile functions below a join can violate volatility semantics by changing the number of times the function is executed. Here we check the Aggref nodes in the targetlist and havingQual for volatile functions and disable eager aggregation when such functions are present. Author: Richard Guo <guofenglinux@gmail.com> Reviewed-by: Matheus Alcantara <matheusssilv97@gmail.com> Discussion: https://postgr.es/m/CAMbWs48A53PY1Y4zoj7YhxPww9fO1hfnbdntKfA855zpXfVFRA@mail.gmail.com
This commit is contained in:
parent
bd94845e8c
commit
3a08a2a8b4
3 changed files with 63 additions and 0 deletions
|
|
@ -810,6 +810,17 @@ create_agg_clause_infos(PlannerInfo *root)
|
|||
Assert(aggref->aggorder == NIL);
|
||||
Assert(aggref->aggdistinct == NIL);
|
||||
|
||||
/*
|
||||
* We cannot push down aggregates that contain volatile functions.
|
||||
* Doing so would change the number of times the function is
|
||||
* evaluated.
|
||||
*/
|
||||
if (contain_volatile_functions((Node *) aggref))
|
||||
{
|
||||
eager_agg_applicable = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are any securityQuals, do not try to apply eager
|
||||
* aggregation if any non-leakproof aggregate functions are present.
|
||||
|
|
|
|||
|
|
@ -428,6 +428,44 @@ GROUP BY t1.a ORDER BY t1.a;
|
|||
|
||||
RESET geqo;
|
||||
RESET geqo_threshold;
|
||||
-- Ensure eager aggregation is not applied because random() is a volatile
|
||||
-- function
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT t1.a, avg(t2.c + random())
|
||||
FROM eager_agg_t1 t1
|
||||
JOIN eager_agg_t2 t2 ON t1.b = t2.b
|
||||
GROUP BY t1.a ORDER BY t1.a;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
GroupAggregate
|
||||
Group Key: t1.a
|
||||
-> Sort
|
||||
Sort Key: t1.a
|
||||
-> Hash Join
|
||||
Hash Cond: (t2.b = t1.b)
|
||||
-> Seq Scan on eager_agg_t2 t2
|
||||
-> Hash
|
||||
-> Seq Scan on eager_agg_t1 t1
|
||||
(9 rows)
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT t1.a, avg(t2.c) FILTER (WHERE random() > 0.5)
|
||||
FROM eager_agg_t1 t1
|
||||
JOIN eager_agg_t2 t2 ON t1.b = t2.b
|
||||
GROUP BY t1.a ORDER BY t1.a;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
GroupAggregate
|
||||
Group Key: t1.a
|
||||
-> Sort
|
||||
Sort Key: t1.a
|
||||
-> Hash Join
|
||||
Hash Cond: (t2.b = t1.b)
|
||||
-> Seq Scan on eager_agg_t2 t2
|
||||
-> Hash
|
||||
-> Seq Scan on eager_agg_t1 t1
|
||||
(9 rows)
|
||||
|
||||
DROP TABLE eager_agg_t1;
|
||||
DROP TABLE eager_agg_t2;
|
||||
DROP TABLE eager_agg_t3;
|
||||
|
|
|
|||
|
|
@ -163,6 +163,20 @@ GROUP BY t1.a ORDER BY t1.a;
|
|||
RESET geqo;
|
||||
RESET geqo_threshold;
|
||||
|
||||
-- Ensure eager aggregation is not applied because random() is a volatile
|
||||
-- function
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT t1.a, avg(t2.c + random())
|
||||
FROM eager_agg_t1 t1
|
||||
JOIN eager_agg_t2 t2 ON t1.b = t2.b
|
||||
GROUP BY t1.a ORDER BY t1.a;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT t1.a, avg(t2.c) FILTER (WHERE random() > 0.5)
|
||||
FROM eager_agg_t1 t1
|
||||
JOIN eager_agg_t2 t2 ON t1.b = t2.b
|
||||
GROUP BY t1.a ORDER BY t1.a;
|
||||
|
||||
DROP TABLE eager_agg_t1;
|
||||
DROP TABLE eager_agg_t2;
|
||||
DROP TABLE eager_agg_t3;
|
||||
|
|
|
|||
Loading…
Reference in a new issue