Re: Bug with Temp table with serial column

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: "David Heggie" <davidh(at)intrapower(dot)com(dot)au>
Cc: pgsql-bugs(at)postgresql(dot)org
Subject: Re: Bug with Temp table with serial column
Date: 2003-02-07 01:24:20
Message-ID: 21881.1044581060@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

"David Heggie" <davidh(at)intrapower(dot)com(dot)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 after disconnection.

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);

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Elias Athanasopoulos 2003-02-07 19:42:47 cvs (7/2/2003) broken?
Previous Message Tom Lane 2003-02-07 00:03:51 Re: psql 7.3.1: signal 11 + replace_vars_with_subplan_refs: variable not in subplan target list