From: dan Date: Wed, 3 Sep 2014 19:30:32 +0000 (+0000) Subject: Split part of "PRAGMA ota_mode" off into "PRAGMA pager_ota_mode". This allows some... X-Git-Tag: version-3.8.11~252^2~115 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=19b465a0ae4c73ad9f118f85bc134e7a7d515949;p=thirdparty%2Fsqlite.git Split part of "PRAGMA ota_mode" off into "PRAGMA pager_ota_mode". This allows some specialized custom VFS implementations to intercept and implement the expected pager-related effects of this pragma. FossilOrigin-Name: 209f672e588b54dfbfb83c7859cacdc4497f0f2b --- diff --git a/ext/ota/ota2.test b/ext/ota/ota2.test index dfa4a48e9d..d80f7360c9 100644 --- a/ext/ota/ota2.test +++ b/ext/ota/ota2.test @@ -14,49 +14,60 @@ set testdir [file join [file dirname $argv0] .. .. test] source $testdir/tester.tcl set ::testprefix ota2 +forcedelete test.db-oal do_execsql_test 1.0 { - PRAGMA ota_mode = 1; - PRAGMA journal_mode = wal; CREATE TABLE t1(a, b); - BEGIN; - INSERT INTO t1 VALUES(1, 2); -} {wal} - -do_test 1.1 { - set state [sqlite3_transaction_save db] - db close - file exists test.db-wal -} {1} - -do_test 1.2 { - sqlite3 db test.db - db eval {SELECT * FROM t1} + INSERT INTO t1 VALUES(1, 2); } {} +do_test 1.1 { glob test.db* } {test.db} -do_test 1.3 { - execsql {BEGIN IMMEDIATE} - sqlite3_transaction_restore db $::state - db eval {SELECT * FROM t1} -} {1 2} +do_execsql_test 1.2 { + PRAGMA pager_ota_mode = 1; + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + SELECT * FROM t1; +} {1 2 3 4 5 6} + +do_test 1.3 { glob test.db* } {test.db test.db-oal} do_test 1.4 { - execsql { - INSERT INTO t1 VALUES(3, 4); - COMMIT; - SELECT * FROM t1; - } -} {1 2 3 4} + sqlite3 db2 test.db + db2 eval { SELECT * FROM t1 } +} {1 2} do_test 1.5 { - db close - file exists test.db-wal -} {0} + catchsql { INSERT INTO t1 VALUES(7, 8) } db2 +} {1 {database is locked}} + +db2 close +db close + +sqlite3 db test.db +do_execsql_test 1.6 { + PRAGMA pager_ota_mode = 1; + SELECT * FROM t1; +} {1 2 3 4 5 6} + +do_execsql_test 1.7 { + INSERT INTO t1 VALUES(7,8); + SELECT * FROM t1; +} {1 2 3 4 5 6 7 8} + +db close +sqlite3 db2 test.db + +do_test 1.8 { + execsql { BEGIN; SELECT * FROM t1 } db2 +} {1 2} +do_test 1.9 { + file rename test.db-oal test.db-wal + execsql { SELECT * FROM t1 } db2 +} {1 2} +do_test 1.10 { + execsql { COMMIT; SELECT * FROM t1 } db2 +} {1 2 3 4 5 6 7 8} -do_test 1.5 { - sqlite3 db test.db - db eval {SELECT * FROM t1} -} {1 2 3 4} finish_test diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c index 5483b9049f..2f61c671ac 100644 --- a/ext/ota/sqlite3ota.c +++ b/ext/ota/sqlite3ota.c @@ -13,6 +13,8 @@ #include #include +#include +#include #include "sqlite3.h" #include "sqlite3ota.h" @@ -23,8 +25,6 @@ ** update so that it can be resumed later. The table contains at most a ** single row: ** -** "wal_state" -> Blob to use with sqlite3_transaction_restore(). -** ** "tbl" -> Table currently being written (target database names). ** ** "idx" -> Index currently being written (target database names). @@ -36,10 +36,11 @@ ** so far as part of this ota update. */ #define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota_state" \ - "(wal_state, tbl, idx, row, progress)" + "(tbl, idx, row, progress)" typedef struct OtaTblIter OtaTblIter; typedef struct OtaIdxIter OtaIdxIter; +typedef struct OtaState OtaState; /* ** Iterator used to iterate through all data tables in the OTA. As follows: @@ -87,10 +88,17 @@ struct OtaIdxIter { sqlite3_stmt *pSelect; /* Select to read values in index order */ }; +struct OtaState { + char *zTbl; + char *zIdx; + sqlite3_int64 iRow; +}; + struct sqlite3ota { sqlite3 *dbDest; /* Target db */ sqlite3 *dbOta; /* Ota db */ + char *zTarget; /* Path to target db */ int rc; /* Value returned by last ota_step() call */ char *zErrmsg; /* Error message if rc!=SQLITE_OK */ @@ -506,133 +514,180 @@ static void otaOpenDatabase(sqlite3ota *p, sqlite3 **pDb, const char *zFile){ } static void otaSaveTransactionState(sqlite3ota *p){ - sqlite3_stmt *pStmt = 0; - void *pWalState = 0; - int nWalState = 0; - int rc; + sqlite3_stmt *pSelect; + char *zInsert; + + pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect); + zInsert = sqlite3_mprintf( + "INSERT OR REPLACE INTO ota_state(rowid, tbl, idx, row, progress)" + "VALUES(1, %Q, %Q, %lld, NULL)", + p->tbliter.zTarget, p->idxiter.zIndex, sqlite3_column_int64(pSelect, 0) + ); + if( zInsert==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + p->rc = sqlite3_exec(p->dbOta, zInsert, 0, 0, &p->zErrmsg); + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_exec(p->dbOta, "COMMIT", 0, 0, &p->zErrmsg); + } + } - const char *zInsert = - "INSERT INTO ota_state(wal_state, tbl, idx, row, progress)" - "VALUES(:wal_state, :tbl, :idx, :row, :progress)"; + sqlite3_free(zInsert); +} - rc = sqlite3_transaction_save(p->dbDest, &pWalState, &nWalState); - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(p->dbOta, "DELETE FROM ota_state", 0, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = prepareAndCollectError(p->dbOta, zInsert, &pStmt, &p->zErrmsg); - } +/* +** Allocate an OtaState object and load the contents of the ota_state +** table into it. Return a pointer to the new object. It is the +** responsibility of the caller to eventually free the object using +** sqlite3_free(). +** +** If an error occurs, leave an error code and message in the ota handle +** and return NULL. +*/ +static OtaState *otaLoadState(sqlite3ota *p){ + const char *zSelect = "SELECT tbl, idx, row, progress FROM ota_state"; + OtaState *pRet = 0; + sqlite3_stmt *pStmt; + int rc; + + assert( p->rc==SQLITE_OK ); + rc = prepareAndCollectError(p->dbOta, zSelect, &pStmt, &p->zErrmsg); if( rc==SQLITE_OK ){ - sqlite3_stmt *pSelect; - pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect); - sqlite3_bind_blob(pStmt, 1, pWalState, nWalState, SQLITE_STATIC); - sqlite3_bind_text(pStmt, 2, p->tbliter.zTarget, -1, SQLITE_STATIC); - if( p->idxiter.zIndex ){ - sqlite3_bind_text(pStmt, 3, p->idxiter.zIndex, -1, SQLITE_STATIC); + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zIdx = (const char*)sqlite3_column_text(pStmt, 1); + const char *zTbl = (const char*)sqlite3_column_text(pStmt, 0); + int nIdx = zIdx ? (strlen(zIdx) + 1) : 0; + int nTbl = strlen(zTbl) + 1; + int nByte = sizeof(OtaState) + nTbl + nIdx; + + pRet = (OtaState*)sqlite3_malloc(nByte); + if( pRet ){ + pRet->zTbl = (char*)&pRet[1]; + memcpy(pRet->zTbl, sqlite3_column_text(pStmt, 0), nTbl); + if( zIdx ){ + pRet->zIdx = &pRet->zTbl[nTbl]; + memcpy(pRet->zIdx, zIdx, nIdx); + }else{ + pRet->zIdx = 0; + } + pRet->iRow = sqlite3_column_int64(pStmt, 2); + } + }else{ + pRet = (OtaState*)sqlite3_malloc(sizeof(OtaState)); + if( pRet ){ + memset(pRet, 0, sizeof(*pRet)); + } } - sqlite3_bind_int64(pStmt, 4, sqlite3_column_int64(pSelect, 0)); - sqlite3_step(pStmt); rc = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(p->dbOta, "COMMIT", 0, 0, 0); - } + if( rc==SQLITE_OK && pRet==0 ) rc = SQLITE_NOMEM; if( rc!=SQLITE_OK ){ - p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->dbOta)); + sqlite3_free(pRet); + pRet = 0; } } - sqlite3_free(pWalState); - assert( p->rc==SQLITE_OK ); + p->rc = rc; + return pRet; } -static void otaLoadTransactionState(sqlite3ota *p){ - sqlite3_stmt *pStmt = 0; - int rc; - - const char *zSelect = - "SELECT wal_state, tbl, idx, row, progress FROM ota_state"; - - rc = prepareAndCollectError(p->dbOta, zSelect, &pStmt, &p->zErrmsg); - if( rc==SQLITE_OK ){ - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - const void *pWalState = 0; - int nWalState = 0; - const char *zTbl; - const char *zIdx; - sqlite3_int64 iRowid; - - pWalState = sqlite3_column_blob(pStmt, 0); - nWalState = sqlite3_column_bytes(pStmt, 0); - zTbl = (const char*)sqlite3_column_text(pStmt, 1); - zIdx = (const char*)sqlite3_column_text(pStmt, 2); - iRowid = sqlite3_column_int64(pStmt, 3); - rc = sqlite3_transaction_restore(p->dbDest, pWalState, nWalState); +static void otaLoadTransactionState(sqlite3ota *p, OtaState *pState){ + assert( p->rc==SQLITE_OK ); + if( pState->zTbl ){ + int rc; + while( rc==SQLITE_OK + && p->tbliter.zTarget + && sqlite3_stricmp(p->tbliter.zTarget, pState->zTbl) + ){ + rc = tblIterNext(&p->tbliter); + } + if( rc==SQLITE_OK && !p->tbliter.zTarget ){ + rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); + } + if( rc==SQLITE_OK && pState->zIdx ){ + rc = idxIterFirst(p->dbDest, p->tbliter.zTarget, &p->idxiter); while( rc==SQLITE_OK - && p->tbliter.zTarget - && sqlite3_stricmp(p->tbliter.zTarget, zTbl) - ){ - rc = tblIterNext(&p->tbliter); + && p->idxiter.zIndex + && sqlite3_stricmp(p->idxiter.zIndex, pState->zIdx) + ){ + rc = idxIterNext(&p->idxiter); } - if( rc==SQLITE_OK && !p->tbliter.zTarget ){ + if( rc==SQLITE_OK && !p->idxiter.zIndex ){ rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); } + } - if( rc==SQLITE_OK && zIdx ){ - rc = idxIterFirst(p->dbDest, p->tbliter.zTarget, &p->idxiter); - while( rc==SQLITE_OK - && p->idxiter.zIndex - && sqlite3_stricmp(p->idxiter.zIndex, zIdx) - ){ - rc = idxIterNext(&p->idxiter); - } - if( rc==SQLITE_OK && !p->idxiter.zIndex ){ - rc = SQLITE_ERROR; - p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); - } - } + if( rc==SQLITE_OK ){ + rc = otaPrepareAll(p); + } - if( rc==SQLITE_OK ){ - rc = otaPrepareAll(p); + if( rc==SQLITE_OK ){ + sqlite3_stmt *pSelect; + pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect); + while( sqlite3_column_int64(pSelect, 0)!=pState->iRow ){ + rc = sqlite3_step(pSelect); + if( rc!=SQLITE_ROW ) break; } - - if( rc==SQLITE_OK ){ - sqlite3_stmt *pSelect; - pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect); - while( sqlite3_column_int64(pSelect, 0)!=iRowid ){ - rc = sqlite3_step(pSelect); - if( rc!=SQLITE_ROW ) break; - } - if( rc==SQLITE_ROW ){ - rc = SQLITE_OK; - }else{ - rc = SQLITE_ERROR; - p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); - } + if( rc==SQLITE_ROW ){ + rc = SQLITE_OK; + }else{ + rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); } } - if( rc==SQLITE_OK ){ - rc = sqlite3_finalize(pStmt); - }else{ - sqlite3_finalize(pStmt); - } + p->rc = rc; } - p->rc = rc; } +/* +** Move the "*-oal" file corresponding to the target database to the +** "*-wal" location. If an error occurs, leave an error code and error +** message in the ota handle. +*/ +static void otaMoveOalFile(sqlite3ota *p){ + char *zWal = sqlite3_mprintf("%s-wal", p->zTarget); + char *zOal = sqlite3_mprintf("%s-oal", p->zTarget); + + assert( p->rc==SQLITE_DONE && p->zErrmsg==0 ); + if( zWal==0 || zOal==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + rename(zOal, zWal); + } + + sqlite3_free(zWal); + sqlite3_free(zOal); +} + +/* +** If there is a "*-oal" file in the file-system corresponding to the +** target database in the file-system, delete it. If an error occurs, +** leave an error code and error message in the ota handle. +*/ +static void otaDeleteOalFile(sqlite3ota *p){ + char *zOal = sqlite3_mprintf("%s-oal", p->zTarget); + assert( p->rc==SQLITE_OK && p->zErrmsg==0 ); + unlink(zOal); + sqlite3_free(zOal); +} /* ** Open and return a new OTA handle. */ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){ sqlite3ota *p; + int nTarget = strlen(zTarget); - p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)); + p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)+nTarget+1); if( p ){ + OtaState *pState = 0; /* Open the target database */ memset(p, 0, sizeof(sqlite3ota)); + p->zTarget = (char*)&p[1]; + memcpy(p->zTarget, zTarget, nTarget+1); otaOpenDatabase(p, &p->dbDest, zTarget); otaOpenDatabase(p, &p->dbOta, zOta); @@ -642,9 +697,18 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){ } if( p->rc==SQLITE_OK ){ - const char *zScript = + pState = otaLoadState(p); + if( pState && pState->zTbl==0 ){ + otaDeleteOalFile(p); + } + } + + + if( p->rc==SQLITE_OK ){ + const char *zScript = + "PRAGMA journal_mode=off;" + "PRAGMA pager_ota_mode=1;" "PRAGMA ota_mode=1;" - "PRAGMA journal_mode=wal;" "BEGIN IMMEDIATE;" ; p->rc = sqlite3_exec(p->dbDest, zScript, 0, 0, &p->zErrmsg); @@ -661,8 +725,10 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){ } if( p->rc==SQLITE_OK ){ - otaLoadTransactionState(p); + otaLoadTransactionState(p, pState); } + + sqlite3_free(pState); } return p; @@ -690,17 +756,20 @@ int sqlite3ota_close(sqlite3ota *p, char **pzErrmsg){ tblIterFinalize(&p->tbliter); idxIterFinalize(&p->idxiter); - /* If the ota update has been fully applied, commit the transaction - ** on the target database. */ - if( p->rc==SQLITE_DONE ){ + /* Commit the transaction to the *-oal file. */ + if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){ rc = sqlite3_exec(p->dbDest, "COMMIT", 0, 0, &p->zErrmsg); if( rc!=SQLITE_OK ) p->rc = rc; } + otaCloseHandle(p->dbDest); + otaCloseHandle(p->dbOta); + + if( p->rc==SQLITE_DONE ){ + otaMoveOalFile(p); + } rc = p->rc; *pzErrmsg = p->zErrmsg; - otaCloseHandle(p->dbDest); - otaCloseHandle(p->dbOta); sqlite3_free(p); }else{ rc = SQLITE_NOMEM; diff --git a/manifest b/manifest index ca224c9b1e..3329e4640b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\scommand\sline\sprogram\sthat\suses\sthe\sextension.\sThis\sserves\sas\sexample\scode\sand\sis\salso\suseful\sfor\sperformance\stesting. -D 2014-09-03T08:25:09.548 +C Split\spart\sof\s"PRAGMA\sota_mode"\soff\sinto\s"PRAGMA\spager_ota_mode".\sThis\sallows\ssome\sspecialized\scustom\sVFS\simplementations\sto\sintercept\sand\simplement\sthe\sexpected\spager-related\seffects\sof\sthis\spragma. +D 2014-09-03T19:30:32.283 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -123,8 +123,8 @@ F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/ota/ota.c 4b48add9494f29144343f513aaac226ca5782189 F ext/ota/ota1.test ea2865997ce573fadaf12eb0a0f80ef22d9dd77f -F ext/ota/ota2.test 4f7abfe1dfb7c3709bf45e94f3e65f3839b4f115 -F ext/ota/sqlite3ota.c ad55821883e4110367a30ffca282032d2bf36e45 +F ext/ota/ota2.test 13f76922446c62ed96192e938b8e625ebf0142fa +F ext/ota/sqlite3ota.c 3e05e3fa5791977eb88261731a6be6d98935efb3 F ext/ota/sqlite3ota.h 545f0008b5f02f2595899cb9841caddada5c17c0 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b @@ -173,7 +173,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c ec9d3f1295dafeb278c3830211cc5584132468f4 -F src/btree.c c46043fbb09c18a19bdb96eadde6e724901d6fcf +F src/btree.c 9cb1989073502a9d2f18fbb0e7df8ad89dda2dcf F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8 F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3 F src/build.c c26b233dcdb1e2c8f468d49236c266f9f3de96d8 @@ -216,13 +216,13 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c 8525ca79457c5b4673a5fda2774ee39fe155f40f F src/os_win.c 2aa8aa7780d7cf03e912d2088ab2ec5c32f33dc5 F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 -F src/pager.c a3caa08db8227c5a32f388be67f33d8cb44d5e35 -F src/pager.h 1acd367a0ffb63026b0461ea5eaeeb8046414a71 +F src/pager.c ed122b1346a40d6b53cec28fa63bf9af4a7dc8d7 +F src/pager.h 6a08df06b7edc3684375c0fab40602c695a044f2 F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 F src/pcache.c 3b3791297e8977002e56b4a9b8916f2039abad9b F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c c5af6403a55178c9d1c09e4f77b0f9c88822762c -F src/pragma.c d252459fb3ce19448d1a2f41000c780fac4c0c26 +F src/pragma.c e1b8049c059ccab0afc2a483ff2e0dd599fcb124 F src/prepare.c 314961aa6650cc860394cb2f31931cf2de93baa8 F src/printf.c 00986c86ddfffefc2fd3c73667ff51b3b9709c74 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece @@ -239,7 +239,7 @@ F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c 29357f2be7b0d00e8ea900eaf727e0c5ffeaa660 F src/test1.c e9a0e5804b078532e69e69ec14c8326bf2cfc318 -F src/test2.c 84f6a786aa7ffa12fff83acb52660e337ffe642a +F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df F src/test5.c 5a34feec76d9b3a86aab30fd4f6cc9c48cbab4c1 @@ -1163,7 +1163,7 @@ F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh 5dc5010e2e748a9e1bba67baca5956a2c2deda7b F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl cce51d8f60c7f145d8fccabe6b5dfdedf31c5f5c +F tool/mkpragmatab.tcl 22c85e67987ad7d2e8789c48506ec95b99a90c08 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 88a1e3b0c769773fb7a9ebb363ffc603a4ac21d8 F tool/mksqlite3c.tcl e72c0c97fe1a105fa9616483e652949be2199fe6 @@ -1198,7 +1198,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 2954ab501049968430011b63d046eb42ff37a56c -R 7bee98aca78bdb17f817d7637df95f18 +P ffa1524ef2a4c32652183eb4745685f0d1c93af2 +R 58c81bcc907452bbe01138bf831636b2 U dan -Z 3a37163be54ffa74ee7c4647ff1214ea +Z 0213bc6d6444959e54104d228d32668b diff --git a/manifest.uuid b/manifest.uuid index 7d509edecc..988b76f2dd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ffa1524ef2a4c32652183eb4745685f0d1c93af2 \ No newline at end of file +209f672e588b54dfbfb83c7859cacdc4497f0f2b \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index e9d737b6a0..5557b67b78 100644 --- a/src/btree.c +++ b/src/btree.c @@ -2046,7 +2046,7 @@ int sqlite3BtreeOpen( btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ - sqlite3PagerClose(pBt->pPager, 0); + sqlite3PagerClose(pBt->pPager); } sqlite3_free(pBt); sqlite3_free(p); @@ -2175,7 +2175,7 @@ int sqlite3BtreeClose(Btree *p){ ** Clean out and delete the BtShared object. */ assert( !pBt->pCursor ); - sqlite3PagerClose(pBt->pPager, (p->db->flags & SQLITE_OtaMode)!=0); + sqlite3PagerClose(pBt->pPager); if( pBt->xFreeSchema && pBt->pSchema ){ pBt->xFreeSchema(pBt->pSchema); } diff --git a/src/pager.c b/src/pager.c index a54ae816e3..9fc88b6930 100644 --- a/src/pager.c +++ b/src/pager.c @@ -630,6 +630,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 */ /************************************************************************** ** The following block contains those class members that change during @@ -824,6 +825,8 @@ static int pagerUseWal(Pager *pPager){ # define pagerBeginReadTransaction(z) SQLITE_OK #endif +static int pagerOpenWalInternal(Pager*, int*); + #ifndef NDEBUG /* ** Usage: @@ -2006,7 +2009,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } - if( !pPager->exclusiveMode + if( !pPager->exclusiveMode && !pPager->otaMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); @@ -3947,7 +3950,7 @@ static void pagerFreeMapHdrs(Pager *pPager){ ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ -int sqlite3PagerClose(Pager *pPager, int bOtaMode){ +int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; assert( assert_pager_state(pPager) ); @@ -3957,8 +3960,8 @@ int sqlite3PagerClose(Pager *pPager, int bOtaMode){ /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL - sqlite3WalClose( - pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, (bOtaMode?0:pTmp) + sqlite3WalClose(pPager->pWal, + pPager->ckptSyncFlags, pPager->pageSize, (pPager->otaMode?0:pTmp) ); pPager->pWal = 0; #endif @@ -5164,6 +5167,12 @@ int sqlite3PagerSharedLock(Pager *pPager){ ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); + if( rc==SQLITE_OK && pPager->otaMode ){ + int nWal = sqlite3Strlen30(pPager->zWal); + pPager->zWal[nWal-3] = 'o'; + rc = pagerOpenWalInternal(pPager, 0); + } + #ifndef SQLITE_OMIT_WAL assert( pPager->pWal==0 || rc==SQLITE_OK ); #endif @@ -7118,7 +7127,7 @@ static int pagerOpenWal(Pager *pPager){ */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, - pPager->fd, pPager->zWal, pPager->exclusiveMode, + pPager->fd, pPager->zWal, pPager->exclusiveMode || pPager->otaMode, pPager->journalSizeLimit, &pPager->pWal ); } @@ -7127,23 +7136,7 @@ static int pagerOpenWal(Pager *pPager){ return rc; } - -/* -** The caller must be holding a SHARED lock on the database file to call -** this function. -** -** If the pager passed as the first argument is open on a real database -** file (not a temp file or an in-memory database), and the WAL file -** is not already open, make an attempt to open it now. If successful, -** return SQLITE_OK. If an error occurs or the VFS used by the pager does -** not support the xShmXXX() methods, return an error code. *pbOpen is -** not modified in either case. -** -** If the pager is open on a temp-file (or in-memory database), or if -** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK -** without doing anything. -*/ -int sqlite3PagerOpenWal( +static int pagerOpenWalInternal( Pager *pPager, /* Pager object */ int *pbOpen /* OUT: Set to true if call is a no-op */ ){ @@ -7173,6 +7166,29 @@ int sqlite3PagerOpenWal( return rc; } +/* +** The caller must be holding a SHARED lock on the database file to call +** this function. +** +** If the pager passed as the first argument is open on a real database +** file (not a temp file or an in-memory database), and the WAL file +** is not already open, make an attempt to open it now. If successful, +** return SQLITE_OK. If an error occurs or the VFS used by the pager does +** not support the xShmXXX() methods, return an error code. *pbOpen is +** not modified in either case. +** +** If the pager is open on a temp-file (or in-memory database), or if +** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK +** without doing anything. +*/ +int sqlite3PagerOpenWal( + Pager *pPager, /* Pager object */ + int *pbOpen /* OUT: Set to true if call is a no-op */ +){ + if( pPager->otaMode ) return SQLITE_CANTOPEN; + return pagerOpenWalInternal(pPager, pbOpen); +} + /* ** This function is called to close the connection to the log file prior ** to switching from WAL to rollback mode. @@ -7270,4 +7286,15 @@ int sqlite3PagerWalFramesize(Pager *pPager){ } #endif +/* +** Set or clear the "OTA mode" flag. +*/ +int sqlite3PagerSetOtaMode(Pager *pPager, int bOta){ + if( pPager->pWal || pPager->eState!=PAGER_OPEN ){ + return SQLITE_ERROR; + } + pPager->otaMode = (u8)bOta; + return SQLITE_OK; +} + #endif /* SQLITE_OMIT_DISKIO */ diff --git a/src/pager.h b/src/pager.h index 79ffa04db8..fd2624c3fa 100644 --- a/src/pager.h +++ b/src/pager.h @@ -112,7 +112,7 @@ int sqlite3PagerOpen( int, void(*)(DbPage*) ); -int sqlite3PagerClose(Pager *pPager, int); +int sqlite3PagerClose(Pager *pPager); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ @@ -210,4 +210,6 @@ void *sqlite3PagerCodec(DbPage *); int sqlite3PagerSaveState(Pager *pPager, void **ppState, int *pnState); int sqlite3PagerRestoreState(Pager *pPager, const void *pState, int nState); +int sqlite3PagerSetOtaMode(Pager *pPager, int bOta); + #endif /* _PAGER_H_ */ diff --git a/src/pragma.c b/src/pragma.c index 3f06a51839..e65593c5ff 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -53,23 +53,24 @@ #define PragTyp_PAGE_COUNT 22 #define PragTyp_MMAP_SIZE 23 #define PragTyp_PAGE_SIZE 24 -#define PragTyp_SECURE_DELETE 25 -#define PragTyp_SHRINK_MEMORY 26 -#define PragTyp_SOFT_HEAP_LIMIT 27 -#define PragTyp_STATS 28 -#define PragTyp_SYNCHRONOUS 29 -#define PragTyp_TABLE_INFO 30 -#define PragTyp_TEMP_STORE 31 -#define PragTyp_TEMP_STORE_DIRECTORY 32 -#define PragTyp_THREADS 33 -#define PragTyp_WAL_AUTOCHECKPOINT 34 -#define PragTyp_WAL_CHECKPOINT 35 -#define PragTyp_ACTIVATE_EXTENSIONS 36 -#define PragTyp_HEXKEY 37 -#define PragTyp_KEY 38 -#define PragTyp_REKEY 39 -#define PragTyp_LOCK_STATUS 40 -#define PragTyp_PARSER_TRACE 41 +#define PragTyp_PAGER_OTA_MODE 25 +#define PragTyp_SECURE_DELETE 26 +#define PragTyp_SHRINK_MEMORY 27 +#define PragTyp_SOFT_HEAP_LIMIT 28 +#define PragTyp_STATS 29 +#define PragTyp_SYNCHRONOUS 30 +#define PragTyp_TABLE_INFO 31 +#define PragTyp_TEMP_STORE 32 +#define PragTyp_TEMP_STORE_DIRECTORY 33 +#define PragTyp_THREADS 34 +#define PragTyp_WAL_AUTOCHECKPOINT 35 +#define PragTyp_WAL_CHECKPOINT 36 +#define PragTyp_ACTIVATE_EXTENSIONS 37 +#define PragTyp_HEXKEY 38 +#define PragTyp_KEY 39 +#define PragTyp_REKEY 40 +#define PragTyp_LOCK_STATUS 41 +#define PragTyp_PARSER_TRACE 42 #define PragFlag_NeedSchema 0x01 static const struct sPragmaNames { const char *const zName; /* Name of pragma */ @@ -323,6 +324,10 @@ static const struct sPragmaNames { /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif + { /* zName: */ "pager_ota_mode", + /* ePragTyp: */ PragTyp_PAGER_OTA_MODE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, #if defined(SQLITE_DEBUG) { /* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_PARSER_TRACE, @@ -476,7 +481,8 @@ static const struct sPragmaNames { /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; -/* Number of pragmas: 57 on by default, 70 total. */ +/* Number of pragmas: 59 on by default, 72 total. */ +/* Number of pragmas: 58 on by default, 71 total. */ /* End of the automatically generated pragma table. ***************************************************************************/ @@ -870,6 +876,19 @@ void sqlite3Pragma( } #endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */ + /* + ** PRAGMA [database.]pager_ota_mode=[01] + */ + case PragTyp_PAGER_OTA_MODE: { + Btree *pBt = pDb->pBt; + assert( pBt!=0 ); + if( zRight ){ + int iArg = !!sqlite3Atoi(zRight); + rc = sqlite3PagerSetOtaMode(sqlite3BtreePager(pBt), iArg); + } + break; + } + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) /* ** PRAGMA [database.]page_size diff --git a/src/test2.c b/src/test2.c index 6d655d6473..58f271ff27 100644 --- a/src/test2.c +++ b/src/test2.c @@ -89,7 +89,7 @@ static int pager_close( return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); - rc = sqlite3PagerClose(pPager, 0); + rc = sqlite3PagerClose(pPager); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index aa7c8078c5..613b565553 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -296,6 +296,12 @@ set pragma_def { NAME: soft_heap_limit NAME: threads + + NAME: pager_ota_mode + + NAME: ota_mode + TYPE: FLAG + ARG: SQLITE_OtaMode } fconfigure stdout -translation lf set name {}