Skip to content

Commit f658235

Browse files
author
Amit Kapila
committed
Prohibit pushing subqueries containing window function calculation to
workers. Allowing window function calculation in workers leads to inconsistent results because if the input row ordering is not fully deterministic, the output of window functions might vary across workers. The fix is to treat them as parallel-restricted. In the passing, improve the coding pattern in max_parallel_hazard_walker so that it has a chain of mutually-exclusive if ... else if ... else if ... else if ... IsA tests. Reported-by: Marko Tiikkaja Bug: 15324 Author: Amit Kapila Reviewed-by: Tom Lane Backpatch-through: 9.6 Discussion: https://postgr.es/m/CAL9smLAnfPJCDUUG4ckX2iznj53V7VSMsYefzZieN93YxTNOcw@mail.gmail.com
1 parent d8030c6 commit f658235

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,20 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
11611161
return true;
11621162
}
11631163

1164+
/*
1165+
* Treat window functions as parallel-restricted because we aren't sure
1166+
* whether the input row ordering is fully deterministic, and the output
1167+
* of window functions might vary across workers if not. (In some cases,
1168+
* like where the window frame orders by a primary key, we could relax
1169+
* this restriction. But it doesn't currently seem worth expending extra
1170+
* effort to do so.)
1171+
*/
1172+
else if (IsA(node, WindowFunc))
1173+
{
1174+
if (!context->allow_restricted)
1175+
return true;
1176+
}
1177+
11641178
/*
11651179
* As a notational convenience for callers, look through RestrictInfo.
11661180
*/

src/test/regress/expected/select_parallel.out

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,29 @@ select count(*) from tenk1;
182182
(1 row)
183183

184184
reset role;
185+
-- Window function calculation can't be pushed to workers.
186+
explain (costs off, verbose)
187+
select count(*) from tenk1 a where (unique1, two) in
188+
(select unique1, row_number() over() from tenk1 b);
189+
QUERY PLAN
190+
------------------------------------------------------------------------------------
191+
Aggregate
192+
Output: count(*)
193+
-> Hash Semi Join
194+
Hash Cond: ((a.unique1 = b.unique1) AND (a.two = (row_number() OVER (?))))
195+
-> Gather
196+
Output: a.unique1, a.two
197+
Workers Planned: 4
198+
-> Parallel Seq Scan on public.tenk1 a
199+
Output: a.unique1, a.two
200+
-> Hash
201+
Output: b.unique1, (row_number() OVER (?))
202+
-> WindowAgg
203+
Output: b.unique1, row_number() OVER (?)
204+
-> Index Only Scan using tenk1_unique1 on public.tenk1 b
205+
Output: b.unique1
206+
(15 rows)
207+
185208
explain (costs off)
186209
select stringu1::int2 from tenk1 where unique1 = 1;
187210
QUERY PLAN

src/test/regress/sql/select_parallel.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ drop role regress_parallel_worker;
8383
select count(*) from tenk1;
8484
reset role;
8585

86+
-- Window function calculation can't be pushed to workers.
87+
explain (costs off, verbose)
88+
select count(*) from tenk1 a where (unique1, two) in
89+
(select unique1, row_number() over() from tenk1 b);
90+
8691
explain (costs off)
8792
select stringu1::int2 from tenk1 where unique1 = 1;
8893

0 commit comments

Comments
 (0)