]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Use the read and write version fields of the database header to mark a database as...
authordan <dan@noemail.net>
Tue, 20 Apr 2010 18:53:15 +0000 (18:53 +0000)
committerdan <dan@noemail.net>
Tue, 20 Apr 2010 18:53:15 +0000 (18:53 +0000)
FossilOrigin-Name: 96bef18c1411c3e0348295886f105e1646c46320

manifest
manifest.uuid
src/btree.c
src/btree.h
src/pager.c
src/pager.h
src/pragma.c
src/vdbe.c
test/wal.test
test/walmode.test [new file with mode: 0644]

index a4e1d8ff29cabe142f3e0b654c24442e476f3d4f..f648a1e9770ac998ef940140b1e0e333796c32a7 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\ssqlite3_log_hook()\sinterface\sfor\sscheduling\scheckpoints.
-D 2010-04-19T18:03:52
+C Use\sthe\sread\sand\swrite\sversion\sfields\sof\sthe\sdatabase\sheader\sto\smark\sa\sdatabase\sas\soperating\sin\swal-mode.
+D 2010-04-20T18:53:15
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -109,8 +109,8 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c e86634da8c48357a759694c9c7c471125cd8d5a8
 F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0
 F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
-F src/btree.c 01559397cbd4a5aa62a822e8ca9ac94b6db14743
-F src/btree.h ad6cff92286f9b02ec32f0b97136e9a544249f37
+F src/btree.c 013cf019484e309e909a667654612b38a02dc2b6
+F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
 F src/btreeInt.h 22447d259639271774a931cbf66aa55112846681
 F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7
 F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
@@ -154,13 +154,13 @@ F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
 F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
 F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1
 F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
-F src/pager.c f9ad51dfa617131240ae77545c0083118324fc81
-F src/pager.h aeaee9ceb4a4a6d15c2163ef4e11a7590fd54b59
+F src/pager.c 1dcf76bead8f1b51809bd8189ef9b02f2c94dc7f
+F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
 F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
 F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
 F src/pcache1.c 6dc1871ce8ead9187161c370a58cd06c84221f76
-F src/pragma.c f12cb58a8aa0d80cfed282ef87a285ed71beb793
+F src/pragma.c bae3ce82ca6d0ac5d3ca3e46b286856d1f0ddd70
 F src/prepare.c fd1398cb1da54385ba5bd68d93928f10d10a1d9c
 F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
@@ -214,7 +214,7 @@ F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
 F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
 F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee
-F src/vdbe.c 2e2aaa765de667dd15e0462cf853efd1b2f97998
+F src/vdbe.c 304851b32c5f918a7ce92e4e9f94fbde0b604b21
 F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
 F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
 F src/vdbeapi.c 466044df5bc916f778833e927165fd02cdef6086
@@ -758,9 +758,10 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
-F test/wal.test a56ff378f58b145fd3bf38c277fbfe792cd47bdd
+F test/wal.test 273c0006e75c99cb34d0659851e7103fd4748c20
 F test/walcrash.test 45cfbab30bb7cbe0b2e9d5cabe90dbcad10cb89b
 F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47
+F test/walmode.test cd6ee20f08af2d81fddc049f8d7e387a807f067e
 F test/walslow.test 38076d5fad49e3678027be0f8110e6a32d531dc2
 F test/walthread.test 27e44ee6fd02f1f494a24f999c97086af3ab739d
 F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
@@ -806,7 +807,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 9d51c3b754f0b94fea5ef3d669ad583b93b2b024
-R 8eb45c9f56fe0d743248bffdfb606bc1
+P 9bda601455705475075e33bfa85687bce34b15ff
+R b30f3db6dd942a33d471d74ec2e33c70
 U dan
-Z e82f118f370901abf724c6ac84b89351
+Z d82da3172ce11d2f9fc95cc996cdb180
index aa29f9aa71165e6476074d70ed747082a3564b01..8af34827b8ce1fe8cff5eed6ceb35717c5fe90c6 100644 (file)
@@ -1 +1 @@
-9bda601455705475075e33bfa85687bce34b15ff
\ No newline at end of file
+96bef18c1411c3e0348295886f105e1646c46320
\ No newline at end of file
index c8810543a17ccc9d6673f03dacec8d317215d960..069c2d0327e9e0d827e8f67684800185f1f5e20a 100644 (file)
@@ -2261,13 +2261,25 @@ static int lockBtree(BtShared *pBt){
     if( memcmp(page1, zMagicHeader, 16)!=0 ){
       goto page1_init_failed;
     }
-    if( page1[18]>1 ){
+    if( page1[18]>2 ){
       pBt->readOnly = 1;
     }
-    if( page1[19]>1 ){
+    if( page1[19]>2 ){
       goto page1_init_failed;
     }
 
+    /* If the write version is set to 2, turn on write-ahead logging mode. */
+    if( page1[19]==2 ){
+      int isOpen = 0;
+      rc = sqlite3PagerOpenLog(pBt->pPager, &isOpen);
+      if( rc!=SQLITE_OK ){
+        goto page1_init_failed;
+      }else if( isOpen==0 ){
+        releasePage(pPage1);
+        return SQLITE_OK;
+      }
+    }
+
     /* The maximum embedded fraction must be exactly 25%.  And the minimum
     ** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
     ** The original design allowed these amounts to vary, but as of
@@ -7963,3 +7975,26 @@ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
   pCur->isIncrblobHandle = 1;
 }
 #endif
+
+/*
+** Set both the "read version" (single byte at byte offset 18) and 
+** "write version" (single byte at byte offset 19) fields in the database
+** header to iVersion.
+*/
+int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
+  BtShared *pBt = pBtree->pBt;
+  int rc;                         /* Return code */
+  assert( pBtree->inTrans==TRANS_WRITE );
+  assert( pBt->pPage1 );
+  assert( iVersion==1 || iVersion==2 );
+
+  rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+  if( rc==SQLITE_OK ){
+    u8 *aData = pBt->pPage1->aData;
+    aData[18] = (u8)iVersion;
+    aData[19] = (u8)iVersion;
+  }
+
+  return rc;
+}
index aba06c965eccdf7fef7de43be4fa37261162c888..584b463384559c289965e85329087cf72c598ada 100644 (file)
@@ -186,6 +186,8 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
 void sqlite3BtreeCacheOverflow(BtCursor *);
 void sqlite3BtreeClearCursor(BtCursor *);
 
+int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
+
 #ifndef NDEBUG
 int sqlite3BtreeCursorIsValid(BtCursor*);
 #endif
index d46350afd254d18a762136831d5f6ec2bf28a4ea..9d1fd0479c5a99ef6720e7a1f24bd9701f3c4b08 100644 (file)
@@ -1405,9 +1405,11 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
       /* This branch may be executed with Pager.journalMode==MEMORY if
       ** a hot-journal was just rolled back. In this case the journal
       ** file should be closed and deleted. If this connection writes to
-      ** the database file, it will do so using an in-memory journal.  */
+      ** the database file, it will do so using an in-memory journal. 
+      */
       assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE 
            || pPager->journalMode==PAGER_JOURNALMODE_MEMORY 
+           || pPager->journalMode==PAGER_JOURNALMODE_WAL 
       );
       sqlite3OsClose(pPager->jfd);
       if( !pPager->tempFile ){
@@ -3724,54 +3726,6 @@ static int hasHotJournal(Pager *pPager, int *pExists){
   return rc;
 }
 
-/*
-** Open a connection to the write-ahead log file for pager pPager. If
-** the log connection is already open, this function is a no-op.
-*/
-static int pagerOpenLog(Pager *pPager){
-  if( !pPager->pLog ){
-    int rc;                       /* Return code */
-
-    /* Before opening the log file, obtain a SHARED lock on the database
-    ** file. This lock will not be released until after the log file
-    ** connection has been closed. The purpose of this lock is to stop
-    ** any other process from unlinking the log or log-summary files while
-    ** this connection still has them open. An EXCLUSIVE lock on the
-    ** database file is required to unlink either of those two files.
-    */
-    assert( pPager->state==PAGER_UNLOCK );
-    rc = pager_wait_on_lock(pPager, SHARED_LOCK);
-    if( rc!=SQLITE_OK ){
-      assert( pPager->state==PAGER_UNLOCK );
-      return pager_error(pPager, rc);
-    }
-    assert( pPager->state>=SHARED_LOCK );
-
-    /* Open the connection to the log file. If this operation fails, 
-    ** (e.g. due to malloc() failure), unlock the database file and 
-    ** return an error code.
-    */
-    rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
-    if( rc!=SQLITE_OK ){
-      osUnlock(pPager->fd, SQLITE_LOCK_NONE);
-      pPager->state = PAGER_UNLOCK;
-      return rc;
-    }
-  }else{
-    /* If the log file was already open, check that the pager is still holding
-    ** the required SHARED lock on the database file. 
-    */
-#ifdef SQLITE_DEBUG
-    int locktype;
-    sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
-    assert( locktype==SQLITE_LOCK_SHARED );
-#endif
-    pPager->state = PAGER_SHARED;
-  }
-
-  return SQLITE_OK;
-}
-
 
 /*
 ** This function is called to obtain a shared lock on the database file.
@@ -3826,16 +3780,9 @@ int sqlite3PagerSharedLock(Pager *pPager){
     pager_reset(pPager);
   }
 
-
-  if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
+  if( pagerUseLog(pPager) ){
     int changed = 0;              /* True if the cache must be flushed */
 
-    /* Open the log file, if it is not already open. */
-    rc = pagerOpenLog(pPager);
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
-
     /* Open a log snapshot to read from. */
     rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed);
     if( rc==SQLITE_OK ){
@@ -3846,6 +3793,8 @@ int sqlite3PagerSharedLock(Pager *pPager){
       }
       rc = sqlite3PagerPagecount(pPager, &dummy);
     }
+    pPager->state = PAGER_SHARED;
+
   }else if( pPager->state==PAGER_UNLOCK || isErrorReset ){
     sqlite3_vfs * const pVfs = pPager->pVfs;
     int isHotJournal = 0;
@@ -4002,6 +3951,10 @@ int sqlite3PagerSharedLock(Pager *pPager){
       }
     }
     assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED );
+
+    if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
+      pPager->journalMode = PAGER_JOURNALMODE_DELETE;
+    }
   }
 
  failed:
@@ -4384,6 +4337,7 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
       if( rc==SQLITE_OK ){
         pPager->dbOrigSize = pPager->dbSize;
         pPager->state = PAGER_RESERVED;
+        pPager->journalOff = 0;
       }
     }else{
       /* Obtain a RESERVED lock on the database file. If the exFlag parameter
@@ -4485,7 +4439,7 @@ static int pager_write(PgHdr *pPg){
     }
     if( !isOpen(pPager->jfd) 
      && pPager->journalMode!=PAGER_JOURNALMODE_OFF 
-     && pPager->journalMode!=PAGER_JOURNALMODE_WAL 
+     && !pagerUseLog(pPager)
     ){
       assert( pPager->useJournal );
       rc = pager_open_journal(pPager);
@@ -5621,7 +5575,7 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){
 **    PAGER_JOURNALMODE_WAL
 **
 ** If the parameter is not _QUERY, then the journal_mode is set to the
-** value specified if the change is allowed.  The change is disallowed
+** value specified if the change is allowed. The change may be disallowed
 ** for the following reasons:
 **
 **   *  An in-memory database can only have its journal_mode set to _OFF
@@ -5640,7 +5594,12 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
             || eMode==PAGER_JOURNALMODE_WAL 
             || eMode==PAGER_JOURNALMODE_MEMORY );
   assert( PAGER_JOURNALMODE_QUERY<0 );
-  if( eMode>=0
+
+  if( eMode==PAGER_JOURNALMODE_WAL 
+   && pPager->journalMode==PAGER_JOURNALMODE_DELETE
+  ){
+    pPager->journalMode = PAGER_JOURNALMODE_WAL;
+  }else if( eMode>=0
    && (pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL)
    && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY||eMode==PAGER_JOURNALMODE_OFF)
    && !pPager->dbModified
@@ -5659,13 +5618,6 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
       sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
     }
 
-    /* Switching into WAL mode can only take place when no 
-    ** locks are held on the database file. 
-    */
-    if( eMode==PAGER_JOURNALMODE_WAL && pPager->state!=PAGER_UNLOCK ){
-      return (int)pPager->journalMode;
-    }
-
     pPager->journalMode = (u8)eMode;
   }
   return (int)pPager->journalMode;
@@ -5713,4 +5665,77 @@ int sqlite3PagerLogCallback(Pager *pPager){
   return sqlite3LogCallback(pPager->pLog);
 }
 
+/*
+** Open a connection to the write-ahead log file for pager pPager. If
+** the log connection is already open, this function is a no-op.
+**
+** The caller must be holding a SHARED lock on the database file to call
+** this function.
+*/
+int sqlite3PagerOpenLog(Pager *pPager, int *pisOpen){
+  int rc = SQLITE_OK;             /* Return code */
+
+#ifdef SQLITE_DEBUG
+  int locktype;
+  sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
+  assert( locktype==SQLITE_LOCK_SHARED );
+  assert( pPager->state>=PAGER_SHARED );
+#endif
+
+  if( !pPager->pLog ){
+
+    /* Open the connection to the log file. If this operation fails, 
+    ** (e.g. due to malloc() failure), unlock the database file and 
+    ** return an error code.
+    */
+    rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
+    if( rc==SQLITE_OK ){
+      pPager->journalMode = PAGER_JOURNALMODE_WAL;
+    }
+  }else{
+    *pisOpen = 1;
+  }
+
+  return rc;
+}
+
+
+/*
+** This function is called to close the connection to the log file prior
+** to switching from WAL to rollback mode.
+**
+** Before closing the log file, this function attempts to take an 
+** EXCLUSIVE lock on the database file. If this cannot be obtained, an
+** error (SQLITE_BUSY) is returned and the log connection is not closed.
+** If successful, the EXCLUSIVE lock is not released before returning.
+*/
+int sqlite3PagerCloseLog(Pager *pPager){
+  int rc = SQLITE_OK;
+  if( pPager->pLog ){
+
+    /* Try to obtain an EXCLUSIVE lock on the database file. */
+    rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+
+    /* If the EXCLUSIVE lock was obtained, checkpoint and close the log. */
+    if( rc==SQLITE_OK ){
+      rc = sqlite3LogClose(pPager->pLog, pPager->fd,
+        (pPager->noSync ? 0 : pPager->sync_flags), 
+        (u8*)pPager->pTmpSpace
+      );
+      pPager->pLog = 0;
+    }
+
+    /* Make sure the EXCLUSIVE lock has not been lost somehow */
+#ifdef SQLITE_DEBUG
+    {
+      int locktype;
+      sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
+      assert( locktype==SQLITE_LOCK_EXCLUSIVE );
+    }
+#endif
+
+  }
+  return rc;
+}
+
 #endif /* SQLITE_OMIT_DISKIO */
index 17d61a500f1004bd8ba4966b0122835230e12ae5..7b760c9b1a8ff59acec482d761fe7c2268a57151 100644 (file)
@@ -136,6 +136,8 @@ int sqlite3PagerSharedLock(Pager *pPager);
 
 int sqlite3PagerCheckpoint(Pager *pPager);
 int sqlite3PagerLogCallback(Pager *pPager);
+int sqlite3PagerOpenLog(Pager *pPager, int *pisOpen);
+int sqlite3PagerCloseLog(Pager *pPager);
 
 /* Functions used to query pager state and configuration. */
 u8 sqlite3PagerIsreadonly(Pager*);
index 137ff510d98e9c9d0d9a72d033c9261a0a20f4bd..1dfc90d2b6ac4d617de068f1726d0c01c60b2368 100644 (file)
@@ -257,6 +257,28 @@ static const char *actionName(u8 action){
 }
 #endif
 
+
+/*
+** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
+** defined in pager.h. This function returns the associated lowercase
+** journal-mode name.
+*/
+const char *sqlite3JournalModename(int eMode){
+  static char * const azModeName[] = {
+    "delete", "persist", "off", "truncate", "memory", "wal"
+  };
+  assert( PAGER_JOURNALMODE_DELETE==0 );
+  assert( PAGER_JOURNALMODE_PERSIST==1 );
+  assert( PAGER_JOURNALMODE_OFF==2 );
+  assert( PAGER_JOURNALMODE_TRUNCATE==3 );
+  assert( PAGER_JOURNALMODE_MEMORY==4 );
+  assert( PAGER_JOURNALMODE_WAL==5 );
+  assert( eMode>=0 && eMode<=ArraySize(azModeName) );
+
+  if( eMode==ArraySize(azModeName) ) return 0;
+  return azModeName[eMode];
+}
+
 /*
 ** Process a pragma statement.  
 **
@@ -513,18 +535,21 @@ void sqlite3Pragma(
   **  PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory)
   */
   if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
-    int eMode;
-    static char * const azModeName[] = {
-      "delete", "persist", "off", "truncate", "memory", "wal"
-    };
+    int eMode;                    /* One of the PAGER_JOURNALMODE_XXX symbols */
+
+    sqlite3VdbeSetNumCols(v, 1);
+    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
 
     if( zRight==0 ){
       eMode = PAGER_JOURNALMODE_QUERY;
     }else{
+      const char *zMode;
       int n = sqlite3Strlen30(zRight);
-      eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1;
-      while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){
-        eMode--;
+      for(eMode=0; (zMode = sqlite3JournalModename(eMode)); eMode++){
+        if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
+      }
+      if( !zMode ){
+        eMode = PAGER_JOURNALMODE_QUERY;
       }
     }
     if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
@@ -533,40 +558,32 @@ void sqlite3Pragma(
       ** the journal-mode of the main database).
       */
       eMode = db->dfltJournalMode;
+      sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
+      sqlite3VdbeChangeP4(v, -1, sqlite3JournalModename(eMode), P4_STATIC);
     }else{
-      Pager *pPager;
-      if( pId2->n==0 ){
+      int ii;
+
+      if( pId2->n==0 && eMode!=PAGER_JOURNALMODE_WAL ){
         /* This indicates that no database name was specified as part
         ** of the PRAGMA command. In this case the journal-mode must be
         ** set on all attached databases, as well as the main db file.
         **
         ** Also, the sqlite3.dfltJournalMode variable is set so that
         ** any subsequently attached databases also use the specified
-        ** journal mode.
+        ** journal mode. Except, the default journal mode is never set
+        ** to WAL.
         */
-        int ii;
-        assert(pDb==&db->aDb[0]);
-        for(ii=1; ii<db->nDb; ii++){
-          if( db->aDb[ii].pBt ){
-            pPager = sqlite3BtreePager(db->aDb[ii].pBt);
-            sqlite3PagerJournalMode(pPager, eMode);
-          }
-        }
         db->dfltJournalMode = (u8)eMode;
       }
-      pPager = sqlite3BtreePager(pDb->pBt);
-      eMode = sqlite3PagerJournalMode(pPager, eMode);
+
+      for(ii=db->nDb-1; ii>=0; ii--){
+        if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
+          sqlite3VdbeUsesBtree(v, ii);
+          sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
+        }
+      }
     }
-    assert( eMode==PAGER_JOURNALMODE_DELETE
-              || eMode==PAGER_JOURNALMODE_TRUNCATE
-              || eMode==PAGER_JOURNALMODE_PERSIST
-              || eMode==PAGER_JOURNALMODE_OFF
-              || eMode==PAGER_JOURNALMODE_WAL
-              || eMode==PAGER_JOURNALMODE_MEMORY );
-    sqlite3VdbeSetNumCols(v, 1);
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, 
-           azModeName[eMode], P4_STATIC);
+
     sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
   }else
 
index 42562cee095bbf32ece5b9c9f4e1ad0c8610bec0..cc53c9bff1eb5f0e106250ed2a184d950e4ed0db 100644 (file)
@@ -5187,6 +5187,9 @@ case OP_AggFinal: {
 }
 
 /* Opcode: Checkpoint P1 * * * *
+**
+** Checkpoint database P1. This is a no-op if P1 is not currently in
+** WAL mode.
 */
 case OP_Checkpoint: {
   Btree *pBt;                     /* Btree to checkpoint */
@@ -5198,6 +5201,84 @@ case OP_Checkpoint: {
   break;
 };  
 
+/* Opcode: JournalMode P1 P2 P3 * *
+**
+** Change the journal mode of database P1 to P3. P3 must be one of the
+** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
+** modes (delete, truncate, persist, off and memory), this is a simple
+** operation. No IO is required.
+**
+** If changing into or out of WAL mode the procedure is more complicated.
+**
+** Write a string containing the final journal-mode to register P2.
+*/
+case OP_JournalMode: {
+  Btree *pBt;                     /* Btree to change journal mode of */
+  Pager *pPager;                  /* Pager associated with pBt */
+  int eNew = pOp->p3;             /* New journal mode */
+
+  assert( eNew==PAGER_JOURNALMODE_DELETE 
+       || eNew==PAGER_JOURNALMODE_TRUNCATE 
+       || eNew==PAGER_JOURNALMODE_PERSIST 
+       || eNew==PAGER_JOURNALMODE_OFF
+       || eNew==PAGER_JOURNALMODE_MEMORY
+       || eNew==PAGER_JOURNALMODE_WAL
+       || eNew==PAGER_JOURNALMODE_QUERY
+  );
+  assert( pOp->p1>=0 && pOp->p1<db->nDb );
+  assert( (p->btreeMask & (1<<pOp->p1))!=0 );
+
+  pBt = db->aDb[pOp->p1].pBt;
+  pPager = sqlite3BtreePager(pBt);
+
+  if( eNew!=PAGER_JOURNALMODE_QUERY ){
+    int eOld = sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_QUERY);
+    if( (eNew!=eOld)
+     && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL)
+    ){
+      if( !db->autoCommit || db->activeVdbeCnt>1 ){
+        rc = SQLITE_ERROR;
+        sqlite3SetString(&p->zErrMsg, db, 
+            "cannot change %s wal mode from within a transaction",
+            (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
+        );
+      }else{
+  
+        /* If leaving WAL mode, close the log file. If successful, the call to
+        ** PagerCloseLog() checkpoints and deletes the write-ahead-log file.
+        ** An EXCLUSIVE lock is still held on the database file after returning.
+        */
+        if( eOld==PAGER_JOURNALMODE_WAL ){
+          rc = sqlite3PagerCloseLog(pPager);
+          if( rc!=SQLITE_OK ) goto abort_due_to_error;
+          sqlite3PagerJournalMode(pPager, eNew);
+        }else{
+          sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
+        }
+  
+        /* Open a transaction on the database file. Regardless of the journal
+        ** mode, this transaction always uses a rollback journal.
+        */
+        assert( sqlite3BtreeIsInTrans(pBt)==0 );
+        rc = sqlite3BtreeBeginTrans(pBt, 2);
+        assert( rc==SQLITE_OK || eOld!=PAGER_JOURNALMODE_WAL );
+        if( rc!=SQLITE_OK ) goto abort_due_to_error;
+        rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
+        if( rc!=SQLITE_OK ) goto abort_due_to_error;
+      }
+    }
+  }
+
+  eNew = sqlite3PagerJournalMode(pPager, eNew);
+  pOut = &aMem[pOp->p2];
+  pOut->flags = MEM_Str|MEM_Static|MEM_Term;
+  pOut->z = sqlite3JournalModename(eNew);
+  pOut->n = sqlite3Strlen30(pOut->z);
+  pOut->enc = SQLITE_UTF8;
+  sqlite3VdbeChangeEncoding(pOut, encoding);
+  break;
+};  
+
 #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
 /* Opcode: Vacuum * * * * *
 **
index fb21d820f96aa9b99b61a939a99cace2b65d0d3e..bb538b120f153081648cafdfd7df5f3926edb31b 100644 (file)
@@ -31,6 +31,7 @@ proc blob {nByte} {
 
 proc sqlite3_wal {args} {
   eval sqlite3 $args
+  [lindex $args 0] eval { PRAGMA page_size = 1024 }
   [lindex $args 0] eval { PRAGMA journal_mode = wal }
   [lindex $args 0] eval { PRAGMA synchronous = normal }
   [lindex $args 0] function blob blob
@@ -60,14 +61,19 @@ do_test wal-0.1 {
   execsql { PRAGMA synchronous = normal }
   execsql { PRAGMA journal_mode = wal }
 } {wal}
+do_test wal-0.2 {
+  file size test.db
+} {1024}
 
 do_test wal-1.0 {
   execsql { 
     BEGIN;
     CREATE TABLE t1(a, b); 
   }
-  list [file exists test.db-journal] [file exists test.db-wal]
-} {0 1}
+  list [file exists test.db-journal] \
+       [file exists test.db-wal]     \
+       [file size test.db]
+} {0 1 1024}
 do_test wal-1.1 {
   execsql COMMIT
   list [file exists test.db-journal] [file exists test.db-wal]
@@ -197,9 +203,10 @@ foreach sector {512 4096} {
   foreach pgsz {512 1024 2048 4096} {
     file delete -force test.db test.db-wal
     do_test wal-6.$sector.$pgsz.1 {
-      sqlite3_wal db test.db -vfs devsym
+      sqlite3 db test.db -vfs devsym
       execsql "
-        PRAGMA page_size = $pgsz ;
+        PRAGMA page_size = $pgsz;
+        PRAGMA journal_mode = wal;
       "
       execsql "
         CREATE TABLE t1(a, b);
@@ -224,7 +231,7 @@ do_test wal-7.1 {
     INSERT INTO t1 VALUES(1, 2);
   }
   list [file size test.db] [file size test.db-wal]
-} [list 0 [log_file_size 3 1024]]
+} [list 1024 [log_file_size 3 1024]]
 do_test wal-7.2 {
   execsql { PRAGMA checkpoint }
   list [file size test.db] [file size test.db-wal]
@@ -235,11 +242,17 @@ do_test wal-7.2 {
 #
 do_test wal-8.1 {
   reopen_db
+  catch { db close }
+  file delete -force test.db test.db-wal
+
+  sqlite3 db test.db
+  db function blob blob
   execsql {
     PRAGMA auto_vacuum = 1;
+    PRAGMA journal_mode = wal;
     PRAGMA auto_vacuum;
   }
-} {1}
+} {wal 1}
 do_test wal-8.2 {
   execsql {
     PRAGMA page_size = 1024;
@@ -269,7 +282,6 @@ do_test wal-8.3 {
 do_test wal-9.1 {
   reopen_db
   execsql {
-    PRAGMA page_size = 1024;
     CREATE TABLE t1(x PRIMARY KEY);
     INSERT INTO t1 VALUES(blob(900));
     INSERT INTO t1 VALUES(blob(900));
@@ -282,7 +294,7 @@ do_test wal-9.1 {
     INSERT INTO t1 SELECT blob(900) FROM t1;       /* 256 */
   }
   file size test.db
-} 0
+} 1024
 do_test wal-9.2 {
   sqlite3_wal db2 test.db
   execsql {PRAGMA integrity_check } db2
@@ -560,7 +572,7 @@ do_test wal-11.1 {
     CREATE TABLE t1(x PRIMARY KEY);
   }
   list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
-} {0 3}
+} {1 3}
 do_test wal-11.2 {
   execsql { PRAGMA checkpoint }
   list [expr [file size test.db]/1024] [file size test.db-wal]
@@ -613,7 +625,7 @@ do_test wal-11.10 {
       SELECT count(*) FROM t1;
   }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 37 [log_file_size 35 1024]]
+} [list 37 [log_file_size 37 1024]]
 do_test wal-11.11 {
   execsql {
       SELECT count(*) FROM t1;
@@ -623,7 +635,7 @@ do_test wal-11.11 {
 } {32 16}
 do_test wal-11.12 {
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 37 [log_file_size 35 1024]]
+} [list 37 [log_file_size 37 1024]]
 do_test wal-11.13 {
   execsql {
     INSERT INTO t1 VALUES( blob(900) );
@@ -633,7 +645,7 @@ do_test wal-11.13 {
 } {17 ok}
 do_test wal-11.14 {
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 37 [log_file_size 35 1024]]
+} [list 37 [log_file_size 37 1024]]
 
 
 #-------------------------------------------------------------------------
@@ -650,11 +662,12 @@ do_test wal-12.1 {
     INSERT INTO t1 VALUES('A', 1);
   }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 0 [log_file_size 5 1024]]
+} [list 1 [log_file_size 5 1024]]
 do_test wal-12.2 {
   db close
-  sqlite3_wal db test.db
+  sqlite3 db test.db
   execsql {
+    PRAGMA synchronous = normal;
     UPDATE t1 SET y = 0 WHERE x = 'A';
   }
   list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
@@ -668,7 +681,6 @@ do_test wal-12.4 {
   file copy -force test.db test2.db
   file copy -force test.db-wal test2.db-wal
   sqlite3_wal db2 test2.db
-breakpoint
   execsql { SELECT * FROM t2 } db2
 } {B 1}
 db2 close
@@ -695,6 +707,5 @@ do_test wal-12.4 {
 } {B 2}
 db2 close
 
-
 finish_test
 
diff --git a/test/walmode.test b/test/walmode.test
new file mode 100644 (file)
index 0000000..1a3af3a
--- /dev/null
@@ -0,0 +1,25 @@
+# 2010 April 19
+#
+# 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.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing the operation of the library in
+# "PRAGMA journal_mode=WAL" mode.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_test walmode-1.1 {
+  execsql {
+    PRAGMA journal_mode = wal;
+  }
+} {wal}
+
+finish_test