Fix nasty TRUNCATE bug reported by Darrin Ladd. RelationTruncateIndexes
authorTom Lane
Sat, 30 Sep 2000 18:28:53 +0000 (18:28 +0000)
committerTom Lane
Sat, 30 Sep 2000 18:28:53 +0000 (18:28 +0000)
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.

src/backend/catalog/heap.c

index 1e4dca2b304874b533159d771e14e9a17400a35c..e7935b48714b5cb25861ef2fae5642d9eba86520 100644 (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;
-
-   heapId = RelationGetRelid(heapRelation);
+   HeapTuple   indexTuple;
 
-   /* 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);
 }