On 11/15/12 12:53 PM, Peter Eisentraut wrote: > We already have the ability to store in pg_db_role_setting configuration > settings for > > specific user, specific database > specific user, any database > any user, specific database > > The existing infrastructure would also support > > any user, any database (= all the time) > > All you'd need is to add > > ApplySetting(InvalidOid, InvalidOid, relsetting, PGC_S_$SOMETHING); > > in postinit.c, and have some SQL command to modify this setting.
Here is a patch for that. The internals are straightforward. Actually, we might want to refactor this a bit later, unifying the AlterRoleSet and AlterDatabaseSet parse nodes and the functions that do the work, because it's really all the same. The SQL level interface is a bit odd. The existing facilities are ALTER ROLE / SET ALTER DATABASE / SET ALTER ROLE / IN DATABASE / SET Since the original design somehow considered roles to be superior to databases in this regard, I added the global setting as ALTER ROLE ALL SET ..., but that's obviously arbitrary. Most other variants would probably be much more invasive, though.
diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml index 2fbba53..6fa51ee 100644 --- a/doc/src/sgml/ref/alter_role.sgml +++ b/doc/src/sgml/ref/alter_role.sgml @@ -39,9 +39,9 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable> ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT } -ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT -ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable> -ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL +ALTER ROLE [ <replaceable class="PARAMETER">name</replaceable> | ALL ] [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT +ALTER ROLE [ <replaceable class="PARAMETER">name</replaceable> | ALL ] [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable> +ALTER ROLE [ <replaceable class="PARAMETER">name</replaceable> | ALL ] [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL </synopsis> </refsynopsisdiv> @@ -83,8 +83,15 @@ <title>Description</title> <para> The remaining variants change a role's session default for a configuration variable, either for all databases or, when the <literal>IN - DATABASE</literal> clause is specified, only for sessions in - the named database. Whenever the role subsequently + DATABASE</literal> clause is specified, only for sessions in the named + database. If <literal>ALL</literal> is specified instead of a role name, + this changes the setting for all roles. Using <literal>ALL</literal> + with <literal>IN DATABASE</literal> is effectively the same as using the + command <literal>ALTER DATABASE ... SET ...</literal>. + </para> + + <para> + Whenever the role subsequently starts a new session, the specified value becomes the session default, overriding whatever setting is present in <filename>postgresql.conf</> or has been received from the <command>postgres</command> @@ -93,12 +100,17 @@ <title>Description</title> <xref linkend="sql-set-session-authorization"> does not cause new configuration values to be set. Settings set for all databases are overridden by database-specific settings - attached to a role. + attached to a role. Settings for specific databases or specific roles override + settings for all roles. + </para> + + <para> Superusers can change anyone's session defaults. Roles having <literal>CREATEROLE</> privilege can change defaults for non-superuser roles. Ordinary roles can only set defaults for themselves. Certain configuration variables cannot be set this way, or can only be - set if a superuser issues the command. + set if a superuser issues the command. Only superusers can change a setting + for all roles in all databases. </para> </refsect1> @@ -307,6 +319,7 @@ <title>See Also</title> <simplelist type="inline"> <member><xref linkend="sql-createrole"></member> <member><xref linkend="sql-droprole"></member> + <member><xref linkend="sql-alterdatabase"></member> <member><xref linkend="sql-set"></member> </simplelist> </refsect1> diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 3ba877d..5edb59a 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -814,41 +814,46 @@ static void DelRoleMems(const char *rolename, Oid roleid, { HeapTuple roletuple; Oid databaseid = InvalidOid; - Oid roleid; + Oid roleid = InvalidOid; - roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role)); + if (stmt->role) + { + roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role)); - if (!HeapTupleIsValid(roletuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("role \"%s\" does not exist", stmt->role))); + if (!HeapTupleIsValid(roletuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role \"%s\" does not exist", stmt->role))); - roleid = HeapTupleGetOid(roletuple); + roleid = HeapTupleGetOid(roletuple); - /* - * Obtain a lock on the role and make sure it didn't go away in the - * meantime. - */ - shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple)); + /* + * Obtain a lock on the role and make sure it didn't go away in the + * meantime. + */ + shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple)); - /* - * To mess with a superuser you gotta be superuser; else you need - * createrole, or just want to change your own settings - */ - if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper) - { - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to alter superusers"))); - } - else - { - if (!have_createrole_privilege() && - HeapTupleGetOid(roletuple) != GetUserId()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied"))); + /* + * To mess with a superuser you gotta be superuser; else you need + * createrole, or just want to change your own settings + */ + if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper) + { + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to alter superusers"))); + } + else + { + if (!have_createrole_privilege() && + HeapTupleGetOid(roletuple) != GetUserId()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied"))); + } + + ReleaseSysCache(roletuple); } /* look up and lock the database, if specified */ @@ -856,10 +861,29 @@ static void DelRoleMems(const char *rolename, Oid roleid, { databaseid = get_database_oid(stmt->database, false); shdepLockAndCheckObject(DatabaseRelationId, databaseid); + + if (!stmt->role) + { + /* + * If no role is specified, then this is effectively the same as + * ALTER DATABASE ... SET, so use the same permission check. + */ + if (!pg_database_ownercheck(databaseid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + stmt->database); + } + } + + if (!stmt->role && !stmt->database) + { + /* Must be superuser to alter settings globally. */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to alter settings globally"))); } - AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt); - ReleaseSysCache(roletuple); + AlterSetting(databaseid, roleid, stmt->setstmt); return roleid; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 76ef11e..fab330d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1018,6 +1018,14 @@ AlterRoleSetStmt: n->setstmt = $5; $$ = (Node *)n; } + | ALTER ROLE ALL opt_in_database SetResetClause + { + AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); + n->role = NULL; + n->database = $4; + n->setstmt = $5; + $$ = (Node *)n; + } ; diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 7e21cea..8427006 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -1010,6 +1010,7 @@ ApplySetting(databaseid, roleid, relsetting, PGC_S_DATABASE_USER); ApplySetting(InvalidOid, roleid, relsetting, PGC_S_USER); ApplySetting(databaseid, InvalidOid, relsetting, PGC_S_DATABASE); + ApplySetting(InvalidOid, InvalidOid, relsetting, PGC_S_GLOBAL); heap_close(relsetting, AccessShareLock); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index ac5e4f3..0c6ab9b 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -500,6 +500,7 @@ static char *config_enum_get_options(struct config_enum * record, /* PGC_S_ENV_VAR */ "environment variable", /* PGC_S_FILE */ "configuration file", /* PGC_S_ARGV */ "command line", + /* PGC_S_GLOBAL */ "global", /* PGC_S_DATABASE */ "database", /* PGC_S_USER */ "user", /* PGC_S_DATABASE_USER */ "database user", @@ -5149,7 +5150,7 @@ struct config_generic ** */ elevel = IsUnderPostmaster ? DEBUG3 : LOG; } - else if (source == PGC_S_DATABASE || source == PGC_S_USER || + else if (source == PGC_S_GLOBAL || source == PGC_S_DATABASE || source == PGC_S_USER || source == PGC_S_DATABASE_USER) elevel = WARNING; else diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 0023c00..d497b1f 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -87,6 +87,7 @@ typedef enum PGC_S_ENV_VAR, /* postmaster environment variable */ PGC_S_FILE, /* postgresql.conf */ PGC_S_ARGV, /* postmaster command line */ + PGC_S_GLOBAL, /* global in-database setting */ PGC_S_DATABASE, /* per-database setting */ PGC_S_USER, /* per-user setting */ PGC_S_DATABASE_USER, /* per-user-and-database setting */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers