]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Have wal file checkpoints exit early if the sqlite3_interrupt() API function is called.
authordan <dan@noemail.net>
Fri, 12 Aug 2016 16:21:15 +0000 (16:21 +0000)
committerdan <dan@noemail.net>
Fri, 12 Aug 2016 16:21:15 +0000 (16:21 +0000)
FossilOrigin-Name: 8a5f41c7b1718507524adef1a2730e99cf53270a

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

index 3d5a0dd058042cb97ef890fab303813dba2e4df1..f170842c22560bc0e92aee993b96b7308538787a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\s"modeof=<filename>"\sURI\sparameter\sto\sos_unix.c\s-\sused\sto\sspecify\sa\sfile\sto\scopy\spermissions\sfrom\swhen\sa\snew\sdatabase\sis\screated.\sAlso\sallow\spassing\sNULL\sas\sthe\ssecond\sparameter\sto\ssqlite3rbu_vacuum().
-D 2016-08-11T18:05:47.763
+C Have\swal\sfile\scheckpoints\sexit\searly\sif\sthe\ssqlite3_interrupt()\sAPI\sfunction\sis\scalled.
+D 2016-08-12T16:21:15.202
 F Makefile.in cfd8fb987cd7a6af046daa87daa146d5aad0e088
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
@@ -328,7 +328,7 @@ F src/auth.c 5c8e0f37f785f935f589496801edd19840485853
 F src/backup.c 17cd25a36d49330df2bacd2cadf2a61f3b525976
 F src/bitvec.c 3ee4c8b2c94ed3a7377256e18199e6ff5cf33f63
 F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
-F src/btree.c 2551bd3ecb8b8988fb8b23aabadfb214dbc38e46
+F src/btree.c 7aa56fb3545b9b84199987ba26e6316ae1abd769
 F src/btree.h 075c45707c0f8f8af118f739f36df8098a08b7da
 F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
 F src/build.c 7c3c780b703c09314032c8f6e4e7c1d80241a818
@@ -349,7 +349,7 @@ F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
 F src/insert.c 8f4e9fcbd8e95e85f15647ba8b413b18d556ec2b
 F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
 F src/loadext.c dd7a2b77902cc66c22555aef02e1a682554b7aec
-F src/main.c 16c1b2114eae8804caf3a8de8cb47bf2c6d83ad3
+F src/main.c 52dad7971461bd1bdaa78c375016ebd883e11608
 F src/malloc.c 1443d1ad95d67c21d77af7ae3f44678252f0efec
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
@@ -371,8 +371,8 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
 F src/os_unix.c be9ca0f901a2b6c1bc93dc338f4863675180c189
 F src/os_win.c 520f23475f1de530c435d30b67b7b15fe90874b0
 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 40928c450320da78bb4bd3ae82818f4239e19b7e
-F src/pager.h 966d2769e76ae347c8a32c4165faf6e6cb64546d
+F src/pager.c 3d3ab7cb526615189750420e673d90689a9592a1
+F src/pager.h 0a19b1e212d0f5d0507f186ae1cca4e523d09d1a
 F src/parse.y 99b676e6fc2f4e331ab93e76b3987cffdbd28efa
 F src/pcache.c 5583c8ade4b05075a60ba953ef471d1c1a9c05df
 F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
@@ -395,7 +395,7 @@ F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
 F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
 F src/tclsqlite.c bdae822f21e229b6daced15938b6343ce44ef454
 F src/test1.c 0a0909cf7962d2359db329c08d15b90b4b6e724f
-F src/test2.c b7174313e993754303a8b33c43df7c44b46857ab
+F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
 F src/test3.c 1339a40be39650ae83894b6578f971dc7f96ea8a
 F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
 F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
@@ -450,7 +450,7 @@ F src/update.c 4f05ea8cddfa367d045e03589756c02199e8f9bd
 F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
 F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d
 F src/vacuum.c 9dd2f5d276bc6094d8f1d85ecd41b30c1a002a43
-F src/vdbe.c ea260b61e73b11a71e70b28a8e25866e2899e5da
+F src/vdbe.c 94c114b3cc72098ea783f04f7a21d7f6b3e1dc73
 F src/vdbe.h 67bc551f7faf04c33493892e4b378aada823ed10
 F src/vdbeInt.h c59381049af5c7751a83456c39b80d1a6fde1f9d
 F src/vdbeapi.c c3f6715a99995c11748ecad91d25e93fd9fc390b
@@ -461,8 +461,8 @@ F src/vdbesort.c 91fda3909326860382b0ca8aa251e609c6a9d62c
 F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
 F src/vtab.c 6b3cfaff7e4397739d6b48511e777ca58c6d06d4
 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a
-F src/wal.h 6dd221ed384afdc204bc61e25c23ef7fd5a511f2
+F src/wal.c 0b44e89742024d3b6992bf404d2ab692113e1e60
+F src/wal.h bf03a23da3100ab25e5c0363450233cfee09cfc2
 F src/walker.c 2d2cc7fb0f320f7f415215d7247f3c584141ac09
 F src/where.c 5c9df42d50888be8274a5a0eb062eb0629869bd3
 F src/whereInt.h e5b939701a7ceffc5a3a8188a37f9746416ebcd0
@@ -859,6 +859,7 @@ F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
 F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2
 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
 F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
+F test/interrupt2.test 829b06f9e20a6c378d8bd121b26c337f4dfa36e5
 F test/intpkey.test ac71107a49a06492b69b82aafaf225400598d3c8
 F test/io.test f95bca1783b01ea7761671560d023360d2dfa4cc
 F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d
@@ -1510,7 +1511,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P ab83d7077da80ddbcf399d0797d79e964dc64f0e
-R 753cf0ce0fc5b95ce832a2f13995ee3e
+P ed406d31ff54ee3de8db91690a966e5c561f8f94
+R fe020edefec096b26ead32b9e5eecd82
+T *branch * interruptible-checkpoint
+T *sym-interruptible-checkpoint *
+T -sym-trunk *
 U dan
-Z 87571942a0f33f54e925f9d7f08d0ded
+Z f50973b5d64203bd29a6b71f91836967
index 32f13a7c5d884ecd332d6215d34f2a7992ad938b..ee026b5b57e00edd0bea1b330037bacec775fa3b 100644 (file)
@@ -1 +1 @@
-ed406d31ff54ee3de8db91690a966e5c561f8f94
\ No newline at end of file
+8a5f41c7b1718507524adef1a2730e99cf53270a
\ No newline at end of file
index 841aee9463f5cecbfe7d7d6fba68377685f054e8..c25c594046dd5bef590f8389209b6079fe9a6f3e 100644 (file)
@@ -2392,7 +2392,7 @@ int sqlite3BtreeOpen(
 btree_open_out:
   if( rc!=SQLITE_OK ){
     if( pBt && pBt->pPager ){
-      sqlite3PagerClose(pBt->pPager);
+      sqlite3PagerClose(pBt->pPager, 0);
     }
     sqlite3_free(pBt);
     sqlite3_free(p);
@@ -2534,7 +2534,7 @@ int sqlite3BtreeClose(Btree *p){
     ** Clean out and delete the BtShared object.
     */
     assert( !pBt->pCursor );
-    sqlite3PagerClose(pBt->pPager);
+    sqlite3PagerClose(pBt->pPager, p->db);
     if( pBt->xFreeSchema && pBt->pSchema ){
       pBt->xFreeSchema(pBt->pSchema);
     }
@@ -9476,7 +9476,7 @@ int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){
     if( pBt->inTransaction!=TRANS_NONE ){
       rc = SQLITE_LOCKED;
     }else{
-      rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
+      rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt);
     }
     sqlite3BtreeLeave(p);
   }
index f31f8658187b312b0d556557cd53a949dbe97f8b..77808f497ffbe2fe68491990511ff22344d26af5 100644 (file)
@@ -2099,6 +2099,13 @@ int sqlite3_wal_checkpoint_v2(
     sqlite3Error(db, rc);
   }
   rc = sqlite3ApiExit(db, rc);
+
+  /* If there are no active statements, clear the interrupt flag at this
+  ** point.  */
+  if( db->nVdbeActive==0 ){
+    db->u1.isInterrupted = 0;
+  }
+
   sqlite3_mutex_leave(db->mutex);
   return rc;
 #endif
index cd8d1204b360c8d95e654fe9da7c8bf4be61401e..56c4329a1672fd6ea22f41d198d4afb87a626169 100644 (file)
@@ -4021,9 +4021,10 @@ 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 sqlite3PagerClose(Pager *pPager, sqlite3 *db){
   u8 *pTmp = (u8 *)pPager->pTmpSpace;
 
+  assert( db || pagerUseWal(pPager)==0 );
   assert( assert_pager_state(pPager) );
   disable_simulated_io_errors();
   sqlite3BeginBenignMalloc();
@@ -4031,7 +4032,7 @@ int sqlite3PagerClose(Pager *pPager){
   /* pPager->errCode = 0; */
   pPager->exclusiveMode = 0;
 #ifndef SQLITE_OMIT_WAL
-  sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
+  sqlite3WalClose(pPager->pWal,db,pPager->ckptSyncFlags,pPager->pageSize,pTmp);
   pPager->pWal = 0;
 #endif
   pager_reset(pPager);
@@ -7176,10 +7177,16 @@ void sqlite3PagerClearCache(Pager *pPager){
 **
 ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
 */
-int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
+int sqlite3PagerCheckpoint(
+  Pager *pPager,                  /* Checkpoint on this pager */
+  sqlite3 *db,                    /* Db handle used to check for interrupts */
+  int eMode,                      /* Type of checkpoint */
+  int *pnLog,                     /* OUT: Final number of frames in log */
+  int *pnCkpt                     /* OUT: Final number of checkpointed frames */
+){
   int rc = SQLITE_OK;
   if( pPager->pWal ){
-    rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
+    rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
         (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
         pPager->pBusyHandlerArg,
         pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
@@ -7311,7 +7318,7 @@ int sqlite3PagerOpenWal(
 ** error (SQLITE_BUSY) is returned and the log connection is not closed.
 ** If successful, the EXCLUSIVE lock is not released before returning.
 */
-int sqlite3PagerCloseWal(Pager *pPager){
+int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
   int rc = SQLITE_OK;
 
   assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
@@ -7339,7 +7346,7 @@ int sqlite3PagerCloseWal(Pager *pPager){
   if( rc==SQLITE_OK && pPager->pWal ){
     rc = pagerExclusiveLock(pPager);
     if( rc==SQLITE_OK ){
-      rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
+      rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags,
                            pPager->pageSize, (u8*)pPager->pTmpSpace);
       pPager->pWal = 0;
       pagerFixMaplimit(pPager);
index 1046670912de3dbef76eeb86901f123189f3b6a4..68f2c06cae61f5dbb32f6cc7c35e93d7af7d0472 100644 (file)
@@ -122,7 +122,7 @@ int sqlite3PagerOpen(
   int,
   void(*)(DbPage*)
 );
-int sqlite3PagerClose(Pager *pPager);
+int sqlite3PagerClose(Pager *pPager, sqlite3*);
 int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
 
 /* Functions used to configure a Pager object. */
@@ -173,11 +173,11 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
 int sqlite3PagerSharedLock(Pager *pPager);
 
 #ifndef SQLITE_OMIT_WAL
-  int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
+  int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
   int sqlite3PagerWalSupported(Pager *pPager);
   int sqlite3PagerWalCallback(Pager *pPager);
   int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
-  int sqlite3PagerCloseWal(Pager *pPager);
+  int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
 # ifdef SQLITE_ENABLE_SNAPSHOT
   int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
   int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
index dfca1d2b31deaceaf5831a40ea491f1a528f38fa..850e1e1a0448ef639178deb881528886bece8cc5 100644 (file)
@@ -93,7 +93,7 @@ static int SQLITE_TCLAPI pager_close(
     return TCL_ERROR;
   }
   pPager = sqlite3TestTextToPtr(argv[1]);
-  rc = sqlite3PagerClose(pPager);
+  rc = sqlite3PagerClose(pPager, 0);
   if( rc!=SQLITE_OK ){
     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
     return TCL_ERROR;
index 5d21ad064c23bf9965fc004fbec16a09491bc0b3..c7b0abf38c01c92fc356666ad80794e26df967f9 100644 (file)
@@ -6227,7 +6227,7 @@ case OP_JournalMode: {    /* out2 */
         ** file. An EXCLUSIVE lock may still be held on the database file 
         ** after a successful return. 
         */
-        rc = sqlite3PagerCloseWal(pPager);
+        rc = sqlite3PagerCloseWal(pPager, db);
         if( rc==SQLITE_OK ){
           sqlite3PagerSetJournalMode(pPager, eNew);
         }
index 235d383e1ae58658c785fcb801e33cc8848d2814..8da7639535e76e9fb884d7ff9a45df99598be6f1 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -1723,6 +1723,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
 */
 static int walCheckpoint(
   Wal *pWal,                      /* Wal connection */
+  sqlite3 *db,                    /* Check for interrupts on this handle */
   int eMode,                      /* One of PASSIVE, FULL or RESTART */
   int (*xBusy)(void*),            /* Function to call when busy */
   void *pBusyArg,                 /* Context argument for xBusyHandler */
@@ -1817,6 +1818,10 @@ static int walCheckpoint(
       while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
         i64 iOffset;
         assert( walFramePgno(pWal, iFrame)==iDbpage );
+        if( db->u1.isInterrupted ){
+          rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
+          break;
+        }
         if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
           continue;
         }
@@ -1921,6 +1926,7 @@ static void walLimitSize(Wal *pWal, i64 nMax){
 */
 int sqlite3WalClose(
   Wal *pWal,                      /* Wal to close */
+  sqlite3 *db,                    /* For interrupt flag */
   int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
   int nBuf,
   u8 *zBuf                        /* Buffer of at least nBuf bytes */
@@ -1942,8 +1948,8 @@ int sqlite3WalClose(
       if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
         pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
       }
-      rc = sqlite3WalCheckpoint(
-          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+      rc = sqlite3WalCheckpoint(pWal, db, 
+          SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
       );
       if( rc==SQLITE_OK ){
         int bPersist = -1;
@@ -3191,6 +3197,7 @@ int sqlite3WalFrames(
 */
 int sqlite3WalCheckpoint(
   Wal *pWal,                      /* Wal connection */
+  sqlite3 *db,                    /* Check this handle's interrupt flag */
   int eMode,                      /* PASSIVE, FULL, RESTART, or TRUNCATE */
   int (*xBusy)(void*),            /* Function to call when busy */
   void *pBusyArg,                 /* Context argument for xBusyHandler */
@@ -3265,7 +3272,7 @@ int sqlite3WalCheckpoint(
     if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
       rc = SQLITE_CORRUPT_BKPT;
     }else{
-      rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
+      rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
     }
 
     /* If no error occurred, set the output variables. */
index 6048e7985c54be7bb8fb8b42c2c19c0682f6cbb2..16d9d6e0d466760e761d60419d6cb3c8c6ea496b 100644 (file)
--- a/src/wal.h
+++ b/src/wal.h
@@ -28,7 +28,7 @@
 #ifdef SQLITE_OMIT_WAL
 # define sqlite3WalOpen(x,y,z)                   0
 # define sqlite3WalLimit(x,y)
-# define sqlite3WalClose(w,x,y,z)                0
+# define sqlite3WalClose(v,w,x,y,z)              0
 # define sqlite3WalBeginReadTransaction(y,z)     0
 # define sqlite3WalEndReadTransaction(z)
 # define sqlite3WalDbsize(y)                     0
@@ -38,7 +38,7 @@
 # define sqlite3WalSavepoint(y,z)
 # define sqlite3WalSavepointUndo(y,z)            0
 # define sqlite3WalFrames(u,v,w,x,y,z)           0
-# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
+# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0
 # define sqlite3WalCallback(z)                   0
 # define sqlite3WalExclusiveMode(y,z)            0
 # define sqlite3WalHeapMemory(z)                 0
@@ -56,7 +56,7 @@ typedef struct Wal Wal;
 
 /* Open and close a connection to a write-ahead log. */
 int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
-int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
+int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);
 
 /* Set the limiting size of a WAL file. */
 void sqlite3WalLimit(Wal*, i64);
@@ -99,6 +99,7 @@ int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
 /* Copy pages from the log to the database file */ 
 int sqlite3WalCheckpoint(
   Wal *pWal,                      /* Write-ahead log connection */
+  sqlite3 *db,                    /* Check this handle's interrupt flag */
   int eMode,                      /* One of PASSIVE, FULL and RESTART */
   int (*xBusy)(void*),            /* Function to call when busy */
   void *pBusyArg,                 /* Context argument for xBusyHandler */
diff --git a/test/interrupt2.test b/test/interrupt2.test
new file mode 100644 (file)
index 0000000..59ad7b3
--- /dev/null
@@ -0,0 +1,154 @@
+# 2016 Aug 12
+#
+# 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 script is using the sqlite_interrupt() API to 
+# interrupt WAL checkpoint operations.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/wal_common.tcl
+set testprefix interrupt2
+
+db close
+testvfs tvfs -default 1
+
+tvfs filter xWrite
+tvfs script write_cb
+
+set ::trigger_interrupt 0
+proc write_cb {method args} {
+  set filename [lindex $args 0]
+  if {[file tail $filename]=="test.db" && $::trigger_interrupt} {
+    if {$::trigger_interrupt} {
+      incr ::trigger_interrupt -1
+      if {$::trigger_interrupt==0} { sqlite3_interrupt db }
+    }
+  }
+  return 0
+}
+
+sqlite3 db test.db 
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a, b);
+  CREATE INDEX t1a ON t1(a);
+  CREATE INDEX t1b ON t1(b);
+  PRAGMA journal_mode = wal;
+
+  WITH ii(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM ii WHERE i<1000 )
+  INSERT INTO t1 SELECT i, i FROM ii;
+} {wal}
+
+foreach idelay {
+  5
+  10
+  15
+  20
+} {
+
+  set ::trigger_interrupt $idelay
+  do_catchsql_test 1.$idelay.1 { PRAGMA wal_checkpoint; } {1 interrupted}
+  do_execsql_test  1.$idelay.2 { SELECT count(*) FROM t1 } 1000
+
+  set ::trigger_interrupt $idelay
+  do_test 1.$idelay.3 { 
+    list [catch { sqlite3_wal_checkpoint_v2 db truncate } msg] $msg
+  } {1 {SQLITE_INTERRUPT - interrupted}}
+  do_execsql_test  1.$idelay.4 { SELECT count(*) FROM t1 } 1000
+}
+
+#-------------------------------------------------------------------------
+# Check that if there are other SQL statements running, a checkpoint does
+# not clear the isInterrupted flag.
+#
+do_execsql_test 2.0 {
+  CREATE TEMP TABLE z1(a, b);
+  INSERT INTO z1 SELECT * FROM t1;
+}
+
+do_test 2.1 {
+  set i 10
+  set res [list [catch {
+    set i 10
+    db eval {SELECT * FROM z1} {
+      incr i -1
+      if {$i==0} {
+        set ::trigger_interrupt 10
+        set cres [catch { sqlite3_wal_checkpoint_v2 db truncate } msg] 
+        lappend cres $msg
+      }
+    }
+  } msg] $msg]
+
+  list $cres $res
+} {{1 {SQLITE_INTERRUPT - interrupted}} {1 interrupted}}
+
+do_execsql_test 2.0 {
+  SELECT count(*) FROM t1
+  UNION ALL
+  SELECT count(*) FROM z1
+} {1000 1000}
+
+#-------------------------------------------------------------------------
+# Check the effect of an interrupt during sqlite3_close().
+#
+db_save_and_close
+
+db_restore_and_reopen
+do_test 3.1.1 {
+  set ::trigger_interrupt 10
+  db eval { SELECT * FROM sqlite_master }
+  db close
+  set {} {}
+} {}
+do_test 3.1.2 {
+  list [file exists test.db] [file exists test.db-wal]
+} {1 1}
+
+db_restore_and_reopen
+do_test 3.2.1 {
+  db eval { SELECT * FROM sqlite_master }
+  db close
+  set {} {}
+} {}
+do_test 3.2.2 {
+  list [file exists test.db] [file exists test.db-wal]
+} {1 0}
+
+#-------------------------------------------------------------------------
+# Check the effect of an interrupt during an automatic checkpoint
+#
+db_restore_and_reopen
+do_test 4.0 { 
+  execsql { PRAGMA wal_autocheckpoint = 10 }
+  set ::trigger_interrupt 10
+  execsql { CREATE TABLE t2(x, y) }
+} {}
+
+# The auto-checkpoint in test 4.0 should have been interrupted. So this
+# db write should cause the wal file to grow.
+do_test 4.1 {
+  set nFrame1 [wal_frame_count test.db-wal 1024]
+  execsql { CREATE TABLE t3(x, y) }
+  set nFrame2 [wal_frame_count test.db-wal 1024]
+  expr $nFrame2 > $nFrame1
+} {1}
+
+# The auto-checkpoint in test 4.0 should not have been interrupted. So 
+# this db write should not cause the wal file to grow.
+do_test 4.2 {
+  set nFrame1 [wal_frame_count test.db-wal 1024]
+  execsql { CREATE TABLE t4(x, y) }
+  set nFrame2 [wal_frame_count test.db-wal 1024]
+  expr $nFrame2 == $nFrame1
+} {1}
+
+finish_test