Track dependencies on shared objects (which is to say, roles; we already

have adequate mechanisms for tracking the contents of databases and
tablespaces).  This solves the longstanding problem that you can drop a
user who still owns objects and/or has access permissions.
Alvaro Herrera, with some kibitzing from Tom Lane.
This commit is contained in:
Tom Lane 2005-07-07 20:40:02 +00:00
parent 442b59dd8b
commit 59d1b3d99e
38 changed files with 1842 additions and 85 deletions

View File

@ -1,6 +1,6 @@
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.106 2005/06/28 05:08:50 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.107 2005/07/07 20:39:56 tgl Exp $
-->
<chapter id="catalogs">
@ -173,6 +173,11 @@
<entry>query rewrite rules</entry>
</row>
<row>
<entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry>
<entry>dependencies on shared objects</entry>
</row>
<row>
<entry><link linkend="catalog-pg-statistic"><structname>pg_statistic</structname></link></entry>
<entry>planner statistics</entry>
@ -1890,6 +1895,12 @@
RESTRICT</> case.
</para>
<para>
See also <link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link>,
which performs a similar function for dependencies involving objects
that are shared across a database cluster.
</para>
<table>
<title><structname>pg_depend</> Columns</title>
@ -3024,7 +3035,7 @@
<row>
<entry><structfield>proargmodes</structfield></entry>
<entry><type>"char"[]</type></entry>
<entry><type>char[]</type></entry>
<entry></entry>
<entry>
An array with the modes of the function arguments, encoded as
@ -3198,6 +3209,149 @@
</sect1>
<sect1 id="catalog-pg-shdepend">
<title><structname>pg_shdepend</structname></title>
<indexterm zone="catalog-pg-shdepend">
<primary>pg_shdepend</primary>
</indexterm>
<para>
The catalog <structname>pg_shdepend</structname> records the
dependency relationships between database objects and shared objects,
such as roles. This information allows
<productname>PostgreSQL</productname> to ensure that those objects are
unreferenced before attempting to delete them.
</para>
<para>
See also <link linkend="catalog-pg-depend"><structname>pg_depend</structname></link>,
which performs a similar function for dependencies involving objects
within a single database.
</para>
<para>
Unlike most system catalogs, <structname>pg_shdepend</structname>
is shared across all databases of a cluster: there is only one
copy of <structname>pg_shdepend</structname> per cluster, not
one per database.
</para>
<table>
<title><structname>pg_shdepend</> 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>dbid</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 dependent object is in,
or zero for a shared object</entry>
</row>
<row>
<entry><structfield>classid</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
<entry>The OID of the system catalog the dependent object is in</entry>
</row>
<row>
<entry><structfield>objid</structfield></entry>
<entry><type>oid</type></entry>
<entry>any OID column</entry>
<entry>The OID of the specific dependent object</entry>
</row>
<row>
<entry><structfield>refclassid</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
<entry>The OID of the system catalog the referenced object is in
(must be a shared catalog)</entry>
</row>
<row>
<entry><structfield>refobjid</structfield></entry>
<entry><type>oid</type></entry>
<entry>any OID column</entry>
<entry>The OID of the specific referenced object</entry>
</row>
<row>
<entry><structfield>deptype</structfield></entry>
<entry><type>char</type></entry>
<entry></entry>
<entry>
A code defining the specific semantics of this dependency relationship; see text.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
In all cases, a <structname>pg_shdepend</structname> entry indicates that
the referenced object may not be dropped without also dropping the dependent
object. However, there are several subflavors identified by
<structfield>deptype</>:
<variablelist>
<varlistentry>
<term><symbol>SHARED_DEPENDENCY_OWNER</> (<literal>o</>)</term>
<listitem>
<para>
The referenced object (which must be a role) is the owner of the
dependent object.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><symbol>SHARED_DEPENDENCY_ACL</> (<literal>a</>)</term>
<listitem>
<para>
The referenced object (which must be a role) is mentioned in the
ACL (access control list, i.e., privileges list) of the
dependent object. (A <symbol>SHARED_DEPENDENCY_ACL</> entry is
not made for the owner of the object, since the owner will have
a <symbol>SHARED_DEPENDENCY_OWNER</> entry anyway.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><symbol>SHARED_DEPENDENCY_PIN</> (<literal>p</>)</term>
<listitem>
<para>
There is no dependent object; this type of entry is a signal
that the system itself depends on the referenced object, and so
that object must never be deleted. Entries of this type are
created only by <command>initdb</command>. The columns for the
dependent object contain zeroes.
</para>
</listitem>
</varlistentry>
</variablelist>
Other dependency flavors may be needed in future. Note in particular
that the current definition only supports roles as referenced objects.
</para>
</sect1>
<sect1 id="catalog-pg-statistic">
<title><structname>pg_statistic</structname></title>
@ -4196,7 +4350,7 @@
<entry><literal><link linkend="catalog-pg-database"><structname>pg_database</structname></link>.oid</literal></entry>
<entry>
OID of the database in which the object exists, or
zero if the object is a globally-shared object, or
zero if the object is a shared object, or
NULL if the object is a transaction ID
</entry>
</row>

View File

@ -2,7 +2,7 @@
#
# Makefile for backend/catalog
#
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.54 2005/06/28 05:08:52 tgl Exp $
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.55 2005/07/07 20:39:57 tgl Exp $
#
#-------------------------------------------------------------------------
@ -12,7 +12,8 @@ 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_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_type.o
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
pg_type.o
BKIFILES = postgres.bki postgres.description
@ -31,7 +32,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
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_namespace.h pg_conversion.h pg_database.h \
pg_namespace.h pg_conversion.h pg_database.h pg_shdepend.h \
pg_authid.h pg_auth_members.h pg_tablespace.h pg_depend.h \
indexing.h \
)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.114 2005/06/28 19:51:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.115 2005/07/07 20:39:57 tgl Exp $
*
* NOTES
* See acl.h.
@ -19,6 +19,7 @@
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_auth_members.h"
@ -252,6 +253,10 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
Datum values[Natts_pg_class];
char nulls[Natts_pg_class];
char replaces[Natts_pg_class];
int noldmembers;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
/* open pg_class */
relation = heap_open(RelationRelationId, RowExclusiveLock);
@ -344,11 +349,19 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
/*
* We need the members of both old and new ACLs so we can correct
* the shared dependency information.
*/
noldmembers = aclmembers(old_acl, &oldmembers);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grant_option, stmt->behavior,
stmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
@ -359,13 +372,19 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
ReleaseSysCache(tuple);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* keep the catalog indexes up to date */
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
ReleaseSysCache(tuple);
pfree(new_acl);
heap_close(relation, RowExclusiveLock);
@ -422,6 +441,10 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
Datum values[Natts_pg_database];
char nulls[Natts_pg_database];
char replaces[Natts_pg_database];
int noldmembers;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
ScanKeyInit(&entry[0],
@ -503,11 +526,19 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
/*
* We need the members of both old and new ACLs so we can correct
* the shared dependency information.
*/
noldmembers = aclmembers(old_acl, &oldmembers);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grant_option, stmt->behavior,
stmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
@ -523,6 +554,12 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
/* keep the catalog indexes up to date */
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
pfree(new_acl);
heap_endscan(scan);
@ -580,6 +617,10 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
Datum values[Natts_pg_proc];
char nulls[Natts_pg_proc];
char replaces[Natts_pg_proc];
int noldmembers;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false);
@ -658,11 +699,19 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
/*
* We need the members of both old and new ACLs so we can correct
* the shared dependency information.
*/
noldmembers = aclmembers(old_acl, &oldmembers);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grant_option, stmt->behavior,
stmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
@ -673,13 +722,19 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
ReleaseSysCache(tuple);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* keep the catalog indexes up to date */
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, oid,
ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
ReleaseSysCache(tuple);
pfree(new_acl);
heap_close(relation, RowExclusiveLock);
@ -734,6 +789,10 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
Datum values[Natts_pg_language];
char nulls[Natts_pg_language];
char replaces[Natts_pg_language];
int noldmembers;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
relation = heap_open(LanguageRelationId, RowExclusiveLock);
tuple = SearchSysCache(LANGNAME,
@ -822,11 +881,19 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
/*
* We need the members of both old and new ACLs so we can correct
* the shared dependency information.
*/
noldmembers = aclmembers(old_acl, &oldmembers);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grant_option, stmt->behavior,
stmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
@ -837,13 +904,19 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
ReleaseSysCache(tuple);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* keep the catalog indexes up to date */
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
ReleaseSysCache(tuple);
pfree(new_acl);
heap_close(relation, RowExclusiveLock);
@ -898,6 +971,10 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
Datum values[Natts_pg_namespace];
char nulls[Natts_pg_namespace];
char replaces[Natts_pg_namespace];
int noldmembers;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
relation = heap_open(NamespaceRelationId, RowExclusiveLock);
tuple = SearchSysCache(NAMESPACENAME,
@ -977,11 +1054,19 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
/*
* We need the members of both old and new ACLs so we can correct
* the shared dependency information.
*/
noldmembers = aclmembers(old_acl, &oldmembers);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grant_option, stmt->behavior,
stmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
@ -992,13 +1077,19 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
ReleaseSysCache(tuple);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* keep the catalog indexes up to date */
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
ReleaseSysCache(tuple);
pfree(new_acl);
heap_close(relation, RowExclusiveLock);
@ -1055,6 +1146,10 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
Datum values[Natts_pg_tablespace];
char nulls[Natts_pg_tablespace];
char replaces[Natts_pg_tablespace];
int noldmembers;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
ScanKeyInit(&entry[0],
@ -1136,11 +1231,19 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
/*
* We need the members of both old and new ACLs so we can correct
* the shared dependency information.
*/
noldmembers = aclmembers(old_acl, &oldmembers);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grant_option, stmt->behavior,
stmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
@ -1156,6 +1259,12 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
/* keep the catalog indexes up to date */
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, HeapTupleGetOid(tuple),
ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
pfree(new_acl);
heap_endscan(scan);

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.44 2005/04/14 20:03:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.45 2005/07/07 20:39:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,9 +22,11 @@
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
@ -32,12 +34,15 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "lib/stringinfo.h"
@ -509,6 +514,7 @@ recursiveDeletion(const ObjectAddress *object,
break;
}
/* delete the pg_depend tuple */
simple_heap_delete(depRel, &tup->t_self);
}
@ -584,6 +590,14 @@ recursiveDeletion(const ObjectAddress *object,
*/
DeleteComments(object->objectId, object->classId, object->objectSubId);
/*
* Delete shared dependency references related to this object.
* Sub-objects (columns) don't have dependencies on global objects,
* so skip them.
*/
if (object->objectSubId == 0)
deleteSharedDependencyRecordsFor(object->classId, object->objectId);
/*
* CommandCounterIncrement here to ensure that preceding changes are
* all visible.
@ -1365,6 +1379,18 @@ getObjectClass(const ObjectAddress *object)
case NamespaceRelationId:
Assert(object->objectSubId == 0);
return OCLASS_SCHEMA;
case AuthIdRelationId:
Assert(object->objectSubId == 0);
return OCLASS_ROLE;
case DatabaseRelationId:
Assert(object->objectSubId == 0);
return OCLASS_DATABASE;
case TableSpaceRelationId:
Assert(object->objectSubId == 0);
return OCLASS_TBLSPACE;
}
/* shouldn't get here */
@ -1680,6 +1706,37 @@ getObjectDescription(const ObjectAddress *object)
break;
}
case OCLASS_ROLE:
{
appendStringInfo(&buffer, _("role %s"),
GetUserNameFromId(object->objectId));
break;
}
case OCLASS_DATABASE:
{
char *datname;
datname = get_database_name(object->objectId);
if (!datname)
elog(ERROR, "cache lookup failed for database %u",
object->objectId);
appendStringInfo(&buffer, _("database %s"), datname);
break;
}
case OCLASS_TBLSPACE:
{
char *tblspace;
tblspace = get_tablespace_name(object->objectId);
if (!tblspace)
elog(ERROR, "cache lookup failed for tablespace %u",
object->objectId);
appendStringInfo(&buffer, _("tablespace %s"), tblspace);
break;
}
default:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.285 2005/06/05 00:38:07 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.286 2005/07/07 20:39:57 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -755,6 +755,8 @@ heap_create_with_catalog(const char *relname,
* make a dependency link to force the relation to be deleted if its
* namespace is. Skip this in bootstrap mode, since we don't make
* dependencies while bootstrapping.
*
* Also make a dependency link to its owner.
*/
if (!IsBootstrapProcessingMode())
{
@ -768,6 +770,8 @@ heap_create_with_catalog(const char *relname,
referenced.objectId = relnamespace;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
recordDependencyOnOwner(RelationRelationId, new_rel_oid, GetUserId());
}
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.24 2005/06/28 05:08:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.25 2005/07/07 20:39:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -120,6 +120,10 @@ ConversionCreate(const char *conname, Oid connamespace,
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* create dependency on owner */
recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
conowner);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);

View File

@ -8,13 +8,14 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_namespace.c,v 1.14 2005/06/28 05:08:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_namespace.c,v 1.15 2005/07/07 20:39:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_namespace.h"
#include "utils/builtins.h"
@ -72,5 +73,8 @@ NamespaceCreate(const char *nspName, Oid ownerId)
heap_close(nspdesc, RowExclusiveLock);
/* Record dependency on owner */
recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId);
return nspoid;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.92 2005/06/28 05:08:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.93 2005/07/07 20:39:57 tgl Exp $
*
* NOTES
* these routines moved here from commands/define.c and somewhat cleaned up.
@ -889,6 +889,7 @@ makeOperatorDependencies(HeapTuple tuple)
/* In case we are updating a shell, delete any existing entries */
deleteDependencyRecordsFor(myself.classId, myself.objectId);
deleteSharedDependencyRecordsFor(myself.classId, myself.objectId);
/* Dependency on namespace */
if (OidIsValid(oper->oprnamespace))
@ -962,4 +963,8 @@ makeOperatorDependencies(HeapTuple tuple)
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* Dependency on owner */
recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
oper->oprowner);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.131 2005/06/28 19:51:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.132 2005/07/07 20:39:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -349,7 +349,10 @@ ProcedureCreate(const char *procedureName,
* existing function, first delete any existing pg_depend entries.
*/
if (is_update)
{
deleteDependencyRecordsFor(ProcedureRelationId, retval);
deleteSharedDependencyRecordsFor(ProcedureRelationId, retval);
}
myself.classId = ProcedureRelationId;
myself.objectId = retval;
@ -382,6 +385,9 @@ ProcedureCreate(const char *procedureName,
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependency on owner */
recordDependencyOnOwner(ProcedureRelationId, retval, GetUserId());
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.101 2005/06/28 05:08:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.102 2005/07/07 20:39:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -75,7 +75,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
namestrcpy(&name, typeName);
values[i++] = NameGetDatum(&name); /* typname */
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typowner */
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
values[i++] = Int16GetDatum(0); /* typlen */
values[i++] = BoolGetDatum(false); /* typbyval */
values[i++] = CharGetDatum(0); /* typtype */
@ -117,6 +117,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
typoid,
InvalidOid,
0,
GetUserId(),
InvalidOid,
InvalidOid,
InvalidOid,
@ -330,6 +331,7 @@ TypeCreate(const char *typeName,
typeObjectId,
relationOid,
relationKind,
GetUserId(),
inputProcedure,
outputProcedure,
receiveProcedure,
@ -365,6 +367,7 @@ GenerateTypeDependencies(Oid typeNamespace,
Oid relationOid, /* only for 'c'atalog
* types */
char relationKind, /* ditto */
Oid owner,
Oid inputProcedure,
Oid outputProcedure,
Oid receiveProcedure,
@ -379,7 +382,10 @@ GenerateTypeDependencies(Oid typeNamespace,
referenced;
if (rebuild)
{
deleteDependencyRecordsFor(TypeRelationId, typeObjectId);
deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId);
}
myself.classId = TypeRelationId;
myself.objectId = typeObjectId;
@ -485,6 +491,9 @@ GenerateTypeDependencies(Oid typeNamespace,
/* Normal dependency on the default expression. */
if (defaultExpr)
recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
/* Shared dependency on owner. */
recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
}
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.19 2005/06/28 05:08:53 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.20 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,6 +17,7 @@
#include "catalog/pg_conversion.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
@ -220,6 +221,10 @@ AlterConversionOwner(List *name, Oid newOwnerId)
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
/* Update owner dependency reference */
changeDependencyOnOwner(ConversionRelationId, conversionOid,
newOwnerId);
}
heap_close(rel, NoLock);

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.164 2005/06/30 00:00:50 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.165 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -28,6 +28,7 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
@ -511,6 +512,12 @@ createdb(const CreatedbStmt *stmt)
/* Update indexes */
CatalogUpdateIndexes(pg_database_rel, tuple);
/* Register owner dependency */
recordDependencyOnOwner(DatabaseRelationId, dboid, datdba);
/* Create pg_shdepend entries for objects within database */
copyTemplateDependencies(src_dboid, dboid);
/* Close pg_database, but keep exclusive lock till commit */
heap_close(pg_database_rel, NoLock);
@ -679,6 +686,11 @@ dropdb(const char *dbname)
/* Close pg_database, but keep exclusive lock till commit */
heap_close(pgdbrel, NoLock);
/*
* Remove shared dependency references for the database.
*/
dropDatabaseDependencies(db_id);
/*
* Set flag to update flat database file at commit.
*/
@ -951,6 +963,10 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
CatalogUpdateIndexes(rel, newtuple);
heap_freetuple(newtuple);
/* Update owner dependency reference */
changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple),
newOwnerId);
}
systable_endscan(scan);

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.62 2005/06/28 05:08:53 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.63 2005/07/07 20:39:58 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@ -925,6 +925,9 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
CatalogUpdateIndexes(rel, newtuple);
heap_freetuple(newtuple);
/* Update owner dependency reference */
changeDependencyOnOwner(ProcedureRelationId, procOid, newOwnerId);
}
ReleaseSysCache(tup);

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.33 2005/06/28 05:08:53 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.34 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -392,6 +392,9 @@ DefineOpClass(CreateOpClassStmt *stmt)
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependency on owner */
recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
heap_close(rel, RowExclusiveLock);
}
@ -962,6 +965,9 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
/* Update owner dependency reference */
changeDependencyOnOwner(OperatorClassRelationId, amOid, newOwnerId);
}
heap_close(rel, NoLock);

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.22 2005/06/28 05:08:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.23 2005/07/07 20:39:58 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -310,6 +310,9 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
/* Update owner dependency reference */
changeDependencyOnOwner(OperatorRelationId, operOid, newOwnerId);
}
heap_close(rel, NoLock);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.31 2005/06/28 05:08:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.32 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -342,6 +342,10 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
CatalogUpdateIndexes(rel, newtuple);
heap_freetuple(newtuple);
/* Update owner dependency reference */
changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),
newOwnerId);
}
ReleaseSysCache(tup);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.162 2005/06/28 05:08:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.163 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -5321,6 +5321,9 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId)
heap_freetuple(newtuple);
/* Update owner dependency reference */
changeDependencyOnOwner(RelationRelationId, relationOid, newOwnerId);
/*
* If we are operating on a table, also change the ownership of
* any indexes and sequences that belong to the table, as well as

View File

@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.24 2005/07/04 04:51:46 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.25 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -50,6 +50,7 @@
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_tablespace.h"
@ -307,6 +308,9 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
heap_freetuple(tuple);
/* Record dependency on owner */
recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
/*
* Attempt to coerce target directory to safe permissions. If this
* fails, it doesn't exist or has the wrong owner.
@ -818,6 +822,10 @@ AlterTableSpaceOwner(const char *name, Oid newOwnerId)
CatalogUpdateIndexes(rel, newtuple);
heap_freetuple(newtuple);
/* Update owner dependency reference */
changeDependencyOnOwner(TableSpaceRelationId, HeapTupleGetOid(tup),
newOwnerId);
}
heap_endscan(scandesc);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.73 2005/06/28 05:08:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.74 2005/07/07 20:39:58 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -1208,6 +1208,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
domainoid,
typTup->typrelid,
0, /* relation kind is n/a */
typTup->typowner,
typTup->typinput,
typTup->typoutput,
typTup->typreceive,
@ -2080,6 +2081,9 @@ AlterTypeOwner(List *names, Oid newOwnerId)
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
/* Update owner dependency reference */
changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
}
/* Clean up */

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.155 2005/06/29 20:34:13 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.156 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -14,10 +14,10 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
#include "commands/user.h"
#include "libpq/crypt.h"
#include "miscadmin.h"
@ -742,10 +742,8 @@ DropRole(DropRoleStmt *stmt)
const char *role = strVal(lfirst(item));
HeapTuple tuple,
tmp_tuple;
Relation pg_rel;
TupleDesc pg_dsc;
ScanKeyData scankey;
HeapScanDesc scan;
ScanKeyData scankey;
char *detail;
SysScanDesc sscan;
Oid roleid;
@ -780,42 +778,18 @@ DropRole(DropRoleStmt *stmt)
errmsg("must be superuser to drop superusers")));
/*
* Check if role still owns a database. If so, error out.
*
* (It used to be that this function would drop the database
* automatically. This is not only very dangerous for people that
* don't read the manual, it doesn't seem to be the behaviour one
* would expect either.) -- petere 2000/01/14)
*/
pg_rel = heap_open(DatabaseRelationId, AccessShareLock);
pg_dsc = RelationGetDescr(pg_rel);
* Lock the role, so nobody can add dependencies to her while we drop
* her. We keep the lock until the end of transaction.
*/
LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
ScanKeyInit(&scankey,
Anum_pg_database_datdba,
BTEqualStrategyNumber, F_OIDEQ,
roleid);
scan = heap_beginscan(pg_rel, SnapshotNow, 1, &scankey);
if ((tmp_tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
char *dbname;
dbname = NameStr(((Form_pg_database) GETSTRUCT(tmp_tuple))->datname);
/* Check for pg_shdepend entries depending on this role */
if ((detail = checkSharedDependencies(AuthIdRelationId, roleid)) != NULL)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("role \"%s\" cannot be dropped", role),
errdetail("The role owns database \"%s\".", dbname)));
}
heap_endscan(scan);
heap_close(pg_rel, AccessShareLock);
/*
* Somehow we'd have to check for tables, views, etc. owned by the
* role as well, but those could be spread out over all sorts of
* databases which we don't have access to (easily).
*/
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("role \"%s\" cannot be dropped because some objects depend on it",
role),
errdetail("%s", detail)));
/*
* Remove the role from the pg_authid table

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.117 2005/06/29 20:34:14 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.118 2005/07/07 20:39:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -59,6 +59,7 @@ static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
Oid ownerId);
static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
Oid ownerId, DropBehavior behavior);
static int oidComparator(const void *arg1, const void *arg2);
static AclMode convert_priv_string(text *priv_type_text);
@ -1052,6 +1053,86 @@ aclmask(const Acl *acl, Oid roleid, Oid ownerId,
}
/*
* aclmembers
* Find out all the roleids mentioned in an Acl.
* Note that we do not distinguish grantors from grantees.
*
* *roleids is set to point to a palloc'd array containing distinct OIDs
* in sorted order. The length of the array is the function result.
*/
int
aclmembers(const Acl *acl, Oid **roleids)
{
Oid *list;
const AclItem *acldat;
int i,
j,
k;
if (acl == NULL || ACL_NUM(acl) == 0)
{
*roleids = NULL;
return 0;
}
/* Allocate the worst-case space requirement */
list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
acldat = ACL_DAT(acl);
/*
* Walk the ACL collecting mentioned RoleIds.
*/
j = 0;
for (i = 0; i < ACL_NUM(acl); i++)
{
const AclItem *ai = &acldat[i];
if (ai->ai_grantee != ACL_ID_PUBLIC)
list[j++] = ai->ai_grantee;
/* grantor is currently never PUBLIC, but let's check anyway */
if (ai->ai_grantor != ACL_ID_PUBLIC)
list[j++] = ai->ai_grantor;
}
/* Sort the array */
qsort(list, j, sizeof(Oid), oidComparator);
/* Remove duplicates from the array */
k = 0;
for (i = 1; i < j; i++)
{
if (list[k] != list[i])
list[++k] = list[i];
}
/*
* We could repalloc the array down to minimum size, but it's hardly
* worth it since it's only transient memory.
*/
*roleids = list;
return k + 1;
}
/*
* oidComparator
* qsort comparison function for Oids
*/
static int
oidComparator(const void *arg1, const void *arg2)
{
Oid oid1 = * (const Oid *) arg1;
Oid oid2 = * (const Oid *) arg2;
if (oid1 > oid2)
return 1;
if (oid1 < oid2)
return -1;
return 0;
}
/*
* aclinsert (exported function)
*/

View File

@ -42,7 +42,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions taken from FreeBSD.
*
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.90 2005/07/02 17:01:50 momjian Exp $
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.91 2005/07/07 20:39:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1512,6 +1512,10 @@ setup_depend(void)
* must be the only entries for their objects.
*/
"DELETE FROM pg_depend;\n",
"VACUUM pg_depend;\n",
"DELETE FROM pg_shdepend;\n",
"VACUUM pg_shdepend;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_class;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
@ -1541,10 +1545,13 @@ setup_depend(void)
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_namespace "
" WHERE nspname LIKE 'pg%';\n",
"INSERT INTO pg_shdepend SELECT 0, 0, 0, tableoid, oid, 'p' "
" FROM pg_authid;\n",
NULL
};
fputs(_("initializing pg_depend ... "), stdout);
fputs(_("initializing dependencies ... "), stdout);
fflush(stdout);
snprintf(cmd, sizeof(cmd),

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.284 2005/07/01 19:19:02 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.285 2005/07/07 20:39:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200507011
#define CATALOG_VERSION_NO 200507071
#endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.14 2004/12/31 22:03:24 pgsql Exp $
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.15 2005/07/07 20:39:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -67,6 +67,40 @@ typedef enum DependencyType
DEPENDENCY_PIN = 'p'
} DependencyType;
/*
* There is also a SharedDependencyType enum type that determines the exact
* semantics of an entry in pg_shdepend. Just like regular dependency entries,
* any pg_shdepend entry means that the referenced object cannot be dropped
* unless the dependent object is dropped at the same time. There are some
* additional rules however:
*
* (a) For a SHARED_DEPENDENCY_PIN entry, there is no dependent object --
* rather, the referenced object is an essential part of the system. This
* applies to the initdb-created superuser. Entries of this type are only
* created by initdb; objects in this category don't need further pg_shdepend
* entries if more objects come to depend on them.
*
* (b) a SHARED_DEPENDENCY_OWNER entry means that the referenced object is
* the role owning the dependent object. The referenced object must be
* a pg_authid entry.
*
* (c) a SHARED_DEPENDENCY_ACL entry means that the referenced object is
* a role mentioned in the ACL field of the dependent object. The referenced
* object must be a pg_authid entry. (SHARED_DEPENDENCY_ACL entries are not
* created for the owner of an object; hence two objects may be linked by
* one or the other, but not both, of these dependency types.)
*
* SHARED_DEPENDENCY_INVALID is a value used as a parameter in internal
* routines, and is not valid in the catalog itself.
*/
typedef enum SharedDependencyType
{
SHARED_DEPENDENCY_PIN = 'p',
SHARED_DEPENDENCY_OWNER = 'o',
SHARED_DEPENDENCY_ACL = 'a',
SHARED_DEPENDENCY_INVALID = 0
} SharedDependencyType;
/*
* The two objects related by a dependency are identified by ObjectAddresses.
@ -81,7 +115,8 @@ typedef struct ObjectAddress
/*
* This enum covers all system catalogs whose OIDs can appear in classId.
* This enum covers all system catalogs whose OIDs can appear in
* pg_depend.classId or pg_shdepend.classId.
*/
typedef enum ObjectClass
{
@ -98,6 +133,9 @@ typedef enum ObjectClass
OCLASS_REWRITE, /* pg_rewrite */
OCLASS_TRIGGER, /* pg_trigger */
OCLASS_SCHEMA, /* pg_namespace */
OCLASS_ROLE, /* pg_authid */
OCLASS_DATABASE, /* pg_database */
OCLASS_TBLSPACE, /* pg_tablespace */
MAX_OCLASS /* MUST BE LAST */
} ObjectClass;
@ -136,4 +174,28 @@ extern void recordMultipleDependencies(const ObjectAddress *depender,
extern long deleteDependencyRecordsFor(Oid classId, Oid objectId);
/* in pg_shdepend.c */
extern void recordSharedDependencyOn(ObjectAddress *depender,
ObjectAddress *referenced,
SharedDependencyType deptype);
extern void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId);
extern void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner);
extern void changeDependencyOnOwner(Oid classId, Oid objectId,
Oid newOwnerId);
extern void updateAclDependencies(Oid classId, Oid objectId,
Oid ownerId, bool isGrant,
int noldmembers, Oid *oldmembers,
int nnewmembers, Oid *newmembers);
extern char *checkSharedDependencies(Oid classId, Oid objectId);
extern void copyTemplateDependencies(Oid templateDbId, Oid newDbId);
extern void dropDatabaseDependencies(Oid databaseId);
#endif /* DEPENDENCY_H */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.88 2005/06/28 05:09:04 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.89 2005/07/07 20:39:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -179,6 +179,13 @@ DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index,2692, on pg_rewrite using btree(oid oi
DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index,2693, on pg_rewrite using btree(ev_class oid_ops, rulename name_ops));
#define RewriteRelRulenameIndexId 2693
/* This following index is not used for a cache and is not unique */
DECLARE_INDEX(pg_shdepend_depender_index,1232, on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops));
#define SharedDependDependerIndexId 1232
/* This following index is not used for a cache and is not unique */
DECLARE_INDEX(pg_shdepend_reference_index,1233, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops));
#define SharedDependReferenceIndexId 1233
DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index,2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops));
#define StatisticRelidAttnumIndexId 2696

View File

@ -0,0 +1,91 @@
/*-------------------------------------------------------------------------
*
* pg_shdepend.h
* definition of the system "shared dependency" relation (pg_shdepend)
* along with the relation's initial contents.
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_shdepend.h,v 1.1 2005/07/07 20:39:59 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
* information from the DATA() statements.
*
*-------------------------------------------------------------------------
*/
#ifndef PG_SHDEPEND_H
#define PG_SHDEPEND_H
/* ----------------
* postgres.h contains the system type definitions and the
* CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file
* can be read by both genbki.sh and the C compiler.
* ----------------
*/
/* ----------------
* pg_shdepend definition. cpp turns this into
* typedef struct FormData_pg_shdepend
* ----------------
*/
#define SharedDependRelationId 1214
CATALOG(pg_shdepend,1214) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
{
/*
* Identification of the dependent (referencing) object.
*
* These fields are all zeroes for a DEPENDENCY_PIN entry. Also,
* dbid can be zero to denote a shared object.
*/
Oid dbid; /* OID of database containing object */
Oid classid; /* OID of table containing object */
Oid objid; /* OID of object itself */
/*
* Identification of the independent (referenced) object. This is
* always a shared object, so we need no database ID field.
*/
Oid refclassid; /* OID of table containing object */
Oid refobjid; /* OID of object itself */
/*
* Precise semantics of the relationship are specified by the deptype
* field. See SharedDependencyType in catalog/dependency.h.
*/
char deptype; /* see codes in dependency.h */
} FormData_pg_shdepend;
/* ----------------
* Form_pg_shdepend corresponds to a pointer to a row with
* the format of pg_shdepend relation.
* ----------------
*/
typedef FormData_pg_shdepend *Form_pg_shdepend;
/* ----------------
* compiler constants for pg_shdepend
* ----------------
*/
#define Natts_pg_shdepend 6
#define Anum_pg_shdepend_dbid 1
#define Anum_pg_shdepend_classid 2
#define Anum_pg_shdepend_objid 3
#define Anum_pg_shdepend_refclassid 4
#define Anum_pg_shdepend_refobjid 5
#define Anum_pg_shdepend_deptype 6
/*
* pg_shdepend has no preloaded contents; system-defined dependencies are
* loaded into it during a late stage of the initdb process.
*
* NOTE: we do not represent all possible dependency pairs in pg_shdepend;
* for example, there's not much value in creating an explicit dependency
* from a relation to its database. Currently, only dependencies on roles
* are explicitly stored in pg_shdepend.
*/
#endif /* PG_SHDEPEND_H */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.162 2005/06/28 05:09:12 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.163 2005/07/07 20:39:59 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -582,6 +582,7 @@ extern void GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId,
Oid relationOid,
char relationKind,
Oid owner,
Oid inputProcedure,
Oid outputProcedure,
Oid receiveProcedure,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.80 2005/06/29 20:34:15 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.81 2005/07/07 20:40:00 tgl Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
@ -208,6 +208,7 @@ extern Acl *aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId);
extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId,
AclMode mask, AclMaskHow how);
extern int aclmembers(const Acl *acl, Oid **roleids);
extern bool is_member_of_role(Oid member, Oid role);
extern bool is_admin_of_role(Oid member, Oid role);

View File

@ -385,5 +385,6 @@ SELECT * FROM clstr_1;
-- clean up
\c -
DROP TABLE clstr_1;
DROP TABLE clstr_2;
DROP TABLE clstr_3;
DROP USER clstr_user;

View File

@ -0,0 +1,39 @@
--
-- DEPENDENCIES
--
CREATE USER regression_user;
CREATE USER regression_user2;
CREATE USER regression_user3;
CREATE GROUP regression_group;
CREATE TABLE deptest ();
GRANT SELECT ON TABLE deptest TO GROUP regression_group;
GRANT ALL ON TABLE deptest TO regression_user, regression_user2;
-- can't drop neither because they have privileges somewhere
DROP USER regression_user;
ERROR: role "regression_user" cannot be dropped because some objects depend on it
DETAIL: access to table deptest
DROP GROUP regression_group;
ERROR: role "regression_group" cannot be dropped because some objects depend on it
DETAIL: access to table deptest
-- if we revoke the privileges we can drop the group
REVOKE SELECT ON deptest FROM GROUP regression_group;
DROP GROUP regression_group;
-- can't drop the user if we revoke the privileges partially
REVOKE SELECT, INSERT, UPDATE, DELETE, RULE, REFERENCES ON deptest FROM regression_user;
DROP USER regression_user;
ERROR: role "regression_user" cannot be dropped because some objects depend on it
DETAIL: access to table deptest
-- now we are OK to drop him
REVOKE TRIGGER ON deptest FROM regression_user;
DROP USER regression_user;
-- we are OK too if we drop the privileges all at once
REVOKE ALL ON deptest FROM regression_user2;
DROP USER regression_user2;
-- can't drop the owner of an object
ALTER TABLE deptest OWNER TO regression_user3;
DROP USER regression_user3;
ERROR: role "regression_user3" cannot be dropped because some objects depend on it
DETAIL: owner of table deptest
-- if we drop the object, we can drop the user too
DROP TABLE deptest;
DROP USER regression_user3;

View File

@ -601,6 +601,7 @@ DROP TABLE atest3;
DROP TABLE atest4;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;
REVOKE USAGE ON LANGUAGE sql FROM regressuser1;
DROP USER regressuser1;
DROP USER regressuser2;
DROP USER regressuser3;

View File

@ -56,6 +56,7 @@ SELECT relname, relhasindex
pg_operator | t
pg_proc | t
pg_rewrite | t
pg_shdepend | t
pg_statistic | t
pg_tablespace | t
pg_trigger | t
@ -65,7 +66,7 @@ SELECT relname, relhasindex
shighway | t
tenk1 | t
tenk2 | t
(55 rows)
(56 rows)
--
-- another sanity check: every system catalog that has OIDs should have

View File

@ -68,7 +68,7 @@ test: misc
# ----------
# The fifth group of parallel test
# ----------
test: select_views portals_p2 rules foreign_key cluster
test: select_views portals_p2 rules foreign_key cluster dependency
# ----------
# The sixth group of parallel test

View File

@ -1,4 +1,4 @@
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.27 2005/06/17 22:32:50 tgl Exp $
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.28 2005/07/07 20:40:01 tgl Exp $
# This should probably be in an order similar to parallel_schedule.
test: boolean
test: char
@ -98,3 +98,4 @@ test: polymorphism
test: rowtypes
test: stats
test: tablespace
test: dependency

View File

@ -156,5 +156,6 @@ SELECT * FROM clstr_1;
-- clean up
\c -
DROP TABLE clstr_1;
DROP TABLE clstr_2;
DROP TABLE clstr_3;
DROP USER clstr_user;

View File

@ -0,0 +1,41 @@
--
-- DEPENDENCIES
--
CREATE USER regression_user;
CREATE USER regression_user2;
CREATE USER regression_user3;
CREATE GROUP regression_group;
CREATE TABLE deptest ();
GRANT SELECT ON TABLE deptest TO GROUP regression_group;
GRANT ALL ON TABLE deptest TO regression_user, regression_user2;
-- can't drop neither because they have privileges somewhere
DROP USER regression_user;
DROP GROUP regression_group;
-- if we revoke the privileges we can drop the group
REVOKE SELECT ON deptest FROM GROUP regression_group;
DROP GROUP regression_group;
-- can't drop the user if we revoke the privileges partially
REVOKE SELECT, INSERT, UPDATE, DELETE, RULE, REFERENCES ON deptest FROM regression_user;
DROP USER regression_user;
-- now we are OK to drop him
REVOKE TRIGGER ON deptest FROM regression_user;
DROP USER regression_user;
-- we are OK too if we drop the privileges all at once
REVOKE ALL ON deptest FROM regression_user2;
DROP USER regression_user2;
-- can't drop the owner of an object
ALTER TABLE deptest OWNER TO regression_user3;
DROP USER regression_user3;
-- if we drop the object, we can drop the user too
DROP TABLE deptest;
DROP USER regression_user3;

View File

@ -339,6 +339,7 @@ DROP TABLE atest4;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;
REVOKE USAGE ON LANGUAGE sql FROM regressuser1;
DROP USER regressuser1;
DROP USER regressuser2;
DROP USER regressuser3;