summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/Makefile6
-rw-r--r--src/backend/catalog/catalog.c13
-rw-r--r--src/backend/catalog/pg_db_role_setting.c231
-rw-r--r--src/backend/catalog/pg_shdepend.c21
-rw-r--r--src/backend/catalog/system_views.sql16
-rw-r--r--src/backend/commands/dbcommands.c106
-rw-r--r--src/backend/commands/user.c91
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/equalfuncs.c3
-rw-r--r--src/backend/parser/gram.y37
-rw-r--r--src/backend/utils/init/miscinit.c22
-rw-r--r--src/backend/utils/init/postinit.c52
12 files changed, 388 insertions, 213 deletions
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 53784e9c54b..ec548990b10 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -2,7 +2,7 @@
#
# Makefile for backend/catalog
#
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.72 2009/10/05 19:24:34 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.73 2009/10/07 22:14:16 alvherre Exp $
#
#-------------------------------------------------------------------------
@@ -13,7 +13,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \
- pg_shdepend.o pg_type.o storage.o toasting.o
+ pg_db_role_setting.o pg_shdepend.o pg_type.o storage.o toasting.o
BKIFILES = postgres.bki postgres.description postgres.shdescription
@@ -32,7 +32,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
- pg_database.h pg_tablespace.h pg_pltemplate.h \
+ pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
pg_ts_parser.h pg_ts_template.h \
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 42371d51373..82d02f9609a 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.83 2009/06/11 14:48:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.84 2009/10/07 22:14:18 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,6 +31,7 @@
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_pltemplate.h"
+#include "catalog/pg_db_role_setting.h"
#include "catalog/pg_shdepend.h"
#include "catalog/pg_shdescription.h"
#include "catalog/pg_tablespace.h"
@@ -306,7 +307,8 @@ IsSharedRelation(Oid relationId)
relationId == PLTemplateRelationId ||
relationId == SharedDescriptionRelationId ||
relationId == SharedDependRelationId ||
- relationId == TableSpaceRelationId)
+ relationId == TableSpaceRelationId ||
+ relationId == DbRoleSettingRelationId)
return true;
/* These are their indexes (see indexing.h) */
if (relationId == AuthIdRolnameIndexId ||
@@ -320,7 +322,8 @@ IsSharedRelation(Oid relationId)
relationId == SharedDependDependerIndexId ||
relationId == SharedDependReferenceIndexId ||
relationId == TablespaceOidIndexId ||
- relationId == TablespaceNameIndexId)
+ relationId == TablespaceNameIndexId ||
+ relationId == DbRoleSettingDatidRolidIndexId)
return true;
/* These are their toast tables and toast indexes (see toasting.h) */
if (relationId == PgAuthidToastTable ||
@@ -328,7 +331,9 @@ IsSharedRelation(Oid relationId)
relationId == PgDatabaseToastTable ||
relationId == PgDatabaseToastIndex ||
relationId == PgShdescriptionToastTable ||
- relationId == PgShdescriptionToastIndex)
+ relationId == PgShdescriptionToastIndex ||
+ relationId == PgDbRoleSettingToastTable ||
+ relationId == PgDbRoleSettingToastIndex)
return true;
return false;
}
diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c
new file mode 100644
index 00000000000..74870113d05
--- /dev/null
+++ b/src/backend/catalog/pg_db_role_setting.c
@@ -0,0 +1,231 @@
+/*
+ * pg_db_role_setting.c
+ * Routines to support manipulation of the pg_db_role_setting relation
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_db_role_setting.c,v 1.1 2009/10/07 22:14:18 alvherre Exp $
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "access/htup.h"
+#include "access/skey.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_db_role_setting.h"
+#include "utils/fmgroids.h"
+#include "utils/rel.h"
+#include "utils/tqual.h"
+
+void
+AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
+{
+ char *valuestr;
+ HeapTuple tuple;
+ Relation rel;
+ ScanKeyData scankey[2];
+ SysScanDesc scan;
+
+ valuestr = ExtractSetVariableArgs(setstmt);
+
+ /* Get the old tuple, if any. */
+
+ rel = heap_open(DbRoleSettingRelationId, RowExclusiveLock);
+ ScanKeyInit(&scankey[0],
+ Anum_pg_db_role_setting_setdatabase,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(databaseid));
+ ScanKeyInit(&scankey[1],
+ Anum_pg_db_role_setting_setrole,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(roleid));
+ scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true,
+ SnapshotNow, 2, scankey);
+ tuple = systable_getnext(scan);
+
+ /*
+ * There are three cases:
+ *
+ * - in RESET ALL, simply delete the pg_db_role_setting tuple (if any)
+ *
+ * - in other commands, if there's a tuple in pg_db_role_setting, update it;
+ * if it ends up empty, delete it
+ *
+ * - otherwise, insert a new pg_db_role_setting tuple, but only if the
+ * command is not RESET
+ */
+ if (setstmt->kind == VAR_RESET_ALL)
+ {
+ if (HeapTupleIsValid(tuple))
+ simple_heap_delete(rel, &tuple->t_self);
+ }
+ else if (HeapTupleIsValid(tuple))
+ {
+ Datum repl_val[Natts_pg_db_role_setting];
+ bool repl_null[Natts_pg_db_role_setting];
+ bool repl_repl[Natts_pg_db_role_setting];
+ HeapTuple newtuple;
+ Datum datum;
+ bool isnull;
+ ArrayType *a;
+
+ memset(repl_repl, false, sizeof(repl_repl));
+ repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
+ repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
+
+ /* Extract old value of setconfig */
+ datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
+ RelationGetDescr(rel), &isnull);
+ a = isnull ? NULL : DatumGetArrayTypeP(datum);
+
+ /* Update (valuestr is NULL in RESET cases) */
+ if (valuestr)
+ a = GUCArrayAdd(a, setstmt->name, valuestr);
+ else
+ a = GUCArrayDelete(a, setstmt->name);
+
+ if (a)
+ {
+ repl_val[Anum_pg_db_role_setting_setconfig - 1] =
+ PointerGetDatum(a);
+
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
+ repl_val, repl_null, repl_repl);
+ simple_heap_update(rel, &tuple->t_self, newtuple);
+
+ /* Update indexes */
+ CatalogUpdateIndexes(rel, newtuple);
+ }
+ else
+ simple_heap_delete(rel, &tuple->t_self);
+ }
+ else if (valuestr)
+ {
+ /* non-null valuestr means it's not RESET, so insert a new tuple */
+ HeapTuple newtuple;
+ Datum values[Natts_pg_db_role_setting];
+ bool nulls[Natts_pg_db_role_setting];
+ ArrayType *a;
+
+ memset(nulls, false, sizeof(nulls));
+
+ a = GUCArrayAdd(NULL, setstmt->name, valuestr);
+
+ values[Anum_pg_db_role_setting_setdatabase - 1] =
+ ObjectIdGetDatum(databaseid);
+ values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
+ values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
+ newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
+
+ simple_heap_insert(rel, newtuple);
+
+ /* Update indexes */
+ CatalogUpdateIndexes(rel, newtuple);
+ }
+
+ systable_endscan(scan);
+
+ /* Close pg_db_role_setting, but keep lock till commit */
+ heap_close(rel, NoLock);
+}
+
+/*
+ * Drop some settings from the catalog. These can be for a particular
+ * database, or for a particular role. (It is of course possible to do both
+ * too, but it doesn't make sense for current uses.)
+ */
+void
+DropSetting(Oid databaseid, Oid roleid)
+{
+ Relation relsetting;
+ HeapScanDesc scan;
+ ScanKeyData keys[2];
+ HeapTuple tup;
+ int numkeys = 0;
+
+ relsetting = heap_open(DbRoleSettingRelationId, RowExclusiveLock);
+
+ if (OidIsValid(databaseid))
+ {
+ ScanKeyInit(&keys[numkeys],
+ Anum_pg_db_role_setting_setdatabase,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(databaseid));
+ numkeys++;
+ }
+ if (OidIsValid(roleid))
+ {
+ ScanKeyInit(&keys[numkeys],
+ Anum_pg_db_role_setting_setrole,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(roleid));
+ numkeys++;
+ }
+
+ scan = heap_beginscan(relsetting, SnapshotNow, numkeys, keys);
+ while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+ {
+ simple_heap_delete(relsetting, &tup->t_self);
+ }
+ heap_endscan(scan);
+
+ heap_close(relsetting, RowExclusiveLock);
+}
+
+/*
+ * Scan pg_db_role_setting looking for applicable settings, and load them on
+ * the current process.
+ *
+ * relsetting is pg_db_role_setting, already opened and locked.
+ *
+ * Note: we only consider setting for the exact databaseid/roleid combination.
+ * This probably needs to be called more than once, with InvalidOid passed as
+ * databaseid/roleid.
+ */
+void
+ApplySetting(Oid databaseid, Oid roleid, Relation relsetting, GucSource source)
+{
+ SysScanDesc scan;
+ ScanKeyData keys[2];
+ HeapTuple tup;
+
+ ScanKeyInit(&keys[0],
+ Anum_pg_db_role_setting_setdatabase,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(databaseid));
+ ScanKeyInit(&keys[1],
+ Anum_pg_db_role_setting_setrole,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(roleid));
+
+ scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
+ SnapshotNow, 2, keys);
+ while (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ bool isnull;
+ Datum datum;
+
+ datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
+ RelationGetDescr(relsetting), &isnull);
+ if (!isnull)
+ {
+ ArrayType *a = DatumGetArrayTypeP(datum);
+
+ /*
+ * We process all the options at SUSET level. We assume that the
+ * right to insert an option into pg_db_role_setting was checked
+ * when it was inserted.
+ */
+ ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET);
+ }
+ }
+
+ systable_endscan(scan);
+}
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 869ec1fdd57..be70143ea27 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.35 2009/10/05 19:24:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.36 2009/10/07 22:14:18 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,6 +31,7 @@
#include "catalog/pg_shdepend.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
+#include "commands/dbcommands.h"
#include "commands/conversioncmds.h"
#include "commands/defrem.h"
#include "commands/proclang.h"
@@ -55,7 +56,6 @@ typedef enum
static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2,
Oid **diff);
static Oid classIdGetDbId(Oid classId);
-static void shdepLockAndCheckObject(Oid classId, Oid objectId);
static void shdepChangeDep(Relation sdepRel,
Oid classid, Oid objid, int32 objsubid,
Oid refclassid, Oid refobjid,
@@ -963,7 +963,7 @@ classIdGetDbId(Oid classId)
* weren't looking. If the object has been dropped, this function
* does not return!
*/
-static void
+void
shdepLockAndCheckObject(Oid classId, Oid objectId)
{
/* AccessShareLock should be OK, since we are not modifying the object */
@@ -1003,6 +1003,21 @@ shdepLockAndCheckObject(Oid classId, Oid objectId)
}
#endif
+ case DatabaseRelationId:
+ {
+ /* For lack of a syscache on pg_database, do this: */
+ char *database = get_database_name(objectId);
+
+ if (database == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("database %u was concurrently dropped",
+ objectId)));
+ pfree(database);
+ break;
+ }
+
+
default:
elog(ERROR, "unrecognized shared classId: %u", classId);
}
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 73e391c8968..c2fbfcdf0a3 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -3,7 +3,7 @@
*
* Copyright (c) 1996-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.60 2009/04/07 00:31:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.61 2009/10/07 22:14:18 alvherre Exp $
*/
CREATE VIEW pg_roles AS
@@ -18,21 +18,23 @@ CREATE VIEW pg_roles AS
rolconnlimit,
'********'::text as rolpassword,
rolvaliduntil,
- rolconfig,
- oid
- FROM pg_authid;
+ setconfig as rolconfig,
+ pg_authid.oid
+ FROM pg_authid LEFT JOIN pg_db_role_setting s
+ ON (pg_authid.oid = setrole AND setdatabase = 0);
CREATE VIEW pg_shadow AS
SELECT
rolname AS usename,
- oid AS usesysid,
+ pg_authid.oid AS usesysid,
rolcreatedb AS usecreatedb,
rolsuper AS usesuper,
rolcatupdate AS usecatupd,
rolpassword AS passwd,
rolvaliduntil::abstime AS valuntil,
- rolconfig AS useconfig
- FROM pg_authid
+ setconfig AS useconfig
+ FROM pg_authid LEFT JOIN pg_db_role_setting s
+ ON (pg_authid.oid = setrole AND setdatabase = 0)
WHERE rolcanlogin;
REVOKE ALL on pg_shadow FROM public;
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 2e6edc4832e..7df44c9ec41 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.226 2009/09/01 02:54:51 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.227 2009/10/07 22:14:18 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,6 +33,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_db_role_setting.h"
#include "catalog/pg_tablespace.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
@@ -50,7 +51,6 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
-#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/pg_locale.h"
#include "utils/snapmgr.h"
@@ -544,12 +544,10 @@ createdb(const CreatedbStmt *stmt)
new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
/*
- * We deliberately set datconfig and datacl to defaults (NULL), rather
- * than copying them from the template database. Copying datacl would be
- * a bad idea when the owner is not the same as the template's owner. It's
- * more debatable whether datconfig should be copied.
+ * We deliberately set datacl to default (NULL), rather than copying it
+ * from the template database. Copying it would be a bad idea when the
+ * owner is not the same as the template's owner.
*/
- new_record_nulls[Anum_pg_database_datconfig - 1] = true;
new_record_nulls[Anum_pg_database_datacl - 1] = true;
tuple = heap_form_tuple(RelationGetDescr(pg_database_rel),
@@ -821,6 +819,11 @@ dropdb(const char *dbname, bool missing_ok)
DeleteSharedComments(db_id, DatabaseRelationId);
/*
+ * Remove settings associated with this database
+ */
+ DropSetting(db_id, InvalidOid);
+
+ /*
* Remove shared dependency references for the database.
*/
dropDatabaseDependencies(db_id);
@@ -1397,85 +1400,26 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
void
AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
{
- char *valuestr;
- HeapTuple tuple,
- newtuple;
- Relation rel;
- ScanKeyData scankey;
- SysScanDesc scan;
- Datum repl_val[Natts_pg_database];
- bool repl_null[Natts_pg_database];
- bool repl_repl[Natts_pg_database];
-
- valuestr = ExtractSetVariableArgs(stmt->setstmt);
+ Oid datid = get_database_oid(stmt->dbname);
+ if (!OidIsValid(datid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_DATABASE),
+ errmsg("database \"%s\" does not exist", stmt->dbname)));
+
/*
- * Get the old tuple. We don't need a lock on the database per se,
- * because we're not going to do anything that would mess up incoming
- * connections.
+ * Obtain a lock on the database and make sure it didn't go away in the
+ * meantime.
*/
- rel = heap_open(DatabaseRelationId, RowExclusiveLock);
- ScanKeyInit(&scankey,
- Anum_pg_database_datname,
- BTEqualStrategyNumber, F_NAMEEQ,
- NameGetDatum(stmt->dbname));
- scan = systable_beginscan(rel, DatabaseNameIndexId, true,
- SnapshotNow, 1, &scankey);
- tuple = systable_getnext(scan);
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_DATABASE),
- errmsg("database \"%s\" does not exist", stmt->dbname)));
+ shdepLockAndCheckObject(DatabaseRelationId, datid);
- if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- stmt->dbname);
-
- memset(repl_repl, false, sizeof(repl_repl));
- repl_repl[Anum_pg_database_datconfig - 1] = true;
-
- if (stmt->setstmt->kind == VAR_RESET_ALL)
- {
- /* RESET ALL, so just set datconfig to null */
- repl_null[Anum_pg_database_datconfig - 1] = true;
- repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0;
- }
- else
- {
- Datum datum;
- bool isnull;
- ArrayType *a;
-
- repl_null[Anum_pg_database_datconfig - 1] = false;
-
- /* Extract old value of datconfig */
- datum = heap_getattr(tuple, Anum_pg_database_datconfig,
- RelationGetDescr(rel), &isnull);
- a = isnull ? NULL : DatumGetArrayTypeP(datum);
-
- /* Update (valuestr is NULL in RESET cases) */
- if (valuestr)
- a = GUCArrayAdd(a, stmt->setstmt->name, valuestr);
- else
- a = GUCArrayDelete(a, stmt->setstmt->name);
+ if (!pg_database_ownercheck(datid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ stmt->dbname);
- if (a)
- repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a);
- else
- repl_null[Anum_pg_database_datconfig - 1] = true;
- }
-
- newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
- repl_val, repl_null, repl_repl);
- simple_heap_update(rel, &tuple->t_self, newtuple);
-
- /* Update indexes */
- CatalogUpdateIndexes(rel, newtuple);
-
- systable_endscan(scan);
-
- /* Close pg_database, but keep lock till commit */
- heap_close(rel, NoLock);
+ AlterSetting(datid, InvalidOid, stmt->setstmt);
+
+ UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock);
}
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index c157ead4726..ef546cf3602 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.188 2009/09/01 02:54:51 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.189 2009/10/07 22:14:19 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,10 @@
#include "catalog/indexing.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
+#include "catalog/pg_database.h"
+#include "catalog/pg_db_role_setting.h"
#include "commands/comment.h"
+#include "commands/dbcommands.h"
#include "commands/user.h"
#include "libpq/md5.h"
#include "miscadmin.h"
@@ -27,7 +30,6 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
-#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
@@ -341,8 +343,6 @@ CreateRole(CreateRoleStmt *stmt)
else
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = true;
- new_record_nulls[Anum_pg_authid_rolconfig - 1] = true;
-
tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
/*
@@ -715,30 +715,29 @@ AlterRole(AlterRoleStmt *stmt)
void
AlterRoleSet(AlterRoleSetStmt *stmt)
{
- char *valuestr;
- HeapTuple oldtuple,
- newtuple;
- Relation rel;
- Datum repl_val[Natts_pg_authid];
- bool repl_null[Natts_pg_authid];
- bool repl_repl[Natts_pg_authid];
+ HeapTuple roletuple;
+ Oid databaseid = InvalidOid;
- valuestr = ExtractSetVariableArgs(stmt->setstmt);
+ roletuple = SearchSysCache(AUTHNAME,
+ PointerGetDatum(stmt->role),
+ 0, 0, 0);
- rel = heap_open(AuthIdRelationId, RowExclusiveLock);
- oldtuple = SearchSysCache(AUTHNAME,
- PointerGetDatum(stmt->role),
- 0, 0, 0);
- if (!HeapTupleIsValid(oldtuple))
+ if (!HeapTupleIsValid(roletuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", stmt->role)));
/*
+ * Obtain a lock on the role and make sure it didn't go away in the
+ * meantime.
+ */
+ shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple));
+
+ /*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own settings
*/
- if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
+ if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
{
if (!superuser())
ereport(ERROR,
@@ -748,54 +747,25 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
else
{
if (!have_createrole_privilege() &&
- HeapTupleGetOid(oldtuple) != GetUserId())
+ HeapTupleGetOid(roletuple) != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied")));
}
- memset(repl_repl, false, sizeof(repl_repl));
- repl_repl[Anum_pg_authid_rolconfig - 1] = true;
-
- if (stmt->setstmt->kind == VAR_RESET_ALL)
+ /* look up and lock the database, if specified */
+ if (stmt->database != NULL)
{
- /* RESET ALL, so just set rolconfig to null */
- repl_null[Anum_pg_authid_rolconfig - 1] = true;
- repl_val[Anum_pg_authid_rolconfig - 1] = (Datum) 0;
- }
- else
- {
- Datum datum;
- bool isnull;
- ArrayType *array;
-
- repl_null[Anum_pg_authid_rolconfig - 1] = false;
-
- /* Extract old value of rolconfig */
- datum = SysCacheGetAttr(AUTHNAME, oldtuple,
- Anum_pg_authid_rolconfig, &isnull);
- array = isnull ? NULL : DatumGetArrayTypeP(datum);
-
- /* Update (valuestr is NULL in RESET cases) */
- if (valuestr)
- array = GUCArrayAdd(array, stmt->setstmt->name, valuestr);
- else
- array = GUCArrayDelete(array, stmt->setstmt->name);
-
- if (array)
- repl_val[Anum_pg_authid_rolconfig - 1] = PointerGetDatum(array);
- else
- repl_null[Anum_pg_authid_rolconfig - 1] = true;
+ databaseid = get_database_oid(stmt->database);
+ if (!OidIsValid(databaseid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("database \"%s\" not found", stmt->database)));
+ shdepLockAndCheckObject(DatabaseRelationId, databaseid);
}
- newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
- repl_val, repl_null, repl_repl);
-
- simple_heap_update(rel, &oldtuple->t_self, newtuple);
- CatalogUpdateIndexes(rel, newtuple);
-
- ReleaseSysCache(oldtuple);
- heap_close(rel, RowExclusiveLock);
+ AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt);
+ ReleaseSysCache(roletuple);
}
@@ -944,6 +914,11 @@ DropRole(DropRoleStmt *stmt)
DeleteSharedComments(roleid, AuthIdRelationId);
/*
+ * Remove settings for this role.
+ */
+ DropSetting(InvalidOid, roleid);
+
+ /*
* Advance command counter so that later iterations of this loop will
* see the changes already made. This is essential if, for example,
* we are trying to drop both a role and one of its direct members ---
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 7c3cb049b09..9319aa84c5e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.440 2009/10/06 00:55:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.441 2009/10/07 22:14:20 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3174,6 +3174,7 @@ _copyAlterRoleSetStmt(AlterRoleSetStmt *from)
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
COPY_STRING_FIELD(role);
+ COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index bf978f871de..6a61112b99c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.363 2009/10/06 00:55:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.364 2009/10/07 22:14:20 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1725,6 +1725,7 @@ static bool
_equalAlterRoleSetStmt(AlterRoleSetStmt *a, AlterRoleSetStmt *b)
{
COMPARE_STRING_FIELD(role);
+ COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
return true;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index af2f080b634..ed265f516b2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.680 2009/10/05 19:24:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.681 2009/10/07 22:14:21 alvherre Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -237,12 +237,13 @@ static TypeName *TableFuncTypeName(List *columns);
opt_grant_grant_option opt_grant_admin_option
opt_nowait opt_if_exists opt_with_data
-%type <list> OptRoleList
-%type <defelt> OptRoleElem
+%type <list> OptRoleList AlterOptRoleList
+%type <defelt> CreateOptRoleElem AlterOptRoleElem
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
%type <str> auth_ident
+%type <str> opt_in_database
%type <str> OptSchemaName
%type <list> OptSchemaEltList
@@ -762,11 +763,16 @@ opt_with: WITH {}
* is "WITH ADMIN name".
*/
OptRoleList:
- OptRoleList OptRoleElem { $$ = lappend($1, $2); }
+ OptRoleList CreateOptRoleElem { $$ = lappend($1, $2); }
| /* EMPTY */ { $$ = NIL; }
;
-OptRoleElem:
+AlterOptRoleList:
+ AlterOptRoleList AlterOptRoleElem { $$ = lappend($1, $2); }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+AlterOptRoleElem:
PASSWORD Sconst
{
$$ = makeDefElem("password",
@@ -848,7 +854,11 @@ OptRoleElem:
{
$$ = makeDefElem("rolemembers", (Node *)$2);
}
- /* The following are not supported by ALTER ROLE/USER/GROUP */
+ ;
+
+CreateOptRoleElem:
+ AlterOptRoleElem { $$ = $1; }
+ /* The following are not supported by ALTER ROLE/USER/GROUP */
| SYSID Iconst
{
$$ = makeDefElem("sysid", (Node *)makeInteger($2));
@@ -897,7 +907,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with OptRoleList
+ ALTER ROLE RoleId opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -907,12 +917,18 @@ AlterRoleStmt:
}
;
+opt_in_database:
+ /* EMPTY */ { $$ = NULL; }
+ | IN_P DATABASE database_name { $$ = $3; }
+ ;
+
AlterRoleSetStmt:
- ALTER ROLE RoleId SetResetClause
+ ALTER ROLE RoleId opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->setstmt = $4;
+ n->database = $4;
+ n->setstmt = $5;
$$ = (Node *)n;
}
;
@@ -925,7 +941,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with OptRoleList
+ ALTER USER RoleId opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -941,6 +957,7 @@ AlterUserSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
+ n->database = NULL;
n->setstmt = $4;
$$ = (Node *)n;
}
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 85f1507ba36..f7a27b9e430 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.177 2009/08/27 16:59:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.178 2009/10/07 22:14:22 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -392,8 +392,6 @@ InitializeSessionUserId(const char *rolename)
{
HeapTuple roleTup;
Form_pg_authid rform;
- Datum datum;
- bool isnull;
Oid roleid;
/*
@@ -470,24 +468,6 @@ InitializeSessionUserId(const char *rolename)
AuthenticatedUserIsSuperuser ? "on" : "off",
PGC_INTERNAL, PGC_S_OVERRIDE);
- /*
- * Set up user-specific configuration variables. This is a good place to
- * do it so we don't have to read pg_authid twice during session startup.
- */
- datum = SysCacheGetAttr(AUTHNAME, roleTup,
- Anum_pg_authid_rolconfig, &isnull);
- if (!isnull)
- {
- ArrayType *a = DatumGetArrayTypeP(datum);
-
- /*
- * We process all the options at SUSET level. We assume that the
- * right to insert an option into pg_authid was checked when it was
- * inserted.
- */
- ProcessGUCArray(a, PGC_SUSET, PGC_S_USER, GUC_ACTION_SET);
- }
-
ReleaseSysCache(roleTup);
}
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 5321afc1b8d..b6c93c7f8eb 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.197 2009/09/01 00:09:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.198 2009/10/07 22:14:23 alvherre Exp $
*
*
*-------------------------------------------------------------------------
@@ -27,6 +27,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_db_role_setting.h"
#include "catalog/pg_tablespace.h"
#include "libpq/auth.h"
#include "libpq/libpq-be.h"
@@ -63,6 +64,7 @@ static void CheckMyDatabase(const char *name, bool am_superuser);
static void InitCommunication(void);
static void ShutdownPostgres(int code, Datum arg);
static bool ThereIsAtLeastOneRole(void);
+static void process_settings(Oid databaseid, Oid roleid);
/*** InitPostgres support ***/
@@ -344,29 +346,6 @@ CheckMyDatabase(const char *name, bool am_superuser)
pg_bind_textdomain_codeset(textdomain(NULL));
#endif
- /*
- * Lastly, set up any database-specific configuration variables.
- */
- if (IsUnderPostmaster)
- {
- Datum datum;
- bool isnull;
-
- datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_datconfig,
- &isnull);
- if (!isnull)
- {
- ArrayType *a = DatumGetArrayTypeP(datum);
-
- /*
- * We process all the options at SUSET level. We assume that the
- * right to insert an option into pg_database was checked when it
- * was inserted.
- */
- ProcessGUCArray(a, PGC_SUSET, PGC_S_DATABASE, GUC_ACTION_SET);
- }
- }
-
ReleaseSysCache(tup);
}
@@ -739,6 +718,9 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
/* set up ACL framework (so CheckMyDatabase can check permissions) */
initialize_acl();
+ /* Process pg_db_role_setting options */
+ process_settings(MyDatabaseId, GetSessionUserId());
+
/*
* Re-read the pg_database row for our database, check permissions and
* set up database-specific GUC settings. We can't do this until all the
@@ -851,6 +833,28 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
CommitTransactionCommand();
}
+/*
+ * Load GUC settings from pg_db_role_setting.
+ *
+ * We try specific settings for the database/role combination, as well as
+ * general for this database and for this user.
+ */
+static void
+process_settings(Oid databaseid, Oid roleid)
+{
+ Relation relsetting;
+
+ if (!IsUnderPostmaster)
+ return;
+
+ relsetting = heap_open(DbRoleSettingRelationId, AccessShareLock);
+
+ ApplySetting(databaseid, roleid, relsetting, PGC_S_DATABASE_USER);
+ ApplySetting(InvalidOid, roleid, relsetting, PGC_S_USER);
+ ApplySetting(databaseid, InvalidOid, relsetting, PGC_S_DATABASE);
+
+ heap_close(relsetting, AccessShareLock);
+}
/*
* Backend-shutdown callback. Do cleanup that we want to be sure happens