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;