? src/backend/commands/.tablecmds.c.swp Index: src/backend/commands/cluster.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/cluster.c,v retrieving revision 1.94 diff -c -r1.94 cluster.c *** src/backend/commands/cluster.c 2002/11/15 03:09:35 1.94 --- src/backend/commands/cluster.c 2002/11/18 16:45:18 *************** *** 20,31 **** #include "access/genam.h" #include "access/heapam.h" #include "catalog/catalog.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 "commands/cluster.h" #include "commands/tablecmds.h" #include "miscadmin.h" --- 20,32 ---- #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/namespace.h" + #include "catalog/pg_constraint.h" #include "commands/cluster.h" #include "commands/tablecmds.h" #include "miscadmin.h" *************** *** 63,69 **** 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); --- 64,69 ---- *************** *** 92,102 **** void cluster_rel(relToCluster *rvtc) { - Oid OIDNewHeap; Relation OldHeap, OldIndex; - char NewHeapName[NAMEDATALEN]; - ObjectAddress object; List *indexes; /* Check for user-requested abort. */ --- 92,99 ---- *************** *** 172,177 **** --- 169,190 ---- 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,189 **** * 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); /* * We don't need CommandCounterIncrement() because make_new_heap did * it. --- 193,201 ---- * namespace from the old, or we will have problems with the TEMP * status of temp tables. */ ! 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,204 **** /* * Copy the heap data into the new table in the desired order. */ ! copy_heap_data(OIDNewHeap, rvtc->tableOid, rvtc->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); CommandCounterIncrement(); --- 204,217 ---- /* * Copy the heap data into the new table in the desired order. */ ! 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(tableOid, OIDNewHeap); CommandCounterIncrement(); *************** *** 219,225 **** * Recreate each index on the relation. We do not need * CommandCounterIncrement() because recreate_indexattr does it. */ ! recreate_indexattr(rvtc->tableOid, indexes); } /* --- 232,238 ---- * Recreate each index on the relation. We do not need * CommandCounterIncrement() because recreate_indexattr does it. */ ! recreate_indexattr(tableOid, indexes); } /* *************** *** 322,328 **** * Get the necessary info about the indexes of the relation and * return a list of IndexAttrs structures. */ ! static List * get_indexattr_list(Relation OldHeap, Oid OldIndex) { List *indexes = NIL; --- 335,341 ---- * Get the necessary info about the indexes of the relation and * return a list of IndexAttrs structures. */ ! List * get_indexattr_list(Relation OldHeap, Oid OldIndex) { List *indexes = NIL; Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/tablecmds.c,v retrieving revision 1.54 diff -c -r1.54 tablecmds.c *** src/backend/commands/tablecmds.c 2002/11/15 02:50:05 1.54 --- src/backend/commands/tablecmds.c 2002/11/18 16:45:22 *************** *** 29,34 **** --- 29,35 ---- #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,366 **** * Removes all the rows from a relation. * * Note: This routine only does safety and permissions checks; ! * heap_truncate does the actual work. */ void TruncateRelation(const RangeVar *relation) --- 361,367 ---- * Removes all the rows from a relation. * * Note: This routine only does safety and permissions checks; ! * rebuild_rel in cluster.c does the actual work. */ void TruncateRelation(const RangeVar *relation) *************** *** 371,376 **** --- 372,378 ---- Relation fkeyRel; SysScanDesc fkeyScan; HeapTuple tuple; + List *indexes; /* Grab exclusive lock in preparation for truncate */ rel = heap_openrv(relation, AccessExclusiveLock); *************** *** 400,415 **** 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. */ --- 402,407 ---- *************** *** 438,444 **** 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", get_rel_name(con->conrelid), NameStr(con->conname)); } --- 430,437 ---- 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", get_rel_name(con->conrelid), NameStr(con->conname)); } *************** *** 446,456 **** systable_endscan(fkeyScan); heap_close(fkeyRel, AccessShareLock); /* Keep the lock until transaction commit */ heap_close(rel, NoLock); ! /* Do the real work */ ! heap_truncate(relid); } /*---------- --- 439,455 ---- 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 using the same technique as cluster, but ! * without the code copy portion ! */ ! rebuild_rel(relid, NULL, indexes, false); } /*---------- Index: src/include/commands/cluster.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/commands/cluster.h,v retrieving revision 1.16 diff -c -r1.16 cluster.h *** src/include/commands/cluster.h 2002/11/15 03:09:39 1.16 --- src/include/commands/cluster.h 2002/11/18 16:45:26 *************** *** 19,22 **** --- 19,27 ---- */ 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 */ Index: src/test/regress/expected/truncate.out =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/expected/truncate.out,v retrieving revision 1.2 diff -c -r1.2 truncate.out *** src/test/regress/expected/truncate.out 2002/08/22 14:23:36 1.2 --- src/test/regress/expected/truncate.out 2002/11/18 16:45:28 *************** *** 10,16 **** --- 10,30 ---- 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 ------ Index: src/test/regress/sql/truncate.sql =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/sql/truncate.sql,v retrieving revision 1.1 diff -c -r1.1 truncate.sql *** src/test/regress/sql/truncate.sql 2002/08/22 04:51:06 1.1 --- src/test/regress/sql/truncate.sql 2002/11/18 16:45:28 *************** *** 3,9 **** --- 3,17 ---- 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