diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backup.c | 3 | ||||
-rw-r--r-- | src/build.c | 2 | ||||
-rw-r--r-- | src/pager.c | 98 | ||||
-rw-r--r-- | src/pager.h | 8 | ||||
-rw-r--r-- | src/vacuum.c | 4 | ||||
-rw-r--r-- | src/vdbe.c | 88 |
6 files changed, 120 insertions, 83 deletions
diff --git a/src/backup.c b/src/backup.c index 3e2cba5ff..1478a991b 100644 --- a/src/backup.c +++ b/src/backup.c @@ -335,8 +335,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** and the page sizes are different between source and destination */ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); pgszDest = sqlite3BtreeGetPageSize(p->pDest); - destMode = sqlite3PagerJournalMode(sqlite3BtreePager(p->pDest), - PAGER_JOURNALMODE_QUERY); + destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){ rc = SQLITE_READONLY; } diff --git a/src/build.c b/src/build.c index 38166ce7f..4c00e398e 100644 --- a/src/build.c +++ b/src/build.c @@ -3422,7 +3422,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){ db->mallocFailed = 1; return 1; } - sqlite3PagerJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode); + sqlite3PagerSetJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode); } return 0; } diff --git a/src/pager.c b/src/pager.c index 9e1ea7aa8..2b102fbea 100644 --- a/src/pager.c +++ b/src/pager.c @@ -5815,9 +5815,8 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){ } /* -** Get/set the journal-mode for this pager. Parameter eMode must be one of: +** Set the journal-mode for this pager. Parameter eMode must be one of: ** -** PAGER_JOURNALMODE_QUERY ** PAGER_JOURNALMODE_DELETE ** PAGER_JOURNALMODE_TRUNCATE ** PAGER_JOURNALMODE_PERSIST @@ -5825,56 +5824,95 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){ ** PAGER_JOURNALMODE_MEMORY ** PAGER_JOURNALMODE_WAL ** -** If the parameter is not _QUERY, then the journal_mode is set to the -** value specified if the change is allowed. The change may be disallowed -** for the following reasons: +** The journalmode is set to the value specified if the change is allowed. +** The change may be disallowed for the following reasons: ** ** * An in-memory database can only have its journal_mode set to _OFF ** or _MEMORY. ** -** * The journal mode may not be changed while a transaction is active. +** * Temporary databases cannot have _WAL journalmode. ** ** The returned indicate the current (possibly updated) journal-mode. */ -int sqlite3PagerJournalMode(Pager *pPager, int eMode){ - assert( eMode==PAGER_JOURNALMODE_QUERY - || eMode==PAGER_JOURNALMODE_DELETE +int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ + u8 eOld = pPager->journalMode; /* Prior journalmode */ + + /* The eMode parameter is always valid */ + assert( eMode==PAGER_JOURNALMODE_DELETE || eMode==PAGER_JOURNALMODE_TRUNCATE || eMode==PAGER_JOURNALMODE_PERSIST || eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_WAL || eMode==PAGER_JOURNALMODE_MEMORY ); - assert( PAGER_JOURNALMODE_QUERY<0 ); - if( eMode==PAGER_JOURNALMODE_WAL - && pPager->journalMode==PAGER_JOURNALMODE_DELETE - ){ - pPager->journalMode = PAGER_JOURNALMODE_WAL; - }else if( eMode>=0 - && (pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL) - && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY||eMode==PAGER_JOURNALMODE_OFF) - && !pPager->dbModified - && (!isOpen(pPager->jfd) || 0==pPager->journalOff) - ){ - if( isOpen(pPager->jfd) ){ - sqlite3OsClose(pPager->jfd); + /* Do not allow the journalmode of a TEMP database to be changed to WAL + */ + if( pPager->tempFile && eMode==PAGER_JOURNALMODE_WAL ){ + assert( eOld!=PAGER_JOURNALMODE_WAL ); + eMode = eOld; + } + + /* Do allow the journalmode of an in-memory database to be set to + ** anything other than MEMORY or OFF + */ + if( MEMDB ){ + assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF ); + if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){ + eMode = eOld; } - assert( (PAGER_JOURNALMODE_TRUNCATE & 1)==1 ); - assert( (PAGER_JOURNALMODE_PERSIST & 1)==1 ); - assert( (PAGER_JOURNALMODE_DELETE & 1)==0 ); - assert( (PAGER_JOURNALMODE_MEMORY & 1)==0 ); - assert( (PAGER_JOURNALMODE_OFF & 1)==0 ); - if( (pPager->journalMode & 1)==1 && (eMode & 1)==0 - && !pPager->exclusiveMode ){ - sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); + } + + if( eMode!=eOld ){ + /* When changing between rollback modes, close the journal file prior + ** to the change. But when changing from a rollback mode to WAL, keep + ** the journal open since there is a rollback-style transaction in play + ** used to convert the version numbers in the btree header. + */ + if( isOpen(pPager->jfd) && eMode!=PAGER_JOURNALMODE_WAL ){ + sqlite3OsClose(pPager->jfd); } + /* Change the journal mode. */ pPager->journalMode = (u8)eMode; + + /* When transistioning from TRUNCATE or PERSIST to any other journal + ** mode (and we are not in locking_mode=EXCLUSIVE) then delete the + ** journal file. + */ + assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 ); + assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 ); + assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 ); + assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 ); + assert( (PAGER_JOURNALMODE_OFF & 5)!=1 ); + assert( (PAGER_JOURNALMODE_WAL & 5)!=1 ); + if( (eOld & 5)==1 && (eMode & 5)!=1 && !pPager->exclusiveMode ){ + sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); + } } + + /* Return the new journal mode */ return (int)pPager->journalMode; } /* +** Return the current journal mode. +*/ +int sqlite3PagerGetJournalMode(Pager *pPager){ + return (int)pPager->journalMode; +} + +/* +** Return TRUE if the pager is in a state where it is OK to change the +** journalmode. Journalmode changes can only happen when the database +** is unmodified. +*/ +int sqlite3PagerOkToChangeJournalMode(Pager *pPager){ + if( pPager->dbModified ) return 0; + if( isOpen(pPager->jfd) && pPager->journalOff>0 ) return 0; + return 1; +} + +/* ** Get/set the size-limit used for persistent journal files. ** ** Setting the size limit to -1 means no limit is enforced. diff --git a/src/pager.h b/src/pager.h index 57ceb0463..9f77cde07 100644 --- a/src/pager.h +++ b/src/pager.h @@ -68,9 +68,9 @@ typedef struct PgHdr DbPage; #define PAGER_LOCKINGMODE_EXCLUSIVE 1 /* -** Valid values for the second argument to sqlite3PagerJournalMode(). +** Numeric constants that encode the journalmode. */ -#define PAGER_JOURNALMODE_QUERY -1 +#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ @@ -104,7 +104,9 @@ int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); void sqlite3PagerSetSafetyLevel(Pager*,int,int); int sqlite3PagerLockingMode(Pager *, int); -int sqlite3PagerJournalMode(Pager *, int); +int sqlite3PagerSetJournalMode(Pager *, int); +int sqlite3PagerGetJournalMode(Pager*); +int sqlite3PagerOkToChangeJournalMode(Pager*); i64 sqlite3PagerJournalSizeLimit(Pager *, i64); sqlite3_backup **sqlite3PagerBackupPtr(Pager*); diff --git a/src/vacuum.c b/src/vacuum.c index e95b4aa90..a0bf1ebfe 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -173,8 +173,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ #endif /* Do not attempt to change the page size for a WAL database */ - if( sqlite3PagerJournalMode(sqlite3BtreePager(pMain), - PAGER_JOURNALMODE_QUERY)==PAGER_JOURNALMODE_WAL ){ + if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) + ==PAGER_JOURNALMODE_WAL ){ db->nextPagesize = 0; } diff --git a/src/vdbe.c b/src/vdbe.c index 89a8c340b..14785d35d 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5176,7 +5176,6 @@ case OP_JournalMode: { /* out2-prerelease */ Pager *pPager; /* Pager associated with pBt */ int eNew; /* New journal mode */ int eOld; /* The old journal mode */ - const sqlite3_vfs *pVfs; /* The VFS of pPager */ const char *zFilename; /* Name of database file for pPager */ eNew = pOp->p3; @@ -5211,10 +5210,12 @@ case OP_JournalMode: { /* out2-prerelease */ pBt = db->aDb[pOp->p1].pBt; pPager = sqlite3BtreePager(pBt); + eOld = sqlite3PagerGetJournalMode(pPager); + if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; + if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; #ifndef SQLITE_OMIT_WAL zFilename = sqlite3PagerFilename(pPager); - pVfs = sqlite3PagerVfs(pPager); /* Do not allow a transition to journal_mode=WAL for a database ** in temporary storage or if the VFS does not support xShmOpen. @@ -5223,59 +5224,56 @@ case OP_JournalMode: { /* out2-prerelease */ && (zFilename[0]==0 /* Temp file */ || !sqlite3PagerWalSupported(pPager)) /* No xShmOpen support */ ){ - eNew = PAGER_JOURNALMODE_QUERY; + eNew = eOld; } - if( eNew!=PAGER_JOURNALMODE_QUERY ){ - eOld = sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_QUERY); - if( (eNew!=eOld) - && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL) - ){ - if( !db->autoCommit || db->activeVdbeCnt>1 ){ - rc = SQLITE_ERROR; - sqlite3SetString(&p->zErrMsg, db, - "cannot change %s wal mode from within a transaction", - (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of") - ); - break; - }else{ - - if( eOld==PAGER_JOURNALMODE_WAL ){ - /* If leaving WAL mode, close the log file. If successful, the call - ** to PagerCloseWal() checkpoints and deletes the write-ahead-log - ** file. An EXCLUSIVE lock may still be held on the database file - ** after a successful return. - */ - rc = sqlite3PagerCloseWal(pPager); - if( rc==SQLITE_OK ){ - sqlite3PagerJournalMode(pPager, eNew); - }else if( rc==SQLITE_BUSY && pOp->p5==0 ){ - goto abort_due_to_error; - } - }else{ - sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE); - rc = SQLITE_OK; - } - - /* Open a transaction on the database file. Regardless of the journal - ** mode, this transaction always uses a rollback journal. + if( (eNew!=eOld) + && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL) + ){ + if( !db->autoCommit || db->activeVdbeCnt>1 ){ + rc = SQLITE_ERROR; + sqlite3SetString(&p->zErrMsg, db, + "cannot change %s wal mode from within a transaction", + (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of") + ); + break; + }else{ + + if( eOld==PAGER_JOURNALMODE_WAL ){ + /* If leaving WAL mode, close the log file. If successful, the call + ** to PagerCloseWal() checkpoints and deletes the write-ahead-log + ** file. An EXCLUSIVE lock may still be held on the database file + ** after a successful return. */ - assert( sqlite3BtreeIsInTrans(pBt)==0 ); + rc = sqlite3PagerCloseWal(pPager); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeSetVersion(pBt, - (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); - if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error; - } - if( rc==SQLITE_BUSY ){ - eNew = PAGER_JOURNALMODE_QUERY; - rc = SQLITE_OK; + sqlite3PagerSetJournalMode(pPager, eNew); + }else if( rc==SQLITE_BUSY && pOp->p5==0 ){ + goto abort_due_to_error; } + }else{ + sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_DELETE); + rc = SQLITE_OK; + } + + /* Open a transaction on the database file. Regardless of the journal + ** mode, this transaction always uses a rollback journal. + */ + assert( sqlite3BtreeIsInTrans(pBt)==0 ); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeSetVersion(pBt, + (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); + if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error; + } + if( rc==SQLITE_BUSY ){ + eNew = eOld; + rc = SQLITE_OK; } } } #endif /* ifndef SQLITE_OMIT_WAL */ - eNew = sqlite3PagerJournalMode(pPager, eNew); + eNew = sqlite3PagerSetJournalMode(pPager, eNew); pOut = &aMem[pOp->p2]; pOut->flags = MEM_Str|MEM_Static|MEM_Term; pOut->z = (char *)sqlite3JournalModename(eNew); |