]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Split part of "PRAGMA ota_mode" off into "PRAGMA pager_ota_mode". This allows some...
authordan <dan@noemail.net>
Wed, 3 Sep 2014 19:30:32 +0000 (19:30 +0000)
committerdan <dan@noemail.net>
Wed, 3 Sep 2014 19:30:32 +0000 (19:30 +0000)
FossilOrigin-Name: 209f672e588b54dfbfb83c7859cacdc4497f0f2b

ext/ota/ota2.test
ext/ota/sqlite3ota.c
manifest
manifest.uuid
src/btree.c
src/pager.c
src/pager.h
src/pragma.c
src/test2.c
tool/mkpragmatab.tcl

index dfa4a48e9d090d5aa4b1c2714206b2ea3f3b7083..d80f7360c9b59680b629cb012b56114d0f98927f 100644 (file)
@@ -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
 
index 5483b9049f5624a6a2cbac92c8079d264692d8b4..2f61c671ac0e0e901db7bdb0393a7ce07c499d9c 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <assert.h>
 #include <string.h>
+#include <stdio.h>
+#include <unistd.h>
 
 #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).
 **                  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;
index ca224c9b1ef3ee3ce13f9c2d3491db7b04b08bc7..3329e4640bb8611ac76cbec61ed5260c3421a1d0 100644 (file)
--- 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
index 7d509edecc2227a958fb083485422e1c389e2aa9..988b76f2ddb98ceddaf4fb68210a28ca4d4a5180 100644 (file)
@@ -1 +1 @@
-ffa1524ef2a4c32652183eb4745685f0d1c93af2
\ No newline at end of file
+209f672e588b54dfbfb83c7859cacdc4497f0f2b
\ No newline at end of file
index e9d737b6a0a68175721c4a3f19dcefb77223db2f..5557b67b78c1f197b4c963378aedc8f6eb870a52 100644 (file)
@@ -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);
     }
index a54ae816e39ad823f08b93b0814cc43d6da63eb9..9fc88b69303231c19896541414a8fcc2a6563bcd 100644 (file)
@@ -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 */
index 79ffa04db8f9201ef93e034547085772f3687a1a..fd2624c3facaa15c721ec09c54ab9c2a1c896b79 100644 (file)
@@ -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_ */
index 3f06a51839fdc352064da6e57b8e84aa4c162941..e65593c5ff8648f108815ee7a43a63fabad0e5be 100644 (file)
 #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
index 6d655d6473a6e9542b363a4af5c66d6df79eba76..58f271ff27ad8fef64522f416fd53367db663072 100644 (file)
@@ -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;
index aa7c8078c556446a10dea6e8a5a39d4781329681..613b565553707e0a3993d5310eb5f930748e66a3 100644 (file)
@@ -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 {}