diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 15dab71cc0d2ecec70a7160946816d8d92527494..487dd7e1690ee0202eb53864e6ad60183a494a0e 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.208 2009/10/05 19:24:32 tgl Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.209 2009/10/07 22:14:14 alvherre Exp $ --> <!-- Documentation of the system catalogs, directed toward PostgreSQL developers --> @@ -203,6 +203,11 @@ <entry>query rewrite rules</entry> </row> + <row> + <entry><link linkend="catalog-pg-db-role-setting"><structname>pg_db_role_setting</structname></link></entry> + <entry>per-role and per-database settings</entry> + </row> + <row> <entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry> <entry>dependencies on shared objects</entry> @@ -2136,13 +2141,6 @@ </entry> </row> - <row> - <entry><structfield>datconfig</structfield></entry> - <entry><type>text[]</type></entry> - <entry></entry> - <entry>Session defaults for run-time configuration variables</entry> - </row> - <row> <entry><structfield>datacl</structfield></entry> <entry><type>aclitem[]</type></entry> @@ -4106,6 +4104,65 @@ </sect1> + <sect1 id="catalog-pg-db-role-setting"> + <title><structname>pg_db_role_setting</structname></title> + + <indexterm zone="catalog-pg-db-role-setting"> + <primary>pg_db_role_setting</primary> + </indexterm> + + <para> + The catalog <structname>pg_db_role_setting</structname> records the default + values that have been set for run-time configuration variables, + for each role and database combination. + </para> + + <para> + Unlike most system catalogs, <structname>pg_db_role_setting</structname> + is shared across all databases of a cluster: there is only one + copy of <structname>pg_db_role_setting</structname> per cluster, not + one per database. + </para> + + <table> + <title><structname>pg_db_role_setting</> Columns</title> + + <tgroup cols="4"> + <thead> + <row> + <entry>Name</entry> + <entry>Type</entry> + <entry>References</entry> + <entry>Description</entry> + </row> + </thead> + + <tbody> + <row> + <entry><structfield>setdatabase</structfield></entry> + <entry><type>oid</type></entry> + <entry><literal><link linkend="catalog-pg-database"><structname>pg_database</structname></link>.oid</literal></entry> + <entry>The OID of the database the setting is applicable to, or zero if not database-specific</entry> + </row> + + <row> + <entry><structfield>setrole</structfield></entry> + <entry><type>oid</type></entry> + <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry> + <entry>The OID of the role the setting is applicable to, or zero if not role-specific</entry> + </row> + + <row> + <entry><structfield>setconfig</structfield></entry> + <entry><type>text[]</type></entry> + <entry></entry> + <entry>Defaults for run-time configuration variables</entry> + </row> + </tbody> + </tgroup> + </table> + </sect1> + <sect1 id="catalog-pg-shdepend"> <title><structname>pg_shdepend</structname></title> @@ -6557,13 +6614,6 @@ NULL if no expiration</entry> </row> - <row> - <entry><structfield>rolconfig</structfield></entry> - <entry><type>text[]</type></entry> - <entry></entry> - <entry>Session defaults for run-time configuration variables</entry> - </row> - <row> <entry><structfield>oid</structfield></entry> <entry><type>oid</type></entry> diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml index 9be5812463d0a232be26e18e83b926e403792ec7..2d09de10c4c1c5af7f31bb68fc07e740ee37a3ce 100644 --- a/doc/src/sgml/ref/alter_role.sgml +++ b/doc/src/sgml/ref/alter_role.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/alter_role.sgml,v 1.14 2009/09/19 10:23:26 petere Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/alter_role.sgml,v 1.15 2009/10/07 22:14:16 alvherre Exp $ PostgreSQL documentation --> @@ -37,10 +37,10 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replace ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable> -ALTER ROLE <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT } -ALTER ROLE <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT -ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET <replaceable>configuration_parameter</replaceable> -ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET ALL +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 </synopsis> </refsynopsisdiv> @@ -80,14 +80,16 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET ALL </para> <para> - The remaining variants change a role's session default for a - specified configuration variable. Whenever the role subsequently + The remaining variants change a role's session default for a configuration variable + for all databases or, when the <literal>IN DATABASE</literal> clause is specified, + for the named database. 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 postgres command line. This only happens at login time, so configuration settings associated with a role to which you've <xref - linkend="sql-set-role" endterm="sql-set-role-title"> will be ignored. + linkend="sql-set-role" endterm="sql-set-role-title"> will be ignored. Settings set to + a role directly are overridden by any database specific settings attached to a role. Superusers can change anyone's session defaults. Roles having <literal>CREATEROLE</> privilege can change defaults for non-superuser roles. Certain variables cannot be set this way, or can only be @@ -145,6 +147,15 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET ALL </listitem> </varlistentry> + <varlistentry> + <term><replaceable>database_name</replaceable></term> + <listitem> + <para> + The name of the database the configuration variable should be set in. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><replaceable>configuration_parameter</replaceable></term> <term><replaceable>value</replaceable></term> @@ -159,6 +170,8 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET ALL <literal>RESET ALL</literal> to clear all role-specific settings. <literal>SET FROM CURRENT</> saves the session's current value of the parameter as the role-specific value. + If used in conjunction with <literal>IN DATABASE</literal>, the configuration + parameter is set or removed for the given role and database only. </para> <para> @@ -207,8 +220,8 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET ALL It is also possible to tie a session default to a specific database rather than to a role; see <xref linkend="sql-alterdatabase" endterm="sql-alterdatabase-title">. - Role-specific settings override database-specific - ones if there is a conflict. + If there is a conflict, database-role-specific settings override role-specific + ones, which in turn override database-specific ones. </para> </refsect1> @@ -261,6 +274,15 @@ ALTER ROLE miriam CREATEROLE CREATEDB; <programlisting> ALTER ROLE worker_bee SET maintenance_work_mem = 100000; +</programlisting> + </para> + + <para> + Give a role a non-default, database-specific setting of the + <xref linkend="guc-client-min-messages"> parameter: + +<programlisting> +ALTER ROLE fred IN DATABASE devel SET client_min_messages = DEBUG; </programlisting> </para> </refsect1> diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 53784e9c54b07dfdd22a8b9435e13c74997b7682..ec548990b1003b850eb5883d2d87e4c25bf65fb1 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -2,7 +2,7 @@ # # Makefile for backend/catalog # -# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.72 2009/10/05 19:24:34 tgl Exp $ +# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.73 2009/10/07 22:14:16 alvherre Exp $ # #------------------------------------------------------------------------- @@ -13,7 +13,7 @@ include $(top_builddir)/src/Makefile.global OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \ pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \ - pg_shdepend.o pg_type.o storage.o toasting.o + pg_db_role_setting.o pg_shdepend.o pg_type.o storage.o toasting.o BKIFILES = postgres.bki postgres.description postgres.shdescription @@ -32,7 +32,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ - pg_database.h pg_tablespace.h pg_pltemplate.h \ + pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \ pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ pg_ts_parser.h pg_ts_template.h \ diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 42371d513735af739ecc0bc2645d3ad559f79696..82d02f9609a09eecbe047b2e41181e0ec01a5eed 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.83 2009/06/11 14:48:54 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.84 2009/10/07 22:14:18 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "catalog/pg_database.h" #include "catalog/pg_namespace.h" #include "catalog/pg_pltemplate.h" +#include "catalog/pg_db_role_setting.h" #include "catalog/pg_shdepend.h" #include "catalog/pg_shdescription.h" #include "catalog/pg_tablespace.h" @@ -306,7 +307,8 @@ IsSharedRelation(Oid relationId) relationId == PLTemplateRelationId || relationId == SharedDescriptionRelationId || relationId == SharedDependRelationId || - relationId == TableSpaceRelationId) + relationId == TableSpaceRelationId || + relationId == DbRoleSettingRelationId) return true; /* These are their indexes (see indexing.h) */ if (relationId == AuthIdRolnameIndexId || @@ -320,7 +322,8 @@ IsSharedRelation(Oid relationId) relationId == SharedDependDependerIndexId || relationId == SharedDependReferenceIndexId || relationId == TablespaceOidIndexId || - relationId == TablespaceNameIndexId) + relationId == TablespaceNameIndexId || + relationId == DbRoleSettingDatidRolidIndexId) return true; /* These are their toast tables and toast indexes (see toasting.h) */ if (relationId == PgAuthidToastTable || @@ -328,7 +331,9 @@ IsSharedRelation(Oid relationId) relationId == PgDatabaseToastTable || relationId == PgDatabaseToastIndex || relationId == PgShdescriptionToastTable || - relationId == PgShdescriptionToastIndex) + relationId == PgShdescriptionToastIndex || + relationId == PgDbRoleSettingToastTable || + relationId == PgDbRoleSettingToastIndex) return true; return false; } diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c new file mode 100644 index 0000000000000000000000000000000000000000..74870113d055fbfb6f2250b537285209bef73b1b --- /dev/null +++ b/src/backend/catalog/pg_db_role_setting.c @@ -0,0 +1,231 @@ +/* + * pg_db_role_setting.c + * Routines to support manipulation of the pg_db_role_setting relation + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/catalog/pg_db_role_setting.c,v 1.1 2009/10/07 22:14:18 alvherre Exp $ + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup.h" +#include "access/skey.h" +#include "catalog/indexing.h" +#include "catalog/pg_db_role_setting.h" +#include "utils/fmgroids.h" +#include "utils/rel.h" +#include "utils/tqual.h" + +void +AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) +{ + char *valuestr; + HeapTuple tuple; + Relation rel; + ScanKeyData scankey[2]; + SysScanDesc scan; + + valuestr = ExtractSetVariableArgs(setstmt); + + /* Get the old tuple, if any. */ + + rel = heap_open(DbRoleSettingRelationId, RowExclusiveLock); + ScanKeyInit(&scankey[0], + Anum_pg_db_role_setting_setdatabase, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(databaseid)); + ScanKeyInit(&scankey[1], + Anum_pg_db_role_setting_setrole, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(roleid)); + scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true, + SnapshotNow, 2, scankey); + tuple = systable_getnext(scan); + + /* + * There are three cases: + * + * - in RESET ALL, simply delete the pg_db_role_setting tuple (if any) + * + * - in other commands, if there's a tuple in pg_db_role_setting, update it; + * if it ends up empty, delete it + * + * - otherwise, insert a new pg_db_role_setting tuple, but only if the + * command is not RESET + */ + if (setstmt->kind == VAR_RESET_ALL) + { + if (HeapTupleIsValid(tuple)) + simple_heap_delete(rel, &tuple->t_self); + } + else if (HeapTupleIsValid(tuple)) + { + Datum repl_val[Natts_pg_db_role_setting]; + bool repl_null[Natts_pg_db_role_setting]; + bool repl_repl[Natts_pg_db_role_setting]; + HeapTuple newtuple; + Datum datum; + bool isnull; + ArrayType *a; + + memset(repl_repl, false, sizeof(repl_repl)); + repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true; + repl_null[Anum_pg_db_role_setting_setconfig - 1] = false; + + /* Extract old value of setconfig */ + datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig, + RelationGetDescr(rel), &isnull); + a = isnull ? NULL : DatumGetArrayTypeP(datum); + + /* Update (valuestr is NULL in RESET cases) */ + if (valuestr) + a = GUCArrayAdd(a, setstmt->name, valuestr); + else + a = GUCArrayDelete(a, setstmt->name); + + if (a) + { + repl_val[Anum_pg_db_role_setting_setconfig - 1] = + PointerGetDatum(a); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); + simple_heap_update(rel, &tuple->t_self, newtuple); + + /* Update indexes */ + CatalogUpdateIndexes(rel, newtuple); + } + else + simple_heap_delete(rel, &tuple->t_self); + } + else if (valuestr) + { + /* non-null valuestr means it's not RESET, so insert a new tuple */ + HeapTuple newtuple; + Datum values[Natts_pg_db_role_setting]; + bool nulls[Natts_pg_db_role_setting]; + ArrayType *a; + + memset(nulls, false, sizeof(nulls)); + + a = GUCArrayAdd(NULL, setstmt->name, valuestr); + + values[Anum_pg_db_role_setting_setdatabase - 1] = + ObjectIdGetDatum(databaseid); + values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid); + values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a); + newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + simple_heap_insert(rel, newtuple); + + /* Update indexes */ + CatalogUpdateIndexes(rel, newtuple); + } + + systable_endscan(scan); + + /* Close pg_db_role_setting, but keep lock till commit */ + heap_close(rel, NoLock); +} + +/* + * Drop some settings from the catalog. These can be for a particular + * database, or for a particular role. (It is of course possible to do both + * too, but it doesn't make sense for current uses.) + */ +void +DropSetting(Oid databaseid, Oid roleid) +{ + Relation relsetting; + HeapScanDesc scan; + ScanKeyData keys[2]; + HeapTuple tup; + int numkeys = 0; + + relsetting = heap_open(DbRoleSettingRelationId, RowExclusiveLock); + + if (OidIsValid(databaseid)) + { + ScanKeyInit(&keys[numkeys], + Anum_pg_db_role_setting_setdatabase, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(databaseid)); + numkeys++; + } + if (OidIsValid(roleid)) + { + ScanKeyInit(&keys[numkeys], + Anum_pg_db_role_setting_setrole, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(roleid)); + numkeys++; + } + + scan = heap_beginscan(relsetting, SnapshotNow, numkeys, keys); + while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection))) + { + simple_heap_delete(relsetting, &tup->t_self); + } + heap_endscan(scan); + + heap_close(relsetting, RowExclusiveLock); +} + +/* + * Scan pg_db_role_setting looking for applicable settings, and load them on + * the current process. + * + * relsetting is pg_db_role_setting, already opened and locked. + * + * Note: we only consider setting for the exact databaseid/roleid combination. + * This probably needs to be called more than once, with InvalidOid passed as + * databaseid/roleid. + */ +void +ApplySetting(Oid databaseid, Oid roleid, Relation relsetting, GucSource source) +{ + SysScanDesc scan; + ScanKeyData keys[2]; + HeapTuple tup; + + ScanKeyInit(&keys[0], + Anum_pg_db_role_setting_setdatabase, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(databaseid)); + ScanKeyInit(&keys[1], + Anum_pg_db_role_setting_setrole, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(roleid)); + + scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true, + SnapshotNow, 2, keys); + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + bool isnull; + Datum datum; + + datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig, + RelationGetDescr(relsetting), &isnull); + if (!isnull) + { + ArrayType *a = DatumGetArrayTypeP(datum); + + /* + * We process all the options at SUSET level. We assume that the + * right to insert an option into pg_db_role_setting was checked + * when it was inserted. + */ + ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET); + } + } + + systable_endscan(scan); +} diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 869ec1fdd57952d8ed106f18c23d28e46774f69e..be70143ea27e4ba554c9ffd13043b8d7912bc70a 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.35 2009/10/05 19:24:36 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.36 2009/10/07 22:14:18 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "catalog/pg_shdepend.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" +#include "commands/dbcommands.h" #include "commands/conversioncmds.h" #include "commands/defrem.h" #include "commands/proclang.h" @@ -55,7 +56,6 @@ typedef enum static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff); static Oid classIdGetDbId(Oid classId); -static void shdepLockAndCheckObject(Oid classId, Oid objectId); static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, int32 objsubid, Oid refclassid, Oid refobjid, @@ -963,7 +963,7 @@ classIdGetDbId(Oid classId) * weren't looking. If the object has been dropped, this function * does not return! */ -static void +void shdepLockAndCheckObject(Oid classId, Oid objectId) { /* AccessShareLock should be OK, since we are not modifying the object */ @@ -1003,6 +1003,21 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) } #endif + case DatabaseRelationId: + { + /* For lack of a syscache on pg_database, do this: */ + char *database = get_database_name(objectId); + + if (database == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("database %u was concurrently dropped", + objectId))); + pfree(database); + break; + } + + default: elog(ERROR, "unrecognized shared classId: %u", classId); } diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 73e391c896878fa71b3f08567a6df492ae49ce06..c2fbfcdf0a3ab48a8aacec6019d530f20f436645 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -3,7 +3,7 @@ * * Copyright (c) 1996-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.60 2009/04/07 00:31:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.61 2009/10/07 22:14:18 alvherre Exp $ */ CREATE VIEW pg_roles AS @@ -18,21 +18,23 @@ CREATE VIEW pg_roles AS rolconnlimit, '********'::text as rolpassword, rolvaliduntil, - rolconfig, - oid - FROM pg_authid; + setconfig as rolconfig, + pg_authid.oid + FROM pg_authid LEFT JOIN pg_db_role_setting s + ON (pg_authid.oid = setrole AND setdatabase = 0); CREATE VIEW pg_shadow AS SELECT rolname AS usename, - oid AS usesysid, + pg_authid.oid AS usesysid, rolcreatedb AS usecreatedb, rolsuper AS usesuper, rolcatupdate AS usecatupd, rolpassword AS passwd, rolvaliduntil::abstime AS valuntil, - rolconfig AS useconfig - FROM pg_authid + setconfig AS useconfig + FROM pg_authid LEFT JOIN pg_db_role_setting s + ON (pg_authid.oid = setrole AND setdatabase = 0) WHERE rolcanlogin; REVOKE ALL on pg_shadow FROM public; diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 2e6edc4832e2fbbc6ba2eed8d756623ea5769ffd..7df44c9ec41b77bf85b9dd65bb471d5d2026ad4b 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.226 2009/09/01 02:54:51 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.227 2009/10/07 22:14:18 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -33,6 +33,7 @@ #include "catalog/indexing.h" #include "catalog/pg_authid.h" #include "catalog/pg_database.h" +#include "catalog/pg_db_role_setting.h" #include "catalog/pg_tablespace.h" #include "commands/comment.h" #include "commands/dbcommands.h" @@ -50,7 +51,6 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" -#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/pg_locale.h" #include "utils/snapmgr.h" @@ -544,12 +544,10 @@ createdb(const CreatedbStmt *stmt) new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace); /* - * We deliberately set datconfig and datacl to defaults (NULL), rather - * than copying them from the template database. Copying datacl would be - * a bad idea when the owner is not the same as the template's owner. It's - * more debatable whether datconfig should be copied. + * We deliberately set datacl to default (NULL), rather than copying it + * from the template database. Copying it would be a bad idea when the + * owner is not the same as the template's owner. */ - new_record_nulls[Anum_pg_database_datconfig - 1] = true; new_record_nulls[Anum_pg_database_datacl - 1] = true; tuple = heap_form_tuple(RelationGetDescr(pg_database_rel), @@ -820,6 +818,11 @@ dropdb(const char *dbname, bool missing_ok) */ DeleteSharedComments(db_id, DatabaseRelationId); + /* + * Remove settings associated with this database + */ + DropSetting(db_id, InvalidOid); + /* * Remove shared dependency references for the database. */ @@ -1397,85 +1400,26 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) void AlterDatabaseSet(AlterDatabaseSetStmt *stmt) { - char *valuestr; - HeapTuple tuple, - newtuple; - Relation rel; - ScanKeyData scankey; - SysScanDesc scan; - Datum repl_val[Natts_pg_database]; - bool repl_null[Natts_pg_database]; - bool repl_repl[Natts_pg_database]; - - valuestr = ExtractSetVariableArgs(stmt->setstmt); + Oid datid = get_database_oid(stmt->dbname); + if (!OidIsValid(datid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", stmt->dbname))); + /* - * Get the old tuple. We don't need a lock on the database per se, - * because we're not going to do anything that would mess up incoming - * connections. + * Obtain a lock on the database and make sure it didn't go away in the + * meantime. */ - rel = heap_open(DatabaseRelationId, RowExclusiveLock); - ScanKeyInit(&scankey, - Anum_pg_database_datname, - BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(stmt->dbname)); - scan = systable_beginscan(rel, DatabaseNameIndexId, true, - SnapshotNow, 1, &scankey); - tuple = systable_getnext(scan); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist", stmt->dbname))); + shdepLockAndCheckObject(DatabaseRelationId, datid); - if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->dbname); - - memset(repl_repl, false, sizeof(repl_repl)); - repl_repl[Anum_pg_database_datconfig - 1] = true; - - if (stmt->setstmt->kind == VAR_RESET_ALL) - { - /* RESET ALL, so just set datconfig to null */ - repl_null[Anum_pg_database_datconfig - 1] = true; - repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0; - } - else - { - Datum datum; - bool isnull; - ArrayType *a; - - repl_null[Anum_pg_database_datconfig - 1] = false; - - /* Extract old value of datconfig */ - datum = heap_getattr(tuple, Anum_pg_database_datconfig, - RelationGetDescr(rel), &isnull); - a = isnull ? NULL : DatumGetArrayTypeP(datum); - - /* Update (valuestr is NULL in RESET cases) */ - if (valuestr) - a = GUCArrayAdd(a, stmt->setstmt->name, valuestr); - else - a = GUCArrayDelete(a, stmt->setstmt->name); + if (!pg_database_ownercheck(datid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + stmt->dbname); - if (a) - repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a); - else - repl_null[Anum_pg_database_datconfig - 1] = true; - } - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); - simple_heap_update(rel, &tuple->t_self, newtuple); - - /* Update indexes */ - CatalogUpdateIndexes(rel, newtuple); - - systable_endscan(scan); - - /* Close pg_database, but keep lock till commit */ - heap_close(rel, NoLock); + AlterSetting(datid, InvalidOid, stmt->setstmt); + + UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock); } diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index c157ead4726e7eaf34e6a53d8b8ec70e7a4302d2..ef546cf3602b9572e8091c2f804efc724847b7fc 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.188 2009/09/01 02:54:51 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.189 2009/10/07 22:14:19 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,10 @@ #include "catalog/indexing.h" #include "catalog/pg_auth_members.h" #include "catalog/pg_authid.h" +#include "catalog/pg_database.h" +#include "catalog/pg_db_role_setting.h" #include "commands/comment.h" +#include "commands/dbcommands.h" #include "commands/user.h" #include "libpq/md5.h" #include "miscadmin.h" @@ -27,7 +30,6 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" -#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -341,8 +343,6 @@ CreateRole(CreateRoleStmt *stmt) else new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = true; - new_record_nulls[Anum_pg_authid_rolconfig - 1] = true; - tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls); /* @@ -715,30 +715,29 @@ AlterRole(AlterRoleStmt *stmt) void AlterRoleSet(AlterRoleSetStmt *stmt) { - char *valuestr; - HeapTuple oldtuple, - newtuple; - Relation rel; - Datum repl_val[Natts_pg_authid]; - bool repl_null[Natts_pg_authid]; - bool repl_repl[Natts_pg_authid]; + HeapTuple roletuple; + Oid databaseid = InvalidOid; - valuestr = ExtractSetVariableArgs(stmt->setstmt); + roletuple = SearchSysCache(AUTHNAME, + PointerGetDatum(stmt->role), + 0, 0, 0); - rel = heap_open(AuthIdRelationId, RowExclusiveLock); - oldtuple = SearchSysCache(AUTHNAME, - PointerGetDatum(stmt->role), - 0, 0, 0); - if (!HeapTupleIsValid(oldtuple)) + if (!HeapTupleIsValid(roletuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", stmt->role))); + /* + * 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(oldtuple))->rolsuper) + if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper) { if (!superuser()) ereport(ERROR, @@ -748,54 +747,25 @@ AlterRoleSet(AlterRoleSetStmt *stmt) else { if (!have_createrole_privilege() && - HeapTupleGetOid(oldtuple) != GetUserId()) + HeapTupleGetOid(roletuple) != GetUserId()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied"))); } - memset(repl_repl, false, sizeof(repl_repl)); - repl_repl[Anum_pg_authid_rolconfig - 1] = true; - - if (stmt->setstmt->kind == VAR_RESET_ALL) + /* look up and lock the database, if specified */ + if (stmt->database != NULL) { - /* RESET ALL, so just set rolconfig to null */ - repl_null[Anum_pg_authid_rolconfig - 1] = true; - repl_val[Anum_pg_authid_rolconfig - 1] = (Datum) 0; - } - else - { - Datum datum; - bool isnull; - ArrayType *array; - - repl_null[Anum_pg_authid_rolconfig - 1] = false; - - /* Extract old value of rolconfig */ - datum = SysCacheGetAttr(AUTHNAME, oldtuple, - Anum_pg_authid_rolconfig, &isnull); - array = isnull ? NULL : DatumGetArrayTypeP(datum); - - /* Update (valuestr is NULL in RESET cases) */ - if (valuestr) - array = GUCArrayAdd(array, stmt->setstmt->name, valuestr); - else - array = GUCArrayDelete(array, stmt->setstmt->name); - - if (array) - repl_val[Anum_pg_authid_rolconfig - 1] = PointerGetDatum(array); - else - repl_null[Anum_pg_authid_rolconfig - 1] = true; + databaseid = get_database_oid(stmt->database); + if (!OidIsValid(databaseid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("database \"%s\" not found", stmt->database))); + shdepLockAndCheckObject(DatabaseRelationId, databaseid); } - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); - - simple_heap_update(rel, &oldtuple->t_self, newtuple); - CatalogUpdateIndexes(rel, newtuple); - - ReleaseSysCache(oldtuple); - heap_close(rel, RowExclusiveLock); + AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt); + ReleaseSysCache(roletuple); } @@ -943,6 +913,11 @@ DropRole(DropRoleStmt *stmt) */ DeleteSharedComments(roleid, AuthIdRelationId); + /* + * Remove settings for this role. + */ + DropSetting(InvalidOid, roleid); + /* * Advance command counter so that later iterations of this loop will * see the changes already made. This is essential if, for example, diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 7c3cb049b0934753489ed48cd8a2524f503bbcbe..9319aa84c5edb1d9d525989b48246d105032d8c2 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.440 2009/10/06 00:55:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.441 2009/10/07 22:14:20 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -3174,6 +3174,7 @@ _copyAlterRoleSetStmt(AlterRoleSetStmt *from) AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt); COPY_STRING_FIELD(role); + COPY_STRING_FIELD(database); COPY_NODE_FIELD(setstmt); return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index bf978f871de494a4a43fbb496a9f39720edf9a7b..6a61112b99c366d960470dde1e310e4025eb129d 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -22,7 +22,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.363 2009/10/06 00:55:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.364 2009/10/07 22:14:20 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -1725,6 +1725,7 @@ static bool _equalAlterRoleSetStmt(AlterRoleSetStmt *a, AlterRoleSetStmt *b) { COMPARE_STRING_FIELD(role); + COMPARE_STRING_FIELD(database); COMPARE_NODE_FIELD(setstmt); return true; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index af2f080b6341938684e2e6897691617e149d4143..ed265f516b293deda53d3a5ed3cc3c1179baa0a0 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.680 2009/10/05 19:24:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.681 2009/10/07 22:14:21 alvherre Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -237,12 +237,13 @@ static TypeName *TableFuncTypeName(List *columns); opt_grant_grant_option opt_grant_admin_option opt_nowait opt_if_exists opt_with_data -%type <list> OptRoleList -%type <defelt> OptRoleElem +%type <list> OptRoleList AlterOptRoleList +%type <defelt> CreateOptRoleElem AlterOptRoleElem %type <str> opt_type %type <str> foreign_server_version opt_foreign_server_version %type <str> auth_ident +%type <str> opt_in_database %type <str> OptSchemaName %type <list> OptSchemaEltList @@ -762,11 +763,16 @@ opt_with: WITH {} * is "WITH ADMIN name". */ OptRoleList: - OptRoleList OptRoleElem { $$ = lappend($1, $2); } + OptRoleList CreateOptRoleElem { $$ = lappend($1, $2); } | /* EMPTY */ { $$ = NIL; } ; -OptRoleElem: +AlterOptRoleList: + AlterOptRoleList AlterOptRoleElem { $$ = lappend($1, $2); } + | /* EMPTY */ { $$ = NIL; } + ; + +AlterOptRoleElem: PASSWORD Sconst { $$ = makeDefElem("password", @@ -848,7 +854,11 @@ OptRoleElem: { $$ = makeDefElem("rolemembers", (Node *)$2); } - /* The following are not supported by ALTER ROLE/USER/GROUP */ + ; + +CreateOptRoleElem: + AlterOptRoleElem { $$ = $1; } + /* The following are not supported by ALTER ROLE/USER/GROUP */ | SYSID Iconst { $$ = makeDefElem("sysid", (Node *)makeInteger($2)); @@ -897,7 +907,7 @@ CreateUserStmt: *****************************************************************************/ AlterRoleStmt: - ALTER ROLE RoleId opt_with OptRoleList + ALTER ROLE RoleId opt_with AlterOptRoleList { AlterRoleStmt *n = makeNode(AlterRoleStmt); n->role = $3; @@ -907,12 +917,18 @@ AlterRoleStmt: } ; +opt_in_database: + /* EMPTY */ { $$ = NULL; } + | IN_P DATABASE database_name { $$ = $3; } + ; + AlterRoleSetStmt: - ALTER ROLE RoleId SetResetClause + ALTER ROLE RoleId opt_in_database SetResetClause { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = $3; - n->setstmt = $4; + n->database = $4; + n->setstmt = $5; $$ = (Node *)n; } ; @@ -925,7 +941,7 @@ AlterRoleSetStmt: *****************************************************************************/ AlterUserStmt: - ALTER USER RoleId opt_with OptRoleList + ALTER USER RoleId opt_with AlterOptRoleList { AlterRoleStmt *n = makeNode(AlterRoleStmt); n->role = $3; @@ -941,6 +957,7 @@ AlterUserSetStmt: { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = $3; + n->database = NULL; n->setstmt = $4; $$ = (Node *)n; } diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 85f1507ba366a507d50ca37d7f4cee1290ab6830..f7a27b9e43018f480b06fcfac480ec423d61ab77 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.177 2009/08/27 16:59:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.178 2009/10/07 22:14:22 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -392,8 +392,6 @@ InitializeSessionUserId(const char *rolename) { HeapTuple roleTup; Form_pg_authid rform; - Datum datum; - bool isnull; Oid roleid; /* @@ -470,24 +468,6 @@ InitializeSessionUserId(const char *rolename) AuthenticatedUserIsSuperuser ? "on" : "off", PGC_INTERNAL, PGC_S_OVERRIDE); - /* - * Set up user-specific configuration variables. This is a good place to - * do it so we don't have to read pg_authid twice during session startup. - */ - datum = SysCacheGetAttr(AUTHNAME, roleTup, - Anum_pg_authid_rolconfig, &isnull); - if (!isnull) - { - ArrayType *a = DatumGetArrayTypeP(datum); - - /* - * We process all the options at SUSET level. We assume that the - * right to insert an option into pg_authid was checked when it was - * inserted. - */ - ProcessGUCArray(a, PGC_SUSET, PGC_S_USER, GUC_ACTION_SET); - } - ReleaseSysCache(roleTup); } diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 5321afc1b8d4da0bd50f0c18384132aa3e0bcb92..b6c93c7f8ebbd8cf8c2fbae7f447c1ca3dc2812d 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.197 2009/09/01 00:09:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.198 2009/10/07 22:14:23 alvherre Exp $ * * *------------------------------------------------------------------------- @@ -27,6 +27,7 @@ #include "catalog/namespace.h" #include "catalog/pg_authid.h" #include "catalog/pg_database.h" +#include "catalog/pg_db_role_setting.h" #include "catalog/pg_tablespace.h" #include "libpq/auth.h" #include "libpq/libpq-be.h" @@ -63,6 +64,7 @@ static void CheckMyDatabase(const char *name, bool am_superuser); static void InitCommunication(void); static void ShutdownPostgres(int code, Datum arg); static bool ThereIsAtLeastOneRole(void); +static void process_settings(Oid databaseid, Oid roleid); /*** InitPostgres support ***/ @@ -344,29 +346,6 @@ CheckMyDatabase(const char *name, bool am_superuser) pg_bind_textdomain_codeset(textdomain(NULL)); #endif - /* - * Lastly, set up any database-specific configuration variables. - */ - if (IsUnderPostmaster) - { - Datum datum; - bool isnull; - - datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_datconfig, - &isnull); - if (!isnull) - { - ArrayType *a = DatumGetArrayTypeP(datum); - - /* - * We process all the options at SUSET level. We assume that the - * right to insert an option into pg_database was checked when it - * was inserted. - */ - ProcessGUCArray(a, PGC_SUSET, PGC_S_DATABASE, GUC_ACTION_SET); - } - } - ReleaseSysCache(tup); } @@ -739,6 +718,9 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, /* set up ACL framework (so CheckMyDatabase can check permissions) */ initialize_acl(); + /* Process pg_db_role_setting options */ + process_settings(MyDatabaseId, GetSessionUserId()); + /* * Re-read the pg_database row for our database, check permissions and * set up database-specific GUC settings. We can't do this until all the @@ -851,6 +833,28 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, CommitTransactionCommand(); } +/* + * Load GUC settings from pg_db_role_setting. + * + * We try specific settings for the database/role combination, as well as + * general for this database and for this user. + */ +static void +process_settings(Oid databaseid, Oid roleid) +{ + Relation relsetting; + + if (!IsUnderPostmaster) + return; + + relsetting = heap_open(DbRoleSettingRelationId, AccessShareLock); + + ApplySetting(databaseid, roleid, relsetting, PGC_S_DATABASE_USER); + ApplySetting(InvalidOid, roleid, relsetting, PGC_S_USER); + ApplySetting(databaseid, InvalidOid, relsetting, PGC_S_DATABASE); + + heap_close(relsetting, AccessShareLock); +} /* * Backend-shutdown callback. Do cleanup that we want to be sure happens diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index a9a27625707928e276249ef8cbf3e5dff6342a7a..f8aa9e64b9107e58e8cf0cf778d958b57446d381 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.49 2009/10/05 19:24:45 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.50 2009/10/07 22:14:24 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -942,7 +942,8 @@ AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname) * * Scan a wildcard-pattern string and generate appropriate WHERE clauses * to limit the set of objects returned. The WHERE clauses are appended - * to the already-partially-constructed query in buf. + * to the already-partially-constructed query in buf. Returns whether + * any clause was added. * * conn: connection query will be sent to (consulted for escaping rules). * buf: output parameter. @@ -961,7 +962,7 @@ AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname) * Formatting note: the text already present in buf should end with a newline. * The appended text, if any, will end with one too. */ -void +bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, @@ -973,9 +974,11 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool inquotes; const char *cp; int i; + bool added_clause = false; #define WHEREAND() \ - (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), have_where = true) + (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), \ + have_where = true, added_clause = true) if (pattern == NULL) { @@ -985,7 +988,7 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, WHEREAND(); appendPQExpBuffer(buf, "%s\n", visibilityrule); } - return; + return added_clause; } initPQExpBuffer(&schemabuf); @@ -1142,5 +1145,6 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, termPQExpBuffer(&schemabuf); termPQExpBuffer(&namebuf); + return added_clause; #undef WHEREAND } diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index a5bfe1bcfda30d8a620ce988567094f70d260c0b..0b73701eb8a76541ec4d040ec01ec9caa07a7536 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.26 2009/10/05 19:24:45 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.27 2009/10/07 22:14:24 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -40,7 +40,7 @@ extern bool buildDefaultACLCommands(const char *type, const char *nspname, const char *acls, const char *owner, int remoteVersion, PQExpBuffer sql); -extern void processSQLNamePattern(PGconn *conn, PQExpBuffer buf, +extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index f0a4d67d2afc9b457598bf3033755b0767943ffb..5567b07cafc27736fad8a573527d35c488d6fc50 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.127 2009/10/05 19:24:46 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.128 2009/10/07 22:14:24 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -43,8 +43,10 @@ static void dropDBs(PGconn *conn); static void dumpCreateDB(PGconn *conn); static void dumpDatabaseConfig(PGconn *conn, const char *dbname); static void dumpUserConfig(PGconn *conn, const char *username); +static void dumpDbRoleConfig(PGconn *conn); static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem, - const char *type, const char *name); + const char *type, const char *name, const char *type2, + const char *name2); static void dumpDatabases(PGconn *conn); static void dumpTimestamp(char *msg); static void doShellQuoting(PQExpBuffer buf, const char *str); @@ -501,6 +503,13 @@ main(int argc, char *argv[]) /* Dump CREATE DATABASE commands */ if (!globals_only && !roles_only && !tablespaces_only) dumpCreateDB(conn); + + /* Dump role/database settings */ + if (!tablespaces_only && !roles_only) + { + if (server_version >= 80500) + dumpDbRoleConfig(conn); + } } if (!globals_only && !roles_only && !tablespaces_only) @@ -1325,15 +1334,24 @@ dumpDatabaseConfig(PGconn *conn, const char *dbname) { PGresult *res; - printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count); + if (server_version >= 80500) + printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE " + "setrole = 0 AND setdatabase = (SELECT oid FROM pg_database WHERE datname = ", count); + else + printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count); appendStringLiteralConn(buf, dbname, conn); + + if (server_version >= 80500) + appendPQExpBuffer(buf, ")"); + appendPQExpBuffer(buf, ";"); res = executeQuery(conn, buf->data); - if (!PQgetisnull(res, 0, 0)) + if (PQntuples(res) == 1 && + !PQgetisnull(res, 0, 0)) { makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0), - "DATABASE", dbname); + "DATABASE", dbname, NULL, NULL); PQclear(res); count++; } @@ -1362,18 +1380,24 @@ dumpUserConfig(PGconn *conn, const char *username) { PGresult *res; - if (server_version >= 80100) + if (server_version >= 80500) + printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE " + "setdatabase = 0 AND setrole = " + "(SELECT oid FROM pg_authid WHERE rolname = ", count); + else if (server_version >= 80100) printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM pg_authid WHERE rolname = ", count); else printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count); appendStringLiteralConn(buf, username, conn); + if (server_version >= 80500) + appendPQExpBuffer(buf, ")"); res = executeQuery(conn, buf->data); if (PQntuples(res) == 1 && !PQgetisnull(res, 0, 0)) { makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0), - "ROLE", username); + "ROLE", username, NULL, NULL); PQclear(res); count++; } @@ -1388,13 +1412,47 @@ dumpUserConfig(PGconn *conn, const char *username) } +/* + * Dump user-and-database-specific configuration + */ +static void +dumpDbRoleConfig(PGconn *conn) +{ + PQExpBuffer buf = createPQExpBuffer(); + PGresult *res; + int i; + + printfPQExpBuffer(buf, "SELECT rolname, datname, unnest(setconfig) " + "FROM pg_db_role_setting, pg_authid, pg_database " + "WHERE setrole = pg_authid.oid AND setdatabase = pg_database.oid"); + res = executeQuery(conn, buf->data); + + if (PQntuples(res) > 0) + { + fprintf(OPF, "--\n-- Per-Database Role Settings \n--\n\n"); + + for (i = 0; i < PQntuples(res); i++) + { + makeAlterConfigCommand(conn, PQgetvalue(res, i, 2), + "ROLE", PQgetvalue(res, i, 0), + "DATABASE", PQgetvalue(res, i, 1)); + } + + fprintf(OPF, "\n\n"); + } + + PQclear(res); + destroyPQExpBuffer(buf); +} + /* * Helper function for dumpXXXConfig(). */ static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem, - const char *type, const char *name) + const char *type, const char *name, + const char *type2, const char *name2) { char *pos; char *mine; @@ -1407,6 +1465,8 @@ makeAlterConfigCommand(PGconn *conn, const char *arrayitem, *pos = 0; appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name)); + if (type2 != NULL && name2 != NULL) + appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2)); appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine)); /* diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index d94d8b80c526c833c5ac3de797acf0613abffb73..cea3942f013be4637cc5d8c946da4e15f6829233 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.208 2009/10/05 19:24:46 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.209 2009/10/07 22:14:24 alvherre Exp $ */ #include "postgres_fe.h" #include "command.h" @@ -411,6 +411,19 @@ exec_command(const char *cmd, case 's': success = listTables(&cmd[1], pattern, show_verbose, show_system); break; + case 'r': + if (cmd[2] == 'd' && cmd[3] == 's') + { + char *pattern2 = NULL; + + if (pattern) + pattern2 = psql_scan_slash_option(scan_state, + OT_NORMAL, NULL, true); + success = listDbRoleSettings(pattern, pattern2); + } + else + success = PSQL_CMD_UNKNOWN; + break; case 'u': success = describeRoles(pattern, show_verbose); break; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 1644623812c991982d160dbf187e44880ae61156..0c49d812eea095b78eef0ef1fc32e9680e53b592 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -8,7 +8,7 @@ * * Copyright (c) 2000-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.227 2009/10/05 19:24:46 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.228 2009/10/07 22:14:24 alvherre Exp $ */ #include "postgres_fe.h" @@ -2243,6 +2243,65 @@ add_role_attribute(PQExpBuffer buf, const char *const str) appendPQExpBufferStr(buf, str); } +/* + * \drds + */ +bool +listDbRoleSettings(const char *pattern, const char *pattern2) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + initPQExpBuffer(&buf); + + if (pset.sversion >= 80500) + { + bool havewhere; + + printfPQExpBuffer(&buf, "SELECT rolname AS role, datname AS database,\n" + "pg_catalog.array_to_string(setconfig, E'\\n') AS settings\n" + "FROM pg_db_role_setting AS s\n" + "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n" + "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n"); + havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false, + NULL, "pg_roles.rolname", NULL, NULL); + processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false, + NULL, "pg_database.datname", NULL, NULL); + appendPQExpBufferStr(&buf, "ORDER BY role, database"); + } + else + { + fprintf(pset.queryFout, + _("No per-database role settings support in this server version.\n")); + return false; + } + + res = PSQLexec(buf.data, false); + if (!res) + return false; + + if (PQntuples(res) == 0 && !pset.quiet) + { + if (pattern) + fprintf(pset.queryFout, _("No matching settings found.\n")); + else + fprintf(pset.queryFout, _("No settings found.\n")); + } + else + { + myopt.nullPrint = NULL; + myopt.title = _("List of settings"); + myopt.translate_header = true; + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + } + + PQclear(res); + resetPQExpBuffer(&buf); + return true; +} + /* * listTables() diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 169ceb3739ad2ec68f484dc1da87ec908c4dd69c..aaef69d703d81609abed4a41bb5999af822322f8 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.41 2009/10/05 19:24:46 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.42 2009/10/07 22:14:24 alvherre Exp $ */ #ifndef DESCRIBE_H #define DESCRIBE_H @@ -27,6 +27,9 @@ extern bool describeOperators(const char *pattern, bool showSystem); /* \du, \dg */ extern bool describeRoles(const char *pattern, bool verbose); +/* \drds */ +extern bool listDbRoleSettings(const char *pattern1, const char *pattern2); + /* \z (or \dp) */ extern bool permissionsList(const char *pattern); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 1d3bfb0726cc989ebf006994cbd1051cccab6c56..20eac6aa1c752eba7c992193381aebe83291cec3 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.541 2009/10/05 19:24:46 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.542 2009/10/07 22:14:24 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200910051 +#define CATALOG_VERSION_NO 200910071 #endif diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 954d3808a855aff69408ab23305161cd3c182264..5134479c3d03988dadbc7235f23eda0048988cf2 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.41 2009/10/05 19:24:48 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.42 2009/10/07 22:14:24 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -238,6 +238,8 @@ extern void updateAclDependencies(Oid classId, Oid objectId, int32 objectSubId, extern bool checkSharedDependencies(Oid classId, Oid objectId, char **detail_msg, char **detail_log_msg); +extern void shdepLockAndCheckObject(Oid classId, Oid objectId); + extern void copyTemplateDependencies(Oid templateDbId, Oid newDbId); extern void dropDatabaseDependencies(Oid databaseId); diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 0272334f2e52da8c9992dda4a61bb07befa83ef8..4f9f9e9c2acfe36941f8d32cbf223c99f5156d32 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.109 2009/10/05 19:24:48 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.110 2009/10/07 22:14:25 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -272,6 +272,9 @@ DECLARE_UNIQUE_INDEX(pg_default_acl_role_nsp_obj_index, 827, on pg_default_acl u DECLARE_UNIQUE_INDEX(pg_default_acl_oid_index, 828, on pg_default_acl using btree(oid oid_ops)); #define DefaultAclOidIndexId 828 +DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops)); +#define DbRoleSettingDatidRolidIndexId 2965 + /* last step of initialization script: build the indexes declared above */ BUILD_INDICES diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 1315e4241aca0fc2c8e5b6e220577cb056bc4064..f5a737f9f0080b9c5a9b7f2e6daf2e12c23a75e7 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.153 2009/09/26 22:42:02 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.154 2009/10/07 22:14:25 alvherre Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -486,8 +486,7 @@ DATA(insert ( 1259 tableoid 26 0 0 4 -7 0 -1 -1 t p i t f f t 0 _null_)); { 1262, {"datlastsysoid"}, 26, -1, 0, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \ { 1262, {"datfrozenxid"}, 28, -1, 0, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \ { 1262, {"dattablespace"}, 26, -1, 0, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \ -{ 1262, {"datconfig"}, 1009, -1, 0, -1, 12, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \ -{ 1262, {"datacl"}, 1034, -1, 0, -1, 13, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } } +{ 1262, {"datacl"}, 1034, -1, 0, -1, 12, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } } /* ---------------- * pg_index diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index 660c3c7c1473d8130872570524a00eba6a7a4cdf..a8fdcf748a55e9c230608136aa8ccf054b7383bc 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_authid.h,v 1.9 2009/01/01 17:23:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_authid.h,v 1.10 2009/10/07 22:14:25 alvherre Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -55,7 +55,6 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION /* remaining fields may be null; use heap_getattr to read them! */ text rolpassword; /* password, if any */ timestamptz rolvaliduntil; /* password expiration time, if any */ - text rolconfig[1]; /* GUC settings to apply at login */ } FormData_pg_authid; #undef timestamptz @@ -83,7 +82,6 @@ typedef FormData_pg_authid *Form_pg_authid; #define Anum_pg_authid_rolconnlimit 8 #define Anum_pg_authid_rolpassword 9 #define Anum_pg_authid_rolvaliduntil 10 -#define Anum_pg_authid_rolconfig 11 /* ---------------- * initial contents of pg_authid @@ -92,7 +90,7 @@ typedef FormData_pg_authid *Form_pg_authid; * user choices. * ---------------- */ -DATA(insert OID = 10 ( "POSTGRES" t t t t t t -1 _null_ _null_ _null_ )); +DATA(insert OID = 10 ( "POSTGRES" t t t t t t -1 _null_ _null_ )); #define BOOTSTRAP_SUPERUSERID 10 diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h index 730c23c8635925f755df2e1f67e8ab5f9b7f41d5..e041fe1154bc83645832adf6494b82dbf965d28a 100644 --- a/src/include/catalog/pg_database.h +++ b/src/include/catalog/pg_database.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.50 2009/09/26 22:42:02 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.51 2009/10/07 22:14:25 alvherre Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -42,7 +42,6 @@ CATALOG(pg_database,1262) BKI_SHARED_RELATION BKI_ROWTYPE_OID(1248) Oid datlastsysoid; /* highest OID to consider a system OID */ TransactionId datfrozenxid; /* all Xids < this are frozen in this DB */ Oid dattablespace; /* default table space for this DB */ - text datconfig[1]; /* database-specific GUC (VAR LENGTH) */ aclitem datacl[1]; /* access permissions (VAR LENGTH) */ } FormData_pg_database; @@ -57,7 +56,7 @@ typedef FormData_pg_database *Form_pg_database; * compiler constants for pg_database * ---------------- */ -#define Natts_pg_database 13 +#define Natts_pg_database 12 #define Anum_pg_database_datname 1 #define Anum_pg_database_datdba 2 #define Anum_pg_database_encoding 3 @@ -69,10 +68,9 @@ typedef FormData_pg_database *Form_pg_database; #define Anum_pg_database_datlastsysoid 9 #define Anum_pg_database_datfrozenxid 10 #define Anum_pg_database_dattablespace 11 -#define Anum_pg_database_datconfig 12 -#define Anum_pg_database_datacl 13 +#define Anum_pg_database_datacl 12 -DATA(insert OID = 1 ( template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_ _null_)); +DATA(insert OID = 1 ( template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_)); SHDESCR("default template database"); #define TemplateDbOid 1 diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h new file mode 100644 index 0000000000000000000000000000000000000000..7c8e8224ae6a7d4077d70cb5ce9158c3062e1ffc --- /dev/null +++ b/src/include/catalog/pg_db_role_setting.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------- + * + * pg_db_role_setting.h + * definition of configuration settings + * + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL: pgsql/src/include/catalog/pg_db_role_setting.h,v 1.1 2009/10/07 22:14:25 alvherre Exp $ + * + * NOTES + * the genbki.sh script reads this file and generates .bki + * information from the DATA() statements. + * + * XXX do NOT break up DATA() statements into multiple lines! + * the scripts are not as smart as you might think... + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DB_ROLE_SETTING_H +#define PG_DB_ROLE_SETTING_H + +#include "catalog/genbki.h" +#include "nodes/parsenodes.h" +#include "utils/guc.h" +#include "utils/relcache.h" + +/* ---------------- + * pg_db_role_setting definition. cpp turns this into + * typedef struct FormData_pg_db_role_setting + * ---------------- + */ +#define DbRoleSettingRelationId 2964 + +CATALOG(pg_db_role_setting,2964) BKI_SHARED_RELATION BKI_WITHOUT_OIDS +{ + Oid setdatabase; /* database */ + Oid setrole; /* role */ + text setconfig[1]; /* GUC settings to apply at login */ +} FormData_pg_db_role_setting; + +typedef FormData_pg_db_role_setting *Form_pg_db_role_setting; + +/* ---------------- + * compiler constants for pg_db_role_setting + * ---------------- + */ +#define Natts_pg_db_role_setting 3 +#define Anum_pg_db_role_setting_setdatabase 1 +#define Anum_pg_db_role_setting_setrole 2 +#define Anum_pg_db_role_setting_setconfig 3 + +/* ---------------- + * initial contents of pg_db_role_setting are NOTHING + * ---------------- + */ + +/* + * prototypes for functions in pg_db_role_setting.h + */ +extern void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt); +extern void DropSetting(Oid databaseid, Oid roleid); +extern void ApplySetting(Oid databaseid, Oid roleid, Relation relsetting, + GucSource source); + +#endif /* PG_DB_ROLE_SETTING_H */ diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h index 5f4a4a79e2966a4b11b5c116b428888b5fb28ca5..fb83aa75df58b0f9870fdb313b7d2b77ebe36bec 100644 --- a/src/include/catalog/toasting.h +++ b/src/include/catalog/toasting.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.8 2009/06/11 20:46:11 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.9 2009/10/07 22:14:25 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -58,5 +58,8 @@ DECLARE_TOAST(pg_database, 2844, 2845); DECLARE_TOAST(pg_shdescription, 2846, 2847); #define PgShdescriptionToastTable 2846 #define PgShdescriptionToastIndex 2847 +DECLARE_TOAST(pg_db_role_setting, 2966, 2967); +#define PgDbRoleSettingToastTable 2966 +#define PgDbRoleSettingToastIndex 2967 #endif /* TOASTING_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index b182dcfd53f3b183de11c90df6f49ed8703d4dde..5f0d763b688738278051bc76cee542b37658e966 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.404 2009/10/06 00:55:26 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.405 2009/10/07 22:14:26 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -1629,6 +1629,7 @@ typedef struct AlterRoleSetStmt { NodeTag type; char *role; /* role name */ + char *database; /* database name, or NULL */ VariableSetStmt *setstmt; /* SET or RESET subcommand */ } AlterRoleSetStmt; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index ef93d0f27cd1128fc62c0683555abf93aae852b4..5c59b02e4f4b99356184e004dbc05e2f32e9e5b7 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -7,7 +7,7 @@ * Copyright (c) 2000-2009, PostgreSQL Global Development Group * Written by Peter Eisentraut <peter_e@gmx.net>. * - * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.106 2009/10/03 18:04:57 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.107 2009/10/07 22:14:26 alvherre Exp $ *-------------------------------------------------------------------- */ #ifndef GUC_H @@ -86,6 +86,7 @@ typedef enum PGC_S_ARGV, /* postmaster command line */ PGC_S_DATABASE, /* per-database setting */ PGC_S_USER, /* per-user setting */ + PGC_S_DATABASE_USER, /* per-user-and-database setting */ PGC_S_CLIENT, /* from client connection request */ PGC_S_OVERRIDE, /* special case to forcibly set default */ PGC_S_INTERACTIVE, /* dividing line for error reporting */ diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 9244376a3b98f2f0b1b813c9e9ac9d9ef445efce..9561a2355940d9a39d0b06b3078fd6e7ff12b512 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1285,10 +1285,10 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem pg_locks | SELECT l.locktype, l.database, l.relation, l.page, l.tuple, l.virtualxid, l.transactionid, l.classid, l.objid, l.objsubid, l.virtualtransaction, l.pid, l.mode, l.granted FROM pg_lock_status() l(locktype, database, relation, page, tuple, virtualxid, transactionid, classid, objid, objsubid, virtualtransaction, pid, mode, granted); pg_prepared_statements | SELECT p.name, p.statement, p.prepare_time, p.parameter_types, p.from_sql FROM pg_prepared_statement() p(name, statement, prepare_time, parameter_types, from_sql); pg_prepared_xacts | SELECT p.transaction, p.gid, p.prepared, u.rolname AS owner, d.datname AS database FROM ((pg_prepared_xact() p(transaction, gid, prepared, ownerid, dbid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid))); - pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig, pg_authid.oid FROM pg_authid; + pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, s.setconfig AS rolconfig, pg_authid.oid FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))); pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline); - pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin; + pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin; pg_stat_activity | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.current_query, s.waiting, s.xact_start, s.query_start, s.backend_start, s.client_addr, s.client_port FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid)); pg_stat_all_indexes | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])); pg_stat_all_tables | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname; diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index 1994edc905e32e356965c78edd0ff0593844d4de..fe0d93670f8f7df5a133abf766770dffacae3826 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -95,6 +95,7 @@ SELECT relname, relhasindex pg_constraint | t pg_conversion | t pg_database | t + pg_db_role_setting | t pg_default_acl | t pg_depend | t pg_description | t @@ -152,7 +153,7 @@ SELECT relname, relhasindex timetz_tbl | f tinterval_tbl | f varchar_tbl | f -(141 rows) +(142 rows) -- -- another sanity check: every system catalog that has OIDs should have