Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 69125c8

Browse files
committed
Fix problems with the "role" GUC and parallel query.
Without this fix, dropping a role can sometimes result in parallel query failures in sessions that have used "SET ROLE" to assume the dropped role, even if that setting isn't active any more. Report by Pavan Deolasee. Patch by Amit Kapila, reviewed by me. Discussion: http://postgr.es/m/CABOikdOomRcZsLsLK+Z+qENM1zxyaWnAvFh3MJZzZnnKiF+REg@mail.gmail.com
1 parent 291a31c commit 69125c8

File tree

5 files changed

+48
-16
lines changed

5 files changed

+48
-16
lines changed

src/backend/access/transam/parallel.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ typedef struct FixedParallelState
7171
Oid database_id;
7272
Oid authenticated_user_id;
7373
Oid current_user_id;
74+
Oid outer_user_id;
7475
Oid temp_namespace_id;
7576
Oid temp_toast_namespace_id;
7677
int sec_context;
78+
bool is_superuser;
7779
PGPROC *parallel_master_pgproc;
7880
pid_t parallel_master_pid;
7981
BackendId parallel_master_backend_id;
@@ -275,6 +277,8 @@ InitializeParallelDSM(ParallelContext *pcxt)
275277
shm_toc_allocate(pcxt->toc, sizeof(FixedParallelState));
276278
fps->database_id = MyDatabaseId;
277279
fps->authenticated_user_id = GetAuthenticatedUserId();
280+
fps->outer_user_id = GetCurrentRoleId();
281+
fps->is_superuser = session_auth_is_superuser;
278282
GetUserIdAndSecContext(&fps->current_user_id, &fps->sec_context);
279283
GetTempNamespaceState(&fps->temp_namespace_id,
280284
&fps->temp_toast_namespace_id);
@@ -1079,6 +1083,13 @@ ParallelWorkerMain(Datum main_arg)
10791083
*/
10801084
InvalidateSystemCaches();
10811085

1086+
/*
1087+
* Restore current role id. Skip verifying whether session user is
1088+
* allowed to become this role and blindly restore the leader's state for
1089+
* current role.
1090+
*/
1091+
SetCurrentRoleId(fps->outer_user_id, fps->is_superuser);
1092+
10821093
/* Restore user ID and security context. */
10831094
SetUserIdAndSecContext(fps->current_user_id, fps->sec_context);
10841095

src/backend/utils/misc/guc.c

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ char *event_source;
446446
bool row_security;
447447
bool check_function_bodies = true;
448448
bool default_with_oids = false;
449+
bool session_auth_is_superuser;
449450

450451
int log_min_error_statement = ERROR;
451452
int log_min_messages = WARNING;
@@ -492,7 +493,6 @@ int huge_pages;
492493
* and is kept in sync by assign_hooks.
493494
*/
494495
static char *syslog_ident_str;
495-
static bool session_auth_is_superuser;
496496
static double phony_random_seed;
497497
static char *client_encoding_string;
498498
static char *datestyle_string;
@@ -8986,12 +8986,18 @@ read_nondefault_variables(void)
89868986
* constants; a few, like server_encoding and lc_ctype, are handled specially
89878987
* outside the serialize/restore procedure. Therefore, SerializeGUCState()
89888988
* never sends these, and RestoreGUCState() never changes them.
8989+
*
8990+
* Role is a special variable in the sense that its current value can be an
8991+
* invalid value and there are multiple ways by which that can happen (like
8992+
* after setting the role, someone drops it). So we handle it outside of
8993+
* serialize/restore machinery.
89898994
*/
89908995
static bool
89918996
can_skip_gucvar(struct config_generic *gconf)
89928997
{
89938998
return gconf->context == PGC_POSTMASTER ||
8994-
gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT;
8999+
gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT ||
9000+
strcmp(gconf->name, "role") == 0;
89959001
}
89969002

89979003
/*
@@ -9252,27 +9258,14 @@ SerializeGUCState(Size maxsize, char *start_address)
92529258
Size actual_size;
92539259
Size bytes_left;
92549260
int i;
9255-
int i_role = -1;
92569261

92579262
/* Reserve space for saving the actual size of the guc state */
92589263
Assert(maxsize > sizeof(actual_size));
92599264
curptr = start_address + sizeof(actual_size);
92609265
bytes_left = maxsize - sizeof(actual_size);
92619266

92629267
for (i = 0; i < num_guc_variables; i++)
9263-
{
9264-
/*
9265-
* It's pretty ugly, but we've got to force "role" to be initialized
9266-
* after "session_authorization"; otherwise, the latter will override
9267-
* the former.
9268-
*/
9269-
if (strcmp(guc_variables[i]->name, "role") == 0)
9270-
i_role = i;
9271-
else
9272-
serialize_variable(&curptr, &bytes_left, guc_variables[i]);
9273-
}
9274-
if (i_role >= 0)
9275-
serialize_variable(&curptr, &bytes_left, guc_variables[i_role]);
9268+
serialize_variable(&curptr, &bytes_left, guc_variables[i]);
92769269

92779270
/* Store actual size without assuming alignment of start_address. */
92789271
actual_size = maxsize - bytes_left - sizeof(actual_size);

src/include/utils/guc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ extern bool log_btree_build_stats;
244244

245245
extern PGDLLIMPORT bool check_function_bodies;
246246
extern bool default_with_oids;
247+
extern bool session_auth_is_superuser;
247248

248249
extern int log_min_error_statement;
249250
extern int log_min_messages;

src/test/regress/expected/select_parallel.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,22 @@ select string4 from tenk1 order by string4 limit 5;
424424

425425
reset max_parallel_workers;
426426
reset enable_hashagg;
427+
-- test the sanity of parallel query after the active role is dropped.
428+
drop role if exists regress_parallel_worker;
429+
NOTICE: role "regress_parallel_worker" does not exist, skipping
430+
create role regress_parallel_worker;
431+
set role regress_parallel_worker;
432+
reset session authorization;
433+
drop role regress_parallel_worker;
434+
set force_parallel_mode = 1;
435+
select count(*) from tenk1;
436+
count
437+
-------
438+
10000
439+
(1 row)
440+
441+
reset force_parallel_mode;
442+
reset role;
427443
set force_parallel_mode=1;
428444
explain (costs off)
429445
select stringu1::int2 from tenk1 where unique1 = 1;

src/test/regress/sql/select_parallel.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,17 @@ select string4 from tenk1 order by string4 limit 5;
162162
reset max_parallel_workers;
163163
reset enable_hashagg;
164164

165+
-- test the sanity of parallel query after the active role is dropped.
166+
drop role if exists regress_parallel_worker;
167+
create role regress_parallel_worker;
168+
set role regress_parallel_worker;
169+
reset session authorization;
170+
drop role regress_parallel_worker;
171+
set force_parallel_mode = 1;
172+
select count(*) from tenk1;
173+
reset force_parallel_mode;
174+
reset role;
175+
165176
set force_parallel_mode=1;
166177

167178
explain (costs off)

0 commit comments

Comments
 (0)