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