From 335f4e316a6dee9eb3383fc3800954ee9e7f6cef Mon Sep 17 00:00:00 2001
From: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Date: Mon, 26 Oct 2026 12:56:01 +0530
Subject: [PATCH v1] Allow parallel query for PL/pgSQL assignment statements.

Commit 61c2e1a95f made exec_eval_expr() prepare expressions with
CURSOR_OPT_PARALLEL_OK, but exec_assign_expr() prepares the plan
itself, with cursorOptions 0, before calling exec_eval_expr().  So
queries used in assignments, such as "x := sum(a) from tab", were
never considered for parallel execution, while the same query used in
IF, RETURN, RAISE and so on could be.  The same applies to DECLARE
default expressions, which are also evaluated by exec_assign_expr().

The pre-planning in exec_assign_expr() is redundant, since
exec_eval_expr() creates the plan if needed; just remove it.

Add regression tests for both an assignment statement and a DECLARE
default expression.
---
 src/pl/plpgsql/src/pl_exec.c                  |  7 +----
 src/test/regress/expected/select_parallel.out | 27 +++++++++++++++++++
 src/test/regress/sql/select_parallel.sql      | 21 +++++++++++++++
 3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index bc1667f7a13..853dee7f4da 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -5116,12 +5116,7 @@ exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
 	Oid			valtype;
 	int32		valtypmod;
 
-	/*
-	 * If first time through, create a plan for this expression.
-	 */
-	if (expr->plan == NULL)
-		exec_prepare_plan(estate, expr, 0);
-
+	/* exec_eval_expr will create a plan if this is the first time through */
 	value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
 	exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
 	exec_eval_cleanup(estate);
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index e1344215644..2eb5cadb80b 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -1167,6 +1167,33 @@ explain (costs off)
                            Filter: (stringu1 ~~ '%AAAA'::text)
 (11 rows)
 
+-- PL/pgSQL assignment from a query should be able to use parallel query;
+-- check by provoking an error in a worker
+SAVEPOINT settings;
+SET LOCAL debug_parallel_query = 1;
+do $$
+declare x int2;
+begin
+  x := stringu1::int2 from tenk1 where unique1 = 1;
+end $$;
+ERROR:  invalid input syntax for type smallint: "BAAAAA"
+CONTEXT:  parallel worker
+PL/pgSQL assignment "x := stringu1::int2 from tenk1 where unique1 = 1"
+PL/pgSQL function inline_code_block line 4 at assignment
+ROLLBACK TO SAVEPOINT settings;
+-- same for a DECLARE default expression
+SAVEPOINT settings;
+SET LOCAL debug_parallel_query = 1;
+do $$
+declare x int2 := stringu1::int2 from tenk1 where unique1 = 1;
+begin
+  null;
+end $$;
+ERROR:  invalid input syntax for type smallint: "BAAAAA"
+CONTEXT:  parallel worker
+PL/pgSQL expression "stringu1::int2 from tenk1 where unique1 = 1"
+PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
+ROLLBACK TO SAVEPOINT settings;
 -- to increase the parallel query test coverage
 SAVEPOINT settings;
 SET LOCAL debug_parallel_query = 1;
diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql
index 71a75bc86ea..9a7c6d5e74e 100644
--- a/src/test/regress/sql/select_parallel.sql
+++ b/src/test/regress/sql/select_parallel.sql
@@ -447,6 +447,27 @@ explain (costs off)
   select * from tenk1 a where two in
     (select two from tenk1 b where stringu1 like '%AAAA' limit 3);
 
+-- PL/pgSQL assignment from a query should be able to use parallel query;
+-- check by provoking an error in a worker
+SAVEPOINT settings;
+SET LOCAL debug_parallel_query = 1;
+do $$
+declare x int2;
+begin
+  x := stringu1::int2 from tenk1 where unique1 = 1;
+end $$;
+ROLLBACK TO SAVEPOINT settings;
+
+-- same for a DECLARE default expression
+SAVEPOINT settings;
+SET LOCAL debug_parallel_query = 1;
+do $$
+declare x int2 := stringu1::int2 from tenk1 where unique1 = 1;
+begin
+  null;
+end $$;
+ROLLBACK TO SAVEPOINT settings;
+
 -- to increase the parallel query test coverage
 SAVEPOINT settings;
 SET LOCAL debug_parallel_query = 1;
-- 
2.43.0

