Skip to content

Commit f74f871

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 21daada commit f74f871

File tree

5 files changed

+43
-16
lines changed

5 files changed

+43
-16
lines changed

src/backend/access/transam/parallel.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@ typedef struct FixedParallelState
7070
Oid database_id;
7171
Oid authenticated_user_id;
7272
Oid current_user_id;
73+
Oid outer_user_id;
7374
Oid temp_namespace_id;
7475
Oid temp_toast_namespace_id;
7576
int sec_context;
77+
bool is_superuser;
7678
PGPROC *parallel_master_pgproc;
7779
pid_t parallel_master_pid;
7880
BackendId parallel_master_backend_id;
@@ -310,6 +312,8 @@ InitializeParallelDSM(ParallelContext *pcxt)
310312
shm_toc_allocate(pcxt->toc, sizeof(FixedParallelState));
311313
fps->database_id = MyDatabaseId;
312314
fps->authenticated_user_id = GetAuthenticatedUserId();
315+
fps->outer_user_id = GetCurrentRoleId();
316+
fps->is_superuser = session_auth_is_superuser;
313317
GetUserIdAndSecContext(&fps->current_user_id, &fps->sec_context);
314318
GetTempNamespaceState(&fps->temp_namespace_id,
315319
&fps->temp_toast_namespace_id);
@@ -1126,6 +1130,13 @@ ParallelWorkerMain(Datum main_arg)
11261130
*/
11271131
InvalidateSystemCaches();
11281132

1133+
/*
1134+
* Restore current role id. Skip verifying whether session user is
1135+
* allowed to become this role and blindly restore the leader's state for
1136+
* current role.
1137+
*/
1138+
SetCurrentRoleId(fps->outer_user_id, fps->is_superuser);
1139+
11291140
/* Restore user ID and security context. */
11301141
SetUserIdAndSecContext(fps->current_user_id, fps->sec_context);
11311142

src/backend/utils/misc/guc.c

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ bool default_with_oids = false;
424424
bool SQL_inheritance = true;
425425

426426
bool Password_encryption = true;
427+
bool session_auth_is_superuser;
427428

428429
int log_min_error_statement = ERROR;
429430
int log_min_messages = WARNING;
@@ -470,7 +471,6 @@ int huge_pages;
470471
* and is kept in sync by assign_hooks.
471472
*/
472473
static char *syslog_ident_str;
473-
static bool session_auth_is_superuser;
474474
static double phony_random_seed;
475475
static char *client_encoding_string;
476476
static char *datestyle_string;
@@ -8873,12 +8873,18 @@ read_nondefault_variables(void)
88738873
* constants; a few, like server_encoding and lc_ctype, are handled specially
88748874
* outside the serialize/restore procedure. Therefore, SerializeGUCState()
88758875
* never sends these, and RestoreGUCState() never changes them.
8876+
*
8877+
* Role is a special variable in the sense that its current value can be an
8878+
* invalid value and there are multiple ways by which that can happen (like
8879+
* after setting the role, someone drops it). So we handle it outside of
8880+
* serialize/restore machinery.
88768881
*/
88778882
static bool
88788883
can_skip_gucvar(struct config_generic * gconf)
88798884
{
88808885
return gconf->context == PGC_POSTMASTER ||
8881-
gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT;
8886+
gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT ||
8887+
strcmp(gconf->name, "role") == 0;
88828888
}
88838889

88848890
/*
@@ -9139,27 +9145,14 @@ SerializeGUCState(Size maxsize, char *start_address)
91399145
Size actual_size;
91409146
Size bytes_left;
91419147
int i;
9142-
int i_role = -1;
91439148

91449149
/* Reserve space for saving the actual size of the guc state */
91459150
Assert(maxsize > sizeof(actual_size));
91469151
curptr = start_address + sizeof(actual_size);
91479152
bytes_left = maxsize - sizeof(actual_size);
91489153

91499154
for (i = 0; i < num_guc_variables; i++)
9150-
{
9151-
/*
9152-
* It's pretty ugly, but we've got to force "role" to be initialized
9153-
* after "session_authorization"; otherwise, the latter will override
9154-
* the former.
9155-
*/
9156-
if (strcmp(guc_variables[i]->name, "role") == 0)
9157-
i_role = i;
9158-
else
9159-
serialize_variable(&curptr, &bytes_left, guc_variables[i]);
9160-
}
9161-
if (i_role >= 0)
9162-
serialize_variable(&curptr, &bytes_left, guc_variables[i_role]);
9155+
serialize_variable(&curptr, &bytes_left, guc_variables[i]);
91639156

91649157
/* Store actual size without assuming alignment of start_address. */
91659158
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
@@ -245,6 +245,7 @@ extern bool log_btree_build_stats;
245245
extern PGDLLIMPORT bool check_function_bodies;
246246
extern bool default_with_oids;
247247
extern bool SQL_inheritance;
248+
extern bool session_auth_is_superuser;
248249

249250
extern int log_min_error_statement;
250251
extern int log_min_messages;

src/test/regress/expected/select_parallel.out

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,21 @@ explain (costs off)
9999
-> Index Only Scan using tenk1_unique1 on tenk1
100100
(3 rows)
101101

102+
-- test the sanity of parallel query after the active role is dropped.
102103
set force_parallel_mode=1;
104+
drop role if exists regress_parallel_worker;
105+
NOTICE: role "regress_parallel_worker" does not exist, skipping
106+
create role regress_parallel_worker;
107+
set role regress_parallel_worker;
108+
reset session authorization;
109+
drop role regress_parallel_worker;
110+
select count(*) from tenk1;
111+
count
112+
-------
113+
10000
114+
(1 row)
115+
116+
reset role;
103117
explain (costs off)
104118
select stringu1::int2 from tenk1 where unique1 = 1;
105119
QUERY PLAN

src/test/regress/sql/select_parallel.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@ explain (costs off)
3939
select sum(parallel_restricted(unique1)) from tenk1
4040
group by(parallel_restricted(unique1));
4141

42+
-- test the sanity of parallel query after the active role is dropped.
4243
set force_parallel_mode=1;
44+
drop role if exists regress_parallel_worker;
45+
create role regress_parallel_worker;
46+
set role regress_parallel_worker;
47+
reset session authorization;
48+
drop role regress_parallel_worker;
49+
select count(*) from tenk1;
50+
reset role;
4351

4452
explain (costs off)
4553
select stringu1::int2 from tenk1 where unique1 = 1;

0 commit comments

Comments
 (0)