mirror of
https://github.com/postgres/postgres.git
synced 2025-05-12 16:21:30 +03:00
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
This commit is contained in:
parent
21daada10e
commit
f74f871b80
@ -70,9 +70,11 @@ typedef struct FixedParallelState
|
|||||||
Oid database_id;
|
Oid database_id;
|
||||||
Oid authenticated_user_id;
|
Oid authenticated_user_id;
|
||||||
Oid current_user_id;
|
Oid current_user_id;
|
||||||
|
Oid outer_user_id;
|
||||||
Oid temp_namespace_id;
|
Oid temp_namespace_id;
|
||||||
Oid temp_toast_namespace_id;
|
Oid temp_toast_namespace_id;
|
||||||
int sec_context;
|
int sec_context;
|
||||||
|
bool is_superuser;
|
||||||
PGPROC *parallel_master_pgproc;
|
PGPROC *parallel_master_pgproc;
|
||||||
pid_t parallel_master_pid;
|
pid_t parallel_master_pid;
|
||||||
BackendId parallel_master_backend_id;
|
BackendId parallel_master_backend_id;
|
||||||
@ -310,6 +312,8 @@ InitializeParallelDSM(ParallelContext *pcxt)
|
|||||||
shm_toc_allocate(pcxt->toc, sizeof(FixedParallelState));
|
shm_toc_allocate(pcxt->toc, sizeof(FixedParallelState));
|
||||||
fps->database_id = MyDatabaseId;
|
fps->database_id = MyDatabaseId;
|
||||||
fps->authenticated_user_id = GetAuthenticatedUserId();
|
fps->authenticated_user_id = GetAuthenticatedUserId();
|
||||||
|
fps->outer_user_id = GetCurrentRoleId();
|
||||||
|
fps->is_superuser = session_auth_is_superuser;
|
||||||
GetUserIdAndSecContext(&fps->current_user_id, &fps->sec_context);
|
GetUserIdAndSecContext(&fps->current_user_id, &fps->sec_context);
|
||||||
GetTempNamespaceState(&fps->temp_namespace_id,
|
GetTempNamespaceState(&fps->temp_namespace_id,
|
||||||
&fps->temp_toast_namespace_id);
|
&fps->temp_toast_namespace_id);
|
||||||
@ -1126,6 +1130,13 @@ ParallelWorkerMain(Datum main_arg)
|
|||||||
*/
|
*/
|
||||||
InvalidateSystemCaches();
|
InvalidateSystemCaches();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
SetCurrentRoleId(fps->outer_user_id, fps->is_superuser);
|
||||||
|
|
||||||
/* Restore user ID and security context. */
|
/* Restore user ID and security context. */
|
||||||
SetUserIdAndSecContext(fps->current_user_id, fps->sec_context);
|
SetUserIdAndSecContext(fps->current_user_id, fps->sec_context);
|
||||||
|
|
||||||
|
@ -424,6 +424,7 @@ bool default_with_oids = false;
|
|||||||
bool SQL_inheritance = true;
|
bool SQL_inheritance = true;
|
||||||
|
|
||||||
bool Password_encryption = true;
|
bool Password_encryption = true;
|
||||||
|
bool session_auth_is_superuser;
|
||||||
|
|
||||||
int log_min_error_statement = ERROR;
|
int log_min_error_statement = ERROR;
|
||||||
int log_min_messages = WARNING;
|
int log_min_messages = WARNING;
|
||||||
@ -470,7 +471,6 @@ int huge_pages;
|
|||||||
* and is kept in sync by assign_hooks.
|
* and is kept in sync by assign_hooks.
|
||||||
*/
|
*/
|
||||||
static char *syslog_ident_str;
|
static char *syslog_ident_str;
|
||||||
static bool session_auth_is_superuser;
|
|
||||||
static double phony_random_seed;
|
static double phony_random_seed;
|
||||||
static char *client_encoding_string;
|
static char *client_encoding_string;
|
||||||
static char *datestyle_string;
|
static char *datestyle_string;
|
||||||
@ -8873,12 +8873,18 @@ read_nondefault_variables(void)
|
|||||||
* constants; a few, like server_encoding and lc_ctype, are handled specially
|
* constants; a few, like server_encoding and lc_ctype, are handled specially
|
||||||
* outside the serialize/restore procedure. Therefore, SerializeGUCState()
|
* outside the serialize/restore procedure. Therefore, SerializeGUCState()
|
||||||
* never sends these, and RestoreGUCState() never changes them.
|
* never sends these, and RestoreGUCState() never changes them.
|
||||||
|
*
|
||||||
|
* Role is a special variable in the sense that its current value can be an
|
||||||
|
* invalid value and there are multiple ways by which that can happen (like
|
||||||
|
* after setting the role, someone drops it). So we handle it outside of
|
||||||
|
* serialize/restore machinery.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
can_skip_gucvar(struct config_generic * gconf)
|
can_skip_gucvar(struct config_generic * gconf)
|
||||||
{
|
{
|
||||||
return gconf->context == PGC_POSTMASTER ||
|
return gconf->context == PGC_POSTMASTER ||
|
||||||
gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT;
|
gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT ||
|
||||||
|
strcmp(gconf->name, "role") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -9139,7 +9145,6 @@ SerializeGUCState(Size maxsize, char *start_address)
|
|||||||
Size actual_size;
|
Size actual_size;
|
||||||
Size bytes_left;
|
Size bytes_left;
|
||||||
int i;
|
int i;
|
||||||
int i_role = -1;
|
|
||||||
|
|
||||||
/* Reserve space for saving the actual size of the guc state */
|
/* Reserve space for saving the actual size of the guc state */
|
||||||
Assert(maxsize > sizeof(actual_size));
|
Assert(maxsize > sizeof(actual_size));
|
||||||
@ -9147,19 +9152,7 @@ SerializeGUCState(Size maxsize, char *start_address)
|
|||||||
bytes_left = maxsize - sizeof(actual_size);
|
bytes_left = maxsize - sizeof(actual_size);
|
||||||
|
|
||||||
for (i = 0; i < num_guc_variables; i++)
|
for (i = 0; i < num_guc_variables; i++)
|
||||||
{
|
|
||||||
/*
|
|
||||||
* It's pretty ugly, but we've got to force "role" to be initialized
|
|
||||||
* after "session_authorization"; otherwise, the latter will override
|
|
||||||
* the former.
|
|
||||||
*/
|
|
||||||
if (strcmp(guc_variables[i]->name, "role") == 0)
|
|
||||||
i_role = i;
|
|
||||||
else
|
|
||||||
serialize_variable(&curptr, &bytes_left, guc_variables[i]);
|
serialize_variable(&curptr, &bytes_left, guc_variables[i]);
|
||||||
}
|
|
||||||
if (i_role >= 0)
|
|
||||||
serialize_variable(&curptr, &bytes_left, guc_variables[i_role]);
|
|
||||||
|
|
||||||
/* Store actual size without assuming alignment of start_address. */
|
/* Store actual size without assuming alignment of start_address. */
|
||||||
actual_size = maxsize - bytes_left - sizeof(actual_size);
|
actual_size = maxsize - bytes_left - sizeof(actual_size);
|
||||||
|
@ -245,6 +245,7 @@ extern bool log_btree_build_stats;
|
|||||||
extern PGDLLIMPORT bool check_function_bodies;
|
extern PGDLLIMPORT bool check_function_bodies;
|
||||||
extern bool default_with_oids;
|
extern bool default_with_oids;
|
||||||
extern bool SQL_inheritance;
|
extern bool SQL_inheritance;
|
||||||
|
extern bool session_auth_is_superuser;
|
||||||
|
|
||||||
extern int log_min_error_statement;
|
extern int log_min_error_statement;
|
||||||
extern int log_min_messages;
|
extern int log_min_messages;
|
||||||
|
@ -99,7 +99,21 @@ explain (costs off)
|
|||||||
-> Index Only Scan using tenk1_unique1 on tenk1
|
-> Index Only Scan using tenk1_unique1 on tenk1
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
|
-- test the sanity of parallel query after the active role is dropped.
|
||||||
set force_parallel_mode=1;
|
set force_parallel_mode=1;
|
||||||
|
drop role if exists regress_parallel_worker;
|
||||||
|
NOTICE: role "regress_parallel_worker" does not exist, skipping
|
||||||
|
create role regress_parallel_worker;
|
||||||
|
set role regress_parallel_worker;
|
||||||
|
reset session authorization;
|
||||||
|
drop role regress_parallel_worker;
|
||||||
|
select count(*) from tenk1;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
10000
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
reset role;
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select stringu1::int2 from tenk1 where unique1 = 1;
|
select stringu1::int2 from tenk1 where unique1 = 1;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
|
@ -39,7 +39,15 @@ explain (costs off)
|
|||||||
select sum(parallel_restricted(unique1)) from tenk1
|
select sum(parallel_restricted(unique1)) from tenk1
|
||||||
group by(parallel_restricted(unique1));
|
group by(parallel_restricted(unique1));
|
||||||
|
|
||||||
|
-- test the sanity of parallel query after the active role is dropped.
|
||||||
set force_parallel_mode=1;
|
set force_parallel_mode=1;
|
||||||
|
drop role if exists regress_parallel_worker;
|
||||||
|
create role regress_parallel_worker;
|
||||||
|
set role regress_parallel_worker;
|
||||||
|
reset session authorization;
|
||||||
|
drop role regress_parallel_worker;
|
||||||
|
select count(*) from tenk1;
|
||||||
|
reset role;
|
||||||
|
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select stringu1::int2 from tenk1 where unique1 = 1;
|
select stringu1::int2 from tenk1 where unique1 = 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user