treat_window_func_calc_parallel_restricted_v3.pg96.patch

application/octet-stream

Filename: treat_window_func_calc_parallel_restricted_v3.pg96.patch
Type: application/octet-stream
Part: 2
Message: Re: BUG #15324: Non-deterministic behaviour from parallelised sub-query

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 v3
File+
src/backend/optimizer/util/clauses.c 14 0
src/test/regress/expected/select_parallel.out 23 0
src/test/regress/sql/select_parallel.sql 5 0
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8cdee70..1734561 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -1162,6 +1162,20 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
 	}
 
 	/*
+	 * Treat window functions as parallel-restricted because we aren't sure
+	 * whether the input row ordering is fully deterministic, and the output
+	 * of window functions might vary across workers if not.  (In some cases,
+	 * like where the window frame orders by a primary key, we could relax
+	 * this restriction.  But it doesn't currently seem worth expending extra
+	 * effort to do so.)
+	 */
+	if (IsA(node, WindowFunc))
+	{
+		if (!context->allow_restricted)
+			return true;
+	}
+
+	/*
 	 * As a notational convenience for callers, look through RestrictInfo.
 	 */
 	else if (IsA(node, RestrictInfo))
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 43801e0..bce2439 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -182,6 +182,29 @@ select count(*) from tenk1;
 (1 row)
 
 reset role;
+-- Window function calculation can't be pushed to workers.
+explain (costs off, verbose)
+  select count(*) from tenk1 where (unique1, two) in
+    (select unique1, row_number() over() from tenk1);
+                                            QUERY PLAN                                            
+--------------------------------------------------------------------------------------------------
+ Aggregate
+   Output: count(*)
+   ->  Hash Semi Join
+         Hash Cond: ((tenk1.unique1 = tenk1_1.unique1) AND (tenk1.two = (row_number() OVER (?))))
+         ->  Gather
+               Output: tenk1.unique1, tenk1.two
+               Workers Planned: 4
+               ->  Parallel Seq Scan on public.tenk1
+                     Output: tenk1.unique1, tenk1.two
+         ->  Hash
+               Output: tenk1_1.unique1, (row_number() OVER (?))
+               ->  WindowAgg
+                     Output: tenk1_1.unique1, row_number() OVER (?)
+                     ->  Index Only Scan using tenk1_unique1 on public.tenk1 tenk1_1
+                           Output: tenk1_1.unique1
+(15 rows)
+
 explain (costs off)
   select stringu1::int2 from tenk1 where unique1 = 1;
                   QUERY PLAN                   
diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql
index 7defc34..272efd5 100644
--- a/src/test/regress/sql/select_parallel.sql
+++ b/src/test/regress/sql/select_parallel.sql
@@ -83,6 +83,11 @@ drop role regress_parallel_worker;
 select count(*) from tenk1;
 reset role;
 
+-- Window function calculation can't be pushed to workers.
+explain (costs off, verbose)
+  select count(*) from tenk1 where (unique1, two) in
+    (select unique1, row_number() over() from tenk1);
+
 explain (costs off)
   select stringu1::int2 from tenk1 where unique1 = 1;