summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/pager.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/pager.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.c265
1 files changed, 175 insertions, 90 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/pager.c b/ext/pdo_sqlite/sqlite/src/pager.c
index 47d895240c..892757406f 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.c
+++ b/ext/pdo_sqlite/sqlite/src/pager.c
@@ -20,6 +20,7 @@
**
** @(#) $Id$
*/
+#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
@@ -171,7 +172,7 @@ struct PgHdr {
#ifdef SQLITE_CHECK_PAGES
u32 pageHash;
#endif
- /* pPager->psAligned bytes of page data follow this header */
+ /* pPager->pageSize bytes of page data follow this header */
/* Pager.nExtra bytes of local data follow the page data */
};
@@ -207,15 +208,22 @@ struct PgHistory {
*/
#define PGHDR_TO_DATA(P) ((void*)(&(P)[1]))
#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1])
-#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->psAligned])
+#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize])
#define PGHDR_TO_HIST(P,PGR) \
- ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->psAligned+(PGR)->nExtra])
+ ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
/*
** How big to make the hash table used for locating in-memory pages
-** by page number.
+** by page number. This macro looks a little silly, but is evaluated
+** at compile-time, not run-time (at least for gcc this is true).
*/
-#define N_PG_HASH 2048
+#define N_PG_HASH (\
+ (MAX_PAGES>1024)?2048: \
+ (MAX_PAGES>512)?1024: \
+ (MAX_PAGES>256)?512: \
+ (MAX_PAGES>128)?256: \
+ (MAX_PAGES>64)?128:64 \
+)
/*
** Hash a page number
@@ -226,30 +234,6 @@ struct PgHistory {
** A open page cache is an instance of the following structure.
*/
struct Pager {
- char *zFilename; /* Name of the database file */
- char *zJournal; /* Name of the journal file */
- char *zDirectory; /* Directory hold database and journal files */
- OsFile fd, jfd; /* File descriptors for database and journal */
- OsFile stfd; /* File descriptor for the statement subjournal*/
- int dbSize; /* Number of pages in the file */
- int origDbSize; /* dbSize before the current change */
- int stmtSize; /* Size of database (in pages) at stmt_begin() */
- i64 stmtJSize; /* Size of journal at stmt_begin() */
- int nRec; /* Number of pages written to the journal */
- u32 cksumInit; /* Quasi-random value added to every checksum */
- int stmtNRec; /* Number of records in stmt subjournal */
- int nExtra; /* Add this many bytes to each in-memory page */
- void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
- void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
- int pageSize; /* Number of bytes in a page */
- int psAligned; /* pageSize rounded up to a multiple of 8 */
- int nPage; /* Total number of in-memory pages */
- int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
- int mxPage; /* Maximum number of pages to hold in cache */
- int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
- int nRead,nWrite; /* Database pages read/written */
- void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
- void *pCodecArg; /* First argument to xCodec() */
u8 journalOpen; /* True if journal file descriptors is valid */
u8 journalStarted; /* True if header of journal is synced */
u8 useJournal; /* Use a rollback journal on this file */
@@ -267,9 +251,26 @@ struct Pager {
u8 dirtyCache; /* True if cached pages have changed */
u8 alwaysRollback; /* Disable dont_rollback() for all pages */
u8 memDb; /* True to inhibit all file I/O */
+ u8 setMaster; /* True if a m-j name has been written to jrnl */
+ int dbSize; /* Number of pages in the file */
+ int origDbSize; /* dbSize before the current change */
+ int stmtSize; /* Size of database (in pages) at stmt_begin() */
+ int nRec; /* Number of pages written to the journal */
+ u32 cksumInit; /* Quasi-random value added to every checksum */
+ int stmtNRec; /* Number of records in stmt subjournal */
+ int nExtra; /* Add this many bytes to each in-memory page */
+ int pageSize; /* Number of bytes in a page */
+ int nPage; /* Total number of in-memory pages */
+ int nMaxPage; /* High water mark of nPage */
+ int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
+ int mxPage; /* Maximum number of pages to hold in cache */
u8 *aInJournal; /* One bit for each page in the database file */
u8 *aInStmt; /* One bit for each page in the database */
- u8 setMaster; /* True if a m-j name has been written to jrnl */
+ char *zFilename; /* Name of the database file */
+ char *zJournal; /* Name of the journal file */
+ char *zDirectory; /* Directory hold database and journal files */
+ OsFile fd, jfd; /* File descriptors for database and journal */
+ OsFile stfd; /* File descriptor for the statement subjournal*/
BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */
PgHdr *pFirst, *pLast; /* List of free pages */
PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */
@@ -279,11 +280,30 @@ struct Pager {
i64 journalHdr; /* Byte offset to previous journal header */
i64 stmtHdrOff; /* First journal header written this statement */
i64 stmtCksum; /* cksumInit when statement was started */
+ i64 stmtJSize; /* Size of journal at stmt_begin() */
int sectorSize; /* Assumed sector size during rollback */
+#ifdef SQLITE_TEST
+ int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
+ int nRead,nWrite; /* Database pages read/written */
+#endif
+ void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
+ void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
+ void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
+ void *pCodecArg; /* First argument to xCodec() */
PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */
};
/*
+** If SQLITE_TEST is defined then increment the variable given in
+** the argument
+*/
+#ifdef SQLITE_TEST
+# define TEST_INCR(x) x++
+#else
+# define TEST_INCR(x)
+#endif
+
+/*
** These are bits that can be set in Pager.errMask.
*/
#define PAGER_ERR_FULL 0x01 /* a write() failed */
@@ -822,6 +842,7 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
*/
static void pager_reset(Pager *pPager){
PgHdr *pPg, *pNext;
+ if( pPager->errMask ) return;
for(pPg=pPager->pAll; pPg; pPg=pNext){
pNext = pPg->pNextAll;
sqliteFree(pPg);
@@ -843,6 +864,29 @@ static void pager_reset(Pager *pPager){
}
/*
+** This function is used to reset the pager after a malloc() failure. This
+** doesn't work with in-memory databases. If a malloc() fails when an
+** in-memory database is in use it is not possible to recover.
+**
+** If a transaction or statement transaction is active, it is rolled back.
+**
+** It is an error to call this function if any pages are in use.
+*/
+#ifndef SQLITE_OMIT_GLOBALRECOVER
+int sqlite3pager_reset(Pager *pPager){
+ if( pPager ){
+ if( pPager->nRef || MEMDB ){
+ return SQLITE_ERROR;
+ }
+ pPager->errMask &= ~(PAGER_ERR_MEM);
+ pager_reset(pPager);
+ }
+ return SQLITE_OK;
+}
+#endif
+
+
+/*
** When this routine is called, the pager has the journal file open and
** a RESERVED or EXCLUSIVE lock on the database. This routine releases
** the database lock and acquires a SHARED lock in its place. The journal
@@ -881,6 +925,7 @@ static int pager_unwritelock(Pager *pPager){
pPager->dirtyCache = 0;
pPager->nRec = 0;
}else{
+ assert( pPager->aInJournal==0 );
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
}
rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
@@ -935,6 +980,12 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
u32 cksum; /* Checksum used for sanity checking */
u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */
+ /* useCksum should be true for the main journal and false for
+ ** statement journals. Verify that this is always the case
+ */
+ assert( jfd == (useCksum ? &pPager->jfd : &pPager->stfd) );
+
+
rc = read32bits(jfd, &pgno);
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);
@@ -969,13 +1020,27 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
**
** If in EXCLUSIVE state, then we update the pager cache if it exists
** and the main file. The page is then marked not dirty.
+ **
+ ** Ticket #1171: The statement journal might contain page content that is
+ ** different from the page content at the start of the transaction.
+ ** This occurs when a page is changed prior to the start of a statement
+ ** then changed again within the statement. When rolling back such a
+ ** statement we must not write to the original database unless we know
+ ** for certain that original page contents are in the main rollback
+ ** journal. Otherwise, if a full ROLLBACK occurs after the statement
+ ** rollback the full ROLLBACK will not restore the page to its original
+ ** content. Two conditions must be met before writing to the database
+ ** files. (1) the database must be locked. (2) we know that the original
+ ** page content is in the main journal either because the page is not in
+ ** cache or else it is marked as needSync==0.
*/
pPg = pager_lookup(pPager, pgno);
- assert( pPager->state>=PAGER_EXCLUSIVE || pPg );
+ assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
- if( pPager->state>=PAGER_EXCLUSIVE ){
+ if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
+ if( pPg ) pPg->dirty = 0;
}
if( pPg ){
/* No page should ever be explicitly rolled back that is in use, except
@@ -991,13 +1056,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/
pPager->xDestructor(pData, pPager->pageSize);
}
- if( pPager->state>=PAGER_EXCLUSIVE ){
- pPg->dirty = 0;
- pPg->needSync = 0;
#ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
+ pPg->pageHash = pager_pagehash(pPg);
#endif
- }
CODEC(pPager, pData, pPg->pgno, 3);
}
return rc;
@@ -1434,22 +1495,8 @@ end_stmt_playback:
/*
** Change the maximum number of in-memory pages that are allowed.
-**
-** The maximum number is the absolute value of the mxPage parameter.
-** If mxPage is negative, the noSync flag is also set. noSync bypasses
-** calls to sqlite3OsSync(). The pager runs much faster with noSync on,
-** but if the operating system crashes or there is an abrupt power
-** failure, the database file might be left in an inconsistent and
-** unrepairable state.
*/
void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
- if( mxPage>=0 ){
- pPager->noSync = pPager->tempFile;
- if( pPager->noSync ) pPager->needSync = 0;
- }else{
- pPager->noSync = 1;
- mxPage = -mxPage;
- }
if( mxPage>10 ){
pPager->mxPage = mxPage;
}else{
@@ -1492,8 +1539,15 @@ void sqlite3pager_set_safety_level(Pager *pPager, int level){
#endif
/*
-** Open a temporary file. Write the name of the file into zName
-** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write
+** The following global variable is incremented whenever the library
+** attempts to open a temporary file. This information is used for
+** testing and analysis only.
+*/
+int sqlite3_opentemp_count = 0;
+
+/*
+** Open a temporary file. Write the name of the file into zFile
+** (zFile must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write
** the file descriptor into *fd. Return SQLITE_OK on success or some
** other error code if we fail.
**
@@ -1503,6 +1557,7 @@ void sqlite3pager_set_safety_level(Pager *pPager, int level){
static int sqlite3pager_opentemp(char *zFile, OsFile *fd){
int cnt = 8;
int rc;
+ sqlite3_opentemp_count++; /* Used for testing and analysis only */
do{
cnt--;
sqlite3OsTempFileName(zFile);
@@ -1610,10 +1665,10 @@ int sqlite3pager_open(
pPager->nRef = 0;
pPager->dbSize = memDb-1;
pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
- pPager->psAligned = FORCE_ALIGNMENT(pPager->pageSize);
pPager->stmtSize = 0;
pPager->stmtJSize = 0;
pPager->nPage = 0;
+ pPager->nMaxPage = 0;
pPager->mxPage = 100;
pPager->state = PAGER_UNLOCK;
pPager->errMask = 0;
@@ -1665,14 +1720,16 @@ void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){
}
/*
-** Set the page size.
-**
-** The page size must only be changed when the cache is empty.
+** Set the page size. Return the new size. If the suggest new page
+** size is inappropriate, then an alternative page size is selected
+** and returned.
*/
-void sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
+int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );
- pPager->pageSize = pageSize;
- pPager->psAligned = FORCE_ALIGNMENT(pageSize);
+ if( !pPager->memDb ){
+ pPager->pageSize = pageSize;
+ }
+ return pPager->pageSize;
}
/*
@@ -1824,12 +1881,12 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
rc = SQLITE_OK;
}else{
int busy = 1;
+ BusyHandler *pH;
do {
rc = sqlite3OsLock(&pPager->fd, locktype);
}while( rc==SQLITE_BUSY &&
- pPager->pBusyHandler &&
- pPager->pBusyHandler->xFunc &&
- pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
+ (pH = pPager->pBusyHandler)!=0 &&
+ pH->xFunc && pH->xFunc(pH->pArg, busy++)
);
if( rc==SQLITE_OK ){
pPager->state = locktype;
@@ -1905,7 +1962,7 @@ int sqlite3pager_close(Pager *pPager){
if( !MEMDB ){
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
}
- assert( pPager->journalOpen==0 );
+ assert( pPager->errMask || pPager->journalOpen==0 );
break;
}
case PAGER_SHARED: {
@@ -1932,8 +1989,15 @@ int sqlite3pager_close(Pager *pPager){
sqliteFree(pPg);
}
TRACE2("CLOSE %d\n", PAGERID(pPager));
+ assert( pPager->errMask || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
+ if( pPager->journalOpen ){
+ sqlite3OsClose(&pPager->jfd);
+ }
+ sqliteFree(pPager->aInJournal);
+ if( pPager->stmtOpen ){
+ sqlite3OsClose(&pPager->stfd);
+ }
sqlite3OsClose(&pPager->fd);
- assert( pPager->journalOpen==0 );
/* Temp files are automatically deleted by the OS
** if( pPager->tempFile ){
** sqlite3OsDelete(pPager->zFilename);
@@ -2144,7 +2208,7 @@ static int pager_write_pagelist(PgHdr *pList){
TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
- pPager->nWrite++;
+ TEST_INCR(pPager->nWrite);
}
#ifndef NDEBUG
else{
@@ -2179,6 +2243,26 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
}
/*
+** Return TRUE if there is a hot journal on the given pager.
+** A hot journal is one that needs to be played back.
+**
+** If the current size of the database file is 0 but a journal file
+** exists, that is probably an old journal left over from a prior
+** database with the same name. Just delete the journal.
+*/
+static int hasHotJournal(Pager *pPager){
+ if( !pPager->useJournal ) return 0;
+ if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
+ if( sqlite3OsCheckReservedLock(&pPager->fd) ) return 0;
+ if( sqlite3pager_pagecount(pPager)==0 ){
+ sqlite3OsDelete(pPager->zJournal);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+
+/*
** Acquire a page.
**
** A read lock on the disk file is obtained when the first page is acquired.
@@ -2203,7 +2287,7 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
*/
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
PgHdr *pPg;
- int rc, n;
+ int rc;
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
** number greater than this, or zero, is requested.
@@ -2234,10 +2318,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
/* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted.
*/
- if( pPager->useJournal &&
- sqlite3OsFileExists(pPager->zJournal) &&
- !sqlite3OsCheckReservedLock(&pPager->fd)
- ){
+ if( hasHotJournal(pPager) ){
int rc;
/* Get an EXCLUSIVE lock on the database file. At this point it is
@@ -2298,16 +2379,13 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( pPg==0 ){
/* The requested page is not in the page cache. */
int h;
- pPager->nMiss++;
+ TEST_INCR(pPager->nMiss);
if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){
/* Create a new page */
- pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->psAligned
+ pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
+ sizeof(u32) + pPager->nExtra
+ MEMDB*sizeof(PgHistory) );
if( pPg==0 ){
- if( !MEMDB ){
- pager_unwritelock(pPager);
- }
pPager->errMask |= PAGER_ERR_MEM;
return SQLITE_NOMEM;
}
@@ -2319,6 +2397,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
pPg->pNextAll = pPager->pAll;
pPager->pAll = pPg;
pPager->nPage++;
+ if( pPager->nPage>pPager->nMaxPage ){
+ assert( pPager->nMaxPage==(pPager->nPage-1) );
+ pPager->nMaxPage++;
+ }
}else{
/* Find a page to recycle. Try to locate a page that does not
** require us to do an fsync() on the journal.
@@ -2383,7 +2465,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
/* Unlink the old page from the free list and the hash table
*/
unlinkPage(pPg);
- pPager->nOvfl++;
+ TEST_INCR(pPager->nOvfl);
}
pPg->pgno = pgno;
if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
@@ -2415,13 +2497,12 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( pPager->nExtra>0 ){
memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
}
- n = sqlite3pager_pagecount(pPager);
if( pPager->errMask!=0 ){
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
rc = pager_errcode(pPager);
return rc;
}
- if( n<(int)pgno ){
+ if( sqlite3pager_pagecount(pPager)<(int)pgno ){
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
}else{
int rc;
@@ -2440,7 +2521,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
}
}else{
- pPager->nRead++;
+ TEST_INCR(pPager->nRead);
}
}
#ifdef SQLITE_CHECK_PAGES
@@ -2448,7 +2529,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
#endif
}else{
/* The requested page is in the page cache. */
- pPager->nHit++;
+ TEST_INCR(pPager->nHit);
page_ref(pPg);
}
*ppPage = PGHDR_TO_DATA(pPg);
@@ -2546,6 +2627,7 @@ static int pager_open_journal(Pager *pPager){
assert( pPager->state>=PAGER_RESERVED );
assert( pPager->journalOpen==0 );
assert( pPager->useJournal );
+ assert( pPager->aInJournal==0 );
sqlite3pager_pagecount(pPager);
pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
if( pPager->aInJournal==0 ){
@@ -2559,6 +2641,8 @@ static int pager_open_journal(Pager *pPager){
if( rc!=SQLITE_OK ){
goto failed_to_open_journal;
}
+ SET_FULLSYNC(pPager->jfd, pPager->fullSync);
+ SET_FULLSYNC(pPager->fd, pPager->fullSync);
sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd);
pPager->journalOpen = 1;
pPager->journalStarted = 0;
@@ -2567,7 +2651,7 @@ static int pager_open_journal(Pager *pPager){
pPager->nRec = 0;
if( pPager->errMask!=0 ){
rc = pager_errcode(pPager);
- return rc;
+ goto failed_to_open_journal;
}
pPager->origDbSize = pPager->dbSize;
@@ -2631,11 +2715,7 @@ int sqlite3pager_begin(void *pData, int exFlag){
pPager->state = PAGER_EXCLUSIVE;
pPager->origDbSize = pPager->dbSize;
}else{
- if( SQLITE_BUSY_RESERVED_LOCK || exFlag ){
- rc = pager_wait_on_lock(pPager, RESERVED_LOCK);
- }else{
- rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
- }
+ rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
if( rc==SQLITE_OK ){
pPager->state = PAGER_RESERVED;
if( exFlag ){
@@ -3118,11 +3198,13 @@ int *sqlite3pager_stats(Pager *pPager){
a[3] = pPager->dbSize;
a[4] = pPager->state;
a[5] = pPager->errMask;
+#ifdef SQLITE_TEST
a[6] = pPager->nHit;
a[7] = pPager->nMiss;
a[8] = pPager->nOvfl;
a[9] = pPager->nRead;
a[10] = pPager->nWrite;
+#endif
return a;
}
@@ -3406,8 +3488,10 @@ sync_exit:
** meta-data associated with page pData (i.e. data stored in the nExtra bytes
** allocated along with the page) is the responsibility of the caller.
**
-** A transaction must be active when this routine is called, however it is
-** illegal to call this routine if a statment transaction is active.
+** A transaction must be active when this routine is called. It used to be
+** required that a statement transaction was not active, but this restriction
+** has been removed (CREATE INDEX needs to move a page when a statement
+** transaction is active).
*/
int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
PgHdr *pPg = DATA_TO_PGHDR(pData);
@@ -3415,7 +3499,6 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
int h;
Pgno needSyncPgno = 0;
- assert( !pPager->stmtInUse );
assert( pPg->nRef>0 );
TRACE5("MOVE %d page %d (needSync=%d) moves to %d\n",
@@ -3517,3 +3600,5 @@ void sqlite3pager_refdump(Pager *pPager){
}
}
#endif
+
+#endif /* SQLITE_OMIT_DISKIO */