Thread: Bug with Temp table with serial column

Bug with Temp table with serial column

From
"David Heggie"
Date:
Hi,

When creating a temp table with a column which has a type of serial, the er=
ror below appears in the postgres log file after disconnection.
This also then leaves the temp table, seq, idx and schema in the db.
It looks like postgres is trying to clean up the temp stuff and is trying t=
o delete the sequence before the table.
To get around this you must drop the temp table before disconnecting but th=
is still leaves a new schema behind.
We are creating this temp table for pagination. Any better ideas?

Thanks
David Heggie

NOTICE:  CREATE TABLE will create implicit sequence 'account800090_account8=
00090id_seq' for SERIAL column 'account800090.account800090id'
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 'account8000=
90_pkey' for table 'account800090'
LOG:  pq_recvbuf: recv() failed: Connection reset by peer
ERROR:  Cannot drop sequence account800090_account800090id_seq because tabl=
e account800090 column account800090id requires it
        You may drop table account800090 column account800090id instead
LOG:  server process (pid 29161) exited with exit code 1
LOG:  terminating any other active server processes
WARNING:  Message from PostgreSQL backend:
        The Postmaster has informed me that some other backend
        died abnormally and possibly corrupted shared memory.
        I have rolled back the current transaction and am
        going to terminate your database system connection and exit.
        Please reconnect to the database system and repeat your query.
WARNING:  Message from PostgreSQL backend:
        The Postmaster has informed me that some other backend
        died abnormally and possibly corrupted shared memory.
        I have rolled back the current transaction and am
        going to terminate your database system connection and exit.
        Please reconnect to the database system and repeat your query.
WARNING:  Message from PostgreSQL backend:
        The Postmaster has informed me that some other backend
        died abnormally and possibly corrupted shared memory.
        I have rolled back the current transaction and am
        going to terminate your database system connection and exit.
        Please reconnect to the database system and repeat your query.
WARNING:  Message from PostgreSQL backend:
        The Postmaster has informed me that some other backend
        died abnormally and possibly corrupted shared memory.
        I have rolled back the current transaction and am
        going to terminate your database system connection and exit.
        Please reconnect to the database system and repeat your query.
LOG:  all server processes terminated; reinitializing shared memory and sem=
aphores
LOG:  database system was interrupted at 2003-02-05 10:01:01 EST
LOG:  checkpoint record is at 0/11B291F0
LOG:  redo record is at 0/11B291F0; undo record is at 0/0; shutdown FALSE
LOG:  next transaction id: 975194; next oid: 352850
LOG:  database system was not properly shut down; automatic recovery in pro=
gress
LOG:  redo starts at 0/11B29230
LOG:  ReadRecord: record with zero length at 0/11B3A5F0
LOG:  redo done at 0/11B3A5C8
LOG:  database system is ready

Re: Bug with Temp table with serial column

From
Tom Lane
Date:
"David Heggie" <davidh@intrapower.com.au> writes:
> When creating a temp table with a column which has a type of serial, the error below appears in the postgres log file
afterdisconnection. 

Good catch.  Here's the patch if you need it before 7.3.3 ...

            regards, tom lane


*** src/backend/catalog/dependency.c~    Wed Dec  4 15:00:19 2002
--- src/backend/catalog/dependency.c    Thu Feb  6 20:14:25 2003
***************
*** 99,104 ****
--- 99,109 ----
                    const ObjectAddress *callingObject,
                    ObjectAddresses *oktodelete,
                    Relation depRel);
+ static bool deleteDependentObjects(const ObjectAddress *object,
+                                    const char *objDescription,
+                                    DropBehavior behavior,
+                                    ObjectAddresses *oktodelete,
+                                    Relation depRel);
  static void doDeletion(const ObjectAddress *object);
  static bool find_expr_references_walker(Node *node,
                              find_expr_references_context *context);
***************
*** 172,177 ****
--- 177,240 ----


  /*
+  * deleteWhatDependsOn: attempt to drop everything that depends on the
+  * specified object, though not the object itself.  Behavior is always
+  * CASCADE.
+  *
+  * This is currently used only to clean out the contents of a schema
+  * (namespace): the passed object is a namespace.
+  */
+ void
+ deleteWhatDependsOn(const ObjectAddress *object)
+ {
+     char       *objDescription;
+     Relation    depRel;
+     ObjectAddresses oktodelete;
+
+     /*
+      * Get object description for possible use in failure messages
+      */
+     objDescription = getObjectDescription(object);
+
+     /*
+      * We save some cycles by opening pg_depend just once and passing the
+      * Relation pointer down to all the recursive deletion steps.
+      */
+     depRel = heap_openr(DependRelationName, RowExclusiveLock);
+
+     /*
+      * Construct a list of objects that are reachable by AUTO or INTERNAL
+      * dependencies from the target object.  These should be deleted silently,
+      * even if the actual deletion pass first reaches one of them via a
+      * non-auto dependency.
+      */
+     init_object_addresses(&oktodelete);
+
+     findAutoDeletableObjects(object, &oktodelete, depRel);
+
+     /*
+      * Now invoke only step 2 of recursiveDeletion: just recurse to the
+      * stuff dependent on the given object.
+      */
+     if (!deleteDependentObjects(object, objDescription,
+                                 DROP_CASCADE, &oktodelete, depRel))
+         elog(ERROR, "Failed to drop all objects depending on %s",
+              objDescription);
+
+     /*
+      * We do not need CommandCounterIncrement here, since if step 2 did
+      * anything then each recursive call will have ended with one.
+      */
+
+     term_object_addresses(&oktodelete);
+
+     heap_close(depRel, RowExclusiveLock);
+
+     pfree(objDescription);
+ }
+
+
+ /*
   * findAutoDeletableObjects: find all objects that are reachable by AUTO or
   * INTERNAL dependency paths from the given object.  Add them all to the
   * oktodelete list.  Note that the originally given object will also be
***************
*** 475,496 ****

      /*
       * Step 2: scan pg_depend records that link to this object, showing
!      * the things that depend on it.  Recursively delete those things. (We
!      * don't delete the pg_depend records here, as the recursive call will
!      * do that.)  Note it's important to delete the dependent objects
       * before the referenced one, since the deletion routines might do
       * things like try to update the pg_class record when deleting a check
       * constraint.
-      *
-      * Again, when dropping a whole object (subId = 0), find pg_depend
-      * records for its sub-objects too.
-      *
-      * NOTE: because we are using SnapshotNow, if a recursive call deletes
-      * any pg_depend tuples that our scan hasn't yet visited, we will not
-      * see them as good when we do visit them.    This is essential for
-      * correct behavior if there are multiple dependency paths between two
-      * objects --- else we might try to delete an already-deleted object.
       */
      ScanKeyEntryInitialize(&key[0], 0x0,
                             Anum_pg_depend_refclassid, F_OIDEQ,
                             ObjectIdGetDatum(object->classId));
--- 538,627 ----

      /*
       * Step 2: scan pg_depend records that link to this object, showing
!      * the things that depend on it.  Recursively delete those things.
!      * Note it's important to delete the dependent objects
       * before the referenced one, since the deletion routines might do
       * things like try to update the pg_class record when deleting a check
       * constraint.
       */
+     if (!deleteDependentObjects(object, objDescription,
+                                 behavior, oktodelete, depRel))
+         ok = false;
+
+     /*
+      * We do not need CommandCounterIncrement here, since if step 2 did
+      * anything then each recursive call will have ended with one.
+      */
+
+     /*
+      * Step 3: delete the object itself.
+      */
+     doDeletion(object);
+
+     /*
+      * Delete any comments associated with this object.  (This is a
+      * convenient place to do it instead of having every object type know
+      * to do it.)
+      */
+     DeleteComments(object->objectId, object->classId, object->objectSubId);
+
+     /*
+      * CommandCounterIncrement here to ensure that preceding changes are
+      * all visible.
+      */
+     CommandCounterIncrement();
+
+     /*
+      * And we're done!
+      */
+     pfree(objDescription);
+
+     return ok;
+ }
+
+
+ /*
+  * deleteDependentObjects - find and delete objects that depend on 'object'
+  *
+  * Scan pg_depend records that link to the given object, showing
+  * the things that depend on it.  Recursively delete those things. (We
+  * don't delete the pg_depend records here, as the recursive call will
+  * do that.)  Note it's important to delete the dependent objects
+  * before the referenced one, since the deletion routines might do
+  * things like try to update the pg_class record when deleting a check
+  * constraint.
+  *
+  * When dropping a whole object (subId = 0), find pg_depend records for
+  * its sub-objects too.
+  *
+  *    object: the object to find dependencies on
+  *    objDescription: description of object (only used for error messages)
+  *    behavior: desired drop behavior
+  *    oktodelete: stuff that's AUTO-deletable
+  *    depRel: already opened pg_depend relation
+  *
+  * Returns TRUE if all is well, false if any problem found.
+  *
+  * NOTE: because we are using SnapshotNow, if a recursive call deletes
+  * any pg_depend tuples that our scan hasn't yet visited, we will not
+  * see them as good when we do visit them.    This is essential for
+  * correct behavior if there are multiple dependency paths between two
+  * objects --- else we might try to delete an already-deleted object.
+  */
+ static bool
+ deleteDependentObjects(const ObjectAddress *object,
+                        const char *objDescription,
+                        DropBehavior behavior,
+                        ObjectAddresses *oktodelete,
+                        Relation depRel)
+ {
+     bool        ok = true;
+     ScanKeyData key[3];
+     int            nkeys;
+     SysScanDesc scan;
+     HeapTuple    tup;
+     ObjectAddress otherObject;
+
      ScanKeyEntryInitialize(&key[0], 0x0,
                             Anum_pg_depend_refclassid, F_OIDEQ,
                             ObjectIdGetDatum(object->classId));
***************
*** 579,612 ****
      }

      systable_endscan(scan);
-
-     /*
-      * We do not need CommandCounterIncrement here, since if step 2 did
-      * anything then each recursive call will have ended with one.
-      */
-
-     /*
-      * Step 3: delete the object itself.
-      */
-     doDeletion(object);
-
-     /*
-      * Delete any comments associated with this object.  (This is a
-      * convenient place to do it instead of having every object type know
-      * to do it.)
-      */
-     DeleteComments(object->objectId, object->classId, object->objectSubId);
-
-     /*
-      * CommandCounterIncrement here to ensure that preceding changes are
-      * all visible.
-      */
-     CommandCounterIncrement();
-
-     /*
-      * And we're done!
-      */
-     pfree(objDescription);

      return ok;
  }
--- 710,715 ----
*** src/backend/catalog/namespace.c~    Sat Nov  2 13:41:21 2002
--- src/backend/catalog/namespace.c    Thu Feb  6 20:14:25 2003
***************
*** 19,33 ****
   */
  #include "postgres.h"

- #include "access/heapam.h"
  #include "access/xact.h"
- #include "catalog/catalog.h"
  #include "catalog/catname.h"
  #include "catalog/dependency.h"
- #include "catalog/heap.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_conversion.h"
- #include "catalog/pg_inherits.h"
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
--- 19,29 ----
***************
*** 42,51 ****
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/catcache.h"
- #include "utils/fmgroids.h"
- #include "utils/guc.h"
  #include "utils/inval.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"


--- 38,46 ----
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/catcache.h"
  #include "utils/inval.h"
  #include "utils/lsyscache.h"
+ #include "utils/memutils.h"
  #include "utils/syscache.h"


***************
*** 1608,1657 ****
  static void
  RemoveTempRelations(Oid tempNamespaceId)
  {
-     Relation    pgclass;
-     HeapScanDesc scan;
-     HeapTuple    tuple;
-     ScanKeyData key;
      ObjectAddress object;

      /*
!      * Scan pg_class to find all the relations in the target namespace.
!      * Ignore indexes, though, on the assumption that they'll go away when
!      * their tables are deleted.
!      *
!      * NOTE: if there are deletion constraints between temp relations, then
!      * our CASCADE delete call may cause as-yet-unvisited objects to go
!      * away.  This is okay because we are using SnapshotNow; when the scan
!      * does reach those pg_class tuples, they'll be ignored as already
!      * deleted.
       */
!     ScanKeyEntryInitialize(&key, 0x0,
!                            Anum_pg_class_relnamespace,
!                            F_OIDEQ,
!                            ObjectIdGetDatum(tempNamespaceId));
!
!     pgclass = heap_openr(RelationRelationName, AccessShareLock);
!     scan = heap_beginscan(pgclass, SnapshotNow, 1, &key);
!
!     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
!     {
!         switch (((Form_pg_class) GETSTRUCT(tuple))->relkind)
!         {
!             case RELKIND_RELATION:
!             case RELKIND_SEQUENCE:
!             case RELKIND_VIEW:
!                 object.classId = RelOid_pg_class;
!                 object.objectId = HeapTupleGetOid(tuple);
!                 object.objectSubId = 0;
!                 performDeletion(&object, DROP_CASCADE);
!                 break;
!             default:
!                 break;
!         }
!     }

!     heap_endscan(scan);
!     heap_close(pgclass, AccessShareLock);
  }

  /*
--- 1603,1621 ----
  static void
  RemoveTempRelations(Oid tempNamespaceId)
  {
      ObjectAddress object;

      /*
!      * We want to get rid of everything in the target namespace, but not
!      * the namespace itself (deleting it only to recreate it later would be
!      * a waste of cycles).  We do this by finding everything that has a
!      * dependency on the namespace.
       */
!     object.classId = get_system_catalog_relid(NamespaceRelationName);
!     object.objectId = tempNamespaceId;
!     object.objectSubId = 0;

!     deleteWhatDependsOn(&object);
  }

  /*
*** src/include/catalog/dependency.h~    Wed Sep  4 16:31:37 2002
--- src/include/catalog/dependency.h    Thu Feb  6 20:14:25 2003
***************
*** 84,89 ****
--- 84,91 ----
  extern void performDeletion(const ObjectAddress *object,
                  DropBehavior behavior);

+ extern void deleteWhatDependsOn(const ObjectAddress *object);
+
  extern void recordDependencyOnExpr(const ObjectAddress *depender,
                         Node *expr, List *rtable,
                         DependencyType behavior);