]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change blocking-checkpoint tests so that they run once using "PRAGMA wal_checkpoint...
authordan <dan@noemail.net>
Mon, 7 Feb 2011 15:12:12 +0000 (15:12 +0000)
committerdan <dan@noemail.net>
Mon, 7 Feb 2011 15:12:12 +0000 (15:12 +0000)
FossilOrigin-Name: 5a4b6652cf3780ffed6fe0fe669e8090b0b71e81

manifest
manifest.uuid
src/main.c
src/test1.c
src/wal.c
test/superlock.test
test/wal5.test

index 89e3b7b07a1e5400126e95f61420515005dd1bc2..727f42e1854ce8afeb5c0208609e257ca6603f6f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Ensure\sfts4aux\scan\shandle\sa\stable\sname\sin\ssingle\sor\sdouble\squotes\sas\sa\sconstructor\sargument.
-D 2011-02-05T15:47:12.471
+C Change\sblocking-checkpoint\stests\sso\sthat\sthey\srun\sonce\susing\s"PRAGMA\swal_checkpoint"\sand\sonce\susing\scalls\sto\ssqlite3_wal_checkpoint_v2().\sAlso\sfix\sedge\scases\ssurrounding\sthe\soutput\svariables\sset\sby\swal_checkpoint_v2().
+D 2011-02-07T15:12:12.557
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in de6498556d536ae60bb8bb10e8c1ba011448658c
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -142,7 +142,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
 F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
 F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
 F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e
-F src/main.c 1b04ef67eb03d026c8cc2d438c61635163153c24
+F src/main.c bc1c822dafa9a6c6c43179c0cbd3f1ce686a84c6
 F src/malloc.c 92d59a007d7a42857d4e9454aa25b6b703286be1
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
@@ -184,7 +184,7 @@ F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
 F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c 549859dc2c143f3deb6a92636a2d27973652c164
-F src/test1.c 771407a49ae199241f0efb7055634e4a1899c026
+F src/test1.c ddbfff546e22e5c31204c973fdd805a4eda3e208
 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
 F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
@@ -238,7 +238,7 @@ F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c
 F src/vdbemem.c c011228c6fb1b5df924e4584765b16bde863c9c6
 F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
 F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
-F src/wal.c 8704a563b37c0c48b6a65d49da5d5656568abfc6
+F src/wal.c aca10a60655e103fc8630a75345000f43c6d47ca
 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
 F src/where.c f4915ac03e5e42c8416b35ca3ba34af841c00d12
@@ -662,7 +662,7 @@ F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
 F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
 F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
-F test/superlock.test f66a8f26dcd390c115bb732a2ea4638ab8204b13
+F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
 F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
 F test/table.test 04ba066432430657712d167ebf28080fe878d305
 F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516
@@ -845,7 +845,7 @@ F test/wal.test f060cae4b2164c4375109a8f803873187234661d
 F test/wal2.test 57a218446654ed3e3592c925762633c1d1e85636
 F test/wal3.test ec87d9dd9e9cebabed4024064e8ff531d336ead2
 F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
-F test/wal5.test 1f99651d856c8b9e1376781c981d1b903e93a478
+F test/wal5.test 3fef990d256cd9e95e9ad97e5dfdf3f150743fce
 F test/wal6.test 07aa31ca8892d0527f2c5c5a9a2a87aa421dfaa8
 F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
 F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
@@ -906,7 +906,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P dc511e60a65232a7087e12ff40b63506cf37a634
-R 8b6bef7500d37a03d9cad23f74319954
+P 929d62e496bb36a3ee0e19ec4609329d79aaeddc
+R 5272b64137511ea0a87063bfd04f9af5
 U dan
-Z 659706e533fac6825c1f6da67c2f77f1
+Z 8b5f17a482d9dd489ee7270bd10b0d2b
index fa38ef0c73d398ee0b39d469062e6fd4d65e0df5..d9e6c00cd0b2f338eeef78b4782535bc7045744e 100644 (file)
@@ -1 +1 @@
-929d62e496bb36a3ee0e19ec4609329d79aaeddc
\ No newline at end of file
+5a4b6652cf3780ffed6fe0fe669e8090b0b71e81
\ No newline at end of file
index 9f7d4b1fdf9628bf45c44ff3314e8160a85b7dbf..b202ac9e56367adab1598af90caa691e55052081 100644 (file)
@@ -1356,6 +1356,10 @@ int sqlite3_wal_checkpoint_v2(
   int rc;                         /* Return code */
   int iDb = SQLITE_MAX_ATTACHED;  /* sqlite3.aDb[] index of db to checkpoint */
 
+  /* Initialize the output variables to -1 in case an error occurs. */
+  if( pnLog ) *pnLog = -1;
+  if( pnCkpt ) *pnCkpt = -1;
+
   if( eMode!=SQLITE_CHECKPOINT_PASSIVE
    && eMode!=SQLITE_CHECKPOINT_FULL
    && eMode!=SQLITE_CHECKPOINT_RESTART
@@ -1416,6 +1420,8 @@ int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
   int bBusy = 0;                  /* True if SQLITE_BUSY has been encountered */
 
   assert( sqlite3_mutex_held(db->mutex) );
+  assert( !pnLog || *pnLog==-1 );
+  assert( !pnCkpt || *pnCkpt==-1 );
 
   for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
     if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
index cf7e06b9c77738ccbab1690891d9fe075437cb25..7f09b292945489cd59f62efef2d934622d26323f 100644 (file)
@@ -5186,6 +5186,73 @@ static int test_wal_checkpoint(
   return TCL_OK;
 }
 
+/*
+** tclcmd:  sqlite3_wal_checkpoint_v2 db MODE ?NAME?
+**
+** This command calls the wal_checkpoint_v2() function with the specified
+** mode argument (passive, full or restart). If present, the database name
+** NAME is passed as the second argument to wal_checkpoint_v2(). If it the
+** NAME argument is not present, a NULL pointer is passed instead.
+**
+** If wal_checkpoint_v2() returns any value other than SQLITE_BUSY or
+** SQLITE_OK, then this command returns TCL_ERROR. The Tcl result is set
+** to the error message obtained from sqlite3_errmsg().
+**
+** Otherwise, this command returns a list of three integers. The first integer
+** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers
+** are the values returned via the output paramaters by wal_checkpoint_v2() -
+** the number of frames in the log and the number of frames in the log
+** that have been checkpointed.
+*/
+static int test_wal_checkpoint_v2(
+  ClientData clientData, /* Unused */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  char *zDb = 0;
+  sqlite3 *db;
+  int rc;
+
+  int eMode;
+  int nLog = -555;
+  int nCkpt = -555;
+  Tcl_Obj *pRet;
+
+  const char * aMode[] = { "passive", "full", "restart", 0 };
+  assert( SQLITE_CHECKPOINT_PASSIVE==0 );
+  assert( SQLITE_CHECKPOINT_FULL==1 );
+  assert( SQLITE_CHECKPOINT_RESTART==2 );
+
+  if( objc!=3 && objc!=4 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "DB MODE ?NAME?");
+    return TCL_ERROR;
+  }
+
+  if( objc==4 ){
+    zDb = Tcl_GetString(objv[3]);
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
+   || Tcl_GetIndexFromObj(interp, objv[2], aMode, "mode", 0, &eMode) 
+  ){
+    return TCL_ERROR;
+  }
+
+  rc = sqlite3_wal_checkpoint_v2(db, zDb, eMode, &nLog, &nCkpt);
+  if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+    Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
+    return TCL_ERROR;
+  }
+
+  pRet = Tcl_NewObj();
+  Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(rc==SQLITE_BUSY?1:0));
+  Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nLog));
+  Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCkpt));
+  Tcl_SetObjResult(interp, pRet);
+
+  return TCL_OK;
+}
+
 /*
 ** tclcmd:  test_sqlite3_log ?SCRIPT?
 */
@@ -5572,6 +5639,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "sqlite3_unlock_notify", test_unlock_notify, 0  },
 #endif
      { "sqlite3_wal_checkpoint",   test_wal_checkpoint, 0  },
+     { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0  },
      { "test_sqlite3_log",         test_sqlite3_log, 0  },
      { "print_explain_query_plan", test_print_eqp, 0  },
   };
index 64c966da976da1ab5622b8223e53474c897bf981..34fb6cbbcd6e9e29c5c71913a43feecdfe896585 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -1623,8 +1623,7 @@ static int walCheckpoint(
   int (*xBusyCall)(void*),        /* Function to call when busy */
   void *pBusyArg,                 /* Context argument for xBusyHandler */
   int sync_flags,                 /* Flags for OsSync() (or 0) */
-  u8 *zBuf,                       /* Temporary buffer to use */
-  int *pnCkpt                     /* Total frames checkpointed */
+  u8 *zBuf                        /* Temporary buffer to use */
 ){
   int rc;                         /* Return code */
   int szPage;                     /* Database page-size */
@@ -1641,7 +1640,6 @@ static int walCheckpoint(
   testcase( szPage<=32768 );
   testcase( szPage>=65536 );
   pInfo = walCkptInfo(pWal);
-  if( pnCkpt ) *pnCkpt = pInfo->nBackfill;
   if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
 
   /* Allocate the iterator */
@@ -1727,7 +1725,6 @@ static int walCheckpoint(
       }
       if( rc==SQLITE_OK ){
         pInfo->nBackfill = mxSafeFrame;
-        if( pnCkpt ) *pnCkpt = mxSafeFrame;
       }
     }
 
@@ -2764,12 +2761,17 @@ int sqlite3WalCheckpoint(
   }
 
   /* Copy data from the log to the database file. */
-  if( rc==SQLITE_OK && pWal->hdr.mxFrame ){
-    if( walPagesize(pWal)!=nBuf ){
+  if( rc==SQLITE_OK ){
+    if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
       rc = SQLITE_CORRUPT_BKPT;
     }else{
+      rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
+    }
+
+    /* If no error occurred, set the output variables. */
+    if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
       if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
-      rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags,zBuf,pnCkpt);
+      if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
     }
   }
 
index 01188203d73bb104ac21f0655b624e321553fb3c..b12863f7ffd0a8361f4ce357566e79b4b3571383 100644 (file)
@@ -220,7 +220,7 @@ db_swap test.db2 test.db
 do_catchsql_test 6.4 { SELECT * FROM t1 } {0 {1 2 3 4}}
 do_catchsql_test 6.5 { SELECT * FROM t2 } {1 {no such table: t2}}
 
-do_execsql_test  6.6 { PRAGMA wal_checkpoint } {0 -1 -1}
+do_execsql_test  6.6 { PRAGMA wal_checkpoint } {0 0 0}
 
 db_swap test.db2 test.db
 do_catchsql_test 6.7 { SELECT * FROM t1 } {1 {no such table: t1}}
index 2ea48057959d0fad59f5dfdcc107e784cc235298..d571dae0d1edd5cd69a9f8fb049be2388c51ad1f 100644 (file)
@@ -25,235 +25,316 @@ proc db_page_count  {{file test.db}} { expr [file size $file] / 1024 }
 proc wal_page_count {{file test.db}} { wal_frame_count ${file}-wal 1024 }
 
 
-do_multiclient_test tn {
+# A checkpoint may be requested either using the C API or by executing
+# an SQL PRAGMA command. To test both methods, all tests in this file are 
+# run twice - once using each method to request checkpoints.
+#
+foreach {testprefix do_wal_checkpoint} {
 
+  wal5-pragma {
+    proc do_wal_checkpoint { dbhandle args } {
+      array set a $args
+      foreach key [array names a] {
+        if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" }
+      }
 
-  set ::nBusyHandler 0
-  set ::busy_handler_script ""
-  proc busyhandler {n} {
-    incr ::nBusyHandler 
-    eval $::busy_handler_script
-    return 0
-  }
+      set sql "PRAGMA "
+      if {[info exists a(-db)]} { append sql "$a(-db)." }
+      append sql "wal_checkpoint"
+      if {[info exists a(-mode)]} { append sql " = $a(-mode)" }
 
-  proc reopen_all {} {
-    code1 {db close}
-    code2 {db2 close}
-    code3 {db3 close}
-    code1 {sqlite3 db test.db}
-    code2 {sqlite3 db2 test.db}
-    code3 {sqlite3 db3 test.db}
-    sql1  { PRAGMA synchronous = NORMAL }
-    code1 { db busy busyhandler }
+      uplevel [list $dbhandle eval $sql]
+    }
   }
 
-  do_test 1.$tn.1 {
-    reopen_all
-    sql1 {
-      PRAGMA page_size = 1024;
-      PRAGMA auto_vacuum = 0;
-      CREATE TABLE t1(x, y);
-      PRAGMA journal_mode = WAL;
-      INSERT INTO t1 VALUES(1, zeroblob(1200));
-      INSERT INTO t1 VALUES(2, zeroblob(1200));
-      INSERT INTO t1 VALUES(3, zeroblob(1200));
+  wal5-capi {
+    proc do_wal_checkpoint { dbhandle args } {
+      set a(-mode) passive
+      array set a $args
+      foreach key [array names a] {
+        if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" }
+      }
+
+      if {$a(-mode)!="restart" && $a(-mode)!="full"} { set a(-mode) passive }
+
+      set cmd [list sqlite3_wal_checkpoint_v2 $dbhandle $a(-mode)]
+      if {[info exists a(-db)]} { lappend sql $a(-db) }
+
+      uplevel $cmd
     }
-    expr [file size test.db] / 1024
-  } {2}
-
-  # Have connection 2 grab a read-lock on the current snapshot.
-  do_test 1.$tn.2 { sql2 { BEGIN; SELECT x FROM t1 } } {1 2 3}
-
-  # Attempt a checkpoint.
-  do_test 1.$tn.3 {
-    sql1 { PRAGMA wal_checkpoint }
-    list [db_page_count] [wal_page_count]
-  } {5 9}
-
-  # Write to the db again. The log cannot wrap because of the lock still
-  # held by connection 2. The busy-handler has not yet been invoked.
-  do_test 1.$tn.4 {
-    sql1 { INSERT INTO t1 VALUES(4, zeroblob(1200)) }
-    list [db_page_count] [wal_page_count] $::nBusyHandler
-  } {5 12 0}
-
-  # Now do a blocking-checkpoint. Set the busy-handler up so that connection
-  # 2 releases its lock on the 6th invocation. The checkpointer should then
-  # proceed to checkpoint the entire log file. Next write should go to the 
-  # start of the log file.
-  #
-  set ::busy_handler_script { if {$n==5} { sql2 COMMIT } }
-  do_test 1.$tn.5 {
-    sql1 { PRAGMA wal_checkpoint = RESTART }
-    list [db_page_count] [wal_page_count] $::nBusyHandler
-  } {6 12 6}
-  do_test 1.$tn.6 {
-    set ::nBusyHandler 0
-    sql1 { INSERT INTO t1 VALUES(5, zeroblob(1200)) }
-    list [db_page_count] [wal_page_count] $::nBusyHandler
-  } {6 12 0}
-
-  do_test 1.$tn.7 {
-    reopen_all
-    list [db_page_count] [wal_page_count] $::nBusyHandler
-  } {7 0 0}
-
-  do_test 1.$tn.8  { sql2 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5}
-  do_test 1.$tn.9  {
-    sql1 { INSERT INTO t1 VALUES(6, zeroblob(1200)) }
-    list [db_page_count] [wal_page_count] $::nBusyHandler
-  } {7 5 0}
-  do_test 1.$tn.10 { sql3 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5 6}
-
-  set ::busy_handler_script { 
-    if {$n==5} { sql2 COMMIT } 
-    if {$n==6} { set ::db_file_size [db_page_count] }
-    if {$n==7} { sql3 COMMIT }
   }
-  do_test 1.$tn.11 {
-    sql1 { PRAGMA wal_checkpoint = RESTART }
-    list [db_page_count] [wal_page_count] $::nBusyHandler
-  } {10 5 8}
-  do_test 1.$tn.12 { set ::db_file_size } 10
-}
+} {
 
+  eval $do_wal_checkpoint
 
-#-------------------------------------------------------------------------
-# This block of tests explores checkpoint operations on more than one 
-# database file.
-#
-proc setup_and_attach_aux {} {
-  sql1 { ATTACH 'test.db2' AS aux }
-  sql2 { ATTACH 'test.db2' AS aux }
-  sql3 { ATTACH 'test.db2' AS aux }
-  sql1 {
-    PRAGMA main.page_size=1024; PRAGMA main.journal_mode=WAL;
-    PRAGMA aux.page_size=1024;  PRAGMA aux.journal_mode=WAL;
-  }
-}
+  do_multiclient_test tn {
 
-proc file_page_counts {} {
-  list [db_page_count  test.db ] \
-       [wal_page_count test.db ] \
-       [db_page_count  test.db2] \
-       [wal_page_count test.db2]
-}
+    set ::nBusyHandler 0
+    set ::busy_handler_script ""
+    proc busyhandler {n} {
+      incr ::nBusyHandler 
+      eval $::busy_handler_script
+      return 0
+    }
 
-# Test that executing "PRAGMA wal_checkpoint" checkpoints all attached
-# databases, not just the main db.
-#
-do_multiclient_test tn {
-  setup_and_attach_aux
-  do_test 2.1.$tn.1 {
-    sql1 {
-      CREATE TABLE t1(a, b);
-      INSERT INTO t1 VALUES(1, 2);
-      CREATE TABLE aux.t2(a, b);
-      INSERT INTO t2 VALUES(1, 2);
+    proc reopen_all {} {
+      code1 {db close}
+      code2 {db2 close}
+      code3 {db3 close}
+
+      code1 {sqlite3 db test.db}
+      code2 {sqlite3 db2 test.db}
+      code3 {sqlite3 db3 test.db}
+
+      sql1  { PRAGMA synchronous = NORMAL }
+      code1 { db busy busyhandler }
     }
-  } {}
-  do_test 2.2.$tn.2 { file_page_counts } {1 5 1 5}
-  do_test 2.1.$tn.3 { sql1 { PRAGMA wal_checkpoint } } {0 5 5}
-  do_test 2.1.$tn.4 { file_page_counts } {2 5 2 5}
-}
 
-do_multiclient_test tn {
-  setup_and_attach_aux
-  do_test 2.2.$tn.1 {
-    execsql {
-      CREATE TABLE t1(a, b);
-      INSERT INTO t1 VALUES(1, 2);
-      CREATE TABLE aux.t2(a, b);
-      INSERT INTO t2 VALUES(1, 2);
-      INSERT INTO t2 VALUES(3, 4);
+    do_test 1.$tn.1 {
+      reopen_all
+      sql1 {
+        PRAGMA page_size = 1024;
+        PRAGMA auto_vacuum = 0;
+        CREATE TABLE t1(x, y);
+        PRAGMA journal_mode = WAL;
+        INSERT INTO t1 VALUES(1, zeroblob(1200));
+        INSERT INTO t1 VALUES(2, zeroblob(1200));
+        INSERT INTO t1 VALUES(3, zeroblob(1200));
+      }
+      expr [file size test.db] / 1024
+    } {2}
+
+    # Have connection 2 grab a read-lock on the current snapshot.
+    do_test 1.$tn.2 { sql2 { BEGIN; SELECT x FROM t1 } } {1 2 3}
+
+    # Attempt a checkpoint.
+    do_test 1.$tn.3 {
+      code1 { do_wal_checkpoint db }
+      list [db_page_count] [wal_page_count]
+    } {5 9}
+
+    # Write to the db again. The log cannot wrap because of the lock still
+    # held by connection 2. The busy-handler has not yet been invoked.
+    do_test 1.$tn.4 {
+      sql1 { INSERT INTO t1 VALUES(4, zeroblob(1200)) }
+      list [db_page_count] [wal_page_count] $::nBusyHandler
+    } {5 12 0}
+
+    # Now do a blocking-checkpoint. Set the busy-handler up so that connection
+    # 2 releases its lock on the 6th invocation. The checkpointer should then
+    # proceed to checkpoint the entire log file. Next write should go to the 
+    # start of the log file.
+    #
+    set ::busy_handler_script { if {$n==5} { sql2 COMMIT } }
+    do_test 1.$tn.5 {
+      code1 { do_wal_checkpoint db -mode restart }
+      list [db_page_count] [wal_page_count] $::nBusyHandler
+    } {6 12 6}
+    do_test 1.$tn.6 {
+      set ::nBusyHandler 0
+      sql1 { INSERT INTO t1 VALUES(5, zeroblob(1200)) }
+      list [db_page_count] [wal_page_count] $::nBusyHandler
+    } {6 12 0}
+
+    do_test 1.$tn.7 {
+      reopen_all
+      list [db_page_count] [wal_page_count] $::nBusyHandler
+    } {7 0 0}
+
+    do_test 1.$tn.8  { sql2 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5}
+    do_test 1.$tn.9  {
+      sql1 { INSERT INTO t1 VALUES(6, zeroblob(1200)) }
+      list [db_page_count] [wal_page_count] $::nBusyHandler
+    } {7 5 0}
+    do_test 1.$tn.10 { sql3 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5 6}
+
+    set ::busy_handler_script { 
+      if {$n==5} { sql2 COMMIT } 
+      if {$n==6} { set ::db_file_size [db_page_count] }
+      if {$n==7} { sql3 COMMIT }
     }
-  } {}
-  do_test 2.2.$tn.2 { file_page_counts } {1 5 1 7}
-  do_test 2.2.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
-  do_test 2.2.$tn.4 { sql1 { PRAGMA wal_checkpoint = RESTART } } {1 5 5}
-  do_test 2.2.$tn.5 { file_page_counts } {2 5 2 7}
-}
+    do_test 1.$tn.11 {
+      code1 { do_wal_checkpoint db -mode restart }
+      list [db_page_count] [wal_page_count] $::nBusyHandler
+    } {10 5 8}
+    do_test 1.$tn.12 { set ::db_file_size } 10
+  }
 
-do_multiclient_test tn {
-  setup_and_attach_aux
-  do_test 2.3.$tn.1 {
-    execsql {
-      CREATE TABLE t1(a, b);
-      INSERT INTO t1 VALUES(1, 2);
-      CREATE TABLE aux.t2(a, b);
-      INSERT INTO t2 VALUES(1, 2);
+  #-------------------------------------------------------------------------
+  # This block of tests explores checkpoint operations on more than one 
+  # database file.
+  #
+  proc setup_and_attach_aux {} {
+    sql1 { ATTACH 'test.db2' AS aux }
+    sql2 { ATTACH 'test.db2' AS aux }
+    sql3 { ATTACH 'test.db2' AS aux }
+    sql1 {
+      PRAGMA main.page_size=1024; PRAGMA main.journal_mode=WAL;
+      PRAGMA aux.page_size=1024;  PRAGMA aux.journal_mode=WAL;
     }
-  } {}
-  do_test 2.3.$tn.2 { file_page_counts } {1 5 1 5}
-  do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
-  do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
-  do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
-  do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7}
-  do_test 2.3.$tn.7 { sql1 { PRAGMA wal_checkpoint = FULL } } {1 7 5}
-  do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7}
-}
+  }
 
-# Check that checkpoints block on the correct locks. And respond correctly
-# if they cannot obtain those locks. There are three locks that a checkpoint
-# may block on (in the following order):
-#
-#   1. The writer lock: FULL and RESTART checkpoints block until any writer
-#      process releases its lock.
-#
-#   2. Readers using part of the log file. FULL and RESTART checkpoints block
-#      until readers using part (but not all) of the log file have finished.
-#
-#   3. Readers using any of the log file. After copying data into the
-#      database file, RESTART checkpoints block until readers using any part
-#      of the log file have finished.
-#
-# This test case involves running a checkpoint while there exist other 
-# processes holding all three types of locks.
-#
-foreach {tn1 checkpoint busy_on ckpt_expected expected} {
-  1   PASSIVE   -   {0 5 5}   -
-  2   TYPO      -   {0 5 5}   -
+  proc file_page_counts {} {
+    list [db_page_count  test.db ] \
+         [wal_page_count test.db ] \
+         [db_page_count  test.db2] \
+         [wal_page_count test.db2]
+  }
 
-  3   FULL      -   {0 7 7}   2
-  4   FULL      1   {1 5 5}   1
-  5   FULL      2   {1 7 5}   2
-  6   FULL      3   {0 7 7}   2
+  # Test that executing "PRAGMA wal_checkpoint" checkpoints all attached
+  # databases, not just the main db.  In capi mode, check that this is
+  # true if a NULL pointer is passed to wal_checkpoint_v2() in place of a 
+  # database name.
+  do_multiclient_test tn {
+    setup_and_attach_aux
+    do_test 2.1.$tn.1 {
+      sql1 {
+        CREATE TABLE t1(a, b);
+        INSERT INTO t1 VALUES(1, 2);
+        CREATE TABLE aux.t2(a, b);
+        INSERT INTO t2 VALUES(1, 2);
+      }
+    } {}
+    do_test 2.2.$tn.2 { file_page_counts } {1 5 1 5}
+    do_test 2.1.$tn.3 { code1 { do_wal_checkpoint db } } {0 5 5}
+    do_test 2.1.$tn.4 { file_page_counts } {2 5 2 5}
+  }
 
-  7   RESTART   -   {0 7 7}   3
-  8   RESTART   1   {1 5 5}   1
-  9   RESTART   2   {1 7 5}   2
-  10  RESTART   3   {1 7 7}   3
+  do_multiclient_test tn {
+    setup_and_attach_aux
+    do_test 2.2.$tn.1 {
+      execsql {
+        CREATE TABLE t1(a, b);
+        INSERT INTO t1 VALUES(1, 2);
+        CREATE TABLE aux.t2(a, b);
+        INSERT INTO t2 VALUES(1, 2);
+        INSERT INTO t2 VALUES(3, 4);
+      }
+    } {}
+    do_test 2.2.$tn.2 { file_page_counts } {1 5 1 7}
+    do_test 2.2.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
+    do_test 2.2.$tn.4 { code1 { do_wal_checkpoint db -mode restart } } {1 5 5}
+    do_test 2.2.$tn.5 { file_page_counts } {2 5 2 7}
+  }
 
-} {
   do_multiclient_test tn {
     setup_and_attach_aux
-  
-    proc busyhandler {x} {
-      set ::max_busyhandler $x
-      if {$::busy_on!="-" && $x==$::busy_on} { return 1 }
-      switch -- $x {
-        1 { sql2 "COMMIT ; BEGIN ; SELECT * FROM t1" }
-        2 { sql3 "COMMIT" }
-        3 { sql2 "COMMIT" }
+    do_test 2.3.$tn.1 {
+      execsql {
+        CREATE TABLE t1(a, b);
+        INSERT INTO t1 VALUES(1, 2);
+        CREATE TABLE aux.t2(a, b);
+        INSERT INTO t2 VALUES(1, 2);
       }
-      return 0
+    } {}
+    do_test 2.3.$tn.2 { file_page_counts } {1 5 1 5}
+    do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
+    do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
+    do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
+    do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7}
+    do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 7 5}
+    do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7}
+  }
+
+  # Check that checkpoints block on the correct locks. And respond correctly
+  # if they cannot obtain those locks. There are three locks that a checkpoint
+  # may block on (in the following order):
+  #
+  #   1. The writer lock: FULL and RESTART checkpoints block until any writer
+  #      process releases its lock.
+  #
+  #   2. Readers using part of the log file. FULL and RESTART checkpoints block
+  #      until readers using part (but not all) of the log file have finished.
+  #
+  #   3. Readers using any of the log file. After copying data into the
+  #      database file, RESTART checkpoints block until readers using any part
+  #      of the log file have finished.
+  #
+  # This test case involves running a checkpoint while there exist other 
+  # processes holding all three types of locks.
+  #
+  foreach {tn1 checkpoint busy_on ckpt_expected expected} {
+    1   PASSIVE   -   {0 5 5}   -
+    2   TYPO      -   {0 5 5}   -
+
+    3   FULL      -   {0 7 7}   2
+    4   FULL      1   {1 5 5}   1
+    5   FULL      2   {1 7 5}   2
+    6   FULL      3   {0 7 7}   2
+
+    7   RESTART   -   {0 7 7}   3
+    8   RESTART   1   {1 5 5}   1
+    9   RESTART   2   {1 7 5}   2
+    10  RESTART   3   {1 7 7}   3
+
+  } {
+    do_multiclient_test tn {
+      setup_and_attach_aux
+
+      proc busyhandler {x} {
+        set ::max_busyhandler $x
+        if {$::busy_on!="-" && $x==$::busy_on} { return 1 }
+        switch -- $x {
+          1 { sql2 "COMMIT ; BEGIN ; SELECT * FROM t1" }
+          2 { sql3 "COMMIT" }
+          3 { sql2 "COMMIT" }
+        }
+        return 0
+      }
+      set ::max_busyhandler -
+
+      do_test 2.4.$tn1.$tn.1 {
+        sql1 {
+          CREATE TABLE t1(a, b);
+          INSERT INTO t1 VALUES(1, 2);
+        }
+        sql2 { BEGIN; INSERT INTO t1 VALUES(3, 4) }
+        sql3 { BEGIN; SELECT * FROM t1 }
+      } {1 2}
+
+      do_test 2.4.$tn1.$tn.2 {
+        code1 { db busy busyhandler }
+        code1 { do_wal_checkpoint db -mode [string tolower $checkpoint] }
+      } $ckpt_expected
+      do_test 2.4.$tn1.$tn.3 { set ::max_busyhandler } $expected
     }
-    set ::max_busyhandler -
-  
-    do_test 2.4.$tn1.$tn.1 {
+  }
+
+
+  do_multiclient_test tn {
+
+    code1 $do_wal_checkpoint
+    code2 $do_wal_checkpoint
+    code3 $do_wal_checkpoint
+    
+    do_test 3.$tn.1 {
       sql1 {
-        CREATE TABLE t1(a, b);
-        INSERT INTO t1 VALUES(1, 2);
+        PRAGMA journal_mode = WAL;
+        PRAGMA synchronous = normal;
+        CREATE TABLE t1(x, y);
       }
-      sql2 { BEGIN; INSERT INTO t1 VALUES(3, 4) }
-      sql3 { BEGIN; SELECT * FROM t1 }
-    } {1 2}
-  
-    do_test 2.4.$tn1.$tn.2 {
-      code1 { db busy busyhandler }
-      sql1 "PRAGMA wal_checkpoint = $checkpoint"
-    } $ckpt_expected
-    do_test 2.4.$tn1.$tn.3 { set ::max_busyhandler } $expected
+
+      sql2 { PRAGMA journal_mode }
+      sql3 { PRAGMA journal_mode }
+    } {wal}
+
+    do_test 3.$tn.2 { code2 { do_wal_checkpoint db2 } } {0 2 2}
+
+    do_test 3.$tn.3 { code2 { do_wal_checkpoint db2 } } {0 2 2}
+
+    do_test 3.$tn.4 { code3 { do_wal_checkpoint db3 } } {0 2 2}
+
+    code1 {db  close}
+    code2 {db2 close}
+    code3 {db3 close}
+
+    code1 {sqlite3 db  test.db}
+    code2 {sqlite3 db2 test.db}
+    code3 {sqlite3 db3 test.db}
+
+    do_test 3.$tn.5 { sql3 { PRAGMA journal_mode } } {wal}
+
+    do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0}
   }
 }