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_statistic planner statistics *************** *** 3104,3109 **** --- 3108,3183 ---- + + <structname>pg_shdepend</structname> + + + 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. + + + + <structname>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 + + + + +
+
+ + <structname>pg_statistic</structname> 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));