Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.90
diff -c -r2.90 catalogs.sgml
*** doc/src/sgml/catalogs.sgml 11 Oct 2004 17:24:39 -0000 2.90
--- doc/src/sgml/catalogs.sgml 30 Oct 2004 15:42:42 -0000
***************
*** 174,179 ****
--- 174,183 ----
+ pg_shdepend
+ cross-database dependencies between objects
+
+ pg_statisticplanner statistics
***************
*** 3104,3109 ****
--- 3108,3183 ----
+
+ pg_shdepend
+
+
+ pg_shdepend
+
+
+
+ The shared catalog pg_shdepend records the
+ dependency relationships between database objects and global objects,
+ such as users and tablespaces. This information allows DROP
+ USER and DROP TABLESPACE to ensure that
+ those objects are unreferenced before attempting to delete them.
+
+
+
+ pg_depend> Columns
+
+
+
+
+ Name
+ Type
+ References
+ Description
+
+
+
+
+
+ dbid
+ oid
+ pg_database.oid
+ The OID of the database the dependent object is in
+
+
+
+ classid
+ oid
+ pg_class.oid
+ The OID of the system catalog the dependent object is in
+
+
+
+ objid
+ oid
+ any OID column
+ The OID of the specific dependent object
+
+
+
+ refclassid
+ oid
+ pg_class.oid
+ The OID of the system catalog the referenced object is in
+
+
+
+ refobjid
+ oid
+ any OID column
+ The OID of the specific referenced object
+
+
+
+
+
+
+
+
pg_statistic
Index: src/backend/catalog/Makefile
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.53
diff -c -r1.53 Makefile
*** src/backend/catalog/Makefile 21 Jul 2004 20:34:45 -0000 1.53
--- src/backend/catalog/Makefile 29 Oct 2004 20:18:04 -0000
***************
*** 11,17 ****
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
BKIFILES = postgres.bki postgres.description
--- 11,17 ----
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_shdepend.o \
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_type.o
BKIFILES = postgres.bki postgres.description
***************
*** 32,38 ****
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
! pg_tablespace.h pg_depend.h indexing.h \
)
pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
--- 32,38 ----
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
! pg_tablespace.h pg_depend.h pg_shdepend.h indexing.h \
)
pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
Index: src/backend/catalog/dependency.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/dependency.c,v
retrieving revision 1.40
diff -c -r1.40 dependency.c
*** src/backend/catalog/dependency.c 12 Oct 2004 21:54:36 -0000 1.40
--- src/backend/catalog/dependency.c 30 Oct 2004 19:42:41 -0000
***************
*** 32,40 ****
--- 32,42 ----
#include "catalog/pg_rewrite.h"
#include "catalog/pg_trigger.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"
***************
*** 496,501 ****
--- 498,504 ----
break;
}
+ /* delete the pg_depend tuple */
simple_heap_delete(depRel, &tup->t_self);
}
***************
*** 572,577 ****
--- 575,588 ----
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.
*/
***************
*** 1305,1313 ****
--- 1316,1327 ----
static void
init_object_classes(void)
{
+ object_classes[OCLASS_AM] = get_system_catalog_relid(AccessMethodRelationName);
object_classes[OCLASS_CLASS] = RelOid_pg_class;
object_classes[OCLASS_PROC] = RelOid_pg_proc;
object_classes[OCLASS_TYPE] = RelOid_pg_type;
+ object_classes[OCLASS_DATABASE] = RelOid_pg_database;
+ object_classes[OCLASS_SHADOW] = RelOid_pg_shadow;
object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
object_classes[OCLASS_CONSTRAINT] = get_system_catalog_relid(ConstraintRelationName);
object_classes[OCLASS_CONVERSION] = get_system_catalog_relid(ConversionRelationName);
***************
*** 1318,1323 ****
--- 1332,1338 ----
object_classes[OCLASS_REWRITE] = get_system_catalog_relid(RewriteRelationName);
object_classes[OCLASS_TRIGGER] = get_system_catalog_relid(TriggerRelationName);
object_classes[OCLASS_SCHEMA] = get_system_catalog_relid(NamespaceRelationName);
+ object_classes[OCLASS_TBLSPACE] = RelOid_pg_tablespace;
object_classes_initialized = true;
}
***************
*** 1344,1349 ****
--- 1359,1376 ----
case RelOid_pg_type:
Assert(object->objectSubId == 0);
return OCLASS_TYPE;
+
+ case RelOid_pg_database:
+ Assert(object->objectSubId == 0);
+ return OCLASS_DATABASE;
+
+ case RelOid_pg_tablespace:
+ Assert(object->objectSubId == 0);
+ return OCLASS_TBLSPACE;
+
+ case RelOid_pg_shadow:
+ Assert(object->objectSubId == 0);
+ return OCLASS_SHADOW;
}
/*
***************
*** 1352,1357 ****
--- 1379,1389 ----
if (!object_classes_initialized)
init_object_classes();
+ if (object->classId == object_classes[OCLASS_AM])
+ {
+ Assert(object->objectSubId == 0);
+ return OCLASS_AM;
+ }
if (object->classId == object_classes[OCLASS_CAST])
{
Assert(object->objectSubId == 0);
***************
*** 1439,1444 ****
--- 1471,1510 ----
format_type_be(object->objectId));
break;
+ case OCLASS_AM:
+ {
+ Relation amDesc;
+ ScanKeyData skey[1];
+ SysScanDesc rcscan;
+ HeapTuple tup;
+ Form_pg_am amForm;
+
+ amDesc = heap_openr(AccessMethodRelationName, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ rcscan = systable_beginscan(amDesc, AmOidIndex, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(rcscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for access method %u",
+ object->objectId);
+
+ amForm = (Form_pg_am) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, gettext("access method %s"),
+ amForm->amname.data);
+
+ systable_endscan(rcscan);
+ heap_close(amDesc, AccessShareLock);
+ break;
+ }
+
case OCLASS_CAST:
{
Relation castDesc;
***************
*** 1715,1720 ****
--- 1781,1817 ----
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, gettext("tablespace %s"), tblspace);
+ 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, gettext("database %s"), datname);
+ break;
+ }
+
+ case OCLASS_SHADOW:
+ {
+ appendStringInfo(&buffer, gettext("user %s"),
+ GetUserNameFromId((AclId)object->objectId));
+ break;
+ }
+
default:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,
Index: src/backend/catalog/heap.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/heap.c,v
retrieving revision 1.276
diff -c -r1.276 heap.c
*** src/backend/catalog/heap.c 31 Aug 2004 17:10:36 -0000 1.276
--- src/backend/catalog/heap.c 30 Oct 2004 15:18:24 -0000
***************
*** 332,338 ****
/* ----------------------------------------------------------------
* heap_create_with_catalog - Create a cataloged relation
*
! * this is done in 6 steps:
*
* 1) CheckAttributeNamesTypes() is used to make certain the tuple
* descriptor contains a valid set of attribute names and types
--- 332,338 ----
/* ----------------------------------------------------------------
* heap_create_with_catalog - Create a cataloged relation
*
! * this is done in 8 steps:
*
* 1) CheckAttributeNamesTypes() is used to make certain the tuple
* descriptor contains a valid set of attribute names and types
***************
*** 804,809 ****
--- 804,811 ----
* 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 dependency links to its owner and tablespace, as needed.
*/
if (!IsBootstrapProcessingMode())
{
***************
*** 813,822 ****
--- 815,841 ----
myself.classId = RelOid_pg_class;
myself.objectId = new_rel_oid;
myself.objectSubId = 0;
+
+ /* the relation depends on its namespace */
referenced.classId = get_system_catalog_relid(NamespaceRelationName);
referenced.objectId = relnamespace;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ /* the relation depends on its tablespace, if specified */
+ if (reltablespace != 0)
+ {
+ referenced.classId = get_system_catalog_relid(TableSpaceRelationName);
+ referenced.objectId = reltablespace;
+ referenced.objectSubId = 0;
+ recordSharedDependencyOn(&myself, &referenced);
+ }
+
+ /* the relation depends on its owner */
+ referenced.classId = get_system_catalog_relid(ShadowRelationName);
+ referenced.objectId = GetUserId();
+ referenced.objectSubId = 0;
+ recordSharedDependencyOn(&myself, &referenced);
}
/*
Index: src/backend/catalog/pg_conversion.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_conversion.c,v
retrieving revision 1.19
diff -c -r1.19 pg_conversion.c
*** src/backend/catalog/pg_conversion.c 29 Aug 2004 04:12:28 -0000 1.19
--- src/backend/catalog/pg_conversion.c 30 Oct 2004 15:18:49 -0000
***************
*** 121,126 ****
--- 121,132 ----
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ /* record shared dependency on owner */
+ referenced.classId = get_system_catalog_relid(ShadowRelationName);
+ referenced.objectId = conowner;
+ referenced.objectSubId = 0;
+ recordSharedDependencyOn(&myself, &referenced);
+
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
Index: src/backend/catalog/pg_operator.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_operator.c,v
retrieving revision 1.86
diff -c -r1.86 pg_operator.c
*** src/backend/catalog/pg_operator.c 29 Aug 2004 04:12:29 -0000 1.86
--- src/backend/catalog/pg_operator.c 30 Oct 2004 15:19:29 -0000
***************
*** 891,896 ****
--- 891,897 ----
/* 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))
***************
*** 964,967 ****
--- 965,974 ----
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
+
+ /* Dependency on owner */
+ referenced.classId = get_system_catalog_relid(ShadowRelationName);
+ referenced.objectId = oper->oprowner;
+ referenced.objectSubId = 0;
+ recordSharedDependencyOn(&myself, &referenced);
}
Index: src/backend/catalog/pg_proc.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_proc.c,v
retrieving revision 1.121
diff -c -r1.121 pg_proc.c
*** src/backend/catalog/pg_proc.c 18 Oct 2004 01:45:38 -0000 1.121
--- src/backend/catalog/pg_proc.c 30 Oct 2004 04:01:36 -0000
***************
*** 295,300 ****
--- 295,303 ----
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
+ /* dependency on owner */
+ recordDependencyOnCurrentUser(&myself);
+
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
Index: src/backend/catalog/pg_type.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_type.c,v
retrieving revision 1.96
diff -c -r1.96 pg_type.c
*** src/backend/catalog/pg_type.c 29 Aug 2004 05:06:41 -0000 1.96
--- src/backend/catalog/pg_type.c 30 Oct 2004 04:01:46 -0000
***************
*** 8,14 ****
*
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.96 2004/08/29 05:06:41 momjian Exp $
*
*-------------------------------------------------------------------------
*/
--- 8,14 ----
*
*
* IDENTIFICATION
! * $PostgreSQL: pgsql-server/src/backend/catalog/pg_type.c,v 1.95 2004/08/29 04:12:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
***************
*** 488,493 ****
--- 488,496 ----
/* Normal dependency on the default expression. */
if (defaultExpr)
recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+
+ /* Shared dependency on owner. */
+ recordDependencyOnCurrentUser(&myself);
}
/*
Index: src/backend/commands/conversioncmds.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/conversioncmds.c,v
retrieving revision 1.15
diff -c -r1.15 conversioncmds.c
*** src/backend/commands/conversioncmds.c 29 Aug 2004 05:06:41 -0000 1.15
--- src/backend/commands/conversioncmds.c 30 Oct 2004 15:21:47 -0000
***************
*** 18,23 ****
--- 18,24 ----
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
+ #include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
***************
*** 221,226 ****
--- 222,231 ----
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
+ /* Update shared dependency reference */
+ shdependChangeOwner(get_system_catalog_relid(ConversionRelationName),
+ conversionOid,
+ newOwnerSysId);
}
heap_close(rel, NoLock);
Index: src/backend/commands/dbcommands.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.145
diff -c -r1.145 dbcommands.c
*** src/backend/commands/dbcommands.c 17 Oct 2004 20:47:20 -0000 1.145
--- src/backend/commands/dbcommands.c 30 Oct 2004 13:43:37 -0000
***************
*** 23,28 ****
--- 23,29 ----
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/catalog.h"
+ #include "catalog/dependency.h"
#include "catalog/pg_database.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_tablespace.h"
***************
*** 342,347 ****
--- 343,349 ----
/*
* Iterate through all tablespaces of the template database, and copy
* each one to the new database.
+ * XXX maybe it could be done better using pg_shdepend info.
*/
rel = heap_openr(TableSpaceRelationName, AccessShareLock);
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
***************
*** 498,503 ****
--- 500,508 ----
/* Close pg_database, but keep lock till commit */
heap_close(pg_database_rel, NoLock);
+
+ /* Create pg_shdepend entries */
+ copyTemplateDependencies(src_dboid, dboid, datdba, dst_deftablespace);
/*
* Force dirty buffers out to disk, so that newly-connecting backends
***************
*** 630,635 ****
--- 635,645 ----
remove_dbtablespaces(db_id);
/*
+ * Remove shared dependency references in the database.
+ */
+ dropDatabaseDependencies(db_id);
+
+ /*
* Force dirty buffers out to disk, so that newly-connecting backends
* will see the database tuple marked dead in pg_database right away.
* (They'll see an uncommitted deletion, but they don't care; see
***************
*** 892,897 ****
--- 902,914 ----
CatalogUpdateIndexes(rel, newtuple);
heap_freetuple(newtuple);
+
+ /*
+ * Update shared dependency references
+ */
+ shdependChangeOwner(RelOid_pg_database,
+ HeapTupleGetOid(tuple),
+ newOwnerSysId);
}
systable_endscan(scan);
Index: src/backend/commands/functioncmds.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/functioncmds.c,v
retrieving revision 1.52
diff -c -r1.52 functioncmds.c
*** src/backend/commands/functioncmds.c 29 Aug 2004 05:06:41 -0000 1.52
--- src/backend/commands/functioncmds.c 30 Oct 2004 14:32:21 -0000
***************
*** 798,803 ****
--- 798,808 ----
simple_heap_update(rel, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(rel, newtuple);
+ /* update shared dependency reference */
+ shdependChangeOwner(get_system_catalog_relid(ProcedureRelationName),
+ procOid,
+ newOwnerSysId);
+
heap_freetuple(newtuple);
}
Index: src/backend/commands/opclasscmds.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/opclasscmds.c,v
retrieving revision 1.28
diff -c -r1.28 opclasscmds.c
*** src/backend/commands/opclasscmds.c 29 Aug 2004 05:06:41 -0000 1.28
--- src/backend/commands/opclasscmds.c 30 Oct 2004 15:22:27 -0000
***************
*** 392,397 ****
--- 392,400 ----
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
+ /* dependency on owner */
+ recordDependencyOnCurrentUser(&myself);
+
heap_close(rel, RowExclusiveLock);
}
***************
*** 964,969 ****
--- 967,977 ----
CatalogUpdateIndexes(rel, tup);
}
+ /* Update shared dependency reference */
+ shdependChangeOwner(get_system_catalog_relid(OperatorClassRelationName),
+ amOid,
+ newOwnerSysId);
+
heap_close(rel, NoLock);
heap_freetuple(tup);
}
Index: src/backend/commands/operatorcmds.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/operatorcmds.c,v
retrieving revision 1.19
diff -c -r1.19 operatorcmds.c
*** src/backend/commands/operatorcmds.c 29 Aug 2004 05:06:41 -0000 1.19
--- src/backend/commands/operatorcmds.c 30 Oct 2004 14:33:34 -0000
***************
*** 311,316 ****
--- 311,323 ----
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
+
+ /*
+ * Update shared dependency references.
+ */
+ shdependChangeOwner(get_system_catalog_relid(OperatorRelationName),
+ operOid,
+ newOwnerSysId);
}
heap_close(rel, NoLock);
Index: src/backend/commands/schemacmds.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/schemacmds.c,v
retrieving revision 1.25
diff -c -r1.25 schemacmds.c
*** src/backend/commands/schemacmds.c 2 Sep 2004 00:22:16 -0000 1.25
--- src/backend/commands/schemacmds.c 30 Oct 2004 15:23:11 -0000
***************
*** 176,181 ****
--- 176,205 ----
}
}
+ /* Record global dependencies */
+ {
+ ObjectAddress myself;
+
+ myself.classId = get_system_catalog_relid(NamespaceRelationName);
+ myself.objectId = namespaceId;
+ myself.objectSubId = 0;
+
+ /* Dependency on owner */
+ recordDependencyOnCurrentUser(&myself);
+
+ /* Dependency on tablespace, if any */
+ if (OidIsValid(tablespaceId))
+ {
+ ObjectAddress referenced;
+
+ referenced.classId = RelOid_pg_tablespace;
+ referenced.objectId = tablespaceId;
+ referenced.objectSubId = 0;
+
+ recordSharedDependencyOn(&myself, &referenced);
+ }
+ }
+
/* Reset search path to normal state */
PopSpecialNamespace(namespaceId);
***************
*** 374,379 ****
--- 398,410 ----
CatalogUpdateIndexes(rel, newtuple);
heap_freetuple(newtuple);
+
+ /*
+ * Update shared dependency references.
+ */
+ shdependChangeOwner(get_system_catalog_relid(NamespaceRelationName),
+ HeapTupleGetOid(tup),
+ newOwnerSysId);
}
ReleaseSysCache(tup);
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.137
diff -c -r1.137 tablecmds.c
*** src/backend/commands/tablecmds.c 22 Oct 2004 17:20:04 -0000 1.137
--- src/backend/commands/tablecmds.c 30 Oct 2004 15:24:01 -0000
***************
*** 5228,5233 ****
--- 5228,5238 ----
heap_freetuple(newtuple);
/*
+ * Update shared dependency reference.
+ */
+ shdependChangeOwner(RelOid_pg_class, relationOid, newOwnerSysId);
+
+ /*
* If we are operating on a table, also change the ownership of
* any indexes and sequences that belong to the table, as well as
* the table's toast table (if it has one)
***************
*** 5411,5416 ****
--- 5416,5424 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespacename);
+ /* Update shared dependency reference */
+ shdependChangeTablespace(RelOid_pg_class, tab->relid, tablespaceId);
+
/* Save info for Phase 3 to do the real work */
if (OidIsValid(tab->newTableSpace))
ereport(ERROR,
Index: src/backend/commands/tablespace.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/tablespace.c,v
retrieving revision 1.12
diff -c -r1.12 tablespace.c
*** src/backend/commands/tablespace.c 17 Oct 2004 20:47:20 -0000 1.12
--- src/backend/commands/tablespace.c 30 Oct 2004 13:36:50 -0000
***************
*** 59,64 ****
--- 59,65 ----
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
+ #include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_tablespace.h"
***************
*** 167,172 ****
--- 168,191 ----
errmsg("could not create directory \"%s\": %m",
dir)));
}
+ /*
+ * Record a shared dependency link from database to
+ * tablespace.
+ */
+ {
+ ObjectAddress myself,
+ referenced;
+
+ myself.classId = RelOid_pg_database;
+ myself.objectId = dbNode;
+ myself.objectSubId = 0;
+
+ referenced.classId = RelOid_pg_tablespace;
+ referenced.objectId = spcNode;
+ referenced.objectSubId = 0;
+
+ recordSharedDependencyOn(&myself, &referenced);
+ }
}
/* OK to drop the exclusive lock */
***************
*** 343,348 ****
--- 362,381 ----
set_short_version(location);
/*
+ * Record dependency link from tablespace to owner.
+ * XXX maybe this should be done after the symlink is created?
+ */
+ {
+ ObjectAddress myself;
+
+ myself.classId = RelOid_pg_tablespace;
+ myself.objectId = tablespaceoid;
+ myself.objectSubId = 0;
+
+ recordDependencyOnCurrentUser(&myself);
+ }
+
+ /*
* All seems well, create the symlink
*/
linkloc = (char *) palloc(strlen(DataDir) + 11 + 10 + 1);
***************
*** 442,447 ****
--- 475,493 ----
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
tablespacename);
+ /* Verify pg_shdepend entries mentioning this tablespace. */
+ if (checkSharedDependencies(RelOid_pg_tablespace, tablespaceoid) > 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("tablespace \"%s\" is not empty",
+ tablespacename)));
+
+ /* Remove shared dependency references to this tablespace */
+ deleteGlobalDependencyRecordsFor(RelOid_pg_tablespace, tablespaceoid);
+
+ /* Remove shared references from this tablespace to its owner */
+ deleteSharedDependencyRecordsFor(RelOid_pg_tablespace, tablespaceoid);
+
/*
* Remove the pg_tablespace tuple (this will roll back if we fail
* below)
***************
*** 939,944 ****
--- 985,995 ----
simple_heap_update(rel, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(rel, newtuple);
+ /* Update shared dependency reference. */
+ shdependChangeOwner(RelOid_pg_tablespace,
+ HeapTupleGetOid(tup),
+ newOwnerSysId);
+
heap_freetuple(newtuple);
}
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.64
diff -c -r1.64 typecmds.c
*** src/backend/commands/typecmds.c 7 Oct 2004 15:21:52 -0000 1.64
--- src/backend/commands/typecmds.c 30 Oct 2004 03:24:21 -0000
***************
*** 2111,2116 ****
--- 2111,2120 ----
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
+
+ shdependChangeOwner(get_system_catalog_relid(TypeRelationName),
+ typeOid,
+ newOwnerSysId);
}
/* Clean up */
Index: src/backend/commands/user.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/user.c,v
retrieving revision 1.146
diff -c -r1.146 user.c
*** src/backend/commands/user.c 27 Sep 2004 04:01:23 -0000 1.146
--- src/backend/commands/user.c 30 Oct 2004 03:41:15 -0000
***************
*** 19,24 ****
--- 19,25 ----
#include "access/heapam.h"
#include "catalog/catname.h"
+ #include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_database.h"
#include "catalog/pg_group.h"
***************
*** 1091,1097 ****
tmp_tuple;
Relation pg_rel;
TupleDesc pg_dsc;
- ScanKeyData scankey;
HeapScanDesc scan;
AclId usesysid;
--- 1092,1097 ----
***************
*** 1114,1156 ****
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("session user cannot be dropped")));
! /*
! * Check if user 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_openr(DatabaseRelationName, AccessShareLock);
! pg_dsc = RelationGetDescr(pg_rel);
!
! ScanKeyInit(&scankey,
! Anum_pg_database_datdba,
! BTEqualStrategyNumber, F_INT4EQ,
! Int32GetDatum(usesysid));
!
! 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);
ereport(ERROR,
! (errcode(ERRCODE_OBJECT_IN_USE),
! errmsg("user \"%s\" cannot be dropped", user),
! errdetail("The user 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
! * user as well, but those could be spread out over all sorts of
! * databases which we don't have access to (easily).
! */
/*
* Remove the user from the pg_shadow table
--- 1114,1127 ----
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("session user cannot be dropped")));
! /* Verify pg_shdepend entries mentioning this user. */
! if (checkSharedDependencies(RelOid_pg_shadow, usesysid) > 0)
ereport(ERROR,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("user cannot be dropped, owns objects")));
! /* Remove shared dependency references to this user */
! deleteGlobalDependencyRecordsFor(RelOid_pg_shadow, usesysid);
/*
* Remove the user from the pg_shadow table
Index: src/bin/initdb/initdb.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/bin/initdb/initdb.c,v
retrieving revision 1.65
diff -c -r1.65 initdb.c
*** src/bin/initdb/initdb.c 24 Oct 2004 15:55:29 -0000 1.65
--- src/bin/initdb/initdb.c 30 Oct 2004 15:24:50 -0000
***************
*** 171,176 ****
--- 171,177 ----
static void get_set_pwd(void);
static void unlimit_systables(void);
static void setup_depend(void);
+ static void setup_shared_depend(void);
static void setup_sysviews(void);
static void setup_description(void);
static void setup_conversion(void);
***************
*** 1503,1508 ****
--- 1504,1602 ----
check_ok();
}
+ static void
+ setup_shared_depend(void)
+ {
+ char *pg_shdepend_setup[] = {
+ /*
+ * Fill pg_shdepend with info about all existant objects.
+ * We need to take the ownership and tablespace into consideration.
+ *
+ * Note that we first clear the table to rid of dependencies recorded
+ * by normal operation, because it's incomplete.
+ */
+ "DELETE FROM pg_shdepend\n",
+
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_type'::regclass, oid, 'pg_shadow'::regclass, typowner"
+ " FROM pg_type t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_proc'::regclass, oid, 'pg_shadow'::regclass, proowner"
+ " FROM pg_proc t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_class'::regclass, oid, 'pg_shadow'::regclass, relowner"
+ " FROM pg_class t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_tablespace'::regclass, oid, 'pg_shadow'::regclass, spcowner"
+ " FROM pg_tablespace t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_operator'::regclass, oid, 'pg_shadow'::regclass, oprowner"
+ " FROM pg_operator t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_opclass'::regclass, oid, 'pg_shadow'::regclass, opcowner"
+ " FROM pg_opclass t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_am'::regclass, oid, 'pg_shadow'::regclass, amowner"
+ " FROM pg_am t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_namespace'::regclass, oid, 'pg_shadow'::regclass, nspowner"
+ " FROM pg_namespace t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_conversion'::regclass, oid, 'pg_shadow'::regclass, conowner"
+ " FROM pg_conversion t\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_database'::regclass, oid, 'pg_shadow'::regclass, datdba"
+ " FROM pg_database t\n",
+
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_database'::regclass, oid, 'pg_tablespace'::regclass, dattablespace"
+ " FROM pg_database t"
+ " WHERE dattablespace <> 0\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_class'::regclass, oid, 'pg_tablespace'::regclass, reltablespace"
+ " FROM pg_class t"
+ " WHERE reltablespace <> 0\n",
+ "INSERT INTO pg_shdepend SELECT"
+ " (SELECT oid FROM pg_database WHERE datname=current_database()),"
+ " 'pg_namespace'::regclass, oid, 'pg_tablespace'::regclass, nsptablespace"
+ " FROM pg_namespace t"
+ " WHERE nsptablespace <> 0\n",
+ NULL
+ };
+
+ PG_CMD_DECL;
+
+ fputs(_("initializing pg_shdepend ... "), stdout);
+ fflush(stdout);
+
+ snprintf(cmd, sizeof(cmd),
+ "\"%s\" %s template1 >%s",
+ backend_exec, backend_options,
+ DEVNULL);
+
+ PG_CMD_OPEN;
+
+ for (line = pg_shdepend_setup; *line != NULL; line++)
+ PG_CMD_PUTLINE;
+
+ PG_CMD_CLOSE;
+
+ check_ok();
+ }
+
+
/*
* set up system views
*/
***************
*** 2548,2553 ****
--- 2642,2649 ----
setup_depend();
+ setup_shared_depend();
+
setup_sysviews();
setup_description();
Index: src/include/catalog/catname.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/catname.h,v
retrieving revision 1.33
diff -c -r1.33 catname.h
*** src/include/catalog/catname.h 29 Aug 2004 04:13:04 -0000 1.33
--- src/include/catalog/catname.h 29 Oct 2004 19:48:50 -0000
***************
*** 25,30 ****
--- 25,31 ----
#define ConversionRelationName "pg_conversion"
#define DatabaseRelationName "pg_database"
#define DependRelationName "pg_depend"
+ #define SharedDependRelationName "pg_shdepend"
#define DescriptionRelationName "pg_description"
#define GroupRelationName "pg_group"
#define IndexRelationName "pg_index"
Index: src/include/catalog/dependency.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/dependency.h,v
retrieving revision 1.13
diff -c -r1.13 dependency.h
*** src/include/catalog/dependency.h 29 Aug 2004 04:13:04 -0000 1.13
--- src/include/catalog/dependency.h 30 Oct 2004 19:43:47 -0000
***************
*** 81,90 ****
/*
! * This enum covers all system catalogs whose OIDs can appear in classId.
*/
typedef enum ObjectClass
{
OCLASS_CLASS, /* pg_class */
OCLASS_PROC, /* pg_proc */
OCLASS_TYPE, /* pg_type */
--- 81,92 ----
/*
! * This enum covers all system catalogs whose OIDs can appear in
! * pg_depend.classId or pg_shdepend.classId.
*/
typedef enum ObjectClass
{
+ OCLASS_AM, /* pg_am */
OCLASS_CLASS, /* pg_class */
OCLASS_PROC, /* pg_proc */
OCLASS_TYPE, /* pg_type */
***************
*** 98,103 ****
--- 100,109 ----
OCLASS_REWRITE, /* pg_rewrite */
OCLASS_TRIGGER, /* pg_trigger */
OCLASS_SCHEMA, /* pg_namespace */
+ /* shared system catalogs: */
+ OCLASS_TBLSPACE, /* pg_tablespace */
+ OCLASS_DATABASE, /* pg_database */
+ OCLASS_SHADOW, /* pg_shadow */
MAX_OCLASS /* MUST BE LAST */
} ObjectClass;
***************
*** 123,128 ****
--- 129,137 ----
extern char *getObjectDescription(const ObjectAddress *object);
+ extern void copyTemplateDependencies(Oid templateDbId, Oid newDbId,
+ AclId datdba, Oid tblspcId);
+
/* in pg_depend.c */
extern void recordDependencyOn(const ObjectAddress *depender,
***************
*** 136,139 ****
--- 145,169 ----
extern long deleteDependencyRecordsFor(Oid classId, Oid objectId);
+ /* in pg_shdepend.c */
+
+ extern void recordSharedDependencyOn(const ObjectAddress *depender,
+ const ObjectAddress *referenced);
+
+ extern void recordDependencyOnCurrentUser(const ObjectAddress *depender);
+
+ extern void shdependChangeOwner(Oid classId, Oid objectId,
+ int newOwnerSysId);
+
+ extern void shdependChangeTablespace(Oid classId, Oid objectId,
+ Oid newTblspc);
+
+ extern int checkSharedDependencies(Oid classId, Oid objectId);
+
+ extern void dropDatabaseDependencies(Oid databaseId);
+
+ extern void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId);
+
+ extern void deleteGlobalDependencyRecordsFor(Oid classId, Oid objectId);
+
#endif /* DEPENDENCY_H */
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/indexing.h,v
retrieving revision 1.83
diff -c -r1.83 indexing.h
*** src/include/catalog/indexing.h 29 Aug 2004 04:13:05 -0000 1.83
--- src/include/catalog/indexing.h 29 Oct 2004 19:49:05 -0000
***************
*** 67,72 ****
--- 67,74 ----
#define ProcedureOidIndex "pg_proc_oid_index"
#define RewriteOidIndex "pg_rewrite_oid_index"
#define RewriteRelRulenameIndex "pg_rewrite_rel_rulename_index"
+ #define SharedDependDependerIndex "pg_shdepend_depender_index"
+ #define SharedDependReferenceIndex "pg_shdepend_reference_index"
#define ShadowNameIndex "pg_shadow_usename_index"
#define ShadowSysidIndex "pg_shadow_usesysid_index"
#define StatisticRelidAttnumIndex "pg_statistic_relid_att_index"
***************
*** 165,170 ****
--- 167,176 ----
/* This following index is not used for a cache and is not unique */
DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index on pg_rewrite using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index on pg_rewrite using btree(ev_class oid_ops, rulename name_ops));
+ /* This following index is not used for a cache and is not unique */
+ DECLARE_INDEX(pg_shdepend_depender_index on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops));
+ /* This following index is not used for a cache and is not unique */
+ DECLARE_INDEX(pg_shdepend_reference_index on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops));
DECLARE_UNIQUE_INDEX(pg_shadow_usename_index on pg_shadow using btree(usename name_ops));
DECLARE_UNIQUE_INDEX(pg_shadow_usesysid_index on pg_shadow using btree(usesysid int4_ops));
DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index on pg_statistic using btree(starelid oid_ops, staattnum int2_ops));