Browse Source

Update sqlite3.(c|h).

mingodad 13 years ago
parent
commit
7132039454
2 changed files with 244 additions and 134 deletions
  1. 243 133
      SquiLu-ext/sqlite3.c
  2. 1 1
      SquiLu-ext/sqlite3.h

+ 243 - 133
SquiLu-ext/sqlite3.c

@@ -676,7 +676,7 @@ extern "C" {
 */
 */
 #define SQLITE_VERSION        "3.7.16"
 #define SQLITE_VERSION        "3.7.16"
 #define SQLITE_VERSION_NUMBER 3007016
 #define SQLITE_VERSION_NUMBER 3007016
-#define SQLITE_SOURCE_ID      "2013-02-19 22:26:51 06bd91305ed6752315c5224be5f89e87cafa6687"
+#define SQLITE_SOURCE_ID      "2013-02-26 12:57:42 c2d5a23b1ab39918e97c596cf75c42f86a5fe2b7"
 
 
 /*
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -39386,6 +39386,8 @@ static int pager_error(Pager *pPager, int rc){
   return rc;
   return rc;
 }
 }
 
 
+static int pager_truncate(Pager *pPager, Pgno nPage);
+
 /*
 /*
 ** This routine ends a transaction. A transaction is usually ended by 
 ** This routine ends a transaction. A transaction is usually ended by 
 ** either a COMMIT or a ROLLBACK operation. This routine may be called 
 ** either a COMMIT or a ROLLBACK operation. This routine may be called 
@@ -39439,7 +39441,7 @@ static int pager_error(Pager *pPager, int rc){
 ** to the first error encountered (the journal finalization one) is
 ** to the first error encountered (the journal finalization one) is
 ** returned.
 ** returned.
 */
 */
-static int pager_end_transaction(Pager *pPager, int hasMaster){
+static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
   int rc = SQLITE_OK;      /* Error code from journal finalization operation */
   int rc = SQLITE_OK;      /* Error code from journal finalization operation */
   int rc2 = SQLITE_OK;     /* Error code from db file unlock operation */
   int rc2 = SQLITE_OK;     /* Error code from db file unlock operation */
 
 
@@ -39525,7 +39527,17 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
     */
     */
     rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
     rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
     assert( rc2==SQLITE_OK );
     assert( rc2==SQLITE_OK );
+  }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
+    /* This branch is taken when committing a transaction in rollback-journal
+    ** mode if the database file on disk is larger than the database image.
+    ** At this point the journal has been finalized and the transaction 
+    ** successfully committed, but the EXCLUSIVE lock is still held on the
+    ** file. So it is safe to truncate the database file to its minimum
+    ** required size.  */
+    assert( pPager->eLock==EXCLUSIVE_LOCK );
+    rc = pager_truncate(pPager, pPager->dbSize);
   }
   }
+
   if( !pPager->exclusiveMode 
   if( !pPager->exclusiveMode 
    && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
    && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
   ){
   ){
@@ -39564,7 +39576,7 @@ static void pagerUnlockAndRollback(Pager *pPager){
       sqlite3EndBenignMalloc();
       sqlite3EndBenignMalloc();
     }else if( !pPager->exclusiveMode ){
     }else if( !pPager->exclusiveMode ){
       assert( pPager->eState==PAGER_READER );
       assert( pPager->eState==PAGER_READER );
-      pager_end_transaction(pPager, 0);
+      pager_end_transaction(pPager, 0, 0);
     }
     }
   }
   }
   pager_unlock(pPager);
   pager_unlock(pPager);
@@ -40339,7 +40351,7 @@ end_playback:
     rc = sqlite3PagerSync(pPager);
     rc = sqlite3PagerSync(pPager);
   }
   }
   if( rc==SQLITE_OK ){
   if( rc==SQLITE_OK ){
-    rc = pager_end_transaction(pPager, zMaster[0]!='\0');
+    rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
     testcase( rc!=SQLITE_OK );
     testcase( rc!=SQLITE_OK );
   }
   }
   if( rc==SQLITE_OK && zMaster[0] && res ){
   if( rc==SQLITE_OK && zMaster[0] && res ){
@@ -43433,36 +43445,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
   #endif
   #endif
       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
   
   
-      /* If this transaction has made the database smaller, then all pages
-      ** being discarded by the truncation must be written to the journal
-      ** file.
-      **
-      ** Before reading the pages with page numbers larger than the 
-      ** current value of Pager.dbSize, set dbSize back to the value
-      ** that it took at the start of the transaction. Otherwise, the
-      ** calls to sqlite3PagerGet() return zeroed pages instead of 
-      ** reading data from the database file.
-      */
-      if( pPager->dbSize<pPager->dbOrigSize 
-       && pPager->journalMode!=PAGER_JOURNALMODE_OFF
-      ){
-        Pgno i;                                   /* Iterator variable */
-        const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
-        const Pgno dbSize = pPager->dbSize;       /* Database image size */ 
-        pPager->dbSize = pPager->dbOrigSize;
-        for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
-          if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
-            PgHdr *pPage;             /* Page to journal */
-            rc = sqlite3PagerGet(pPager, i, &pPage);
-            if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-            rc = sqlite3PagerWrite(pPage);
-            sqlite3PagerUnref(pPage);
-            if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-          }
-        }
-        pPager->dbSize = dbSize;
-      } 
-  
       /* Write the master journal name into the journal file. If a master 
       /* Write the master journal name into the journal file. If a master 
       ** journal file name has already been written to the journal file, 
       ** journal file name has already been written to the journal file, 
       ** or if zMaster is NULL (no master journal), then this call is a no-op.
       ** or if zMaster is NULL (no master journal), then this call is a no-op.
@@ -43490,11 +43472,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
         goto commit_phase_one_exit;
         goto commit_phase_one_exit;
       }
       }
       sqlite3PcacheCleanAll(pPager->pPCache);
       sqlite3PcacheCleanAll(pPager->pPCache);
-  
-      /* If the file on disk is not the same size as the database image,
-      ** then use pager_truncate to grow or shrink the file here.
-      */
-      if( pPager->dbSize!=pPager->dbFileSize ){
+
+      /* If the file on disk is smaller than the database image, use 
+      ** pager_truncate to grow the file here. This can happen if the database
+      ** image was extended as part of the current transaction and then the
+      ** last page in the db image moved to the free-list. In this case the
+      ** last page is never written out to disk, leaving the database file
+      ** undersized. Fix this now if it is the case.  */
+      if( pPager->dbSize>pPager->dbFileSize ){
         Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
         Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
         assert( pPager->eState==PAGER_WRITER_DBMOD );
         assert( pPager->eState==PAGER_WRITER_DBMOD );
         rc = pager_truncate(pPager, nNew);
         rc = pager_truncate(pPager, nNew);
@@ -43567,7 +43552,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
   }
   }
 
 
   PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
   PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
-  rc = pager_end_transaction(pPager, pPager->setMaster);
+  rc = pager_end_transaction(pPager, pPager->setMaster, 1);
   return pager_error(pPager, rc);
   return pager_error(pPager, rc);
 }
 }
 
 
@@ -43612,11 +43597,11 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
   if( pagerUseWal(pPager) ){
   if( pagerUseWal(pPager) ){
     int rc2;
     int rc2;
     rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
     rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
-    rc2 = pager_end_transaction(pPager, pPager->setMaster);
+    rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
     if( rc==SQLITE_OK ) rc = rc2;
     if( rc==SQLITE_OK ) rc = rc2;
   }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
   }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
     int eState = pPager->eState;
     int eState = pPager->eState;
-    rc = pager_end_transaction(pPager, 0);
+    rc = pager_end_transaction(pPager, 0, 0);
     if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
     if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
       /* This can happen using journal_mode=off. Move the pager to the error 
       /* This can happen using journal_mode=off. Move the pager to the error 
       ** state to indicate that the contents of the cache may not be trusted.
       ** state to indicate that the contents of the cache may not be trusted.
@@ -48018,6 +48003,7 @@ struct BtShared {
 #ifndef SQLITE_OMIT_AUTOVACUUM
 #ifndef SQLITE_OMIT_AUTOVACUUM
   u8 autoVacuum;        /* True if auto-vacuum is enabled */
   u8 autoVacuum;        /* True if auto-vacuum is enabled */
   u8 incrVacuum;        /* True if incr-vacuum is enabled */
   u8 incrVacuum;        /* True if incr-vacuum is enabled */
+  u8 bDoTruncate;       /* True to truncate db on commit */
 #endif
 #endif
   u8 inTransaction;     /* Transaction state */
   u8 inTransaction;     /* Transaction state */
   u8 max1bytePayload;   /* Maximum first byte of cell for a 1-byte payload */
   u8 max1bytePayload;   /* Maximum first byte of cell for a 1-byte payload */
@@ -51136,6 +51122,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
   if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
   if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
     goto trans_begun;
     goto trans_begun;
   }
   }
+  assert( pBt->bDoTruncate==0 );
 
 
   /* Write transactions are not possible on a read-only database */
   /* Write transactions are not possible on a read-only database */
   if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
   if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
@@ -51450,26 +51437,28 @@ static int relocatePage(
 
 
 /* Forward declaration required by incrVacuumStep(). */
 /* Forward declaration required by incrVacuumStep(). */
 static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
 static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
+#define BTALLOC_ANY   0           /* Allocate any page */
+#define BTALLOC_EXACT 1           /* Allocate exact page if possible */
+#define BTALLOC_LE    2           /* Allocate any page <= the parameter */
 
 
 /*
 /*
-** Perform a single step of an incremental-vacuum. If successful,
-** return SQLITE_OK. If there is no work to do (and therefore no
-** point in calling this function again), return SQLITE_DONE.
+** Perform a single step of an incremental-vacuum. If successful, return
+** SQLITE_OK. If there is no work to do (and therefore no point in 
+** calling this function again), return SQLITE_DONE. Or, if an error 
+** occurs, return some other error code.
+**
+** More specificly, this function attempts to re-organize the database so 
+** that the last page of the file currently in use is no longer in use.
 **
 **
-** More specificly, this function attempts to re-organize the 
-** database so that the last page of the file currently in use
-** is no longer in use.
+** Parameter nFin is the number of pages that this database would contain
+** were this function called until it returns SQLITE_DONE.
 **
 **
-** If the nFin parameter is non-zero, this function assumes
-** that the caller will keep calling incrVacuumStep() until
-** it returns SQLITE_DONE or an error, and that nFin is the
-** number of pages the database file will contain after this 
-** process is complete.  If nFin is zero, it is assumed that
-** incrVacuumStep() will be called a finite amount of times
-** which may or may not empty the freelist.  A full autovacuum
-** has nFin>0.  A "PRAGMA incremental_vacuum" has nFin==0.
+** If the bCommit parameter is non-zero, this function assumes that the 
+** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE 
+** or an error. bCommit is passed true for an auto-vacuum-on-commmit 
+** operation, or false for an incremental vacuum.
 */
 */
-static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
+static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
   Pgno nFreeList;           /* Number of pages still on the free-list */
   Pgno nFreeList;           /* Number of pages still on the free-list */
   int rc;
   int rc;
 
 
@@ -51494,15 +51483,15 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
     }
     }
 
 
     if( eType==PTRMAP_FREEPAGE ){
     if( eType==PTRMAP_FREEPAGE ){
-      if( nFin==0 ){
+      if( bCommit==0 ){
         /* Remove the page from the files free-list. This is not required
         /* Remove the page from the files free-list. This is not required
-        ** if nFin is non-zero. In that case, the free-list will be
+        ** if bCommit is non-zero. In that case, the free-list will be
         ** truncated to zero after this function returns, so it doesn't 
         ** truncated to zero after this function returns, so it doesn't 
         ** matter if it still contains some garbage entries.
         ** matter if it still contains some garbage entries.
         */
         */
         Pgno iFreePg;
         Pgno iFreePg;
         MemPage *pFreePg;
         MemPage *pFreePg;
-        rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
+        rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT);
         if( rc!=SQLITE_OK ){
         if( rc!=SQLITE_OK ){
           return rc;
           return rc;
         }
         }
@@ -51512,34 +51501,37 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
     } else {
     } else {
       Pgno iFreePg;             /* Index of free page to move pLastPg to */
       Pgno iFreePg;             /* Index of free page to move pLastPg to */
       MemPage *pLastPg;
       MemPage *pLastPg;
+      u8 eMode = BTALLOC_ANY;   /* Mode parameter for allocateBtreePage() */
+      Pgno iNear = 0;           /* nearby parameter for allocateBtreePage() */
 
 
       rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
       rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
       if( rc!=SQLITE_OK ){
       if( rc!=SQLITE_OK ){
         return rc;
         return rc;
       }
       }
 
 
-      /* If nFin is zero, this loop runs exactly once and page pLastPg
+      /* If bCommit is zero, this loop runs exactly once and page pLastPg
       ** is swapped with the first free page pulled off the free list.
       ** is swapped with the first free page pulled off the free list.
       **
       **
-      ** On the other hand, if nFin is greater than zero, then keep
+      ** On the other hand, if bCommit is greater than zero, then keep
       ** looping until a free-page located within the first nFin pages
       ** looping until a free-page located within the first nFin pages
       ** of the file is found.
       ** of the file is found.
       */
       */
+      if( bCommit==0 ){
+        eMode = BTALLOC_LE;
+        iNear = nFin;
+      }
       do {
       do {
         MemPage *pFreePg;
         MemPage *pFreePg;
-        rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
+        rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
         if( rc!=SQLITE_OK ){
         if( rc!=SQLITE_OK ){
           releasePage(pLastPg);
           releasePage(pLastPg);
           return rc;
           return rc;
         }
         }
         releasePage(pFreePg);
         releasePage(pFreePg);
-      }while( nFin!=0 && iFreePg>nFin );
+      }while( bCommit && iFreePg>nFin );
       assert( iFreePg<iLastPg );
       assert( iFreePg<iLastPg );
       
       
-      rc = sqlite3PagerWrite(pLastPg->pDbPage);
-      if( rc==SQLITE_OK ){
-        rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
-      }
+      rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
       releasePage(pLastPg);
       releasePage(pLastPg);
       if( rc!=SQLITE_OK ){
       if( rc!=SQLITE_OK ){
         return rc;
         return rc;
@@ -51547,29 +51539,39 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
     }
     }
   }
   }
 
 
-  if( nFin==0 ){
-    iLastPg--;
-    while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
-      if( PTRMAP_ISPAGE(pBt, iLastPg) ){
-        MemPage *pPg;
-        rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
-        if( rc!=SQLITE_OK ){
-          return rc;
-        }
-        rc = sqlite3PagerWrite(pPg->pDbPage);
-        releasePage(pPg);
-        if( rc!=SQLITE_OK ){
-          return rc;
-        }
-      }
+  if( bCommit==0 ){
+    do {
       iLastPg--;
       iLastPg--;
-    }
-    sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
+    }while( iLastPg==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, iLastPg) );
+    pBt->bDoTruncate = 1;
     pBt->nPage = iLastPg;
     pBt->nPage = iLastPg;
   }
   }
   return SQLITE_OK;
   return SQLITE_OK;
 }
 }
 
 
+/*
+** The database opened by the first argument is an auto-vacuum database
+** nOrig pages in size containing nFree free pages. Return the expected 
+** size of the database in pages following an auto-vacuum operation.
+*/
+static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
+  int nEntry;                     /* Number of entries on one ptrmap page */
+  Pgno nPtrmap;                   /* Number of PtrMap pages to be freed */
+  Pgno nFin;                      /* Return value */
+
+  nEntry = pBt->usableSize/5;
+  nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
+  nFin = nOrig - nFree - nPtrmap;
+  if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
+    nFin--;
+  }
+  while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
+    nFin--;
+  }
+
+  return nFin;
+}
+
 /*
 /*
 ** A write-transaction must be opened before calling this function.
 ** A write-transaction must be opened before calling this function.
 ** It performs a single unit of work towards an incremental vacuum.
 ** It performs a single unit of work towards an incremental vacuum.
@@ -51587,11 +51589,21 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
   if( !pBt->autoVacuum ){
   if( !pBt->autoVacuum ){
     rc = SQLITE_DONE;
     rc = SQLITE_DONE;
   }else{
   }else{
-    invalidateAllOverflowCache(pBt);
-    rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
-    if( rc==SQLITE_OK ){
-      rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
-      put4byte(&pBt->pPage1->aData[28], pBt->nPage);
+    Pgno nOrig = btreePagecount(pBt);
+    Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
+    Pgno nFin = finalDbSize(pBt, nOrig, nFree);
+
+    if( nOrig<nFin ){
+      rc = SQLITE_CORRUPT_BKPT;
+    }else if( nFree>0 ){
+      invalidateAllOverflowCache(pBt);
+      rc = incrVacuumStep(pBt, nFin, nOrig, 0);
+      if( rc==SQLITE_OK ){
+        rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+        put4byte(&pBt->pPage1->aData[28], pBt->nPage);
+      }
+    }else{
+      rc = SQLITE_DONE;
     }
     }
   }
   }
   sqlite3BtreeLeave(p);
   sqlite3BtreeLeave(p);
@@ -51618,9 +51630,7 @@ static int autoVacuumCommit(BtShared *pBt){
   if( !pBt->incrVacuum ){
   if( !pBt->incrVacuum ){
     Pgno nFin;         /* Number of pages in database after autovacuuming */
     Pgno nFin;         /* Number of pages in database after autovacuuming */
     Pgno nFree;        /* Number of pages on the freelist initially */
     Pgno nFree;        /* Number of pages on the freelist initially */
-    Pgno nPtrmap;      /* Number of PtrMap pages to be freed */
     Pgno iFree;        /* The next page to be freed */
     Pgno iFree;        /* The next page to be freed */
-    int nEntry;        /* Number of entries on one ptrmap page */
     Pgno nOrig;        /* Database size before freeing */
     Pgno nOrig;        /* Database size before freeing */
 
 
     nOrig = btreePagecount(pBt);
     nOrig = btreePagecount(pBt);
@@ -51633,26 +51643,18 @@ static int autoVacuumCommit(BtShared *pBt){
     }
     }
 
 
     nFree = get4byte(&pBt->pPage1->aData[36]);
     nFree = get4byte(&pBt->pPage1->aData[36]);
-    nEntry = pBt->usableSize/5;
-    nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
-    nFin = nOrig - nFree - nPtrmap;
-    if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
-      nFin--;
-    }
-    while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
-      nFin--;
-    }
+    nFin = finalDbSize(pBt, nOrig, nFree);
     if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
     if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
 
 
     for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
     for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
-      rc = incrVacuumStep(pBt, nFin, iFree);
+      rc = incrVacuumStep(pBt, nFin, iFree, 1);
     }
     }
     if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
     if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
       rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
       rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
       put4byte(&pBt->pPage1->aData[32], 0);
       put4byte(&pBt->pPage1->aData[32], 0);
       put4byte(&pBt->pPage1->aData[36], 0);
       put4byte(&pBt->pPage1->aData[36], 0);
       put4byte(&pBt->pPage1->aData[28], nFin);
       put4byte(&pBt->pPage1->aData[28], nFin);
-      sqlite3PagerTruncateImage(pBt->pPager, nFin);
+      pBt->bDoTruncate = 1;
       pBt->nPage = nFin;
       pBt->nPage = nFin;
     }
     }
     if( rc!=SQLITE_OK ){
     if( rc!=SQLITE_OK ){
@@ -51707,6 +51709,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
         return rc;
         return rc;
       }
       }
     }
     }
+    if( pBt->bDoTruncate ){
+      sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
+    }
 #endif
 #endif
     rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
     rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
     sqlite3BtreeLeave(p);
     sqlite3BtreeLeave(p);
@@ -51722,6 +51727,9 @@ static void btreeEndTransaction(Btree *p){
   BtShared *pBt = p->pBt;
   BtShared *pBt = p->pBt;
   assert( sqlite3BtreeHoldsMutex(p) );
   assert( sqlite3BtreeHoldsMutex(p) );
 
 
+#ifndef SQLITE_OMIT_AUTOVACUUM
+  pBt->bDoTruncate = 0;
+#endif
   btreeClearHasContent(pBt);
   btreeClearHasContent(pBt);
   if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
   if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
     /* If there are other active statements that belong to this database
     /* If there are other active statements that belong to this database
@@ -53408,7 +53416,7 @@ static int allocateBtreePage(
   MemPage **ppPage, 
   MemPage **ppPage, 
   Pgno *pPgno, 
   Pgno *pPgno, 
   Pgno nearby,
   Pgno nearby,
-  u8 exact
+  u8 eMode
 ){
 ){
   MemPage *pPage1;
   MemPage *pPage1;
   int rc;
   int rc;
@@ -53436,16 +53444,19 @@ static int allocateBtreePage(
     ** the entire-list will be searched for that page.
     ** the entire-list will be searched for that page.
     */
     */
 #ifndef SQLITE_OMIT_AUTOVACUUM
 #ifndef SQLITE_OMIT_AUTOVACUUM
-    if( exact && nearby<=mxPage ){
-      u8 eType;
-      assert( nearby>0 );
-      assert( pBt->autoVacuum );
-      rc = ptrmapGet(pBt, nearby, &eType, 0);
-      if( rc ) return rc;
-      if( eType==PTRMAP_FREEPAGE ){
-        searchList = 1;
+    if( eMode==BTALLOC_EXACT ){
+      if( nearby<=mxPage ){
+        u8 eType;
+        assert( nearby>0 );
+        assert( pBt->autoVacuum );
+        rc = ptrmapGet(pBt, nearby, &eType, 0);
+        if( rc ) return rc;
+        if( eType==PTRMAP_FREEPAGE ){
+          searchList = 1;
+        }
       }
       }
-      *pPgno = nearby;
+    }else if( eMode==BTALLOC_LE ){
+      searchList = 1;
     }
     }
 #endif
 #endif
 
 
@@ -53500,11 +53511,13 @@ static int allocateBtreePage(
         rc = SQLITE_CORRUPT_BKPT;
         rc = SQLITE_CORRUPT_BKPT;
         goto end_allocate_page;
         goto end_allocate_page;
 #ifndef SQLITE_OMIT_AUTOVACUUM
 #ifndef SQLITE_OMIT_AUTOVACUUM
-      }else if( searchList && nearby==iTrunk ){
+      }else if( searchList 
+            && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE)) 
+      ){
         /* The list is being searched and this trunk page is the page
         /* The list is being searched and this trunk page is the page
         ** to allocate, regardless of whether it has leaves.
         ** to allocate, regardless of whether it has leaves.
         */
         */
-        assert( *pPgno==iTrunk );
+        *pPgno = iTrunk;
         *ppPage = pTrunk;
         *ppPage = pTrunk;
         searchList = 0;
         searchList = 0;
         rc = sqlite3PagerWrite(pTrunk->pDbPage);
         rc = sqlite3PagerWrite(pTrunk->pDbPage);
@@ -53567,14 +53580,24 @@ static int allocateBtreePage(
         unsigned char *aData = pTrunk->aData;
         unsigned char *aData = pTrunk->aData;
         if( nearby>0 ){
         if( nearby>0 ){
           u32 i;
           u32 i;
-          int dist;
           closest = 0;
           closest = 0;
-          dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
-          for(i=1; i<k; i++){
-            int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
-            if( d2<dist ){
-              closest = i;
-              dist = d2;
+          if( eMode==BTALLOC_LE ){
+            for(i=0; i<k; i++){
+              iPage = get4byte(&aData[8+i*4]);
+              if( iPage<=nearby ){
+                closest = i;
+                break;
+              }
+            }
+          }else{
+            int dist;
+            dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
+            for(i=1; i<k; i++){
+              int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
+              if( d2<dist ){
+                closest = i;
+                dist = d2;
+              }
             }
             }
           }
           }
         }else{
         }else{
@@ -53588,7 +53611,9 @@ static int allocateBtreePage(
           goto end_allocate_page;
           goto end_allocate_page;
         }
         }
         testcase( iPage==mxPage );
         testcase( iPage==mxPage );
-        if( !searchList || iPage==nearby ){
+        if( !searchList 
+         || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE)) 
+        ){
           int noContent;
           int noContent;
           *pPgno = iPage;
           *pPgno = iPage;
           TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
           TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
@@ -53615,8 +53640,26 @@ static int allocateBtreePage(
       pPrevTrunk = 0;
       pPrevTrunk = 0;
     }while( searchList );
     }while( searchList );
   }else{
   }else{
-    /* There are no pages on the freelist, so create a new page at the
-    ** end of the file */
+    /* There are no pages on the freelist, so append a new page to the
+    ** database image.
+    **
+    ** Normally, new pages allocated by this block can be requested from the
+    ** pager layer with the 'no-content' flag set. This prevents the pager
+    ** from trying to read the pages content from disk. However, if the
+    ** current transaction has already run one or more incremental-vacuum
+    ** steps, then the page we are about to allocate may contain content
+    ** that is required in the event of a rollback. In this case, do
+    ** not set the no-content flag. This causes the pager to load and journal
+    ** the current page content before overwriting it.
+    **
+    ** Note that the pager will not actually attempt to load or journal 
+    ** content for any page that really does lie past the end of the database
+    ** file on disk. So the effects of disabling the no-content optimization
+    ** here are confined to those pages that lie between the end of the
+    ** database image and the end of the database file.
+    */
+    int bNoContent = (0==pBt->bDoTruncate);
+
     rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
     rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
     if( rc ) return rc;
     if( rc ) return rc;
     pBt->nPage++;
     pBt->nPage++;
@@ -53631,7 +53674,7 @@ static int allocateBtreePage(
       MemPage *pPg = 0;
       MemPage *pPg = 0;
       TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
       TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
       assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
       assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
-      rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
+      rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
       if( rc==SQLITE_OK ){
       if( rc==SQLITE_OK ){
         rc = sqlite3PagerWrite(pPg->pDbPage);
         rc = sqlite3PagerWrite(pPg->pDbPage);
         releasePage(pPg);
         releasePage(pPg);
@@ -53645,7 +53688,7 @@ static int allocateBtreePage(
     *pPgno = pBt->nPage;
     *pPgno = pBt->nPage;
 
 
     assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
     assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
-    rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
+    rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
     if( rc ) return rc;
     if( rc ) return rc;
     rc = sqlite3PagerWrite((*ppPage)->pDbPage);
     rc = sqlite3PagerWrite((*ppPage)->pDbPage);
     if( rc!=SQLITE_OK ){
     if( rc!=SQLITE_OK ){
@@ -55660,7 +55703,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
     ** be moved to the allocated page (unless the allocated page happens
     ** be moved to the allocated page (unless the allocated page happens
     ** to reside at pgnoRoot).
     ** to reside at pgnoRoot).
     */
     */
-    rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
+    rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT);
     if( rc!=SQLITE_OK ){
     if( rc!=SQLITE_OK ){
       return rc;
       return rc;
     }
     }
@@ -57352,7 +57395,6 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
           nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
           nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
         }
         }
         assert( nDestTruncate>0 );
         assert( nDestTruncate>0 );
-        sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
 
 
         if( pgszSrc<pgszDest ){
         if( pgszSrc<pgszDest ){
           /* If the source page-size is smaller than the destination page-size,
           /* If the source page-size is smaller than the destination page-size,
@@ -57366,6 +57408,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
           */
           */
           const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
           const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
           sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
           sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
+          Pgno iPg;
+          int nDstPage;
           i64 iOff;
           i64 iOff;
           i64 iEnd;
           i64 iEnd;
 
 
@@ -57376,13 +57420,26 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
              && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
              && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
           ));
           ));
 
 
-          /* This call ensures that all data required to recreate the original
+          /* This block ensures that all data required to recreate the original
           ** database has been stored in the journal for pDestPager and the
           ** database has been stored in the journal for pDestPager and the
           ** journal synced to disk. So at this point we may safely modify
           ** journal synced to disk. So at this point we may safely modify
           ** the database file in any way, knowing that if a power failure
           ** the database file in any way, knowing that if a power failure
           ** occurs, the original database will be reconstructed from the 
           ** occurs, the original database will be reconstructed from the 
           ** journal file.  */
           ** journal file.  */
-          rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
+          sqlite3PagerPagecount(pDestPager, &nDstPage);
+          for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
+            if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
+              DbPage *pPg;
+              rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
+              if( rc==SQLITE_OK ){
+                rc = sqlite3PagerWrite(pPg);
+                sqlite3PagerUnref(pPg);
+              }
+            }
+          }
+          if( rc==SQLITE_OK ){
+            rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
+          }
 
 
           /* Write the extra pages and truncate the database file as required */
           /* Write the extra pages and truncate the database file as required */
           iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
           iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
@@ -57409,6 +57466,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
             rc = sqlite3PagerSync(pDestPager);
             rc = sqlite3PagerSync(pDestPager);
           }
           }
         }else{
         }else{
+          sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
           rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
           rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
         }
         }
     
     
@@ -72888,12 +72946,12 @@ SQLITE_PRIVATE int sqlite3MatchSpanName(
 ){
 ){
   int n;
   int n;
   for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
   for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
-  if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
+  if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
     return 0;
     return 0;
   }
   }
   zSpan += n+1;
   zSpan += n+1;
   for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
   for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
-  if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
+  if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){
     return 0;
     return 0;
   }
   }
   zSpan += n+1;
   zSpan += n+1;
@@ -87030,6 +87088,56 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
   }
   }
 }
 }
 
 
+/*
+** The unicode() function.  Return the integer unicode code-point value
+** for the first character of the input string. 
+*/
+static void unicodeFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  const unsigned char *z = sqlite3_value_text(argv[0]);
+  if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z));
+}
+
+/*
+** The char() function takes zero or more arguments, each of which is
+** an integer.  It constructs a string where each character of the string
+** is the unicode character for the corresponding integer argument.
+*/
+static void charFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  unsigned char *z, *zOut;
+  int i;
+  zOut = z = sqlite3_malloc( argc*4 );
+  if( z==0 ){
+    sqlite3_result_error_nomem(context);
+    return;
+  }
+  for(i=0; i<argc; i++){
+    sqlite3_int64 x;
+    unsigned c;
+    x = sqlite3_value_int64(argv[i]);
+    if( x<0 || x>0x10ffff ) x = 0xfffd;
+    c = (unsigned)(x & 0x1fffff);
+    if( c<=0xFFFF ){
+      *zOut++ = (u8)(c&0x00FF);
+      *zOut++ = (u8)((c>>8)&0x00FF);
+    }else{
+      if( c>=0xd800 && c<=0xdbff ) c = 0xfffd;
+      *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0));
+      *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03));
+      *zOut++ = (u8)(c&0x00FF);
+      *zOut++ = (u8)(0x00DC + ((c>>8)&0x03));
+    }
+  }
+  sqlite3_result_text16le(context, (char*)z, (int)(zOut-z), sqlite3_free);
+}
+
 /*
 /*
 ** The hex() function.  Interpret the argument as a blob.  Return
 ** The hex() function.  Interpret the argument as a blob.  Return
 ** a hexadecimal rendering as text.
 ** a hexadecimal rendering as text.
@@ -87657,6 +87765,8 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(instr,              2, 0, 0, instrFunc        ),
     FUNCTION(instr,              2, 0, 0, instrFunc        ),
     FUNCTION(substr,             2, 0, 0, substrFunc       ),
     FUNCTION(substr,             2, 0, 0, substrFunc       ),
     FUNCTION(substr,             3, 0, 0, substrFunc       ),
     FUNCTION(substr,             3, 0, 0, substrFunc       ),
+    FUNCTION(unicode,            1, 0, 0, unicodeFunc      ),
+    FUNCTION(char,              -1, 0, 0, charFunc         ),
     FUNCTION(abs,                1, 0, 0, absFunc          ),
     FUNCTION(abs,                1, 0, 0, absFunc          ),
 #ifndef SQLITE_OMIT_FLOATING_POINT
 #ifndef SQLITE_OMIT_FLOATING_POINT
     FUNCTION(round,              1, 0, 0, roundFunc        ),
     FUNCTION(round,              1, 0, 0, roundFunc        ),

+ 1 - 1
SquiLu-ext/sqlite3.h

@@ -109,7 +109,7 @@ extern "C" {
 */
 */
 #define SQLITE_VERSION        "3.7.16"
 #define SQLITE_VERSION        "3.7.16"
 #define SQLITE_VERSION_NUMBER 3007016
 #define SQLITE_VERSION_NUMBER 3007016
-#define SQLITE_SOURCE_ID      "2013-02-19 22:26:51 06bd91305ed6752315c5224be5f89e87cafa6687"
+#define SQLITE_SOURCE_ID      "2013-02-26 12:57:42 c2d5a23b1ab39918e97c596cf75c42f86a5fe2b7"
 
 
 /*
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** CAPI3REF: Run-Time Library Version Numbers