diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 010845536825b3892ee0336647c84260792deaa4..2d97dba701408fca2b0b2d645594689bef3ecc36 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.357 2009/08/02 22:14:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.358 2009/08/23 19:23:40 tgl Exp $ * * * INTERFACE ROUTINES @@ -2342,18 +2342,9 @@ heap_truncate(List *relids) { Oid rid = lfirst_oid(cell); Relation rel; - Oid toastrelid; rel = heap_open(rid, AccessExclusiveLock); relations = lappend(relations, rel); - - /* If there is a toast table, add it to the list too */ - toastrelid = rel->rd_rel->reltoastrelid; - if (OidIsValid(toastrelid)) - { - rel = heap_open(toastrelid, AccessExclusiveLock); - relations = lappend(relations, rel); - } } /* Don't allow truncate on tables that are referenced by foreign keys */ @@ -2364,19 +2355,47 @@ heap_truncate(List *relids) { Relation rel = lfirst(cell); - /* Truncate the actual file (and discard buffers) */ - RelationTruncate(rel, 0); + /* Truncate the relation */ + heap_truncate_one_rel(rel); - /* If this relation has indexes, truncate the indexes too */ - RelationTruncateIndexes(rel); - - /* - * Close the relation, but keep exclusive lock on it until commit. - */ + /* Close the relation, but keep exclusive lock on it until commit */ heap_close(rel, NoLock); } } +/* + * heap_truncate_one_rel + * + * This routine deletes all data within the specified relation. + * + * This is not transaction-safe, because the truncation is done immediately + * and cannot be rolled back later. Caller is responsible for having + * checked permissions etc, and must have obtained AccessExclusiveLock. + */ +void +heap_truncate_one_rel(Relation rel) +{ + Oid toastrelid; + + /* Truncate the actual file (and discard buffers) */ + RelationTruncate(rel, 0); + + /* If the relation has indexes, truncate the indexes too */ + RelationTruncateIndexes(rel); + + /* If there is a toast table, truncate that too */ + toastrelid = rel->rd_rel->reltoastrelid; + if (OidIsValid(toastrelid)) + { + Relation toastrel = heap_open(toastrelid, AccessExclusiveLock); + + RelationTruncate(toastrel, 0); + RelationTruncateIndexes(toastrel); + /* keep the lock... */ + heap_close(toastrel, NoLock); + } +} + /* * heap_truncate_check_FKs * Check for foreign keys referencing a list of relations that diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 07bc3932003b10e52135319c32f3d1700334433c..a36cbc51aff79f94368a61f2a13635f04d400781 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.297 2009/08/12 23:00:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.298 2009/08/23 19:23:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -775,6 +775,7 @@ ExecuteTruncate(TruncateStmt *stmt) EState *estate; ResultRelInfo *resultRelInfos; ResultRelInfo *resultRelInfo; + SubTransactionId mySubid; ListCell *cell; /* @@ -944,36 +945,58 @@ ExecuteTruncate(TruncateStmt *stmt) /* * OK, truncate each table. */ + mySubid = GetCurrentSubTransactionId(); + foreach(cell, rels) { Relation rel = (Relation) lfirst(cell); - Oid heap_relid; - Oid toast_relid; /* - * Create a new empty storage file for the relation, and assign it as - * the relfilenode value. The old storage file is scheduled for - * deletion at commit. + * Normally, we need a transaction-safe truncation here. However, + * if the table was either created in the current (sub)transaction + * or has a new relfilenode in the current (sub)transaction, then + * we can just truncate it in-place, because a rollback would + * cause the whole table or the current physical file to be + * thrown away anyway. */ - setNewRelfilenode(rel, RecentXmin); - - heap_relid = RelationGetRelid(rel); - toast_relid = rel->rd_rel->reltoastrelid; - - /* - * The same for the toast table, if any. - */ - if (OidIsValid(toast_relid)) + if (rel->rd_createSubid == mySubid || + rel->rd_newRelfilenodeSubid == mySubid) { - rel = relation_open(toast_relid, AccessExclusiveLock); - setNewRelfilenode(rel, RecentXmin); - heap_close(rel, NoLock); + /* Immediate, non-rollbackable truncation is OK */ + heap_truncate_one_rel(rel); } + else + { + Oid heap_relid; + Oid toast_relid; - /* - * Reconstruct the indexes to match, and we're done. - */ - reindex_relation(heap_relid, true); + /* + * Need the full transaction-safe pushups. + * + * Create a new empty storage file for the relation, and assign it + * as the relfilenode value. The old storage file is scheduled for + * deletion at commit. + */ + setNewRelfilenode(rel, RecentXmin); + + heap_relid = RelationGetRelid(rel); + toast_relid = rel->rd_rel->reltoastrelid; + + /* + * The same for the toast table, if any. + */ + if (OidIsValid(toast_relid)) + { + rel = relation_open(toast_relid, AccessExclusiveLock); + setNewRelfilenode(rel, RecentXmin); + heap_close(rel, NoLock); + } + + /* + * Reconstruct the indexes to match, and we're done. + */ + reindex_relation(heap_relid, true); + } } /* diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 2d6eb3c34ad392e140c26b2fd94489f70fac1d05..1d7449f1f10d4db075b483e0578af652e5db3c35 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.91 2009/06/11 14:49:09 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.92 2009/08/23 19:23:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -62,6 +62,8 @@ extern void heap_drop_with_catalog(Oid relid); extern void heap_truncate(List *relids); +extern void heap_truncate_one_rel(Relation rel); + extern void heap_truncate_check_FKs(List *relations, bool tempTables); extern List *heap_truncate_find_FKs(List *relationIds);