mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-30 19:00:29 +08:00
Transaction safe Truncate
Rod Taylor
This commit is contained in:
parent
a2b4a7071d
commit
d46f3de363
@ -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;
|
||||
|
@ -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);
|
||||
@ -399,16 +401,6 @@ TruncateRelation(const RangeVar *relation)
|
||||
if (!pg_class_ownercheck(relid, GetUserId()))
|
||||
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);
|
||||
}
|
||||
|
||||
/*----------
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
------
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user