mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Use the read and write version fields of the database header to mark a database as operating in wal-mode.
FossilOrigin-Name: 96bef18c1411c3e0348295886f105e1646c46320
This commit is contained in:
25
manifest
25
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\ssqlite3_log_hook()\sinterface\sfor\sscheduling\scheckpoints.
|
||||
D 2010-04-19T18:03:52
|
||||
C Use\sthe\sread\sand\swrite\sversion\sfields\sof\sthe\sdatabase\sheader\sto\smark\sa\sdatabase\sas\soperating\sin\swal-mode.
|
||||
D 2010-04-20T18:53:15
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -109,8 +109,8 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c e86634da8c48357a759694c9c7c471125cd8d5a8
|
||||
F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c 01559397cbd4a5aa62a822e8ca9ac94b6db14743
|
||||
F src/btree.h ad6cff92286f9b02ec32f0b97136e9a544249f37
|
||||
F src/btree.c 013cf019484e309e909a667654612b38a02dc2b6
|
||||
F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
|
||||
F src/btreeInt.h 22447d259639271774a931cbf66aa55112846681
|
||||
F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7
|
||||
F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
|
||||
@ -154,13 +154,13 @@ F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
|
||||
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
|
||||
F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1
|
||||
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
|
||||
F src/pager.c f9ad51dfa617131240ae77545c0083118324fc81
|
||||
F src/pager.h aeaee9ceb4a4a6d15c2163ef4e11a7590fd54b59
|
||||
F src/pager.c 1dcf76bead8f1b51809bd8189ef9b02f2c94dc7f
|
||||
F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
|
||||
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 6dc1871ce8ead9187161c370a58cd06c84221f76
|
||||
F src/pragma.c f12cb58a8aa0d80cfed282ef87a285ed71beb793
|
||||
F src/pragma.c bae3ce82ca6d0ac5d3ca3e46b286856d1f0ddd70
|
||||
F src/prepare.c fd1398cb1da54385ba5bd68d93928f10d10a1d9c
|
||||
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
@ -214,7 +214,7 @@ F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||
F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee
|
||||
F src/vdbe.c 2e2aaa765de667dd15e0462cf853efd1b2f97998
|
||||
F src/vdbe.c 304851b32c5f918a7ce92e4e9f94fbde0b604b21
|
||||
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
|
||||
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
|
||||
F src/vdbeapi.c 466044df5bc916f778833e927165fd02cdef6086
|
||||
@ -758,9 +758,10 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test a56ff378f58b145fd3bf38c277fbfe792cd47bdd
|
||||
F test/wal.test 273c0006e75c99cb34d0659851e7103fd4748c20
|
||||
F test/walcrash.test 45cfbab30bb7cbe0b2e9d5cabe90dbcad10cb89b
|
||||
F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47
|
||||
F test/walmode.test cd6ee20f08af2d81fddc049f8d7e387a807f067e
|
||||
F test/walslow.test 38076d5fad49e3678027be0f8110e6a32d531dc2
|
||||
F test/walthread.test 27e44ee6fd02f1f494a24f999c97086af3ab739d
|
||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||
@ -806,7 +807,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 9d51c3b754f0b94fea5ef3d669ad583b93b2b024
|
||||
R 8eb45c9f56fe0d743248bffdfb606bc1
|
||||
P 9bda601455705475075e33bfa85687bce34b15ff
|
||||
R b30f3db6dd942a33d471d74ec2e33c70
|
||||
U dan
|
||||
Z e82f118f370901abf724c6ac84b89351
|
||||
Z d82da3172ce11d2f9fc95cc996cdb180
|
||||
|
@ -1 +1 @@
|
||||
9bda601455705475075e33bfa85687bce34b15ff
|
||||
96bef18c1411c3e0348295886f105e1646c46320
|
39
src/btree.c
39
src/btree.c
@ -2261,13 +2261,25 @@ static int lockBtree(BtShared *pBt){
|
||||
if( memcmp(page1, zMagicHeader, 16)!=0 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
if( page1[18]>1 ){
|
||||
if( page1[18]>2 ){
|
||||
pBt->readOnly = 1;
|
||||
}
|
||||
if( page1[19]>1 ){
|
||||
if( page1[19]>2 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
|
||||
/* If the write version is set to 2, turn on write-ahead logging mode. */
|
||||
if( page1[19]==2 ){
|
||||
int isOpen = 0;
|
||||
rc = sqlite3PagerOpenLog(pBt->pPager, &isOpen);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto page1_init_failed;
|
||||
}else if( isOpen==0 ){
|
||||
releasePage(pPage1);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* The maximum embedded fraction must be exactly 25%. And the minimum
|
||||
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
|
||||
** The original design allowed these amounts to vary, but as of
|
||||
@ -7963,3 +7975,26 @@ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
|
||||
pCur->isIncrblobHandle = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Set both the "read version" (single byte at byte offset 18) and
|
||||
** "write version" (single byte at byte offset 19) fields in the database
|
||||
** header to iVersion.
|
||||
*/
|
||||
int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
|
||||
BtShared *pBt = pBtree->pBt;
|
||||
int rc; /* Return code */
|
||||
|
||||
assert( pBtree->inTrans==TRANS_WRITE );
|
||||
assert( pBt->pPage1 );
|
||||
assert( iVersion==1 || iVersion==2 );
|
||||
|
||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *aData = pBt->pPage1->aData;
|
||||
aData[18] = (u8)iVersion;
|
||||
aData[19] = (u8)iVersion;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -186,6 +186,8 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *);
|
||||
void sqlite3BtreeClearCursor(BtCursor *);
|
||||
|
||||
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
|
||||
|
||||
#ifndef NDEBUG
|
||||
int sqlite3BtreeCursorIsValid(BtCursor*);
|
||||
#endif
|
||||
|
159
src/pager.c
159
src/pager.c
@ -1405,9 +1405,11 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
|
||||
/* This branch may be executed with Pager.journalMode==MEMORY if
|
||||
** a hot-journal was just rolled back. In this case the journal
|
||||
** file should be closed and deleted. If this connection writes to
|
||||
** the database file, it will do so using an in-memory journal. */
|
||||
** the database file, it will do so using an in-memory journal.
|
||||
*/
|
||||
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
|
||||
);
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
if( !pPager->tempFile ){
|
||||
@ -3724,54 +3726,6 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a connection to the write-ahead log file for pager pPager. If
|
||||
** the log connection is already open, this function is a no-op.
|
||||
*/
|
||||
static int pagerOpenLog(Pager *pPager){
|
||||
if( !pPager->pLog ){
|
||||
int rc; /* Return code */
|
||||
|
||||
/* Before opening the log file, obtain a SHARED lock on the database
|
||||
** file. This lock will not be released until after the log file
|
||||
** connection has been closed. The purpose of this lock is to stop
|
||||
** any other process from unlinking the log or log-summary files while
|
||||
** this connection still has them open. An EXCLUSIVE lock on the
|
||||
** database file is required to unlink either of those two files.
|
||||
*/
|
||||
assert( pPager->state==PAGER_UNLOCK );
|
||||
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( pPager->state==PAGER_UNLOCK );
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
assert( pPager->state>=SHARED_LOCK );
|
||||
|
||||
/* Open the connection to the log file. If this operation fails,
|
||||
** (e.g. due to malloc() failure), unlock the database file and
|
||||
** return an error code.
|
||||
*/
|
||||
rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
|
||||
if( rc!=SQLITE_OK ){
|
||||
osUnlock(pPager->fd, SQLITE_LOCK_NONE);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
return rc;
|
||||
}
|
||||
}else{
|
||||
/* If the log file was already open, check that the pager is still holding
|
||||
** the required SHARED lock on the database file.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int locktype;
|
||||
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
|
||||
assert( locktype==SQLITE_LOCK_SHARED );
|
||||
#endif
|
||||
pPager->state = PAGER_SHARED;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called to obtain a shared lock on the database file.
|
||||
@ -3826,16 +3780,9 @@ int sqlite3PagerSharedLock(Pager *pPager){
|
||||
pager_reset(pPager);
|
||||
}
|
||||
|
||||
|
||||
if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
|
||||
if( pagerUseLog(pPager) ){
|
||||
int changed = 0; /* True if the cache must be flushed */
|
||||
|
||||
/* Open the log file, if it is not already open. */
|
||||
rc = pagerOpenLog(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Open a log snapshot to read from. */
|
||||
rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed);
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -3846,6 +3793,8 @@ int sqlite3PagerSharedLock(Pager *pPager){
|
||||
}
|
||||
rc = sqlite3PagerPagecount(pPager, &dummy);
|
||||
}
|
||||
pPager->state = PAGER_SHARED;
|
||||
|
||||
}else if( pPager->state==PAGER_UNLOCK || isErrorReset ){
|
||||
sqlite3_vfs * const pVfs = pPager->pVfs;
|
||||
int isHotJournal = 0;
|
||||
@ -4002,6 +3951,10 @@ int sqlite3PagerSharedLock(Pager *pPager){
|
||||
}
|
||||
}
|
||||
assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED );
|
||||
|
||||
if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
|
||||
pPager->journalMode = PAGER_JOURNALMODE_DELETE;
|
||||
}
|
||||
}
|
||||
|
||||
failed:
|
||||
@ -4384,6 +4337,7 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
|
||||
if( rc==SQLITE_OK ){
|
||||
pPager->dbOrigSize = pPager->dbSize;
|
||||
pPager->state = PAGER_RESERVED;
|
||||
pPager->journalOff = 0;
|
||||
}
|
||||
}else{
|
||||
/* Obtain a RESERVED lock on the database file. If the exFlag parameter
|
||||
@ -4485,7 +4439,7 @@ static int pager_write(PgHdr *pPg){
|
||||
}
|
||||
if( !isOpen(pPager->jfd)
|
||||
&& pPager->journalMode!=PAGER_JOURNALMODE_OFF
|
||||
&& pPager->journalMode!=PAGER_JOURNALMODE_WAL
|
||||
&& !pagerUseLog(pPager)
|
||||
){
|
||||
assert( pPager->useJournal );
|
||||
rc = pager_open_journal(pPager);
|
||||
@ -5621,7 +5575,7 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){
|
||||
** 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 is disallowed
|
||||
** 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
|
||||
@ -5640,7 +5594,12 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
|
||||
|| eMode==PAGER_JOURNALMODE_WAL
|
||||
|| eMode==PAGER_JOURNALMODE_MEMORY );
|
||||
assert( PAGER_JOURNALMODE_QUERY<0 );
|
||||
if( eMode>=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
|
||||
@ -5659,13 +5618,6 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
|
||||
sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
|
||||
}
|
||||
|
||||
/* Switching into WAL mode can only take place when no
|
||||
** locks are held on the database file.
|
||||
*/
|
||||
if( eMode==PAGER_JOURNALMODE_WAL && pPager->state!=PAGER_UNLOCK ){
|
||||
return (int)pPager->journalMode;
|
||||
}
|
||||
|
||||
pPager->journalMode = (u8)eMode;
|
||||
}
|
||||
return (int)pPager->journalMode;
|
||||
@ -5713,4 +5665,77 @@ int sqlite3PagerLogCallback(Pager *pPager){
|
||||
return sqlite3LogCallback(pPager->pLog);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a connection to the write-ahead log file for pager pPager. If
|
||||
** the log connection is already open, this function is a no-op.
|
||||
**
|
||||
** The caller must be holding a SHARED lock on the database file to call
|
||||
** this function.
|
||||
*/
|
||||
int sqlite3PagerOpenLog(Pager *pPager, int *pisOpen){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int locktype;
|
||||
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
|
||||
assert( locktype==SQLITE_LOCK_SHARED );
|
||||
assert( pPager->state>=PAGER_SHARED );
|
||||
#endif
|
||||
|
||||
if( !pPager->pLog ){
|
||||
|
||||
/* Open the connection to the log file. If this operation fails,
|
||||
** (e.g. due to malloc() failure), unlock the database file and
|
||||
** return an error code.
|
||||
*/
|
||||
rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
|
||||
if( rc==SQLITE_OK ){
|
||||
pPager->journalMode = PAGER_JOURNALMODE_WAL;
|
||||
}
|
||||
}else{
|
||||
*pisOpen = 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called to close the connection to the log file prior
|
||||
** to switching from WAL to rollback mode.
|
||||
**
|
||||
** Before closing the log file, this function attempts to take an
|
||||
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
|
||||
** error (SQLITE_BUSY) is returned and the log connection is not closed.
|
||||
** If successful, the EXCLUSIVE lock is not released before returning.
|
||||
*/
|
||||
int sqlite3PagerCloseLog(Pager *pPager){
|
||||
int rc = SQLITE_OK;
|
||||
if( pPager->pLog ){
|
||||
|
||||
/* Try to obtain an EXCLUSIVE lock on the database file. */
|
||||
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
|
||||
|
||||
/* If the EXCLUSIVE lock was obtained, checkpoint and close the log. */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3LogClose(pPager->pLog, pPager->fd,
|
||||
(pPager->noSync ? 0 : pPager->sync_flags),
|
||||
(u8*)pPager->pTmpSpace
|
||||
);
|
||||
pPager->pLog = 0;
|
||||
}
|
||||
|
||||
/* Make sure the EXCLUSIVE lock has not been lost somehow */
|
||||
#ifdef SQLITE_DEBUG
|
||||
{
|
||||
int locktype;
|
||||
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
|
||||
assert( locktype==SQLITE_LOCK_EXCLUSIVE );
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_DISKIO */
|
||||
|
@ -136,6 +136,8 @@ int sqlite3PagerSharedLock(Pager *pPager);
|
||||
|
||||
int sqlite3PagerCheckpoint(Pager *pPager);
|
||||
int sqlite3PagerLogCallback(Pager *pPager);
|
||||
int sqlite3PagerOpenLog(Pager *pPager, int *pisOpen);
|
||||
int sqlite3PagerCloseLog(Pager *pPager);
|
||||
|
||||
/* Functions used to query pager state and configuration. */
|
||||
u8 sqlite3PagerIsreadonly(Pager*);
|
||||
|
77
src/pragma.c
77
src/pragma.c
@ -257,6 +257,28 @@ static const char *actionName(u8 action){
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
|
||||
** defined in pager.h. This function returns the associated lowercase
|
||||
** journal-mode name.
|
||||
*/
|
||||
const char *sqlite3JournalModename(int eMode){
|
||||
static char * const azModeName[] = {
|
||||
"delete", "persist", "off", "truncate", "memory", "wal"
|
||||
};
|
||||
assert( PAGER_JOURNALMODE_DELETE==0 );
|
||||
assert( PAGER_JOURNALMODE_PERSIST==1 );
|
||||
assert( PAGER_JOURNALMODE_OFF==2 );
|
||||
assert( PAGER_JOURNALMODE_TRUNCATE==3 );
|
||||
assert( PAGER_JOURNALMODE_MEMORY==4 );
|
||||
assert( PAGER_JOURNALMODE_WAL==5 );
|
||||
assert( eMode>=0 && eMode<=ArraySize(azModeName) );
|
||||
|
||||
if( eMode==ArraySize(azModeName) ) return 0;
|
||||
return azModeName[eMode];
|
||||
}
|
||||
|
||||
/*
|
||||
** Process a pragma statement.
|
||||
**
|
||||
@ -513,18 +535,21 @@ void sqlite3Pragma(
|
||||
** PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory)
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
|
||||
int eMode;
|
||||
static char * const azModeName[] = {
|
||||
"delete", "persist", "off", "truncate", "memory", "wal"
|
||||
};
|
||||
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
|
||||
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
|
||||
|
||||
if( zRight==0 ){
|
||||
eMode = PAGER_JOURNALMODE_QUERY;
|
||||
}else{
|
||||
const char *zMode;
|
||||
int n = sqlite3Strlen30(zRight);
|
||||
eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1;
|
||||
while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){
|
||||
eMode--;
|
||||
for(eMode=0; (zMode = sqlite3JournalModename(eMode)); eMode++){
|
||||
if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
|
||||
}
|
||||
if( !zMode ){
|
||||
eMode = PAGER_JOURNALMODE_QUERY;
|
||||
}
|
||||
}
|
||||
if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
|
||||
@ -533,40 +558,32 @@ void sqlite3Pragma(
|
||||
** the journal-mode of the main database).
|
||||
*/
|
||||
eMode = db->dfltJournalMode;
|
||||
sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3JournalModename(eMode), P4_STATIC);
|
||||
}else{
|
||||
Pager *pPager;
|
||||
if( pId2->n==0 ){
|
||||
int ii;
|
||||
|
||||
if( pId2->n==0 && eMode!=PAGER_JOURNALMODE_WAL ){
|
||||
/* This indicates that no database name was specified as part
|
||||
** of the PRAGMA command. In this case the journal-mode must be
|
||||
** set on all attached databases, as well as the main db file.
|
||||
**
|
||||
** Also, the sqlite3.dfltJournalMode variable is set so that
|
||||
** any subsequently attached databases also use the specified
|
||||
** journal mode.
|
||||
** journal mode. Except, the default journal mode is never set
|
||||
** to WAL.
|
||||
*/
|
||||
int ii;
|
||||
assert(pDb==&db->aDb[0]);
|
||||
for(ii=1; ii<db->nDb; ii++){
|
||||
if( db->aDb[ii].pBt ){
|
||||
pPager = sqlite3BtreePager(db->aDb[ii].pBt);
|
||||
sqlite3PagerJournalMode(pPager, eMode);
|
||||
}
|
||||
}
|
||||
db->dfltJournalMode = (u8)eMode;
|
||||
}
|
||||
pPager = sqlite3BtreePager(pDb->pBt);
|
||||
eMode = sqlite3PagerJournalMode(pPager, eMode);
|
||||
|
||||
for(ii=db->nDb-1; ii>=0; ii--){
|
||||
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
|
||||
sqlite3VdbeUsesBtree(v, ii);
|
||||
sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
|
||||
}
|
||||
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 );
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0,
|
||||
azModeName[eMode], P4_STATIC);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}else
|
||||
|
||||
|
81
src/vdbe.c
81
src/vdbe.c
@ -5187,6 +5187,9 @@ case OP_AggFinal: {
|
||||
}
|
||||
|
||||
/* Opcode: Checkpoint P1 * * * *
|
||||
**
|
||||
** Checkpoint database P1. This is a no-op if P1 is not currently in
|
||||
** WAL mode.
|
||||
*/
|
||||
case OP_Checkpoint: {
|
||||
Btree *pBt; /* Btree to checkpoint */
|
||||
@ -5198,6 +5201,84 @@ case OP_Checkpoint: {
|
||||
break;
|
||||
};
|
||||
|
||||
/* Opcode: JournalMode P1 P2 P3 * *
|
||||
**
|
||||
** Change the journal mode of database P1 to P3. P3 must be one of the
|
||||
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
|
||||
** modes (delete, truncate, persist, off and memory), this is a simple
|
||||
** operation. No IO is required.
|
||||
**
|
||||
** If changing into or out of WAL mode the procedure is more complicated.
|
||||
**
|
||||
** Write a string containing the final journal-mode to register P2.
|
||||
*/
|
||||
case OP_JournalMode: {
|
||||
Btree *pBt; /* Btree to change journal mode of */
|
||||
Pager *pPager; /* Pager associated with pBt */
|
||||
int eNew = pOp->p3; /* New journal mode */
|
||||
|
||||
assert( eNew==PAGER_JOURNALMODE_DELETE
|
||||
|| eNew==PAGER_JOURNALMODE_TRUNCATE
|
||||
|| eNew==PAGER_JOURNALMODE_PERSIST
|
||||
|| eNew==PAGER_JOURNALMODE_OFF
|
||||
|| eNew==PAGER_JOURNALMODE_MEMORY
|
||||
|| eNew==PAGER_JOURNALMODE_WAL
|
||||
|| eNew==PAGER_JOURNALMODE_QUERY
|
||||
);
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (1<<pOp->p1))!=0 );
|
||||
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
pPager = sqlite3BtreePager(pBt);
|
||||
|
||||
if( eNew!=PAGER_JOURNALMODE_QUERY ){
|
||||
int 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")
|
||||
);
|
||||
}else{
|
||||
|
||||
/* If leaving WAL mode, close the log file. If successful, the call to
|
||||
** PagerCloseLog() checkpoints and deletes the write-ahead-log file.
|
||||
** An EXCLUSIVE lock is still held on the database file after returning.
|
||||
*/
|
||||
if( eOld==PAGER_JOURNALMODE_WAL ){
|
||||
rc = sqlite3PagerCloseLog(pPager);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
sqlite3PagerJournalMode(pPager, eNew);
|
||||
}else{
|
||||
sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
|
||||
}
|
||||
|
||||
/* Open a transaction on the database file. Regardless of the journal
|
||||
** mode, this transaction always uses a rollback journal.
|
||||
*/
|
||||
assert( sqlite3BtreeIsInTrans(pBt)==0 );
|
||||
rc = sqlite3BtreeBeginTrans(pBt, 2);
|
||||
assert( rc==SQLITE_OK || eOld!=PAGER_JOURNALMODE_WAL );
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eNew = sqlite3PagerJournalMode(pPager, eNew);
|
||||
pOut = &aMem[pOp->p2];
|
||||
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
|
||||
pOut->z = sqlite3JournalModename(eNew);
|
||||
pOut->n = sqlite3Strlen30(pOut->z);
|
||||
pOut->enc = SQLITE_UTF8;
|
||||
sqlite3VdbeChangeEncoding(pOut, encoding);
|
||||
break;
|
||||
};
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/* Opcode: Vacuum * * * * *
|
||||
**
|
||||
|
@ -31,6 +31,7 @@ proc blob {nByte} {
|
||||
|
||||
proc sqlite3_wal {args} {
|
||||
eval sqlite3 $args
|
||||
[lindex $args 0] eval { PRAGMA page_size = 1024 }
|
||||
[lindex $args 0] eval { PRAGMA journal_mode = wal }
|
||||
[lindex $args 0] eval { PRAGMA synchronous = normal }
|
||||
[lindex $args 0] function blob blob
|
||||
@ -60,14 +61,19 @@ do_test wal-0.1 {
|
||||
execsql { PRAGMA synchronous = normal }
|
||||
execsql { PRAGMA journal_mode = wal }
|
||||
} {wal}
|
||||
do_test wal-0.2 {
|
||||
file size test.db
|
||||
} {1024}
|
||||
|
||||
do_test wal-1.0 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(a, b);
|
||||
}
|
||||
list [file exists test.db-journal] [file exists test.db-wal]
|
||||
} {0 1}
|
||||
list [file exists test.db-journal] \
|
||||
[file exists test.db-wal] \
|
||||
[file size test.db]
|
||||
} {0 1 1024}
|
||||
do_test wal-1.1 {
|
||||
execsql COMMIT
|
||||
list [file exists test.db-journal] [file exists test.db-wal]
|
||||
@ -197,9 +203,10 @@ foreach sector {512 4096} {
|
||||
foreach pgsz {512 1024 2048 4096} {
|
||||
file delete -force test.db test.db-wal
|
||||
do_test wal-6.$sector.$pgsz.1 {
|
||||
sqlite3_wal db test.db -vfs devsym
|
||||
sqlite3 db test.db -vfs devsym
|
||||
execsql "
|
||||
PRAGMA page_size = $pgsz ;
|
||||
PRAGMA page_size = $pgsz;
|
||||
PRAGMA journal_mode = wal;
|
||||
"
|
||||
execsql "
|
||||
CREATE TABLE t1(a, b);
|
||||
@ -224,7 +231,7 @@ do_test wal-7.1 {
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
list [file size test.db] [file size test.db-wal]
|
||||
} [list 0 [log_file_size 3 1024]]
|
||||
} [list 1024 [log_file_size 3 1024]]
|
||||
do_test wal-7.2 {
|
||||
execsql { PRAGMA checkpoint }
|
||||
list [file size test.db] [file size test.db-wal]
|
||||
@ -235,11 +242,17 @@ do_test wal-7.2 {
|
||||
#
|
||||
do_test wal-8.1 {
|
||||
reopen_db
|
||||
catch { db close }
|
||||
file delete -force test.db test.db-wal
|
||||
|
||||
sqlite3 db test.db
|
||||
db function blob blob
|
||||
execsql {
|
||||
PRAGMA auto_vacuum = 1;
|
||||
PRAGMA journal_mode = wal;
|
||||
PRAGMA auto_vacuum;
|
||||
}
|
||||
} {1}
|
||||
} {wal 1}
|
||||
do_test wal-8.2 {
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
@ -269,7 +282,6 @@ do_test wal-8.3 {
|
||||
do_test wal-9.1 {
|
||||
reopen_db
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(x PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(blob(900));
|
||||
INSERT INTO t1 VALUES(blob(900));
|
||||
@ -282,7 +294,7 @@ do_test wal-9.1 {
|
||||
INSERT INTO t1 SELECT blob(900) FROM t1; /* 256 */
|
||||
}
|
||||
file size test.db
|
||||
} 0
|
||||
} 1024
|
||||
do_test wal-9.2 {
|
||||
sqlite3_wal db2 test.db
|
||||
execsql {PRAGMA integrity_check } db2
|
||||
@ -560,7 +572,7 @@ do_test wal-11.1 {
|
||||
CREATE TABLE t1(x PRIMARY KEY);
|
||||
}
|
||||
list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
|
||||
} {0 3}
|
||||
} {1 3}
|
||||
do_test wal-11.2 {
|
||||
execsql { PRAGMA checkpoint }
|
||||
list [expr [file size test.db]/1024] [file size test.db-wal]
|
||||
@ -613,7 +625,7 @@ do_test wal-11.10 {
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
list [expr [file size test.db]/1024] [file size test.db-wal]
|
||||
} [list 37 [log_file_size 35 1024]]
|
||||
} [list 37 [log_file_size 37 1024]]
|
||||
do_test wal-11.11 {
|
||||
execsql {
|
||||
SELECT count(*) FROM t1;
|
||||
@ -623,7 +635,7 @@ do_test wal-11.11 {
|
||||
} {32 16}
|
||||
do_test wal-11.12 {
|
||||
list [expr [file size test.db]/1024] [file size test.db-wal]
|
||||
} [list 37 [log_file_size 35 1024]]
|
||||
} [list 37 [log_file_size 37 1024]]
|
||||
do_test wal-11.13 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES( blob(900) );
|
||||
@ -633,7 +645,7 @@ do_test wal-11.13 {
|
||||
} {17 ok}
|
||||
do_test wal-11.14 {
|
||||
list [expr [file size test.db]/1024] [file size test.db-wal]
|
||||
} [list 37 [log_file_size 35 1024]]
|
||||
} [list 37 [log_file_size 37 1024]]
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@ -650,11 +662,12 @@ do_test wal-12.1 {
|
||||
INSERT INTO t1 VALUES('A', 1);
|
||||
}
|
||||
list [expr [file size test.db]/1024] [file size test.db-wal]
|
||||
} [list 0 [log_file_size 5 1024]]
|
||||
} [list 1 [log_file_size 5 1024]]
|
||||
do_test wal-12.2 {
|
||||
db close
|
||||
sqlite3_wal db test.db
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
PRAGMA synchronous = normal;
|
||||
UPDATE t1 SET y = 0 WHERE x = 'A';
|
||||
}
|
||||
list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
|
||||
@ -668,7 +681,6 @@ do_test wal-12.4 {
|
||||
file copy -force test.db test2.db
|
||||
file copy -force test.db-wal test2.db-wal
|
||||
sqlite3_wal db2 test2.db
|
||||
breakpoint
|
||||
execsql { SELECT * FROM t2 } db2
|
||||
} {B 1}
|
||||
db2 close
|
||||
@ -695,6 +707,5 @@ do_test wal-12.4 {
|
||||
} {B 2}
|
||||
db2 close
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
25
test/walmode.test
Normal file
25
test/walmode.test
Normal file
@ -0,0 +1,25 @@
|
||||
# 2010 April 19
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the operation of the library in
|
||||
# "PRAGMA journal_mode=WAL" mode.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_test walmode-1.1 {
|
||||
execsql {
|
||||
PRAGMA journal_mode = wal;
|
||||
}
|
||||
} {wal}
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user