treat_window_func_calc_parallel_restricted_v1.patch
application/octet-stream
Filename: treat_window_func_calc_parallel_restricted_v1.patch
Type: application/octet-stream
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/optimizer/util/clauses.c | 13 | 0 |
| src/include/catalog/pg_proc.dat | 49 | 38 |
| src/test/regress/expected/select_parallel.out | 15 | 0 |
| src/test/regress/sql/select_parallel.sql | 4 | 0 |
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a04ad6e..1c7136f 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -1197,6 +1197,19 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
}
/*
+ * Treat window functions as parallel-restricted as the row ordering
+ * induced by them is non-deterministic. We can relax this condition for
+ * cases where the row ordering can be deterministic like when there is
+ * an ORDER BY on the primary key, but those cases don't seem to be
+ * interesting enough to have additional checks.
+ */
+ if (IsA(node, WindowFunc))
+ {
+ if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
+ return true;
+ }
+
+ /*
* As a notational convenience for callers, look through RestrictInfo.
*/
else if (IsA(node, RestrictInfo))
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index a146510..a641b8c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -9413,51 +9413,62 @@
# SQL-spec window functions
{ oid => '3100', descr => 'row number within partition',
proname => 'row_number', prokind => 'w', proisstrict => 'f',
- prorettype => 'int8', proargtypes => '', prosrc => 'window_row_number' },
+ proparallel => 'r', prorettype => 'int8', proargtypes => '',
+ prosrc => 'window_row_number' },
{ oid => '3101', descr => 'integer rank with gaps',
- proname => 'rank', prokind => 'w', proisstrict => 'f', prorettype => 'int8',
- proargtypes => '', prosrc => 'window_rank' },
+ proname => 'rank', prokind => 'w', proisstrict => 'f', proparallel => 'r',
+ prorettype => 'int8', proargtypes => '', prosrc => 'window_rank' },
{ oid => '3102', descr => 'integer rank without gaps',
proname => 'dense_rank', prokind => 'w', proisstrict => 'f',
- prorettype => 'int8', proargtypes => '', prosrc => 'window_dense_rank' },
+ proparallel => 'r', prorettype => 'int8', proargtypes => '',
+ prosrc => 'window_dense_rank' },
{ oid => '3103', descr => 'fractional rank within partition',
proname => 'percent_rank', prokind => 'w', proisstrict => 'f',
- prorettype => 'float8', proargtypes => '', prosrc => 'window_percent_rank' },
+ proparallel => 'r', prorettype => 'float8', proargtypes => '',
+ prosrc => 'window_percent_rank' },
{ oid => '3104', descr => 'fractional row number within partition',
proname => 'cume_dist', prokind => 'w', proisstrict => 'f',
- prorettype => 'float8', proargtypes => '', prosrc => 'window_cume_dist' },
+ proparallel => 'r', prorettype => 'float8', proargtypes => '',
+ prosrc => 'window_cume_dist' },
{ oid => '3105', descr => 'split rows into N groups',
- proname => 'ntile', prokind => 'w', prorettype => 'int4',
- proargtypes => 'int4', prosrc => 'window_ntile' },
+ proname => 'ntile', prokind => 'w', proparallel => 'r',
+ prorettype => 'int4', proargtypes => 'int4', prosrc => 'window_ntile' },
{ oid => '3106', descr => 'fetch the preceding row value',
- proname => 'lag', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement', prosrc => 'window_lag' },
+ proname => 'lag', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement',
+ prosrc => 'window_lag' },
{ oid => '3107', descr => 'fetch the Nth preceding row value',
- proname => 'lag', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement int4', prosrc => 'window_lag_with_offset' },
+ proname => 'lag', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement int4',
+ prosrc => 'window_lag_with_offset' },
{ oid => '3108', descr => 'fetch the Nth preceding row value with default',
- proname => 'lag', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement int4 anyelement',
+ proname => 'lag', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement int4 anyelement',
prosrc => 'window_lag_with_offset_and_default' },
{ oid => '3109', descr => 'fetch the following row value',
- proname => 'lead', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement', prosrc => 'window_lead' },
+ proname => 'lead', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement',
+ prosrc => 'window_lead' },
{ oid => '3110', descr => 'fetch the Nth following row value',
- proname => 'lead', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement int4', prosrc => 'window_lead_with_offset' },
+ proname => 'lead', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement int4',
+ prosrc => 'window_lead_with_offset' },
{ oid => '3111', descr => 'fetch the Nth following row value with default',
- proname => 'lead', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement int4 anyelement',
+ proname => 'lead', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement int4 anyelement',
prosrc => 'window_lead_with_offset_and_default' },
{ oid => '3112', descr => 'fetch the first row value',
- proname => 'first_value', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement', prosrc => 'window_first_value' },
+ proname => 'first_value', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement',
+ prosrc => 'window_first_value' },
{ oid => '3113', descr => 'fetch the last row value',
- proname => 'last_value', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement', prosrc => 'window_last_value' },
+ proname => 'last_value', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement',
+ prosrc => 'window_last_value' },
{ oid => '3114', descr => 'fetch the Nth row value',
- proname => 'nth_value', prokind => 'w', prorettype => 'anyelement',
- proargtypes => 'anyelement int4', prosrc => 'window_nth_value' },
+ proname => 'nth_value', prokind => 'w', proparallel => 'r',
+ prorettype => 'anyelement', proargtypes => 'anyelement int4',
+ prosrc => 'window_nth_value' },
# functions for range types
{ oid => '3832', descr => 'I/O',
@@ -9957,41 +9968,41 @@
# hypothetical-set aggregates (and their support functions)
{ oid => '3986', descr => 'rank of hypothetical row',
proname => 'rank', provariadic => 'any', prokind => 'a', proisstrict => 'f',
- prorettype => 'int8', proargtypes => 'any', proallargtypes => '{any}',
- proargmodes => '{v}', prosrc => 'aggregate_dummy' },
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'any',
+ proallargtypes => '{any}', proargmodes => '{v}', prosrc => 'aggregate_dummy' },
{ oid => '3987', descr => 'aggregate final function',
proname => 'rank_final', provariadic => 'any', proisstrict => 'f',
- prorettype => 'int8', proargtypes => 'internal any',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'internal any',
proallargtypes => '{internal,any}', proargmodes => '{i,v}',
prosrc => 'hypothetical_rank_final' },
{ oid => '3988', descr => 'fractional rank of hypothetical row',
proname => 'percent_rank', provariadic => 'any', prokind => 'a',
- proisstrict => 'f', prorettype => 'float8', proargtypes => 'any',
- proallargtypes => '{any}', proargmodes => '{v}',
+ proisstrict => 'f', proparallel => 'r', prorettype => 'float8',
+ proargtypes => 'any', proallargtypes => '{any}', proargmodes => '{v}',
prosrc => 'aggregate_dummy' },
{ oid => '3989', descr => 'aggregate final function',
proname => 'percent_rank_final', provariadic => 'any', proisstrict => 'f',
- prorettype => 'float8', proargtypes => 'internal any',
+ proparallel => 'r', prorettype => 'float8', proargtypes => 'internal any',
proallargtypes => '{internal,any}', proargmodes => '{i,v}',
prosrc => 'hypothetical_percent_rank_final' },
{ oid => '3990', descr => 'cumulative distribution of hypothetical row',
proname => 'cume_dist', provariadic => 'any', prokind => 'a',
- proisstrict => 'f', prorettype => 'float8', proargtypes => 'any',
- proallargtypes => '{any}', proargmodes => '{v}',
+ proisstrict => 'f', proparallel => 'r', prorettype => 'float8',
+ proargtypes => 'any', proallargtypes => '{any}', proargmodes => '{v}',
prosrc => 'aggregate_dummy' },
{ oid => '3991', descr => 'aggregate final function',
proname => 'cume_dist_final', provariadic => 'any', proisstrict => 'f',
- prorettype => 'float8', proargtypes => 'internal any',
+ proparallel => 'r', prorettype => 'float8', proargtypes => 'internal any',
proallargtypes => '{internal,any}', proargmodes => '{i,v}',
prosrc => 'hypothetical_cume_dist_final' },
{ oid => '3992', descr => 'rank of hypothetical row without gaps',
proname => 'dense_rank', provariadic => 'any', prokind => 'a',
- proisstrict => 'f', prorettype => 'int8', proargtypes => 'any',
- proallargtypes => '{any}', proargmodes => '{v}',
+ proisstrict => 'f', proparallel => 'r', prorettype => 'int8',
+ proargtypes => 'any', proallargtypes => '{any}', proargmodes => '{v}',
prosrc => 'aggregate_dummy' },
{ oid => '3993', descr => 'aggregate final function',
proname => 'dense_rank_final', provariadic => 'any', proisstrict => 'f',
- prorettype => 'int8', proargtypes => 'internal any',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'internal any',
proallargtypes => '{internal,any}', proargmodes => '{i,v}',
prosrc => 'hypothetical_dense_rank_final' },
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index ad03807..bb96931 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -977,6 +977,21 @@ select * from tenk1 where two in
Filter: (stringu1 ~~ '%AAAA'::text)
(11 rows)
+-- Window function calculation can't be pushed to workers.
+explain (costs off, verbose)
+select two, row_number() over() from tenk1 where two > 100;
+ QUERY PLAN
+-----------------------------------------------
+ WindowAgg
+ Output: two, row_number() OVER (?)
+ -> Gather
+ Output: two
+ Workers Planned: 4
+ -> Parallel Seq Scan on public.tenk1
+ Output: two
+ Filter: (tenk1.two > 100)
+(8 rows)
+
-- to increase the parallel query test coverage
SAVEPOINT settings;
SET LOCAL force_parallel_mode = 1;
diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql
index aea2461..7e30543 100644
--- a/src/test/regress/sql/select_parallel.sql
+++ b/src/test/regress/sql/select_parallel.sql
@@ -367,6 +367,10 @@ explain (costs off)
select * from tenk1 where two in
(select two from tenk1 where stringu1 like '%AAAA' limit 3);
+-- Window function calculation can't be pushed to workers.
+explain (costs off, verbose)
+select two, row_number() over() from tenk1 where two > 100;
+
-- to increase the parallel query test coverage
SAVEPOINT settings;
SET LOCAL force_parallel_mode = 1;