The unified diff between revisions [83b5270b..] and [5587f68e..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'sqlite/btree.c'

#
#
# patch "sqlite/btree.c"
#  from [d2e09ebf755bfd665727133361b22c6a915b12d7]
#    to [236126155d5607da945d33514218cbec762d887e]
#
============================================================
--- sqlite/btree.c	d2e09ebf755bfd665727133361b22c6a915b12d7
+++ sqlite/btree.c	236126155d5607da945d33514218cbec762d887e
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.261 2005/05/24 20:19:58 drh Exp $
+** $Id: btree.c,v 1.269 2005/09/17 15:20:27 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -234,8 +234,19 @@ typedef struct MemPage MemPage;
 /*
 ** This is a magic string that appears at the beginning of every
 ** SQLite database in order to identify the file as a real database.
-**                                  123456789 123456 */
-static const char zMagicHeader[] = "SQLite format 3";
+**
+** You can change this value at compile-time by specifying a
+** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
+** header must be exactly 16 bytes including the zero-terminator so
+** the string itself should be 15 characters long.  If you change
+** the header, then your custom library will not be able to read
+** databases generated by the standard tools and the standard tools
+** will not be able to read databases created by your custom library.
+*/
+#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
+#  define SQLITE_FILE_HEADER "SQLite format 3"
+#endif
+static const char zMagicHeader[] = SQLITE_FILE_HEADER;

 /*
 ** Page type flags.  An ORed combination of these flags appear as the
@@ -483,7 +494,7 @@ static int ptrmapPut(Btree *pBt, Pgno ke

   assert( pBt->autoVacuum );
   if( key==0 ){
-    return SQLITE_CORRUPT;
+    return SQLITE_CORRUPT_BKPT;
   }
   iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
   rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
@@ -529,7 +540,7 @@ static int ptrmapGet(Btree *pBt, Pgno ke
   if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);

   sqlite3pager_unref(pPtrmap);
-  if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT;
+  if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
   return SQLITE_OK;
 }

@@ -1019,7 +1030,7 @@ static int initPage(
   assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
   if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
     /* The parent page should never change unless the file is corrupt */
-    return SQLITE_CORRUPT; /* bkpt-CORRUPT */
+    return SQLITE_CORRUPT_BKPT;
   }
   if( pPage->isInit ) return SQLITE_OK;
   if( pPage->pParent==0 && pParent!=0 ){
@@ -1037,11 +1048,11 @@ static int initPage(
   pPage->nCell = get2byte(&data[hdr+3]);
   if( pPage->nCell>MX_CELL(pBt) ){
     /* To many cells for a single page.  The page must be corrupt */
-    return SQLITE_CORRUPT; /* bkpt-CORRUPT */
+    return SQLITE_CORRUPT_BKPT;
   }
   if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
     /* All pages must have at least one cell, except for root pages */
-    return SQLITE_CORRUPT; /* bkpt-CORRUPT */
+    return SQLITE_CORRUPT_BKPT;
   }

   /* Compute the total free space on the page */
@@ -1051,13 +1062,13 @@ static int initPage(
     int next, size;
     if( pc>usableSize-4 ){
       /* Free block is off the page */
-      return SQLITE_CORRUPT;  /* bkpt-CORRUPT */
+      return SQLITE_CORRUPT_BKPT;
     }
     next = get2byte(&data[pc]);
     size = get2byte(&data[pc+2]);
     if( next>0 && next<=pc+size+3 ){
       /* Free blocks must be in accending order */
-      return SQLITE_CORRUPT;  /* bkpt-CORRUPT */
+      return SQLITE_CORRUPT_BKPT;
     }
     nFree += size;
     pc = next;
@@ -1065,7 +1076,7 @@ static int initPage(
   pPage->nFree = nFree;
   if( nFree>=usableSize ){
     /* Free space cannot exceed total page size */
-    return SQLITE_CORRUPT;  /* bkpt-CORRUPT */
+    return SQLITE_CORRUPT_BKPT;
   }

   pPage->isInit = 1;
@@ -1135,7 +1146,7 @@ static int getAndInitPage(
 ){
   int rc;
   if( pgno==0 ){
-    return SQLITE_CORRUPT;  /* bkpt-CORRUPT */
+    return SQLITE_CORRUPT_BKPT;
   }
   rc = getPage(pBt, pgno, ppPage);
   if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
@@ -1334,6 +1345,15 @@ int sqlite3BtreeSetSafetyLevel(Btree *pB
 }
 #endif

+/*
+** Return TRUE if the given btree is set to safety level 1.  In other
+** words, return TRUE if no sync() occurs on the disk files.
+*/
+int sqlite3BtreeSyncDisabled(Btree *pBt){
+  assert( pBt && pBt->pPager );
+  return sqlite3pager_nosync(pBt->pPager);
+}
+
 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
 /*
 ** Change the default pages size and the number of reserved bytes per page.
@@ -1595,8 +1615,6 @@ int sqlite3BtreeBeginTrans(Btree *pBt, i
 */
 int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
   int rc = SQLITE_OK;
-  int busy = 0;
-  BusyHandler *pH;

   /* If the btree is already in a write-transaction, or it
   ** is already in a read-transaction and a read-transaction
@@ -1630,9 +1648,7 @@ int sqlite3BtreeBeginTrans(Btree *pBt, i
       unlockBtreeIfUnused(pBt);
     }
   }while( rc==SQLITE_BUSY && pBt->inTrans==TRANS_NONE &&
-      (pH = pBt->pBusyHandler)!=0 &&
-      pH->xFunc && pH->xFunc(pH->pArg, busy++)
-  );
+          sqlite3InvokeBusyHandler(pBt->pBusyHandler) );
   return rc;
 }

@@ -1698,7 +1714,7 @@ static int modifyPagePointer(MemPage *pP
   if( eType==PTRMAP_OVERFLOW2 ){
     /* The pointer is always the first 4 bytes of the page in this case.  */
     if( get4byte(pPage->aData)!=iFrom ){
-      return SQLITE_CORRUPT;
+      return SQLITE_CORRUPT_BKPT;
     }
     put4byte(pPage->aData, iTo);
   }else{
@@ -1731,7 +1747,7 @@ static int modifyPagePointer(MemPage *pP
     if( i==nCell ){
       if( eType!=PTRMAP_BTREE ||
           get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
-        return SQLITE_CORRUPT;
+        return SQLITE_CORRUPT_BKPT;
       }
       put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
     }
@@ -1844,7 +1860,7 @@ static int autoVacuumCommit(Btree *pBt,

   assert( pBt->autoVacuum );
   if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
-    return SQLITE_CORRUPT;
+    return SQLITE_CORRUPT_BKPT;
   }

   /* Figure out how many free-pages are in the database. If there are no
@@ -1859,7 +1875,7 @@ static int autoVacuumCommit(Btree *pBt,
   origSize = sqlite3pager_pagecount(pPager);
   nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
   finSize = origSize - nFreeList - nPtrMap;
-  if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
+  if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
     finSize--;
     if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
       finSize--;
@@ -1882,7 +1898,7 @@ static int autoVacuumCommit(Btree *pBt,
     rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage);
     if( rc!=SQLITE_OK ) goto autovacuum_out;
     if( eType==PTRMAP_ROOTPAGE ){
-      rc = SQLITE_CORRUPT;
+      rc = SQLITE_CORRUPT_BKPT;
       goto autovacuum_out;
     }

@@ -2398,7 +2414,7 @@ static int getPayload(
   }

   if( amt>0 ){
-    return SQLITE_CORRUPT; /* bkpt-CORRUPT */
+    return SQLITE_CORRUPT_BKPT;
   }
   return SQLITE_OK;
 }
@@ -2416,7 +2432,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32
   assert( pCur->isValid );
   assert( pCur->pPage!=0 );
   if( pCur->pPage->intKey ){
-    return SQLITE_CORRUPT;
+    return SQLITE_CORRUPT_BKPT;
   }
   assert( pCur->pPage->intKey==0 );
   assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
@@ -2465,13 +2481,11 @@ static const unsigned char *fetchPayload
 ){
   unsigned char *aPayload;
   MemPage *pPage;
-  Btree *pBt;
   u32 nKey;
   int nLocal;

   assert( pCur!=0 && pCur->pPage!=0 );
   assert( pCur->isValid );
-  pBt = pCur->pBt;
   pPage = pCur->pPage;
   pageIntegrity(pPage);
   assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
@@ -2538,7 +2552,7 @@ static int moveToChild(BtCursor *pCur, u
   pCur->idx = 0;
   pCur->info.nSize = 0;
   if( pNewPage->nCell<1 ){
-    return SQLITE_CORRUPT; /* bkpt-CORRUPT */
+    return SQLITE_CORRUPT_BKPT;
   }
   return SQLITE_OK;
 }
@@ -2569,7 +2583,6 @@ static void moveToParent(BtCursor *pCur)
 ** the largest cell index.
 */
 static void moveToParent(BtCursor *pCur){
-  Pgno oldPgno;
   MemPage *pParent;
   MemPage *pPage;
   int idxParent;
@@ -2584,7 +2597,6 @@ static void moveToParent(BtCursor *pCur)
   pageIntegrity(pParent);
   idxParent = pPage->idxParent;
   sqlite3pager_ref(pParent->aData);
-  oldPgno = pPage->pgno;
   releasePage(pPage);
   pCur->pPage = pParent;
   pCur->info.nSize = 0;
@@ -2749,7 +2761,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, c
     lwr = 0;
     upr = pPage->nCell-1;
     if( !pPage->intKey && pKey==0 ){
-      return SQLITE_CORRUPT;
+      return SQLITE_CORRUPT_BKPT;
     }
     pageIntegrity(pPage);
     while( lwr<=upr ){
@@ -3034,7 +3046,7 @@ static int allocatePage(
         TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
       }else if( k>pBt->usableSize/4 - 8 ){
         /* Value of k is out of range.  Database corruption */
-        return SQLITE_CORRUPT; /* bkpt-CORRUPT */
+        return SQLITE_CORRUPT_BKPT;
 #ifndef SQLITE_OMIT_AUTOVACUUM
       }else if( searchList && nearby==iTrunk ){
         /* The list is being searched and this trunk page is the page
@@ -3109,7 +3121,7 @@ static int allocatePage(
           *pPgno = iPage;
           if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
             /* Free page off the end of the file */
-            return SQLITE_CORRUPT; /* bkpt-CORRUPT */
+            return SQLITE_CORRUPT_BKPT;
           }
           TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
                  ": %d more free pages\n",
@@ -3250,7 +3262,7 @@ static int clearCell(MemPage *pPage, uns
   while( ovflPgno!=0 ){
     MemPage *pOvfl;
     if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){
-      return SQLITE_CORRUPT;
+      return SQLITE_CORRUPT_BKPT;
     }
     rc = getPage(pBt, ovflPgno, &pOvfl);
     if( rc ) return rc;
@@ -3595,17 +3607,19 @@ static void assemblePage(
   data = pPage->aData;
   hdr = pPage->hdrOffset;
   put2byte(&data[hdr+3], nCell);
-  cellbody = allocateSpace(pPage, totalSize);
-  assert( cellbody>0 );
-  assert( pPage->nFree >= 2*nCell );
-  pPage->nFree -= 2*nCell;
-  for(i=0; i<nCell; i++){
-    put2byte(&data[cellptr], cellbody);
-    memcpy(&data[cellbody], apCell[i], aSize[i]);
-    cellptr += 2;
-    cellbody += aSize[i];
+  if( nCell ){
+    cellbody = allocateSpace(pPage, totalSize);
+    assert( cellbody>0 );
+    assert( pPage->nFree >= 2*nCell );
+    pPage->nFree -= 2*nCell;
+    for(i=0; i<nCell; i++){
+      put2byte(&data[cellptr], cellbody);
+      memcpy(&data[cellbody], apCell[i], aSize[i]);
+      cellptr += 2;
+      cellbody += aSize[i];
+    }
+    assert( cellbody==pPage->pBt->usableSize );
   }
-  assert( cellbody==pPage->pBt->usableSize );
   pPage->nCell = nCell;
 }

@@ -3809,7 +3823,7 @@ static int balance_nonroot(MemPage *pPag
   /*
   ** A special case:  If a new entry has just been inserted into a
   ** table (that is, a btree with integer keys and all data at the leaves)
-  ** an the new entry is the right-most entry in the tree (it has the
+  ** and the new entry is the right-most entry in the tree (it has the
   ** largest key) then use the special balance_quick() routine for
   ** balancing.  balance_quick() is much faster and results in a tighter
   ** packing of data in the common case.
@@ -4082,8 +4096,13 @@ static int balance_nonroot(MemPage *pPag
     szNew[i] = szRight;
     szNew[i-1] = szLeft;
   }
-  assert( cntNew[0]>0 );

+  /* Either we found one or more cells (cntnew[0])>0) or we are the
+  ** a virtual root page.  A virtual root page is when the real root
+  ** page is page 1 and we are the only child of that page.
+  */
+  assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) );
+
   /*
   ** Allocate k new pages.  Reuse old pages where possible.
   */
@@ -4171,7 +4190,7 @@ static int balance_nonroot(MemPage *pPag
     assert( j<nMaxCells );
     assert( pNew->pgno==pgnoNew[i] );
     assemblePage(pNew, cntNew[i]-j, &apCell[j], &szCell[j]);
-    assert( pNew->nCell>0 );
+    assert( pNew->nCell>0 || (nNew==1 && cntNew[0]==0) );
     assert( pNew->nOverflow==0 );

 #ifndef SQLITE_OMIT_AUTOVACUUM
@@ -4649,7 +4668,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
     rc = sqlite3BtreeNext(&leafCur, &notUsed);
     if( rc!=SQLITE_OK ){
       if( rc!=SQLITE_NOMEM ){
-        rc = SQLITE_CORRUPT;  /* bkpt-CORRUPT */
+        rc = SQLITE_CORRUPT_BKPT;
       }
     }
     if( rc==SQLITE_OK ){
@@ -4835,7 +4854,7 @@ static int clearDatabasePage(
   int i;

   if( pgno>sqlite3pager_pagecount(pBt->pPager) ){
-    return SQLITE_CORRUPT;
+    return SQLITE_CORRUPT_BKPT;
   }

   rc = getAndInitPage(pBt, pgno, &pPage, pParent);
@@ -5457,7 +5476,7 @@ static int checkTreePage(
   u8 *data;
   BtCursor cur;
   Btree *pBt;
-  int maxLocal, usableSize;
+  int usableSize;
   char zContext[100];
   char *hit;

@@ -5474,7 +5493,6 @@ static int checkTreePage(
        "unable to get the page. error code=%d", rc);
     return 0;
   }
-  maxLocal = pPage->leafData ? pBt->maxLeaf : pBt->maxLocal;
   if( (rc = initPage(pPage, pParent))!=0 ){
     checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
     releasePage(pPage);
@@ -5721,7 +5739,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, B
 */
 int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
   int rc = SQLITE_OK;
-  Pgno i, nPage, nToPage;
+  Pgno i, nPage, nToPage, iSkip;

   if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
     return SQLITE_ERROR;
@@ -5729,8 +5747,10 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, B
   if( pBtTo->pCursor ) return SQLITE_BUSY;
   nToPage = sqlite3pager_pagecount(pBtTo->pPager);
   nPage = sqlite3pager_pagecount(pBtFrom->pPager);
+  iSkip = PENDING_BYTE_PAGE(pBtTo);
   for(i=1; rc==SQLITE_OK && i<=nPage; i++){
     void *pPage;
+    if( i==iSkip ) continue;
     rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
     if( rc ) break;
     rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
@@ -5739,6 +5759,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, B
   }
   for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
     void *pPage;
+    if( i==iSkip ) continue;
     rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
     if( rc ) break;
     rc = sqlite3pager_write(pPage);