/ Check-in [1a391f3c]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix problems with recovering wal files that use a page-size other than the default.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1a391f3c55dc9d4266552fa26d2a9839c6bafce4
User & Date: dan 2010-05-04 14:47:40
Context
2010-05-04
15:20
Add a test case to verify that log files containing pages that are not a power-of-two bytes in size are handled correctly. check-in: c2bf693f user: dan tags: trunk
14:47
Fix problems with recovering wal files that use a page-size other than the default. check-in: 1a391f3c user: dan tags: trunk
11:06
Fix a typo in walfault.test. check-in: 232dbe8e user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  2192   2192   ** If an IO error occurs, then the IO error is returned to the caller.
  2193   2193   ** Otherwise, SQLITE_OK is returned.
  2194   2194   */
  2195   2195   static int readDbPage(PgHdr *pPg){
  2196   2196     Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
  2197   2197     Pgno pgno = pPg->pgno;       /* Page number to read */
  2198   2198     int rc = SQLITE_OK;          /* Return code */
  2199         -  i64 iOffset;                 /* Byte offset of file to read from */
  2200   2199     int isInWal = 0;             /* True if page is in log file */
         2200  +  int pgsz = pPager->pageSize; /* Number of bytes to read */
  2201   2201   
  2202   2202     assert( pPager->state>=PAGER_SHARED && !MEMDB );
  2203   2203     assert( isOpen(pPager->fd) );
  2204   2204   
  2205   2205     if( NEVER(!isOpen(pPager->fd)) ){
  2206   2206       assert( pPager->tempFile );
  2207   2207       memset(pPg->pData, 0, pPager->pageSize);
  2208   2208       return SQLITE_OK;
  2209   2209     }
  2210   2210   
  2211   2211     if( pagerUseWal(pPager) ){
  2212   2212       /* Try to pull the page from the write-ahead log. */
  2213         -    rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pPg->pData);
         2213  +    rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData);
  2214   2214     }
  2215   2215     if( rc==SQLITE_OK && !isInWal ){
  2216         -    iOffset = (pgno-1)*(i64)pPager->pageSize;
  2217         -    rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
         2216  +    i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
         2217  +    rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
  2218   2218       if( rc==SQLITE_IOERR_SHORT_READ ){
  2219   2219         rc = SQLITE_OK;
  2220   2220       }
  2221   2221     }
  2222   2222   
  2223   2223     if( pgno==1 ){
  2224   2224       if( rc ){
................................................................................
  2828   2828   ** the error code is returned to the caller and the contents of the
  2829   2829   ** output buffer undefined.
  2830   2830   */
  2831   2831   int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
  2832   2832     int rc = SQLITE_OK;
  2833   2833     memset(pDest, 0, N);
  2834   2834     assert( isOpen(pPager->fd) || pPager->tempFile );
         2835  +
         2836  +  if( pagerUseWal(pPager) ){
         2837  +    int isInWal = 0;
         2838  +    rc = sqlite3WalRead(pPager->pWal, 1, &isInWal, N, pDest);
         2839  +    if( rc!=SQLITE_OK || isInWal ){
         2840  +      return rc;
         2841  +    }
         2842  +  }
         2843  +
  2835   2844     if( isOpen(pPager->fd) ){
  2836   2845       IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
  2837   2846       rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
  2838   2847       if( rc==SQLITE_IOERR_SHORT_READ ){
  2839   2848         rc = SQLITE_OK;
  2840   2849       }
  2841   2850     }
................................................................................
  3051   3060   
  3052   3061     disable_simulated_io_errors();
  3053   3062     sqlite3BeginBenignMalloc();
  3054   3063     pPager->errCode = 0;
  3055   3064     pPager->exclusiveMode = 0;
  3056   3065   #ifndef SQLITE_OMIT_WAL
  3057   3066     sqlite3WalClose(pPager->pWal, pPager->fd, 
  3058         -    (pPager->noSync ? 0 : pPager->sync_flags), pTmp
         3067  +    (pPager->noSync ? 0 : pPager->sync_flags), 
         3068  +    pPager->pageSize, pTmp
  3059   3069     );
  3060   3070     pPager->pWal = 0;
  3061   3071   #endif
  3062   3072     pager_reset(pPager);
  3063   3073     if( MEMDB ){
  3064   3074       pager_unlock(pPager);
  3065   3075     }else{
................................................................................
  5829   5839   */
  5830   5840   int sqlite3PagerCheckpoint(Pager *pPager){
  5831   5841     int rc = SQLITE_OK;
  5832   5842     if( pPager->pWal ){
  5833   5843       u8 *zBuf = (u8 *)pPager->pTmpSpace;
  5834   5844       rc = sqlite3WalCheckpoint(pPager->pWal, pPager->fd, 
  5835   5845           (pPager->noSync ? 0 : pPager->sync_flags),
  5836         -        zBuf, pPager->xBusyHandler, pPager->pBusyHandlerArg
         5846  +        pPager->pageSize, zBuf, 
         5847  +        pPager->xBusyHandler, pPager->pBusyHandlerArg
  5837   5848       );
  5838   5849     }
  5839   5850     return rc;
  5840   5851   }
  5841   5852   
  5842   5853   int sqlite3PagerWalCallback(Pager *pPager){
  5843   5854     return sqlite3WalCallback(pPager->pWal);
................................................................................
  5904   5915     ** the database file, the log and log-summary files will be deleted.
  5905   5916     */
  5906   5917     if( rc==SQLITE_OK && pPager->pWal ){
  5907   5918       rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);
  5908   5919       if( rc==SQLITE_OK ){
  5909   5920         rc = sqlite3WalClose(pPager->pWal, pPager->fd,
  5910   5921           (pPager->noSync ? 0 : pPager->sync_flags), 
  5911         -        (u8*)pPager->pTmpSpace
         5922  +        pPager->pageSize, (u8*)pPager->pTmpSpace
  5912   5923         );
  5913   5924         pPager->pWal = 0;
  5914   5925       }
  5915   5926     }
  5916   5927     return rc;
  5917   5928   }
  5918   5929   #endif
  5919   5930   
  5920   5931   #endif /* SQLITE_OMIT_DISKIO */

Changes to src/wal.c.

   706    706   /*
   707    707   ** Checkpoint the contents of the log file.
   708    708   */
   709    709   static int walCheckpoint(
   710    710     Wal *pWal,                      /* Wal connection */
   711    711     sqlite3_file *pFd,              /* File descriptor open on db file */
   712    712     int sync_flags,                 /* Flags for OsSync() (or 0) */
          713  +  int nBuf,                       /* Size of zBuf in bytes */
   713    714     u8 *zBuf                        /* Temporary buffer to use */
   714    715   ){
   715    716     int rc;                         /* Return code */
   716    717     int pgsz = pWal->hdr.pgsz;      /* Database page-size */
   717    718     WalIterator *pIter = 0;         /* Wal iterator context */
   718    719     u32 iDbpage = 0;                /* Next database page to write */
   719    720     u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
   720    721   
   721         -  if( pWal->hdr.iLastPg==0 ){
   722         -    return SQLITE_OK;
   723         -  }
   724         -
   725    722     /* Allocate the iterator */
   726    723     pIter = walIteratorInit(pWal);
   727    724     if( !pIter ) return SQLITE_NOMEM;
          725  +
          726  +  if( pWal->hdr.iLastPg==0 ){
          727  +    rc = SQLITE_OK;
          728  +    goto out;
          729  +  }
          730  +
          731  +  if( pWal->hdr.pgsz!=nBuf ){
          732  +    rc = SQLITE_CORRUPT_BKPT;
          733  +    goto out;
          734  +  }
   728    735   
   729    736     /* Sync the log file to disk */
   730    737     if( sync_flags ){
   731    738       rc = sqlite3OsSync(pWal->pFd, sync_flags);
   732    739       if( rc!=SQLITE_OK ) goto out;
   733    740     }
   734    741   
................................................................................
   784    791   /*
   785    792   ** Close a connection to a log file.
   786    793   */
   787    794   int sqlite3WalClose(
   788    795     Wal *pWal,                      /* Wal to close */
   789    796     sqlite3_file *pFd,              /* Database file */
   790    797     int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
   791         -  u8 *zBuf                        /* Buffer of at least page-size bytes */
          798  +  int nBuf,
          799  +  u8 *zBuf                        /* Buffer of at least nBuf bytes */
   792    800   ){
   793    801     int rc = SQLITE_OK;
   794    802     if( pWal ){
   795    803       int isDelete = 0;             /* True to unlink wal and wal-index files */
   796    804   
   797    805       /* If an EXCLUSIVE lock can be obtained on the database file (using the
   798    806       ** ordinary, rollback-mode locking methods, this guarantees that the
................................................................................
   800    808       ** the database. In this case checkpoint the database and unlink both
   801    809       ** the wal and wal-index files.
   802    810       **
   803    811       ** The EXCLUSIVE lock is not released before returning.
   804    812       */
   805    813       rc = sqlite3OsLock(pFd, SQLITE_LOCK_EXCLUSIVE);
   806    814       if( rc==SQLITE_OK ){
   807         -      rc = walCheckpoint(pWal, pFd, sync_flags, zBuf);
          815  +      rc = walCheckpoint(pWal, pFd, sync_flags, nBuf, zBuf);
   808    816         if( rc==SQLITE_OK ){
   809    817           isDelete = 1;
   810    818         }
   811    819         walIndexUnmap(pWal);
   812    820       }
   813    821   
   814    822       pWal->pVfs->xShmClose(pWal->pVfs, pWal->pWIndex, isDelete);
................................................................................
   949    957     );
   950    958     walSetLock(pWal, SQLITE_SHM_UNLOCK);
   951    959   }
   952    960   
   953    961   /*
   954    962   ** Read a page from the log, if it is present. 
   955    963   */
   956         -int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, u8 *pOut){
          964  +int sqlite3WalRead(
          965  +  Wal *pWal, 
          966  +  Pgno pgno, 
          967  +  int *pInWal, 
          968  +  int nOut,
          969  +  u8 *pOut
          970  +){
   957    971     u32 iRead = 0;
   958    972     u32 *aData; 
   959    973     int iFrame = (pWal->hdr.iLastPg & 0xFFFFFF00);
   960    974   
   961    975     assert( pWal->lockState==SQLITE_SHM_READ||pWal->lockState==SQLITE_SHM_WRITE );
   962    976     walIndexMap(pWal, -1);
   963    977   
................................................................................
  1007   1021   
  1008   1022     /* If iRead is non-zero, then it is the log frame number that contains the
  1009   1023     ** required page. Read and return data from the log file.
  1010   1024     */
  1011   1025     if( iRead ){
  1012   1026       i64 iOffset = walFrameOffset(iRead, pWal->hdr.pgsz) + WAL_FRAME_HDRSIZE;
  1013   1027       *pInWal = 1;
  1014         -    return sqlite3OsRead(pWal->pFd, pOut, pWal->hdr.pgsz, iOffset);
         1028  +    return sqlite3OsRead(pWal->pFd, pOut, nOut, iOffset);
  1015   1029     }
  1016   1030   
  1017   1031     *pInWal = 0;
  1018   1032     return SQLITE_OK;
  1019   1033   }
  1020   1034   
  1021   1035   
................................................................................
  1262   1276   **   3. Zero the wal-index header (so new readers will ignore the log).
  1263   1277   **   4. Drop the CHECKPOINT lock.
  1264   1278   */
  1265   1279   int sqlite3WalCheckpoint(
  1266   1280     Wal *pWal,                      /* Wal connection */
  1267   1281     sqlite3_file *pFd,              /* File descriptor open on db file */
  1268   1282     int sync_flags,                 /* Flags to sync db file with (or 0) */
         1283  +  int nBuf,                       /* Size of temporary buffer */
  1269   1284     u8 *zBuf,                       /* Temporary buffer to use */
  1270   1285     int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
  1271   1286     void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
  1272   1287   ){
  1273   1288     int rc;                         /* Return code */
  1274   1289     int isChanged = 0;              /* True if a new wal-index header is loaded */
  1275   1290   
................................................................................
  1284   1299       walSetLock(pWal, SQLITE_SHM_UNLOCK);
  1285   1300       return rc;
  1286   1301     }
  1287   1302   
  1288   1303     /* Copy data from the log to the database file. */
  1289   1304     rc = walIndexReadHdr(pWal, &isChanged);
  1290   1305     if( rc==SQLITE_OK ){
  1291         -    rc = walCheckpoint(pWal, pFd, sync_flags, zBuf);
         1306  +    rc = walCheckpoint(pWal, pFd, sync_flags, nBuf, zBuf);
  1292   1307     }
  1293   1308     if( isChanged ){
  1294   1309       /* If a new wal-index header was loaded before the checkpoint was 
  1295   1310       ** performed, then the pager-cache associated with log pWal is now
  1296   1311       ** out of date. So zero the cached wal-index header to ensure that
  1297   1312       ** next time the pager opens a snapshot on this database it knows that
  1298   1313       ** the cache needs to be reset.

Changes to src/wal.h.

    20     20   #include "sqliteInt.h"
    21     21   
    22     22   #ifdef SQLITE_OMIT_WAL
    23     23   # define sqlite3WalOpen(x,y,z)             0
    24     24   # define sqlite3WalClose(w,x,y,z)          0
    25     25   # define sqlite3WalOpenSnapshot(y,z)       0
    26     26   # define sqlite3WalCloseSnapshot(z) 
    27         -# define sqlite3WalRead(w,x,y,z)           0
           27  +# define sqlite3WalRead(v,w,x,y,z)         0
    28     28   # define sqlite3WalDbsize(y,z)
    29     29   # define sqlite3WalWriteLock(y,z)          0
    30     30   # define sqlite3WalUndo(x,y,z)             0
    31     31   # define sqlite3WalSavepoint(z)            0
    32     32   # define sqlite3WalSavepointUndo(y,z)      0
    33     33   # define sqlite3WalFrames(u,v,w,x,y,z)     0
    34     34   # define sqlite3WalCheckpoint(u,v,w,x,y,z) 0
................................................................................
    38     38   /* Connection to a write-ahead log (WAL) file. 
    39     39   ** There is one object of this type for each pager. 
    40     40   */
    41     41   typedef struct Wal Wal;
    42     42   
    43     43   /* Open and close a connection to a write-ahead log. */
    44     44   int sqlite3WalOpen(sqlite3_vfs*, const char *zDb, Wal **ppWal);
    45         -int sqlite3WalClose(Wal *pWal, sqlite3_file *pFd, int sync_flags, u8 *zBuf);
           45  +int sqlite3WalClose(Wal *pWal, sqlite3_file *pFd, int sync_flags, int, u8 *);
    46     46   
    47     47   /* Used by readers to open (lock) and close (unlock) a snapshot.  A 
    48     48   ** snapshot is like a read-transaction.  It is the state of the database
    49     49   ** at an instant in time.  sqlite3WalOpenSnapshot gets a read lock and
    50     50   ** preserves the current state even if the other threads or processes
    51     51   ** write to or checkpoint the WAL.  sqlite3WalCloseSnapshot() closes the
    52     52   ** transaction and releases the lock.
    53     53   */
    54     54   int sqlite3WalOpenSnapshot(Wal *pWal, int *);
    55     55   void sqlite3WalCloseSnapshot(Wal *pWal);
    56     56   
    57     57   /* Read a page from the write-ahead log, if it is present. */
    58         -int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, u8 *pOut);
           58  +int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
    59     59   
    60     60   /* Return the size of the database as it existed at the beginning
    61     61   ** of the snapshot */
    62     62   void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno);
    63     63   
    64     64   /* Obtain or release the WRITER lock. */
    65     65   int sqlite3WalWriteLock(Wal *pWal, int op);
................................................................................
    79     79   int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
    80     80   
    81     81   /* Copy pages from the log to the database file */ 
    82     82   int sqlite3WalCheckpoint(
    83     83     Wal *pWal,                      /* Write-ahead log connection */
    84     84     sqlite3_file *pFd,              /* File descriptor open on db file */
    85     85     int sync_flags,                 /* Flags to sync db file with (or 0) */
           86  +  int nBuf,                       /* Size of buffer nBuf */
    86     87     u8 *zBuf,                       /* Temporary buffer to use */
    87     88     int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
    88     89     void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
    89     90   );
    90     91   
    91     92   /* Return the value to pass to a sqlite3_wal_hook callback, the
    92     93   ** number of frames in the WAL at the point of the last commit since

Changes to test/wal.test.

  1188   1188   
  1189   1189     do_test wal-17.$tn.3 {
  1190   1190       db close
  1191   1191       file size test.db
  1192   1192     } [expr 512*171]
  1193   1193   }
  1194   1194   sqlite3_test_control_pending_byte $old_pending_byte
         1195  +
         1196  +#-------------------------------------------------------------------------
         1197  +# This test - wal-18.* - verifies a couple of specific conditions that
         1198  +# may be encountered while recovering a log file are handled correctly:
         1199  +#
         1200  +#   wal-18.1.* When the first 32-bits of a frame checksum is correct but 
         1201  +#              the second 32-bits are false, and
         1202  +#
         1203  +#   wal-18.2.* When the page-size field that occurs at the start of a log
         1204  +#              file is a power of 2 greater than 16384 or smaller than 512.
         1205  +#
         1206  +file delete -force test.db test.db-wal test.db-journal
         1207  +do_test wal-18.0 {
         1208  +  sqlite3 db test.db
         1209  +  execsql {
         1210  +    PRAGMA page_size = 1024;
         1211  +    PRAGMA auto_vacuum = 0;
         1212  +    PRAGMA journal_mode = WAL;
         1213  +    PRAGMA synchronous = OFF;
         1214  +
         1215  +    CREATE TABLE t1(a, b, UNIQUE(a, b));
         1216  +    INSERT INTO t1 VALUES(0, 0);
         1217  +    PRAGMA wal_checkpoint;
         1218  +
         1219  +    INSERT INTO t1 VALUES(1, 2);          -- frames 1 and 2
         1220  +    INSERT INTO t1 VALUES(3, 4);          -- frames 3 and 4
         1221  +    INSERT INTO t1 VALUES(5, 6);          -- frames 5 and 6
         1222  +  }
         1223  +
         1224  +  file copy -force test.db testX.db
         1225  +  file copy -force test.db-wal testX.db-wal
         1226  +  db close
         1227  +  list [file size testX.db] [file size testX.db-wal]
         1228  +} [list [expr 3*1024] [log_file_size 6 1024]]
         1229  +
         1230  +foreach {nFrame result} {
         1231  +         0      {0 0}
         1232  +         1      {0 0}
         1233  +         2      {0 0 1 2}
         1234  +         3      {0 0 1 2}
         1235  +         4      {0 0 1 2 3 4}
         1236  +         5      {0 0 1 2 3 4}
         1237  +         6      {0 0 1 2 3 4 5 6}
         1238  +} {
         1239  +  do_test wal-18.1.$nFrame {
         1240  +    file copy -force testX.db test.db
         1241  +    file copy -force testX.db-wal test.db-wal
         1242  +
         1243  +    hexio_write test.db-wal [expr 12 + $nFrame*(16+1024) + 12] 00000000
         1244  +
         1245  +    sqlite3 db test.db
         1246  +    execsql { 
         1247  +      SELECT * FROM t1;
         1248  +      PRAGMA integrity_check; 
         1249  +    }
         1250  +  } [concat $result ok]
         1251  +  db close
         1252  +} 
         1253  +
         1254  +proc randomblob {pgsz} {
         1255  +  sqlite3 rbdb :memory:
         1256  +  set blob [rbdb one {SELECT randomblob($pgsz)}]
         1257  +  rbdb close
         1258  +  set blob
         1259  +}
         1260  +
         1261  +proc logcksum {ckv1 ckv2 blob} {
         1262  +  upvar $ckv1 c1
         1263  +  upvar $ckv2 c2
         1264  +
         1265  +  binary scan $blob iu* values
         1266  +  foreach v $values {
         1267  +    incr c1 $v
         1268  +    incr c2 $c1
         1269  +  }
         1270  +
         1271  +  set c1 [expr ($c1 + ($c1>>24))&0xFFFFFFFF]
         1272  +  set c2 [expr ($c2 + ($c2>>24))&0xFFFFFFFF]
         1273  +}
         1274  +
         1275  +file copy -force test.db testX.db
         1276  +foreach {tn pgsz works} { 
         1277  +  1    128    0
         1278  +  2    256    0
         1279  +  3    512    1
         1280  +  4   1024    1
         1281  +  5   2048    1
         1282  +  6   4096    1
         1283  +  7   8192    1
         1284  +  8  16384    1
         1285  +  9  32768    1
         1286  + 10  65536    0
         1287  +} {
         1288  +
         1289  +  for {set pg 1} {$pg <= 3} {incr pg} {
         1290  +    file copy -force testX.db test.db
         1291  +    file delete -force test.db-wal
         1292  +  
         1293  +    # Check that the database now exists and consists of three pages. And
         1294  +    # that there is no associated wal file.
         1295  +    #
         1296  +    do_test wal-18.2.$tn.$pg.1 { file exists test.db-wal } 0
         1297  +    do_test wal-18.2.$tn.$pg.2 { file exists test.db } 1
         1298  +    do_test wal-18.2.$tn.$pg.3 { file size test.db } [expr 1024*3]
         1299  +  
         1300  +    do_test wal-18.2.$tn.$pg.4 {
         1301  +
         1302  +      # Create a wal file that contains a single frame (database page
         1303  +      # number $pg) with the commit flag set. The frame checksum is
         1304  +      # correct, but the contents of the database page are corrupt.
         1305  +      #
         1306  +      # The page-size in the log file header is set to $pgsz. If the
         1307  +      # WAL code considers $pgsz to be a valid SQLite database file page-size,
         1308  +      # the database will be corrupt (because the garbage frame contents
         1309  +      # will be treated as valid content). If $pgsz is invalid (too small
         1310  +      # or too large), the db will not be corrupt as the log file will
         1311  +      # be ignored.
         1312  +      #
         1313  +      set c1 22
         1314  +      set c2 23
         1315  +      set walhdr [binary format III $pgsz $c1 $c2]
         1316  +      set framebody [randomblob $pgsz]
         1317  +      set framehdr  [binary format II $pg 5]
         1318  +      logcksum c1 c2 $framehdr
         1319  +      logcksum c1 c2 $framebody
         1320  +      set framehdr [binary format IIII $pg 5 $c1 $c2]
         1321  +      set fd [open test.db-wal w]
         1322  +      fconfigure $fd -encoding binary -translation binary
         1323  +      puts -nonewline $fd $walhdr
         1324  +      puts -nonewline $fd $framehdr
         1325  +      puts -nonewline $fd $framebody
         1326  +      close $fd
         1327  +  
         1328  +      file size test.db-wal
         1329  +    } [log_file_size 1 $pgsz]
         1330  +  
         1331  +    do_test wal-18.2.$tn.$pg.5 {
         1332  +      sqlite3 db test.db
         1333  +      set rc [catch { db one {PRAGMA integrity_check} } msg]
         1334  +      expr { $rc!=0 || $msg!="ok" }
         1335  +    } $works
         1336  +  
         1337  +    db close
         1338  +  }
         1339  +}
  1195   1340   
  1196   1341   catch { db2 close }
  1197   1342   catch { db close }
  1198   1343   finish_test
  1199         -
  1200   1344   

Changes to test/walcrash.test.

   246    246     } {1}
   247    247     do_test walcrash-6.$i.3 { execsql { PRAGMA main.integrity_check } } {ok}
   248    248     do_test walcrash-6.$i.4 { execsql { PRAGMA main.journal_mode } } {wal}
   249    249   
   250    250     db close
   251    251   }
   252    252   
          253  +#-------------------------------------------------------------------------
          254  +# This test case simulates a crash while checkpointing the database. Page
          255  +# 1 is one of the pages overwritten by the checkpoint. This is a special
          256  +# case because it means the content of page 1 may be damaged. SQLite will
          257  +# have to determine:
          258  +#
          259  +#   (a) that the database is a WAL database, and 
          260  +#   (b) the database page-size
          261  +#
          262  +# based on the log file.
          263  +#
   253    264   for {set i 1} {$i < $REPEATS} {incr i} {
   254    265     file delete -force test.db test.db-wal
   255    266   
          267  +  # Select a page-size for this test.
          268  +  #
          269  +  set pgsz [lindex {512 1024 2048 4096 8192 16384} [expr $i%6]]
          270  +
   256    271     do_test walcrash-7.$i.1 {
   257         -    crashsql -delay 3 -file test.db -seed [incr seed] -blocksize 512 {
          272  +    crashsql -delay 3 -file test.db -seed [incr seed] -blocksize 512 "
          273  +      PRAGMA page_size = $pgsz;
   258    274         PRAGMA journal_mode = wal;
   259    275         BEGIN;
   260    276           CREATE TABLE t1(a, b);
   261    277           INSERT INTO t1 VALUES(1, 2);
   262    278         COMMIT;
   263    279         PRAGMA wal_checkpoint;
   264    280         CREATE INDEX i1 ON t1(a);
   265    281         PRAGMA wal_checkpoint;
   266         -    }
          282  +    "
   267    283     } {1 {child process exited abnormally}}
   268    284   
   269    285     do_test walcrash-7.$i.2 {
   270    286       sqlite3 db test.db
   271    287       execsql { SELECT b FROM t1 WHERE a = 1 }
   272    288     } {2}
   273    289     do_test walcrash-7.$i.3 { execsql { PRAGMA main.integrity_check } } {ok}