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
#include <assert.h>
#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
#include "sqlite3.h"
#include "sqlite3ota.h"
** 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).
** 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:
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 */
}
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);
}
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);
}
if( p->rc==SQLITE_OK ){
- otaLoadTransactionState(p);
+ otaLoadTransactionState(p, pState);
}
+
+ sqlite3_free(pState);
}
return p;
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;
-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
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
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
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
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
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
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
-ffa1524ef2a4c32652183eb4745685f0d1c93af2
\ No newline at end of file
+209f672e588b54dfbfb83c7859cacdc4497f0f2b
\ No newline at end of file
btree_open_out:
if( rc!=SQLITE_OK ){
if( pBt && pBt->pPager ){
- sqlite3PagerClose(pBt->pPager, 0);
+ sqlite3PagerClose(pBt->pPager);
}
sqlite3_free(pBt);
sqlite3_free(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);
}
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
# define pagerBeginReadTransaction(z) SQLITE_OK
#endif
+static int pagerOpenWalInternal(Pager*, int*);
+
#ifndef NDEBUG
/*
** Usage:
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);
** 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) );
/* 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
** 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
*/
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
);
}
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 */
){
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.
}
#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 */
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. */
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_ */
#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 */
/* 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,
/* 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.
***************************************************************************/
}
#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
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;
NAME: soft_heap_limit
NAME: threads
+
+ NAME: pager_ota_mode
+
+ NAME: ota_mode
+ TYPE: FLAG
+ ARG: SQLITE_OtaMode
}
fconfigure stdout -translation lf
set name {}