Hackers,

Here is the current shared dependency patch I promised.  (The new files
are src/include/catalog/pg_shdepend.h and
src/backend/catalog/pg_shdepend.c).

The big problem with the current patch is this:

-- session 1
BEGIN;
DROP USER foo;
-- checks dependencies, all is OK
                                -- session 2
                                ALTER TABLE foo OWNER TO foo;
COMMIT;

Everything works, a dependency on user foo is recorded, but now it's
useless (it will be never checked).

Of course, there needs to be a lock to protect this from happening.  But
I'm not sure what should be locked.  The whole pg_shadow relation?  That
might be overkill.

I was trying to find out if I could lock the user (and have the ALTER
TABLE get a shared lock on the user before checking its existance, and
the DROP USER get an exclusive lock which would be release at
transaction end.  So everything would remain consistant.)  However the
LOCKTAG does not have provisions to lock arbitrary objects, only
relations (I could end up locking some completely unrelated table, I
guess).

Any ideas on how to handle this?

-- 
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"Aprende a avergonzarte más ante ti que ante los demás" (Demócrito)
Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.94
diff -c -r2.94 catalogs.sgml
*** doc/src/sgml/catalogs.sgml  13 Dec 2004 18:05:07 -0000      2.94
--- doc/src/sgml/catalogs.sgml  13 Dec 2004 20:15:32 -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>
***************
*** 3095,3100 ****
--- 3099,3174 ----
   </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        10 Dec 2004 14:21:47 -0000
***************
*** 12,18 ****
  
  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
  
--- 12,19 ----
  
  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_shdepend.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)
--- 33,39 ----
        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/catalog.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/catalog.c,v
retrieving revision 1.56
diff -c -r1.56 catalog.c
*** src/backend/catalog/catalog.c       29 Aug 2004 04:12:26 -0000      1.56
--- src/backend/catalog/catalog.c       10 Dec 2004 20:48:52 -0000
***************
*** 9,15 ****
   *
   *
   * IDENTIFICATION
!  *      $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.56 2004/08/29 
04:12:26 momjian Exp $
   *
   *-------------------------------------------------------------------------
   */
--- 9,15 ----
   *
   *
   * IDENTIFICATION
!  *      $PostgreSQL: pgsql-server/src/backend/catalog/catalog.c,v 1.55 
2004/08/04 21:33:47 tgl Exp $
   *
   *-------------------------------------------------------------------------
   */
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    10 Dec 2004 14:32:52 -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.277
diff -c -r1.277 heap.c
*** src/backend/catalog/heap.c  1 Dec 2004 19:00:39 -0000       1.277
--- src/backend/catalog/heap.c  10 Dec 2004 14:33:13 -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
***************
*** 789,794 ****
--- 789,796 ----
         * 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())
        {
***************
*** 798,807 ****
--- 800,826 ----
                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       8 Dec 2004 05:44:26 -0000
***************
*** 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.147
diff -c -r1.147 dbcommands.c
*** src/backend/commands/dbcommands.c   18 Nov 2004 01:14:26 -0000      1.147
--- src/backend/commands/dbcommands.c   10 Dec 2004 03:58:29 -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"
***************
*** 343,348 ****
--- 344,350 ----
        /*
         * 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);
***************
*** 497,502 ****
--- 499,526 ----
        /* Update indexes */
        CatalogUpdateIndexes(pg_database_rel, tuple);
  
+       /* Create pg_shdepend entries */
+       copyTemplateDependencies(src_dboid, dboid);
+       /* Register tablespace and owner dependencies */
+       {
+               ObjectAddress myself,
+                                         referenced;
+ 
+               myself.classId = RelOid_pg_database;
+               myself.objectId = dboid;
+               myself.objectSubId = 0;
+ 
+               referenced.classId = RelOid_pg_shadow;
+               referenced.objectId = datdba;
+               referenced.objectSubId = 0;
+               recordSharedDependencyOn(&myself, &referenced);
+ 
+               referenced.classId = RelOid_pg_tablespace;
+               referenced.objectId = dst_deftablespace;
+               referenced.objectSubId = 0;
+               recordSharedDependencyOn(&myself, &referenced);
+       }
+ 
        /*
         * Force dirty buffers out to disk, so that newly-connecting backends
         * will see the new database in pg_database right away.  (They'll see
***************
*** 633,638 ****
--- 657,667 ----
        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
***************
*** 917,922 ****
--- 946,958 ----
  
                heap_freetuple(newtuple);
  
+               /*
+                * Update shared dependency references
+                */
+               shdependChangeOwner(RelOid_pg_database,
+                                                       HeapTupleGetOid(tuple),
+                                                       newOwnerSysId);
+ 
                /* must release buffer pins before FlushRelationBuffers */
                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.26
diff -c -r1.26 schemacmds.c
*** src/backend/commands/schemacmds.c   5 Nov 2004 19:15:57 -0000       1.26
--- src/backend/commands/schemacmds.c   6 Nov 2004 18:08:35 -0000
***************
*** 47,52 ****
--- 47,53 ----
        AclId           owner_userid;
        AclId           saved_userid;
        AclResult       aclresult;
+       ObjectAddress myself;
  
        saved_userid = GetUserId();
  
***************
*** 147,152 ****
--- 148,160 ----
                }
        }
  
+       /* Record dependency on owner*/
+       myself.classId = get_system_catalog_relid(NamespaceRelationName);
+       myself.objectId = namespaceId;
+       myself.objectSubId = 0;
+ 
+       recordDependencyOnCurrentUser(&myself);
+ 
        /* Reset search path to normal state */
        PopSpecialNamespace(namespaceId);
  
***************
*** 345,350 ****
--- 353,365 ----
                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.140
diff -c -r1.140 tablecmds.c
*** src/backend/commands/tablecmds.c    16 Nov 2004 23:34:22 -0000      1.140
--- src/backend/commands/tablecmds.c    2 Dec 2004 22:17:19 -0000
***************
*** 5256,5261 ****
--- 5256,5266 ----
                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)
***************
*** 5439,5444 ****
--- 5444,5452 ----
        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.14
diff -c -r1.14 tablespace.c
*** src/backend/commands/tablespace.c   5 Nov 2004 19:15:57 -0000       1.14
--- src/backend/commands/tablespace.c   9 Dec 2004 05:23:38 -0000
***************
*** 51,56 ****
--- 51,57 ----
  #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"
***************
*** 340,345 ****
--- 341,360 ----
        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);
***************
*** 439,444 ****
--- 454,472 ----
                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_IN_USE),
+                                errmsg("cannot drop tablespace \"%s\"", 
tablespacename),
+                                errdetail("Some objects depend on this 
tablespace.")));
+ 
+       /* 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)
***************
*** 865,870 ****
--- 893,903 ----
                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 8 Dec 2004 04:23:56 -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,1128 ----
                                        (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_IN_USE),
                                         errmsg("user \"%s\" cannot be 
dropped", user),
!                                  errdetail("Some objects depend on this 
user.")));
  
!               /* 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.70
diff -c -r1.70 initdb.c
*** src/bin/initdb/initdb.c     29 Nov 2004 03:05:03 -0000      1.70
--- src/bin/initdb/initdb.c     9 Dec 2004 07:53:10 -0000
***************
*** 173,178 ****
--- 173,179 ----
  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);
***************
*** 1559,1564 ****
--- 1560,1659 ----
        check_ok();
  }
  
+ static void
+ setup_shared_depend(void)
+ {
+       PG_CMD_DECL;
+       char       **line;
+       static 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",
+ 
+               /* Entries for owners of database-local objects */
+               "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_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",
+ 
+               /* Entries for tablespaces of database-local objects */
+               "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",
+ 
+               /* Entries for owners of shared objects */
+               "INSERT INTO pg_shdepend SELECT"
+                       "   0,"
+                       "   'pg_tablespace'::regclass, oid, 
'pg_shadow'::regclass, spcowner"
+                       "   FROM pg_tablespace t\n",
+               "INSERT INTO pg_shdepend SELECT"
+                       "   0,"
+                       "   'pg_database'::regclass, oid, 
'pg_shadow'::regclass, datdba"
+                       "   FROM pg_database t\n",
+               /* Entries for tablespaces of shared objects */
+               "INSERT INTO pg_shdepend SELECT"
+                       "   0,"
+                       "   'pg_database'::regclass, oid, 
'pg_tablespace'::regclass, dattablespace"
+                       "   FROM pg_database t"
+                       "   WHERE dattablespace <> 0\n",
+               NULL
+       };
+ 
+ 
+       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_PUTS(*line);
+ 
+       PG_CMD_CLOSE;
+ 
+       check_ok();
+ }
+ 
+ 
  /*
   * set up system views
   */
***************
*** 2595,2600 ****
--- 2690,2697 ----
  
        setup_depend();
  
+       setup_shared_depend();
+ 
        setup_sysviews();
  
        setup_description();
Index: src/bin/psql/po/es.po
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/bin/psql/po/es.po,v
retrieving revision 1.5
diff -c -r1.5 es.po
*** src/bin/psql/po/es.po       11 Dec 2004 19:03:47 -0000      1.5
--- src/bin/psql/po/es.po       13 Dec 2004 20:17:40 -0000
***************
*** 809,815 ****
  #, c-format
  msgid "  \\dp [PATTERN]  list table, view, and sequence access privileges\n"
  msgstr ""
! "\\dp [PATRÓN]    listar privilegios de acceso a tablas, vistas y 
secuencias\n"
  
  #: help.c:228
  #, c-format
--- 809,815 ----
  #, c-format
  msgid "  \\dp [PATTERN]  list table, view, and sequence access privileges\n"
  msgstr ""
! "  \\dp [PATRÓN]    listar privilegios de acceso a tablas, vistas y 
secuencias\n"
  
  #: help.c:228
  #, c-format
***************
*** 835,841 ****
  msgstr ""
  "  \\z [PATRÓN]     listar privilegios de acceso a tablas, vistas y "
  "secuencias\n"
! "                   (lo mismo que \\dp)\n"
  
  #: help.c:234
  #, c-format
--- 835,841 ----
  msgstr ""
  "  \\z [PATRÓN]     listar privilegios de acceso a tablas, vistas y "
  "secuencias\n"
! "                  (lo mismo que \\dp)\n"
  
  #: help.c:234
  #, c-format
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    10 Dec 2004 03:58:25 -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;
  
***************
*** 136,139 ****
--- 142,168 ----
  
  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 copyTemplateDependencies(Oid templateDbId, Oid newDbId);
+ 
+ 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));
Index: src/include/catalog/pg_tablespace.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/pg_tablespace.h,v
retrieving revision 1.4
diff -c -r1.4 pg_tablespace.h
*** src/include/catalog/pg_tablespace.h 29 Aug 2004 05:06:55 -0000      1.4
--- src/include/catalog/pg_tablespace.h 10 Dec 2004 20:46:27 -0000
***************
*** 8,14 ****
   * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
   *
!  * $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.4 2004/08/29 
05:06:55 momjian Exp $
   *
   * NOTES
   *      the genbki.sh script reads this file and generates .bki
--- 8,14 ----
   * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
   *
!  * $PostgreSQL: pgsql-server/src/include/catalog/pg_tablespace.h,v 1.3 
2004/08/29 04:13:05 momjian Exp $
   *
   * NOTES
   *      the genbki.sh script reads this file and generates .bki
Index: src/test/regress/expected/sanity_check.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/sanity_check.out,v
retrieving revision 1.24
diff -c -r1.24 sanity_check.out
*** src/test/regress/expected/sanity_check.out  18 Jun 2004 06:14:27 -0000      
1.24
--- src/test/regress/expected/sanity_check.out  10 Dec 2004 18:48:36 -0000
***************
*** 55,60 ****
--- 55,61 ----
   pg_proc             | t
   pg_rewrite          | t
   pg_shadow           | t
+  pg_shdepend         | t
   pg_statistic        | t
   pg_tablespace       | t
   pg_trigger          | t
***************
*** 63,69 ****
   shighway            | t
   tenk1               | t
   tenk2               | t
! (53 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
--- 64,70 ----
   shighway            | t
   tenk1               | t
   tenk2               | t
! (54 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
/*-------------------------------------------------------------------------
 *
 * pg_shdepend.c
 *        routines to support manipulation of the pg_shdepend relation
 *
 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *        $PostgreSQL$
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "miscadmin.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup.h"
#include "access/skey.h"
#include "catalog/catname.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_shdepend.h"
#include "storage/proc.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/fmgroids.h"


static Oid classIdGetDbId(Oid classId);

/*
 * Record a dependency between 2 objects via their respective ObjectAddress.
 * The first argument is the dependent object, the second the one it
 * references.
 *
 * This simply creates an entry in pg_shdepend, without any other processing.
 */
void
recordSharedDependencyOn(const ObjectAddress *depender,
                                                   const ObjectAddress 
*referenced)
{
        Relation        shdepRel;
        HeapTuple       tup;
        char            nulls[Natts_pg_shdepend];
        Datum           values[Natts_pg_shdepend];
        int                     i;

        /*
         * Objects in pg_shdepend can't have SubIds.
         *
         * XXX Is this restriction actually useful, besides saving space
         * in pg_shdepend?
         */
        Assert(depender->objectSubId == 0);
        Assert(referenced->objectSubId == 0);

        /*
         * During bootstrap, do nothing since pg_shdepend may not exist yet.
         * initdb will fill in appropriate pg_shdepend entries after bootstrap.
         */
        if (IsBootstrapProcessingMode())
                return;

        shdepRel = heap_openr(SharedDependRelationName, RowExclusiveLock);

        MemSet(nulls, ' ', sizeof(nulls));

        /*
         * Form the new tuple and record the dependency.
         */
        i = 0;
        values[i++] = ObjectIdGetDatum(classIdGetDbId(depender->classId));      
/* dbid */
        values[i++] = ObjectIdGetDatum(depender->classId);              /* 
classid */
        values[i++] = ObjectIdGetDatum(depender->objectId);             /* 
objid */

        values[i++] = ObjectIdGetDatum(referenced->classId);    /* refclassid */
        values[i++] = ObjectIdGetDatum(referenced->objectId);   /* refobjid */

        tup = heap_formtuple(shdepRel->rd_att, values, nulls);
        simple_heap_insert(shdepRel, tup);

        /* keep indexes current */
        CatalogUpdateIndexes(shdepRel, tup);

        /* clean up */
        heap_freetuple(tup);
        heap_close(shdepRel, RowExclusiveLock);
}

/*
 * recordDependencyOnCurrentUser
 *
 * A convenient form of recordSharedDependencyOn().
 */
void
recordDependencyOnCurrentUser(const ObjectAddress *object)
{
        ObjectAddress referenced;

        referenced.classId = get_system_catalog_relid(ShadowRelationName);
        referenced.objectId = GetUserId();
        referenced.objectSubId = 0;

        recordSharedDependencyOn(object, &referenced);
}

/*
 * shdependChangeOwner
 *
 * Update the shared dependencies to account for the new owner.
 */
void
shdependChangeOwner(Oid classId, Oid objectId, int newOwnerSysId)
{
        Relation        sdepRel;
        ScanKeyData     key[3];
        SysScanDesc     scan;
        HeapTuple       tup;

        sdepRel = heap_openr(SharedDependRelationName, RowExclusiveLock);

        ScanKeyInit(&key[0],
                            Anum_pg_shdepend_dbid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classIdGetDbId(classId)));
        ScanKeyInit(&key[1],
                            Anum_pg_shdepend_classid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classId));
        ScanKeyInit(&key[2],
                                Anum_pg_shdepend_objid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(objectId));

        scan = systable_beginscan(sdepRel, SharedDependDependerIndex, true,
                                                          SnapshotNow, 3, key);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
                Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
                HeapTuple       newtup;
                char            repl_nulls[Natts_pg_shdepend];
                char            replace[Natts_pg_shdepend];
                Datum      *values;

                /* Look for tuples referring to pg_shadow */
                if (sdepForm->refclassid != RelOid_pg_shadow)
                        continue;

                /*
                 * Skip a tuple we just inserted.
                 *
                 * XXX Another possibility would be to break out of the loop
                 * as soon as we modify one tuple.  Not sure what is best.
                 */
                if (DatumGetInt32(sdepForm->refobjid) == newOwnerSysId)
                        continue;

                values = (Datum *) palloc0(sizeof(Datum) * Natts_pg_shdepend);

                MemSet(repl_nulls, ' ', Natts_pg_shdepend);
                MemSet(replace, ' ', Natts_pg_shdepend);

                replace[Anum_pg_shdepend_refobjid - 1] = 'r';
                values[Anum_pg_shdepend_refobjid - 1] = 
Int32GetDatum(newOwnerSysId);

                newtup = heap_modifytuple(tup, sdepRel, values, repl_nulls, 
replace);

                simple_heap_update(sdepRel, &tup->t_self, newtup);

                /* Keep indexes current */
                CatalogUpdateIndexes(sdepRel, newtup);

                pfree(values);
                heap_freetuple(newtup);
        }

        systable_endscan(scan);

        heap_close(sdepRel, RowExclusiveLock);
}

/*
 * shdependChangeTablespace
 *
 * Update the shared dependencies to account for the new tablespace.
 */
void
shdependChangeTablespace(Oid classId, Oid objectId, Oid newTblspc)
{
        Relation        sdepRel;
        ScanKeyData     key[3];
        SysScanDesc     scan;
        HeapTuple       tup;
        int                     count = 0;

        sdepRel = heap_openr(SharedDependRelationName, RowExclusiveLock);

        ScanKeyInit(&key[0],
                            Anum_pg_shdepend_dbid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classIdGetDbId(classId)));
        ScanKeyInit(&key[1],
                            Anum_pg_shdepend_classid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classId));
        ScanKeyInit(&key[2],
                                Anum_pg_shdepend_objid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(objectId));

        scan = systable_beginscan(sdepRel, SharedDependDependerIndex, true,
                                                          SnapshotNow, 3, key);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
                Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
                HeapTuple       newtup;
                char            repl_nulls[Natts_pg_shdepend];
                char            replace[Natts_pg_shdepend];
                Datum      *values;

                /* Look for tuples referring to pg_tablespace */
                if (sdepForm->refclassid != RelOid_pg_tablespace)
                        continue;

                /*
                 * Skip a tuple we just inserted; otherwise we could loop here
                 * forever.  If we do skip it, count it anyway, so we don't 
insert
                 * a new entry when the user changes a relation's tablespace to
                 * the same as before.
                 *
                 * XXX Another possibility would be to break out of the loop
                 * as soon as we modify one tuple.  Not sure what is best.
                 */
                if (DatumGetObjectId(sdepForm->refobjid) == newTblspc)
                {
                        count++;
                        continue;
                }

                values = (Datum *) palloc0(sizeof(Datum) * Natts_pg_shdepend);

                MemSet(repl_nulls, ' ', Natts_pg_shdepend);
                MemSet(replace, ' ', Natts_pg_shdepend);

                replace[Anum_pg_shdepend_refobjid - 1] = 'r';
                values[Anum_pg_shdepend_refobjid - 1] = 
ObjectIdGetDatum(newTblspc);

                newtup = heap_modifytuple(tup, sdepRel, values, repl_nulls, 
replace);

                simple_heap_update(sdepRel, &tup->t_self, newtup);

                /* Keep indexes current */
                CatalogUpdateIndexes(sdepRel, newtup);

                count++;
                pfree(values);
                heap_freetuple(newtup);
        }

        systable_endscan(scan);

        /*
         * If we didn't update anything, then the object didn't have a
         * reference registered because it was using the default tablespace.
         * Register one now.
         */
        if (count == 0)
        {
                ObjectAddress self,
                                          referenced;

                self.classId = classId;
                self.objectId = objectId;
                self.objectSubId = 0;

                referenced.classId = RelOid_pg_tablespace;
                referenced.objectId = newTblspc;
                referenced.objectSubId = 0;

                recordSharedDependencyOn(&self, &referenced);
        }               

        heap_close(sdepRel, RowExclusiveLock);
}


/*
 * A struct to keep track of dependencies found in other databases.
 */
typedef struct
{
        Oid             dbOid;
        int             count;
} remoteDep;

/*
 * checkSharedDependencies
 *
 * Check whether there are shared dependency entries for a given global
 * object.  Returns the number found.
 *
 * XXX decide what to do with those found.  Display them inconditionally?
 */
int
checkSharedDependencies(Oid classId, Oid objectId)
{
        Relation        sdepRel;
        ScanKeyData     key[2];
        SysScanDesc     scan;
        HeapTuple       tup;
        int                     count = 0;
        List       *remDeps = NIL;
        ListCell   *cell;
        ObjectAddress   object;

        sdepRel = heap_openr(SharedDependRelationName, RowExclusiveLock);

        ScanKeyInit(&key[0],
                            Anum_pg_shdepend_refclassid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classId));
        ScanKeyInit(&key[1],
                            Anum_pg_shdepend_refobjid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(objectId));
                                
        scan = systable_beginscan(sdepRel, SharedDependReferenceIndex, true,
                                                          SnapshotNow, 2, key);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
                Form_pg_shdepend        sdepForm = (Form_pg_shdepend) 
GETSTRUCT(tup);

                object.classId = sdepForm->classid;
                object.objectId = sdepForm->objid;
                object.objectSubId = 0;

                /*
                 * If it's a dependency local to this database, describe it.
                 * If the dependent object is on a shared catalog, describe it.
                 * If it's a remote dependency, keep track of it so we can
                 * report later.
                 * XXX this info is kept on a simple List.  It might be better
                 * to use a hash table, but I'm not sure it's worth the extra
                 * complexity.
                 */
                if (sdepForm->dbid == MyProc->databaseId)
                        elog(NOTICE, "in this database: %s",
                                        getObjectDescription(&object));
                /* XXX optimize this.  Keep a list of entries? */
                else if (classIdGetDbId(sdepForm->classid) == InvalidOid)
                        elog(NOTICE, getObjectDescription(&object));
                else
                {
                        remoteDep  *dep;
                        bool            stored = false;

                        foreach(cell, remDeps)
                        {
                                dep = lfirst(cell);
                                if (dep->dbOid == sdepForm->dbid)
                                {
                                        dep->count++;
                                        stored = true;
                                        break;
                                }
                        }
                        if (!stored)
                        {
                                dep = (remoteDep *) palloc(sizeof(remoteDep));
                                dep->dbOid = sdepForm->dbid;
                                dep->count = 1;
                                remDeps = lappend(remDeps, dep);
                        }
                }
                count++;
        }

        systable_endscan(scan);
        heap_close(sdepRel, RowExclusiveLock);

        foreach(cell, remDeps)
        {
                remoteDep          *dep = lfirst(cell);

                object.classId = RelOid_pg_database;
                object.objectId = dep->dbOid;
                object.objectSubId = 0;

                elog(NOTICE, "in %s: %d objects",
                         getObjectDescription(&object),
                         dep->count);
        }

        list_free_deep(remDeps);

        return count;
}

/*
 * copyTemplateDependencies
 *
 * Routine to create the initial shared dependencies of a new database.
 * We simply copy the dependencies from the template database.
 */
void
copyTemplateDependencies(Oid templateDbId, Oid newDbId)
{
        Relation        sdepRel;
        ScanKeyData     key[1];
        SysScanDesc     scan;
        HeapTuple       tup;
        CatalogIndexState indstate;
        Datum      *values;
        char            repl_nulls[Natts_pg_shdepend];
        char            replace[Natts_pg_shdepend];

        /* I think this lock is OK? */
        sdepRel = heap_openr(SharedDependRelationName, RowShareLock);

        ScanKeyInit(&key[0],
                        Anum_pg_shdepend_dbid,
                        BTEqualStrategyNumber, F_OIDEQ,
                        ObjectIdGetDatum(templateDbId));

        scan = systable_beginscan(sdepRel, SharedDependDependerIndex, true,
                                                          SnapshotNow, 1, key);

        indstate = CatalogOpenIndexes(sdepRel);

        values = (Datum *) palloc0(sizeof(Datum) * Natts_pg_shdepend);
        MemSet(repl_nulls, ' ', Natts_pg_shdepend);
        MemSet(replace, ' ', Natts_pg_shdepend);
        replace[Anum_pg_shdepend_dbid - 1] = 'r';
        values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
                HeapTuple       newtup;

                newtup = heap_modifytuple(tup, sdepRel, values, repl_nulls, 
replace);

                simple_heap_insert(sdepRel, newtup);

                /* Keep indexes current */
                CatalogIndexInsert(indstate, newtup);

                heap_freetuple(newtup);
        }

        pfree(values);
        systable_endscan(scan);
        CatalogCloseIndexes(indstate);
        heap_close(sdepRel, RowShareLock);
}

/*
 * dropDatabaseDependencies
 *
 * Delete pg_shdepend entries corresponding to a database that's being
 * dropped.
 */
void
dropDatabaseDependencies(Oid databaseId)
{
        Relation        sdepRel;
        ScanKeyData     key[3];
        SysScanDesc     scan;
        HeapTuple       tup;

        sdepRel = heap_openr(SharedDependRelationName, RowExclusiveLock);

        /*
         * First, delete all the entries that have the database Oid in the
         * dbid field.
         */
        ScanKeyInit(&key[0],
                                Anum_pg_shdepend_dbid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(databaseId));

        scan = systable_beginscan(sdepRel, SharedDependDependerIndex, true,
                                                          SnapshotNow, 1, key);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
                simple_heap_delete(sdepRel, &tup->t_self);
        }

        systable_endscan(scan);

        /* Now delete all entries corresponding to the database itself */
        deleteSharedDependencyRecordsFor(RelOid_pg_database, databaseId);

        heap_close(sdepRel, RowExclusiveLock);
}

/*
 * deleteSharedDependencyRecordsFor
 *
 * Delete pg_shdepend entries corresponding to a database-local object that's
 * being dropped or modified.
 */
void
deleteSharedDependencyRecordsFor(Oid classId, Oid objectId)
{
        Relation        sdepRel;
        ScanKeyData     key[3];
        SysScanDesc     scan;
        HeapTuple       tup;

        sdepRel = heap_openr(SharedDependRelationName, RowExclusiveLock);

        ScanKeyInit(&key[0],
                            Anum_pg_shdepend_dbid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classIdGetDbId(classId)));
        ScanKeyInit(&key[1],
                            Anum_pg_shdepend_classid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classId));
        ScanKeyInit(&key[2],
                                Anum_pg_shdepend_objid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(objectId));

        scan = systable_beginscan(sdepRel, SharedDependDependerIndex, true,
                                                          SnapshotNow, 3, key);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
                simple_heap_delete(sdepRel, &tup->t_self);

        systable_endscan(scan);

        heap_close(sdepRel, RowExclusiveLock);
}

/*
 * deleteGlobalDependencyRecordsFor
 *
 * Delete pg_shdepend entries corresponding to a global object that's
 * being dropped or modified.
 * 
 * XXX -- maybe this shouldn't exist at all, because when we drop a
 * global object we first check it isn't referenced.
 */
void
deleteGlobalDependencyRecordsFor(Oid classId, Oid objectId)
{
        Relation        sdepRel;
        ScanKeyData     key[2];
        SysScanDesc     scan;
        HeapTuple       tup;

        sdepRel = heap_openr(SharedDependRelationName, RowExclusiveLock);

        ScanKeyInit(&key[0],
                                Anum_pg_shdepend_refclassid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(classId));
        ScanKeyInit(&key[1],
                                Anum_pg_shdepend_refobjid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(objectId));

        scan = systable_beginscan(sdepRel, SharedDependReferenceIndex, true,
                                                          SnapshotNow, 2, key);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
                simple_heap_delete(sdepRel, &tup->t_self);
        }

        systable_endscan(scan);

        heap_close(sdepRel, RowExclusiveLock);
}

/*
 * classIdGetDbId
 *
 * Get the database Id that should be used in pg_shdepend.  For shared
 * objects, it's 0 (InvalidOid); for all other objects, it's the
 * current database Id.
 */
static Oid
classIdGetDbId(Oid classId)
{
        Relation        class;
        Oid                     dbId;
        
        class = heap_open(classId, AccessShareLock);
        if (class->rd_rel->relisshared)
                dbId = InvalidOid;
        else
                dbId = MyProc->databaseId;

        heap_close(class, AccessShareLock);

        return dbId;
}
/*-------------------------------------------------------------------------
 *
 * pg_shdepend.h
 *        definition of the system "shared dependency" relation (pg_shdepend)
 *        along with the relation's initial contents.
 *
 *
 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * $PostgreSQL$
 *
 * NOTES
 *        the genbki.sh script reads this file and generates .bki
 *        information from the DATA() statements.
 *
 *-------------------------------------------------------------------------
 */
#ifndef PG_SHDEPEND_H
#define PG_SHDEPEND_H

/* ----------------
 *              postgres.h contains the system type definitions and the
 *              CATALOG(), BOOTSTRAP and DATA() sugar words so this file
 *              can be read by both genbki.sh and the C compiler.
 * ----------------
 */

/* ----------------
 *              pg_shdepend definition.  cpp turns this into
 *              typedef struct FormData_pg_shdepend
 * ----------------
 */
CATALOG(pg_shdepend) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
{
        /*
         * Identification of the dependent (referencing) object.
         *
         * These fields are all zeroes for a DEPENDENCY_PIN entry.
         */
        Oid                     dbid;                   /* OID of database 
containing object */
        Oid                     classid;                /* OID of table 
containing object */
        Oid                     objid;                  /* OID of object itself 
*/

        /*
         * Identification of the independent (referenced) object.
         */
        Oid                     refclassid;             /* OID of table 
containing object */
        Oid                     refobjid;               /* OID of object itself 
*/
} FormData_pg_shdepend;

/* ----------------
 *              Form_pg_shdepend corresponds to a pointer to a row with
 *              the format of pg_shdepend relation.
 * ----------------
 */
typedef FormData_pg_shdepend *Form_pg_shdepend;

/* ----------------
 *              compiler constants for pg_shdepend
 * ----------------
 */
#define Natts_pg_shdepend                       5
#define Anum_pg_shdepend_dbid           1
#define Anum_pg_shdepend_classid        2
#define Anum_pg_shdepend_objid          3
#define Anum_pg_shdepend_refclassid     4
#define Anum_pg_shdepend_refobjid       5


/*
 * pg_shdepend has no preloaded contents; system-defined dependencies are
 * loaded into it during a late stage of the initdb process.
 */

#endif   /* PG_SHDEPEND_H */
---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faqs/FAQ.html

Reply via email to