Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d46f3de

Browse files
committed
Transaction safe Truncate
Rod Taylor
1 parent a2b4a70 commit d46f3de

File tree

5 files changed

+68
-29
lines changed

5 files changed

+68
-29
lines changed

src/backend/commands/cluster.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.95 2002/11/18 17:12:07 momjian Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.96 2002/11/23 04:05:51 momjian Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -20,12 +20,13 @@
2020
#include "access/genam.h"
2121
#include "access/heapam.h"
2222
#include "catalog/catalog.h"
23+
#include "catalog/catname.h"
2324
#include "catalog/dependency.h"
2425
#include "catalog/heap.h"
2526
#include "catalog/index.h"
2627
#include "catalog/indexing.h"
27-
#include "catalog/catname.h"
2828
#include "catalog/namespace.h"
29+
#include "catalog/pg_constraint.h"
2930
#include "commands/cluster.h"
3031
#include "commands/tablecmds.h"
3132
#include "miscadmin.h"
@@ -63,7 +64,6 @@ typedef struct
6364

6465
static Oid make_new_heap(Oid OIDOldHeap, const char *NewName);
6566
static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
66-
static List *get_indexattr_list(Relation OldHeap, Oid OldIndex);
6767
static void recreate_indexattr(Oid OIDOldHeap, List *indexes);
6868
static void swap_relfilenodes(Oid r1, Oid r2);
6969
static void cluster_rel(relToCluster *rv);
@@ -92,11 +92,8 @@ static MemoryContext cluster_context = NULL;
9292
void
9393
cluster_rel(relToCluster *rvtc)
9494
{
95-
Oid OIDNewHeap;
9695
Relation OldHeap,
9796
OldIndex;
98-
char NewHeapName[NAMEDATALEN];
99-
ObjectAddress object;
10097
List *indexes;
10198

10299
/* Check for user-requested abort. */
@@ -172,6 +169,22 @@ cluster_rel(relToCluster *rvtc)
172169
index_close(OldIndex);
173170
heap_close(OldHeap, NoLock);
174171

172+
/* rebuild_rel does all the dirty work */
173+
rebuild_rel(rvtc->tableOid, rvtc->indexOid, indexes, true);
174+
}
175+
176+
void
177+
rebuild_rel(Oid tableOid, Oid indexOid, List *indexes, bool dataCopy)
178+
{
179+
Oid OIDNewHeap;
180+
char NewHeapName[NAMEDATALEN];
181+
ObjectAddress object;
182+
183+
/*
184+
* If dataCopy is true, we assume that we will be basing the
185+
* copy off an index for cluster operations.
186+
*/
187+
Assert(!dataCopy || indexOid != NULL);
175188
/*
176189
* Create the new heap, using a temporary name in the same namespace
177190
* as the existing table. NOTE: there is some risk of collision with
@@ -180,10 +193,9 @@ cluster_rel(relToCluster *rvtc)
180193
* namespace from the old, or we will have problems with the TEMP
181194
* status of temp tables.
182195
*/
183-
snprintf(NewHeapName, NAMEDATALEN, "pg_temp_%u", rvtc->tableOid);
184-
185-
OIDNewHeap = make_new_heap(rvtc->tableOid, NewHeapName);
196+
snprintf(NewHeapName, NAMEDATALEN, "pg_temp_%u", tableOid);
186197

198+
OIDNewHeap = make_new_heap(tableOid, NewHeapName);
187199
/*
188200
* We don't need CommandCounterIncrement() because make_new_heap did
189201
* it.
@@ -192,13 +204,14 @@ cluster_rel(relToCluster *rvtc)
192204
/*
193205
* Copy the heap data into the new table in the desired order.
194206
*/
195-
copy_heap_data(OIDNewHeap, rvtc->tableOid, rvtc->indexOid);
207+
if (dataCopy)
208+
copy_heap_data(OIDNewHeap, tableOid, indexOid);
196209

197210
/* To make the new heap's data visible (probably not needed?). */
198211
CommandCounterIncrement();
199212

200213
/* Swap the relfilenodes of the old and new heaps. */
201-
swap_relfilenodes(rvtc->tableOid, OIDNewHeap);
214+
swap_relfilenodes(tableOid, OIDNewHeap);
202215

203216
CommandCounterIncrement();
204217

@@ -219,7 +232,7 @@ cluster_rel(relToCluster *rvtc)
219232
* Recreate each index on the relation. We do not need
220233
* CommandCounterIncrement() because recreate_indexattr does it.
221234
*/
222-
recreate_indexattr(rvtc->tableOid, indexes);
235+
recreate_indexattr(tableOid, indexes);
223236
}
224237

225238
/*
@@ -322,7 +335,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
322335
* Get the necessary info about the indexes of the relation and
323336
* return a list of IndexAttrs structures.
324337
*/
325-
static List *
338+
List *
326339
get_indexattr_list(Relation OldHeap, Oid OldIndex)
327340
{
328341
List *indexes = NIL;

src/backend/commands/tablecmds.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.55 2002/11/23 03:59:07 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.56 2002/11/23 04:05:51 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -29,6 +29,7 @@
2929
#include "catalog/pg_opclass.h"
3030
#include "catalog/pg_trigger.h"
3131
#include "catalog/pg_type.h"
32+
#include "commands/cluster.h"
3233
#include "commands/tablecmds.h"
3334
#include "commands/trigger.h"
3435
#include "executor/executor.h"
@@ -360,7 +361,7 @@ RemoveRelation(const RangeVar *relation, DropBehavior behavior)
360361
* Removes all the rows from a relation.
361362
*
362363
* Note: This routine only does safety and permissions checks;
363-
* heap_truncate does the actual work.
364+
* rebuild_rel in cluster.c does the actual work.
364365
*/
365366
void
366367
TruncateRelation(const RangeVar *relation)
@@ -371,6 +372,7 @@ TruncateRelation(const RangeVar *relation)
371372
Relation fkeyRel;
372373
SysScanDesc fkeyScan;
373374
HeapTuple tuple;
375+
List *indexes;
374376

375377
/* Grab exclusive lock in preparation for truncate */
376378
rel = heap_openrv(relation, AccessExclusiveLock);
@@ -399,16 +401,6 @@ TruncateRelation(const RangeVar *relation)
399401
if (!pg_class_ownercheck(relid, GetUserId()))
400402
aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel));
401403

402-
/*
403-
* Truncate within a transaction block is dangerous, because if
404-
* the transaction is later rolled back we have no way to undo
405-
* truncation of the relation's physical file. Disallow it except for
406-
* a rel created in the current xact (which would be deleted on abort,
407-
* anyway).
408-
*/
409-
if (!rel->rd_isnew)
410-
PreventTransactionChain((void *) relation, "TRUNCATE TABLE");
411-
412404
/*
413405
* Don't allow truncate on temp tables of other backends ... their
414406
* local buffer manager is not going to cope.
@@ -438,19 +430,26 @@ TruncateRelation(const RangeVar *relation)
438430
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
439431

440432
if (con->contype == 'f' && con->conrelid != relid)
441-
elog(ERROR, "TRUNCATE cannot be used as table %s references this one via foreign key constraint %s",
433+
elog(ERROR, "TRUNCATE cannot be used as table %s references "
434+
"this one via foreign key constraint %s",
442435
get_rel_name(con->conrelid),
443436
NameStr(con->conname));
444437
}
445438

446439
systable_endscan(fkeyScan);
447440
heap_close(fkeyRel, AccessShareLock);
448441

442+
/* Save the information of all indexes on the relation. */
443+
indexes = get_indexattr_list(rel, InvalidOid);
444+
449445
/* Keep the lock until transaction commit */
450446
heap_close(rel, NoLock);
451447

452-
/* Do the real work */
453-
heap_truncate(relid);
448+
/*
449+
* Do the real work using the same technique as cluster, but
450+
* without the code copy portion
451+
*/
452+
rebuild_rel(relid, NULL, indexes, false);
454453
}
455454

456455
/*----------

src/include/commands/cluster.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994-5, Regents of the University of California
88
*
9-
* $Id: cluster.h,v 1.16 2002/11/15 03:09:39 momjian Exp $
9+
* $Id: cluster.h,v 1.17 2002/11/23 04:05:52 momjian Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -19,4 +19,9 @@
1919
*/
2020
extern void cluster(ClusterStmt *stmt);
2121

22+
extern List *get_indexattr_list(Relation OldHeap, Oid OldIndex);
23+
extern void rebuild_rel(Oid tableOid, Oid indexOid,
24+
List *indexes, bool dataCopy);
25+
26+
2227
#endif /* CLUSTER_H */

src/test/regress/expected/truncate.out

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,21 @@ SELECT * FROM truncate_a;
1010
2
1111
(2 rows)
1212

13+
-- Roll truncate back
14+
BEGIN;
1315
TRUNCATE truncate_a;
16+
ROLLBACK;
17+
SELECT * FROM truncate_a;
18+
col1
19+
------
20+
1
21+
2
22+
(2 rows)
23+
24+
-- Commit the truncate this time
25+
BEGIN;
26+
TRUNCATE truncate_a;
27+
COMMIT;
1428
SELECT * FROM truncate_a;
1529
col1
1630
------

src/test/regress/sql/truncate.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@ CREATE TABLE truncate_a (col1 integer primary key);
33
INSERT INTO truncate_a VALUES (1);
44
INSERT INTO truncate_a VALUES (2);
55
SELECT * FROM truncate_a;
6+
-- Roll truncate back
7+
BEGIN;
68
TRUNCATE truncate_a;
9+
ROLLBACK;
10+
SELECT * FROM truncate_a;
11+
-- Commit the truncate this time
12+
BEGIN;
13+
TRUNCATE truncate_a;
14+
COMMIT;
715
SELECT * FROM truncate_a;
816

917
-- Test foreign constraint check

0 commit comments

Comments
 (0)