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 ----
       </row>
  
       <row>
+       <entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link</entry>
+       <entry>cross-database dependencies between objects</entry>
+      </row>
+      <row>
        <entry><link linkend="catalog-pg-statistic"><structname>pg_statistic</structname></link></entry>
        <entry>planner statistics</entry>
       </row>
***************
*** 3104,3109 ****
--- 3108,3183 ----
   </sect1>
  
  
+  <sect1 id="catalog-pg-shdepend">
+   <title><structname>pg_shdepend</structname></title>
+ 
+   <indexterm zone="catalog-pg-shdepend">
+    <primary>pg_shdepend</primary>
+   </indexterm>
+ 
+   <para>
+    The shared catalog <structname>pg_shdepend</structname> records the
+    dependency relationships between database objects and global objects,
+    such as users and tablespaces.  This information allows <command>DROP
+    USER</command> and <command>DROP TABLESPACE</command> to ensure that
+    those objects are unreferenced before attempting to delete them.
+   </para>
+ 
+   <table>
+    <title><structname>pg_depend</> 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</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</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>
+ 
+     </tbody>
+    </tgroup>
+   </table>
+  </sect1>
+ 
+ 
   <sect1 id="catalog-pg-statistic">
    <title><structname>pg_statistic</structname></title>
  
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));
