Fix an oversight in the original implementation of performMultipleDeletions():

the alreadyDeleted list has to be passed down through
deleteDependentObjects(), else objects that are deleted via auto/internal
dependencies don't get reported back up to performMultipleDeletions().
Depending on the visitation order, this could cause the code to try to delete
an already-deleted object, leading to strange errors in DROP OWNED (typically
"cache lookup failed for relation NNNNN" or similar).  Per bug #4289.

Patch for back branches only.  This code has recently been rewritten in HEAD,
and doesn't have this particular bug anymore.
This commit is contained in:
Tom Lane 2008-07-11 16:08:50 +00:00
parent 165b65bb37
commit 6dafb5b4ae

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.69 2008/01/01 19:45:48 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.69.2.1 2008/07/11 16:08:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -130,7 +130,8 @@ static bool deleteDependentObjects(const ObjectAddress *object,
DropBehavior behavior, DropBehavior behavior,
int msglevel, int msglevel,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel); Relation depRel,
ObjectAddresses *alreadyDeleted);
static void doDeletion(const ObjectAddress *object); static void doDeletion(const ObjectAddress *object);
static bool find_expr_references_walker(Node *node, static bool find_expr_references_walker(Node *node,
find_expr_references_context *context); find_expr_references_context *context);
@ -369,7 +370,7 @@ deleteWhatDependsOn(const ObjectAddress *object,
if (!deleteDependentObjects(object, objDescription, if (!deleteDependentObjects(object, objDescription,
DROP_CASCADE, DROP_CASCADE,
showNotices ? NOTICE : DEBUG2, showNotices ? NOTICE : DEBUG2,
oktodelete, depRel)) oktodelete, depRel, NULL))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("failed to drop all objects depending on %s", errmsg("failed to drop all objects depending on %s",
@ -501,6 +502,9 @@ findAutoDeletableObjects(const ObjectAddress *object,
* *
* depRel is the already-open pg_depend relation. * depRel is the already-open pg_depend relation.
* *
* alreadyDeleted is a list to add objects to as they are deleted, or NULL
* if the caller doesn't need to have such a list.
*
* *
* In RESTRICT mode, we perform all the deletions anyway, but ereport a message * In RESTRICT mode, we perform all the deletions anyway, but ereport a message
* and return FALSE if we find a restriction violation. performDeletion * and return FALSE if we find a restriction violation. performDeletion
@ -717,7 +721,7 @@ recursiveDeletion(const ObjectAddress *object,
*/ */
if (!deleteDependentObjects(object, objDescription, if (!deleteDependentObjects(object, objDescription,
behavior, msglevel, behavior, msglevel,
oktodelete, depRel)) oktodelete, depRel, alreadyDeleted))
ok = false; ok = false;
/* /*
@ -783,6 +787,7 @@ recursiveDeletion(const ObjectAddress *object,
* behavior: desired drop behavior * behavior: desired drop behavior
* oktodelete: stuff that's AUTO-deletable * oktodelete: stuff that's AUTO-deletable
* depRel: already opened pg_depend relation * depRel: already opened pg_depend relation
* alreadyDeleted: optional list to add deleted objects to
* *
* Returns TRUE if all is well, false if any problem found. * Returns TRUE if all is well, false if any problem found.
* *
@ -798,7 +803,8 @@ deleteDependentObjects(const ObjectAddress *object,
DropBehavior behavior, DropBehavior behavior,
int msglevel, int msglevel,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel) Relation depRel,
ObjectAddresses *alreadyDeleted)
{ {
bool ok = true; bool ok = true;
ScanKeyData key[3]; ScanKeyData key[3];
@ -865,7 +871,8 @@ deleteDependentObjects(const ObjectAddress *object,
getObjectDescription(&otherObject)))); getObjectDescription(&otherObject))));
if (!recursiveDeletion(&otherObject, behavior, msglevel, if (!recursiveDeletion(&otherObject, behavior, msglevel,
object, oktodelete, depRel, NULL)) object, oktodelete, depRel,
alreadyDeleted))
ok = false; ok = false;
break; break;
case DEPENDENCY_AUTO: case DEPENDENCY_AUTO:
@ -881,7 +888,8 @@ deleteDependentObjects(const ObjectAddress *object,
getObjectDescription(&otherObject)))); getObjectDescription(&otherObject))));
if (!recursiveDeletion(&otherObject, behavior, msglevel, if (!recursiveDeletion(&otherObject, behavior, msglevel,
object, oktodelete, depRel, NULL)) object, oktodelete, depRel,
alreadyDeleted))
ok = false; ok = false;
break; break;
case DEPENDENCY_PIN: case DEPENDENCY_PIN: