|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.177 2006/01/30 16:18:58 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.178 2006/03/03 03:30:52 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -527,26 +527,79 @@ RemoveRelation(const RangeVar *relation, DropBehavior behavior)
|
527 | 527 | * ExecuteTruncate
|
528 | 528 | *Executes a TRUNCATE command.
|
529 | 529 | *
|
530 |
| - * This is a multi-relation truncate. It first opens and grabs exclusive |
531 |
| - * locks on all relations involved, checking permissions and otherwise |
532 |
| - * verifying that the relation is OK for truncation. When they are all |
533 |
| - * open, it checks foreign key references on them, namely that FK references |
534 |
| - * are all internal to the group that's being truncated. Finally all |
535 |
| - * relations are truncated and reindexed. |
| 530 | + * This is a multi-relation truncate. We first open and grab exclusive |
| 531 | + * lock on all relations involved, checking permissions and otherwise |
| 532 | + * verifying that the relation is OK for truncation. In CASCADE mode, |
| 533 | + * relations having FK references to the targeted relations are automatically |
| 534 | + * added to the group; in RESTRICT mode, we check that all FK references are |
| 535 | + * internal to the group that's being truncated. Finally all the relations |
| 536 | + * are truncated and reindexed. |
536 | 537 | */
|
537 | 538 | void
|
538 |
| -ExecuteTruncate(List*relations) |
| 539 | +ExecuteTruncate(TruncateStmt*stmt) |
539 | 540 | {
|
540 | 541 | List*rels=NIL;
|
| 542 | +List*directRelids=NIL; |
541 | 543 | ListCell*cell;
|
| 544 | +Oidrelid; |
| 545 | +Relationrel; |
542 | 546 |
|
543 |
| -foreach(cell,relations) |
| 547 | +/* |
| 548 | + * Open and exclusive-lock all the explicitly-specified relations |
| 549 | + */ |
| 550 | +foreach(cell,stmt->relations) |
544 | 551 | {
|
545 | 552 | RangeVar*rv=lfirst(cell);
|
546 |
| -Relationrel; |
547 | 553 |
|
548 |
| -/* Grab exclusive lock in preparation for truncate */ |
549 | 554 | rel=heap_openrv(rv,AccessExclusiveLock);
|
| 555 | +rels=lappend(rels,rel); |
| 556 | +directRelids=lappend_oid(directRelids,RelationGetRelid(rel)); |
| 557 | +} |
| 558 | + |
| 559 | +/* |
| 560 | + * In CASCADE mode, suck in all referencing relations as well. This |
| 561 | + * requires multiple iterations to find indirectly-dependent relations. |
| 562 | + * At each phase, we need to exclusive-lock new rels before looking |
| 563 | + * for their dependencies, else we might miss something. |
| 564 | + */ |
| 565 | +if (stmt->behavior==DROP_CASCADE) |
| 566 | +{ |
| 567 | +List*relids=list_copy(directRelids); |
| 568 | + |
| 569 | +for (;;) |
| 570 | +{ |
| 571 | +List*newrelids; |
| 572 | + |
| 573 | +newrelids=heap_truncate_find_FKs(relids); |
| 574 | +if (newrelids==NIL) |
| 575 | +break;/* nothing else to add */ |
| 576 | + |
| 577 | +foreach(cell,newrelids) |
| 578 | +{ |
| 579 | +relid=lfirst_oid(cell); |
| 580 | +rel=heap_open(relid,AccessExclusiveLock); |
| 581 | +rels=lappend(rels,rel); |
| 582 | +relids=lappend_oid(relids,relid); |
| 583 | +} |
| 584 | +} |
| 585 | +} |
| 586 | + |
| 587 | +/* now check all involved relations */ |
| 588 | +foreach(cell,rels) |
| 589 | +{ |
| 590 | +rel= (Relation)lfirst(cell); |
| 591 | +relid=RelationGetRelid(rel); |
| 592 | + |
| 593 | +/* |
| 594 | + * If this table was added to the command by CASCADE, report it. |
| 595 | + * We don't do this earlier because if we error out on one of the |
| 596 | + * tables, it'd be confusing to list subsequently-added tables. |
| 597 | + */ |
| 598 | +if (stmt->behavior==DROP_CASCADE&& |
| 599 | +!list_member_oid(directRelids,relid)) |
| 600 | +ereport(NOTICE, |
| 601 | +(errmsg("truncate cascades to table \"%s\"", |
| 602 | +RelationGetRelationName(rel)))); |
550 | 603 |
|
551 | 604 | /* Only allow truncate on regular tables */
|
552 | 605 | if (rel->rd_rel->relkind!=RELKIND_RELATION)
|
@@ -585,25 +638,30 @@ ExecuteTruncate(List *relations)
|
585 | 638 | ereport(ERROR,
|
586 | 639 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
587 | 640 | errmsg("cannot truncate temporary tables of other sessions")));
|
588 |
| - |
589 |
| -/* Save it into the list of rels to truncate */ |
590 |
| -rels=lappend(rels,rel); |
591 | 641 | }
|
592 | 642 |
|
593 | 643 | /*
|
594 |
| - * Check foreign key references. |
| 644 | + * Check foreign key references. In CASCADE mode, this should be |
| 645 | + * unnecessary since we just pulled in all the references; but as |
| 646 | + * a cross-check, do it anyway if in an Assert-enabled build. |
595 | 647 | */
|
| 648 | +#ifdefUSE_ASSERT_CHECKING |
596 | 649 | heap_truncate_check_FKs(rels, false);
|
| 650 | +#else |
| 651 | +if (stmt->behavior==DROP_RESTRICT) |
| 652 | +heap_truncate_check_FKs(rels, false); |
| 653 | +#endif |
597 | 654 |
|
598 | 655 | /*
|
599 | 656 | * OK, truncate each table.
|
600 | 657 | */
|
601 | 658 | foreach(cell,rels)
|
602 | 659 | {
|
603 |
| -Relationrel=lfirst(cell); |
604 | 660 | Oidheap_relid;
|
605 | 661 | Oidtoast_relid;
|
606 | 662 |
|
| 663 | +rel= (Relation)lfirst(cell); |
| 664 | + |
607 | 665 | /*
|
608 | 666 | * Create a new empty storage file for the relation, and assign it as
|
609 | 667 | * the relfilenode value.The old storage file is scheduled for
|
|