summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Momjian2002-11-23 04:05:52 +0000
committerBruce Momjian2002-11-23 04:05:52 +0000
commitd46f3de3638029179546c863f2ca0af3e86c1db6 (patch)
tree92c98e13145ff7e69bab7400b09d529718e38a42
parenta2b4a7071d86c0c150ab9ea8260a4bffc3ae863f (diff)
Transaction safe Truncate
Rod Taylor
-rw-r--r--src/backend/commands/cluster.c39
-rw-r--r--src/backend/commands/tablecmds.c29
-rw-r--r--src/include/commands/cluster.h7
-rw-r--r--src/test/regress/expected/truncate.out14
-rw-r--r--src/test/regress/sql/truncate.sql8
5 files changed, 68 insertions, 29 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 1e5a11220c6..68b1f12e082 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.95 2002/11/18 17:12:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.96 2002/11/23 04:05:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,12 +20,13 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
+#include "catalog/catname.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
-#include "catalog/catname.h"
#include "catalog/namespace.h"
+#include "catalog/pg_constraint.h"
#include "commands/cluster.h"
#include "commands/tablecmds.h"
#include "miscadmin.h"
@@ -63,7 +64,6 @@ typedef struct
static Oid make_new_heap(Oid OIDOldHeap, const char *NewName);
static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
-static List *get_indexattr_list(Relation OldHeap, Oid OldIndex);
static void recreate_indexattr(Oid OIDOldHeap, List *indexes);
static void swap_relfilenodes(Oid r1, Oid r2);
static void cluster_rel(relToCluster *rv);
@@ -92,11 +92,8 @@ static MemoryContext cluster_context = NULL;
void
cluster_rel(relToCluster *rvtc)
{
- Oid OIDNewHeap;
Relation OldHeap,
OldIndex;
- char NewHeapName[NAMEDATALEN];
- ObjectAddress object;
List *indexes;
/* Check for user-requested abort. */
@@ -172,6 +169,22 @@ cluster_rel(relToCluster *rvtc)
index_close(OldIndex);
heap_close(OldHeap, NoLock);
+ /* rebuild_rel does all the dirty work */
+ rebuild_rel(rvtc->tableOid, rvtc->indexOid, indexes, true);
+}
+
+void
+rebuild_rel(Oid tableOid, Oid indexOid, List *indexes, bool dataCopy)
+{
+ Oid OIDNewHeap;
+ char NewHeapName[NAMEDATALEN];
+ ObjectAddress object;
+
+ /*
+ * If dataCopy is true, we assume that we will be basing the
+ * copy off an index for cluster operations.
+ */
+ Assert(!dataCopy || indexOid != NULL);
/*
* Create the new heap, using a temporary name in the same namespace
* as the existing table. NOTE: there is some risk of collision with
@@ -180,10 +193,9 @@ cluster_rel(relToCluster *rvtc)
* namespace from the old, or we will have problems with the TEMP
* status of temp tables.
*/
- snprintf(NewHeapName, NAMEDATALEN, "pg_temp_%u", rvtc->tableOid);
-
- OIDNewHeap = make_new_heap(rvtc->tableOid, NewHeapName);
+ snprintf(NewHeapName, NAMEDATALEN, "pg_temp_%u", tableOid);
+ OIDNewHeap = make_new_heap(tableOid, NewHeapName);
/*
* We don't need CommandCounterIncrement() because make_new_heap did
* it.
@@ -192,13 +204,14 @@ cluster_rel(relToCluster *rvtc)
/*
* Copy the heap data into the new table in the desired order.
*/
- copy_heap_data(OIDNewHeap, rvtc->tableOid, rvtc->indexOid);
+ if (dataCopy)
+ copy_heap_data(OIDNewHeap, tableOid, indexOid);
/* To make the new heap's data visible (probably not needed?). */
CommandCounterIncrement();
/* Swap the relfilenodes of the old and new heaps. */
- swap_relfilenodes(rvtc->tableOid, OIDNewHeap);
+ swap_relfilenodes(tableOid, OIDNewHeap);
CommandCounterIncrement();
@@ -219,7 +232,7 @@ cluster_rel(relToCluster *rvtc)
* Recreate each index on the relation. We do not need
* CommandCounterIncrement() because recreate_indexattr does it.
*/
- recreate_indexattr(rvtc->tableOid, indexes);
+ recreate_indexattr(tableOid, indexes);
}
/*
@@ -322,7 +335,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
* Get the necessary info about the indexes of the relation and
* return a list of IndexAttrs structures.
*/
-static List *
+List *
get_indexattr_list(Relation OldHeap, Oid OldIndex)
{
List *indexes = NIL;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e3c3d0c2906..c545b261a5a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.55 2002/11/23 03:59:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.56 2002/11/23 04:05:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,6 +29,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
+#include "commands/cluster.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "executor/executor.h"
@@ -360,7 +361,7 @@ RemoveRelation(const RangeVar *relation, DropBehavior behavior)
* Removes all the rows from a relation.
*
* Note: This routine only does safety and permissions checks;
- * heap_truncate does the actual work.
+ * rebuild_rel in cluster.c does the actual work.
*/
void
TruncateRelation(const RangeVar *relation)
@@ -371,6 +372,7 @@ TruncateRelation(const RangeVar *relation)
Relation fkeyRel;
SysScanDesc fkeyScan;
HeapTuple tuple;
+ List *indexes;
/* Grab exclusive lock in preparation for truncate */
rel = heap_openrv(relation, AccessExclusiveLock);
@@ -400,16 +402,6 @@ TruncateRelation(const RangeVar *relation)
aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel));
/*
- * Truncate within a transaction block is dangerous, because if
- * the transaction is later rolled back we have no way to undo
- * truncation of the relation's physical file. Disallow it except for
- * a rel created in the current xact (which would be deleted on abort,
- * anyway).
- */
- if (!rel->rd_isnew)
- PreventTransactionChain((void *) relation, "TRUNCATE TABLE");
-
- /*
* Don't allow truncate on temp tables of other backends ... their
* local buffer manager is not going to cope.
*/
@@ -438,7 +430,8 @@ TruncateRelation(const RangeVar *relation)
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
if (con->contype == 'f' && con->conrelid != relid)
- elog(ERROR, "TRUNCATE cannot be used as table %s references this one via foreign key constraint %s",
+ elog(ERROR, "TRUNCATE cannot be used as table %s references "
+ "this one via foreign key constraint %s",
get_rel_name(con->conrelid),
NameStr(con->conname));
}
@@ -446,11 +439,17 @@ TruncateRelation(const RangeVar *relation)
systable_endscan(fkeyScan);
heap_close(fkeyRel, AccessShareLock);
+ /* Save the information of all indexes on the relation. */
+ indexes = get_indexattr_list(rel, InvalidOid);
+
/* Keep the lock until transaction commit */
heap_close(rel, NoLock);
- /* Do the real work */
- heap_truncate(relid);
+ /*
+ * Do the real work using the same technique as cluster, but
+ * without the code copy portion
+ */
+ rebuild_rel(relid, NULL, indexes, false);
}
/*----------
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 2490278b6ca..c83db667252 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * $Id: cluster.h,v 1.16 2002/11/15 03:09:39 momjian Exp $
+ * $Id: cluster.h,v 1.17 2002/11/23 04:05:52 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,4 +19,9 @@
*/
extern void cluster(ClusterStmt *stmt);
+extern List *get_indexattr_list(Relation OldHeap, Oid OldIndex);
+extern void rebuild_rel(Oid tableOid, Oid indexOid,
+ List *indexes, bool dataCopy);
+
+
#endif /* CLUSTER_H */
diff --git a/src/test/regress/expected/truncate.out b/src/test/regress/expected/truncate.out
index 8751b1fdb7d..2aa2f3810e3 100644
--- a/src/test/regress/expected/truncate.out
+++ b/src/test/regress/expected/truncate.out
@@ -10,7 +10,21 @@ SELECT * FROM truncate_a;
2
(2 rows)
+-- Roll truncate back
+BEGIN;
TRUNCATE truncate_a;
+ROLLBACK;
+SELECT * FROM truncate_a;
+ col1
+------
+ 1
+ 2
+(2 rows)
+
+-- Commit the truncate this time
+BEGIN;
+TRUNCATE truncate_a;
+COMMIT;
SELECT * FROM truncate_a;
col1
------
diff --git a/src/test/regress/sql/truncate.sql b/src/test/regress/sql/truncate.sql
index 5333113a9e7..79e229feac6 100644
--- a/src/test/regress/sql/truncate.sql
+++ b/src/test/regress/sql/truncate.sql
@@ -3,7 +3,15 @@ CREATE TABLE truncate_a (col1 integer primary key);
INSERT INTO truncate_a VALUES (1);
INSERT INTO truncate_a VALUES (2);
SELECT * FROM truncate_a;
+-- Roll truncate back
+BEGIN;
TRUNCATE truncate_a;
+ROLLBACK;
+SELECT * FROM truncate_a;
+-- Commit the truncate this time
+BEGIN;
+TRUNCATE truncate_a;
+COMMIT;
SELECT * FROM truncate_a;
-- Test foreign constraint check