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.
This commit is contained in:
Tom Lane 2000-09-30 18:28:53 +00:00
parent 0ba77c14aa
commit 36786a8150
1 changed files with 24 additions and 28 deletions

View File

@ -8,7 +8,7 @@
*
*
* 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
@ -1064,32 +1064,32 @@ DeleteRelationTuple(Relation rel)
* RelationTruncateIndexes - This routine is used to truncate all
* indices associated with the heap relation to zero tuples.
* 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
RelationTruncateIndexes(Relation heapRelation)
RelationTruncateIndexes(Oid heapId)
{
Relation indexRelation,
currentIndex;
Relation indexRelation;
ScanKeyData entry;
HeapScanDesc scan;
HeapTuple indexTuple,
classTuple;
IndexInfo *indexInfo;
Oid heapId,
indexId,
accessMethodId;
HeapTuple indexTuple;
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);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
ObjectIdGetDatum(heapId));
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
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
*/
@ -1105,10 +1105,16 @@ RelationTruncateIndexes(Relation heapRelation)
indexId);
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 */
currentIndex = index_open(indexId);
if (currentIndex == NULL)
elog(ERROR, "RelationTruncateIndexes: can't open index relation");
/* Obtain exclusive lock on it, just to be sure */
LockRelation(currentIndex, AccessExclusiveLock);
@ -1127,15 +1133,10 @@ RelationTruncateIndexes(Relation heapRelation)
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
currentIndex, accessMethodId);
index_build(heapRelation, currentIndex, indexInfo, NULL);
/*
* 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
* 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.
* not give up the locks we hold on them).
*/
heapRelation = heap_open(heapId, NoLock);
}
/* Complete the scan and close pg_index */
@ -1191,17 +1192,12 @@ heap_truncate(char *relname)
rel->rd_nblocks = 0;
/* If this relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rel);
RelationTruncateIndexes(rid);
/*
* Close the relation, but keep exclusive lock on it until commit.
*/
heap_close(rel, NoLock);
/*
* Is this really necessary?
*/
RelationForgetRelation(rid);
}