Clarify the effects of the pager_ota_mode pragma. Add tests and fixes for the same.
FossilOrigin-Name: decaccc37cbdcd2a663233469efdf4982a810513
This commit is contained in:
parent
15e1ec4c5b
commit
1b95de09bc
121
ext/ota/ota4.test
Normal file
121
ext/ota/ota4.test
Normal file
@ -0,0 +1,121 @@
|
||||
# 2014 August 30
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test some properties of the pager_ota_mode pragma.
|
||||
#
|
||||
|
||||
set testdir [file join [file dirname $argv0] .. .. test]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix ota4
|
||||
|
||||
# 1. Cannot set the pager_ota_mode flag on a WAL mode database.
|
||||
#
|
||||
# 2. Or if there is an open read transaction.
|
||||
#
|
||||
# 3. Cannot start a transaction with pager_ota_mode set if there
|
||||
# is a WAL file in the file-system.
|
||||
#
|
||||
# 4. Or if the wal-mode flag is set in the database file header.
|
||||
#
|
||||
# 5. Cannot open a transaction with pager_ota_mode set if the database
|
||||
# file has been modified by a rollback mode client since the *-oal
|
||||
# file was started.
|
||||
#
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA journal_mode = wal;
|
||||
SELECT * FROM sqlite_master;
|
||||
} {wal}
|
||||
do_catchsql_test 1.2 {
|
||||
PRAGMA pager_ota_mode = 1
|
||||
} {1 {cannot set pager_ota_mode in wal mode}}
|
||||
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
PRAGMA journal_mode = delete;
|
||||
BEGIN;
|
||||
SELECT * FROM sqlite_master;
|
||||
} {delete}
|
||||
do_catchsql_test 2.2 {
|
||||
PRAGMA pager_ota_mode = 1
|
||||
} {1 {cannot set pager_ota_mode with open transaction}}
|
||||
do_execsql_test 2.3 {
|
||||
COMMIT;
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
PRAGMA journal_mode = wal;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
} {wal}
|
||||
do_test 3.2 {
|
||||
forcecopy test.db-wal test.db-bak
|
||||
execsql {
|
||||
PRAGMA journal_mode = delete;
|
||||
PRAGMA pager_ota_mode = 1;
|
||||
}
|
||||
forcecopy test.db-bak test.db-wal
|
||||
catchsql {
|
||||
SELECT * FROM sqlite_master
|
||||
}
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
do_test 4.1 {
|
||||
db close
|
||||
forcedelete test.db-wal test.db-oal
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
PRAGMA journal_mode = wal;
|
||||
PRAGMA pager_ota_mode = 1;
|
||||
}
|
||||
catchsql {
|
||||
SELECT * FROM sqlite_master;
|
||||
}
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
do_test 5.1 {
|
||||
forcedelete test.db-oal
|
||||
reset_db
|
||||
execsql {
|
||||
PRAGMA journal_mode = delete;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
execsql {
|
||||
PRAGMA pager_ota_mode = 1;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2}
|
||||
do_execsql_test 5.2 {
|
||||
PRAGMA pager_ota_mode = 1;
|
||||
SELECT * FROM t1;
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
} {1 2 3 4}
|
||||
do_test 5.3 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(7, 8);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2 7 8}
|
||||
do_catchsql_test 5.4 {
|
||||
PRAGMA pager_ota_mode = 1;
|
||||
SELECT * FROM t1;
|
||||
} {1 {database is locked}}
|
||||
|
||||
finish_test
|
21
manifest
21
manifest
@ -1,5 +1,5 @@
|
||||
C Remove\sthe\sexperimental\ssqlite3_transaction_save()\sand\srestore()\sAPIs.
|
||||
D 2014-09-15T19:34:04.372
|
||||
C Clarify\sthe\seffects\sof\sthe\spager_ota_mode\spragma.\sAdd\stests\sand\sfixes\sfor\sthe\ssame.
|
||||
D 2014-09-16T20:02:41.756
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -125,6 +125,7 @@ F ext/ota/ota.c d37097e92a005d3915883adefbb93019ea6f8841
|
||||
F ext/ota/ota1.test 7cbf37a9f6cd29320f47b041cfeb0cc1d7eaa916
|
||||
F ext/ota/ota2.test 13f76922446c62ed96192e938b8e625ebf0142fa
|
||||
F ext/ota/ota3.test 1c48b7476af1c5920db9a43e7b1476d421a463b5
|
||||
F ext/ota/ota4.test ec01b0d69ad2989559a65fde74560c1cfcca8202
|
||||
F ext/ota/sqlite3ota.c 668ed08dd81ff8ae1e8524b2d4bf0f2609cbf907
|
||||
F ext/ota/sqlite3ota.h 39ce4dffbfcf4ade9e4526369fe2243709345c8e
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
@ -220,13 +221,13 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c addd023b26c623fec4dedc110fc4370a65b4768c
|
||||
F src/os_win.c 0a4042ef35f322e86fa01f6c8884c5e645b911e7
|
||||
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
|
||||
F src/pager.c c1cdf5509386b5c3695082655ce6de6431d920d6
|
||||
F src/pager.h 5c13927809e1c35d85e82e14342d817df3019e07
|
||||
F src/pager.c 2dafc02d49457084c92472f934fe26a75e6d08f5
|
||||
F src/pager.h b62e645e8a19e4f0181253d1663a09f2793d8c94
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a
|
||||
F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a
|
||||
F src/pcache1.c dab8ab930d4a73b99768d881185994f34b80ecaa
|
||||
F src/pragma.c c401b5ddbb5c882e2b9d9e16fad2abd8b4a86564
|
||||
F src/pragma.c 5b255c09d6e38a37ec07830b92acceec5cab8c85
|
||||
F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196
|
||||
F src/printf.c e74925089a85e3c9f0e315595f41c139d3d118c2
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
@ -304,8 +305,8 @@ F src/vdbemem.c dc36ea9fe26c25550c50085f388167086ef7d73a
|
||||
F src/vdbesort.c a7a40ceca6325b853040ffcc363dcd49a45f201b
|
||||
F src/vdbetrace.c 16d39c1ef7d1f4a3a7464bea3b7b4bdd7849c415
|
||||
F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f
|
||||
F src/wal.c 3c56c85d80a17b51cd8cb0bed5c1ecc4f0771012
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/wal.c 8bd0ced6cf1d3389fd6a73b4f12a1e2bf926e75a
|
||||
F src/wal.h e25f9d383ffb07986ba20b78dbde2c1d0cb36ab6
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c 839b5e1db2507e221ad1c308f148a8519ed750be
|
||||
F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
|
||||
@ -1204,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 5efafef51d146bcba3adc425561bfa1ac083c0a7
|
||||
R 684c9325f89b1d695bf7f6172a6df69f
|
||||
P 48d201cd8b68c0377cf8a2cc6439b893f9462fe2
|
||||
R de185427497b23c6bf5f7a43a97cdd26
|
||||
U dan
|
||||
Z 4568916327f8707f39b56bf66a2404a6
|
||||
Z de73fdb4c4401b74adf143cdfee4f7e2
|
||||
|
@ -1 +1 @@
|
||||
48d201cd8b68c0377cf8a2cc6439b893f9462fe2
|
||||
decaccc37cbdcd2a663233469efdf4982a810513
|
36
src/pager.c
36
src/pager.c
@ -615,6 +615,15 @@ struct PagerSavepoint {
|
||||
** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
|
||||
** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
|
||||
** sub-codes.
|
||||
**
|
||||
** otaMode
|
||||
** This variable is normally 0. It is set to 1 by the PagerSetOtaMode()
|
||||
** function - as a result of a "PRAGMA pager_ota_mode=1" command. Once
|
||||
** the *-oal file has been opened and it has been determined that the
|
||||
** database file has not been modified since it was created, this variable
|
||||
** is set to 2.
|
||||
**
|
||||
**
|
||||
*/
|
||||
struct Pager {
|
||||
sqlite3_vfs *pVfs; /* OS functions to use for IO */
|
||||
@ -630,7 +639,7 @@ struct Pager {
|
||||
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 */
|
||||
u8 otaMode; /* True if in ota_mode */
|
||||
u8 otaMode; /* Non-zero if in ota_mode */
|
||||
|
||||
/**************************************************************************
|
||||
** The following block contains those class members that change during
|
||||
@ -5183,6 +5192,15 @@ int sqlite3PagerSharedLock(Pager *pPager){
|
||||
if( pagerUseWal(pPager) ){
|
||||
assert( rc==SQLITE_OK );
|
||||
rc = pagerBeginReadTransaction(pPager);
|
||||
if( rc==SQLITE_OK && pPager->otaMode==1 ){
|
||||
rc = sqlite3WalCheckSalt(pPager->pWal, pPager->fd);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3WalClose(pPager->pWal, 0, 0, 0);
|
||||
pPager->pWal = 0;
|
||||
}else{
|
||||
pPager->otaMode = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
|
||||
@ -7237,6 +7255,20 @@ int sqlite3PagerCloseWal(Pager *pPager){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called by the wal.c module to obtain the 8 bytes of
|
||||
** "salt" written into the wal file header. In OTA mode, this is a copy
|
||||
** of bytes 24-31 of the database file. In non-OTA mode, it is 8 bytes
|
||||
** of pseudo-random data.
|
||||
*/
|
||||
void sqlite3PagerWalSalt(Pager *pPager, u32 *aSalt){
|
||||
if( pPager->otaMode ){
|
||||
memcpy(aSalt, pPager->dbFileVers, 8);
|
||||
}else{
|
||||
sqlite3_randomness(8, aSalt);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !SQLITE_OMIT_WAL */
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
@ -7260,7 +7292,7 @@ int sqlite3PagerSetOtaMode(Pager *pPager, int bOta){
|
||||
if( pPager->pWal || pPager->eState!=PAGER_OPEN ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pPager->otaMode = (u8)bOta;
|
||||
pPager->otaMode = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -208,5 +208,6 @@ void *sqlite3PagerCodec(DbPage *);
|
||||
#endif
|
||||
|
||||
int sqlite3PagerSetOtaMode(Pager *pPager, int bOta);
|
||||
void sqlite3PagerWalSalt(Pager *pPager, u32 *aSalt);
|
||||
|
||||
#endif /* _PAGER_H_ */
|
||||
|
26
src/pragma.c
26
src/pragma.c
@ -877,13 +877,37 @@ void sqlite3Pragma(
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]pager_ota_mode=[01]
|
||||
**
|
||||
** This pragma sets a flag on the pager associated with the main database
|
||||
** only. The flag can only be set when there is no open transaction and
|
||||
** the pager does not already have an open WAL file.
|
||||
**
|
||||
** Once the flag has been set, it is not possible to open a regular WAL
|
||||
** file. If, when the next read-transaction is opened, a *-wal file is
|
||||
** found or the database header flags indicate that it is a wal-mode
|
||||
** database, SQLITE_CANTOPEN is returned.
|
||||
**
|
||||
** Otherwise, if no WAL file or flags are found, the pager opens the *-oal
|
||||
** file and uses it as a write-ahead-log with the *-shm data stored in
|
||||
** heap-memory. If the *-oal file already exists but the database file has
|
||||
** been modified since it was created, an SQLITE_BUSY_SNAPSHOT error is
|
||||
** returned and the read-transaction cannot be opened.
|
||||
**
|
||||
** Other clients see a rollback-mode database on which the pager_ota_mode
|
||||
** client is holding a SHARED lock.
|
||||
*/
|
||||
case PragTyp_PAGER_OTA_MODE: {
|
||||
Btree *pBt = pDb->pBt;
|
||||
assert( pBt!=0 );
|
||||
if( zRight ){
|
||||
int iArg = !!sqlite3Atoi(zRight);
|
||||
rc = sqlite3PagerSetOtaMode(sqlite3BtreePager(pBt), iArg);
|
||||
if( sqlite3BtreeIsInReadTrans(pBt) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"cannot set pager_ota_mode with open transaction"
|
||||
);
|
||||
}else if( sqlite3PagerSetOtaMode(sqlite3BtreePager(pBt), iArg) ){
|
||||
sqlite3ErrorMsg(pParse, "cannot set pager_ota_mode in wal mode");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
22
src/wal.c
22
src/wal.c
@ -2769,7 +2769,9 @@ int sqlite3WalFrames(
|
||||
sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
|
||||
sqlite3Put4byte(&aWalHdr[8], szPage);
|
||||
sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
|
||||
if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
|
||||
if( pWal->nCkpt==0 ){
|
||||
sqlite3PagerWalSalt(pList->pPager, pWal->hdr.aSalt);
|
||||
}
|
||||
memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
|
||||
walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
|
||||
sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
|
||||
@ -3084,6 +3086,24 @@ int sqlite3WalHeapMemory(Wal *pWal){
|
||||
return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
|
||||
}
|
||||
|
||||
/*
|
||||
** Unless the wal file is empty, check that the 8 bytes of salt stored in
|
||||
** the wal header are identical to those in the buffer indicated by the
|
||||
** second argument. If they are not, return SQLITE_BUSY_SNAPSHOT. Otherwise,
|
||||
** if the buffers match or the WAL file is empty, return SQLITE_OK.
|
||||
*/
|
||||
int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file *pFd){
|
||||
int rc = SQLITE_OK;
|
||||
if( pWal->hdr.mxFrame>0 ){
|
||||
u8 aData[16];
|
||||
rc = sqlite3OsRead(pFd, aData, sizeof(aData), 24);
|
||||
if( rc==SQLITE_OK && memcmp(pWal->hdr.aSalt, aData, 8) ){
|
||||
rc = SQLITE_BUSY_SNAPSHOT;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
/*
|
||||
** If the argument is not NULL, it points to a Wal object that holds a
|
||||
|
@ -126,6 +126,8 @@ int sqlite3WalExclusiveMode(Wal *pWal, int op);
|
||||
*/
|
||||
int sqlite3WalHeapMemory(Wal *pWal);
|
||||
|
||||
int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file*);
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
/* If the WAL file is not empty, return the number of bytes of content
|
||||
** stored in each frame (i.e. the db page-size when the WAL was created).
|
||||
|
Loading…
Reference in New Issue
Block a user