-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.208 2009/10/05 19:24:32 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.209 2009/10/07 22:14:14 alvherre Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
<entry>query rewrite rules</entry>
</row>
+ <row>
+ <entry><link linkend="catalog-pg-db-role-setting"><structname>pg_db_role_setting</structname></link></entry>
+ <entry>per-role and per-database settings</entry>
+ </row>
+
<row>
<entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry>
<entry>dependencies on shared objects</entry>
</entry>
</row>
- <row>
- <entry><structfield>datconfig</structfield></entry>
- <entry><type>text[]</type></entry>
- <entry></entry>
- <entry>Session defaults for run-time configuration variables</entry>
- </row>
-
<row>
<entry><structfield>datacl</structfield></entry>
<entry><type>aclitem[]</type></entry>
</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>
NULL if no expiration</entry>
</row>
- <row>
- <entry><structfield>rolconfig</structfield></entry>
- <entry><type>text[]</type></entry>
- <entry></entry>
- <entry>Session defaults for run-time configuration variables</entry>
- </row>
-
<row>
<entry><structfield>oid</structfield></entry>
<entry><type>oid</type></entry>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_role.sgml,v 1.14 2009/09/19 10:23:26 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_role.sgml,v 1.15 2009/10/07 22:14:16 alvherre Exp $
PostgreSQL documentation
-->
ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RESET ALL
+ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL
</synopsis>
</refsynopsisdiv>
</para>
<para>
- The remaining variants change a role's session default for a
- specified configuration variable. Whenever the role subsequently
+ The remaining variants change a role's session default for a configuration variable
+ for all databases or, when the <literal>IN DATABASE</literal> clause is specified,
+ for the named database. Whenever the role subsequently
starts a new session, the specified value becomes the session
default, overriding whatever setting is present in
<filename>postgresql.conf</> or has been received from the postgres
command line. This only happens at login time, so configuration
settings associated with a role to which you've <xref
- linkend="sql-set-role" endterm="sql-set-role-title"> will be ignored.
+ linkend="sql-set-role" endterm="sql-set-role-title"> will be ignored. Settings set to
+ a role directly are overridden by any database specific settings attached to a role.
Superusers can change anyone's session defaults. Roles having
<literal>CREATEROLE</> privilege can change defaults for non-superuser
roles. Certain variables cannot be set this way, or can only be
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><replaceable>database_name</replaceable></term>
+ <listitem>
+ <para>
+ The name of the database the configuration variable should be set in.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><replaceable>configuration_parameter</replaceable></term>
<term><replaceable>value</replaceable></term>
<literal>RESET ALL</literal> to clear all role-specific settings.
<literal>SET FROM CURRENT</> saves the session's current value of
the parameter as the role-specific value.
+ If used in conjunction with <literal>IN DATABASE</literal>, the configuration
+ parameter is set or removed for the given role and database only.
</para>
<para>
It is also possible to tie a
session default to a specific database rather than to a role; see
<xref linkend="sql-alterdatabase" endterm="sql-alterdatabase-title">.
- Role-specific settings override database-specific
- ones if there is a conflict.
+ If there is a conflict, database-role-specific settings override role-specific
+ ones, which in turn override database-specific ones.
</para>
</refsect1>
<programlisting>
ALTER ROLE worker_bee SET maintenance_work_mem = 100000;
+</programlisting>
+ </para>
+
+ <para>
+ Give a role a non-default, database-specific setting of the
+ <xref linkend="guc-client-min-messages"> parameter:
+
+<programlisting>
+ALTER ROLE fred IN DATABASE devel SET client_min_messages = DEBUG;
</programlisting>
</para>
</refsect1>
#
# Makefile for backend/catalog
#
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.72 2009/10/05 19:24:34 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.73 2009/10/07 22:14:16 alvherre Exp $
#
#-------------------------------------------------------------------------
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \
- pg_shdepend.o pg_type.o storage.o toasting.o
+ pg_db_role_setting.o pg_shdepend.o pg_type.o storage.o toasting.o
BKIFILES = postgres.bki postgres.description postgres.shdescription
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
- pg_database.h pg_tablespace.h pg_pltemplate.h \
+ pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
pg_ts_parser.h pg_ts_template.h \
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.83 2009/06/11 14:48:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.84 2009/10/07 22:14:18 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#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"
relationId == PLTemplateRelationId ||
relationId == SharedDescriptionRelationId ||
relationId == SharedDependRelationId ||
- relationId == TableSpaceRelationId)
+ relationId == TableSpaceRelationId ||
+ relationId == DbRoleSettingRelationId)
return true;
/* These are their indexes (see indexing.h) */
if (relationId == AuthIdRolnameIndexId ||
relationId == SharedDependDependerIndexId ||
relationId == SharedDependReferenceIndexId ||
relationId == TablespaceOidIndexId ||
- relationId == TablespaceNameIndexId)
+ relationId == TablespaceNameIndexId ||
+ relationId == DbRoleSettingDatidRolidIndexId)
return true;
/* These are their toast tables and toast indexes (see toasting.h) */
if (relationId == PgAuthidToastTable ||
relationId == PgDatabaseToastTable ||
relationId == PgDatabaseToastIndex ||
relationId == PgShdescriptionToastTable ||
- relationId == PgShdescriptionToastIndex)
+ relationId == PgShdescriptionToastIndex ||
+ relationId == PgDbRoleSettingToastTable ||
+ relationId == PgDbRoleSettingToastIndex)
return true;
return false;
}
--- /dev/null
+/*
+ * pg_db_role_setting.c
+ * Routines to support manipulation of the pg_db_role_setting relation
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_db_role_setting.c,v 1.1 2009/10/07 22:14:18 alvherre Exp $
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "access/htup.h"
+#include "access/skey.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_db_role_setting.h"
+#include "utils/fmgroids.h"
+#include "utils/rel.h"
+#include "utils/tqual.h"
+
+void
+AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
+{
+ char *valuestr;
+ HeapTuple tuple;
+ Relation rel;
+ ScanKeyData scankey[2];
+ SysScanDesc scan;
+
+ valuestr = ExtractSetVariableArgs(setstmt);
+
+ /* Get the old tuple, if any. */
+
+ rel = heap_open(DbRoleSettingRelationId, RowExclusiveLock);
+ ScanKeyInit(&scankey[0],
+ Anum_pg_db_role_setting_setdatabase,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(databaseid));
+ ScanKeyInit(&scankey[1],
+ Anum_pg_db_role_setting_setrole,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(roleid));
+ scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true,
+ SnapshotNow, 2, scankey);
+ tuple = systable_getnext(scan);
+
+ /*
+ * There are three cases:
+ *
+ * - in RESET ALL, simply delete the pg_db_role_setting tuple (if any)
+ *
+ * - in other commands, if there's a tuple in pg_db_role_setting, update it;
+ * if it ends up empty, delete it
+ *
+ * - otherwise, insert a new pg_db_role_setting tuple, but only if the
+ * command is not RESET
+ */
+ if (setstmt->kind == VAR_RESET_ALL)
+ {
+ if (HeapTupleIsValid(tuple))
+ simple_heap_delete(rel, &tuple->t_self);
+ }
+ else if (HeapTupleIsValid(tuple))
+ {
+ Datum repl_val[Natts_pg_db_role_setting];
+ bool repl_null[Natts_pg_db_role_setting];
+ bool repl_repl[Natts_pg_db_role_setting];
+ HeapTuple newtuple;
+ Datum datum;
+ bool isnull;
+ ArrayType *a;
+
+ memset(repl_repl, false, sizeof(repl_repl));
+ repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
+ repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
+
+ /* Extract old value of setconfig */
+ datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
+ RelationGetDescr(rel), &isnull);
+ a = isnull ? NULL : DatumGetArrayTypeP(datum);
+
+ /* Update (valuestr is NULL in RESET cases) */
+ if (valuestr)
+ a = GUCArrayAdd(a, setstmt->name, valuestr);
+ else
+ a = GUCArrayDelete(a, setstmt->name);
+
+ if (a)
+ {
+ repl_val[Anum_pg_db_role_setting_setconfig - 1] =
+ PointerGetDatum(a);
+
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
+ repl_val, repl_null, repl_repl);
+ simple_heap_update(rel, &tuple->t_self, newtuple);
+
+ /* Update indexes */
+ CatalogUpdateIndexes(rel, newtuple);
+ }
+ else
+ simple_heap_delete(rel, &tuple->t_self);
+ }
+ else if (valuestr)
+ {
+ /* non-null valuestr means it's not RESET, so insert a new tuple */
+ HeapTuple newtuple;
+ Datum values[Natts_pg_db_role_setting];
+ bool nulls[Natts_pg_db_role_setting];
+ ArrayType *a;
+
+ memset(nulls, false, sizeof(nulls));
+
+ a = GUCArrayAdd(NULL, setstmt->name, valuestr);
+
+ values[Anum_pg_db_role_setting_setdatabase - 1] =
+ ObjectIdGetDatum(databaseid);
+ values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
+ values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
+ newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
+
+ simple_heap_insert(rel, newtuple);
+
+ /* Update indexes */
+ CatalogUpdateIndexes(rel, newtuple);
+ }
+
+ systable_endscan(scan);
+
+ /* Close pg_db_role_setting, but keep lock till commit */
+ heap_close(rel, NoLock);
+}
+
+/*
+ * Drop some settings from the catalog. These can be for a particular
+ * database, or for a particular role. (It is of course possible to do both
+ * too, but it doesn't make sense for current uses.)
+ */
+void
+DropSetting(Oid databaseid, Oid roleid)
+{
+ Relation relsetting;
+ HeapScanDesc scan;
+ ScanKeyData keys[2];
+ HeapTuple tup;
+ int numkeys = 0;
+
+ relsetting = heap_open(DbRoleSettingRelationId, RowExclusiveLock);
+
+ if (OidIsValid(databaseid))
+ {
+ ScanKeyInit(&keys[numkeys],
+ Anum_pg_db_role_setting_setdatabase,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(databaseid));
+ numkeys++;
+ }
+ if (OidIsValid(roleid))
+ {
+ ScanKeyInit(&keys[numkeys],
+ Anum_pg_db_role_setting_setrole,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(roleid));
+ numkeys++;
+ }
+
+ scan = heap_beginscan(relsetting, SnapshotNow, numkeys, keys);
+ while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+ {
+ simple_heap_delete(relsetting, &tup->t_self);
+ }
+ heap_endscan(scan);
+
+ heap_close(relsetting, RowExclusiveLock);
+}
+
+/*
+ * Scan pg_db_role_setting looking for applicable settings, and load them on
+ * the current process.
+ *
+ * relsetting is pg_db_role_setting, already opened and locked.
+ *
+ * Note: we only consider setting for the exact databaseid/roleid combination.
+ * This probably needs to be called more than once, with InvalidOid passed as
+ * databaseid/roleid.
+ */
+void
+ApplySetting(Oid databaseid, Oid roleid, Relation relsetting, GucSource source)
+{
+ SysScanDesc scan;
+ ScanKeyData keys[2];
+ HeapTuple tup;
+
+ ScanKeyInit(&keys[0],
+ Anum_pg_db_role_setting_setdatabase,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(databaseid));
+ ScanKeyInit(&keys[1],
+ Anum_pg_db_role_setting_setrole,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(roleid));
+
+ scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
+ SnapshotNow, 2, keys);
+ while (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ bool isnull;
+ Datum datum;
+
+ datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
+ RelationGetDescr(relsetting), &isnull);
+ if (!isnull)
+ {
+ ArrayType *a = DatumGetArrayTypeP(datum);
+
+ /*
+ * We process all the options at SUSET level. We assume that the
+ * right to insert an option into pg_db_role_setting was checked
+ * when it was inserted.
+ */
+ ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET);
+ }
+ }
+
+ systable_endscan(scan);
+}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.35 2009/10/05 19:24:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.36 2009/10/07 22:14:18 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_shdepend.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
+#include "commands/dbcommands.h"
#include "commands/conversioncmds.h"
#include "commands/defrem.h"
#include "commands/proclang.h"
static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2,
Oid **diff);
static Oid classIdGetDbId(Oid classId);
-static void shdepLockAndCheckObject(Oid classId, Oid objectId);
static void shdepChangeDep(Relation sdepRel,
Oid classid, Oid objid, int32 objsubid,
Oid refclassid, Oid refobjid,
* weren't looking. If the object has been dropped, this function
* does not return!
*/
-static void
+void
shdepLockAndCheckObject(Oid classId, Oid objectId)
{
/* AccessShareLock should be OK, since we are not modifying the object */
}
#endif
+ case DatabaseRelationId:
+ {
+ /* For lack of a syscache on pg_database, do this: */
+ char *database = get_database_name(objectId);
+
+ if (database == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("database %u was concurrently dropped",
+ objectId)));
+ pfree(database);
+ break;
+ }
+
+
default:
elog(ERROR, "unrecognized shared classId: %u", classId);
}
*
* Copyright (c) 1996-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.60 2009/04/07 00:31:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.61 2009/10/07 22:14:18 alvherre Exp $
*/
CREATE VIEW pg_roles AS
rolconnlimit,
'********'::text as rolpassword,
rolvaliduntil,
- rolconfig,
- oid
- FROM pg_authid;
+ setconfig as rolconfig,
+ pg_authid.oid
+ FROM pg_authid LEFT JOIN pg_db_role_setting s
+ ON (pg_authid.oid = setrole AND setdatabase = 0);
CREATE VIEW pg_shadow AS
SELECT
rolname AS usename,
- oid AS usesysid,
+ pg_authid.oid AS usesysid,
rolcreatedb AS usecreatedb,
rolsuper AS usesuper,
rolcatupdate AS usecatupd,
rolpassword AS passwd,
rolvaliduntil::abstime AS valuntil,
- rolconfig AS useconfig
- FROM pg_authid
+ setconfig AS useconfig
+ FROM pg_authid LEFT JOIN pg_db_role_setting s
+ ON (pg_authid.oid = setrole AND setdatabase = 0)
WHERE rolcanlogin;
REVOKE ALL on pg_shadow FROM public;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.226 2009/09/01 02:54:51 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.227 2009/10/07 22:14:18 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#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"
#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"
new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
/*
- * We deliberately set datconfig and datacl to defaults (NULL), rather
- * than copying them from the template database. Copying datacl would be
- * a bad idea when the owner is not the same as the template's owner. It's
- * more debatable whether datconfig should be copied.
+ * We deliberately set datacl to default (NULL), rather than copying it
+ * from the template database. Copying it would be a bad idea when the
+ * owner is not the same as the template's owner.
*/
- new_record_nulls[Anum_pg_database_datconfig - 1] = true;
new_record_nulls[Anum_pg_database_datacl - 1] = true;
tuple = heap_form_tuple(RelationGetDescr(pg_database_rel),
*/
DeleteSharedComments(db_id, DatabaseRelationId);
+ /*
+ * Remove settings associated with this database
+ */
+ DropSetting(db_id, InvalidOid);
+
/*
* Remove shared dependency references for the database.
*/
void
AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
{
- char *valuestr;
- HeapTuple tuple,
- newtuple;
- Relation rel;
- ScanKeyData scankey;
- SysScanDesc scan;
- Datum repl_val[Natts_pg_database];
- bool repl_null[Natts_pg_database];
- bool repl_repl[Natts_pg_database];
-
- valuestr = ExtractSetVariableArgs(stmt->setstmt);
+ Oid datid = get_database_oid(stmt->dbname);
+ if (!OidIsValid(datid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_DATABASE),
+ errmsg("database \"%s\" does not exist", stmt->dbname)));
+
/*
- * Get the old tuple. We don't need a lock on the database per se,
- * because we're not going to do anything that would mess up incoming
- * connections.
+ * Obtain a lock on the database and make sure it didn't go away in the
+ * meantime.
*/
- rel = heap_open(DatabaseRelationId, RowExclusiveLock);
- ScanKeyInit(&scankey,
- Anum_pg_database_datname,
- BTEqualStrategyNumber, F_NAMEEQ,
- NameGetDatum(stmt->dbname));
- scan = systable_beginscan(rel, DatabaseNameIndexId, true,
- SnapshotNow, 1, &scankey);
- tuple = systable_getnext(scan);
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_DATABASE),
- errmsg("database \"%s\" does not exist", stmt->dbname)));
+ shdepLockAndCheckObject(DatabaseRelationId, datid);
- if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- stmt->dbname);
-
- memset(repl_repl, false, sizeof(repl_repl));
- repl_repl[Anum_pg_database_datconfig - 1] = true;
-
- if (stmt->setstmt->kind == VAR_RESET_ALL)
- {
- /* RESET ALL, so just set datconfig to null */
- repl_null[Anum_pg_database_datconfig - 1] = true;
- repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0;
- }
- else
- {
- Datum datum;
- bool isnull;
- ArrayType *a;
-
- repl_null[Anum_pg_database_datconfig - 1] = false;
-
- /* Extract old value of datconfig */
- datum = heap_getattr(tuple, Anum_pg_database_datconfig,
- RelationGetDescr(rel), &isnull);
- a = isnull ? NULL : DatumGetArrayTypeP(datum);
-
- /* Update (valuestr is NULL in RESET cases) */
- if (valuestr)
- a = GUCArrayAdd(a, stmt->setstmt->name, valuestr);
- else
- a = GUCArrayDelete(a, stmt->setstmt->name);
+ if (!pg_database_ownercheck(datid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ stmt->dbname);
- if (a)
- repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a);
- else
- repl_null[Anum_pg_database_datconfig - 1] = true;
- }
-
- newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
- repl_val, repl_null, repl_repl);
- simple_heap_update(rel, &tuple->t_self, newtuple);
-
- /* Update indexes */
- CatalogUpdateIndexes(rel, newtuple);
-
- systable_endscan(scan);
-
- /* Close pg_database, but keep lock till commit */
- heap_close(rel, NoLock);
+ AlterSetting(datid, InvalidOid, stmt->setstmt);
+
+ UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock);
}
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.188 2009/09/01 02:54:51 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.189 2009/10/07 22:14:19 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/indexing.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
+#include "catalog/pg_database.h"
+#include "catalog/pg_db_role_setting.h"
#include "commands/comment.h"
+#include "commands/dbcommands.h"
#include "commands/user.h"
#include "libpq/md5.h"
#include "miscadmin.h"
#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"
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);
/*
void
AlterRoleSet(AlterRoleSetStmt *stmt)
{
- char *valuestr;
- HeapTuple oldtuple,
- newtuple;
- Relation rel;
- Datum repl_val[Natts_pg_authid];
- bool repl_null[Natts_pg_authid];
- bool repl_repl[Natts_pg_authid];
+ HeapTuple roletuple;
+ Oid databaseid = InvalidOid;
- valuestr = ExtractSetVariableArgs(stmt->setstmt);
+ roletuple = SearchSysCache(AUTHNAME,
+ PointerGetDatum(stmt->role),
+ 0, 0, 0);
- rel = heap_open(AuthIdRelationId, RowExclusiveLock);
- oldtuple = SearchSysCache(AUTHNAME,
- PointerGetDatum(stmt->role),
- 0, 0, 0);
- if (!HeapTupleIsValid(oldtuple))
+ if (!HeapTupleIsValid(roletuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", stmt->role)));
+ /*
+ * Obtain a lock on the role and make sure it didn't go away in the
+ * meantime.
+ */
+ shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple));
+
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own settings
*/
- if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
+ if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
{
if (!superuser())
ereport(ERROR,
else
{
if (!have_createrole_privilege() &&
- HeapTupleGetOid(oldtuple) != GetUserId())
+ HeapTupleGetOid(roletuple) != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied")));
}
- memset(repl_repl, false, sizeof(repl_repl));
- repl_repl[Anum_pg_authid_rolconfig - 1] = true;
-
- if (stmt->setstmt->kind == VAR_RESET_ALL)
+ /* look up and lock the database, if specified */
+ if (stmt->database != NULL)
{
- /* RESET ALL, so just set rolconfig to null */
- repl_null[Anum_pg_authid_rolconfig - 1] = true;
- repl_val[Anum_pg_authid_rolconfig - 1] = (Datum) 0;
- }
- else
- {
- Datum datum;
- bool isnull;
- ArrayType *array;
-
- repl_null[Anum_pg_authid_rolconfig - 1] = false;
-
- /* Extract old value of rolconfig */
- datum = SysCacheGetAttr(AUTHNAME, oldtuple,
- Anum_pg_authid_rolconfig, &isnull);
- array = isnull ? NULL : DatumGetArrayTypeP(datum);
-
- /* Update (valuestr is NULL in RESET cases) */
- if (valuestr)
- array = GUCArrayAdd(array, stmt->setstmt->name, valuestr);
- else
- array = GUCArrayDelete(array, stmt->setstmt->name);
-
- if (array)
- repl_val[Anum_pg_authid_rolconfig - 1] = PointerGetDatum(array);
- else
- repl_null[Anum_pg_authid_rolconfig - 1] = true;
+ databaseid = get_database_oid(stmt->database);
+ if (!OidIsValid(databaseid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("database \"%s\" not found", stmt->database)));
+ shdepLockAndCheckObject(DatabaseRelationId, databaseid);
}
- newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
- repl_val, repl_null, repl_repl);
-
- simple_heap_update(rel, &oldtuple->t_self, newtuple);
- CatalogUpdateIndexes(rel, newtuple);
-
- ReleaseSysCache(oldtuple);
- heap_close(rel, RowExclusiveLock);
+ AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt);
+ ReleaseSysCache(roletuple);
}
*/
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,
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.440 2009/10/06 00:55:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.441 2009/10/07 22:14:20 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
COPY_STRING_FIELD(role);
+ COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
return newnode;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.363 2009/10/06 00:55:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.364 2009/10/07 22:14:20 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
_equalAlterRoleSetStmt(AlterRoleSetStmt *a, AlterRoleSetStmt *b)
{
COMPARE_STRING_FIELD(role);
+ COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
return true;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.680 2009/10/05 19:24:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.681 2009/10/07 22:14:21 alvherre Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
opt_grant_grant_option opt_grant_admin_option
opt_nowait opt_if_exists opt_with_data
-%type <list> OptRoleList
-%type <defelt> OptRoleElem
+%type <list> OptRoleList AlterOptRoleList
+%type <defelt> CreateOptRoleElem AlterOptRoleElem
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
%type <str> auth_ident
+%type <str> opt_in_database
%type <str> OptSchemaName
%type <list> OptSchemaEltList
* is "WITH ADMIN name".
*/
OptRoleList:
- OptRoleList OptRoleElem { $$ = lappend($1, $2); }
+ OptRoleList CreateOptRoleElem { $$ = lappend($1, $2); }
| /* EMPTY */ { $$ = NIL; }
;
-OptRoleElem:
+AlterOptRoleList:
+ AlterOptRoleList AlterOptRoleElem { $$ = lappend($1, $2); }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+AlterOptRoleElem:
PASSWORD Sconst
{
$$ = makeDefElem("password",
{
$$ = makeDefElem("rolemembers", (Node *)$2);
}
- /* The following are not supported by ALTER ROLE/USER/GROUP */
+ ;
+
+CreateOptRoleElem:
+ AlterOptRoleElem { $$ = $1; }
+ /* The following are not supported by ALTER ROLE/USER/GROUP */
| SYSID Iconst
{
$$ = makeDefElem("sysid", (Node *)makeInteger($2));
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with OptRoleList
+ ALTER ROLE RoleId opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
}
;
+opt_in_database:
+ /* EMPTY */ { $$ = NULL; }
+ | IN_P DATABASE database_name { $$ = $3; }
+ ;
+
AlterRoleSetStmt:
- ALTER ROLE RoleId SetResetClause
+ ALTER ROLE RoleId opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->setstmt = $4;
+ n->database = $4;
+ n->setstmt = $5;
$$ = (Node *)n;
}
;
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with OptRoleList
+ ALTER USER RoleId opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
+ n->database = NULL;
n->setstmt = $4;
$$ = (Node *)n;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.177 2009/08/27 16:59:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.178 2009/10/07 22:14:22 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
{
HeapTuple roleTup;
Form_pg_authid rform;
- Datum datum;
- bool isnull;
Oid roleid;
/*
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);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.197 2009/09/01 00:09:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.198 2009/10/07 22:14:23 alvherre Exp $
*
*
*-------------------------------------------------------------------------
#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 InitCommunication(void);
static void ShutdownPostgres(int code, Datum arg);
static bool ThereIsAtLeastOneRole(void);
+static void process_settings(Oid databaseid, Oid roleid);
/*** InitPostgres support ***/
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);
}
/* 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
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
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.49 2009/10/05 19:24:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.50 2009/10/07 22:14:24 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
*
* Scan a wildcard-pattern string and generate appropriate WHERE clauses
* to limit the set of objects returned. The WHERE clauses are appended
- * to the already-partially-constructed query in buf.
+ * to the already-partially-constructed query in buf. Returns whether
+ * any clause was added.
*
* conn: connection query will be sent to (consulted for escaping rules).
* buf: output parameter.
* Formatting note: the text already present in buf should end with a newline.
* The appended text, if any, will end with one too.
*/
-void
+bool
processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
bool have_where, bool force_escape,
const char *schemavar, const char *namevar,
bool inquotes;
const char *cp;
int i;
+ bool added_clause = false;
#define WHEREAND() \
- (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), have_where = true)
+ (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), \
+ have_where = true, added_clause = true)
if (pattern == NULL)
{
WHEREAND();
appendPQExpBuffer(buf, "%s\n", visibilityrule);
}
- return;
+ return added_clause;
}
initPQExpBuffer(&schemabuf);
termPQExpBuffer(&schemabuf);
termPQExpBuffer(&namebuf);
+ return added_clause;
#undef WHEREAND
}
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.26 2009/10/05 19:24:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.27 2009/10/07 22:14:24 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
const char *acls, const char *owner,
int remoteVersion,
PQExpBuffer sql);
-extern void processSQLNamePattern(PGconn *conn, PQExpBuffer buf,
+extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf,
const char *pattern,
bool have_where, bool force_escape,
const char *schemavar, const char *namevar,
* Portions Copyright (c) 1994, Regents of the University of California
*
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.127 2009/10/05 19:24:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.128 2009/10/07 22:14:24 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
static void dumpCreateDB(PGconn *conn);
static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
static void dumpUserConfig(PGconn *conn, const char *username);
+static void dumpDbRoleConfig(PGconn *conn);
static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
- const char *type, const char *name);
+ const char *type, const char *name, const char *type2,
+ const char *name2);
static void dumpDatabases(PGconn *conn);
static void dumpTimestamp(char *msg);
static void doShellQuoting(PQExpBuffer buf, const char *str);
/* Dump CREATE DATABASE commands */
if (!globals_only && !roles_only && !tablespaces_only)
dumpCreateDB(conn);
+
+ /* Dump role/database settings */
+ if (!tablespaces_only && !roles_only)
+ {
+ if (server_version >= 80500)
+ dumpDbRoleConfig(conn);
+ }
}
if (!globals_only && !roles_only && !tablespaces_only)
{
PGresult *res;
- printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
+ if (server_version >= 80500)
+ printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE "
+ "setrole = 0 AND setdatabase = (SELECT oid FROM pg_database WHERE datname = ", count);
+ else
+ printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
appendStringLiteralConn(buf, dbname, conn);
+
+ if (server_version >= 80500)
+ appendPQExpBuffer(buf, ")");
+
appendPQExpBuffer(buf, ";");
res = executeQuery(conn, buf->data);
- if (!PQgetisnull(res, 0, 0))
+ if (PQntuples(res) == 1 &&
+ !PQgetisnull(res, 0, 0))
{
makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
- "DATABASE", dbname);
+ "DATABASE", dbname, NULL, NULL);
PQclear(res);
count++;
}
{
PGresult *res;
- if (server_version >= 80100)
+ if (server_version >= 80500)
+ printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE "
+ "setdatabase = 0 AND setrole = "
+ "(SELECT oid FROM pg_authid WHERE rolname = ", count);
+ else if (server_version >= 80100)
printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM pg_authid WHERE rolname = ", count);
else
printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
appendStringLiteralConn(buf, username, conn);
+ if (server_version >= 80500)
+ appendPQExpBuffer(buf, ")");
res = executeQuery(conn, buf->data);
if (PQntuples(res) == 1 &&
!PQgetisnull(res, 0, 0))
{
makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
- "ROLE", username);
+ "ROLE", username, NULL, NULL);
PQclear(res);
count++;
}
}
+/*
+ * Dump user-and-database-specific configuration
+ */
+static void
+dumpDbRoleConfig(PGconn *conn)
+{
+ PQExpBuffer buf = createPQExpBuffer();
+ PGresult *res;
+ int i;
+
+ printfPQExpBuffer(buf, "SELECT rolname, datname, unnest(setconfig) "
+ "FROM pg_db_role_setting, pg_authid, pg_database "
+ "WHERE setrole = pg_authid.oid AND setdatabase = pg_database.oid");
+ res = executeQuery(conn, buf->data);
+
+ if (PQntuples(res) > 0)
+ {
+ fprintf(OPF, "--\n-- Per-Database Role Settings \n--\n\n");
+
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ makeAlterConfigCommand(conn, PQgetvalue(res, i, 2),
+ "ROLE", PQgetvalue(res, i, 0),
+ "DATABASE", PQgetvalue(res, i, 1));
+ }
+
+ fprintf(OPF, "\n\n");
+ }
+
+ PQclear(res);
+ destroyPQExpBuffer(buf);
+}
+
/*
* Helper function for dumpXXXConfig().
*/
static void
makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
- const char *type, const char *name)
+ const char *type, const char *name,
+ const char *type2, const char *name2)
{
char *pos;
char *mine;
*pos = 0;
appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
+ if (type2 != NULL && name2 != NULL)
+ appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2));
appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
/*
*
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.208 2009/10/05 19:24:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.209 2009/10/07 22:14:24 alvherre Exp $
*/
#include "postgres_fe.h"
#include "command.h"
case 's':
success = listTables(&cmd[1], pattern, show_verbose, show_system);
break;
+ case 'r':
+ if (cmd[2] == 'd' && cmd[3] == 's')
+ {
+ char *pattern2 = NULL;
+
+ if (pattern)
+ pattern2 = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, true);
+ success = listDbRoleSettings(pattern, pattern2);
+ }
+ else
+ success = PSQL_CMD_UNKNOWN;
+ break;
case 'u':
success = describeRoles(pattern, show_verbose);
break;
*
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.227 2009/10/05 19:24:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.228 2009/10/07 22:14:24 alvherre Exp $
*/
#include "postgres_fe.h"
appendPQExpBufferStr(buf, str);
}
+/*
+ * \drds
+ */
+bool
+listDbRoleSettings(const char *pattern, const char *pattern2)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+
+ if (pset.sversion >= 80500)
+ {
+ bool havewhere;
+
+ printfPQExpBuffer(&buf, "SELECT rolname AS role, datname AS database,\n"
+ "pg_catalog.array_to_string(setconfig, E'\\n') AS settings\n"
+ "FROM pg_db_role_setting AS s\n"
+ "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
+ "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n");
+ havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
+ NULL, "pg_roles.rolname", NULL, NULL);
+ processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
+ NULL, "pg_database.datname", NULL, NULL);
+ appendPQExpBufferStr(&buf, "ORDER BY role, database");
+ }
+ else
+ {
+ fprintf(pset.queryFout,
+ _("No per-database role settings support in this server version.\n"));
+ return false;
+ }
+
+ res = PSQLexec(buf.data, false);
+ if (!res)
+ return false;
+
+ if (PQntuples(res) == 0 && !pset.quiet)
+ {
+ if (pattern)
+ fprintf(pset.queryFout, _("No matching settings found.\n"));
+ else
+ fprintf(pset.queryFout, _("No settings found.\n"));
+ }
+ else
+ {
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of settings");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+ }
+
+ PQclear(res);
+ resetPQExpBuffer(&buf);
+ return true;
+}
+
/*
* listTables()
*
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.41 2009/10/05 19:24:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.42 2009/10/07 22:14:24 alvherre Exp $
*/
#ifndef DESCRIBE_H
#define DESCRIBE_H
/* \du, \dg */
extern bool describeRoles(const char *pattern, bool verbose);
+/* \drds */
+extern bool listDbRoleSettings(const char *pattern1, const char *pattern2);
+
/* \z (or \dp) */
extern bool permissionsList(const char *pattern);
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.541 2009/10/05 19:24:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.542 2009/10/07 22:14:24 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200910051
+#define CATALOG_VERSION_NO 200910071
#endif
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.41 2009/10/05 19:24:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.42 2009/10/07 22:14:24 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
extern bool checkSharedDependencies(Oid classId, Oid objectId,
char **detail_msg, char **detail_log_msg);
+extern void shdepLockAndCheckObject(Oid classId, Oid objectId);
+
extern void copyTemplateDependencies(Oid templateDbId, Oid newDbId);
extern void dropDatabaseDependencies(Oid databaseId);
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.109 2009/10/05 19:24:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.110 2009/10/07 22:14:25 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
DECLARE_UNIQUE_INDEX(pg_default_acl_oid_index, 828, on pg_default_acl using btree(oid oid_ops));
#define DefaultAclOidIndexId 828
+DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops));
+#define DbRoleSettingDatidRolidIndexId 2965
+
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.153 2009/09/26 22:42:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.154 2009/10/07 22:14:25 alvherre Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
{ 1262, {"datlastsysoid"}, 26, -1, 0, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
{ 1262, {"datfrozenxid"}, 28, -1, 0, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
{ 1262, {"dattablespace"}, 26, -1, 0, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
-{ 1262, {"datconfig"}, 1009, -1, 0, -1, 12, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
-{ 1262, {"datacl"}, 1034, -1, 0, -1, 13, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
+{ 1262, {"datacl"}, 1034, -1, 0, -1, 12, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
/* ----------------
* pg_index
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_authid.h,v 1.9 2009/01/01 17:23:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_authid.h,v 1.10 2009/10/07 22:14:25 alvherre Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
/* 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
#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
* user choices.
* ----------------
*/
-DATA(insert OID = 10 ( "POSTGRES" t t t t t t -1 _null_ _null_ _null_ ));
+DATA(insert OID = 10 ( "POSTGRES" t t t t t t -1 _null_ _null_ ));
#define BOOTSTRAP_SUPERUSERID 10
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.50 2009/09/26 22:42:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.51 2009/10/07 22:14:25 alvherre Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
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;
* compiler constants for pg_database
* ----------------
*/
-#define Natts_pg_database 13
+#define Natts_pg_database 12
#define Anum_pg_database_datname 1
#define Anum_pg_database_datdba 2
#define Anum_pg_database_encoding 3
#define Anum_pg_database_datlastsysoid 9
#define Anum_pg_database_datfrozenxid 10
#define Anum_pg_database_dattablespace 11
-#define Anum_pg_database_datconfig 12
-#define Anum_pg_database_datacl 13
+#define Anum_pg_database_datacl 12
-DATA(insert OID = 1 ( template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_ _null_));
+DATA(insert OID = 1 ( template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_));
SHDESCR("default template database");
#define TemplateDbOid 1
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_db_role_setting.h
+ * definition of configuration settings
+ *
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/pg_db_role_setting.h,v 1.1 2009/10/07 22:14:25 alvherre Exp $
+ *
+ * NOTES
+ * the genbki.sh script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ * XXX do NOT break up DATA() statements into multiple lines!
+ * the scripts are not as smart as you might think...
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_DB_ROLE_SETTING_H
+#define PG_DB_ROLE_SETTING_H
+
+#include "catalog/genbki.h"
+#include "nodes/parsenodes.h"
+#include "utils/guc.h"
+#include "utils/relcache.h"
+
+/* ----------------
+ * pg_db_role_setting definition. cpp turns this into
+ * typedef struct FormData_pg_db_role_setting
+ * ----------------
+ */
+#define DbRoleSettingRelationId 2964
+
+CATALOG(pg_db_role_setting,2964) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
+{
+ Oid setdatabase; /* database */
+ Oid setrole; /* role */
+ text setconfig[1]; /* GUC settings to apply at login */
+} FormData_pg_db_role_setting;
+
+typedef FormData_pg_db_role_setting *Form_pg_db_role_setting;
+
+/* ----------------
+ * compiler constants for pg_db_role_setting
+ * ----------------
+ */
+#define Natts_pg_db_role_setting 3
+#define Anum_pg_db_role_setting_setdatabase 1
+#define Anum_pg_db_role_setting_setrole 2
+#define Anum_pg_db_role_setting_setconfig 3
+
+/* ----------------
+ * initial contents of pg_db_role_setting are NOTHING
+ * ----------------
+ */
+
+/*
+ * prototypes for functions in pg_db_role_setting.h
+ */
+extern void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt);
+extern void DropSetting(Oid databaseid, Oid roleid);
+extern void ApplySetting(Oid databaseid, Oid roleid, Relation relsetting,
+ GucSource source);
+
+#endif /* PG_DB_ROLE_SETTING_H */
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.8 2009/06/11 20:46:11 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.9 2009/10/07 22:14:25 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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 */
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.404 2009/10/06 00:55:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.405 2009/10/07 22:14:26 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
{
NodeTag type;
char *role; /* role name */
+ char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.106 2009/10/03 18:04:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.107 2009/10/07 22:14:26 alvherre Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
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 */
pg_locks | SELECT l.locktype, l.database, l.relation, l.page, l.tuple, l.virtualxid, l.transactionid, l.classid, l.objid, l.objsubid, l.virtualtransaction, l.pid, l.mode, l.granted FROM pg_lock_status() l(locktype, database, relation, page, tuple, virtualxid, transactionid, classid, objid, objsubid, virtualtransaction, pid, mode, granted);
pg_prepared_statements | SELECT p.name, p.statement, p.prepare_time, p.parameter_types, p.from_sql FROM pg_prepared_statement() p(name, statement, prepare_time, parameter_types, from_sql);
pg_prepared_xacts | SELECT p.transaction, p.gid, p.prepared, u.rolname AS owner, d.datname AS database FROM ((pg_prepared_xact() p(transaction, gid, prepared, ownerid, dbid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
- pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig, pg_authid.oid FROM pg_authid;
+ pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, s.setconfig AS rolconfig, pg_authid.oid FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))));
pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
- pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin;
+ pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin;
pg_stat_activity | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.current_query, s.waiting, s.xact_start, s.query_start, s.backend_start, s.client_addr, s.client_port FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
pg_stat_all_indexes | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
pg_stat_all_tables | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
pg_constraint | t
pg_conversion | t
pg_database | t
+ pg_db_role_setting | t
pg_default_acl | t
pg_depend | t
pg_description | t
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
-(141 rows)
+(142 rows)
--
-- another sanity check: every system catalog that has OIDs should have