postgres.git / summary / log / commit / refs

commit    f5f30c22ed69fb37b896c4d4546b2ab823c3fd61
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Wed Jul 31 22:54:10 2024 +0000

    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


src/backend/access/transam/parallel.c | 12 ++++++++---- src/backend/commands/variable.c | 10 ++++++++-- src/test/regress/expected/select_parallel.out | 18 ++++++++++++++++++ src/test/regress/sql/select_parallel.sql | 9 +++++++++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 8613fc6fb54..b9cf197d353 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -1410,10 +1410,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. */ @@ -1455,6 +1451,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 diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index f44d942aa4d..e3f9f110d87 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -577,14 +577,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_transaction_isolation(int *newval, void **extra, GucSource source) { int newXactIsoLevel = *newval; - if (newXactIsoLevel != XactIsoLevel && IsTransactionState()) + if (newXactIsoLevel != XactIsoLevel && + IsTransactionState() && !InitializingParallelWorker) { if (FirstSnapshotSet) { @@ -619,6 +621,10 @@ check_transaction_isolation(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 5a603f86b73..68a629619a6 100644 --- a/src/test/regress/expected/select_parallel.out +++ b/src/test/regress/expected/select_parallel.out @@ -1329,3 +1329,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 debug_parallel_query = 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 c7df8f775ce..1a0e7f144d0 100644 --- a/src/test/regress/sql/select_parallel.sql +++ b/src/test/regress/sql/select_parallel.sql @@ -511,3 +511,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 debug_parallel_query = 1; +select current_setting('session_authorization'); +rollback; [parent: bd15b7db489d]