Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.207
diff -c -p -r2.207 catalogs.sgml
*** doc/src/sgml/catalogs.sgml	22 Sep 2009 23:43:37 -0000	2.207
--- doc/src/sgml/catalogs.sgml	25 Sep 2009 23:46:31 -0000
***************
*** 199,204 ****
--- 199,209 ----
       </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>
       </row>
***************
*** 2132,2144 ****
       </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>
        <entry></entry>
--- 2137,2142 ----
***************
*** 4014,4019 ****
--- 4012,4076 ----
  
   </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>
***************
*** 6466,6478 ****
       </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>
        <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
--- 6523,6528 ----
Index: src/backend/catalog/Makefile
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.71
diff -c -p -r1.71 Makefile
*** src/backend/catalog/Makefile	26 Aug 2009 22:24:43 -0000	1.71
--- src/backend/catalog/Makefile	25 Sep 2009 19:20:23 -0000
*************** include $(top_builddir)/src/Makefile.glo
*** 13,19 ****
  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
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
--- 13,19 ----
  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_db_role_setting.o pg_shdepend.o pg_type.o storage.o toasting.o
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr
*** 32,38 ****
  	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_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 \
--- 32,38 ----
  	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_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: src/backend/catalog/catalog.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/catalog.c,v
retrieving revision 1.83
diff -c -p -r1.83 catalog.c
*** src/backend/catalog/catalog.c	11 Jun 2009 14:48:54 -0000	1.83
--- src/backend/catalog/catalog.c	25 Sep 2009 19:54:45 -0000
***************
*** 31,36 ****
--- 31,37 ----
  #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"
*************** IsSharedRelation(Oid relationId)
*** 306,312 ****
  		relationId == PLTemplateRelationId ||
  		relationId == SharedDescriptionRelationId ||
  		relationId == SharedDependRelationId ||
! 		relationId == TableSpaceRelationId)
  		return true;
  	/* These are their indexes (see indexing.h) */
  	if (relationId == AuthIdRolnameIndexId ||
--- 307,314 ----
  		relationId == PLTemplateRelationId ||
  		relationId == SharedDescriptionRelationId ||
  		relationId == SharedDependRelationId ||
! 		relationId == TableSpaceRelationId ||
! 		relationId == DbRoleSettingRelationId)
  		return true;
  	/* These are their indexes (see indexing.h) */
  	if (relationId == AuthIdRolnameIndexId ||
*************** IsSharedRelation(Oid relationId)
*** 320,326 ****
  		relationId == SharedDependDependerIndexId ||
  		relationId == SharedDependReferenceIndexId ||
  		relationId == TablespaceOidIndexId ||
! 		relationId == TablespaceNameIndexId)
  		return true;
  	/* These are their toast tables and toast indexes (see toasting.h) */
  	if (relationId == PgAuthidToastTable ||
--- 322,329 ----
  		relationId == SharedDependDependerIndexId ||
  		relationId == SharedDependReferenceIndexId ||
  		relationId == TablespaceOidIndexId ||
! 		relationId == TablespaceNameIndexId ||
! 		relationId == DbRoleSettingDatidRolidIndexId)
  		return true;
  	/* These are their toast tables and toast indexes (see toasting.h) */
  	if (relationId == PgAuthidToastTable ||
*************** IsSharedRelation(Oid relationId)
*** 328,334 ****
  		relationId == PgDatabaseToastTable ||
  		relationId == PgDatabaseToastIndex ||
  		relationId == PgShdescriptionToastTable ||
! 		relationId == PgShdescriptionToastIndex)
  		return true;
  	return false;
  }
--- 331,339 ----
  		relationId == PgDatabaseToastTable ||
  		relationId == PgDatabaseToastIndex ||
  		relationId == PgShdescriptionToastTable ||
! 		relationId == PgShdescriptionToastIndex ||
! 		relationId == PgDbRoleSettingToastTable ||
! 		relationId == PgDbRoleSettingToastIndex)
  		return true;
  	return false;
  }
Index: src/backend/catalog/system_views.sql
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/system_views.sql,v
retrieving revision 1.60
diff -c -p -r1.60 system_views.sql
*** src/backend/catalog/system_views.sql	7 Apr 2009 00:31:26 -0000	1.60
--- src/backend/catalog/system_views.sql	25 Sep 2009 23:13:18 -0000
*************** CREATE VIEW pg_roles AS 
*** 18,38 ****
          rolconnlimit,
          '********'::text as rolpassword,
          rolvaliduntil,
!         rolconfig,
!         oid
!     FROM pg_authid;
  
  CREATE VIEW pg_shadow AS
      SELECT
          rolname AS usename,
!         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
      WHERE rolcanlogin;
  
  REVOKE ALL on pg_shadow FROM public;
--- 18,40 ----
          rolconnlimit,
          '********'::text as rolpassword,
          rolvaliduntil,
!         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,
!         pg_authid.oid AS usesysid,
          rolcreatedb AS usecreatedb,
          rolsuper AS usesuper,
          rolcatupdate AS usecatupd,
          rolpassword AS passwd,
          rolvaliduntil::abstime AS valuntil,
!         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;
*************** CREATE RULE pg_settings_n AS 
*** 171,176 ****
--- 173,187 ----
  
  GRANT SELECT, UPDATE ON pg_settings TO PUBLIC;
  
+ CREATE VIEW pg_db_role_settings AS
+     SELECT
+             datname AS database,
+             rolname AS role,
+             setconfig AS settings
+     FROM pg_db_role_setting AS s
+     LEFT JOIN pg_database ON pg_database.oid = setdatabase
+     LEFT JOIN pg_roles ON pg_roles.oid = setrole;
+ 
  CREATE VIEW pg_timezone_abbrevs AS
      SELECT * FROM pg_timezone_abbrevs();
  
Index: src/backend/commands/dbcommands.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.226
diff -c -p -r1.226 dbcommands.c
*** src/backend/commands/dbcommands.c	1 Sep 2009 02:54:51 -0000	1.226
--- src/backend/commands/dbcommands.c	25 Sep 2009 19:21:19 -0000
***************
*** 33,38 ****
--- 33,39 ----
  #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,56 ****
  #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"
--- 51,56 ----
*************** createdb(const CreatedbStmt *stmt)
*** 544,555 ****
  	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.
  	 */
- 	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),
--- 544,553 ----
  	new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
  
  	/*
! 	 * 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_datacl - 1] = true;
  
  	tuple = heap_form_tuple(RelationGetDescr(pg_database_rel),
*************** dropdb(const char *dbname, bool missing_
*** 821,826 ****
--- 819,829 ----
  	DeleteSharedComments(db_id, DatabaseRelationId);
  
  	/*
+ 	 * Remove settings associated with this database
+ 	 */
+ 	DropSetting(db_id, InvalidOid);
+ 
+ 	/*
  	 * Remove shared dependency references for the database.
  	 */
  	dropDatabaseDependencies(db_id);
*************** AlterDatabase(AlterDatabaseStmt *stmt, b
*** 1397,1481 ****
  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);
! 
! 	/*
! 	 * 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.
! 	 */
! 	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)));
! 
! 	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 (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);
  }
  
  
--- 1400,1421 ----
  void
  AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
  {
! 	Oid		datid = get_database_oid(stmt->dbname);
  
! 	if (!OidIsValid(datid))
!   		ereport(ERROR,
!   				(errcode(ERRCODE_UNDEFINED_DATABASE),
!   				 errmsg("database \"%s\" does not exist", stmt->dbname)));
!   
! 	LockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock);
! 
! 	if (!pg_database_ownercheck(datid, GetUserId()))
!   		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
!   					   stmt->dbname);
! 
! 	AlterSetting(datid, InvalidOid, stmt->setstmt);
!   
! 	UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock);
  }
  
  
Index: src/backend/commands/user.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/user.c,v
retrieving revision 1.188
diff -c -p -r1.188 user.c
*** src/backend/commands/user.c	1 Sep 2009 02:54:51 -0000	1.188
--- src/backend/commands/user.c	25 Sep 2009 19:22:11 -0000
***************
*** 19,25 ****
--- 19,27 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_auth_members.h"
  #include "catalog/pg_authid.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,33 ****
  #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"
--- 29,34 ----
*************** CreateRole(CreateRoleStmt *stmt)
*** 341,348 ****
  	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);
  
  	/*
--- 342,347 ----
*************** AlterRole(AlterRoleStmt *stmt)
*** 715,744 ****
  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];
  
! 	valuestr = ExtractSetVariableArgs(stmt->setstmt);
  
! 	rel = heap_open(AuthIdRelationId, RowExclusiveLock);
! 	oldtuple = SearchSysCache(AUTHNAME,
! 							  PointerGetDatum(stmt->role),
! 							  0, 0, 0);
! 	if (!HeapTupleIsValid(oldtuple))
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
  				 errmsg("role \"%s\" does not exist", stmt->role)));
  
  	/*
  	 * 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 (!superuser())
  			ereport(ERROR,
--- 714,738 ----
  void
  AlterRoleSet(AlterRoleSetStmt *stmt)
  {
! 	HeapTuple	roletuple;
! 	Oid			databaseid = InvalidOid;
  
! 	roletuple = SearchSysCache(AUTHNAME,
! 							   PointerGetDatum(stmt->role),
! 							   0, 0, 0);
  
! 	if (!HeapTupleIsValid(roletuple))
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
  				 errmsg("role \"%s\" does not exist", stmt->role)));
  
+ 	/* XXX need some kind of lock here */
+ 
  	/*
  	 * To mess with a superuser you gotta be superuser; else you need
  	 * createrole, or just want to change your own settings
  	 */
! 	if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
  	{
  		if (!superuser())
  			ereport(ERROR,
*************** AlterRoleSet(AlterRoleSetStmt *stmt)
*** 748,801 ****
  	else
  	{
  		if (!have_createrole_privilege() &&
! 			HeapTupleGetOid(oldtuple) != 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)
  	{
! 		/* 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;
  	}
  
! 	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);
  }
  
  
--- 742,765 ----
  	else
  	{
  		if (!have_createrole_privilege() &&
! 			HeapTupleGetOid(roletuple) != GetUserId())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("permission denied")));
  	}
  
! 	/* look up the database, if specified */
! 	if (stmt->database != NULL)
  	{
! 		databaseid = get_database_oid(stmt->database);
! 		if (!OidIsValid(databaseid))
! 			ereport(ERROR,
! 					(errcode(ERRCODE_UNDEFINED_OBJECT),
! 					 errmsg("database \"%s\" not found", stmt->database)));
  	}
  
! 	AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt);
! 	ReleaseSysCache(roletuple);
  }
  
  
*************** DropRole(DropRoleStmt *stmt)
*** 944,949 ****
--- 908,918 ----
  		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,
  		 * we are trying to drop both a role and one of its direct members ---
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.438
diff -c -p -r1.438 copyfuncs.c
*** src/backend/nodes/copyfuncs.c	22 Sep 2009 23:43:37 -0000	1.438
--- src/backend/nodes/copyfuncs.c	25 Sep 2009 04:02:21 -0000
*************** _copyAlterRoleSetStmt(AlterRoleSetStmt *
*** 3163,3168 ****
--- 3163,3169 ----
  	AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
  
  	COPY_STRING_FIELD(role);
+ 	COPY_STRING_FIELD(database);
  	COPY_NODE_FIELD(setstmt);
  
  	return newnode;
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.361
diff -c -p -r1.361 equalfuncs.c
*** src/backend/nodes/equalfuncs.c	22 Sep 2009 23:43:38 -0000	1.361
--- src/backend/nodes/equalfuncs.c	25 Sep 2009 04:02:21 -0000
*************** static bool
*** 1716,1721 ****
--- 1716,1722 ----
  _equalAlterRoleSetStmt(AlterRoleSetStmt *a, AlterRoleSetStmt *b)
  {
  	COMPARE_STRING_FIELD(role);
+ 	COMPARE_STRING_FIELD(database);
  	COMPARE_NODE_FIELD(setstmt);
  
  	return true;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.679
diff -c -p -r2.679 gram.y
*** src/backend/parser/gram.y	22 Sep 2009 23:43:38 -0000	2.679
--- src/backend/parser/gram.y	25 Sep 2009 14:09:49 -0000
*************** static TypeName *TableFuncTypeName(List 
*** 235,242 ****
  				opt_grant_grant_option opt_grant_admin_option
  				opt_nowait opt_if_exists opt_with_data
  
! %type <list>	OptRoleList
! %type <defelt>	OptRoleElem
  
  %type <str>		opt_type
  %type <str>		foreign_server_version opt_foreign_server_version
--- 235,242 ----
  				opt_grant_grant_option opt_grant_admin_option
  				opt_nowait opt_if_exists opt_with_data
  
! %type <list>	OptRoleList AlterOptRoleList
! %type <defelt>	CreateOptRoleElem AlterOptRoleElem
  
  %type <str>		opt_type
  %type <str>		foreign_server_version opt_foreign_server_version
*************** opt_with:	WITH									{}
*** 756,766 ****
   * is "WITH ADMIN name".
   */
  OptRoleList:
! 			OptRoleList OptRoleElem					{ $$ = lappend($1, $2); }
  			| /* EMPTY */							{ $$ = NIL; }
  		;
  
! OptRoleElem:
  			PASSWORD Sconst
  				{
  					$$ = makeDefElem("password",
--- 756,771 ----
   * is "WITH ADMIN name".
   */
  OptRoleList:
! 			OptRoleList CreateOptRoleElem			{ $$ = lappend($1, $2); }
  			| /* EMPTY */							{ $$ = NIL; }
  		;
  
! AlterOptRoleList:
! 			AlterOptRoleList AlterOptRoleElem		{ $$ = lappend($1, $2); }
! 			| /* EMPTY */							{ $$ = NIL; }
! 		;
! 
! AlterOptRoleElem:
  			PASSWORD Sconst
  				{
  					$$ = makeDefElem("password",
*************** OptRoleElem:
*** 842,848 ****
  				{
  					$$ = makeDefElem("rolemembers", (Node *)$2);
  				}
! 		/* The following are not supported by ALTER ROLE/USER/GROUP */
  			| SYSID Iconst
  				{
  					$$ = makeDefElem("sysid", (Node *)makeInteger($2));
--- 847,857 ----
  				{
  					$$ = makeDefElem("rolemembers", (Node *)$2);
  				}
! 		;
! 
! CreateOptRoleElem:
! 			AlterOptRoleElem			{ $$ = $1; }
! 			/* The following are not supported by ALTER ROLE/USER/GROUP */
  			| SYSID Iconst
  				{
  					$$ = makeDefElem("sysid", (Node *)makeInteger($2));
*************** CreateUserStmt:
*** 891,897 ****
   *****************************************************************************/
  
  AlterRoleStmt:
! 			ALTER ROLE RoleId opt_with OptRoleList
  				 {
  					AlterRoleStmt *n = makeNode(AlterRoleStmt);
  					n->role = $3;
--- 900,906 ----
   *****************************************************************************/
  
  AlterRoleStmt:
! 			ALTER ROLE RoleId opt_with AlterOptRoleList
  				 {
  					AlterRoleStmt *n = makeNode(AlterRoleStmt);
  					n->role = $3;
*************** AlterRoleStmt:
*** 902,911 ****
  		;
  
  AlterRoleSetStmt:
! 			ALTER ROLE RoleId SetResetClause
  				{
  					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
  					n->role = $3;
  					n->setstmt = $4;
  					$$ = (Node *)n;
  				}
--- 911,929 ----
  		;
  
  AlterRoleSetStmt:
! 			ALTER ROLE RoleId IN_P DATABASE database_name SetResetClause
! 				{
! 					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
! 					n->role = $3;
! 					n->database = $6;
! 					n->setstmt = $7;
! 					$$ = (Node *)n;
! 				}
! 			| ALTER ROLE RoleId SetResetClause
  				{
  					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
  					n->role = $3;
+ 					n->database = NULL;
  					n->setstmt = $4;
  					$$ = (Node *)n;
  				}
*************** AlterRoleSetStmt:
*** 919,925 ****
   *****************************************************************************/
  
  AlterUserStmt:
! 			ALTER USER RoleId opt_with OptRoleList
  				 {
  					AlterRoleStmt *n = makeNode(AlterRoleStmt);
  					n->role = $3;
--- 937,943 ----
   *****************************************************************************/
  
  AlterUserStmt:
! 			ALTER USER RoleId opt_with AlterOptRoleList
  				 {
  					AlterRoleStmt *n = makeNode(AlterRoleStmt);
  					n->role = $3;
*************** AlterUserSetStmt:
*** 935,940 ****
--- 953,959 ----
  				{
  					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
  					n->role = $3;
+ 					n->database = NULL;
  					n->setstmt = $4;
  					$$ = (Node *)n;
  				}
Index: src/backend/utils/init/miscinit.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/init/miscinit.c,v
retrieving revision 1.177
diff -c -p -r1.177 miscinit.c
*** src/backend/utils/init/miscinit.c	27 Aug 2009 16:59:38 -0000	1.177
--- src/backend/utils/init/miscinit.c	25 Sep 2009 04:02:21 -0000
*************** InitializeSessionUserId(const char *role
*** 392,399 ****
  {
  	HeapTuple	roleTup;
  	Form_pg_authid rform;
- 	Datum		datum;
- 	bool		isnull;
  	Oid			roleid;
  
  	/*
--- 392,397 ----
*************** InitializeSessionUserId(const char *role
*** 470,493 ****
  					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);
  }
  
--- 468,473 ----
Index: src/backend/utils/init/postinit.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.197
diff -c -p -r1.197 postinit.c
*** src/backend/utils/init/postinit.c	1 Sep 2009 00:09:42 -0000	1.197
--- src/backend/utils/init/postinit.c	25 Sep 2009 23:49:11 -0000
***************
*** 27,32 ****
--- 27,33 ----
  #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"
*************** static void CheckMyDatabase(const char *
*** 63,68 ****
--- 64,70 ----
  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 ***/
*************** CheckMyDatabase(const char *name, bool a
*** 344,372 ****
  	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);
  }
  
--- 346,351 ----
*************** InitPostgres(const char *in_dbname, Oid 
*** 739,744 ****
--- 718,726 ----
  	/* 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
*************** InitPostgres(const char *in_dbname, Oid 
*** 851,856 ****
--- 833,860 ----
  		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: src/include/catalog/indexing.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/indexing.h,v
retrieving revision 1.108
diff -c -p -r1.108 indexing.h
*** src/include/catalog/indexing.h	11 Jun 2009 14:49:09 -0000	1.108
--- src/include/catalog/indexing.h	25 Sep 2009 19:54:01 -0000
*************** DECLARE_UNIQUE_INDEX(pg_user_mapping_oid
*** 267,272 ****
--- 267,275 ----
  DECLARE_UNIQUE_INDEX(pg_user_mapping_user_server_index, 175, on pg_user_mapping using btree(umuser oid_ops, umserver oid_ops));
  #define UserMappingUserServerIndexId	175
  
+ 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: src/include/catalog/pg_attribute.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/pg_attribute.h,v
retrieving revision 1.152
diff -c -p -r1.152 pg_attribute.h
*** src/include/catalog/pg_attribute.h	12 Aug 2009 20:53:30 -0000	1.152
--- src/include/catalog/pg_attribute.h	25 Sep 2009 04:02:21 -0000
*************** DATA(insert ( 1259 tableoid			26 0 0  4 
*** 485,492 ****
  { 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 } }
  
  /* ----------------
   *		pg_index
--- 485,491 ----
  { 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, {"datacl"},			1034, -1, 0,   -1, 12, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
  
  /* ----------------
   *		pg_index
Index: src/include/catalog/pg_authid.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/pg_authid.h,v
retrieving revision 1.9
diff -c -p -r1.9 pg_authid.h
*** src/include/catalog/pg_authid.h	1 Jan 2009 17:23:56 -0000	1.9
--- src/include/catalog/pg_authid.h	25 Sep 2009 23:54:26 -0000
*************** CATALOG(pg_authid,1260) BKI_SHARED_RELAT
*** 55,61 ****
  	/* 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
--- 55,60 ----
*************** typedef FormData_pg_authid *Form_pg_auth
*** 83,89 ****
  #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
--- 82,87 ----
*************** typedef FormData_pg_authid *Form_pg_auth
*** 92,98 ****
   * user choices.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t -1 _null_ _null_ _null_ ));
  
  #define BOOTSTRAP_SUPERUSERID 10
  
--- 90,96 ----
   * user choices.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t -1 _null_ _null_ ));
  
  #define BOOTSTRAP_SUPERUSERID 10
  
Index: src/include/catalog/pg_database.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/pg_database.h,v
retrieving revision 1.49
diff -c -p -r1.49 pg_database.h
*** src/include/catalog/pg_database.h	1 Jan 2009 17:23:57 -0000	1.49
--- src/include/catalog/pg_database.h	25 Sep 2009 23:54:32 -0000
*************** CATALOG(pg_database,1262) BKI_SHARED_REL
*** 41,47 ****
  	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;
  
--- 41,46 ----
*************** typedef FormData_pg_database *Form_pg_da
*** 56,62 ****
   *		compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database				13
  #define Anum_pg_database_datname		1
  #define Anum_pg_database_datdba			2
  #define Anum_pg_database_encoding		3
--- 55,61 ----
   *		compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database				12
  #define Anum_pg_database_datname		1
  #define Anum_pg_database_datdba			2
  #define Anum_pg_database_encoding		3
*************** typedef FormData_pg_database *Form_pg_da
*** 68,77 ****
  #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
  
! DATA(insert OID = 1 (  template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_ _null_));
  SHDESCR("default template database");
  #define TemplateDbOid			1
  
--- 67,75 ----
  #define Anum_pg_database_datlastsysoid	9
  #define Anum_pg_database_datfrozenxid	10
  #define Anum_pg_database_dattablespace	11
! #define Anum_pg_database_datacl			12
  
! 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
  
Index: src/include/catalog/toasting.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/toasting.h,v
retrieving revision 1.8
diff -c -p -r1.8 toasting.h
*** src/include/catalog/toasting.h	11 Jun 2009 20:46:11 -0000	1.8
--- src/include/catalog/toasting.h	25 Sep 2009 19:56:03 -0000
*************** DECLARE_TOAST(pg_database, 2844, 2845);
*** 58,62 ****
--- 58,65 ----
  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: src/include/nodes/parsenodes.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.402
diff -c -p -r1.402 parsenodes.h
*** src/include/nodes/parsenodes.h	22 Sep 2009 23:43:41 -0000	1.402
--- src/include/nodes/parsenodes.h	25 Sep 2009 04:02:21 -0000
*************** typedef struct AlterRoleSetStmt
*** 1619,1624 ****
--- 1619,1625 ----
  {
  	NodeTag		type;
  	char	   *role;			/* role name */
+ 	char	   *database;		/* database name, or NULL */
  	VariableSetStmt *setstmt;	/* SET or RESET subcommand */
  } AlterRoleSetStmt;
  
Index: src/include/utils/guc.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/utils/guc.h,v
retrieving revision 1.105
diff -c -p -r1.105 guc.h
*** src/include/utils/guc.h	22 Sep 2009 23:43:41 -0000	1.105
--- src/include/utils/guc.h	25 Sep 2009 04:02:21 -0000
*************** typedef enum
*** 86,91 ****
--- 86,92 ----
  	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: src/test/regress/expected/rules.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/rules.out,v
retrieving revision 1.150
diff -c -p -r1.150 rules.out
*** src/test/regress/expected/rules.out	22 Sep 2009 15:46:34 -0000	1.150
--- src/test/regress/expected/rules.out	25 Sep 2009 23:51:31 -0000
*************** SELECT viewname, definition FROM pg_view
*** 1280,1294 ****
  --------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   iexit                    | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
   pg_cursors               | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
   pg_group                 | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
   pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS tablespace, pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
   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_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_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;
--- 1280,1295 ----
  --------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   iexit                    | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
   pg_cursors               | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
+  pg_db_role_settings      | SELECT pg_database.datname AS database, pg_roles.rolname AS role, s.setconfig AS settings FROM ((pg_db_role_setting s LEFT JOIN pg_database ON ((pg_database.oid = s.setdatabase))) LEFT JOIN pg_roles ON ((pg_roles.oid = s.setrole)));
   pg_group                 | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
   pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS tablespace, pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
   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, 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, 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;
*************** SELECT viewname, definition FROM pg_view
*** 1329,1335 ****
   shoelace_obsolete        | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
   street                   | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
   toyemp                   | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
! (51 rows)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
--- 1330,1336 ----
   shoelace_obsolete        | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
   street                   | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
   toyemp                   | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
! (52 rows)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
Index: src/test/regress/expected/sanity_check.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/sanity_check.out,v
retrieving revision 1.40
diff -c -p -r1.40 sanity_check.out
*** src/test/regress/expected/sanity_check.out	29 Jul 2009 20:56:21 -0000	1.40
--- src/test/regress/expected/sanity_check.out	25 Sep 2009 23:51:26 -0000
*************** SELECT relname, relhasindex
*** 95,100 ****
--- 95,101 ----
   pg_constraint           | t
   pg_conversion           | t
   pg_database             | t
+  pg_db_role_setting      | t
   pg_depend               | t
   pg_description          | t
   pg_enum                 | t
*************** SELECT relname, relhasindex
*** 151,157 ****
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (140 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
--- 152,158 ----
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (141 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
