Commit 36786a81 authored by Tom Lane's avatar Tom Lane

Fix nasty TRUNCATE bug reported by Darrin Ladd. RelationTruncateIndexes

would close and then re-open rel being truncated.  Depending on the
luck of the draw, the re-opened relcache entry might or might not be
at the same physical location as before.  Unfortunately, if it wasn't
then heap_truncate would crash and burn, because it still had a pointer
at the old location.  Fix is to open and then close rel in
RelationTruncateIndexes, so that rel's refcount never goes to zero
until heap_truncate is done.
parent 0ba77c14
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.145 2000/09/29 18:21:25 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.146 2000/09/30 18:28:53 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1064,32 +1064,32 @@ DeleteRelationTuple(Relation rel) ...@@ -1064,32 +1064,32 @@ DeleteRelationTuple(Relation rel)
* RelationTruncateIndexes - This routine is used to truncate all * RelationTruncateIndexes - This routine is used to truncate all
* indices associated with the heap relation to zero tuples. * indices associated with the heap relation to zero tuples.
* The routine will truncate and then reconstruct the indices on * The routine will truncate and then reconstruct the indices on
* the relation specified by the heapRelation parameter. * the relation specified by the heapId parameter.
* -------------------------------- * --------------------------------
*/ */
static void static void
RelationTruncateIndexes(Relation heapRelation) RelationTruncateIndexes(Oid heapId)
{ {
Relation indexRelation, Relation indexRelation;
currentIndex;
ScanKeyData entry; ScanKeyData entry;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple indexTuple, HeapTuple indexTuple;
classTuple;
IndexInfo *indexInfo;
Oid heapId,
indexId,
accessMethodId;
heapId = RelationGetRelid(heapRelation);
/* Scan pg_index to find indexes on heapRelation */ /* Scan pg_index to find indexes on specified heap */
indexRelation = heap_openr(IndexRelationName, AccessShareLock); indexRelation = heap_openr(IndexRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ, ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
ObjectIdGetDatum(heapId)); ObjectIdGetDatum(heapId));
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry); scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0))) while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
{ {
Oid indexId,
accessMethodId;
IndexInfo *indexInfo;
HeapTuple classTuple;
Relation heapRelation,
currentIndex;
/* /*
* For each index, fetch info needed for index_build * For each index, fetch info needed for index_build
*/ */
...@@ -1105,10 +1105,16 @@ RelationTruncateIndexes(Relation heapRelation) ...@@ -1105,10 +1105,16 @@ RelationTruncateIndexes(Relation heapRelation)
indexId); indexId);
accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam; accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
/*
* We have to re-open the heap rel each time through this loop
* because index_build will close it again. We need grab no lock,
* however, because we assume heap_truncate is holding an exclusive
* lock on the heap rel.
*/
heapRelation = heap_open(heapId, NoLock);
/* Open the index relation */ /* Open the index relation */
currentIndex = index_open(indexId); currentIndex = index_open(indexId);
if (currentIndex == NULL)
elog(ERROR, "RelationTruncateIndexes: can't open index relation");
/* Obtain exclusive lock on it, just to be sure */ /* Obtain exclusive lock on it, just to be sure */
LockRelation(currentIndex, AccessExclusiveLock); LockRelation(currentIndex, AccessExclusiveLock);
...@@ -1127,15 +1133,10 @@ RelationTruncateIndexes(Relation heapRelation) ...@@ -1127,15 +1133,10 @@ RelationTruncateIndexes(Relation heapRelation)
InitIndexStrategy(indexInfo->ii_NumIndexAttrs, InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
currentIndex, accessMethodId); currentIndex, accessMethodId);
index_build(heapRelation, currentIndex, indexInfo, NULL); index_build(heapRelation, currentIndex, indexInfo, NULL);
/* /*
* index_build will close both the heap and index relations (but * index_build will close both the heap and index relations (but
* not give up the locks we hold on them). That's fine for the * not give up the locks we hold on them).
* index, but we need to open the heap again. We need no new
* lock, since this backend still has the exclusive lock grabbed
* by heap_truncate.
*/ */
heapRelation = heap_open(heapId, NoLock);
} }
/* Complete the scan and close pg_index */ /* Complete the scan and close pg_index */
...@@ -1191,17 +1192,12 @@ heap_truncate(char *relname) ...@@ -1191,17 +1192,12 @@ heap_truncate(char *relname)
rel->rd_nblocks = 0; rel->rd_nblocks = 0;
/* If this relation has indexes, truncate the indexes too */ /* If this relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rel); RelationTruncateIndexes(rid);
/* /*
* 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_close(rel, NoLock);
/*
* Is this really necessary?
*/
RelationForgetRelation(rid);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment