|
8 | 8 | * Portions Copyright (c) 1994, Regents of the University of California |
9 | 9 | * |
10 | 10 | * IDENTIFICATION |
11 | | - * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.19 2003/01/10 21:08:07 tgl Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.20 2003/02/07 01:33:06 tgl Exp $ |
12 | 12 | * |
13 | 13 | *------------------------------------------------------------------------- |
14 | 14 | */ |
@@ -100,6 +100,11 @@ static bool recursiveDeletion(const ObjectAddress *object, |
100 | 100 | constObjectAddress*callingObject, |
101 | 101 | ObjectAddresses*oktodelete, |
102 | 102 | RelationdepRel); |
| 103 | +staticbooldeleteDependentObjects(constObjectAddress*object, |
| 104 | +constchar*objDescription, |
| 105 | +DropBehaviorbehavior, |
| 106 | +ObjectAddresses*oktodelete, |
| 107 | +RelationdepRel); |
103 | 108 | staticvoiddoDeletion(constObjectAddress*object); |
104 | 109 | staticboolfind_expr_references_walker(Node*node, |
105 | 110 | find_expr_references_context*context); |
@@ -172,6 +177,64 @@ performDeletion(const ObjectAddress *object, |
172 | 177 | } |
173 | 178 |
|
174 | 179 |
|
| 180 | +/* |
| 181 | + * deleteWhatDependsOn: attempt to drop everything that depends on the |
| 182 | + * specified object, though not the object itself. Behavior is always |
| 183 | + * CASCADE. |
| 184 | + * |
| 185 | + * This is currently used only to clean out the contents of a schema |
| 186 | + * (namespace): the passed object is a namespace. |
| 187 | + */ |
| 188 | +void |
| 189 | +deleteWhatDependsOn(constObjectAddress*object) |
| 190 | +{ |
| 191 | +char*objDescription; |
| 192 | +RelationdepRel; |
| 193 | +ObjectAddressesoktodelete; |
| 194 | + |
| 195 | +/* |
| 196 | + * Get object description for possible use in failure messages |
| 197 | + */ |
| 198 | +objDescription=getObjectDescription(object); |
| 199 | + |
| 200 | +/* |
| 201 | + * We save some cycles by opening pg_depend just once and passing the |
| 202 | + * Relation pointer down to all the recursive deletion steps. |
| 203 | + */ |
| 204 | +depRel=heap_openr(DependRelationName,RowExclusiveLock); |
| 205 | + |
| 206 | +/* |
| 207 | + * Construct a list of objects that are reachable by AUTO or INTERNAL |
| 208 | + * dependencies from the target object. These should be deleted silently, |
| 209 | + * even if the actual deletion pass first reaches one of them via a |
| 210 | + * non-auto dependency. |
| 211 | + */ |
| 212 | +init_object_addresses(&oktodelete); |
| 213 | + |
| 214 | +findAutoDeletableObjects(object,&oktodelete,depRel); |
| 215 | + |
| 216 | +/* |
| 217 | + * Now invoke only step 2 of recursiveDeletion: just recurse to the |
| 218 | + * stuff dependent on the given object. |
| 219 | + */ |
| 220 | +if (!deleteDependentObjects(object,objDescription, |
| 221 | +DROP_CASCADE,&oktodelete,depRel)) |
| 222 | +elog(ERROR,"Failed to drop all objects depending on %s", |
| 223 | +objDescription); |
| 224 | + |
| 225 | +/* |
| 226 | + * We do not need CommandCounterIncrement here, since if step 2 did |
| 227 | + * anything then each recursive call will have ended with one. |
| 228 | + */ |
| 229 | + |
| 230 | +term_object_addresses(&oktodelete); |
| 231 | + |
| 232 | +heap_close(depRel,RowExclusiveLock); |
| 233 | + |
| 234 | +pfree(objDescription); |
| 235 | +} |
| 236 | + |
| 237 | + |
175 | 238 | /* |
176 | 239 | * findAutoDeletableObjects: find all objects that are reachable by AUTO or |
177 | 240 | * INTERNAL dependency paths from the given object. Add them all to the |
@@ -476,22 +539,90 @@ recursiveDeletion(const ObjectAddress *object, |
476 | 539 |
|
477 | 540 | /* |
478 | 541 | * Step 2: scan pg_depend records that link to this object, showing |
479 | | - * the things that depend on it. Recursively delete those things. (We |
480 | | - * don't delete the pg_depend records here, as the recursive call will |
481 | | - * do that.) Note it's important to delete the dependent objects |
| 542 | + * the things that depend on it. Recursively delete those things. |
| 543 | + * Note it's important to delete the dependent objects |
482 | 544 | * before the referenced one, since the deletion routines might do |
483 | 545 | * things like try to update the pg_class record when deleting a check |
484 | 546 | * constraint. |
485 | | - * |
486 | | - * Again, when dropping a whole object (subId = 0), find pg_depend |
487 | | - * records for its sub-objects too. |
488 | | - * |
489 | | - * NOTE: because we are using SnapshotNow, if a recursive call deletes |
490 | | - * any pg_depend tuples that our scan hasn't yet visited, we will not |
491 | | - * see them as good when we do visit them.This is essential for |
492 | | - * correct behavior if there are multiple dependency paths between two |
493 | | - * objects --- else we might try to delete an already-deleted object. |
494 | 547 | */ |
| 548 | +if (!deleteDependentObjects(object,objDescription, |
| 549 | +behavior,oktodelete,depRel)) |
| 550 | +ok= false; |
| 551 | + |
| 552 | +/* |
| 553 | + * We do not need CommandCounterIncrement here, since if step 2 did |
| 554 | + * anything then each recursive call will have ended with one. |
| 555 | + */ |
| 556 | + |
| 557 | +/* |
| 558 | + * Step 3: delete the object itself. |
| 559 | + */ |
| 560 | +doDeletion(object); |
| 561 | + |
| 562 | +/* |
| 563 | + * Delete any comments associated with this object. (This is a |
| 564 | + * convenient place to do it instead of having every object type know |
| 565 | + * to do it.) |
| 566 | + */ |
| 567 | +DeleteComments(object->objectId,object->classId,object->objectSubId); |
| 568 | + |
| 569 | +/* |
| 570 | + * CommandCounterIncrement here to ensure that preceding changes are |
| 571 | + * all visible. |
| 572 | + */ |
| 573 | +CommandCounterIncrement(); |
| 574 | + |
| 575 | +/* |
| 576 | + * And we're done! |
| 577 | + */ |
| 578 | +pfree(objDescription); |
| 579 | + |
| 580 | +returnok; |
| 581 | +} |
| 582 | + |
| 583 | + |
| 584 | +/* |
| 585 | + * deleteDependentObjects - find and delete objects that depend on 'object' |
| 586 | + * |
| 587 | + * Scan pg_depend records that link to the given object, showing |
| 588 | + * the things that depend on it. Recursively delete those things. (We |
| 589 | + * don't delete the pg_depend records here, as the recursive call will |
| 590 | + * do that.) Note it's important to delete the dependent objects |
| 591 | + * before the referenced one, since the deletion routines might do |
| 592 | + * things like try to update the pg_class record when deleting a check |
| 593 | + * constraint. |
| 594 | + * |
| 595 | + * When dropping a whole object (subId = 0), find pg_depend records for |
| 596 | + * its sub-objects too. |
| 597 | + * |
| 598 | + *object: the object to find dependencies on |
| 599 | + *objDescription: description of object (only used for error messages) |
| 600 | + *behavior: desired drop behavior |
| 601 | + *oktodelete: stuff that's AUTO-deletable |
| 602 | + *depRel: already opened pg_depend relation |
| 603 | + * |
| 604 | + * Returns TRUE if all is well, false if any problem found. |
| 605 | + * |
| 606 | + * NOTE: because we are using SnapshotNow, if a recursive call deletes |
| 607 | + * any pg_depend tuples that our scan hasn't yet visited, we will not |
| 608 | + * see them as good when we do visit them.This is essential for |
| 609 | + * correct behavior if there are multiple dependency paths between two |
| 610 | + * objects --- else we might try to delete an already-deleted object. |
| 611 | + */ |
| 612 | +staticbool |
| 613 | +deleteDependentObjects(constObjectAddress*object, |
| 614 | +constchar*objDescription, |
| 615 | +DropBehaviorbehavior, |
| 616 | +ObjectAddresses*oktodelete, |
| 617 | +RelationdepRel) |
| 618 | +{ |
| 619 | +boolok= true; |
| 620 | +ScanKeyDatakey[3]; |
| 621 | +intnkeys; |
| 622 | +SysScanDescscan; |
| 623 | +HeapTupletup; |
| 624 | +ObjectAddressotherObject; |
| 625 | + |
495 | 626 | ScanKeyEntryInitialize(&key[0],0x0, |
496 | 627 | Anum_pg_depend_refclassid,F_OIDEQ, |
497 | 628 | ObjectIdGetDatum(object->classId)); |
@@ -581,34 +712,6 @@ recursiveDeletion(const ObjectAddress *object, |
581 | 712 |
|
582 | 713 | systable_endscan(scan); |
583 | 714 |
|
584 | | -/* |
585 | | - * We do not need CommandCounterIncrement here, since if step 2 did |
586 | | - * anything then each recursive call will have ended with one. |
587 | | - */ |
588 | | - |
589 | | -/* |
590 | | - * Step 3: delete the object itself. |
591 | | - */ |
592 | | -doDeletion(object); |
593 | | - |
594 | | -/* |
595 | | - * Delete any comments associated with this object. (This is a |
596 | | - * convenient place to do it instead of having every object type know |
597 | | - * to do it.) |
598 | | - */ |
599 | | -DeleteComments(object->objectId,object->classId,object->objectSubId); |
600 | | - |
601 | | -/* |
602 | | - * CommandCounterIncrement here to ensure that preceding changes are |
603 | | - * all visible. |
604 | | - */ |
605 | | -CommandCounterIncrement(); |
606 | | - |
607 | | -/* |
608 | | - * And we're done! |
609 | | - */ |
610 | | -pfree(objDescription); |
611 | | - |
612 | 715 | returnok; |
613 | 716 | } |
614 | 717 |
|
|