Make it possibly to specify GUC params per user and per database.
authorAlvaro Herrera
Wed, 7 Oct 2009 22:14:26 +0000 (22:14 +0000)
committerAlvaro Herrera
Wed, 7 Oct 2009 22:14:26 +0000 (22:14 +0000)
Create a new catalog pg_db_role_setting where they are now stored, and better
encapsulate the code that deals with settings into its realm.  The old
datconfig and rolconfig columns are removed.

psql has gained a \drds command to display the settings.

Backwards compatibility warning: while the backwards-compatible system views
still have the config columns, they no longer completely represent the
configuration for a user or database.

Catalog version bumped.

32 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/alter_role.sgml
src/backend/catalog/Makefile
src/backend/catalog/catalog.c
src/backend/catalog/pg_db_role_setting.c [new file with mode: 0644]
src/backend/catalog/pg_shdepend.c
src/backend/catalog/system_views.sql
src/backend/commands/dbcommands.c
src/backend/commands/user.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/utils/init/miscinit.c
src/backend/utils/init/postinit.c
src/bin/pg_dump/dumputils.c
src/bin/pg_dump/dumputils.h
src/bin/pg_dump/pg_dumpall.c
src/bin/psql/command.c
src/bin/psql/describe.c
src/bin/psql/describe.h
src/include/catalog/catversion.h
src/include/catalog/dependency.h
src/include/catalog/indexing.h
src/include/catalog/pg_attribute.h
src/include/catalog/pg_authid.h
src/include/catalog/pg_database.h
src/include/catalog/pg_db_role_setting.h [new file with mode: 0644]
src/include/catalog/toasting.h
src/include/nodes/parsenodes.h
src/include/utils/guc.h
src/test/regress/expected/rules.out
src/test/regress/expected/sanity_check.out

index 15dab71cc0d2ecec70a7160946816d8d92527494..487dd7e1690ee0202eb53864e6ad60183a494a0e 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
       query rewrite rules
      
 
+     
+      pg_db_role_setting
+      per-role and per-database settings
+     
+
      
       pg_shdepend
       dependencies on shared objects
       
      
 
-     
-      datconfig
-      text[]
-      
-      Session defaults for run-time configuration variables
-     
-
      
       datacl
       aclitem[]
 
  
 
+  <structname>pg_db_role_setting</structname>
+
+  
+   pg_db_role_setting
+  
+
+  
+   The catalog pg_db_role_setting records the default
+   values that have been set for run-time configuration variables,
+   for each role and database combination.
+  
+
+  
+   Unlike most system catalogs, pg_db_role_setting
+   is shared across all databases of a cluster: there is only one
+   copy of pg_db_role_setting per cluster, not
+   one per database.
+  
+
+  
+   <structname>pg_db_role_setting</> Columns
+
+   
+    
+     
+      Name
+      Type
+      References
+      Description
+     
+    
+
+    
+     
+      setdatabase
+      oid
+      pg_database.oid
+      The OID of the database the setting is applicable to, or zero if not database-specific
+     
+
+     
+      setrole
+      oid
+      pg_authid.oid
+      The OID of the role the setting is applicable to, or zero if not role-specific
+     
+
+     
+      setconfig
+      text[]
+      
+      Defaults for run-time configuration variables
+     
+    
+   
+  
+
 
  
   <structname>pg_shdepend</structname>
        NULL if no expiration
      
 
-     
-      rolconfig
-      text[]
-      
-      Session defaults for run-time configuration variables
-     
-
      
       oid
       oid
index 9be5812463d0a232be26e18e83b926e403792ec7..2d09de10c4c1c5af7f31bb68fc07e740ee37a3ce 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -37,10 +37,10 @@ ALTER ROLE name [ [ WITH ] 
 
 ALTER ROLE name RENAME TO new_name
 
-ALTER ROLE name SET configuration_parameter { TO | = } { value | DEFAULT }
-ALTER ROLE name SET configuration_parameter FROM CURRENT
-ALTER ROLE name RESET configuration_parameter
-ALTER ROLE name RESET ALL
+ALTER ROLE name [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT }
+ALTER ROLE name [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT
+ALTER ROLE name [ IN DATABASE database_name ] RESET configuration_parameter
+ALTER ROLE name [ IN DATABASE database_name ] RESET ALL
 
  
 
@@ -80,14 +80,16 @@ ALTER ROLE name RESET ALL
   
 
    
-   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 IN DATABASE 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
    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 
-   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
    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 name RESET ALL
       
      
 
+     
+       database_name
+       
+         
+           The name of the database the configuration variable should be set in.
+         
+       
+     
+
      
       configuration_parameter
       value
@@ -159,6 +170,8 @@ ALTER ROLE name RESET ALL
         RESET ALL to clear all role-specific settings.
         SET FROM CURRENT saves the session's current value of
         the parameter as the role-specific value.
+        If used in conjunction with IN DATABASE, the configuration
+        parameter is set or removed for the given role and database only.
        
 
        
@@ -207,8 +220,8 @@ ALTER ROLE name RESET ALL
    It is also possible to tie a
    session default to a specific database rather than to a role; see
    .
-   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.
   
  
 
@@ -261,6 +274,15 @@ ALTER ROLE miriam CREATEROLE CREATEDB;
 
 
 ALTER ROLE worker_bee SET maintenance_work_mem = 100000;
+
+  
+
+  
+    Give a role a non-default, database-specific setting of the 
+   parameter:
+
+
+ALTER ROLE fred IN DATABASE devel SET client_min_messages = DEBUG;
 
   
  
index 53784e9c54b07dfdd22a8b9435e13c74997b7682..ec548990b1003b850eb5883d2d87e4c25bf65fb1 100644 (file)
@@ -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 \
index 42371d513735af739ecc0bc2645d3ad559f79696..82d02f9609a09eecbe047b2e41181e0ec01a5eed 100644 (file)
@@ -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 (file)
index 0000000..7487011
--- /dev/null
@@ -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);
+}
index 869ec1fdd57952d8ed106f18c23d28e46774f69e..be70143ea27e4ba554c9ffd13043b8d7912bc70a 100644 (file)
@@ -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);
    }
index 73e391c896878fa71b3f08567a6df492ae49ce06..c2fbfcdf0a3ab48a8aacec6019d530f20f436645 100644 (file)
@@ -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;
index 2e6edc4832e2fbbc6ba2eed8d756623ea5769ffd..7df44c9ec41b77bf85b9dd65bb471d5d2026ad4b 100644 (file)
@@ -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);
 }
 
 
index c157ead4726e7eaf34e6a53d8b8ec70e7a4302d2..ef546cf3602b9572e8091c2f804efc724847b7fc 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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,
index 7c3cb049b0934753489ed48cd8a2524f503bbcbe..9319aa84c5edb1d9d525989b48246d105032d8c2 100644 (file)
@@ -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;
index bf978f871de494a4a43fbb496a9f39720edf9a7b..6a61112b99c366d960470dde1e310e4025eb129d 100644 (file)
@@ -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;
index af2f080b6341938684e2e6897691617e149d4143..ed265f516b293deda53d3a5ed3cc3c1179baa0a0 100644 (file)
@@ -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    OptRoleList
-%type  OptRoleElem
+%type    OptRoleList AlterOptRoleList
+%type  CreateOptRoleElem AlterOptRoleElem
 
 %type         opt_type
 %type         foreign_server_version opt_foreign_server_version
 %type         auth_ident
+%type         opt_in_database
 
 %type         OptSchemaName
 %type    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;
                }
index 85f1507ba366a507d50ca37d7f4cee1290ab6830..f7a27b9e43018f480b06fcfac480ec423d61ab77 100644 (file)
@@ -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);
 }
 
index 5321afc1b8d4da0bd50f0c18384132aa3e0bcb92..b6c93c7f8ebbd8cf8c2fbae7f447c1ca3dc2812d 100644 (file)
@@ -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
index a9a27625707928e276249ef8cbf3e5dff6342a7a..f8aa9e64b9107e58e8cf0cf778d958b57446d381 100644 (file)
@@ -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
 }
index a5bfe1bcfda30d8a620ce988567094f70d260c0b..0b73701eb8a76541ec4d040ec01ec9caa07a7536 100644 (file)
@@ -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,
index f0a4d67d2afc9b457598bf3033755b0767943ffb..5567b07cafc27736fad8a573527d35c488d6fc50 100644 (file)
@@ -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));
 
    /*
index d94d8b80c526c833c5ac3de797acf0613abffb73..cea3942f013be4637cc5d8c946da4e15f6829233 100644 (file)
@@ -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;
index 1644623812c991982d160dbf187e44880ae61156..0c49d812eea095b78eef0ef1fc32e9680e53b592 100644 (file)
@@ -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()
index 169ceb3739ad2ec68f484dc1da87ec908c4dd69c..aaef69d703d81609abed4a41bb5999af822322f8 100644 (file)
@@ -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);
 
index 1d3bfb0726cc989ebf006994cbd1051cccab6c56..20eac6aa1c752eba7c992193381aebe83291cec3 100644 (file)
@@ -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
index 954d3808a855aff69408ab23305161cd3c182264..5134479c3d03988dadbc7235f23eda0048988cf2 100644 (file)
@@ -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);
index 0272334f2e52da8c9992dda4a61bb07befa83ef8..4f9f9e9c2acfe36941f8d32cbf223c99f5156d32 100644 (file)
@@ -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
 
index 1315e4241aca0fc2c8e5b6e220577cb056bc4064..f5a737f9f0080b9c5a9b7f2e6daf2e12c23a75e7 100644 (file)
@@ -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
index 660c3c7c1473d8130872570524a00eba6a7a4cdf..a8fdcf748a55e9c230608136aa8ccf054b7383bc 100644 (file)
@@ -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
 
index 730c23c8635925f755df2e1f67e8ab5f9b7f41d5..e041fe1154bc83645832adf6494b82dbf965d28a 100644 (file)
@@ -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 (file)
index 0000000..7c8e822
--- /dev/null
@@ -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 */
index 5f4a4a79e2966a4b11b5c116b428888b5fb28ca5..fb83aa75df58b0f9870fdb313b7d2b77ebe36bec 100644 (file)
@@ -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 */
index b182dcfd53f3b183de11c90df6f49ed8703d4dde..5f0d763b688738278051bc76cee542b37658e966 100644 (file)
@@ -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;
 
index ef93d0f27cd1128fc62c0683555abf93aae852b4..5c59b02e4f4b99356184e004dbc05e2f32e9e5b7 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 2000-2009, PostgreSQL Global Development Group
  * Written by Peter Eisentraut .
  *
- * $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 */
index 9244376a3b98f2f0b1b813c9e9ac9d9ef445efce..9561a2355940d9a39d0b06b3078fd6e7ff12b512 100644 (file)
@@ -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;
index 1994edc905e32e356965c78edd0ff0593844d4de..fe0d93670f8f7df5a133abf766770dffacae3826 100644 (file)
@@ -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