]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Clarify the effects of the pager_ota_mode pragma. Add tests and fixes for the same.
authordan <dan@noemail.net>
Tue, 16 Sep 2014 20:02:41 +0000 (20:02 +0000)
committerdan <dan@noemail.net>
Tue, 16 Sep 2014 20:02:41 +0000 (20:02 +0000)
FossilOrigin-Name: decaccc37cbdcd2a663233469efdf4982a810513

ext/ota/ota4.test [new file with mode: 0644]
manifest
manifest.uuid
src/pager.c
src/pager.h
src/pragma.c
src/wal.c
src/wal.h

diff --git a/ext/ota/ota4.test b/ext/ota/ota4.test
new file mode 100644 (file)
index 0000000..d0c9dfa
--- /dev/null
@@ -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
index 7898dc2ecf69aab681f0a8a8edcc28834f51b69d..bcb8678d885fdcb62083dee22d08341934cac474 100644 (file)
--- a/manifest
+++ b/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
index 282b6874b8855e7aa6625ce3c0f90534f5bd6938..fa8e1e694fc79b9881dec45fc999b0148dd09c8f 100644 (file)
@@ -1 +1 @@
-48d201cd8b68c0377cf8a2cc6439b893f9462fe2
\ No newline at end of file
+decaccc37cbdcd2a663233469efdf4982a810513
\ No newline at end of file
index 7de6a655503ff0484358e1036cef2fd4a8309f2b..967f776f0907d3301f8768642877ffb36b800216 100644 (file)
@@ -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;
 }
 
index 57948079d2e785ea9ebc6b8bc2035b419719a1c6..0e928fe64c91f5fe66830c60b813136234e6ce3f 100644 (file)
@@ -208,5 +208,6 @@ void *sqlite3PagerCodec(DbPage *);
 #endif
 
 int sqlite3PagerSetOtaMode(Pager *pPager, int bOta);
+void sqlite3PagerWalSalt(Pager *pPager, u32 *aSalt);
 
 #endif /* _PAGER_H_ */
index 9785a33c266ce3468286d860047e8c95cf43fb40..ee990022743cf583751753764a96252c29b74a9c 100644 (file)
@@ -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;
   }
index aa797dfb53cd02bb46e3542412c83c9749cec107..c7ad2bcb2c88a3f0aec5994a0920ccada9332300 100644 (file)
--- a/src/wal.c
+++ b/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
index 092546354b34c0ab3d20056a7f8a8a52e4d0b5f5..1c6f27d8f05ec364d1c90e1abce21121f1f2d64d 100644 (file)
--- a/src/wal.h
+++ b/src/wal.h
@@ -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).