Try to detect oversize tuple before corrupting relation, instead of
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Nov 1999 04:34:55 +0000 (04:34 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Nov 1999 04:34:55 +0000 (04:34 +0000)
after...

src/backend/access/heap/hio.c

index 595c79e0236f50ee380f1fd7e92129068b764a15..d21d219c10c9eea4941ba07ee703544d58eeba1e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Id: hio.c,v 1.26 1999/07/19 07:07:18 momjian Exp $
+ *   $Id: hio.c,v 1.27 1999/11/29 04:34:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,10 +107,20 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
    ItemId      itemId;
    Item        item;
 
+   len = (unsigned) MAXALIGN(tuple->t_len); /* be conservative */
+
+   /*
+    * If we're gonna fail for oversize tuple, do it right away...
+    * this code should go away eventually.
+    */
+   if (len > MaxTupleSize)
+       elog(ERROR, "Tuple is too big: size %d, max size %d",
+            len, MaxTupleSize);
+
    /*
-    * Lock relation for extention. We can use LockPage here as long as in
+    * Lock relation for extension. We can use LockPage here as long as in
     * all other places we use page-level locking for indices only.
-    * Alternatevely, we could define pseudo-table as we do for
+    * Alternatively, we could define pseudo-table as we do for
     * transactions with XactLockTable.
     */
    if (!relation->rd_myxactonly)
@@ -122,17 +132,17 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
     * relation.  A good optimization would be to get this to actually
     * work properly.
     */
-
    lastblock = RelationGetNumberOfBlocks(relation);
 
+   /*
+    * Get the last existing page --- may need to create the first one
+    * if this is a virgin relation.
+    */
    if (lastblock == 0)
    {
+       /* what exactly is this all about??? */
        buffer = ReadBuffer(relation, lastblock);
        pageHeader = (Page) BufferGetPage(buffer);
-
-       /*
-        * There was IF instead of ASSERT here ?!
-        */
        Assert(PageIsNew((PageHeader) pageHeader));
        buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
        pageHeader = (Page) BufferGetPage(buffer);
@@ -143,13 +153,10 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
 
    LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
    pageHeader = (Page) BufferGetPage(buffer);
-   len = (unsigned) MAXALIGN(tuple->t_len); /* be conservative */
 
    /*
-    * Note that this is true if the above returned a bogus page, which it
-    * will do for a completely empty relation.
+    * Is there room on the last existing page?
     */
-
    if (len > PageGetFreeSpace(pageHeader))
    {
        LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
@@ -159,12 +166,18 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
        PageInit(pageHeader, BufferGetPageSize(buffer), 0);
 
        if (len > PageGetFreeSpace(pageHeader))
+       {
+           /*
+            * BUG: by elog'ing here, we leave the new buffer locked and not
+            * marked dirty, which may result in an invalid page header
+            * being left on disk.  But we should not get here given the
+            * test at the top of the routine, and the whole deal should
+            * go away when we implement tuple splitting anyway...
+            */
            elog(ERROR, "Tuple is too big: size %d", len);
+       }
    }
 
-   if (len > MaxTupleSize)
-       elog(ERROR, "Tuple is too big: size %d, max size %d", len, MaxTupleSize);
-
    if (!relation->rd_myxactonly)
        UnlockPage(relation, 0, ExclusiveLock);
 
@@ -178,7 +191,7 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
 
    ItemPointerSet(&((HeapTupleHeader) item)->t_ctid, lastblock, offnum);
 
-   /* return an accurate tuple */
+   /* return an accurate tuple self-pointer */
    ItemPointerSet(&tuple->t_self, lastblock, offnum);
 
    LockBuffer(buffer, BUFFER_LOCK_UNLOCK);