aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2024-07-31 18:54:10 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2024-07-31 18:54:10 -0400
commit68855c03878c0c90227e24533ca40127da3578cd (patch)
treef01bc80cc34135c2182fde6a4d8e6df61c714284
parent447e25c049150a0954b0532393de24916a1b7479 (diff)
downloadpostgresql-68855c03878c0c90227e24533ca40127da3578cd.tar.gz
postgresql-68855c03878c0c90227e24533ca40127da3578cd.zip
Allow parallel workers to cope with a newly-created session user ID.
Parallel workers failed after a sequence like BEGIN; CREATE USER foo; SET SESSION AUTHORIZATION foo; because check_session_authorization could not see the uncommitted pg_authid row for "foo". This is because we ran RestoreGUCState() in a separate transaction using an ordinary just-created snapshot. The same disease afflicts any other GUC that requires catalog lookups and isn't forgiving about the lookups failing. To fix, postpone RestoreGUCState() into the worker's main transaction after we've set up a snapshot duplicating the leader's. This affects check_transaction_isolation and check_transaction_deferrable, which think they should only run during transaction start. Make them act like check_transaction_read_only, which already knows it should silently accept the value when InitializingParallelWorker. Per bug #18545 from Andrey Rachitskiy. Back-patch to all supported branches, because this has been wrong for awhile. Discussion: https://postgr.es/m/18545-feba138862f19aaa@postgresql.org
-rw-r--r--src/backend/access/transam/parallel.c12
-rw-r--r--src/backend/commands/variable.c10
-rw-r--r--src/test/regress/expected/select_parallel.out18
-rw-r--r--src/test/regress/sql/select_parallel.sql9
4 files changed, 43 insertions, 6 deletions
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index f357804fda0..9c68d401430 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -1367,10 +1367,6 @@ ParallelWorkerMain(Datum main_arg)
libraryspace = shm_toc_lookup(toc, PARALLEL_KEY_LIBRARY, false);
StartTransactionCommand();
RestoreLibraryState(libraryspace);
-
- /* Restore GUC values from launching backend. */
- gucspace = shm_toc_lookup(toc, PARALLEL_KEY_GUC, false);
- RestoreGUCState(gucspace);
CommitTransactionCommand();
/* Crank up a transaction state appropriate to a parallel worker. */
@@ -1413,6 +1409,14 @@ ParallelWorkerMain(Datum main_arg)
InvalidateSystemCaches();
/*
+ * Restore GUC values from launching backend. We can't do this earlier,
+ * because GUC check hooks that do catalog lookups need to see the same
+ * database state as the leader.
+ */
+ gucspace = shm_toc_lookup(toc, PARALLEL_KEY_GUC, false);
+ RestoreGUCState(gucspace);
+
+ /*
* Restore current role id. Skip verifying whether session user is
* allowed to become this role and blindly restore the leader's state for
* current role.
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 16fa68c18c6..46a2be1be62 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -519,14 +519,16 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
* We allow idempotent changes at any time, but otherwise this can only be
* changed in a toplevel transaction that has not yet taken a snapshot.
*
- * As in check_transaction_read_only, allow it if not inside a transaction.
+ * As in check_transaction_read_only, allow it if not inside a transaction,
+ * or if restoring state in a parallel worker.
*/
bool
check_XactIsoLevel(int *newval, void **extra, GucSource source)
{
int newXactIsoLevel = *newval;
- if (newXactIsoLevel != XactIsoLevel && IsTransactionState())
+ if (newXactIsoLevel != XactIsoLevel &&
+ IsTransactionState() && !InitializingParallelWorker)
{
if (FirstSnapshotSet)
{
@@ -561,6 +563,10 @@ check_XactIsoLevel(int *newval, void **extra, GucSource source)
bool
check_transaction_deferrable(bool *newval, void **extra, GucSource source)
{
+ /* Just accept the value when restoring state in a parallel worker */
+ if (InitializingParallelWorker)
+ return true;
+
if (IsSubTransaction())
{
GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 49f54d640a1..27e155e87d3 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -1174,3 +1174,21 @@ SELECT 1 FROM tenk1_vw_sec
(9 rows)
rollback;
+-- test that a newly-created session role propagates to workers.
+begin;
+create role regress_parallel_worker;
+set session authorization regress_parallel_worker;
+select current_setting('session_authorization');
+ current_setting
+-------------------------
+ regress_parallel_worker
+(1 row)
+
+set force_parallel_mode = 1;
+select current_setting('session_authorization');
+ current_setting
+-------------------------
+ regress_parallel_worker
+(1 row)
+
+rollback;
diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql
index 5a01a98b268..35bc8bc4956 100644
--- a/src/test/regress/sql/select_parallel.sql
+++ b/src/test/regress/sql/select_parallel.sql
@@ -454,3 +454,12 @@ SELECT 1 FROM tenk1_vw_sec
WHERE (SELECT sum(f1) FROM int4_tbl WHERE f1 < unique1) < 100;
rollback;
+
+-- test that a newly-created session role propagates to workers.
+begin;
+create role regress_parallel_worker;
+set session authorization regress_parallel_worker;
+select current_setting('session_authorization');
+set force_parallel_mode = 1;
+select current_setting('session_authorization');
+rollback;