| Index: third_party/sqlite/src/src/pager.c | 
| diff --git a/third_party/sqlite/src/src/pager.c b/third_party/sqlite/src/src/pager.c | 
| index a4fe31869376f59978bf7d9c5a90ed7db8409576..34fa50fe8cf582eb2a9a26b0837414aaad345cee 100644 | 
| --- a/third_party/sqlite/src/src/pager.c | 
| +++ b/third_party/sqlite/src/src/pager.c | 
| @@ -75,13 +75,13 @@ | 
| ** | 
| ** Definition: Two databases (or the same database at two points it time) | 
| ** are said to be "logically equivalent" if they give the same answer to | 
| -** all queries.  Note in particular the the content of freelist leaf | 
| -** pages can be changed arbitarily without effecting the logical equivalence | 
| +** all queries.  Note in particular the content of freelist leaf | 
| +** pages can be changed arbitrarily without affecting the logical equivalence | 
| ** of the database. | 
| ** | 
| ** (7) At any time, if any subset, including the empty set and the total set, | 
| **     of the unsynced changes to a rollback journal are removed and the | 
| -**     journal is rolled back, the resulting database file will be logical | 
| +**     journal is rolled back, the resulting database file will be logically | 
| **     equivalent to the database file at the beginning of the transaction. | 
| ** | 
| ** (8) When a transaction is rolled back, the xTruncate method of the VFS | 
| @@ -273,7 +273,7 @@ int sqlite3PagerTrace=1;  /* True to enable tracing */ | 
| **    * A write transaction is active. | 
| **    * An EXCLUSIVE or greater lock is held on the database file. | 
| **    * All writing and syncing of journal and database data has finished. | 
| -**      If no error occured, all that remains is to finalize the journal to | 
| +**      If no error occurred, all that remains is to finalize the journal to | 
| **      commit the transaction. If an error did occur, the caller will need | 
| **      to rollback the transaction. | 
| ** | 
| @@ -378,7 +378,7 @@ int sqlite3PagerTrace=1;  /* True to enable tracing */ | 
| ** | 
| ** The exception is when the database file is unlocked as the pager moves | 
| ** from ERROR to OPEN state. At this point there may be a hot-journal file | 
| -** in the file-system that needs to be rolled back (as part of a OPEN->SHARED | 
| +** in the file-system that needs to be rolled back (as part of an OPEN->SHARED | 
| ** transition, by the same pager or any other). If the call to xUnlock() | 
| ** fails at this point and the pager is left holding an EXCLUSIVE lock, this | 
| ** can confuse the call to xCheckReservedLock() call made later as part | 
| @@ -454,7 +454,14 @@ struct PagerSavepoint { | 
| }; | 
|  | 
| /* | 
| -** A open page cache is an instance of struct Pager. A description of | 
| +** Bits of the Pager.doNotSpill flag.  See further description below. | 
| +*/ | 
| +#define SPILLFLAG_OFF         0x01      /* Never spill cache.  Set via pragma */ | 
| +#define SPILLFLAG_ROLLBACK    0x02      /* Current rolling back, so do not spill */ | 
| +#define SPILLFLAG_NOSYNC      0x04      /* Spill is ok, but do not sync */ | 
| + | 
| +/* | 
| +** An open page cache is an instance of struct Pager. A description of | 
| ** some of the more important member variables follows: | 
| ** | 
| ** eState | 
| @@ -519,19 +526,21 @@ struct PagerSavepoint { | 
| **   journal file from being successfully finalized, the setMaster flag | 
| **   is cleared anyway (and the pager will move to ERROR state). | 
| ** | 
| -** doNotSpill, doNotSyncSpill | 
| +** doNotSpill | 
| ** | 
| -**   These two boolean variables control the behaviour of cache-spills | 
| -**   (calls made by the pcache module to the pagerStress() routine to | 
| -**   write cached data to the file-system in order to free up memory). | 
| +**   This variables control the behavior of cache-spills  (calls made by | 
| +**   the pcache module to the pagerStress() routine to write cached data | 
| +**   to the file-system in order to free up memory). | 
| ** | 
| -**   When doNotSpill is non-zero, writing to the database from pagerStress() | 
| -**   is disabled altogether. This is done in a very obscure case that | 
| +**   When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set, | 
| +**   writing to the database from pagerStress() is disabled altogether. | 
| +**   The SPILLFLAG_ROLLBACK case is done in a very obscure case that | 
| **   comes up during savepoint rollback that requires the pcache module | 
| **   to allocate a new page to prevent the journal file from being written | 
| -**   while it is being traversed by code in pager_playback(). | 
| +**   while it is being traversed by code in pager_playback().  The SPILLFLAG_OFF | 
| +**   case is a user preference. | 
| ** | 
| -**   If doNotSyncSpill is non-zero, writing to the database from pagerStress() | 
| +**   If the SPILLFLAG_NOSYNC bit is set, writing to the database from pagerStress() | 
| **   is permitted, but syncing the journal file is not. This flag is set | 
| **   by sqlite3PagerWrite() when the file-system sector-size is larger than | 
| **   the database page-size in order to prevent a journal sync from happening | 
| @@ -612,18 +621,19 @@ struct Pager { | 
| u8 exclusiveMode;           /* Boolean. True if locking_mode==EXCLUSIVE */ | 
| u8 journalMode;             /* One of the PAGER_JOURNALMODE_* values */ | 
| u8 useJournal;              /* Use a rollback journal on this file */ | 
| -  u8 noReadlock;              /* Do not bother to obtain readlocks */ | 
| u8 noSync;                  /* Do not sync the journal if true */ | 
| u8 fullSync;                /* Do extra syncs of the journal for robustness */ | 
| u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */ | 
| +  u8 walSyncFlags;            /* SYNC_NORMAL or SYNC_FULL for wal writes */ | 
| u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */ | 
| -  u8 tempFile;                /* zFilename is a temporary file */ | 
| +  u8 tempFile;                /* zFilename is a temporary or immutable file */ | 
| +  u8 noLock;                  /* Do not lock (except in WAL mode) */ | 
| u8 readOnly;                /* True for a read-only database */ | 
| u8 memDb;                   /* True to inhibit all file I/O */ | 
|  | 
| /************************************************************************** | 
| ** The following block contains those class members that change during | 
| -  ** routine opertion.  Class members not in this block are either fixed | 
| +  ** routine operation.  Class members not in this block are either fixed | 
| ** when the pager is first created or else only change when there is a | 
| ** significant mode change (such as changing the page_size, locking_mode, | 
| ** or the journal_mode).  From another view, these class members describe | 
| @@ -635,7 +645,6 @@ struct Pager { | 
| u8 changeCountDone;         /* Set after incrementing the change-counter */ | 
| u8 setMaster;               /* True if a m-j name has been written to jrnl */ | 
| u8 doNotSpill;              /* Do not spill the cache when non-zero */ | 
| -  u8 doNotSyncSpill;          /* Do not do a spill that requires jrnl sync */ | 
| u8 subjInMemory;            /* True to use in-memory sub-journals */ | 
| Pgno dbSize;                /* Number of pages in the database */ | 
| Pgno dbOrigSize;            /* dbSize before the current transaction */ | 
| @@ -655,6 +664,11 @@ struct Pager { | 
| PagerSavepoint *aSavepoint; /* Array of active savepoints */ | 
| int nSavepoint;             /* Number of elements in aSavepoint[] */ | 
| char dbFileVers[16];        /* Changes whenever database file changes */ | 
| + | 
| +  u8 bUseFetch;               /* True to use xFetch() */ | 
| +  int nMmapOut;               /* Number of mmap pages currently outstanding */ | 
| +  sqlite3_int64 szMmap;       /* Desired maximum mmap size */ | 
| +  PgHdr *pMmapFreelist;       /* List of free mmap page headers (pDirty) */ | 
| /* | 
| ** End of the routinely-changing class members | 
| ***************************************************************************/ | 
| @@ -670,9 +684,9 @@ struct Pager { | 
| char *zJournal;             /* Name of the journal file */ | 
| int (*xBusyHandler)(void*); /* Function to call when busy */ | 
| void *pBusyHandlerArg;      /* Context argument for xBusyHandler */ | 
| +  int aStat[3];               /* Total cache hits, misses and writes */ | 
| #ifdef SQLITE_TEST | 
| -  int nHit, nMiss;            /* Cache hits and missing */ | 
| -  int nRead, nWrite;          /* Database pages read/written */ | 
| +  int nRead;                  /* Database pages read */ | 
| #endif | 
| void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ | 
| #ifdef SQLITE_HAS_CODEC | 
| @@ -690,6 +704,15 @@ struct Pager { | 
| }; | 
|  | 
| /* | 
| +** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains | 
| +** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS | 
| +** or CACHE_WRITE to sqlite3_db_status(). | 
| +*/ | 
| +#define PAGER_STAT_HIT   0 | 
| +#define PAGER_STAT_MISS  1 | 
| +#define PAGER_STAT_WRITE 2 | 
| + | 
| +/* | 
| ** The following global variables hold counters used for | 
| ** testing purposes only.  These variables do not exist in | 
| ** a non-testing build.  These variables are not thread-safe. | 
| @@ -757,6 +780,16 @@ static const unsigned char aJournalMagic[] = { | 
| #endif | 
|  | 
| /* | 
| +** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch | 
| +** interfaces to access the database using memory-mapped I/O. | 
| +*/ | 
| +#if SQLITE_MAX_MMAP_SIZE>0 | 
| +# define USEFETCH(x) ((x)->bUseFetch) | 
| +#else | 
| +# define USEFETCH(x) 0 | 
| +#endif | 
| + | 
| +/* | 
| ** The maximum legal page number is (2^31 - 1). | 
| */ | 
| #define PAGER_MAX_PGNO 2147483647 | 
| @@ -786,7 +819,7 @@ static int pagerUseWal(Pager *pPager){ | 
| #else | 
| # define pagerUseWal(x) 0 | 
| # define pagerRollbackWal(x) 0 | 
| -# define pagerWalFrames(v,w,x,y,z) 0 | 
| +# define pagerWalFrames(v,w,x,y) 0 | 
| # define pagerOpenWalIfPresent(z) SQLITE_OK | 
| # define pagerBeginReadTransaction(z) SQLITE_OK | 
| #endif | 
| @@ -859,7 +892,7 @@ static int assert_pager_state(Pager *p){ | 
| case PAGER_READER: | 
| assert( pPager->errCode==SQLITE_OK ); | 
| assert( p->eLock!=UNKNOWN_LOCK ); | 
| -      assert( p->eLock>=SHARED_LOCK || p->noReadlock ); | 
| +      assert( p->eLock>=SHARED_LOCK ); | 
| break; | 
|  | 
| case PAGER_WRITER_LOCKED: | 
| @@ -990,11 +1023,12 @@ static char *print_pager_state(Pager *p){ | 
| **     PagerSavepoint.pInSavepoint. | 
| */ | 
| static int subjRequiresPage(PgHdr *pPg){ | 
| -  Pgno pgno = pPg->pgno; | 
| Pager *pPager = pPg->pPager; | 
| +  PagerSavepoint *p; | 
| +  Pgno pgno = pPg->pgno; | 
| int i; | 
| for(i=0; i<pPager->nSavepoint; i++){ | 
| -    PagerSavepoint *p = &pPager->aSavepoint[i]; | 
| +    p = &pPager->aSavepoint[i]; | 
| if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){ | 
| return 1; | 
| } | 
| @@ -1005,8 +1039,8 @@ static int subjRequiresPage(PgHdr *pPg){ | 
| /* | 
| ** Return true if the page is already in the journal file. | 
| */ | 
| -static int pageInJournal(PgHdr *pPg){ | 
| -  return sqlite3BitvecTest(pPg->pPager->pInJournal, pPg->pgno); | 
| +static int pageInJournal(Pager *pPager, PgHdr *pPg){ | 
| +  return sqlite3BitvecTest(pPager->pInJournal, pPg->pgno); | 
| } | 
|  | 
| /* | 
| @@ -1058,7 +1092,7 @@ static int pagerUnlockDb(Pager *pPager, int eLock){ | 
| assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 ); | 
| if( isOpen(pPager->fd) ){ | 
| assert( pPager->eLock>=eLock ); | 
| -    rc = sqlite3OsUnlock(pPager->fd, eLock); | 
| +    rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); | 
| if( pPager->eLock!=UNKNOWN_LOCK ){ | 
| pPager->eLock = (u8)eLock; | 
| } | 
| @@ -1082,7 +1116,7 @@ static int pagerLockDb(Pager *pPager, int eLock){ | 
|  | 
| assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK ); | 
| if( pPager->eLock<eLock || pPager->eLock==UNKNOWN_LOCK ){ | 
| -    rc = sqlite3OsLock(pPager->fd, eLock); | 
| +    rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock); | 
| if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){ | 
| pPager->eLock = (u8)eLock; | 
| IOTRACE(("LOCK %p %d\n", pPager, eLock)) | 
| @@ -1213,6 +1247,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){ | 
| || szJ<16 | 
| || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) | 
| || len>=nMaster | 
| +   || len==0 | 
| || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) | 
| || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) | 
| || memcmp(aMagic, aJournalMagic, 8) | 
| @@ -1390,7 +1425,7 @@ static int writeJournalHdr(Pager *pPager){ | 
| memset(zHeader, 0, sizeof(aJournalMagic)+4); | 
| } | 
|  | 
| -  /* The random check-hash initialiser */ | 
| +  /* The random check-hash initializer */ | 
| sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); | 
| put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); | 
| /* The initial database size */ | 
| @@ -1590,12 +1625,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ | 
|  | 
| if( !zMaster | 
| || pPager->journalMode==PAGER_JOURNALMODE_MEMORY | 
| -   || pPager->journalMode==PAGER_JOURNALMODE_OFF | 
| +   || !isOpen(pPager->jfd) | 
| ){ | 
| return SQLITE_OK; | 
| } | 
| pPager->setMaster = 1; | 
| -  assert( isOpen(pPager->jfd) ); | 
| assert( pPager->journalHdr <= pPager->journalOff ); | 
|  | 
| /* Calculate the length in bytes and the checksum of zMaster */ | 
| @@ -1644,21 +1678,6 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ | 
| } | 
|  | 
| /* | 
| -** Find a page in the hash table given its page number. Return | 
| -** a pointer to the page or NULL if the requested page is not | 
| -** already in memory. | 
| -*/ | 
| -static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ | 
| -  PgHdr *p;                         /* Return value */ | 
| - | 
| -  /* It is not possible for a call to PcacheFetch() with createFlag==0 to | 
| -  ** fail, since no attempt to allocate dynamic memory will be made. | 
| -  */ | 
| -  (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p); | 
| -  return p; | 
| -} | 
| - | 
| -/* | 
| ** Discard the entire contents of the in-memory page-cache. | 
| */ | 
| static void pager_reset(Pager *pPager){ | 
| @@ -1788,6 +1807,7 @@ static void pager_unlock(Pager *pPager){ | 
| pPager->changeCountDone = pPager->tempFile; | 
| pPager->eState = PAGER_OPEN; | 
| pPager->errCode = SQLITE_OK; | 
| +    if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); | 
| } | 
|  | 
| pPager->journalOff = 0; | 
| @@ -1829,6 +1849,8 @@ static int pager_error(Pager *pPager, int rc){ | 
| return rc; | 
| } | 
|  | 
| +static int pager_truncate(Pager *pPager, Pgno nPage); | 
| + | 
| /* | 
| ** This routine ends a transaction. A transaction is usually ended by | 
| ** either a COMMIT or a ROLLBACK operation. This routine may be called | 
| @@ -1882,7 +1904,7 @@ static int pager_error(Pager *pPager, int rc){ | 
| ** to the first error encountered (the journal finalization one) is | 
| ** 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 rc2 = SQLITE_OK;     /* Error code from db file unlock operation */ | 
|  | 
| @@ -1919,6 +1941,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){ | 
| rc = SQLITE_OK; | 
| }else{ | 
| rc = sqlite3OsTruncate(pPager->jfd, 0); | 
| +        if( rc==SQLITE_OK && pPager->fullSync ){ | 
| +          /* Make sure the new file size is written into the inode right away. | 
| +          ** Otherwise the journal might resurrect following a power loss and | 
| +          ** cause the last transaction to roll back.  See | 
| +          ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773 | 
| +          */ | 
| +          rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); | 
| +        } | 
| } | 
| pPager->journalOff = 0; | 
| }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST | 
| @@ -1932,12 +1962,13 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){ | 
| ** file should be closed and deleted. If this connection writes to | 
| ** the database file, it will do so using an in-memory journal. | 
| */ | 
| +      int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd)); | 
| assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE | 
| || pPager->journalMode==PAGER_JOURNALMODE_MEMORY | 
| || pPager->journalMode==PAGER_JOURNALMODE_WAL | 
| ); | 
| sqlite3OsClose(pPager->jfd); | 
| -      if( !pPager->tempFile ){ | 
| +      if( bDelete ){ | 
| rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); | 
| } | 
| } | 
| @@ -1946,10 +1977,10 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){ | 
| #ifdef SQLITE_CHECK_PAGES | 
| sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash); | 
| if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){ | 
| -    PgHdr *p = pager_lookup(pPager, 1); | 
| +    PgHdr *p = sqlite3PagerLookup(pPager, 1); | 
| if( p ){ | 
| p->pageHash = 0; | 
| -      sqlite3PagerUnref(p); | 
| +      sqlite3PagerUnrefNotNull(p); | 
| } | 
| } | 
| #endif | 
| @@ -1967,7 +1998,22 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){ | 
| */ | 
| rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); | 
| 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( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){ | 
| +    rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); | 
| +    if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; | 
| } | 
| + | 
| if( !pPager->exclusiveMode | 
| && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) | 
| ){ | 
| @@ -2006,7 +2052,7 @@ static void pagerUnlockAndRollback(Pager *pPager){ | 
| sqlite3EndBenignMalloc(); | 
| }else if( !pPager->exclusiveMode ){ | 
| assert( pPager->eState==PAGER_READER ); | 
| -      pager_end_transaction(pPager, 0); | 
| +      pager_end_transaction(pPager, 0, 0); | 
| } | 
| } | 
| pager_unlock(pPager); | 
| @@ -2210,7 +2256,7 @@ static int pager_playback_one_page( | 
| if( pagerUseWal(pPager) ){ | 
| pPg = 0; | 
| }else{ | 
| -    pPg = pager_lookup(pPager, pgno); | 
| +    pPg = sqlite3PagerLookup(pPager, pgno); | 
| } | 
| assert( pPg || !MEMDB ); | 
| assert( pPager->eState!=PAGER_OPEN || pPg==0 ); | 
| @@ -2230,7 +2276,7 @@ static int pager_playback_one_page( | 
| i64 ofst = (pgno-1)*(i64)pPager->pageSize; | 
| testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); | 
| assert( !pagerUseWal(pPager) ); | 
| -    rc = sqlite3OsWrite(pPager->fd, (u8*)aData, pPager->pageSize, ofst); | 
| +    rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); | 
| if( pgno>pPager->dbFileSize ){ | 
| pPager->dbFileSize = pgno; | 
| } | 
| @@ -2257,11 +2303,11 @@ static int pager_playback_one_page( | 
| ** requiring a journal-sync before it is written. | 
| */ | 
| assert( isSavepnt ); | 
| -    assert( pPager->doNotSpill==0 ); | 
| -    pPager->doNotSpill++; | 
| +    assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 ); | 
| +    pPager->doNotSpill |= SPILLFLAG_ROLLBACK; | 
| rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1); | 
| -    assert( pPager->doNotSpill==1 ); | 
| -    pPager->doNotSpill--; | 
| +    assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 ); | 
| +    pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK; | 
| if( rc!=SQLITE_OK ) return rc; | 
| pPg->flags &= ~PGHDR_NEED_READ; | 
| sqlite3PcacheMakeDirty(pPg); | 
| @@ -2390,7 +2436,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){ | 
| rc = sqlite3OsFileSize(pMaster, &nMasterJournal); | 
| if( rc!=SQLITE_OK ) goto delmaster_out; | 
| nMasterPtr = pVfs->mxPathname+1; | 
| -  zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1); | 
| +  zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1); | 
| if( !zMasterJournal ){ | 
| rc = SQLITE_NOMEM; | 
| goto delmaster_out; | 
| @@ -2459,7 +2505,7 @@ delmaster_out: | 
| ** If the file on disk is currently larger than nPage pages, then use the VFS | 
| ** xTruncate() method to truncate it. | 
| ** | 
| -** Or, it might might be the case that the file on disk is smaller than | 
| +** Or, it might be the case that the file on disk is smaller than | 
| ** nPage pages. Some operating system implementations can get confused if | 
| ** you try to truncate a file to some size that is larger than it | 
| ** currently is, so detect this case and write a single zero byte to | 
| @@ -2485,10 +2531,9 @@ static int pager_truncate(Pager *pPager, Pgno nPage){ | 
| if( rc==SQLITE_OK && currentSize!=newSize ){ | 
| if( currentSize>newSize ){ | 
| rc = sqlite3OsTruncate(pPager->fd, newSize); | 
| -      }else{ | 
| +      }else if( (currentSize+szPage)<=newSize ){ | 
| char *pTmp = pPager->pTmpSpace; | 
| memset(pTmp, 0, szPage); | 
| -        testcase( (newSize-szPage) <  currentSize ); | 
| testcase( (newSize-szPage) == currentSize ); | 
| testcase( (newSize-szPage) >  currentSize ); | 
| rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); | 
| @@ -2502,9 +2547,24 @@ static int pager_truncate(Pager *pPager, Pgno nPage){ | 
| } | 
|  | 
| /* | 
| +** Return a sanitized version of the sector-size of OS file pFile. The | 
| +** return value is guaranteed to lie between 32 and MAX_SECTOR_SIZE. | 
| +*/ | 
| +int sqlite3SectorSize(sqlite3_file *pFile){ | 
| +  int iRet = sqlite3OsSectorSize(pFile); | 
| +  if( iRet<32 ){ | 
| +    iRet = 512; | 
| +  }else if( iRet>MAX_SECTOR_SIZE ){ | 
| +    assert( MAX_SECTOR_SIZE>=512 ); | 
| +    iRet = MAX_SECTOR_SIZE; | 
| +  } | 
| +  return iRet; | 
| +} | 
| + | 
| +/* | 
| ** Set the value of the Pager.sectorSize variable for the given | 
| ** pager based on the value returned by the xSectorSize method | 
| -** of the open database file. The sector size will be used used | 
| +** of the open database file. The sector size will be used | 
| ** to determine the size and alignment of journal header and | 
| ** master journal pointers within created journal files. | 
| ** | 
| @@ -2514,23 +2574,29 @@ static int pager_truncate(Pager *pPager, Pgno nPage){ | 
| ** the value returned by the xSectorSize() method rounded up to 32 if | 
| ** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it | 
| ** is greater than MAX_SECTOR_SIZE. | 
| +** | 
| +** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set | 
| +** the effective sector size to its minimum value (512).  The purpose of | 
| +** pPager->sectorSize is to define the "blast radius" of bytes that | 
| +** might change if a crash occurs while writing to a single byte in | 
| +** that range.  But with POWERSAFE_OVERWRITE, the blast radius is zero | 
| +** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector | 
| +** size.  For backwards compatibility of the rollback journal file format, | 
| +** we cannot reduce the effective sector size below 512. | 
| */ | 
| static void setSectorSize(Pager *pPager){ | 
| assert( isOpen(pPager->fd) || pPager->tempFile ); | 
|  | 
| -  if( !pPager->tempFile ){ | 
| +  if( pPager->tempFile | 
| +   || (sqlite3OsDeviceCharacteristics(pPager->fd) & | 
| +              SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0 | 
| +  ){ | 
| /* Sector size doesn't matter for temporary files. Also, the file | 
| ** may not have been opened yet, in which case the OsSectorSize() | 
| -    ** call will segfault. | 
| -    */ | 
| -    pPager->sectorSize = sqlite3OsSectorSize(pPager->fd); | 
| -  } | 
| -  if( pPager->sectorSize<32 ){ | 
| +    ** call will segfault. */ | 
| pPager->sectorSize = 512; | 
| -  } | 
| -  if( pPager->sectorSize>MAX_SECTOR_SIZE ){ | 
| -    assert( MAX_SECTOR_SIZE>=512 ); | 
| -    pPager->sectorSize = MAX_SECTOR_SIZE; | 
| +  }else{ | 
| +    pPager->sectorSize = sqlite3SectorSize(pPager->fd); | 
| } | 
| } | 
|  | 
| @@ -2601,6 +2667,7 @@ static int pager_playback(Pager *pPager, int isHot){ | 
| int res = 1;             /* Value returned by sqlite3OsAccess() */ | 
| char *zMaster = 0;       /* Name of master journal file if any */ | 
| int needPagerReset;      /* True to reset page prior to first page rollback */ | 
| +  int nPlayback = 0;       /* Total number of pages restored from journal */ | 
|  | 
| /* Figure out how many records are in the journal.  Abort early if | 
| ** the journal is empty. | 
| @@ -2701,9 +2768,10 @@ static int pager_playback(Pager *pPager, int isHot){ | 
| needPagerReset = 0; | 
| } | 
| rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0); | 
| -      if( rc!=SQLITE_OK ){ | 
| +      if( rc==SQLITE_OK ){ | 
| +        nPlayback++; | 
| +      }else{ | 
| if( rc==SQLITE_DONE ){ | 
| -          rc = SQLITE_OK; | 
| pPager->journalOff = szJ; | 
| break; | 
| }else if( rc==SQLITE_IOERR_SHORT_READ ){ | 
| @@ -2734,10 +2802,11 @@ end_playback: | 
| ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the | 
| ** assertion that the transaction counter was modified. | 
| */ | 
| -  assert( | 
| -    pPager->fd->pMethods==0 || | 
| -    sqlite3OsFileControl(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0)>=SQLITE_OK | 
| -  ); | 
| +#ifdef SQLITE_DEBUG | 
| +  if( pPager->fd->pMethods ){ | 
| +    sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0); | 
| +  } | 
| +#endif | 
|  | 
| /* If this playback is happening automatically as a result of an IO or | 
| ** malloc error that occurred after the change-counter was updated but | 
| @@ -2758,10 +2827,10 @@ end_playback: | 
| if( rc==SQLITE_OK | 
| && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) | 
| ){ | 
| -    rc = sqlite3PagerSync(pPager); | 
| +    rc = sqlite3PagerSync(pPager, 0); | 
| } | 
| 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 ); | 
| } | 
| if( rc==SQLITE_OK && zMaster[0] && res ){ | 
| @@ -2771,6 +2840,10 @@ end_playback: | 
| rc = pager_delmaster(pPager, zMaster); | 
| testcase( rc!=SQLITE_OK ); | 
| } | 
| +  if( isHot && nPlayback ){ | 
| +    sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s", | 
| +                nPlayback, pPager->zJournal); | 
| +  } | 
|  | 
| /* The Pager.sectorSize variable may have been updated while rolling | 
| ** back a journal created by a process with a different sector size | 
| @@ -2792,27 +2865,22 @@ end_playback: | 
| ** If an IO error occurs, then the IO error is returned to the caller. | 
| ** Otherwise, SQLITE_OK is returned. | 
| */ | 
| -static int readDbPage(PgHdr *pPg){ | 
| +static int readDbPage(PgHdr *pPg, u32 iFrame){ | 
| Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ | 
| Pgno pgno = pPg->pgno;       /* Page number to read */ | 
| int rc = SQLITE_OK;          /* Return code */ | 
| -  int isInWal = 0;             /* True if page is in log file */ | 
| int pgsz = pPager->pageSize; /* Number of bytes to read */ | 
|  | 
| assert( pPager->eState>=PAGER_READER && !MEMDB ); | 
| assert( isOpen(pPager->fd) ); | 
|  | 
| -  if( NEVER(!isOpen(pPager->fd)) ){ | 
| -    assert( pPager->tempFile ); | 
| -    memset(pPg->pData, 0, pPager->pageSize); | 
| -    return SQLITE_OK; | 
| -  } | 
| - | 
| -  if( pagerUseWal(pPager) ){ | 
| +#ifndef SQLITE_OMIT_WAL | 
| +  if( iFrame ){ | 
| /* Try to pull the page from the write-ahead log. */ | 
| -    rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData); | 
| -  } | 
| -  if( rc==SQLITE_OK && !isInWal ){ | 
| +    rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); | 
| +  }else | 
| +#endif | 
| +  { | 
| i64 iOffset = (pgno-1)*(i64)pPager->pageSize; | 
| rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); | 
| if( rc==SQLITE_IOERR_SHORT_READ ){ | 
| @@ -2891,16 +2959,21 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){ | 
| Pager *pPager = (Pager *)pCtx; | 
| PgHdr *pPg; | 
|  | 
| +  assert( pagerUseWal(pPager) ); | 
| pPg = sqlite3PagerLookup(pPager, iPg); | 
| if( pPg ){ | 
| if( sqlite3PcachePageRefcount(pPg)==1 ){ | 
| sqlite3PcacheDrop(pPg); | 
| }else{ | 
| -      rc = readDbPage(pPg); | 
| +      u32 iFrame = 0; | 
| +      rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); | 
| +      if( rc==SQLITE_OK ){ | 
| +        rc = readDbPage(pPg, iFrame); | 
| +      } | 
| if( rc==SQLITE_OK ){ | 
| pPager->xReiniter(pPg); | 
| } | 
| -      sqlite3PagerUnref(pPg); | 
| +      sqlite3PagerUnrefNotNull(pPg); | 
| } | 
| } | 
|  | 
| @@ -2956,15 +3029,16 @@ static int pagerWalFrames( | 
| Pager *pPager,                  /* Pager object */ | 
| PgHdr *pList,                   /* List of frames to log */ | 
| Pgno nTruncate,                 /* Database size after this commit */ | 
| -  int isCommit,                   /* True if this is a commit */ | 
| -  int syncFlags                   /* Flags to pass to OsSync() (or 0) */ | 
| +  int isCommit                    /* True if this is a commit */ | 
| ){ | 
| int rc;                         /* Return code */ | 
| +  int nList;                      /* Number of pages in pList */ | 
| #if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES) | 
| PgHdr *p;                       /* For looping over pages */ | 
| #endif | 
|  | 
| assert( pPager->pWal ); | 
| +  assert( pList ); | 
| #ifdef SQLITE_DEBUG | 
| /* Verify that the page list is in accending order */ | 
| for(p=pList; p && p->pDirty; p=p->pDirty){ | 
| @@ -2972,6 +3046,7 @@ static int pagerWalFrames( | 
| } | 
| #endif | 
|  | 
| +  assert( pList->pDirty==0 || isCommit ); | 
| if( isCommit ){ | 
| /* If a WAL transaction is being committed, there is no point in writing | 
| ** any pages with page numbers greater than nTruncate into the WAL file. | 
| @@ -2979,15 +3054,22 @@ static int pagerWalFrames( | 
| ** list here. */ | 
| PgHdr *p; | 
| PgHdr **ppNext = &pList; | 
| -    for(p=pList; (*ppNext = p); p=p->pDirty){ | 
| -      if( p->pgno<=nTruncate ) ppNext = &p->pDirty; | 
| +    nList = 0; | 
| +    for(p=pList; (*ppNext = p)!=0; p=p->pDirty){ | 
| +      if( p->pgno<=nTruncate ){ | 
| +        ppNext = &p->pDirty; | 
| +        nList++; | 
| +      } | 
| } | 
| assert( pList ); | 
| +  }else{ | 
| +    nList = 1; | 
| } | 
| +  pPager->aStat[PAGER_STAT_WRITE] += nList; | 
|  | 
| if( pList->pgno==1 ) pager_write_changecounter(pList); | 
| rc = sqlite3WalFrames(pPager->pWal, | 
| -      pPager->pageSize, pList, nTruncate, isCommit, syncFlags | 
| +      pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags | 
| ); | 
| if( rc==SQLITE_OK && pPager->pBackup ){ | 
| PgHdr *p; | 
| @@ -3031,6 +3113,7 @@ static int pagerBeginReadTransaction(Pager *pPager){ | 
| rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); | 
| if( rc!=SQLITE_OK || changed ){ | 
| pager_reset(pPager); | 
| +    if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); | 
| } | 
|  | 
| return rc; | 
| @@ -3056,7 +3139,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ | 
| ** contains no valid committed transactions. | 
| */ | 
| assert( pPager->eState==PAGER_OPEN ); | 
| -  assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock ); | 
| +  assert( pPager->eLock>=SHARED_LOCK ); | 
| nPage = sqlite3WalDbsize(pPager->pWal); | 
|  | 
| /* If the database size was not available from the WAL sub-system, | 
| @@ -3074,10 +3157,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ | 
| return rc; | 
| } | 
| } | 
| -    nPage = (Pgno)(n / pPager->pageSize); | 
| -    if( nPage==0 && n>0 ){ | 
| -      nPage = 1; | 
| -    } | 
| +    nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize); | 
| } | 
|  | 
| /* If the current number of pages in the file is greater than the | 
| @@ -3114,7 +3194,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ | 
| static int pagerOpenWalIfPresent(Pager *pPager){ | 
| int rc = SQLITE_OK; | 
| assert( pPager->eState==PAGER_OPEN ); | 
| -  assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock ); | 
| +  assert( pPager->eLock>=SHARED_LOCK ); | 
|  | 
| if( !pPager->tempFile ){ | 
| int isWal;                    /* True if WAL file exists */ | 
| @@ -3124,6 +3204,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){ | 
| if( rc ) return rc; | 
| if( nPage==0 ){ | 
| rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); | 
| +      if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK; | 
| isWal = 0; | 
| }else{ | 
| rc = sqlite3OsAccess( | 
| @@ -3267,13 +3348,13 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ | 
| */ | 
| if( pSavepoint ){ | 
| u32 ii;            /* Loop counter */ | 
| -    i64 offset = pSavepoint->iSubRec*(4+pPager->pageSize); | 
| +    i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize); | 
|  | 
| if( pagerUseWal(pPager) ){ | 
| rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData); | 
| } | 
| for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){ | 
| -      assert( offset==ii*(4+pPager->pageSize) ); | 
| +      assert( offset==(i64)ii*(4+pPager->pageSize) ); | 
| rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1); | 
| } | 
| assert( rc!=SQLITE_DONE ); | 
| @@ -3295,9 +3376,42 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ | 
| } | 
|  | 
| /* | 
| -** Adjust the robustness of the database to damage due to OS crashes | 
| -** or power failures by changing the number of syncs()s when writing | 
| -** the rollback journal.  There are three levels: | 
| +** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap. | 
| +*/ | 
| +static void pagerFixMaplimit(Pager *pPager){ | 
| +#if SQLITE_MAX_MMAP_SIZE>0 | 
| +  sqlite3_file *fd = pPager->fd; | 
| +  if( isOpen(fd) && fd->pMethods->iVersion>=3 ){ | 
| +    sqlite3_int64 sz; | 
| +    sz = pPager->szMmap; | 
| +    pPager->bUseFetch = (sz>0); | 
| +    sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz); | 
| +  } | 
| +#endif | 
| +} | 
| + | 
| +/* | 
| +** Change the maximum size of any memory mapping made of the database file. | 
| +*/ | 
| +void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){ | 
| +  pPager->szMmap = szMmap; | 
| +  pagerFixMaplimit(pPager); | 
| +} | 
| + | 
| +/* | 
| +** Free as much memory as possible from the pager. | 
| +*/ | 
| +void sqlite3PagerShrink(Pager *pPager){ | 
| +  sqlite3PcacheShrink(pPager->pPCache); | 
| +} | 
| + | 
| +/* | 
| +** Adjust settings of the pager to those specified in the pgFlags parameter. | 
| +** | 
| +** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness | 
| +** of the database to damage due to OS crashes or power failures by | 
| +** changing the number of syncs()s when writing the journals. | 
| +** There are three levels: | 
| ** | 
| **    OFF       sqlite3OsSync() is never called.  This is the default | 
| **              for temporary and transient files. | 
| @@ -3338,28 +3452,36 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ | 
| ** and FULL=3. | 
| */ | 
| #ifndef SQLITE_OMIT_PAGER_PRAGMAS | 
| -void sqlite3PagerSetSafetyLevel( | 
| +void sqlite3PagerSetFlags( | 
| Pager *pPager,        /* The pager to set safety level for */ | 
| -  int level,            /* PRAGMA synchronous.  1=OFF, 2=NORMAL, 3=FULL */ | 
| -  int bFullFsync,       /* PRAGMA fullfsync */ | 
| -  int bCkptFullFsync    /* PRAGMA checkpoint_fullfsync */ | 
| +  unsigned pgFlags      /* Various flags */ | 
| ){ | 
| +  unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK; | 
| assert( level>=1 && level<=3 ); | 
| pPager->noSync =  (level==1 || pPager->tempFile) ?1:0; | 
| pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0; | 
| if( pPager->noSync ){ | 
| pPager->syncFlags = 0; | 
| pPager->ckptSyncFlags = 0; | 
| -  }else if( bFullFsync ){ | 
| +  }else if( pgFlags & PAGER_FULLFSYNC ){ | 
| pPager->syncFlags = SQLITE_SYNC_FULL; | 
| pPager->ckptSyncFlags = SQLITE_SYNC_FULL; | 
| -  }else if( bCkptFullFsync ){ | 
| +  }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){ | 
| pPager->syncFlags = SQLITE_SYNC_NORMAL; | 
| pPager->ckptSyncFlags = SQLITE_SYNC_FULL; | 
| }else{ | 
| pPager->syncFlags = SQLITE_SYNC_NORMAL; | 
| pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; | 
| } | 
| +  pPager->walSyncFlags = pPager->syncFlags; | 
| +  if( pPager->fullSync ){ | 
| +    pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS; | 
| +  } | 
| +  if( pgFlags & PAGER_CACHESPILL ){ | 
| +    pPager->doNotSpill &= ~SPILLFLAG_OFF; | 
| +  }else{ | 
| +    pPager->doNotSpill |= SPILLFLAG_OFF; | 
| +  } | 
| } | 
| #endif | 
|  | 
| @@ -3430,9 +3552,16 @@ void sqlite3PagerSetBusyhandler( | 
| Pager *pPager,                       /* Pager object */ | 
| int (*xBusyHandler)(void *),         /* Pointer to busy-handler function */ | 
| void *pBusyHandlerArg                /* Argument to pass to xBusyHandler */ | 
| -){ | 
| +){ | 
| pPager->xBusyHandler = xBusyHandler; | 
| pPager->pBusyHandlerArg = pBusyHandlerArg; | 
| + | 
| +  if( isOpen(pPager->fd) ){ | 
| +    void **ap = (void **)&pPager->xBusyHandler; | 
| +    assert( ((int(*)(void *))(ap[0]))==xBusyHandler ); | 
| +    assert( ap[1]==pBusyHandlerArg ); | 
| +    sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap); | 
| +  } | 
| } | 
|  | 
| /* | 
| @@ -3497,11 +3626,15 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){ | 
|  | 
| if( rc==SQLITE_OK ){ | 
| pager_reset(pPager); | 
| -      pPager->dbSize = (Pgno)(nByte/pageSize); | 
| -      pPager->pageSize = pageSize; | 
| +      rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); | 
| +    } | 
| +    if( rc==SQLITE_OK ){ | 
| sqlite3PageFree(pPager->pTmpSpace); | 
| pPager->pTmpSpace = pNew; | 
| -      sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); | 
| +      pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); | 
| +      pPager->pageSize = pageSize; | 
| +    }else{ | 
| +      sqlite3PageFree(pNew); | 
| } | 
| } | 
|  | 
| @@ -3511,6 +3644,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){ | 
| assert( nReserve>=0 && nReserve<1000 ); | 
| pPager->nReserve = (i16)nReserve; | 
| pagerReportSize(pPager); | 
| +    pagerFixMaplimit(pPager); | 
| } | 
| return rc; | 
| } | 
| @@ -3634,7 +3768,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ | 
| int rc;                              /* Return code */ | 
|  | 
| /* Check that this is either a no-op (because the requested lock is | 
| -  ** already held, or one of the transistions that the busy-handler | 
| +  ** already held), or one of the transitions that the busy-handler | 
| ** may be invoked during, according to the comment above | 
| ** sqlite3PagerSetBusyhandler(). | 
| */ | 
| @@ -3664,7 +3798,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ | 
| ** dirty page were to be discarded from the cache via the pagerStress() | 
| ** routine, pagerStress() would not write the current page content to | 
| ** the database file. If a savepoint transaction were rolled back after | 
| -** this happened, the correct behaviour would be to restore the current | 
| +** this happened, the correct behavior would be to restore the current | 
| ** content of the page. However, since this content is not present in either | 
| ** the database file or the portion of the rollback journal and | 
| ** sub-journal rolled back the content could not be restored and the | 
| @@ -3688,12 +3822,26 @@ static void assertTruncateConstraint(Pager *pPager){ | 
| ** function does not actually modify the database file on disk. It | 
| ** just sets the internal state of the pager object so that the | 
| ** truncation will be done when the current transaction is committed. | 
| +** | 
| +** This function is only called right before committing a transaction. | 
| +** Once this function has been called, the transaction must either be | 
| +** rolled back or committed. It is not safe to call this function and | 
| +** then continue writing to the database. | 
| */ | 
| void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ | 
| assert( pPager->dbSize>=nPage ); | 
| assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); | 
| pPager->dbSize = nPage; | 
| -  assertTruncateConstraint(pPager); | 
| + | 
| +  /* At one point the code here called assertTruncateConstraint() to | 
| +  ** ensure that all pages being truncated away by this operation are, | 
| +  ** if one or more savepoints are open, present in the savepoint | 
| +  ** journal so that they can be restored if the savepoint is rolled | 
| +  ** back. This is no longer necessary as this function is now only | 
| +  ** called right before committing a transaction. So although the | 
| +  ** Pager object may still have open savepoints (Pager.nSavepoint!=0), | 
| +  ** they cannot be rolled back. So the assertTruncateConstraint() call | 
| +  ** is no longer correct. */ | 
| } | 
|  | 
|  | 
| @@ -3723,6 +3871,81 @@ static int pagerSyncHotJournal(Pager *pPager){ | 
| } | 
|  | 
| /* | 
| +** Obtain a reference to a memory mapped page object for page number pgno. | 
| +** The new object will use the pointer pData, obtained from xFetch(). | 
| +** If successful, set *ppPage to point to the new page reference | 
| +** and return SQLITE_OK. Otherwise, return an SQLite error code and set | 
| +** *ppPage to zero. | 
| +** | 
| +** Page references obtained by calling this function should be released | 
| +** by calling pagerReleaseMapPage(). | 
| +*/ | 
| +static int pagerAcquireMapPage( | 
| +  Pager *pPager,                  /* Pager object */ | 
| +  Pgno pgno,                      /* Page number */ | 
| +  void *pData,                    /* xFetch()'d data for this page */ | 
| +  PgHdr **ppPage                  /* OUT: Acquired page object */ | 
| +){ | 
| +  PgHdr *p;                       /* Memory mapped page to return */ | 
| + | 
| +  if( pPager->pMmapFreelist ){ | 
| +    *ppPage = p = pPager->pMmapFreelist; | 
| +    pPager->pMmapFreelist = p->pDirty; | 
| +    p->pDirty = 0; | 
| +    memset(p->pExtra, 0, pPager->nExtra); | 
| +  }else{ | 
| +    *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra); | 
| +    if( p==0 ){ | 
| +      sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData); | 
| +      return SQLITE_NOMEM; | 
| +    } | 
| +    p->pExtra = (void *)&p[1]; | 
| +    p->flags = PGHDR_MMAP; | 
| +    p->nRef = 1; | 
| +    p->pPager = pPager; | 
| +  } | 
| + | 
| +  assert( p->pExtra==(void *)&p[1] ); | 
| +  assert( p->pPage==0 ); | 
| +  assert( p->flags==PGHDR_MMAP ); | 
| +  assert( p->pPager==pPager ); | 
| +  assert( p->nRef==1 ); | 
| + | 
| +  p->pgno = pgno; | 
| +  p->pData = pData; | 
| +  pPager->nMmapOut++; | 
| + | 
| +  return SQLITE_OK; | 
| +} | 
| + | 
| +/* | 
| +** Release a reference to page pPg. pPg must have been returned by an | 
| +** earlier call to pagerAcquireMapPage(). | 
| +*/ | 
| +static void pagerReleaseMapPage(PgHdr *pPg){ | 
| +  Pager *pPager = pPg->pPager; | 
| +  pPager->nMmapOut--; | 
| +  pPg->pDirty = pPager->pMmapFreelist; | 
| +  pPager->pMmapFreelist = pPg; | 
| + | 
| +  assert( pPager->fd->pMethods->iVersion>=3 ); | 
| +  sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData); | 
| +} | 
| + | 
| +/* | 
| +** Free all PgHdr objects stored in the Pager.pMmapFreelist list. | 
| +*/ | 
| +static void pagerFreeMapHdrs(Pager *pPager){ | 
| +  PgHdr *p; | 
| +  PgHdr *pNext; | 
| +  for(p=pPager->pMmapFreelist; p; p=pNext){ | 
| +    pNext = p->pDirty; | 
| +    sqlite3_free(p); | 
| +  } | 
| +} | 
| + | 
| + | 
| +/* | 
| ** Shutdown the page cache.  Free all memory and close all files. | 
| ** | 
| ** If a transaction was in progress when this routine is called, that | 
| @@ -3739,8 +3962,10 @@ static int pagerSyncHotJournal(Pager *pPager){ | 
| int sqlite3PagerClose(Pager *pPager){ | 
| u8 *pTmp = (u8 *)pPager->pTmpSpace; | 
|  | 
| +  assert( assert_pager_state(pPager) ); | 
| disable_simulated_io_errors(); | 
| sqlite3BeginBenignMalloc(); | 
| +  pagerFreeMapHdrs(pPager); | 
| /* pPager->errCode = 0; */ | 
| pPager->exclusiveMode = 0; | 
| #ifndef SQLITE_OMIT_WAL | 
| @@ -3810,7 +4035,7 @@ void sqlite3PagerRef(DbPage *pPg){ | 
| ** | 
| ** If the Pager.noSync flag is set, then this function is a no-op. | 
| ** Otherwise, the actions required depend on the journal-mode and the | 
| -** device characteristics of the the file-system, as follows: | 
| +** device characteristics of the file-system, as follows: | 
| ** | 
| **   * If the journal file is an in-memory journal file, no action need | 
| **     be taken. | 
| @@ -4002,9 +4227,12 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ | 
| ** file size will be. | 
| */ | 
| assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); | 
| -  if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){ | 
| +  if( rc==SQLITE_OK | 
| +   && pPager->dbHintSize<pPager->dbSize | 
| +   && (pList->pDirty || pList->pgno>pPager->dbHintSize) | 
| +  ){ | 
| sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; | 
| -    sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); | 
| +    sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); | 
| pPager->dbHintSize = pPager->dbSize; | 
| } | 
|  | 
| @@ -4042,6 +4270,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ | 
| if( pgno>pPager->dbFileSize ){ | 
| pPager->dbFileSize = pgno; | 
| } | 
| +      pPager->aStat[PAGER_STAT_WRITE]++; | 
|  | 
| /* Update any backup objects copying the contents of this pager. */ | 
| sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData); | 
| @@ -4050,7 +4279,6 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ | 
| PAGERID(pPager), pgno, pager_pagehash(pList))); | 
| IOTRACE(("PGOUT %p %d\n", pPager, pgno)); | 
| PAGER_INCR(sqlite3_pager_writedb_count); | 
| -      PAGER_INCR(pPager->nWrite); | 
| }else{ | 
| PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno)); | 
| } | 
| @@ -4104,7 +4332,7 @@ static int subjournalPage(PgHdr *pPg){ | 
| assert( isOpen(pPager->jfd) || pagerUseWal(pPager) ); | 
| assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 ); | 
| assert( pagerUseWal(pPager) | 
| -         || pageInJournal(pPg) | 
| +         || pageInJournal(pPager, pPg) | 
| || pPg->pgno>pPager->dbOrigSize | 
| ); | 
| rc = openSubJournal(pPager); | 
| @@ -4113,7 +4341,7 @@ static int subjournalPage(PgHdr *pPg){ | 
| ** write the journal record into the file.  */ | 
| if( rc==SQLITE_OK ){ | 
| void *pData = pPg->pData; | 
| -      i64 offset = pPager->nSubRec*(4+pPager->pageSize); | 
| +      i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); | 
| char *pData2; | 
|  | 
| CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2); | 
| @@ -4158,24 +4386,30 @@ static int pagerStress(void *p, PgHdr *pPg){ | 
| assert( pPg->pPager==pPager ); | 
| assert( pPg->flags&PGHDR_DIRTY ); | 
|  | 
| -  /* The doNotSyncSpill flag is set during times when doing a sync of | 
| +  /* The doNotSpill NOSYNC bit is set during times when doing a sync of | 
| ** journal (and adding a new header) is not allowed.  This occurs | 
| ** during calls to sqlite3PagerWrite() while trying to journal multiple | 
| ** pages belonging to the same sector. | 
| ** | 
| -  ** The doNotSpill flag inhibits all cache spilling regardless of whether | 
| -  ** or not a sync is required.  This is set during a rollback. | 
| +  ** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling | 
| +  ** regardless of whether or not a sync is required.  This is set during | 
| +  ** a rollback or by user request, respectively. | 
| ** | 
| ** Spilling is also prohibited when in an error state since that could | 
| -  ** lead to database corruption.   In the current implementaton it | 
| -  ** is impossible for sqlite3PCacheFetch() to be called with createFlag==1 | 
| +  ** lead to database corruption.   In the current implementation it | 
| +  ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3 | 
| ** while in the error state, hence it is impossible for this routine to | 
| ** be called in the error state.  Nevertheless, we include a NEVER() | 
| ** test for the error state as a safeguard against future changes. | 
| */ | 
| if( NEVER(pPager->errCode) ) return SQLITE_OK; | 
| -  if( pPager->doNotSpill ) return SQLITE_OK; | 
| -  if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){ | 
| +  testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK ); | 
| +  testcase( pPager->doNotSpill & SPILLFLAG_OFF ); | 
| +  testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC ); | 
| +  if( pPager->doNotSpill | 
| +   && ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0 | 
| +      || (pPg->flags & PGHDR_NEED_SYNC)!=0) | 
| +  ){ | 
| return SQLITE_OK; | 
| } | 
|  | 
| @@ -4186,7 +4420,7 @@ static int pagerStress(void *p, PgHdr *pPg){ | 
| rc = subjournalPage(pPg); | 
| } | 
| if( rc==SQLITE_OK ){ | 
| -      rc = pagerWalFrames(pPager, pPg, 0, 0, 0); | 
| +      rc = pagerWalFrames(pPager, pPg, 0, 0); | 
| } | 
| }else{ | 
|  | 
| @@ -4265,7 +4499,7 @@ static int pagerStress(void *p, PgHdr *pPg){ | 
| ** | 
| ** The flags argument is used to specify properties that affect the | 
| ** operation of the pager. It should be passed some bitwise combination | 
| -** of the PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK flags. | 
| +** of the PAGER_* flags. | 
| ** | 
| ** The vfsFlags parameter is a bitmask to pass to the flags parameter | 
| ** of the xOpen() method of the supplied VFS when opening files. | 
| @@ -4296,9 +4530,10 @@ int sqlite3PagerOpen( | 
| char *zPathname = 0;     /* Full path to database file */ | 
| int nPathname = 0;       /* Number of bytes in zPathname */ | 
| int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ | 
| -  int noReadlock = (flags & PAGER_NO_READLOCK)!=0;  /* True to omit read-lock */ | 
| int pcacheSize = sqlite3PcacheSize();       /* Bytes to allocate for PCache */ | 
| u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE;  /* Default page size */ | 
| +  const char *zUri = 0;    /* URI args to copy */ | 
| +  int nUri = 0;            /* Number of bytes of URI args at *zUri */ | 
|  | 
| /* Figure out how much space is required for each journal file-handle | 
| ** (there are two of them, the main journal and the sub-journal). This | 
| @@ -4320,7 +4555,12 @@ int sqlite3PagerOpen( | 
| #ifndef SQLITE_OMIT_MEMORYDB | 
| if( flags & PAGER_MEMORY ){ | 
| memDb = 1; | 
| -    zFilename = 0; | 
| +    if( zFilename && zFilename[0] ){ | 
| +      zPathname = sqlite3DbStrDup(0, zFilename); | 
| +      if( zPathname==0  ) return SQLITE_NOMEM; | 
| +      nPathname = sqlite3Strlen30(zPathname); | 
| +      zFilename = 0; | 
| +    } | 
| } | 
| #endif | 
|  | 
| @@ -4329,14 +4569,22 @@ int sqlite3PagerOpen( | 
| ** leave both nPathname and zPathname set to 0. | 
| */ | 
| if( zFilename && zFilename[0] ){ | 
| +    const char *z; | 
| nPathname = pVfs->mxPathname+1; | 
| -    zPathname = sqlite3Malloc(nPathname*2); | 
| +    zPathname = sqlite3DbMallocRaw(0, nPathname*2); | 
| if( zPathname==0 ){ | 
| return SQLITE_NOMEM; | 
| } | 
| zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ | 
| rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); | 
| nPathname = sqlite3Strlen30(zPathname); | 
| +    z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; | 
| +    while( *z ){ | 
| +      z += sqlite3Strlen30(z)+1; | 
| +      z += sqlite3Strlen30(z)+1; | 
| +    } | 
| +    nUri = (int)(&z[1] - zUri); | 
| +    assert( nUri>=0 ); | 
| if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ | 
| /* This branch is taken when the journal path required by | 
| ** the database being opened will be more than pVfs->mxPathname | 
| @@ -4347,7 +4595,7 @@ int sqlite3PagerOpen( | 
| rc = SQLITE_CANTOPEN_BKPT; | 
| } | 
| if( rc!=SQLITE_OK ){ | 
| -      sqlite3_free(zPathname); | 
| +      sqlite3DbFree(0, zPathname); | 
| return rc; | 
| } | 
| } | 
| @@ -4369,15 +4617,15 @@ int sqlite3PagerOpen( | 
| ROUND8(pcacheSize) +           /* PCache object */ | 
| ROUND8(pVfs->szOsFile) +       /* The main db file */ | 
| journalFileSize * 2 +          /* The two journal files */ | 
| -    nPathname + 1 +                /* zFilename */ | 
| -    nPathname + 8 + 1              /* zJournal */ | 
| +    nPathname + 1 + nUri +         /* zFilename */ | 
| +    nPathname + 8 + 2              /* zJournal */ | 
| #ifndef SQLITE_OMIT_WAL | 
| -    + nPathname + 4 + 1              /* zWal */ | 
| +    + nPathname + 4 + 2            /* zWal */ | 
| #endif | 
| ); | 
| assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); | 
| if( !pPtr ){ | 
| -    sqlite3_free(zPathname); | 
| +    sqlite3DbFree(0, zPathname); | 
| return SQLITE_NOMEM; | 
| } | 
| pPager =              (Pager*)(pPtr); | 
| @@ -4391,16 +4639,19 @@ int sqlite3PagerOpen( | 
| /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ | 
| if( zPathname ){ | 
| assert( nPathname>0 ); | 
| -    pPager->zJournal =   (char*)(pPtr += nPathname + 1); | 
| +    pPager->zJournal =   (char*)(pPtr += nPathname + 1 + nUri); | 
| memcpy(pPager->zFilename, zPathname, nPathname); | 
| +    if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri); | 
| memcpy(pPager->zJournal, zPathname, nPathname); | 
| -    memcpy(&pPager->zJournal[nPathname], "-journal", 8); | 
| +    memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2); | 
| +    sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal); | 
| #ifndef SQLITE_OMIT_WAL | 
| pPager->zWal = &pPager->zJournal[nPathname+8+1]; | 
| memcpy(pPager->zWal, zPathname, nPathname); | 
| -    memcpy(&pPager->zWal[nPathname], "-wal", 4); | 
| +    memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1); | 
| +    sqlite3FileSuffix3(pPager->zFilename, pPager->zWal); | 
| #endif | 
| -    sqlite3_free(zPathname); | 
| +    sqlite3DbFree(0, zPathname); | 
| } | 
| pPager->pVfs = pVfs; | 
| pPager->vfsFlags = vfsFlags; | 
| @@ -4421,30 +4672,38 @@ int sqlite3PagerOpen( | 
| **    + The value returned by sqlite3OsSectorSize() | 
| **    + The largest page size that can be written atomically. | 
| */ | 
| -    if( rc==SQLITE_OK && !readOnly ){ | 
| -      setSectorSize(pPager); | 
| -      assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); | 
| -      if( szPageDflt<pPager->sectorSize ){ | 
| -        if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ | 
| -          szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; | 
| -        }else{ | 
| -          szPageDflt = (u32)pPager->sectorSize; | 
| +    if( rc==SQLITE_OK ){ | 
| +      int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); | 
| +      if( !readOnly ){ | 
| +        setSectorSize(pPager); | 
| +        assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); | 
| +        if( szPageDflt<pPager->sectorSize ){ | 
| +          if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ | 
| +            szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; | 
| +          }else{ | 
| +            szPageDflt = (u32)pPager->sectorSize; | 
| +          } | 
| } | 
| -      } | 
| #ifdef SQLITE_ENABLE_ATOMIC_WRITE | 
| -      { | 
| -        int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); | 
| -        int ii; | 
| -        assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); | 
| -        assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); | 
| -        assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); | 
| -        for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ | 
| -          if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ | 
| -            szPageDflt = ii; | 
| +        { | 
| +          int ii; | 
| +          assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); | 
| +          assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); | 
| +          assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); | 
| +          for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ | 
| +            if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ | 
| +              szPageDflt = ii; | 
| +            } | 
| } | 
| } | 
| -      } | 
| #endif | 
| +      } | 
| +      pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0); | 
| +      if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 | 
| +       || sqlite3_uri_boolean(zFilename, "immutable", 0) ){ | 
| +          vfsFlags |= SQLITE_OPEN_READONLY; | 
| +          goto act_like_temp_file; | 
| +      } | 
| } | 
| }else{ | 
| /* If a temporary file is requested, it is not opened immediately. | 
| @@ -4454,10 +4713,14 @@ int sqlite3PagerOpen( | 
| ** This branch is also run for an in-memory database. An in-memory | 
| ** database is the same as a temp-file that is never written out to | 
| ** disk and uses an in-memory rollback journal. | 
| +    ** | 
| +    ** This branch also runs for files marked as immutable. | 
| */ | 
| +act_like_temp_file: | 
| tempFile = 1; | 
| -    pPager->eState = PAGER_READER; | 
| -    pPager->eLock = EXCLUSIVE_LOCK; | 
| +    pPager->eState = PAGER_READER;     /* Pretend we already have a lock */ | 
| +    pPager->eLock = EXCLUSIVE_LOCK;    /* Pretend we are in EXCLUSIVE locking mode */ | 
| +    pPager->noLock = 1;                /* Do no locking */ | 
| readOnly = (vfsFlags&SQLITE_OPEN_READONLY); | 
| } | 
|  | 
| @@ -4470,27 +4733,27 @@ int sqlite3PagerOpen( | 
| testcase( rc!=SQLITE_OK ); | 
| } | 
|  | 
| -  /* If an error occurred in either of the blocks above, free the | 
| -  ** Pager structure and close the file. | 
| +  /* Initialize the PCache object. */ | 
| +  if( rc==SQLITE_OK ){ | 
| +    assert( nExtra<1000 ); | 
| +    nExtra = ROUND8(nExtra); | 
| +    rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, | 
| +                           !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); | 
| +  } | 
| + | 
| +  /* If an error occurred above, free the  Pager structure and close the file. | 
| */ | 
| if( rc!=SQLITE_OK ){ | 
| -    assert( !pPager->pTmpSpace ); | 
| sqlite3OsClose(pPager->fd); | 
| +    sqlite3PageFree(pPager->pTmpSpace); | 
| sqlite3_free(pPager); | 
| return rc; | 
| } | 
|  | 
| -  /* Initialize the PCache object. */ | 
| -  assert( nExtra<1000 ); | 
| -  nExtra = ROUND8(nExtra); | 
| -  sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, | 
| -                    !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); | 
| - | 
| PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename)); | 
| IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) | 
|  | 
| pPager->useJournal = (u8)useJournal; | 
| -  pPager->noReadlock = (noReadlock && readOnly) ?1:0; | 
| /* pPager->stmtOpen = 0; */ | 
| /* pPager->stmtInUse = 0; */ | 
| /* pPager->nRef = 0; */ | 
| @@ -4499,9 +4762,6 @@ int sqlite3PagerOpen( | 
| /* pPager->nPage = 0; */ | 
| pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; | 
| /* pPager->state = PAGER_UNLOCK; */ | 
| -#if 0 | 
| -  assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) ); | 
| -#endif | 
| /* pPager->errMask = 0; */ | 
| pPager->tempFile = (u8)tempFile; | 
| assert( tempFile==PAGER_LOCKINGMODE_NORMAL | 
| @@ -4513,9 +4773,17 @@ int sqlite3PagerOpen( | 
| pPager->readOnly = (u8)readOnly; | 
| assert( useJournal || pPager->tempFile ); | 
| pPager->noSync = pPager->tempFile; | 
| -  pPager->fullSync = pPager->noSync ?0:1; | 
| -  pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL; | 
| -  pPager->ckptSyncFlags = pPager->syncFlags; | 
| +  if( pPager->noSync ){ | 
| +    assert( pPager->fullSync==0 ); | 
| +    assert( pPager->syncFlags==0 ); | 
| +    assert( pPager->walSyncFlags==0 ); | 
| +    assert( pPager->ckptSyncFlags==0 ); | 
| +  }else{ | 
| +    pPager->fullSync = 1; | 
| +    pPager->syncFlags = SQLITE_SYNC_NORMAL; | 
| +    pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS; | 
| +    pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; | 
| +  } | 
| /* pPager->pFirst = 0; */ | 
| /* pPager->pFirstSynced = 0; */ | 
| /* pPager->pLast = 0; */ | 
| @@ -4532,12 +4800,37 @@ int sqlite3PagerOpen( | 
| /* pPager->pBusyHandlerArg = 0; */ | 
| pPager->xReiniter = xReinit; | 
| /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ | 
| +  /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ | 
|  | 
| *ppPager = pPager; | 
| return SQLITE_OK; | 
| } | 
|  | 
|  | 
| +/* Verify that the database file has not be deleted or renamed out from | 
| +** under the pager.  Return SQLITE_OK if the database is still were it ought | 
| +** to be on disk.  Return non-zero (SQLITE_READONLY_DBMOVED or some other error | 
| +** code from sqlite3OsAccess()) if the database has gone missing. | 
| +*/ | 
| +static int databaseIsUnmoved(Pager *pPager){ | 
| +  int bHasMoved = 0; | 
| +  int rc; | 
| + | 
| +  if( pPager->tempFile ) return SQLITE_OK; | 
| +  if( pPager->dbSize==0 ) return SQLITE_OK; | 
| +  assert( pPager->zFilename && pPager->zFilename[0] ); | 
| +  rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved); | 
| +  if( rc==SQLITE_NOTFOUND ){ | 
| +    /* If the HAS_MOVED file-control is unimplemented, assume that the file | 
| +    ** has not been moved.  That is the historical behavior of SQLite: prior to | 
| +    ** version 3.8.3, it never checked */ | 
| +    rc = SQLITE_OK; | 
| +  }else if( rc==SQLITE_OK && bHasMoved ){ | 
| +    rc = SQLITE_READONLY_DBMOVED; | 
| +  } | 
| +  return rc; | 
| +} | 
| + | 
|  | 
| /* | 
| ** This function is called after transitioning from PAGER_UNLOCK to | 
| @@ -4603,15 +4896,17 @@ static int hasHotJournal(Pager *pPager, int *pExists){ | 
| if( rc==SQLITE_OK && !locked ){ | 
| Pgno nPage;                 /* Number of pages in database file */ | 
|  | 
| -      /* Check the size of the database file. If it consists of 0 pages, | 
| -      ** then delete the journal file. See the header comment above for | 
| -      ** the reasoning here.  Delete the obsolete journal file under | 
| -      ** a RESERVED lock to avoid race conditions and to avoid violating | 
| -      ** [H33020]. | 
| -      */ | 
| rc = pagerPagecount(pPager, &nPage); | 
| if( rc==SQLITE_OK ){ | 
| -        if( nPage==0 ){ | 
| +        /* If the database is zero pages in size, that means that either (1) the | 
| +        ** journal is a remnant from a prior database with the same name where | 
| +        ** the database file but not the journal was deleted, or (2) the initial | 
| +        ** transaction that populates a new database is being rolled back. | 
| +        ** In either case, the journal file can be deleted.  However, take care | 
| +        ** not to delete the journal file if it is already open due to | 
| +        ** journal_mode=PERSIST. | 
| +        */ | 
| +        if( nPage==0 && !jrnlOpen ){ | 
| sqlite3BeginBenignMalloc(); | 
| if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){ | 
| sqlite3OsDelete(pVfs, pPager->zJournal, 0); | 
| @@ -4641,7 +4936,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ | 
| *pExists = (first!=0); | 
| }else if( rc==SQLITE_CANTOPEN ){ | 
| /* If we cannot open the rollback journal file in order to see if | 
| -            ** its has a zero header, that might be due to an I/O error, or | 
| +            ** it has a zero header, that might be due to an I/O error, or | 
| ** it might be due to the race condition described above and in | 
| ** ticket #3883.  Either way, assume that the journal is hot. | 
| ** This might be a false positive.  But if it is, then the | 
| @@ -4704,14 +4999,11 @@ int sqlite3PagerSharedLock(Pager *pPager){ | 
| int bHotJournal = 1;          /* True if there exists a hot journal-file */ | 
|  | 
| assert( !MEMDB ); | 
| -    assert( pPager->noReadlock==0 || pPager->readOnly ); | 
|  | 
| -    if( pPager->noReadlock==0 ){ | 
| -      rc = pager_wait_on_lock(pPager, SHARED_LOCK); | 
| -      if( rc!=SQLITE_OK ){ | 
| -        assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); | 
| -        goto failed; | 
| -      } | 
| +    rc = pager_wait_on_lock(pPager, SHARED_LOCK); | 
| +    if( rc!=SQLITE_OK ){ | 
| +      assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); | 
| +      goto failed; | 
| } | 
|  | 
| /* If a journal file exists, and there is no RESERVED lock on the | 
| @@ -4724,6 +5016,11 @@ int sqlite3PagerSharedLock(Pager *pPager){ | 
| goto failed; | 
| } | 
| if( bHotJournal ){ | 
| +      if( pPager->readOnly ){ | 
| +        rc = SQLITE_READONLY_ROLLBACK; | 
| +        goto failed; | 
| +      } | 
| + | 
| /* Get an EXCLUSIVE lock on the database file. At this point it is | 
| ** important that a RESERVED lock is not obtained on the way to the | 
| ** EXCLUSIVE lock. If it were, another process might open the | 
| @@ -4821,9 +5118,11 @@ int sqlite3PagerSharedLock(Pager *pPager){ | 
| ); | 
| } | 
|  | 
| -    if( !pPager->tempFile | 
| -     && (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0) | 
| -    ){ | 
| +    if( !pPager->tempFile && ( | 
| +        pPager->pBackup | 
| +     || sqlite3PcachePagecount(pPager->pPCache)>0 | 
| +     || USEFETCH(pPager) | 
| +    )){ | 
| /* The shared-lock has just been acquired on the database file | 
| ** and there are already pages in the cache (from a previous | 
| ** read or write transaction).  Check to see if the database | 
| @@ -4849,7 +5148,7 @@ int sqlite3PagerSharedLock(Pager *pPager){ | 
| if( nPage>0 ){ | 
| IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); | 
| rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); | 
| -        if( rc!=SQLITE_OK ){ | 
| +        if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ | 
| goto failed; | 
| } | 
| }else{ | 
| @@ -4858,6 +5157,16 @@ int sqlite3PagerSharedLock(Pager *pPager){ | 
|  | 
| if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ | 
| pager_reset(pPager); | 
| + | 
| +        /* Unmap the database file. It is possible that external processes | 
| +        ** may have truncated the database file and then extended it back | 
| +        ** to its original size while this process was not holding a lock. | 
| +        ** In this case there may exist a Pager.pMap mapping that appears | 
| +        ** to be the right size but is not actually valid. Avoid this | 
| +        ** possibility by unmapping the db here. */ | 
| +        if( USEFETCH(pPager) ){ | 
| +          sqlite3OsUnfetch(pPager->fd, 0, 0); | 
| +        } | 
| } | 
| } | 
|  | 
| @@ -4899,7 +5208,7 @@ int sqlite3PagerSharedLock(Pager *pPager){ | 
| ** nothing to rollback, so this routine is a no-op. | 
| */ | 
| static void pagerUnlockIfUnused(Pager *pPager){ | 
| -  if( (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ | 
| +  if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ | 
| pagerUnlockAndRollback(pPager); | 
| } | 
| } | 
| @@ -4927,7 +5236,7 @@ static void pagerUnlockIfUnused(Pager *pPager){ | 
| ** page is initialized to all zeros. | 
| ** | 
| ** If noContent is true, it means that we do not care about the contents | 
| -** of the page. This occurs in two seperate scenarios: | 
| +** of the page. This occurs in two scenarios: | 
| ** | 
| **   a) When reading a free-list leaf page from the database, and | 
| ** | 
| @@ -4958,13 +5267,27 @@ int sqlite3PagerAcquire( | 
| Pager *pPager,      /* The pager open on the database file */ | 
| Pgno pgno,          /* Page number to fetch */ | 
| DbPage **ppPage,    /* Write a pointer to the page here */ | 
| -  int noContent       /* Do not bother reading content from disk if true */ | 
| +  int flags           /* PAGER_GET_XXX flags */ | 
| ){ | 
| -  int rc; | 
| -  PgHdr *pPg; | 
| +  int rc = SQLITE_OK; | 
| +  PgHdr *pPg = 0; | 
| +  u32 iFrame = 0;                 /* Frame to read from WAL file */ | 
| +  const int noContent = (flags & PAGER_GET_NOCONTENT); | 
| + | 
| +  /* It is acceptable to use a read-only (mmap) page for any page except | 
| +  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY | 
| +  ** flag was specified by the caller. And so long as the db is not a | 
| +  ** temporary or in-memory database.  */ | 
| +  const int bMmapOk = (pgno!=1 && USEFETCH(pPager) | 
| +   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) | 
| +#ifdef SQLITE_HAS_CODEC | 
| +   && pPager->xCodec==0 | 
| +#endif | 
| +  ); | 
|  | 
| assert( pPager->eState>=PAGER_READER ); | 
| assert( assert_pager_state(pPager) ); | 
| +  assert( noContent==0 || bMmapOk==0 ); | 
|  | 
| if( pgno==0 ){ | 
| return SQLITE_CORRUPT_BKPT; | 
| @@ -4975,7 +5298,48 @@ int sqlite3PagerAcquire( | 
| if( pPager->errCode!=SQLITE_OK ){ | 
| rc = pPager->errCode; | 
| }else{ | 
| -    rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage); | 
| +    if( bMmapOk && pagerUseWal(pPager) ){ | 
| +      rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); | 
| +      if( rc!=SQLITE_OK ) goto pager_acquire_err; | 
| +    } | 
| + | 
| +    if( bMmapOk && iFrame==0 ){ | 
| +      void *pData = 0; | 
| + | 
| +      rc = sqlite3OsFetch(pPager->fd, | 
| +          (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData | 
| +      ); | 
| + | 
| +      if( rc==SQLITE_OK && pData ){ | 
| +        if( pPager->eState>PAGER_READER ){ | 
| +          pPg = sqlite3PagerLookup(pPager, pgno); | 
| +        } | 
| +        if( pPg==0 ){ | 
| +          rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); | 
| +        }else{ | 
| +          sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData); | 
| +        } | 
| +        if( pPg ){ | 
| +          assert( rc==SQLITE_OK ); | 
| +          *ppPage = pPg; | 
| +          return SQLITE_OK; | 
| +        } | 
| +      } | 
| +      if( rc!=SQLITE_OK ){ | 
| +        goto pager_acquire_err; | 
| +      } | 
| +    } | 
| + | 
| +    { | 
| +      sqlite3_pcache_page *pBase; | 
| +      pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); | 
| +      if( pBase==0 ){ | 
| +        rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase); | 
| +        if( rc!=SQLITE_OK ) goto pager_acquire_err; | 
| +      } | 
| +      pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase); | 
| +      if( pPg==0 ) rc = SQLITE_NOMEM; | 
| +    } | 
| } | 
|  | 
| if( rc!=SQLITE_OK ){ | 
| @@ -4992,14 +5356,13 @@ int sqlite3PagerAcquire( | 
| /* In this case the pcache already contains an initialized copy of | 
| ** the page. Return without further ado.  */ | 
| assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) ); | 
| -    PAGER_INCR(pPager->nHit); | 
| +    pPager->aStat[PAGER_STAT_HIT]++; | 
| return SQLITE_OK; | 
|  | 
| }else{ | 
| /* The pager cache has created a new page. Its content needs to | 
| ** be initialized.  */ | 
|  | 
| -    PAGER_INCR(pPager->nMiss); | 
| pPg = *ppPage; | 
| pPg->pPager = pPager; | 
|  | 
| @@ -5034,8 +5397,13 @@ int sqlite3PagerAcquire( | 
| memset(pPg->pData, 0, pPager->pageSize); | 
| IOTRACE(("ZERO %p %d\n", pPager, pgno)); | 
| }else{ | 
| +      if( pagerUseWal(pPager) && bMmapOk==0 ){ | 
| +        rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); | 
| +        if( rc!=SQLITE_OK ) goto pager_acquire_err; | 
| +      } | 
| assert( pPg->pPager==pPager ); | 
| -      rc = readDbPage(pPg); | 
| +      pPager->aStat[PAGER_STAT_MISS]++; | 
| +      rc = readDbPage(pPg, iFrame); | 
| if( rc!=SQLITE_OK ){ | 
| goto pager_acquire_err; | 
| } | 
| @@ -5068,13 +5436,12 @@ pager_acquire_err: | 
| ** has ever happened. | 
| */ | 
| DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ | 
| -  PgHdr *pPg = 0; | 
| +  sqlite3_pcache_page *pPage; | 
| assert( pPager!=0 ); | 
| assert( pgno!=0 ); | 
| assert( pPager->pPCache!=0 ); | 
| -  assert( pPager->eState>=PAGER_READER && pPager->eState!=PAGER_ERROR ); | 
| -  sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); | 
| -  return pPg; | 
| +  pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0); | 
| +  return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage); | 
| } | 
|  | 
| /* | 
| @@ -5085,12 +5452,19 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ | 
| ** are released, a rollback occurs and the lock on the database is | 
| ** removed. | 
| */ | 
| -void sqlite3PagerUnref(DbPage *pPg){ | 
| -  if( pPg ){ | 
| -    Pager *pPager = pPg->pPager; | 
| +void sqlite3PagerUnrefNotNull(DbPage *pPg){ | 
| +  Pager *pPager; | 
| +  assert( pPg!=0 ); | 
| +  pPager = pPg->pPager; | 
| +  if( pPg->flags & PGHDR_MMAP ){ | 
| +    pagerReleaseMapPage(pPg); | 
| +  }else{ | 
| sqlite3PcacheRelease(pPg); | 
| -    pagerUnlockIfUnused(pPager); | 
| } | 
| +  pagerUnlockIfUnused(pPager); | 
| +} | 
| +void sqlite3PagerUnref(DbPage *pPg){ | 
| +  if( pPg ) sqlite3PagerUnrefNotNull(pPg); | 
| } | 
|  | 
| #if defined(__APPLE__) | 
| @@ -5159,31 +5533,37 @@ static int pager_open_journal(Pager *pPager){ | 
| (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL): | 
| (SQLITE_OPEN_MAIN_JOURNAL) | 
| ); | 
| -  #ifdef SQLITE_ENABLE_ATOMIC_WRITE | 
| -        rc = sqlite3JournalOpen( | 
| -            pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) | 
| -        ); | 
| -  #else | 
| -        rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); | 
| -  #endif | 
| + | 
| +        /* Verify that the database still has the same name as it did when | 
| +        ** it was originally opened. */ | 
| +        rc = databaseIsUnmoved(pPager); | 
| +        if( rc==SQLITE_OK ){ | 
| +#ifdef SQLITE_ENABLE_ATOMIC_WRITE | 
| +          rc = sqlite3JournalOpen( | 
| +              pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) | 
| +          ); | 
| +#else | 
| +          rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); | 
| +#endif | 
| #if defined(__APPLE__) | 
| -        /* Set the TimeMachine exclusion metadata for the journal if it has | 
| -        ** been set for the database. Only do this for unix-type vfs | 
| -        ** implementations. */ | 
| -        if( rc==SQLITE_OK && pPager->zFilename!=NULL | 
| -         && strlen(pPager->zFilename)>0 | 
| -         && strncmp(pVfs->zName, "unix", 4)==0 | 
| -         && ( pVfs->zName[4]=='-' || pVfs->zName[4]=='\0' ) ){ | 
| -          CFURLRef database = create_cfurl_from_cstring(pPager->zFilename); | 
| -          if( CSBackupIsItemExcluded(database, NULL) ){ | 
| -            CFURLRef journal = create_cfurl_from_cstring(pPager->zJournal); | 
| -            /* Ignore errors from the following exclusion call. */ | 
| -            CSBackupSetItemExcluded(journal, TRUE, FALSE); | 
| -            CFRelease(journal); | 
| +          /* Set the TimeMachine exclusion metadata for the journal if it has | 
| +          ** been set for the database. Only do this for unix-type vfs | 
| +          ** implementations. */ | 
| +          if( rc==SQLITE_OK && pPager->zFilename!=NULL | 
| +           && strlen(pPager->zFilename)>0 | 
| +           && strncmp(pVfs->zName, "unix", 4)==0 | 
| +           && ( pVfs->zName[4]=='-' || pVfs->zName[4]=='\0' ) ){ | 
| +            CFURLRef database = create_cfurl_from_cstring(pPager->zFilename); | 
| +            if( CSBackupIsItemExcluded(database, NULL) ){ | 
| +              CFURLRef journal = create_cfurl_from_cstring(pPager->zJournal); | 
| +              /* Ignore errors from the following exclusion call. */ | 
| +              CSBackupSetItemExcluded(journal, TRUE, FALSE); | 
| +              CFRelease(journal); | 
| +            } | 
| +            CFRelease(database); | 
| } | 
| -          CFRelease(database); | 
| -        } | 
| #endif | 
| +        } | 
| } | 
| assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); | 
| } | 
| @@ -5304,9 +5684,9 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){ | 
| ** of any open savepoints as appropriate. | 
| */ | 
| static int pager_write(PgHdr *pPg){ | 
| -  void *pData = pPg->pData; | 
| Pager *pPager = pPg->pPager; | 
| int rc = SQLITE_OK; | 
| +  int inJournal; | 
|  | 
| /* This routine is not called unless a write-transaction has already | 
| ** been started. The journal file may or may not be open at this point. | 
| @@ -5317,14 +5697,8 @@ static int pager_write(PgHdr *pPg){ | 
| || pPager->eState==PAGER_WRITER_DBMOD | 
| ); | 
| assert( assert_pager_state(pPager) ); | 
| - | 
| -  /* If an error has been previously detected, report the same error | 
| -  ** again. This should not happen, but the check provides robustness. */ | 
| -  if( NEVER(pPager->errCode) )  return pPager->errCode; | 
| - | 
| -  /* Higher-level routines never call this function if database is not | 
| -  ** writable.  But check anyway, just for robustness. */ | 
| -  if( NEVER(pPager->readOnly) ) return SQLITE_PERM; | 
| +  assert( pPager->errCode==0 ); | 
| +  assert( pPager->readOnly==0 ); | 
|  | 
| CHECK_PAGE(pPg); | 
|  | 
| @@ -5348,7 +5722,8 @@ static int pager_write(PgHdr *pPg){ | 
| ** to the journal then we can return right away. | 
| */ | 
| sqlite3PcacheMakeDirty(pPg); | 
| -  if( pageInJournal(pPg) && !subjRequiresPage(pPg) ){ | 
| +  inJournal = pageInJournal(pPager, pPg); | 
| +  if( inJournal && (pPager->nSavepoint==0 || !subjRequiresPage(pPg)) ){ | 
| assert( !pagerUseWal(pPager) ); | 
| }else{ | 
|  | 
| @@ -5356,7 +5731,7 @@ static int pager_write(PgHdr *pPg){ | 
| ** EXCLUSIVE lock on the main database file.  Write the current page to | 
| ** the transaction journal if it is not there already. | 
| */ | 
| -    if( !pageInJournal(pPg) && !pagerUseWal(pPager) ){ | 
| +    if( !inJournal && !pagerUseWal(pPager) ){ | 
| assert( pagerUseWal(pPager)==0 ); | 
| if( pPg->pgno<=pPager->dbOrigSize && isOpen(pPager->jfd) ){ | 
| u32 cksum; | 
| @@ -5369,7 +5744,7 @@ static int pager_write(PgHdr *pPg){ | 
| assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); | 
|  | 
| assert( pPager->journalHdr<=pPager->journalOff ); | 
| -        CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2); | 
| +        CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2); | 
| cksum = pager_cksum(pPager, (u8*)pData2); | 
|  | 
| /* Even if an IO or diskfull error occurs while journalling the | 
| @@ -5421,7 +5796,7 @@ static int pager_write(PgHdr *pPg){ | 
| ** the statement journal format differs from the standard journal format | 
| ** in that it omits the checksums and the header. | 
| */ | 
| -    if( subjRequiresPage(pPg) ){ | 
| +    if( pPager->nSavepoint>0 && subjRequiresPage(pPg) ){ | 
| rc = subjournalPage(pPg); | 
| } | 
| } | 
| @@ -5435,6 +5810,97 @@ static int pager_write(PgHdr *pPg){ | 
| } | 
|  | 
| /* | 
| +** This is a variant of sqlite3PagerWrite() that runs when the sector size | 
| +** is larger than the page size.  SQLite makes the (reasonable) assumption that | 
| +** all bytes of a sector are written together by hardware.  Hence, all bytes of | 
| +** a sector need to be journalled in case of a power loss in the middle of | 
| +** a write. | 
| +** | 
| +** Usually, the sector size is less than or equal to the page size, in which | 
| +** case pages can be individually written.  This routine only runs in the exceptional | 
| +** case where the page size is smaller than the sector size. | 
| +*/ | 
| +static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){ | 
| +  int rc = SQLITE_OK;            /* Return code */ | 
| +  Pgno nPageCount;               /* Total number of pages in database file */ | 
| +  Pgno pg1;                      /* First page of the sector pPg is located on. */ | 
| +  int nPage = 0;                 /* Number of pages starting at pg1 to journal */ | 
| +  int ii;                        /* Loop counter */ | 
| +  int needSync = 0;              /* True if any page has PGHDR_NEED_SYNC */ | 
| +  Pager *pPager = pPg->pPager;   /* The pager that owns pPg */ | 
| +  Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); | 
| + | 
| +  /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow | 
| +  ** a journal header to be written between the pages journaled by | 
| +  ** this function. | 
| +  */ | 
| +  assert( !MEMDB ); | 
| +  assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 ); | 
| +  pPager->doNotSpill |= SPILLFLAG_NOSYNC; | 
| + | 
| +  /* This trick assumes that both the page-size and sector-size are | 
| +  ** an integer power of 2. It sets variable pg1 to the identifier | 
| +  ** of the first page of the sector pPg is located on. | 
| +  */ | 
| +  pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; | 
| + | 
| +  nPageCount = pPager->dbSize; | 
| +  if( pPg->pgno>nPageCount ){ | 
| +    nPage = (pPg->pgno - pg1)+1; | 
| +  }else if( (pg1+nPagePerSector-1)>nPageCount ){ | 
| +    nPage = nPageCount+1-pg1; | 
| +  }else{ | 
| +    nPage = nPagePerSector; | 
| +  } | 
| +  assert(nPage>0); | 
| +  assert(pg1<=pPg->pgno); | 
| +  assert((pg1+nPage)>pPg->pgno); | 
| + | 
| +  for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){ | 
| +    Pgno pg = pg1+ii; | 
| +    PgHdr *pPage; | 
| +    if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ | 
| +      if( pg!=PAGER_MJ_PGNO(pPager) ){ | 
| +        rc = sqlite3PagerGet(pPager, pg, &pPage); | 
| +        if( rc==SQLITE_OK ){ | 
| +          rc = pager_write(pPage); | 
| +          if( pPage->flags&PGHDR_NEED_SYNC ){ | 
| +            needSync = 1; | 
| +          } | 
| +          sqlite3PagerUnrefNotNull(pPage); | 
| +        } | 
| +      } | 
| +    }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){ | 
| +      if( pPage->flags&PGHDR_NEED_SYNC ){ | 
| +        needSync = 1; | 
| +      } | 
| +      sqlite3PagerUnrefNotNull(pPage); | 
| +    } | 
| +  } | 
| + | 
| +  /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages | 
| +  ** starting at pg1, then it needs to be set for all of them. Because | 
| +  ** writing to any of these nPage pages may damage the others, the | 
| +  ** journal file must contain sync()ed copies of all of them | 
| +  ** before any of them can be written out to the database file. | 
| +  */ | 
| +  if( rc==SQLITE_OK && needSync ){ | 
| +    assert( !MEMDB ); | 
| +    for(ii=0; ii<nPage; ii++){ | 
| +      PgHdr *pPage = sqlite3PagerLookup(pPager, pg1+ii); | 
| +      if( pPage ){ | 
| +        pPage->flags |= PGHDR_NEED_SYNC; | 
| +        sqlite3PagerUnrefNotNull(pPage); | 
| +      } | 
| +    } | 
| +  } | 
| + | 
| +  assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 ); | 
| +  pPager->doNotSpill &= ~SPILLFLAG_NOSYNC; | 
| +  return rc; | 
| +} | 
| + | 
| +/* | 
| ** Mark a data page as writeable. This routine must be called before | 
| ** making changes to a page. The caller must check the return value | 
| ** of this function and be careful not to change any page data unless | 
| @@ -5448,95 +5914,16 @@ static int pager_write(PgHdr *pPg){ | 
| ** If an error occurs, SQLITE_NOMEM or an IO error code is returned | 
| ** as appropriate. Otherwise, SQLITE_OK. | 
| */ | 
| -int sqlite3PagerWrite(DbPage *pDbPage){ | 
| -  int rc = SQLITE_OK; | 
| - | 
| -  PgHdr *pPg = pDbPage; | 
| -  Pager *pPager = pPg->pPager; | 
| -  Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); | 
| - | 
| -  assert( pPager->eState>=PAGER_WRITER_LOCKED ); | 
| -  assert( pPager->eState!=PAGER_ERROR ); | 
| -  assert( assert_pager_state(pPager) ); | 
| - | 
| -  if( nPagePerSector>1 ){ | 
| -    Pgno nPageCount;          /* Total number of pages in database file */ | 
| -    Pgno pg1;                 /* First page of the sector pPg is located on. */ | 
| -    int nPage = 0;            /* Number of pages starting at pg1 to journal */ | 
| -    int ii;                   /* Loop counter */ | 
| -    int needSync = 0;         /* True if any page has PGHDR_NEED_SYNC */ | 
| - | 
| -    /* Set the doNotSyncSpill flag to 1. This is because we cannot allow | 
| -    ** a journal header to be written between the pages journaled by | 
| -    ** this function. | 
| -    */ | 
| -    assert( !MEMDB ); | 
| -    assert( pPager->doNotSyncSpill==0 ); | 
| -    pPager->doNotSyncSpill++; | 
| - | 
| -    /* This trick assumes that both the page-size and sector-size are | 
| -    ** an integer power of 2. It sets variable pg1 to the identifier | 
| -    ** of the first page of the sector pPg is located on. | 
| -    */ | 
| -    pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; | 
| - | 
| -    nPageCount = pPager->dbSize; | 
| -    if( pPg->pgno>nPageCount ){ | 
| -      nPage = (pPg->pgno - pg1)+1; | 
| -    }else if( (pg1+nPagePerSector-1)>nPageCount ){ | 
| -      nPage = nPageCount+1-pg1; | 
| -    }else{ | 
| -      nPage = nPagePerSector; | 
| -    } | 
| -    assert(nPage>0); | 
| -    assert(pg1<=pPg->pgno); | 
| -    assert((pg1+nPage)>pPg->pgno); | 
| - | 
| -    for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){ | 
| -      Pgno pg = pg1+ii; | 
| -      PgHdr *pPage; | 
| -      if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ | 
| -        if( pg!=PAGER_MJ_PGNO(pPager) ){ | 
| -          rc = sqlite3PagerGet(pPager, pg, &pPage); | 
| -          if( rc==SQLITE_OK ){ | 
| -            rc = pager_write(pPage); | 
| -            if( pPage->flags&PGHDR_NEED_SYNC ){ | 
| -              needSync = 1; | 
| -            } | 
| -            sqlite3PagerUnref(pPage); | 
| -          } | 
| -        } | 
| -      }else if( (pPage = pager_lookup(pPager, pg))!=0 ){ | 
| -        if( pPage->flags&PGHDR_NEED_SYNC ){ | 
| -          needSync = 1; | 
| -        } | 
| -        sqlite3PagerUnref(pPage); | 
| -      } | 
| -    } | 
| - | 
| -    /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages | 
| -    ** starting at pg1, then it needs to be set for all of them. Because | 
| -    ** writing to any of these nPage pages may damage the others, the | 
| -    ** journal file must contain sync()ed copies of all of them | 
| -    ** before any of them can be written out to the database file. | 
| -    */ | 
| -    if( rc==SQLITE_OK && needSync ){ | 
| -      assert( !MEMDB ); | 
| -      for(ii=0; ii<nPage; ii++){ | 
| -        PgHdr *pPage = pager_lookup(pPager, pg1+ii); | 
| -        if( pPage ){ | 
| -          pPage->flags |= PGHDR_NEED_SYNC; | 
| -          sqlite3PagerUnref(pPage); | 
| -        } | 
| -      } | 
| -    } | 
| - | 
| -    assert( pPager->doNotSyncSpill==1 ); | 
| -    pPager->doNotSyncSpill--; | 
| +int sqlite3PagerWrite(PgHdr *pPg){ | 
| +  assert( (pPg->flags & PGHDR_MMAP)==0 ); | 
| +  assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED ); | 
| +  assert( pPg->pPager->eState!=PAGER_ERROR ); | 
| +  assert( assert_pager_state(pPg->pPager) ); | 
| +  if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){ | 
| +    return pagerWriteLargeSector(pPg); | 
| }else{ | 
| -    rc = pager_write(pDbPage); | 
| +    return pager_write(pPg); | 
| } | 
| -  return rc; | 
| } | 
|  | 
| /* | 
| @@ -5622,7 +6009,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ | 
| # define DIRECT_MODE isDirectMode | 
| #endif | 
|  | 
| -  if( !pPager->changeCountDone && pPager->dbSize>0 ){ | 
| +  if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){ | 
| PgHdr *pPgHdr;                /* Reference to page 1 */ | 
|  | 
| assert( !pPager->tempFile && isOpen(pPager->fd) ); | 
| @@ -5651,8 +6038,14 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ | 
| CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf); | 
| if( rc==SQLITE_OK ){ | 
| rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); | 
| +          pPager->aStat[PAGER_STAT_WRITE]++; | 
| } | 
| if( rc==SQLITE_OK ){ | 
| +          /* Update the pager's copy of the change-counter. Otherwise, the | 
| +          ** next time a read transaction is opened the cache will be | 
| +          ** flushed (as the change-counter values will not match).  */ | 
| +          const void *pCopy = (const void *)&((const char *)zBuf)[24]; | 
| +          memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers)); | 
| pPager->changeCountDone = 1; | 
| } | 
| }else{ | 
| @@ -5673,14 +6066,17 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ | 
| ** If successful, or if called on a pager for which it is a no-op, this | 
| ** function returns SQLITE_OK. Otherwise, an IO error code is returned. | 
| */ | 
| -int sqlite3PagerSync(Pager *pPager){ | 
| +int sqlite3PagerSync(Pager *pPager, const char *zMaster){ | 
| int rc = SQLITE_OK; | 
| -  if( !pPager->noSync ){ | 
| + | 
| +  if( isOpen(pPager->fd) ){ | 
| +    void *pArg = (void*)zMaster; | 
| +    rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg); | 
| +    if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; | 
| +  } | 
| +  if( rc==SQLITE_OK && !pPager->noSync ){ | 
| assert( !MEMDB ); | 
| rc = sqlite3OsSync(pPager->fd, pPager->syncFlags); | 
| -  }else if( isOpen(pPager->fd) ){ | 
| -    assert( !MEMDB ); | 
| -    sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, (void *)&rc); | 
| } | 
| return rc; | 
| } | 
| @@ -5775,11 +6171,9 @@ int sqlite3PagerCommitPhaseOne( | 
| pList = pPageOne; | 
| pList->pDirty = 0; | 
| } | 
| -      assert( pList!=0 || rc!=SQLITE_OK ); | 
| -      if( pList ){ | 
| -        rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1, | 
| -            (pPager->fullSync ? pPager->syncFlags : 0) | 
| -        ); | 
| +      assert( rc==SQLITE_OK ); | 
| +      if( ALWAYS(pList) ){ | 
| +        rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1); | 
| } | 
| sqlite3PagerUnref(pPageOne); | 
| if( rc==SQLITE_OK ){ | 
| @@ -5838,38 +6232,6 @@ int sqlite3PagerCommitPhaseOne( | 
| #endif | 
| 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. This can only happen in auto-vacuum mode. | 
| -      ** | 
| -      ** 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. | 
| -      */ | 
| -  #ifndef SQLITE_OMIT_AUTOVACUUM | 
| -      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; | 
| -      } | 
| -  #endif | 
| - | 
| /* Write the master journal name into the journal file. If a master | 
| ** 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. | 
| @@ -5897,11 +6259,14 @@ int sqlite3PagerCommitPhaseOne( | 
| goto commit_phase_one_exit; | 
| } | 
| 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)); | 
| assert( pPager->eState==PAGER_WRITER_DBMOD ); | 
| rc = pager_truncate(pPager, nNew); | 
| @@ -5910,7 +6275,7 @@ int sqlite3PagerCommitPhaseOne( | 
|  | 
| /* Finally, sync the database file. */ | 
| if( !noSync ){ | 
| -        rc = sqlite3PagerSync(pPager); | 
| +        rc = sqlite3PagerSync(pPager, zMaster); | 
| } | 
| IOTRACE(("DBSYNC %p\n", pPager)) | 
| } | 
| @@ -5974,7 +6339,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *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); | 
| } | 
|  | 
| @@ -6019,11 +6384,11 @@ int sqlite3PagerRollback(Pager *pPager){ | 
| if( pagerUseWal(pPager) ){ | 
| int rc2; | 
| 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; | 
| }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){ | 
| int eState = pPager->eState; | 
| -    rc = pager_end_transaction(pPager, 0); | 
| +    rc = pager_end_transaction(pPager, 0, 0); | 
| if( !MEMDB && eState>PAGER_WRITER_LOCKED ){ | 
| /* 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. | 
| @@ -6038,7 +6403,10 @@ int sqlite3PagerRollback(Pager *pPager){ | 
| } | 
|  | 
| assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); | 
| -  assert( rc==SQLITE_OK || rc==SQLITE_FULL || (rc&0xFF)==SQLITE_IOERR ); | 
| +  assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT | 
| +          || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR | 
| +          || rc==SQLITE_CANTOPEN | 
| +  ); | 
|  | 
| /* If an error occurs during a ROLLBACK, we can no longer trust the pager | 
| ** cache. So call pager_error() on the way out to make any error persistent. | 
| @@ -6092,16 +6460,40 @@ int *sqlite3PagerStats(Pager *pPager){ | 
| a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize; | 
| a[4] = pPager->eState; | 
| a[5] = pPager->errCode; | 
| -  a[6] = pPager->nHit; | 
| -  a[7] = pPager->nMiss; | 
| +  a[6] = pPager->aStat[PAGER_STAT_HIT]; | 
| +  a[7] = pPager->aStat[PAGER_STAT_MISS]; | 
| a[8] = 0;  /* Used to be pPager->nOvfl */ | 
| a[9] = pPager->nRead; | 
| -  a[10] = pPager->nWrite; | 
| +  a[10] = pPager->aStat[PAGER_STAT_WRITE]; | 
| return a; | 
| } | 
| #endif | 
|  | 
| /* | 
| +** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or | 
| +** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the | 
| +** current cache hit or miss count, according to the value of eStat. If the | 
| +** reset parameter is non-zero, the cache hit or miss count is zeroed before | 
| +** returning. | 
| +*/ | 
| +void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ | 
| + | 
| +  assert( eStat==SQLITE_DBSTATUS_CACHE_HIT | 
| +       || eStat==SQLITE_DBSTATUS_CACHE_MISS | 
| +       || eStat==SQLITE_DBSTATUS_CACHE_WRITE | 
| +  ); | 
| + | 
| +  assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS ); | 
| +  assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE ); | 
| +  assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 ); | 
| + | 
| +  *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT]; | 
| +  if( reset ){ | 
| +    pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0; | 
| +  } | 
| +} | 
| + | 
| +/* | 
| ** Return true if this is an in-memory pager. | 
| */ | 
| int sqlite3PagerIsMemdb(Pager *pPager){ | 
| @@ -6246,9 +6638,16 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ | 
|  | 
| /* | 
| ** Return the full pathname of the database file. | 
| +** | 
| +** Except, if the pager is in-memory only, then return an empty string if | 
| +** nullIfMemDb is true.  This routine is called with nullIfMemDb==1 when | 
| +** used to report the filename to the user, for compatibility with legacy | 
| +** behavior.  But when the Btree needs to know the filename for matching to | 
| +** shared cache, it uses nullIfMemDb==0 so that in-memory databases can | 
| +** participate in shared-cache. | 
| */ | 
| -const char *sqlite3PagerFilename(Pager *pPager){ | 
| -  return pPager->zFilename; | 
| +const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){ | 
| +  return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename; | 
| } | 
|  | 
| /* | 
| @@ -6303,7 +6702,27 @@ void sqlite3PagerSetCodec( | 
| void *sqlite3PagerGetCodec(Pager *pPager){ | 
| return pPager->pCodec; | 
| } | 
| -#endif | 
| + | 
| +/* | 
| +** This function is called by the wal module when writing page content | 
| +** into the log file. | 
| +** | 
| +** This function returns a pointer to a buffer containing the encrypted | 
| +** page content. If a malloc fails, this function may return NULL. | 
| +*/ | 
| +void *sqlite3PagerCodec(PgHdr *pPg){ | 
| +  void *aData = 0; | 
| +  CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); | 
| +  return aData; | 
| +} | 
| + | 
| +/* | 
| +** Return the current pager state | 
| +*/ | 
| +int sqlite3PagerState(Pager *pPager){ | 
| +  return pPager->eState; | 
| +} | 
| +#endif /* SQLITE_HAS_CODEC */ | 
|  | 
| #ifndef SQLITE_OMIT_AUTOVACUUM | 
| /* | 
| @@ -6389,7 +6808,8 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ | 
| */ | 
| if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){ | 
| needSyncPgno = pPg->pgno; | 
| -    assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize ); | 
| +    assert( pPager->journalMode==PAGER_JOURNALMODE_OFF || | 
| +            pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize ); | 
| assert( pPg->flags&PGHDR_DIRTY ); | 
| } | 
|  | 
| @@ -6399,7 +6819,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ | 
| ** for the page moved there. | 
| */ | 
| pPg->flags &= ~PGHDR_NEED_SYNC; | 
| -  pPgOld = pager_lookup(pPager, pgno); | 
| +  pPgOld = sqlite3PagerLookup(pPager, pgno); | 
| assert( !pPgOld || pPgOld->nRef==1 ); | 
| if( pPgOld ){ | 
| pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); | 
| @@ -6423,7 +6843,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ | 
| if( MEMDB ){ | 
| assert( pPgOld ); | 
| sqlite3PcacheMove(pPgOld, origPgno); | 
| -    sqlite3PagerUnref(pPgOld); | 
| +    sqlite3PagerUnrefNotNull(pPgOld); | 
| } | 
|  | 
| if( needSyncPgno ){ | 
| @@ -6452,7 +6872,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ | 
| } | 
| pPgHdr->flags |= PGHDR_NEED_SYNC; | 
| sqlite3PcacheMakeDirty(pPgHdr); | 
| -    sqlite3PagerUnref(pPgHdr); | 
| +    sqlite3PagerUnrefNotNull(pPgHdr); | 
| } | 
|  | 
| return SQLITE_OK; | 
| @@ -6639,6 +7059,7 @@ int sqlite3PagerOkToChangeJournalMode(Pager *pPager){ | 
| i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){ | 
| if( iLimit>=-1 ){ | 
| pPager->journalSizeLimit = iLimit; | 
| +    sqlite3WalLimit(pPager->pWal, iLimit); | 
| } | 
| return pPager->journalSizeLimit; | 
| } | 
| @@ -6653,6 +7074,15 @@ sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){ | 
| return &pPager->pBackup; | 
| } | 
|  | 
| +#ifndef SQLITE_OMIT_VACUUM | 
| +/* | 
| +** Unless this is an in-memory or temporary database, clear the pager cache. | 
| +*/ | 
| +void sqlite3PagerClearCache(Pager *pPager){ | 
| +  if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager); | 
| +} | 
| +#endif | 
| + | 
| #ifndef SQLITE_OMIT_WAL | 
| /* | 
| ** This function is called when the user invokes "PRAGMA wal_checkpoint", | 
| @@ -6714,7 +7144,7 @@ static int pagerOpenWal(Pager *pPager){ | 
| int rc = SQLITE_OK; | 
|  | 
| assert( pPager->pWal==0 && pPager->tempFile==0 ); | 
| -  assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK || pPager->noReadlock); | 
| +  assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); | 
|  | 
| /* If the pager is already in exclusive-mode, the WAL module will use | 
| ** heap-memory for the wal-index instead of the VFS shared-memory | 
| @@ -6729,10 +7159,12 @@ static int pagerOpenWal(Pager *pPager){ | 
| ** (e.g. due to malloc() failure), return an error code. | 
| */ | 
| if( rc==SQLITE_OK ){ | 
| -    rc = sqlite3WalOpen(pPager->pVfs, | 
| -        pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal | 
| +    rc = sqlite3WalOpen(pPager->pVfs, | 
| +        pPager->fd, pPager->zWal, pPager->exclusiveMode, | 
| +        pPager->journalSizeLimit, &pPager->pWal | 
| ); | 
| } | 
| +  pagerFixMaplimit(pPager); | 
|  | 
| return rc; | 
| } | 
| @@ -6823,26 +7255,26 @@ int sqlite3PagerCloseWal(Pager *pPager){ | 
| rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, | 
| pPager->pageSize, (u8*)pPager->pTmpSpace); | 
| pPager->pWal = 0; | 
| +      pagerFixMaplimit(pPager); | 
| } | 
| } | 
| return rc; | 
| } | 
|  | 
| -#ifdef SQLITE_HAS_CODEC | 
| +#endif /* !SQLITE_OMIT_WAL */ | 
| + | 
| +#ifdef SQLITE_ENABLE_ZIPVFS | 
| /* | 
| -** This function is called by the wal module when writing page content | 
| -** into the log file. | 
| -** | 
| -** This function returns a pointer to a buffer containing the encrypted | 
| -** page content. If a malloc fails, this function may return NULL. | 
| +** A read-lock must be held on the pager when this function is called. If | 
| +** the pager is in WAL mode and the WAL file currently contains one or more | 
| +** frames, return the size in bytes of the page images stored within the | 
| +** WAL frames. Otherwise, if this is not a WAL database or the WAL file | 
| +** is empty, return 0. | 
| */ | 
| -void *sqlite3PagerCodec(PgHdr *pPg){ | 
| -  void *aData = 0; | 
| -  CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); | 
| -  return aData; | 
| +int sqlite3PagerWalFramesize(Pager *pPager){ | 
| +  assert( pPager->eState>=PAGER_READER ); | 
| +  return sqlite3WalFramesize(pPager->pWal); | 
| } | 
| -#endif /* SQLITE_HAS_CODEC */ | 
| - | 
| -#endif /* !SQLITE_OMIT_WAL */ | 
| +#endif | 
|  | 
| #endif /* SQLITE_OMIT_DISKIO */ | 
|  |