Skip to content

Commit bf61873

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 3b7a96a commit bf61873

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,12 +1168,26 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
11681168
return true;
11691169
}
11701170

1171-
if (IsA(node, NextValueExpr))
1171+
else if (IsA(node, NextValueExpr))
11721172
{
11731173
if (max_parallel_hazard_test(PROPARALLEL_UNSAFE, context))
11741174
return true;
11751175
}
11761176

1177+
/*
1178+
* Treat window functions as parallel-restricted because we aren't sure
1179+
* whether the input row ordering is fully deterministic, and the output
1180+
* of window functions might vary across workers if not. (In some cases,
1181+
* like where the window frame orders by a primary key, we could relax
1182+
* this restriction. But it doesn't currently seem worth expending extra
1183+
* effort to do so.)
1184+
*/
1185+
else if (IsA(node, WindowFunc))
1186+
{
1187+
if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
1188+
return true;
1189+
}
1190+
11771191
/*
11781192
* As a notational convenience for callers, look through RestrictInfo.
11791193
*/

src/test/regress/expected/select_parallel.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,32 @@ explain (costs off)
573573
Index Cond: (unique1 = 1)
574574
(5 rows)
575575

576+
-- Window function calculation can't be pushed to workers.
577+
explain (costs off, verbose)
578+
select count(*) from tenk1 a where (unique1, two) in
579+
(select unique1, row_number() over() from tenk1 b);
580+
QUERY PLAN
581+
----------------------------------------------------------------------------------------------
582+
Aggregate
583+
Output: count(*)
584+
-> Hash Semi Join
585+
Hash Cond: ((a.unique1 = b.unique1) AND (a.two = (row_number() OVER (?))))
586+
-> Gather
587+
Output: a.unique1, a.two
588+
Workers Planned: 4
589+
-> Parallel Seq Scan on public.tenk1 a
590+
Output: a.unique1, a.two
591+
-> Hash
592+
Output: b.unique1, (row_number() OVER (?))
593+
-> WindowAgg
594+
Output: b.unique1, row_number() OVER (?)
595+
-> Gather
596+
Output: b.unique1
597+
Workers Planned: 4
598+
-> Parallel Index Only Scan using tenk1_unique1 on public.tenk1 b
599+
Output: b.unique1
600+
(18 rows)
601+
576602
-- to increase the parallel query test coverage
577603
EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1;
578604
QUERY PLAN

src/test/regress/sql/select_parallel.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ set force_parallel_mode=1;
204204
explain (costs off)
205205
select stringu1::int2 from tenk1 where unique1 = 1;
206206

207+
-- Window function calculation can't be pushed to workers.
208+
explain (costs off, verbose)
209+
select count(*) from tenk1 a where (unique1, two) in
210+
(select unique1, row_number() over() from tenk1 b);
211+
212+
207213
-- to increase the parallel query test coverage
208214
EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1;
209215

0 commit comments

Comments
 (0)