Alvaro Herrera wrote:

> Implementation-side, it requires a new catalog (pg_settings), with the
> following columns:

So, I've come up with the attached patch.  It does not have the new
command yet, so you can do ALTER USER and ALTER DATABASE and it works,
but there's no way to set user-and-database-specific settings, short of
INSERT into the catalog.  Apart from that it works nicely.

I'm just posting in case somebody has thoughts on the UI part of it.

Other things that need fixed:

- need to figure out locking for roles; this stuff must be synchronized
  with role drop
- pg_shadow and pg_roles need a join to obtain settings
- two regression tests need their expected file updated
- catalog version bump

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.206
diff -c -p -r2.206 catalogs.sgml
*** doc/src/sgml/catalogs.sgml	10 Aug 2009 22:13:50 -0000	2.206
--- doc/src/sgml/catalogs.sgml	26 Aug 2009 02:01:11 -0000
***************
*** 199,204 ****
--- 199,209 ----
       </row>
  
       <row>
+       <entry><link linkend="catalog-pg-setting"><structname>pg_setting</structname></link></entry>
+       <entry>per-user 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 ----
***************
*** 3996,4001 ****
--- 3994,4058 ----
  
   </sect1>
  
+  <sect1 id="catalog-pg-setting">
+   <title><structname>pg_setting</structname></title>
+ 
+   <indexterm zone="catalog-pg-setting">
+    <primary>pg_setting</primary>
+   </indexterm>
+ 
+   <para>
+    The catalog <structname>pg_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_setting</structname>
+    is shared across all databases of a cluster: there is only one
+    copy of <structname>pg_setting</structname> per cluster, not
+    one per database.
+   </para>
+ 
+   <table>
+    <title><structname>pg_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>
***************
*** 6448,6460 ****
       </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>
--- 6505,6510 ----
Index: src/backend/catalog/Makefile
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.70
diff -c -p -r1.70 Makefile
*** src/backend/catalog/Makefile	12 May 2009 00:56:05 -0000	1.70
--- src/backend/catalog/Makefile	25 Aug 2009 19:15:03 -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_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_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/Code/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	24 Aug 2009 22:41:36 -0000
***************
*** 31,36 ****
--- 31,37 ----
  #include "catalog/pg_database.h"
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_pltemplate.h"
+ #include "catalog/pg_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 == SettingRelationId)
  		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 == SettingDatidRolidIndexId)
  		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 == PgSettingToastTable ||
! 		relationId == PgSettingToastIndex)
  		return true;
  	return false;
  }
Index: src/backend/catalog/pg_setting.c
===================================================================
RCS file: src/backend/catalog/pg_setting.c
diff -N src/backend/catalog/pg_setting.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/backend/catalog/pg_setting.c	25 Aug 2009 21:15:57 -0000
***************
*** 0 ****
--- 1,231 ----
+ /*
+  * pg_setting.c
+  *		Routines to support manipulation of the pg_setting relation
+  *    
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * IDENTIFICATION
+  *		$PostgreSQL$
+  */
+ #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_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(SettingRelationId, RowExclusiveLock);
+ 	ScanKeyInit(&scankey[0],
+ 				Anum_pg_setting_setdatabase,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(databaseid));
+ 	ScanKeyInit(&scankey[1],
+ 				Anum_pg_setting_setrole,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(roleid));
+ 	scan = systable_beginscan(rel, SettingDatidRolidIndexId, true,
+ 							  SnapshotNow, 2, scankey);
+ 	tuple = systable_getnext(scan);
+ 
+ 	/*
+ 	 * There are three cases:
+ 	 *
+ 	 * - in RESET ALL, simply delete the pg_setting tuple (if any)
+ 	 *
+ 	 * - in other commands, if there's a tuple in pg_setting, update it;
+ 	 *   if it ends up empty, delete it
+ 	 *
+ 	 * - otherwise, insert a new pg_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_setting];
+ 		bool		repl_null[Natts_pg_setting];
+ 		bool		repl_repl[Natts_pg_setting];
+ 		HeapTuple	newtuple;
+ 		Datum		datum;
+ 		bool		isnull;
+ 		ArrayType  *a;
+ 
+ 		memset(repl_repl, false, sizeof(repl_repl));
+ 		repl_repl[Anum_pg_setting_setconfig - 1] = true;
+ 		repl_null[Anum_pg_setting_setconfig - 1] = false;
+ 
+ 		/* Extract old value of setconfig */
+ 		datum = heap_getattr(tuple, Anum_pg_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_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_setting];
+ 		bool		nulls[Natts_pg_setting];
+ 		ArrayType  *a;
+ 
+ 		memset(nulls, false, sizeof(nulls));
+ 		
+ 		a = GUCArrayAdd(NULL, setstmt->name, valuestr);
+ 
+ 		values[Anum_pg_setting_setdatabase - 1] = ObjectIdGetDatum(databaseid);
+ 		values[Anum_pg_setting_setrole - 1] = ObjectIdGetDatum(roleid);
+ 		values[Anum_pg_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_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(SettingRelationId, RowExclusiveLock);
+ 
+ 	if (OidIsValid(databaseid))
+ 	{
+ 		ScanKeyInit(&keys[numkeys],
+ 					Anum_pg_setting_setdatabase,
+ 					BTEqualStrategyNumber,
+ 					F_OIDEQ,
+ 					ObjectIdGetDatum(databaseid));
+ 		numkeys++;
+ 	}
+ 	if (OidIsValid(roleid))
+ 	{
+ 		ScanKeyInit(&keys[numkeys],
+ 					Anum_pg_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_setting looking for applicable settings, and load them on the
+  * current process.
+  *
+  * relsetting is pg_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_setting_setdatabase,
+ 				BTEqualStrategyNumber,
+ 				F_OIDEQ,
+ 				ObjectIdGetDatum(databaseid));
+ 	ScanKeyInit(&keys[1],
+ 				Anum_pg_setting_setrole,
+ 				BTEqualStrategyNumber,
+ 				F_OIDEQ,
+ 				ObjectIdGetDatum(roleid));
+ 
+ 	scan = systable_beginscan(relsetting, SettingDatidRolidIndexId, true,
+ 							  SnapshotNow, 2, keys);
+ 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
+ 	{
+ 		bool	isnull;
+ 		Datum	datum;
+ 
+ 		datum = heap_getattr(tup, Anum_pg_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_settings was checked when it
+ 			 * was inserted.
+ 			 */
+ 			ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET);
+ 		}
+ 	}
+ 
+ 	systable_endscan(scan);
+ }
Index: src/backend/catalog/system_views.sql
===================================================================
RCS file: /home/alvherre/Code/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	24 Aug 2009 22:32:31 -0000
*************** CREATE VIEW pg_roles AS 
*** 18,24 ****
          rolconnlimit,
          '********'::text as rolpassword,
          rolvaliduntil,
!         rolconfig,
          oid
      FROM pg_authid;
  
--- 18,24 ----
          rolconnlimit,
          '********'::text as rolpassword,
          rolvaliduntil,
!         NULL as rolconfig,
          oid
      FROM pg_authid;
  
*************** CREATE VIEW pg_shadow AS
*** 31,37 ****
          rolcatupdate AS usecatupd,
          rolpassword AS passwd,
          rolvaliduntil::abstime AS valuntil,
!         rolconfig AS useconfig
      FROM pg_authid
      WHERE rolcanlogin;
  
--- 31,37 ----
          rolcatupdate AS usecatupd,
          rolpassword AS passwd,
          rolvaliduntil::abstime AS valuntil,
!         NULL AS useconfig
      FROM pg_authid
      WHERE rolcanlogin;
  
Index: src/backend/commands/dbcommands.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.225
diff -c -p -r1.225 dbcommands.c
*** src/backend/commands/dbcommands.c	11 Jun 2009 14:48:55 -0000	1.225
--- src/backend/commands/dbcommands.c	25 Aug 2009 19:43:40 -0000
***************
*** 33,38 ****
--- 33,39 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_authid.h"
  #include "catalog/pg_database.h"
+ #include "catalog/pg_setting.h"
  #include "catalog/pg_tablespace.h"
  #include "commands/comment.h"
  #include "commands/dbcommands.h"
***************
*** 51,57 ****
  #include "utils/builtins.h"
  #include "utils/flatfiles.h"
  #include "utils/fmgroids.h"
- #include "utils/guc.h"
  #include "utils/lsyscache.h"
  #include "utils/pg_locale.h"
  #include "utils/snapmgr.h"
--- 52,57 ----
*************** createdb(const CreatedbStmt *stmt)
*** 545,556 ****
  	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),
--- 545,554 ----
  	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_
*** 824,829 ****
--- 822,832 ----
  	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
*** 1415,1499 ****
  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);
  
  	/*
  	 * We don't bother updating the flat file since ALTER DATABASE SET doesn't
--- 1418,1439 ----
  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);
  
  	/*
  	 * We don't bother updating the flat file since ALTER DATABASE SET doesn't
Index: src/backend/commands/user.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/user.c,v
retrieving revision 1.187
diff -c -p -r1.187 user.c
*** src/backend/commands/user.c	11 Jun 2009 14:48:56 -0000	1.187
--- src/backend/commands/user.c	25 Aug 2009 21:16:09 -0000
***************
*** 19,24 ****
--- 19,25 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_auth_members.h"
  #include "catalog/pg_authid.h"
+ #include "catalog/pg_setting.h"
  #include "commands/comment.h"
  #include "commands/user.h"
  #include "libpq/md5.h"
***************
*** 28,34 ****
  #include "utils/builtins.h"
  #include "utils/flatfiles.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)
*** 342,349 ****
  	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)
*** 728,757 ****
  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,
--- 726,749 ----
  void
  AlterRoleSet(AlterRoleSetStmt *stmt)
  {
! 	HeapTuple	roletuple;
  
! 	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)
*** 761,815 ****
  	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);
! 	/* needn't keep lock since we won't be updating the flat file */
! 	heap_close(rel, RowExclusiveLock);
  }
  
  
--- 753,767 ----
  	else
  	{
  		if (!have_createrole_privilege() &&
! 			HeapTupleGetOid(roletuple) != GetUserId())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("permission denied")));
  	}
  
! 	AlterSetting(InvalidOid, HeapTupleGetOid(roletuple), stmt->setstmt);
  
! 	ReleaseSysCache(roletuple);
  }
  
  
*************** DropRole(DropRoleStmt *stmt)
*** 958,963 ****
--- 910,920 ----
  		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/utils/init/miscinit.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/utils/init/miscinit.c,v
retrieving revision 1.176
diff -c -p -r1.176 miscinit.c
*** src/backend/utils/init/miscinit.c	12 Aug 2009 20:53:30 -0000	1.176
--- src/backend/utils/init/miscinit.c	26 Aug 2009 02:15:51 -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/Code/cvs/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.194
diff -c -p -r1.194 postinit.c
*** src/backend/utils/init/postinit.c	12 Aug 2009 20:53:30 -0000	1.194
--- src/backend/utils/init/postinit.c	25 Aug 2009 19:58:05 -0000
***************
*** 26,31 ****
--- 26,32 ----
  #include "catalog/namespace.h"
  #include "catalog/pg_authid.h"
  #include "catalog/pg_database.h"
+ #include "catalog/pg_setting.h"
  #include "catalog/pg_tablespace.h"
  #include "libpq/libpq-be.h"
  #include "mb/pg_wchar.h"
*************** static void CheckMyDatabase(const char *
*** 58,64 ****
  static void InitCommunication(void);
  static void ShutdownPostgres(int code, Datum arg);
  static bool ThereIsAtLeastOneRole(void);
! 
  
  /*** InitPostgres support ***/
  
--- 59,65 ----
  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
*** 277,305 ****
  	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);
  }
  
--- 278,283 ----
*************** InitPostgres(const char *in_dbname, Oid 
*** 659,664 ****
--- 637,645 ----
  				(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
  				 errmsg("connection limit exceeded for non-superusers")));
  
+ 	/* Process pg_setting options */
+ 	process_settings(MyDatabaseId, GetSessionUserId());
+ 
  	/*
  	 * Initialize various default states that can't be set up until we've
  	 * selected the active user and gotten the right GUC settings.
*************** InitPostgres(const char *in_dbname, Oid 
*** 681,686 ****
--- 662,689 ----
  	return am_superuser;
  }
  
+ /*
+  * Load GUC settings from pg_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		pg_setting;
+ 
+ 	if (!IsUnderPostmaster)
+ 		return;
+ 
+ 	pg_setting = heap_open(SettingRelationId, AccessShareLock);
+ 
+ 	ApplySetting(databaseid, roleid, pg_setting, PGC_S_DATABASE_USER);
+ 	ApplySetting(InvalidOid, roleid, pg_setting, PGC_S_USER);
+ 	ApplySetting(databaseid, InvalidOid, pg_setting, PGC_S_DATABASE);
+ 
+ 	heap_close(pg_setting, AccessShareLock);
+ }
  
  /*
   * Backend-shutdown callback.  Do cleanup that we want to be sure happens
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /home/alvherre/Code/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	24 Aug 2009 22:40:59 -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_setting_databaseid_rol_index, 2965, on pg_setting using btree(setdatabase oid_ops, setrole oid_ops));
+ #define SettingDatidRolidIndexId	2965
+ 
  /* last step of initialization script: build the indexes declared above */
  BUILD_INDICES
  
Index: src/include/catalog/pg_attribute.h
===================================================================
RCS file: /home/alvherre/Code/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	24 Aug 2009 21:47:31 -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/Code/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	24 Aug 2009 21:39:19 -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/Code/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	24 Aug 2009 22:35:04 -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/pg_setting.h
===================================================================
RCS file: src/include/catalog/pg_setting.h
diff -N src/include/catalog/pg_setting.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/include/catalog/pg_setting.h	25 Aug 2009 19:59:31 -0000
***************
*** 0 ****
--- 1,67 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_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_ts_config.h,v 1.5 2009-01-01 17:23:58 momjian 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_SETTING_H
+ #define PG_SETTING_H
+ 
+ #include "catalog/genbki.h"
+ #include "nodes/parsenodes.h"
+ #include "utils/guc.h"
+ #include "utils/relcache.h"
+ 
+ /* ----------------
+  *		pg_setting definition.  cpp turns this into
+  *		typedef struct FormData_pg_setting
+  * ----------------
+  */
+ #define SettingRelationId	2964
+ 
+ CATALOG(pg_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_setting;
+ 
+ typedef FormData_pg_setting *Form_pg_setting;
+ 
+ /* ----------------
+  *		compiler constants for pg_setting
+  * ----------------
+  */
+ #define Natts_pg_setting				3
+ #define Anum_pg_setting_setdatabase		1
+ #define Anum_pg_setting_setrole			2
+ #define Anum_pg_setting_setconfig		3
+ 
+ /* ----------------
+  *		initial contents of pg_setting are NOTHING
+  * ----------------
+  */
+ 
+ /*
+  * prototypes for functions in pg_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 pg_setting,
+ 			 GucSource source);
+ 
+ #endif   /* PG_SETTING_H */
Index: src/include/catalog/toasting.h
===================================================================
RCS file: /home/alvherre/Code/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	24 Aug 2009 22:40:36 -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_setting, 2966, 2967);
+ #define PgSettingToastTable 2966
+ #define PgSettingToastIndex 2967
  
  #endif   /* TOASTING_H */
Index: src/include/utils/guc.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/utils/guc.h,v
retrieving revision 1.102
diff -c -p -r1.102 guc.h
*** src/include/utils/guc.h	11 Jun 2009 14:49:13 -0000	1.102
--- src/include/utils/guc.h	24 Aug 2009 21:11:00 -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 */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to