SQLite

Changes On Branch two-mappings
Login

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

Changes In Branch two-mappings Excluding Merge-Ins

This is equivalent to a diff from 30c0a693 to 80c63443

2013-04-01
14:20
Minor changes to unixMapfile() function. (Leaf check-in: 80c63443 user: dan tags: two-mappings)
2013-03-29
19:38
Further fixes for test scripts. (check-in: 23ffa4f9 user: dan tags: two-mappings)
2013-03-26
20:32
Change os_unix.c to use either one or two mappings internally. (check-in: e7698cba user: dan tags: two-mappings)
14:36
Change the name of the Pager.pFree field to Pager.pMmapFreelist. (check-in: 611bd824 user: drh tags: experimental-mmap)
14:16
In btree.c, save the positions of any open cursors before moving any pages around to auto-vacuum the database on commit. (check-in: 30c0a693 user: dan tags: experimental-mmap)
01:07
Previous check-in accidently left mmap turned off by default. This checkin fixes that. Unfortunately, shared.test is now segfaulting. All other veryquick tests appear to work, however. (check-in: a850c731 user: drh tags: experimental-mmap)

Changes to src/btree.c.

2592
2593
2594
2595
2596
2597
2598
2599

2600
2601
2602
2603
2604

2605
2606
2607
2608
2609
2610
2611

  for(pCsr=pBt->pCursor; pCsr && rc==SQLITE_OK; pCsr=pCsr->pNext){
    if( pCsr->iPage>=0 ){
      MemPage *pPg = pCsr->apPage[0];
      if( pPg && pPg->pDbPage->flags & PGHDR_MMAP ){
        MemPage *pNew = 0;
        rc = getAndInitPage(pBt, pPg->pgno, &pNew, 0);
        if( rc==SQLITE_OK && pCsr->iPage==0 ){

          pCsr->info.pCell = pNew->aData + (pCsr->info.pCell - pPg->aData);
        }
        pCsr->apPage[0] = pNew;
        releasePage(pPg);
        if( rc!=SQLITE_OK ) return rc;

      }
    }
  }

  return rc;
}








|
>
|
|
|
|
<
>







2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604

2605
2606
2607
2608
2609
2610
2611
2612

  for(pCsr=pBt->pCursor; pCsr && rc==SQLITE_OK; pCsr=pCsr->pNext){
    if( pCsr->iPage>=0 ){
      MemPage *pPg = pCsr->apPage[0];
      if( pPg && pPg->pDbPage->flags & PGHDR_MMAP ){
        MemPage *pNew = 0;
        rc = getAndInitPage(pBt, pPg->pgno, &pNew, 0);
        if( rc==SQLITE_OK ){
          if( pCsr->iPage==0 ){
            pCsr->info.pCell = pNew->aData + (pCsr->info.pCell - pPg->aData);
          }
          pCsr->apPage[0] = pNew;
          releasePage(pPg);

        }
      }
    }
  }

  return rc;
}

Changes to src/os_unix.c.

202
203
204
205
206
207
208








209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232


233
234
235
236
237
238
239
** opportunity to either close or reuse it.
*/
struct UnixUnusedFd {
  int fd;                   /* File descriptor to close */
  int flags;                /* Flags this file descriptor was opened with */
  UnixUnusedFd *pNext;      /* Next unused file descriptor on same file */
};









/*
** The unixFile structure is subclass of sqlite3_file specific to the unix
** VFS implementations.
*/
typedef struct unixFile unixFile;
struct unixFile {
  sqlite3_io_methods const *pMethod;  /* Always the first entry */
  sqlite3_vfs *pVfs;                  /* The VFS that created this unixFile */
  unixInodeInfo *pInode;              /* Info about locks on this inode */
  int h;                              /* The file descriptor */
  unsigned char eFileLock;            /* The type of lock held on this fd */
  unsigned short int ctrlFlags;       /* Behavioral bits.  UNIXFILE_* flags */
  int lastErrno;                      /* The unix errno from last I/O error */
  void *lockingContext;               /* Locking style specific state */
  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
  const char *zPath;                  /* Name of the file */
  unixShm *pShm;                      /* Shared memory segment information */
  int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
  int nFetchOut;                      /* Number of outstanding xFetch refs */
  sqlite3_int64 mmapSize;             /* Usable size of mapping at pMapRegion */
  sqlite3_int64 mmapOrigsize;         /* Actual size of mapping at pMapRegion */
  sqlite3_int64 mmapLimit;            /* Configured FCNTL_MMAP_LIMIT value */
  void *pMapRegion;                   /* Memory mapped region */


#ifdef __QNXNTO__
  int sectorSize;                     /* Device sector size */
  int deviceCharacteristics;          /* Precomputed device characteristics */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
  int openFlags;                      /* The flags specified at open() */
#endif







>
>
>
>
>
>
>
>




















<
<

|
>
>







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236


237
238
239
240
241
242
243
244
245
246
247
** opportunity to either close or reuse it.
*/
struct UnixUnusedFd {
  int fd;                   /* File descriptor to close */
  int flags;                /* Flags this file descriptor was opened with */
  UnixUnusedFd *pNext;      /* Next unused file descriptor on same file */
};

typedef struct unixMapping unixMapping;
struct unixMapping {
  sqlite3_int64 mmapSize;
  sqlite3_int64 mmapOrigsize;
  void *pMapRegion;
};


/*
** The unixFile structure is subclass of sqlite3_file specific to the unix
** VFS implementations.
*/
typedef struct unixFile unixFile;
struct unixFile {
  sqlite3_io_methods const *pMethod;  /* Always the first entry */
  sqlite3_vfs *pVfs;                  /* The VFS that created this unixFile */
  unixInodeInfo *pInode;              /* Info about locks on this inode */
  int h;                              /* The file descriptor */
  unsigned char eFileLock;            /* The type of lock held on this fd */
  unsigned short int ctrlFlags;       /* Behavioral bits.  UNIXFILE_* flags */
  int lastErrno;                      /* The unix errno from last I/O error */
  void *lockingContext;               /* Locking style specific state */
  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
  const char *zPath;                  /* Name of the file */
  unixShm *pShm;                      /* Shared memory segment information */
  int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
  int nFetchOut;                      /* Number of outstanding xFetch refs */


  sqlite3_int64 mmapLimit;            /* Configured FCNTL_MMAP_LIMIT value */
  int szSyspage;                      /* System page size */
  unixMapping aMmap[2];               /* Up to two memory mapped regions */

#ifdef __QNXNTO__
  int sectorSize;                     /* Device sector size */
  int deviceCharacteristics;          /* Precomputed device characteristics */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
  int openFlags;                      /* The flags specified at open() */
#endif
308
309
310
311
312
313
314








315
316
317
318
319
320
321
** testing and debugging only.
*/
#if SQLITE_THREADSAFE
#define threadid pthread_self()
#else
#define threadid 0
#endif









/*
** Different Unix systems declare open() in different ways.  Same use
** open(const char*,int,mode_t).  Others use open(const char*,int,...).
** The difference is important when using a pointer to the function.
**
** The safest way to deal with the problem is to always use this wrapper







>
>
>
>
>
>
>
>







316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
** testing and debugging only.
*/
#if SQLITE_THREADSAFE
#define threadid pthread_self()
#else
#define threadid 0
#endif

#if !defined(HAVE_MREMAP)
#if defined(__linux__) && defined(_GNU_SOURCE)
# define HAVE_MREMAP 1
#else
# define HAVE_MREMAP 0
#endif
#endif

/*
** Different Unix systems declare open() in different ways.  Same use
** open(const char*,int,mode_t).  Others use open(const char*,int,...).
** The difference is important when using a pointer to the function.
**
** The safest way to deal with the problem is to always use this wrapper
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

  { "mmap",       (sqlite3_syscall_ptr)mmap,     0 },
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)

  { "munmap",       (sqlite3_syscall_ptr)munmap,          0 },
#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)

#if defined(__linux__) && defined(_GNU_SOURCE)
  { "mremap",       (sqlite3_syscall_ptr)mremap,          0 },
#else
  { "mremap",       (sqlite3_syscall_ptr)0,               0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)

}; /* End of the overrideable system calls */







|







462
463
464
465
466
467
468
469
470
471
472
473
474
475
476

  { "mmap",       (sqlite3_syscall_ptr)mmap,     0 },
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)

  { "munmap",       (sqlite3_syscall_ptr)munmap,          0 },
#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)

#if HAVE_MREMAP
  { "mremap",       (sqlite3_syscall_ptr)mremap,          0 },
#else
  { "mremap",       (sqlite3_syscall_ptr)0,               0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)

}; /* End of the overrideable system calls */
1862
1863
1864
1865
1866
1867
1868

1869
1870
1871
1872
1873
1874
1875

/*
** Close a file.
*/
static int unixClose(sqlite3_file *id){
  int rc = SQLITE_OK;
  unixFile *pFile = (unixFile *)id;

  unixUnlock(id, NO_LOCK);
  unixEnterMutex();

  /* unixFile.pInode is always valid here. Otherwise, a different close
  ** routine (e.g. nolockClose()) would be called instead.
  */
  assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );







>







1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892

/*
** Close a file.
*/
static int unixClose(sqlite3_file *id){
  int rc = SQLITE_OK;
  unixFile *pFile = (unixFile *)id;
  unixUnmapfile(pFile);
  unixUnlock(id, NO_LOCK);
  unixEnterMutex();

  /* unixFile.pInode is always valid here. Otherwise, a different close
  ** routine (e.g. nolockClose()) would be called instead.
  */
  assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
3093
3094
3095
3096
3097
3098
3099


3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111



3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122


3123
3124
3125
3126
3127
3128
3129
  void *pBuf, 
  int amt,
  sqlite3_int64 offset
){
  unixFile *pFile = (unixFile *)id;
  int got;
  assert( id );



  /* If this is a database file (not a journal, master-journal or temp
  ** file), the bytes in the locking range should never be read or written. */
#if 0
  assert( pFile->pUnused==0
       || offset>=PENDING_BYTE+512
       || offset+amt<=PENDING_BYTE 
  );
#endif

  /* Deal with as much of this write request as possible by transfering
  ** data to the memory mapping using memcpy().  */



  if( offset<pFile->mmapSize ){
    if( offset+amt <= pFile->mmapSize ){
      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
      return SQLITE_OK;
    }else{
      int nCopy = pFile->mmapSize - offset;
      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
      pBuf = &((u8 *)pBuf)[nCopy];
      amt -= nCopy;
      offset += nCopy;
    }


  }

  got = seekAndRead(pFile, offset, pBuf, amt);
  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    /* lastErrno set by seekAndRead */







>
>










|
|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
>
>







3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
  void *pBuf, 
  int amt,
  sqlite3_int64 offset
){
  unixFile *pFile = (unixFile *)id;
  int got;
  assert( id );
  sqlite3_int64 iMap = 0;         /* File offset of start of mapping i */
  int i;                          /* Used to iterate through mappings */

  /* If this is a database file (not a journal, master-journal or temp
  ** file), the bytes in the locking range should never be read or written. */
#if 0
  assert( pFile->pUnused==0
       || offset>=PENDING_BYTE+512
       || offset+amt<=PENDING_BYTE 
  );
#endif

  /* Deal with as much of this read request as possible by transfering
  ** data from the memory mapping using memcpy().  */
  for(i=0; i<2; i++){
    unixMapping *pMap = &pFile->aMmap[i];
    sqlite3_int64 iEnd = iMap + pMap->mmapSize;
    if( offset<iEnd ){
      if( offset+amt <= iEnd ){
        memcpy(pBuf, &((u8 *)(pMap->pMapRegion))[offset-iMap], amt);
        return SQLITE_OK;
      }else{
        int nCopy = iEnd - offset;
        memcpy(pBuf, &((u8 *)(pMap->pMapRegion))[offset-iMap], nCopy);
        pBuf = &((u8 *)pBuf)[nCopy];
        amt -= nCopy;
        offset += nCopy;
      }
    }
    iMap = pMap->mmapSize;
  }

  got = seekAndRead(pFile, offset, pBuf, amt);
  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    /* lastErrno set by seekAndRead */
3190
3191
3192
3193
3194
3195
3196


3197
3198
3199
3200
3201
3202
3203
  int amt,
  sqlite3_int64 offset 
){
  unixFile *pFile = (unixFile*)id;
  int wrote = 0;
  assert( id );
  assert( amt>0 );



  /* If this is a database file (not a journal, master-journal or temp
  ** file), the bytes in the locking range should never be read or written. */
#if 0
  assert( pFile->pUnused==0
       || offset>=PENDING_BYTE+512
       || offset+amt<=PENDING_BYTE 







>
>







3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
  int amt,
  sqlite3_int64 offset 
){
  unixFile *pFile = (unixFile*)id;
  int wrote = 0;
  assert( id );
  assert( amt>0 );
  int i;
  sqlite3_int64 iMap = 0;

  /* If this is a database file (not a journal, master-journal or temp
  ** file), the bytes in the locking range should never be read or written. */
#if 0
  assert( pFile->pUnused==0
       || offset>=PENDING_BYTE+512
       || offset+amt<=PENDING_BYTE 
3222
3223
3224
3225
3226
3227
3228
3229
3230

3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241


3242
3243
3244
3245
3246
3247
3248
      if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){
        pFile->transCntrChng = 1;  /* The transaction counter has changed */
      }
    }
  }
#endif

  /* Deal with as much of this write request as possible by transfering
  ** data from the memory mapping using memcpy().  */

  if( offset<pFile->mmapSize ){
    if( offset+amt <= pFile->mmapSize ){
      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
      return SQLITE_OK;
    }else{
      int nCopy = pFile->mmapSize - offset;
      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
      pBuf = &((u8 *)pBuf)[nCopy];
      amt -= nCopy;
      offset += nCopy;
    }


  }

  while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
    amt -= wrote;
    offset += wrote;
    pBuf = &((char*)pBuf)[wrote];
  }







|
|
>
|
|
|
|
|
|
|
|
|
|
|
>
>







3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
      if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){
        pFile->transCntrChng = 1;  /* The transaction counter has changed */
      }
    }
  }
#endif

  for(i=0; i<2; i++){
    unixMapping *pMap = &pFile->aMmap[i];
    sqlite3_int64 iEnd = iMap + pMap->mmapSize;
    if( offset<iEnd ){
      if( offset+amt <= iEnd ){
        memcpy(&((u8 *)(pMap->pMapRegion))[offset-iMap], pBuf, amt);
        return SQLITE_OK;
      }else{
        int nCopy = iEnd - offset;
        memcpy(&((u8 *)(pMap->pMapRegion))[offset-iMap], pBuf, nCopy);
        pBuf = &((u8 *)pBuf)[nCopy];
        amt -= nCopy;
        offset += nCopy;
      }
    }
    iMap = pMap->mmapSize;
  }

  while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
    amt -= wrote;
    offset += wrote;
    pBuf = &((char*)pBuf)[wrote];
  }
3506
3507
3508
3509
3510
3511
3512


3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529



3530
3531


3532
3533
3534
3535
3536
3537
3538
  }

  rc = robust_ftruncate(pFile->h, (off_t)nByte);
  if( rc ){
    pFile->lastErrno = errno;
    return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
  }else{


#ifdef SQLITE_DEBUG
    /* If we are doing a normal write to a database file (as opposed to
    ** doing a hot-journal rollback or a write to some file other than a
    ** normal database file) and we truncate the file to zero length,
    ** that effectively updates the change counter.  This might happen
    ** when restoring a database using the backup API from a zero-length
    ** source.
    */
    if( pFile->inNormalWrite && nByte==0 ){
      pFile->transCntrChng = 1;
    }
#endif

    /* If the file was just truncated to a size smaller than the currently
    ** mapped region, reduce the effective mapping size as well. SQLite will
    ** use read() and write() to access data beyond this point from now on.  
    */



    if( nByte<pFile->mmapSize ){
      pFile->mmapSize = nByte;


    }

    return SQLITE_OK;
  }
}

/*







>
>

















>
>
>
|
|
>
>







3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
  }

  rc = robust_ftruncate(pFile->h, (off_t)nByte);
  if( rc ){
    pFile->lastErrno = errno;
    return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
  }else{
    int i;

#ifdef SQLITE_DEBUG
    /* If we are doing a normal write to a database file (as opposed to
    ** doing a hot-journal rollback or a write to some file other than a
    ** normal database file) and we truncate the file to zero length,
    ** that effectively updates the change counter.  This might happen
    ** when restoring a database using the backup API from a zero-length
    ** source.
    */
    if( pFile->inNormalWrite && nByte==0 ){
      pFile->transCntrChng = 1;
    }
#endif

    /* If the file was just truncated to a size smaller than the currently
    ** mapped region, reduce the effective mapping size as well. SQLite will
    ** use read() and write() to access data beyond this point from now on.  
    */
    for(i=1; i>=0; i--){
      unixMapping *pMap = &pFile->aMmap[i];
      sqlite3_int64 iEnd = pMap->mmapSize + (i==1 ? pMap[-1].mmapSize : 0);
      if( nByte<iEnd ){
        pMap->mmapSize -= (iEnd - nByte);
        if( pMap->mmapSize<0 ) pMap->mmapSize = 0;
      }
    }

    return SQLITE_OK;
  }
}

/*
3617
3618
3619
3620
3621
3622
3623

3624

3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
      }
#endif
    }
  }

  if( pFile->mmapLimit>0 ){
    int rc;

    if( pFile->szChunk<=0 ){

      if( robust_ftruncate(pFile->h, nByte) ){
        pFile->lastErrno = errno;
        return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
      }
    }

    rc = unixMapfile(pFile, nByte);
    return rc;
  }

  return SQLITE_OK;
}

/*







>

>
|





|







3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
      }
#endif
    }
  }

  if( pFile->mmapLimit>0 ){
    int rc;
    sqlite3_int64 nSz = nByte;
    if( pFile->szChunk<=0 ){
      nSz = ((nSz+pFile->szSyspage-1) / pFile->szSyspage) * pFile->szSyspage;
      if( robust_ftruncate(pFile->h, nSz) ){
        pFile->lastErrno = errno;
        return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
      }
    }

    rc = unixMapfile(pFile, nSz);
    return rc;
  }

  return SQLITE_OK;
}

/*
4505
4506
4507
4508
4509
4510
4511

4512


4513
4514
4515
4516
4517
4518
4519














4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543





4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558





4559
4560
4561
4562
4563
4564

4565



4566



4567
4568



4569
4570






4571







4572
















4573
4574
4575
4576
4577
4578

4579
4580
4581
4582
4583
4584
4585
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */

/*
** If it is currently memory mapped, unmap file pFd.
*/
static void unixUnmapfile(unixFile *pFd){

  assert( pFd->nFetchOut==0 );


  if( pFd->pMapRegion ){
    osMunmap(pFd->pMapRegion, pFd->mmapOrigsize);
    pFd->pMapRegion = 0;
    pFd->mmapSize = 0;
    pFd->mmapOrigsize = 0;
  }
}















/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
** is already mapped, the existing mapping is replaced by the new). Or, if 
** there already exists a mapping for this file, and there are still 
** outstanding xFetch() references to it, this function is a no-op.
**
** If parameter nByte is non-negative, then it is the requested size of 
** the mapping to create. Otherwise, if nByte is less than zero, then the 
** requested size is the size of the file on disk. The actual size of the
** created mapping is either the requested size or the value configured 
** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
static int unixMapfile(unixFile *pFd, i64 nByte){
  i64 nMap = nByte;
  int rc;

  assert( nMap>=0 || pFd->nFetchOut==0 );
  if( pFd->nFetchOut>0 ) return SQLITE_OK;






  if( nMap<0 ){
    struct stat statbuf;          /* Low-level file information */
    rc = osFstat(pFd->h, &statbuf);
    if( rc!=SQLITE_OK ){
      return SQLITE_IOERR_FSTAT;
    }
    nMap = statbuf.st_size;
  }
  if( nMap>pFd->mmapLimit ){
    nMap = pFd->mmapLimit;
  }

  if( nMap!=pFd->mmapSize ){
    void *pNew = 0;






#if defined(__linux__) && defined(_GNU_SOURCE)
    if( pFd->pMapRegion && nMap>0 ){
      pNew = osMremap(pFd->pMapRegion, pFd->mmapOrigsize, nMap, MREMAP_MAYMOVE);
    }else
#endif
    {

      unixUnmapfile(pFd);



      if( nMap>0 ){



        int flags = PROT_READ;
        if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;



        pNew = osMmap(0, nMap, flags, MAP_SHARED, pFd->h, 0);
      }






    }
























    if( pNew==MAP_FAILED ){
      return SQLITE_IOERR_MMAP;
    }
    pFd->pMapRegion = pNew;
    pFd->mmapSize = nMap;
    pFd->mmapOrigsize = nMap;

  }

  return SQLITE_OK;
}

/*
** If possible, return a pointer to a mapping of file fd starting at offset







>

>
>
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>


















|





>
>
>
>
>












|
<

>
>
>
>
>
|
|
|
<

<
>

>
>
>
|
>
>
>
|
|
>
>
>


>
>
>
>
>
>
|
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
>







4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616

4617
4618
4619
4620
4621
4622
4623
4624
4625

4626

4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */

/*
** If it is currently memory mapped, unmap file pFd.
*/
static void unixUnmapfile(unixFile *pFd){
  int i;
  assert( pFd->nFetchOut==0 );
  for(i=0; i<2; i++){
    unixMapping *pMap = &pFd->aMmap[i];
    if( pMap->pMapRegion ){
      osMunmap(pMap->pMapRegion, pMap->mmapOrigsize);
      pMap->pMapRegion = 0;
      pMap->mmapSize = 0;
      pMap->mmapOrigsize = 0;
    }
  }
}

/*
** Return the system page size somehow.
*/
static int unixGetPagesize(void){
#if HAVE_REMAP
  return 512;
#elif _BSD_SOURCE
  return getpagesize();
#else
  return (int)sysconf(_SC_PAGESIZE);
#endif
}

/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
** is already mapped, the existing mapping is replaced by the new). Or, if 
** there already exists a mapping for this file, and there are still 
** outstanding xFetch() references to it, this function is a no-op.
**
** If parameter nByte is non-negative, then it is the requested size of 
** the mapping to create. Otherwise, if nByte is less than zero, then the 
** requested size is the size of the file on disk. The actual size of the
** created mapping is either the requested size or the value configured 
** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
static int unixMapfile(unixFile *pFd, i64 nByte){
  i64 nMap;                       /* Number of bytes of file to map */
  int rc;

  assert( nMap>=0 || pFd->nFetchOut==0 );
  if( pFd->nFetchOut>0 ) return SQLITE_OK;

  /* Set variable nMap to the number of bytes of the file to map. This is
  ** the smaller of argument nByte and the limit configured by
  ** SQLITE_FCNTL_MMAP_LIMIT. Or, if nByte is less than zero, the smaller
  ** of the file size or the SQLITE_FCNTL_MMAP_LIMIT value.  */
  nMap = nByte;
  if( nMap<0 ){
    struct stat statbuf;          /* Low-level file information */
    rc = osFstat(pFd->h, &statbuf);
    if( rc!=SQLITE_OK ){
      return SQLITE_IOERR_FSTAT;
    }
    nMap = statbuf.st_size;
  }
  if( nMap>pFd->mmapLimit ){
    nMap = pFd->mmapLimit;
  }

  if( nMap!=(pFd->aMmap[0].mmapSize + pFd->aMmap[1].mmapSize) ){


    /* If the request is for a mapping zero bytes in size, or there are 
    ** currently already two mapping regions, or there is already a mapping
    ** region that is not a multiple of the page-size in size, unmap
    ** everything.  */
    if( nMap==0 
#if !HAVE_MREMAP
     || (pFd->aMmap[0].pMapRegion && pFd->aMmap[1].pMapRegion)
     || (pFd->aMmap[0].mmapSize % pFd->szSyspage)

#endif

    ){
      unixUnmapfile(pFd);
    }
    assert( pFd->aMmap[1].pMapRegion==0 );

    if( nMap>0 ){
      unixMapping *pMap = &pFd->aMmap[0];   /* First mapping object */
      void *pNew = 0;
      int iNew = 0;
      int flags = PROT_READ;
      if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;

      /* If there are currently no mappings, create a new one */
      if( pMap->pMapRegion==0 ){
        pNew = osMmap(0, nMap, flags, MAP_SHARED, pFd->h, 0);
      }
#if HAVE_MREMAP
      /* If we have an mremap() call, resize the existing mapping. */
      else{
        pNew = osMremap(
            pMap->pMapRegion, pMap->mmapOrigsize, nMap, MREMAP_MAYMOVE
        );
      }
#else
      /* Otherwise, create a second mapping. If the existing mapping is
      ** a multiple of the page-size in size, then request that the new
      ** mapping immediately follow the old in virtual memory.  */
      else{
        i64 nNew;                 /* Bytes to map with this call */
        void *pAddr = 0;          /* Virtual address to request mapping at */

        nNew = nMap - pMap->mmapSize;
        if( pMap->mmapSize==pMap->mmapOrigsize ){
          pAddr = (void *)&((u8 *)pMap->pMapRegion)[pMap->mmapSize];
        }

        pNew = osMmap(pAddr, nNew, flags, MAP_SHARED, pFd->h, pMap->mmapSize);

        if( pAddr && pNew==pAddr ){
          pNew = pMap->pMapRegion;
        }else{
          iNew = 1;
          nMap = nNew;
        }
      }
#endif

      if( pNew==MAP_FAILED ){
        return SQLITE_IOERR_MMAP;
      }
      pFd->aMmap[iNew].pMapRegion = pNew;
      pFd->aMmap[iNew].mmapSize = nMap;
      pFd->aMmap[iNew].mmapOrigsize = nMap;
    }
  }

  return SQLITE_OK;
}

/*
** If possible, return a pointer to a mapping of file fd starting at offset
4594
4595
4596
4597
4598
4599
4600



4601
4602
4603
4604
4605



4606
4607



4608
4609
4610
4611
4612
4613
4614
** release the reference by calling unixUnfetch().
*/
static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
  unixFile *pFd = (unixFile *)fd;   /* The underlying database file */
  *pp = 0;

  if( pFd->mmapLimit>0 ){



    if( pFd->pMapRegion==0 ){
      int rc = unixMapfile(pFd, -1);
      if( rc!=SQLITE_OK ) return rc;
    }
    if( pFd->mmapSize >= iOff+nAmt ){



      *pp = &((u8 *)pFd->pMapRegion)[iOff];
      pFd->nFetchOut++;



    }
  }
  return SQLITE_OK;
}

/*
** If the third argument is non-NULL, then this function releases a 







>
>
>
|



|
>
>
>
|
|
>
>
>







4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
** release the reference by calling unixUnfetch().
*/
static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
  unixFile *pFd = (unixFile *)fd;   /* The underlying database file */
  *pp = 0;

  if( pFd->mmapLimit>0 ){
    int i;
    sqlite3_int64 iMap = 0;
    
    if( pFd->aMmap[0].pMapRegion==0 ){
      int rc = unixMapfile(pFd, -1);
      if( rc!=SQLITE_OK ) return rc;
    }

    for(i=0; i<2; i++){
      unixMapping *pMap = &pFd->aMmap[i];
      if( iOff>=iMap && iOff+nAmt<=(iMap + pMap->mmapSize) ){
        *pp = &((u8 *)pMap->pMapRegion)[iOff-iMap];
        pFd->nFetchOut++;
        break;
      }
      iMap = pMap->mmapSize;
    }
  }
  return SQLITE_OK;
}

/*
** If the third argument is non-NULL, then this function releases a 
4625
4626
4627
4628
4629
4630
4631

4632

4633
4634
4635
4636
4637
4638
4639

  /* If p==0 (unmap the entire file) then there must be no outstanding 
  ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
  ** then there must be at least one outstanding.  */
  assert( (p==0)==(pFd->nFetchOut==0) );

  /* If p!=0, it must match the iOff value. */

  assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );


  if( p ){
    pFd->nFetchOut--;
  }else{
    unixUnmapfile(pFd);
  }








>

>







4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752

  /* If p==0 (unmap the entire file) then there must be no outstanding 
  ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
  ** then there must be at least one outstanding.  */
  assert( (p==0)==(pFd->nFetchOut==0) );

  /* If p!=0, it must match the iOff value. */
  #if 0
  assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
  #endif

  if( p ){
    pFd->nFetchOut--;
  }else{
    unixUnmapfile(pFd);
  }

5587
5588
5589
5590
5591
5592
5593

5594
5595
5596
5597
5598
5599
5600
        }
      }
      goto open_finished;
    }
  }
#endif
  

  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);

open_finished:
  if( rc!=SQLITE_OK ){
    sqlite3_free(p->pUnused);
  }
  return rc;







>







5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
        }
      }
      goto open_finished;
    }
  }
#endif
  
  p->szSyspage = unixGetPagesize();
  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);

open_finished:
  if( rc!=SQLITE_OK ){
    sqlite3_free(p->pUnused);
  }
  return rc;

Changes to src/pager.c.

3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
/*
** Invoke SQLITE_FCNTL_MMAP_LIMIT based on the current value of mxMmap.
*/
static void pagerFixMaplimit(Pager *pPager){
  sqlite3_file *fd = pPager->fd;
  if( isOpen(fd) ){
    pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->mxMmap>0;
    if( pPager->bUseFetch ){
      sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_LIMIT,
                               (void*)&pPager->mxMmap);
    }
  }
}

/*
** Change the maximum size of any memory mapping made of the database file.
*/
void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 mxMmap){







<
|

<







3356
3357
3358
3359
3360
3361
3362

3363
3364

3365
3366
3367
3368
3369
3370
3371
/*
** Invoke SQLITE_FCNTL_MMAP_LIMIT based on the current value of mxMmap.
*/
static void pagerFixMaplimit(Pager *pPager){
  sqlite3_file *fd = pPager->fd;
  if( isOpen(fd) ){
    pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->mxMmap>0;

    sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_LIMIT,
                               (void*)&pPager->mxMmap);

  }
}

/*
** Change the maximum size of any memory mapping made of the database file.
*/
void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 mxMmap){
3635
3636
3637
3638
3639
3640
3641

3642

3643
3644
3645
3646
3647
3648
3649
** Regardless of mxPage, return the current maximum page count.
*/
int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
  if( mxPage>0 ){
    pPager->mxPgno = mxPage;
  }
  assert( pPager->eState!=PAGER_OPEN );      /* Called only by OP_MaxPgcnt */

  assert( pPager->mxPgno>=pPager->dbSize );  /* OP_MaxPgcnt enforces this */

  return pPager->mxPgno;
}

/*
** The following set of routines are used to disable the simulated
** I/O error mechanism.  These routines are used to avoid simulated
** errors in places where we do not care about errors.







>

>







3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
** Regardless of mxPage, return the current maximum page count.
*/
int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
  if( mxPage>0 ){
    pPager->mxPgno = mxPage;
  }
  assert( pPager->eState!=PAGER_OPEN );      /* Called only by OP_MaxPgcnt */
  #if 0
  assert( pPager->mxPgno>=pPager->dbSize );  /* OP_MaxPgcnt enforces this */
  #endif
  return pPager->mxPgno;
}

/*
** The following set of routines are used to disable the simulated
** I/O error mechanism.  These routines are used to avoid simulated
** errors in places where we do not care about errors.

Changes to src/wal.c.

1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
    /* If more than one frame was recovered from the log file, report an
    ** event via sqlite3_log(). This is to help with identifying performance
    ** problems caused by applications routinely shutting down without
    ** checkpointing the log file.
    */
    if( pWal->hdr.nPage ){
      sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
          pWal->hdr.nPage, pWal->zWalName
      );
    }
  }

recovery_error:
  WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
  walUnlockExclusive(pWal, iLock, nLock);







|







1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
    /* If more than one frame was recovered from the log file, report an
    ** event via sqlite3_log(). This is to help with identifying performance
    ** problems caused by applications routinely shutting down without
    ** checkpointing the log file.
    */
    if( pWal->hdr.nPage ){
      sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
          pWal->hdr.mxFrame, pWal->zWalName
      );
    }
  }

recovery_error:
  WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
  walUnlockExclusive(pWal, iLock, nLock);

Changes to test/autovacuum.test.

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
proc make_str {char len} {
  set str [string repeat $char. $len]
  return [string range $str 0 [expr $len-1]]
}

# Return the number of pages in the file test.db by looking at the file system.
proc file_pages {} {
  return [expr [file size test.db] / 1024]
}

#-------------------------------------------------------------------------
# Test cases autovacuum-1.* work as follows:
#
# 1. A table with a single indexed field is created.
# 2. Approximately 20 rows are inserted into the table. Each row is long 







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
proc make_str {char len} {
  set str [string repeat $char. $len]
  return [string range $str 0 [expr $len-1]]
}

# Return the number of pages in the file test.db by looking at the file system.
proc file_pages {} {
  file_page_count test.db
}

#-------------------------------------------------------------------------
# Test cases autovacuum-1.* work as follows:
#
# 1. A table with a single indexed field is created.
# 2. Approximately 20 rows are inserted into the table. Each row is long 
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 4
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 8
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 16
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 32
  }

  expr {[file size test.db] / 1024}
} {73}

do_test autovacuum-7.2 {
  execsql {
    CREATE TABLE t2(a, b, PRIMARY KEY(a, b));
    INSERT INTO t2 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    CREATE TABLE t3(a, b, PRIMARY KEY(a, b));
    INSERT INTO t3 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    CREATE TABLE t4(a, b, PRIMARY KEY(a, b));
    INSERT INTO t4 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    CREATE TABLE t5(a, b, PRIMARY KEY(a, b));
    INSERT INTO t5 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
  }
  expr {[file size test.db] / 1024}
} {354}

do_test autovacuum-7.3 {
  db close
  sqlite3 db test.db
  execsql {
    BEGIN;
    DELETE FROM t4;
    COMMIT;
    SELECT count(*) FROM t1;
  }
  expr {[file size test.db] / 1024}
} {286}

#------------------------------------------------------------------------
# Additional tests.
#
# Try to determine the autovacuum setting for a database that is locked.
#







|













|











|







610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 4
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 8
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 16
    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 32
  }

  file_page_count test.db
} {73}

do_test autovacuum-7.2 {
  execsql {
    CREATE TABLE t2(a, b, PRIMARY KEY(a, b));
    INSERT INTO t2 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    CREATE TABLE t3(a, b, PRIMARY KEY(a, b));
    INSERT INTO t3 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    CREATE TABLE t4(a, b, PRIMARY KEY(a, b));
    INSERT INTO t4 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    CREATE TABLE t5(a, b, PRIMARY KEY(a, b));
    INSERT INTO t5 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
  }
  file_page_count test.db
} {354}

do_test autovacuum-7.3 {
  db close
  sqlite3 db test.db
  execsql {
    BEGIN;
    DELETE FROM t4;
    COMMIT;
    SELECT count(*) FROM t1;
  }
  file_page_count test.db
} {286}

#------------------------------------------------------------------------
# Additional tests.
#
# Try to determine the autovacuum setting for a database that is locked.
#

Changes to test/backup.test.

657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    INSERT INTO t1 VALUES(3, randstr(1000,1000));
    INSERT INTO t1 VALUES(4, randstr(1000,1000));
    INSERT INTO t1 VALUES(5, randstr(1000,1000));
    COMMIT;
  }
} {}
do_test backup-6.2 {
  set nTotal [expr {[file size test.db]/1024}]
  sqlite3_backup B db2 main db main
  B step 1
} {SQLITE_OK}
do_test backup-6.3 {
  B pagecount
} $nTotal
do_test backup-6.4 {







|







657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    INSERT INTO t1 VALUES(3, randstr(1000,1000));
    INSERT INTO t1 VALUES(4, randstr(1000,1000));
    INSERT INTO t1 VALUES(5, randstr(1000,1000));
    COMMIT;
  }
} {}
do_test backup-6.2 {
  set nTotal [file_page_count test.db]
  sqlite3_backup B db2 main db main
  B step 1
} {SQLITE_OK}
do_test backup-6.3 {
  B pagecount
} $nTotal
do_test backup-6.4 {

Changes to test/backup4.test.

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# Test that if the source is zero bytes, the destination database 
# consists of a single page only.
#
do_execsql_test 2.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a, b);
}
do_test 2.2 { file size test.db } [expr $AUTOVACUUM ? 4096 : 3072]

do_test 2.3 {
  sqlite3 db1 test.db2
  db1 backup test.db
  db1 close
  file size test.db
} {1024}







|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# Test that if the source is zero bytes, the destination database 
# consists of a single page only.
#
do_execsql_test 2.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a, b);
}
do_test 2.2 { file_page_count test.db } [expr $AUTOVACUUM ? 4 : 3]

do_test 2.3 {
  sqlite3 db1 test.db2
  db1 backup test.db
  db1 close
  file size test.db
} {1024}

Changes to test/corrupt2.test.

330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
    PRAGMA page_size = 1024;
    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
    INSERT INTO t1 VALUES(1, randomblob(2500));
    INSERT INTO t1 VALUES(2, randomblob(2500));
    INSERT INTO t1 VALUES(3, randomblob(2500));
    DELETE FROM t1 WHERE a = 1;
  } -corrupt {
    set nPage [expr [file size corrupt.db] / 1024]
    hexio_write corrupt.db [expr 1024 + ($nPage-3)*5] 010000000
  } -test {
    do_test corrupt2-6.3 {
      catchsql " $::presql pragma incremental_vacuum = 1 "
    } {1 {database disk image is malformed}}
  }








|







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
    PRAGMA page_size = 1024;
    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
    INSERT INTO t1 VALUES(1, randomblob(2500));
    INSERT INTO t1 VALUES(2, randomblob(2500));
    INSERT INTO t1 VALUES(3, randomblob(2500));
    DELETE FROM t1 WHERE a = 1;
  } -corrupt {
    set nPage [file_page_count corrupt.db]
    hexio_write corrupt.db [expr 1024 + ($nPage-3)*5] 010000000
  } -test {
    do_test corrupt2-6.3 {
      catchsql " $::presql pragma incremental_vacuum = 1 "
    } {1 {database disk image is malformed}}
  }

Changes to test/corrupt3.test.

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  set bigstring [string repeat 0123456789 200]
  execsql {
    PRAGMA auto_vacuum=OFF;
    PRAGMA page_size=1024;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES($bigstring);
  }
  file size test.db
} [expr {1024*3}]

# Verify that the file format is as we expect.  The page size
# should be 1024 bytes.  The only record should have a single
# overflow page.  The overflow page is page 3.  The pointer to
# the overflow page is on the last 4 bytes of page 2.
#
do_test corrupt3-1.2 {







|
|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  set bigstring [string repeat 0123456789 200]
  execsql {
    PRAGMA auto_vacuum=OFF;
    PRAGMA page_size=1024;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES($bigstring);
  }
  list [file_page_count test.db] [file_page_size test.db]
} {3 1024}

# Verify that the file format is as we expect.  The page size
# should be 1024 bytes.  The only record should have a single
# overflow page.  The overflow page is page 3.  The pointer to
# the overflow page is on the last 4 bytes of page 2.
#
do_test corrupt3-1.2 {

Changes to test/corrupt6.test.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  execsql {
    PRAGMA auto_vacuum=OFF;
    PRAGMA page_size=1024;
    CREATE TABLE t1(x);
    INSERT INTO t1(x) VALUES('varint32-01234567890123456789012345678901234567890123456789');
    INSERT INTO t1(x) VALUES('varint32-01234567890123456789012345678901234567890123456789');
  }
  file size test.db
} [expr {1024*2}]

# Verify that the file format is as we expect.  The page size
# should be 1024 bytes.
#
do_test corrupt6-1.2 {
  hexio_get_int [hexio_read test.db 16 2]
} 1024   ;# The page size is 1024







|
|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  execsql {
    PRAGMA auto_vacuum=OFF;
    PRAGMA page_size=1024;
    CREATE TABLE t1(x);
    INSERT INTO t1(x) VALUES('varint32-01234567890123456789012345678901234567890123456789');
    INSERT INTO t1(x) VALUES('varint32-01234567890123456789012345678901234567890123456789');
  }
  file_page_count test.db
} {2}

# Verify that the file format is as we expect.  The page size
# should be 1024 bytes.
#
do_test corrupt6-1.2 {
  hexio_get_int [hexio_read test.db 16 2]
} 1024   ;# The page size is 1024

Changes to test/corrupt7.test.

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    CREATE TABLE t1(x);
    INSERT INTO t1(x) VALUES(1);
    INSERT INTO t1(x) VALUES(2);
    INSERT INTO t1(x) SELECT x+2 FROM t1;
    INSERT INTO t1(x) SELECT x+4 FROM t1;
    INSERT INTO t1(x) SELECT x+8 FROM t1;
  }
  file size test.db
} [expr {1024*2}]

# Verify that the file format is as we expect.  The page size
# should be 1024 bytes.
#
do_test corrupt7-1.2 {
  hexio_get_int [hexio_read test.db 16 2]
} 1024   ;# The page size is 1024







|
|







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    CREATE TABLE t1(x);
    INSERT INTO t1(x) VALUES(1);
    INSERT INTO t1(x) VALUES(2);
    INSERT INTO t1(x) SELECT x+2 FROM t1;
    INSERT INTO t1(x) SELECT x+4 FROM t1;
    INSERT INTO t1(x) SELECT x+8 FROM t1;
  }
  file_page_count test.db
} {2}

# Verify that the file format is as we expect.  The page size
# should be 1024 bytes.
#
do_test corrupt7-1.2 {
  hexio_get_int [hexio_read test.db 16 2]
} 1024   ;# The page size is 1024

Changes to test/corruptC.test.

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  forcecopy test.bu test.db

  sqlite3 db test.db
  set blob [string repeat abcdefghij 10000]
  execsql { INSERT INTO t1 VALUES (1, $blob) }

  sqlite3 db test.db
  set filesize [file size test.db]
  hexio_write test.db [expr $filesize-2048] 00000001
  catchsql {DELETE FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)}
} {1 {database disk image is malformed}}

# At one point this particular corrupt database was causing a buffer
# overread. Which caused a crash in a run of all.test once.
#







|







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  forcecopy test.bu test.db

  sqlite3 db test.db
  set blob [string repeat abcdefghij 10000]
  execsql { INSERT INTO t1 VALUES (1, $blob) }

  sqlite3 db test.db
  set filesize [expr [file_page_count test.db] * [file_page_size test.db]]
  hexio_write test.db [expr $filesize-2048] 00000001
  catchsql {DELETE FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)}
} {1 {database disk image is malformed}}

# At one point this particular corrupt database was causing a buffer
# overread. Which caused a crash in a run of all.test once.
#

Changes to test/corruptF.test.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
}

do_test 1.1 { create_test_db } {}

# Check the db is as we expect. 6 pages in total, with 3 and 4 on the free
# list. Page 3 is the free list trunk and page 4 is a leaf.
#
do_test 1.2 { file size test.db } [expr 6*1024]
do_test 1.3 { hexio_read test.db 32 4 } 00000003
do_test 1.4 { hexio_read test.db [expr 2*1024] 12 } 000000000000000100000004

# Change the free-list entry to page 6 and reopen the db file.
do_test 1.5 { 
  hexio_write test.db [expr 2*1024 + 8] 00000006 
  sqlite3 db test.db







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
}

do_test 1.1 { create_test_db } {}

# Check the db is as we expect. 6 pages in total, with 3 and 4 on the free
# list. Page 3 is the free list trunk and page 4 is a leaf.
#
do_test 1.2 { file_page_count test.db } 6
do_test 1.3 { hexio_read test.db 32 4 } 00000003
do_test 1.4 { hexio_read test.db [expr 2*1024] 12 } 000000000000000100000004

# Change the free-list entry to page 6 and reopen the db file.
do_test 1.5 { 
  hexio_write test.db [expr 2*1024 + 8] 00000006 
  sqlite3 db test.db
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    }
    set res
  } {}
}
}

do_test 2.1 { create_test_db } {}
do_test 2.2 { file size test.db } [expr 6*1024]
do_test 2.3 { hexio_read test.db 32 4 } 00000003
do_test 2.4 { hexio_read test.db [expr 2*1024] 12 } 000000000000000100000004

# Change the free-list entry to page 5 and reopen the db file.
do_test 2.5 { 
  hexio_write test.db [expr 2*1024 + 8] 00000005 
  sqlite3 db test.db







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    }
    set res
  } {}
}
}

do_test 2.1 { create_test_db } {}
do_test 2.2 { file_page_count test.db } 6
do_test 2.3 { hexio_read test.db 32 4 } 00000003
do_test 2.4 { hexio_read test.db [expr 2*1024] 12 } 000000000000000100000004

# Change the free-list entry to page 5 and reopen the db file.
do_test 2.5 { 
  hexio_write test.db [expr 2*1024 + 8] 00000005 
  sqlite3 db test.db

Changes to test/crash.test.

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);   -- Overflow page 4
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
  }
} {}
do_test crash-5.2 {
  expr [file size test.db] / 1024
} [expr [string match [execsql {pragma auto_vacuum}] 1] ? 11 : 10]
set sig [signature]
do_test crash-5.3 {
# The SQL below is used to expose a bug that existed in
# sqlite3pager_movepage() during development of the auto-vacuum feature. It
# functions as follows:
# 







|







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);   -- Overflow page 4
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
  }
} {}
do_test crash-5.2 {
  file_page_count test.db
} [expr [string match [execsql {pragma auto_vacuum}] 1] ? 11 : 10]
set sig [signature]
do_test crash-5.3 {
# The SQL below is used to expose a bug that existed in
# sqlite3pager_movepage() during development of the auto-vacuum feature. It
# functions as follows:
# 

Changes to test/createtab.test.

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

  set isUtf16 0
  ifcapable utf16 { 
    set isUtf16 [expr {[execsql {PRAGMA encoding}] != "UTF-8"}]
  }

  do_test createtab-$av.2 {
    file size test.db
  } [expr {1024*(4+($av!=0)+(${isUtf16}*2))}]
  
  # Start reading the table
  #
  do_test createtab-$av.3 {
    set STMT [sqlite3_prepare db {SELECT x FROM t1} -1 TAIL]
    sqlite3_step $STMT
  } {SQLITE_ROW}







|
|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

  set isUtf16 0
  ifcapable utf16 { 
    set isUtf16 [expr {[execsql {PRAGMA encoding}] != "UTF-8"}]
  }

  do_test createtab-$av.2 {
    file_page_count test.db
  } [expr {4+($av!=0)+(${isUtf16}*2)}]
  
  # Start reading the table
  #
  do_test createtab-$av.3 {
    set STMT [sqlite3_prepare db {SELECT x FROM t1} -1 TAIL]
    sqlite3_step $STMT
  } {SQLITE_ROW}

Changes to test/dbstatus2.test.

16
17
18
19
20
21
22

23
24
25
26
27
28
29
source $testdir/tester.tcl

set ::testprefix dbstatus2

do_execsql_test 1.0 {
  PRAGMA page_size = 1024;
  PRAGMA auto_vacuum = 0;


  CREATE TABLE t1(a PRIMARY KEY, b);
  INSERT INTO t1 VALUES(1, randomblob(600));
  INSERT INTO t1 VALUES(2, randomblob(600));
  INSERT INTO t1 VALUES(3, randomblob(600));
}








>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
source $testdir/tester.tcl

set ::testprefix dbstatus2

do_execsql_test 1.0 {
  PRAGMA page_size = 1024;
  PRAGMA auto_vacuum = 0;
  PRAGMA mmap_limit = 0;

  CREATE TABLE t1(a PRIMARY KEY, b);
  INSERT INTO t1 VALUES(1, randomblob(600));
  INSERT INTO t1 VALUES(2, randomblob(600));
  INSERT INTO t1 VALUES(3, randomblob(600));
}

Changes to test/e_vacuum.test.

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
      INSERT INTO t1 SELECT a+64, randomblob(400) FROM t1;

      CREATE TABLE t2(a PRIMARY KEY, b UNIQUE);
      INSERT INTO t2 SELECT * FROM t1;
    }
  }

  return [expr {[file size test.db] / 1024}]
}

# This proc returns the number of contiguous blocks of pages that make up
# the table or index named by the only argument. For example, if the table
# occupies database pages 3, 4, 8 and 9, then this command returns 2 (there
# are 2 fragments - one consisting of pages 3 and 4, the other of fragments
# 8 and 9).







|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
      INSERT INTO t1 SELECT a+64, randomblob(400) FROM t1;

      CREATE TABLE t2(a PRIMARY KEY, b UNIQUE);
      INSERT INTO t2 SELECT * FROM t1;
    }
  }

  return [file_page_count test.db]
}

# This proc returns the number of contiguous blocks of pages that make up
# the table or index named by the only argument. For example, if the table
# occupies database pages 3, 4, 8 and 9, then this command returns 2 (there
# are 2 fragments - one consisting of pages 3 and 4, the other of fragments
# 8 and 9).

Changes to test/filefmt.test.

61
62
63
64
65
66
67

68
69
70
71
72
73
74
  foreach pagesize {512 1024 2048 4096 8192 16384 32768} {
     if {[info exists SQLITE_MAX_PAGE_SIZE]
          && $pagesize>$SQLITE_MAX_PAGE_SIZE} continue
     do_test filefmt-1.5.$pagesize.1 {
       db close
       forcedelete test.db
       sqlite3 db test.db

       db eval "PRAGMA auto_vacuum=OFF"
       db eval "PRAGMA page_size=$pagesize"
       db eval {CREATE TABLE t1(x)}
       file size test.db
     } [expr $pagesize*2]
     do_test filefmt-1.5.$pagesize.2 {
       hexio_get_int [hexio_read test.db 16 2]







>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  foreach pagesize {512 1024 2048 4096 8192 16384 32768} {
     if {[info exists SQLITE_MAX_PAGE_SIZE]
          && $pagesize>$SQLITE_MAX_PAGE_SIZE} continue
     do_test filefmt-1.5.$pagesize.1 {
       db close
       forcedelete test.db
       sqlite3 db test.db
       db eval "PRAGMA mmap_limit=0"
       db eval "PRAGMA auto_vacuum=OFF"
       db eval "PRAGMA page_size=$pagesize"
       db eval {CREATE TABLE t1(x)}
       file size test.db
     } [expr $pagesize*2]
     do_test filefmt-1.5.$pagesize.2 {
       hexio_get_int [hexio_read test.db 16 2]
211
212
213
214
215
216
217

218
219
220
221
222
223
224
do_execsql_test filefmt-3.3 {
  SELECT * FROM sqlite_master;
  PRAGMA integrity_check;
} {ok}

reset_db
do_execsql_test filefmt-4.1 {

  PRAGMA auto_vacuum = 1;
  CREATE TABLE t1(x, y);
  CREATE TABLE t2(x, y);

  INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
  INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
  INSERT INTO t1 VALUES(randomblob(100), randomblob(100));







>







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
do_execsql_test filefmt-3.3 {
  SELECT * FROM sqlite_master;
  PRAGMA integrity_check;
} {ok}

reset_db
do_execsql_test filefmt-4.1 {
  PRAGMA mmap_limit = 0;
  PRAGMA auto_vacuum = 1;
  CREATE TABLE t1(x, y);
  CREATE TABLE t2(x, y);

  INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
  INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
  INSERT INTO t1 VALUES(randomblob(100), randomblob(100));

Changes to test/format4.test.

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
  }
  file size test.db
} $small
do_test format4-1.2 {
  execsql {
    UPDATE t1 SET x0=1, x1=1, x2=1, x3=1, x4=1, x5=1, x6=1, x7=1, x8=1, x9=1
  }
  file size test.db
} $small
do_test format4-1.3 {
  execsql {
    UPDATE t1 SET x0=2, x1=2, x2=2, x3=2, x4=2, x5=2, x6=2, x7=2, x8=2, x9=2
  }
  file size test.db
} $large


finish_test







|





|





|




42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
  }
  expr {1024 * [file_page_count test.db]}
} $small
do_test format4-1.2 {
  execsql {
    UPDATE t1 SET x0=1, x1=1, x2=1, x3=1, x4=1, x5=1, x6=1, x7=1, x8=1, x9=1
  }
  expr {1024 * [file_page_count test.db]}
} $small
do_test format4-1.3 {
  execsql {
    UPDATE t1 SET x0=2, x1=2, x2=2, x3=2, x4=2, x5=2, x6=2, x7=2, x8=2, x9=2
  }
  expr {1024 * [file_page_count test.db]}
} $large


finish_test

Changes to test/incrblob.test.

615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
    INSERT INTO t2 VALUES(456, $::otherdata);
  }
  set ::b [db incrblob -readonly t2 b 456]
  fconfigure $::b -translation binary
  read $::b
} $::otherdata
do_test incrblob-7.3.2 {
  expr [file size test.db]/1024
} 30
do_test incrblob-7.3.3 {
  execsql {
    DELETE FROM t1 WHERE a = 123;
    PRAGMA INCREMENTAL_VACUUM(0);
  }
  seek $::b 0







|







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
    INSERT INTO t2 VALUES(456, $::otherdata);
  }
  set ::b [db incrblob -readonly t2 b 456]
  fconfigure $::b -translation binary
  read $::b
} $::otherdata
do_test incrblob-7.3.2 {
  file_page_count test.db
} 30
do_test incrblob-7.3.3 {
  execsql {
    DELETE FROM t1 WHERE a = 123;
    PRAGMA INCREMENTAL_VACUUM(0);
  }
  seek $::b 0

Changes to test/incrvacuum.test.

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  #
  #   1 -> database header
  #   2 -> first back-pointer page
  #   3 -> table abc
  #   4 -> table tbl2
  #   5 -> table tbl2 overflow page.
  #
  expr {[file size test.db] / 1024}
} {5}
do_test incrvacuum-3.3 {
  execsql {
    DROP TABLE abc;
    DELETE FROM tbl2;
  }
  expr {[file size test.db] / 1024}
} {5}
do_test incrvacuum-3.4 {
  execsql {
    PRAGMA auto_vacuum = 1;
    INSERT INTO tbl2 VALUES('hello world');
  }
  expr {[file size test.db] / 1024}
} {3}

#---------------------------------------------------------------------
# Try to run a very simple incremental vacuum. Also verify that 
# PRAGMA incremental_vacuum is a harmless no-op against a database that
# does not support auto-vacuum.
#
do_test incrvacuum-4.1 {
  set ::str [string repeat 1234567890 110]
  execsql {
    PRAGMA auto_vacuum = 2;
    INSERT INTO tbl2 VALUES($::str);
    CREATE TABLE tbl1(a, b, c);
  }
  expr {[file size test.db] / 1024}
} {5}
do_test incrvacuum-4.2 {
  execsql {
    DELETE FROM tbl2;
    DROP TABLE tbl1;
  }
  expr {[file size test.db] / 1024}
} {5}
do_test incrvacuum-4.3 {
  set ::nStep 0
  db eval {pragma incremental_vacuum(10)} {
    incr ::nStep
  }
  list [expr {[file size test.db] / 1024}] $::nStep







|






|






|














|






|







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  #
  #   1 -> database header
  #   2 -> first back-pointer page
  #   3 -> table abc
  #   4 -> table tbl2
  #   5 -> table tbl2 overflow page.
  #
  file_page_count test.db
} {5}
do_test incrvacuum-3.3 {
  execsql {
    DROP TABLE abc;
    DELETE FROM tbl2;
  }
  file_page_count test.db
} {5}
do_test incrvacuum-3.4 {
  execsql {
    PRAGMA auto_vacuum = 1;
    INSERT INTO tbl2 VALUES('hello world');
  }
  file_page_count test.db
} {3}

#---------------------------------------------------------------------
# Try to run a very simple incremental vacuum. Also verify that 
# PRAGMA incremental_vacuum is a harmless no-op against a database that
# does not support auto-vacuum.
#
do_test incrvacuum-4.1 {
  set ::str [string repeat 1234567890 110]
  execsql {
    PRAGMA auto_vacuum = 2;
    INSERT INTO tbl2 VALUES($::str);
    CREATE TABLE tbl1(a, b, c);
  }
  file_page_count test.db
} {5}
do_test incrvacuum-4.2 {
  execsql {
    DELETE FROM tbl2;
    DROP TABLE tbl1;
  }
  file_page_count test.db
} {5}
do_test incrvacuum-4.3 {
  set ::nStep 0
  db eval {pragma incremental_vacuum(10)} {
    incr ::nStep
  }
  list [expr {[file size test.db] / 1024}] $::nStep
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  execsql {
    BEGIN;
    CREATE TABLE tbl1(a);
    INSERT INTO tbl1 VALUES($::str);
    PRAGMA incremental_vacuum;                 -- this is a no-op.
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {4}
do_test incrvacuum-5.2.2 {
  set ::str [string repeat abcdefghij 110]
  execsql {
    BEGIN;
    INSERT INTO tbl1 VALUES($::str);
    INSERT INTO tbl1 SELECT * FROM tbl1;
    DELETE FROM tbl1 WHERE oid%2;        -- Put 2 overflow pages on free-list.
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {7}
do_test incrvacuum-5.2.3 {
  execsql {
    BEGIN;
    PRAGMA incremental_vacuum;           -- Vacuum up the two pages.
    CREATE TABLE tbl2(b);                -- Use one free page as a table root.
    INSERT INTO tbl2 VALUES('a nice string');
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {6}
do_test incrvacuum-5.2.4 {
  execsql {
    SELECT * FROM tbl2;
  }
} {{a nice string}}
do_test incrvacuum-5.2.5 {
  execsql {
    DROP TABLE tbl1;
    DROP TABLE tbl2;
    PRAGMA incremental_vacuum;
  }
  expr {[file size test.db] / 1024}
} {1}


# Test cases incrvacuum-5.3.* use the following list as input data.
# Two new databases are opened, one with incremental vacuum enabled,
# the other with no auto-vacuum completely disabled. After executing
# each element of the following list on both databases, test that







|










|









|












|







217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  execsql {
    BEGIN;
    CREATE TABLE tbl1(a);
    INSERT INTO tbl1 VALUES($::str);
    PRAGMA incremental_vacuum;                 -- this is a no-op.
    COMMIT;
  }
  file_page_count test.db
} {4}
do_test incrvacuum-5.2.2 {
  set ::str [string repeat abcdefghij 110]
  execsql {
    BEGIN;
    INSERT INTO tbl1 VALUES($::str);
    INSERT INTO tbl1 SELECT * FROM tbl1;
    DELETE FROM tbl1 WHERE oid%2;        -- Put 2 overflow pages on free-list.
    COMMIT;
  }
  file_page_count test.db
} {7}
do_test incrvacuum-5.2.3 {
  execsql {
    BEGIN;
    PRAGMA incremental_vacuum;           -- Vacuum up the two pages.
    CREATE TABLE tbl2(b);                -- Use one free page as a table root.
    INSERT INTO tbl2 VALUES('a nice string');
    COMMIT;
  }
  file_page_count test.db
} {6}
do_test incrvacuum-5.2.4 {
  execsql {
    SELECT * FROM tbl2;
  }
} {{a nice string}}
do_test incrvacuum-5.2.5 {
  execsql {
    DROP TABLE tbl1;
    DROP TABLE tbl2;
    PRAGMA incremental_vacuum;
  }
  file_page_count test.db
} {1}


# Test cases incrvacuum-5.3.* use the following list as input data.
# Two new databases are opened, one with incremental vacuum enabled,
# the other with no auto-vacuum completely disabled. After executing
# each element of the following list on both databases, test that
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
# N pages are vacuumed.
#
do_test incrvacuum-10.1 {
  execsql {
    DROP TABLE t1;
    DROP TABLE t2;
  }
  expr [file size test.db] / 1024
} {29}

do_test incrvacuum-10.2 {
  execsql {
    PRAGMA incremental_vacuum(1);
  }
  expr [file size test.db] / 1024







|







523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
# N pages are vacuumed.
#
do_test incrvacuum-10.1 {
  execsql {
    DROP TABLE t1;
    DROP TABLE t2;
  }
  file_page_count test.db
} {29}

do_test incrvacuum-10.2 {
  execsql {
    PRAGMA incremental_vacuum(1);
  }
  expr [file size test.db] / 1024

Changes to test/io.test.

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
    # size may be a little less than that. So this test case just tests
    # that the file is now greater than 20000 bytes in size.
    list [expr [file size test.db]>20000] [nSync]
  } {1 0}
  do_test io-3.3 {
    # The COMMIT requires a single fsync() - to the database file.
    execsql { COMMIT }
    list [file size test.db] [nSync]
  } {39936 1}
}

#----------------------------------------------------------------------
# Test cases io-4.* test the IOCAP_SAFE_APPEND optimization.
#
sqlite3_simulate_device -char safe_append








|
|







414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
    # size may be a little less than that. So this test case just tests
    # that the file is now greater than 20000 bytes in size.
    list [expr [file size test.db]>20000] [nSync]
  } {1 0}
  do_test io-3.3 {
    # The COMMIT requires a single fsync() - to the database file.
    execsql { COMMIT }
    list [file_page_count test.db] [nSync]
  } {39 1}
}

#----------------------------------------------------------------------
# Test cases io-4.* test the IOCAP_SAFE_APPEND optimization.
#
sqlite3_simulate_device -char safe_append

484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
  }
  expr {[file size test.db]/1024}
} {43}
ifcapable pager_pragmas {
  do_test io-4.3.2 {
    execsql {
      PRAGMA synchronous = full;
      PRAGMA cache_size = 10;
      PRAGMA synchronous;







|







484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
    INSERT INTO abc SELECT * FROM abc;
  }
  file_page_count test.db
} {43}
ifcapable pager_pragmas {
  do_test io-4.3.2 {
    execsql {
      PRAGMA synchronous = full;
      PRAGMA cache_size = 10;
      PRAGMA synchronous;
558
559
560
561
562
563
564


565
566
567
568
569
    if {[regexp {^atomic} $char]} continue
  }
  do_test io-5.$tn {
    execsql {
      CREATE TABLE abc(a, b, c);
    }
    expr {[file size test.db]/2}


  } $pgsize
}

sqlite3_simulate_device -char {} -sectorsize 0
finish_test







>
>
|




558
559
560
561
562
563
564
565
566
567
568
569
570
571
    if {[regexp {^atomic} $char]} continue
  }
  do_test io-5.$tn {
    execsql {
      CREATE TABLE abc(a, b, c);
    }
    expr {[file size test.db]/2}

    list [file_page_count test.db] [file_page_size test.db]
  } [list 2 $pgsize]
}

sqlite3_simulate_device -char {} -sectorsize 0
finish_test

Changes to test/jrnlmode.test.

517
518
519
520
521
522
523
524


525
526
527
528
529
530
531
      PRAGMA journal_mode = memory;
      PRAGMA auto_vacuum = 0;
      PRAGMA page_size = 1024;
      PRAGMA user_version = 5;
      PRAGMA user_version;
    }
  } {memory 5}
  do_test jrnlmode-7.2 { file size test.db } {1024}


}

do_execsql_test jrnlmode-8.1  { PRAGMA locking_mode=EXCLUSIVE } {exclusive}
do_execsql_test jrnlmode-8.2  { CREATE TABLE t1(x) }            {}
do_execsql_test jrnlmode-8.3  { INSERT INTO t1 VALUES(123) }    {}
do_execsql_test jrnlmode-8.4  { SELECT * FROM t1 }              {123}
do_execsql_test jrnlmode-8.5  { PRAGMA journal_mode=PERSIST }   {persist}







|
>
>







517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
      PRAGMA journal_mode = memory;
      PRAGMA auto_vacuum = 0;
      PRAGMA page_size = 1024;
      PRAGMA user_version = 5;
      PRAGMA user_version;
    }
  } {memory 5}
  do_test jrnlmode-7.2 { 
    list [file_page_count test.db] [file_page_size test.db]
  } {1 1024}
}

do_execsql_test jrnlmode-8.1  { PRAGMA locking_mode=EXCLUSIVE } {exclusive}
do_execsql_test jrnlmode-8.2  { CREATE TABLE t1(x) }            {}
do_execsql_test jrnlmode-8.3  { INSERT INTO t1 VALUES(123) }    {}
do_execsql_test jrnlmode-8.4  { SELECT * FROM t1 }              {123}
do_execsql_test jrnlmode-8.5  { PRAGMA journal_mode=PERSIST }   {persist}

Changes to test/lock4.test.

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  forcedelete test2.db test2.db-journal
  sqlite3 db2 test2.db
  db2 eval {
     PRAGMA auto_vacuum=OFF;
     CREATE TABLE t2(x)
  }
  db2 close
  list [file size test.db] [file size test2.db]
} {2048 2048}

# Create a script to drive a separate process that will
#
#     1.  Create a second database test2.db
#     2.  Get an exclusive lock on test2.db
#     3.  Add an entry to test.db in table t1, waiting as necessary.
#     4.  Commit the change to test2.db.







|
|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  forcedelete test2.db test2.db-journal
  sqlite3 db2 test2.db
  db2 eval {
     PRAGMA auto_vacuum=OFF;
     CREATE TABLE t2(x)
  }
  db2 close
  list [file_page_count test.db] [file_page_count test2.db]
} {2 2}

# Create a script to drive a separate process that will
#
#     1.  Create a second database test2.db
#     2.  Get an exclusive lock on test2.db
#     3.  Add an entry to test.db in table t1, waiting as necessary.
#     4.  Commit the change to test2.db.

Changes to test/mallocH.test.

58
59
60
61
62
63
64

65
66
67
68
69
70
71
     EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid=1;
  }
}

# Malloc failure during integrity_check pragma.
#
do_malloc_test mallocH-5 -sqlprep {

   CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
   CREATE TABLE t2(x,y);
   INSERT INTO t1 VALUES(1,2);
   INSERT INTO t2 SELECT * FROM t1;
} -sqlbody {
   PRAGMA integrity_check;
}







>







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
     EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid=1;
  }
}

# Malloc failure during integrity_check pragma.
#
do_malloc_test mallocH-5 -sqlprep {
   PRAGMA mmap_limit = 0;
   CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
   CREATE TABLE t2(x,y);
   INSERT INTO t1 VALUES(1,2);
   INSERT INTO t2 SELECT * FROM t1;
} -sqlbody {
   PRAGMA integrity_check;
}

Changes to test/pager1.test.

1105
1106
1107
1108
1109
1110
1111

1112
1113
1114
1115
1116
1117
1118

#-------------------------------------------------------------------------
# The following tests work with "PRAGMA max_page_count"
#
do_test pager1-6.1 {
  faultsim_delete_and_reopen
  execsql {

    PRAGMA auto_vacuum = none;
    PRAGMA max_page_count = 10;
    CREATE TABLE t2(a, b);
    CREATE TABLE t3(a, b);
    CREATE TABLE t4(a, b);
    CREATE TABLE t5(a, b);
    CREATE TABLE t6(a, b);







>







1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119

#-------------------------------------------------------------------------
# The following tests work with "PRAGMA max_page_count"
#
do_test pager1-6.1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA page_size = 4096;
    PRAGMA auto_vacuum = none;
    PRAGMA max_page_count = 10;
    CREATE TABLE t2(a, b);
    CREATE TABLE t3(a, b);
    CREATE TABLE t4(a, b);
    CREATE TABLE t5(a, b);
    CREATE TABLE t6(a, b);
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  B step 30
  list [B step 10000] [B finish]
} {SQLITE_DONE SQLITE_OK}
do_test pager1-9.3.3 {
  db2 close
  db close
  tv delete
  file size test.db2
} [file size test.db]

do_test pager1-9.4.1 {
  faultsim_delete_and_reopen
  sqlite3 db2 test.db2
  execsql {
    PRAGMA page_size = 4096;
    CREATE TABLE t1(a, b);







|
|







1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
  B step 30
  list [B step 10000] [B finish]
} {SQLITE_DONE SQLITE_OK}
do_test pager1-9.3.3 {
  db2 close
  db close
  tv delete
  file_page_count test.db2
} [file_page_count test.db]

do_test pager1-9.4.1 {
  faultsim_delete_and_reopen
  sqlite3 db2 test.db2
  execsql {
    PRAGMA page_size = 4096;
    CREATE TABLE t1(a, b);
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
  file size test.db
} {32768}
do_test pager1.10.x.2 {
  execsql {
    CREATE TABLE t2(x);
    DROP TABLE t2;
  }
  file size test.db
} {33792}
do_test pager1.10.x.3 {
  execsql {
    BEGIN;
    CREATE TABLE t2(x);
  }
  recursive_select 30 t1
  execsql {







|
|







1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
  file size test.db
} {32768}
do_test pager1.10.x.2 {
  execsql {
    CREATE TABLE t2(x);
    DROP TABLE t2;
  }
  list [file_page_count test.db] [file_page_size test.db]
} {33 1024}
do_test pager1.10.x.3 {
  execsql {
    BEGIN;
    CREATE TABLE t2(x);
  }
  recursive_select 30 t1
  execsql {
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562

  do_test pager1-12.$pagesize.1 {
    sqlite3 db2 test.db
    execsql "
      PRAGMA page_size = $pagesize;
      CREATE VIEW v AS SELECT * FROM sqlite_master;
    " db2
    file size test.db
  } $eff
  do_test pager1-12.$pagesize.2 {
    sqlite3 db2 test.db
    execsql { 
      SELECT count(*) FROM v;
      PRAGMA main.page_size;
    } db2







|







1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563

  do_test pager1-12.$pagesize.1 {
    sqlite3 db2 test.db
    execsql "
      PRAGMA page_size = $pagesize;
      CREATE VIEW v AS SELECT * FROM sqlite_master;
    " db2
    file_page_size test.db
  } $eff
  do_test pager1-12.$pagesize.2 {
    sqlite3 db2 test.db
    execsql { 
      SELECT count(*) FROM v;
      PRAGMA main.page_size;
    } db2
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA auto_vacuum = full;
    PRAGMA locking_mode=exclusive;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
  }
  file size test.db
} [expr 1024*3]
do_test pager1-29.2 {
  execsql {
    PRAGMA page_size = 4096;
    VACUUM;
  }
  file size test.db
} [expr 4096*3]

#-------------------------------------------------------------------------
# Test that if an empty database file (size 0 bytes) is opened in 
# exclusive-locking mode, any journal file is deleted from the file-system
# without being rolled back. And that the RESERVED lock obtained while
# doing this is not released.
#







|
|





|
|







2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA auto_vacuum = full;
    PRAGMA locking_mode=exclusive;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
  }
  list [file_page_count test.db] [file_page_size test.db]
} {3 1024}
do_test pager1-29.2 {
  execsql {
    PRAGMA page_size = 4096;
    VACUUM;
  }
  list [file_page_count test.db] [file_page_size test.db]
} {3 4096}

#-------------------------------------------------------------------------
# Test that if an empty database file (size 0 bytes) is opened in 
# exclusive-locking mode, any journal file is deleted from the file-system
# without being rolled back. And that the RESERVED lock obtained while
# doing this is not released.
#

Changes to test/pagerfault.test.

1197
1198
1199
1200
1201
1202
1203

1204
1205
1206

1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
  }
} -test {
  faultsim_test_result {0 {}}

  set contents [db eval {SELECT * FROM t1}]
  if {$contents != "1 2"} { error "Bad database contents ($contents)" }


  set sz [file size test.db]
  if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { 
    error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes"

  }
  if {$testrc==0 && $sz!=4096*3} { 
    error "Expected file size to be 12288 bytes - actual size $sz bytes"
  }
} 

do_test pagerfault-27-pre {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {







>
|
|
<
>

|
|







1197
1198
1199
1200
1201
1202
1203
1204
1205
1206

1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
  }
} -test {
  faultsim_test_result {0 {}}

  set contents [db eval {SELECT * FROM t1}]
  if {$contents != "1 2"} { error "Bad database contents ($contents)" }

  set nPg [file_page_count test.db]
  set pgsz [file_page_size test.db]
  if {$testrc!=0 && ($nPg!=3 || ($pgsz!=1024 && $pgsz!=4096))} {

    error "File should be 3 pages. Page size 1024 or 4096 bytes. Is $nPg/$pgsz."
  }
  if {$testrc==0 && ($nPg!=3 || $pgsz!=4096)} {
    error "File should be 3 pages. Page size 4096 bytes. Is $nPg/$pgsz."
  }
} 

do_test pagerfault-27-pre {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {

Changes to test/pagesize.test.

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
    db close
    sqlite3 db test.db
    execsql {
      PRAGMA page_size
    }
  } $PGSZ
  do_test pagesize-2.$PGSZ.3 {
    file size test.db
  } [expr {$PGSZ*($AUTOVACUUM?3:2)}]
  ifcapable {vacuum} {
    do_test pagesize-2.$PGSZ.4 {
      execsql {VACUUM}
    } {}
  }
  integrity_check pagesize-2.$PGSZ.5
  do_test pagesize-2.$PGSZ.6 {







|
|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
    db close
    sqlite3 db test.db
    execsql {
      PRAGMA page_size
    }
  } $PGSZ
  do_test pagesize-2.$PGSZ.3 {
    list [file_page_count test.db] [file_page_size test.db]
  } [list [expr ($AUTOVACUUM?3:2)] $PGSZ]
  ifcapable {vacuum} {
    do_test pagesize-2.$PGSZ.4 {
      execsql {VACUUM}
    } {}
  }
  integrity_check pagesize-2.$PGSZ.5
  do_test pagesize-2.$PGSZ.6 {

Changes to test/permutations.test.

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
]

test_suite "full" -prefix "" -description {
  Full test suite. Takes a long time.
} -files [ 
  test_set $alltests 
] -initialize {
  unset -nocomplain ::G(isquick)
}

test_suite "threads" -prefix "" -description {
  All multi-threaded tests.
} -files {
  notify2.test   thread001.test thread002.test thread003.test 
  thread004.test thread005.test walthread.test







|







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
]

test_suite "full" -prefix "" -description {
  Full test suite. Takes a long time.
} -files [ 
  test_set $alltests 
] -initialize {
  # unset -nocomplain ::G(isquick)
}

test_suite "threads" -prefix "" -description {
  All multi-threaded tests.
} -files {
  notify2.test   thread001.test thread002.test thread003.test 
  thread004.test thread005.test walthread.test

Changes to test/pragma.test.

258
259
260
261
262
263
264

265
266
267
268
269
270
271
# These tests won't work if the database is encrypted
#
do_test pragma-3.1 {
  db close
  forcedelete test.db test.db-journal
  sqlite3 db test.db
  execsql {

    PRAGMA auto_vacuum=OFF;
    BEGIN;
    CREATE TABLE t2(a,b,c);
    CREATE INDEX i2 ON t2(a);
    INSERT INTO t2 VALUES(11,2,3);
    INSERT INTO t2 VALUES(22,3,4);
    COMMIT;







>







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# These tests won't work if the database is encrypted
#
do_test pragma-3.1 {
  db close
  forcedelete test.db test.db-journal
  sqlite3 db test.db
  execsql {
    PRAGMA mmap_limit=0;
    PRAGMA auto_vacuum=OFF;
    BEGIN;
    CREATE TABLE t2(a,b,c);
    CREATE INDEX i2 ON t2(a);
    INSERT INTO t2 VALUES(11,2,3);
    INSERT INTO t2 VALUES(22,3,4);
    COMMIT;
280
281
282
283
284
285
286

287
288
289
290
291
292
293
      # overwrite the header on the rootpage of the index in order to
      # make the index appear to be empty.
      #
      set offset [expr {$pgsz*($rootpage-1)}]
      hexio_write test.db $offset 0a00000000040000000000
      db close
      sqlite3 db test.db

      execsql {PRAGMA integrity_check}
    } {{rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.3 {
      execsql {PRAGMA integrity_check=1}
    } {{rowid 1 missing from index i2}}
    do_test pragma-3.4 {
      execsql {







>







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
      # overwrite the header on the rootpage of the index in order to
      # make the index appear to be empty.
      #
      set offset [expr {$pgsz*($rootpage-1)}]
      hexio_write test.db $offset 0a00000000040000000000
      db close
      sqlite3 db test.db
      execsql {PRAGMA mmap_limit=0}
      execsql {PRAGMA integrity_check}
    } {{rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.3 {
      execsql {PRAGMA integrity_check=1}
    } {{rowid 1 missing from index i2}}
    do_test pragma-3.4 {
      execsql {
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
  } {3}
  do_test pragma-14.3uc {
    execsql {pragma PAGE_COUNT}
  } {3}

  do_test pragma-14.4 {
    set page_size [db one {pragma page_size}]
    expr [file size test.db] / $page_size
  } {2}

  do_test pragma-14.5 {
    execsql {
      ROLLBACK;
      PRAGMA page_count;
    }
  } {2}







|
|







1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
  } {3}
  do_test pragma-14.3uc {
    execsql {pragma PAGE_COUNT}
  } {3}

  do_test pragma-14.4 {
    set page_size [db one {pragma page_size}]
    list [file_page_count test.db] $page_size
  } [list 2 [file_page_size test.db]]

  do_test pragma-14.5 {
    execsql {
      ROLLBACK;
      PRAGMA page_count;
    }
  } {2}

Changes to test/pragma2.test.

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    set ::val [string repeat 0123456789 1000]
    execsql {
      INSERT INTO aux.abc VALUES(1, 2, $::val);
      PRAGMA aux.freelist_count;
    }
  } {0}
  do_test pragma2-2.4 {
    expr {[file size test2.db] / 1024}
  } {11}
  do_test pragma2-2.5 {
    execsql {
      DELETE FROM aux.abc;
      PRAGMA aux.freelist_count;
    }
  } {9}
  







|
|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    set ::val [string repeat 0123456789 1000]
    execsql {
      INSERT INTO aux.abc VALUES(1, 2, $::val);
      PRAGMA aux.freelist_count;
    }
  } {0}
  do_test pragma2-2.4 {
    list [file_page_count test2.db] [file_page_size test2.db]
  } {11 1024}
  do_test pragma2-2.5 {
    execsql {
      DELETE FROM aux.abc;
      PRAGMA aux.freelist_count;
    }
  } {9}
  

Changes to test/quota.test.

67
68
69
70
71
72
73

74
75
76
77
78
79
80

do_test quota-2.1.1 {
  sqlite3_quota_set *test.db 4096 quota_check
} {SQLITE_OK}
do_test quota-2.1.2 {
  sqlite3 db test.db
  execsql {

    PRAGMA page_size=1024;
    PRAGMA auto_vacuum=OFF;
    PRAGMA journal_mode=DELETE;
  }
  set ::quota [list]
  execsql {
    CREATE TABLE t1(a, b);







>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

do_test quota-2.1.1 {
  sqlite3_quota_set *test.db 4096 quota_check
} {SQLITE_OK}
do_test quota-2.1.2 {
  sqlite3 db test.db
  execsql {
    PRAGMA mmap_limit=0;
    PRAGMA page_size=1024;
    PRAGMA auto_vacuum=OFF;
    PRAGMA journal_mode=DELETE;
  }
  set ::quota [list]
  execsql {
    CREATE TABLE t1(a, b);
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
  forcedelete test.db
  sqlite3_quota_initialize "" 1
  sqlite3_quota_set *test.db 4096 quota_check
} {SQLITE_OK}
do_test quota-3.1.2 {
  sqlite3 db test.db
  execsql {

    PRAGMA page_size = 1024;
    PRAGMA journal_mode = delete;
    PRAGMA auto_vacuum = off;
    CREATE TABLE t1(a PRIMARY KEY, b);
    INSERT INTO t1 VALUES(1, 'one');
  }
  file size test.db
} {3072}
do_test quota-3.1.3 {
  sqlite3 db2 test.db
  set ::quota [list]

  execsql { CREATE TABLE t2(a, b) } db2
  set ::quota
} {}
do_test quota-3.1.4 {
  catchsql { CREATE TABLE t3(a, b) }
} {1 {database or disk is full}}
do_test quota-3.1.5 {







>











>







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  forcedelete test.db
  sqlite3_quota_initialize "" 1
  sqlite3_quota_set *test.db 4096 quota_check
} {SQLITE_OK}
do_test quota-3.1.2 {
  sqlite3 db test.db
  execsql {
    PRAGMA mmap_limit = 0;
    PRAGMA page_size = 1024;
    PRAGMA journal_mode = delete;
    PRAGMA auto_vacuum = off;
    CREATE TABLE t1(a PRIMARY KEY, b);
    INSERT INTO t1 VALUES(1, 'one');
  }
  file size test.db
} {3072}
do_test quota-3.1.3 {
  sqlite3 db2 test.db
  set ::quota [list]
  execsql { PRAGMA mmap_limit=0 } db2
  execsql { CREATE TABLE t2(a, b) } db2
  set ::quota
} {}
do_test quota-3.1.4 {
  catchsql { CREATE TABLE t3(a, b) }
} {1 {database or disk is full}}
do_test quota-3.1.5 {
175
176
177
178
179
180
181

182
183
184
185
186
187
188

  sqlite3_quota_set * 4096 {}
  sqlite3 db1a test.db
  sqlite3 db2a test2.db

  foreach db {db1a db2a} {
    execsql {

      PRAGMA page_size = 1024;
      PRAGMA journal_mode = delete;
      PRAGMA auto_vacuum = off;
      CREATE TABLE t1(a, b);
    } $db
  }








>







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

  sqlite3_quota_set * 4096 {}
  sqlite3 db1a test.db
  sqlite3 db2a test2.db

  foreach db {db1a db2a} {
    execsql {
      PRAGMA mmap_limit=0;
      PRAGMA page_size = 1024;
      PRAGMA journal_mode = delete;
      PRAGMA auto_vacuum = off;
      CREATE TABLE t1(a, b);
    } $db
  }

Changes to test/sqllimits1.test.

530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
    INSERT INTO abc SELECT a||b||c, b||c||a, c||a||b FROM abc;
    INSERT INTO abc SELECT a||b||c, b||c||a, c||a||b FROM abc;
    INSERT INTO abc SELECT a||b||c, b||c||a, c||a||b FROM abc;
    INSERT INTO abc SELECT a, b, c FROM abc;
    INSERT INTO abc SELECT b, a, c FROM abc;
    INSERT INTO abc SELECT c, b, a FROM abc;
  }
  expr [file size test.db] / 1024
} $fsize
do_test sqllimits1-7.7.2 {
  db close
  sqlite3 db test.db
  execsql {
    PRAGMA max_page_count = 1000;
  }
  execsql {
    SELECT count(*) FROM sqlite_master;
  }
} {6}
do_test sqllimits1-7.7.3 {
  execsql {
    PRAGMA max_page_count;
  }
} $fsize
do_test sqllimits1-7.7.4 {
  execsql {
    DROP TABLE abc;
  }
} {}

#--------------------------------------------------------------------







|















|







530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
    INSERT INTO abc SELECT a||b||c, b||c||a, c||a||b FROM abc;
    INSERT INTO abc SELECT a||b||c, b||c||a, c||a||b FROM abc;
    INSERT INTO abc SELECT a||b||c, b||c||a, c||a||b FROM abc;
    INSERT INTO abc SELECT a, b, c FROM abc;
    INSERT INTO abc SELECT b, a, c FROM abc;
    INSERT INTO abc SELECT c, b, a FROM abc;
  }
  file_page_count test.db
} $fsize
do_test sqllimits1-7.7.2 {
  db close
  sqlite3 db test.db
  execsql {
    PRAGMA max_page_count = 1000;
  }
  execsql {
    SELECT count(*) FROM sqlite_master;
  }
} {6}
do_test sqllimits1-7.7.3 {
  execsql {
    PRAGMA max_page_count;
  }
} [expr [file size test.db] / 1024]
do_test sqllimits1-7.7.4 {
  execsql {
    DROP TABLE abc;
  }
} {}

#--------------------------------------------------------------------

Changes to test/tester.tcl.

1632
1633
1634
1635
1636
1637
1638

1639
1640
1641
1642
1643
1644
1645
# to the values they held before the SQL was executed. This simulates
# a write by a pre-3.7.0 client.
#
proc sql36231 {sql} {
  set B [hexio_read test.db 92 8]
  set A [hexio_read test.db 28 4]
  sqlite3 db36231 test.db

  catch { db36231 func a_string a_string }
  execsql $sql db36231
  db36231 close
  hexio_write test.db 28 $A
  hexio_write test.db 92 $B
  return ""
}







>







1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
# to the values they held before the SQL was executed. This simulates
# a write by a pre-3.7.0 client.
#
proc sql36231 {sql} {
  set B [hexio_read test.db 92 8]
  set A [hexio_read test.db 28 4]
  sqlite3 db36231 test.db
  db36231 eval { PRAGMA mmap_limit = 0 }
  catch { db36231 func a_string a_string }
  execsql $sql db36231
  db36231 close
  hexio_write test.db 28 $A
  hexio_write test.db 92 $B
  return ""
}
1669
1670
1671
1672
1673
1674
1675





























1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
  sqlite3 db $dbfile
}
proc db_delete_and_reopen {{file test.db}} {
  catch { db close }
  foreach f [glob -nocomplain test.db*] { forcedelete $f }
  sqlite3 db $file
}






























# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

# Make sure the FTS enhanced query syntax is disabled.
set sqlite_fts3_enable_parentheses 0

source $testdir/thread_common.tcl
source $testdir/malloc_common.tcl







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
  sqlite3 db $dbfile
}
proc db_delete_and_reopen {{file test.db}} {
  catch { db close }
  foreach f [glob -nocomplain test.db*] { forcedelete $f }
  sqlite3 db $file
}

# Return the number of pages in the database file $zFile, according to 
# the database header.
#
proc file_page_count {zFile} {
  set nPg [hexio_get_int [hexio_read $zFile 28 4]]
  set pgsz [file_page_size $zFile]
  set filesz [file size $zFile]
  set syspgsz 4096

  # Check that the file size is consistent with the database page size,
  # the page count, and the system page size.
  if {($filesz < ($nPg * $pgsz))
   || ($filesz > (((($nPg * $pgsz)+$syspgsz-1) / $syspgsz) * $syspgsz))
  } {
    error "file_size=$filesz. page_count=$nPg. page_size=$pgsz."
  }

  return $nPg
}

# Return the page size of database file $zFile, according to the database 
# header.
#
proc file_page_size {zFile} {
  set pgsz [hexio_get_int [hexio_read $zFile 16 2]]
  if {$pgsz==1} {set pgsz 65536}
  return $pgsz
}

# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

# Make sure the FTS enhanced query syntax is disabled.
set sqlite_fts3_enable_parentheses 0

source $testdir/thread_common.tcl
source $testdir/malloc_common.tcl

Changes to test/tkt1512.test.

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    CREATE TABLE t1(a,b);
    INSERT INTO t1 VALUES(1,2);
    INSERT INTO t1 VALUES(3,4);
    SELECT * FROM t1
  }
} {1 2 3 4}
do_test tkt1512-1.2 {
  file size test.db
} {2048}
do_test tkt1512-1.3 {
  execsql {
    DROP TABLE t1;
  }
  file size test.db
} {2048}
do_test tkt1512-1.4 {
  execsql {
    VACUUM;
  }
  file size test.db
} {1024}


finish_test







|
|




|
|




|
|



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    CREATE TABLE t1(a,b);
    INSERT INTO t1 VALUES(1,2);
    INSERT INTO t1 VALUES(3,4);
    SELECT * FROM t1
  }
} {1 2 3 4}
do_test tkt1512-1.2 {
  file_page_count test.db
} {2}
do_test tkt1512-1.3 {
  execsql {
    DROP TABLE t1;
  }
  file_page_count test.db
} {2}
do_test tkt1512-1.4 {
  execsql {
    VACUUM;
  }
  file_page_count test.db
} {1}


finish_test

Changes to test/tkt2920.test.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
do_test tkt2920-1.1 {
  db eval {
    PRAGMA page_size=1024;
    PRAGMA max_page_count=40;
    PRAGMA auto_vacuum=0;
    CREATE TABLE filler (fill);
  }
  file size test.db
} {2048}
do_test tkt2920-1.2 {
  db eval BEGIN
  for {set i 0} {$i<34} {incr i} {
    db eval {INSERT INTO filler VALUES(randomblob(1024))}
  }
  db eval COMMIT
}  {}







|
|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
do_test tkt2920-1.1 {
  db eval {
    PRAGMA page_size=1024;
    PRAGMA max_page_count=40;
    PRAGMA auto_vacuum=0;
    CREATE TABLE filler (fill);
  }
  list [file_page_count test.db] [file_page_size test.db]
} {2 1024}
do_test tkt2920-1.2 {
  db eval BEGIN
  for {set i 0} {$i<34} {incr i} {
    db eval {INSERT INTO filler VALUES(randomblob(1024))}
  }
  db eval COMMIT
}  {}

Changes to test/vacuum3.test.

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    INSERT INTO t1 VALUES(1, 2, 3);
  }
} {}
do_test vacuum3-1.2 {
  execsql { PRAGMA page_size }
} {1024}
do_test vacuum3-1.3 {
  file size test.db
} {2048}

set I 4
foreach {request actual database} [list \
  2048 2048 4096                        \
  1024 1024 2048                        \
  1170 1024 2048                        \
  256  1024 2048                        \
  512  512  1024                        \
  4096 4096 8192                        \
  1024 1024 2048                        \
] {
  do_test vacuum3-1.$I.1 {
    execsql " 
      PRAGMA page_size = $request;
      VACUUM;
    "
    execsql { PRAGMA page_size }
  } $actual
  do_test vacuum3-1.$I.2 {
    file size test.db

  } $database
  do_test vacuum3-1.$I.3 {
    execsql { SELECT * FROM t1 }
  } {1 2 3}
  integrity_check vacuum3-1.$I.4

  incr I
}

#-------------------------------------------------------------------
# Test cases vacuum3-2.* convert a simple 3-page database between a 
# few different page sizes.
#
do_test vacuum3-2.1 {
  execsql {
    PRAGMA page_size = 1024;
    VACUUM;
    ALTER TABLE t1 ADD COLUMN d;
    UPDATE t1 SET d = randomblob(1000);
  }
  file size test.db
} {3072}
do_test vacuum3-2.2 {
  execsql { PRAGMA page_size }
} {1024}
do_test vacuum3-2.3 {
  set blob [db one {select d from t1}]
  string length $blob
} {1000}







|
|



















|
>




















|
|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    INSERT INTO t1 VALUES(1, 2, 3);
  }
} {}
do_test vacuum3-1.2 {
  execsql { PRAGMA page_size }
} {1024}
do_test vacuum3-1.3 {
  file_page_count test.db
} {2}

set I 4
foreach {request actual database} [list \
  2048 2048 4096                        \
  1024 1024 2048                        \
  1170 1024 2048                        \
  256  1024 2048                        \
  512  512  1024                        \
  4096 4096 8192                        \
  1024 1024 2048                        \
] {
  do_test vacuum3-1.$I.1 {
    execsql " 
      PRAGMA page_size = $request;
      VACUUM;
    "
    execsql { PRAGMA page_size }
  } $actual
  do_test vacuum3-1.$I.2 {
    set nPg [file_page_count test.db]
    expr {$nPg * $actual}
  } $database
  do_test vacuum3-1.$I.3 {
    execsql { SELECT * FROM t1 }
  } {1 2 3}
  integrity_check vacuum3-1.$I.4

  incr I
}

#-------------------------------------------------------------------
# Test cases vacuum3-2.* convert a simple 3-page database between a 
# few different page sizes.
#
do_test vacuum3-2.1 {
  execsql {
    PRAGMA page_size = 1024;
    VACUUM;
    ALTER TABLE t1 ADD COLUMN d;
    UPDATE t1 SET d = randomblob(1000);
  }
  file_page_count test.db
} {3}
do_test vacuum3-2.2 {
  execsql { PRAGMA page_size }
} {1024}
do_test vacuum3-2.3 {
  set blob [db one {select d from t1}]
  string length $blob
} {1000}

Changes to test/wal.test.

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#
do_test wal-0.1 {
  execsql { PRAGMA auto_vacuum = 0 }
  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]     \
       [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]
} {0 1}
do_test wal-1.2 {
  # There are now two pages in the log.
  file size test.db-wal







|
|








|
|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#
do_test wal-0.1 {
  execsql { PRAGMA auto_vacuum = 0 }
  execsql { PRAGMA synchronous = normal }
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test wal-0.2 {
  file_page_count test.db
} {1}

do_test wal-1.0 {
  execsql { 
    BEGIN;
    CREATE TABLE t1(a, b); 
  }
  list [file exists test.db-journal] \
       [file exists test.db-wal]     \
       [file_page_count test.db]
} {0 1 1}
do_test wal-1.1 {
  execsql COMMIT
  list [file exists test.db-journal] [file exists test.db-wal]
} {0 1}
do_test wal-1.2 {
  # There are now two pages in the log.
  file size test.db-wal
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366


367
368
369
370


371
372
373
374
375
376
377
378
379
        PRAGMA journal_mode = wal;
      "
      execsql "
        CREATE TABLE t1(a, b);
        INSERT INTO t1 VALUES(1, 2);
      "
      db close
      file size test.db
    } [expr $pgsz*2]
  
    do_test wal-6.$sector.$pgsz.2 {
      log_deleted test.db-wal
    } {1}
  }
}

do_test wal-7.1 {
  forcedelete test.db test.db-wal
  sqlite3_wal db test.db
  execsql {
    PRAGMA page_size = 1024;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
  }


  list [file size test.db] [file size test.db-wal]
} [list 1024 [wal_file_size 3 1024]]
do_test wal-7.2 {
  execsql { PRAGMA wal_checkpoint }


  list [file size test.db] [file size test.db-wal]
} [list 2048 [wal_file_size 3 1024]]

# Execute some transactions in auto-vacuum mode to test database file
# truncation.
#
do_test wal-8.1 {
  reopen_db
  catch { db close }







|
|















>
>
|
|


>
>
|
|







343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
        PRAGMA journal_mode = wal;
      "
      execsql "
        CREATE TABLE t1(a, b);
        INSERT INTO t1 VALUES(1, 2);
      "
      db close
      list [file_page_count test.db] [file_page_size test.db]
    } [list 2 $pgsz]
  
    do_test wal-6.$sector.$pgsz.2 {
      log_deleted test.db-wal
    } {1}
  }
}

do_test wal-7.1 {
  forcedelete test.db test.db-wal
  sqlite3_wal db test.db
  execsql {
    PRAGMA page_size = 1024;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
  }
  list [file_page_count test.db] \
       [file_page_size test.db]  \
       [file size test.db-wal]
} [list 1 1024 [wal_file_size 3 1024]]
do_test wal-7.2 {
  execsql { PRAGMA wal_checkpoint }
  list [file_page_count test.db] \
       [file_page_size test.db]  \
       [file size test.db-wal]
} [list 2 1024 [wal_file_size 3 1024]]

# Execute some transactions in auto-vacuum mode to test database file
# truncation.
#
do_test wal-8.1 {
  reopen_db
  catch { db close }
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
    INSERT INTO t1 SELECT blob(900) FROM t1;       /*  8 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 16 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 32 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 64 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 128 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 256 */
  }
  file size test.db
} 1024
do_test wal-9.2 {
  sqlite3_wal db2 test.db
  execsql {PRAGMA integrity_check } db2
} {ok}

do_test wal-9.3 {
  forcedelete test2.db test2.db-wal







|
|







428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
    INSERT INTO t1 SELECT blob(900) FROM t1;       /*  8 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 16 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 32 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 64 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 128 */
    INSERT INTO t1 SELECT blob(900) FROM t1;       /* 256 */
  }
  file_page_count test.db
} 1
do_test wal-9.2 {
  sqlite3_wal db2 test.db
  execsql {PRAGMA integrity_check } db2
} {ok}

do_test wal-9.3 {
  forcedelete test2.db test2.db-wal
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
do_test wal-11.1 {
  reopen_db
  execsql {
    PRAGMA cache_size = 10;
    PRAGMA page_size = 1024;
    CREATE TABLE t1(x PRIMARY KEY);
  }
  list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
} {1 3}
do_test wal-11.2 {
  execsql { PRAGMA wal_checkpoint }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 3 [wal_file_size 3 1024]]
do_test wal-11.3 {
  execsql { INSERT INTO t1 VALUES( blob(900) ) }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 3 [wal_file_size 4 1024]]

do_test wal-11.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 2
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 4
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 8
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 16
  }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 3 [wal_file_size 32 1024]]
do_test wal-11.5 {
  execsql { 
    SELECT count(*) FROM t1;
    PRAGMA integrity_check;
  }
} {16 ok}
do_test wal-11.6 {
  execsql COMMIT
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 3 [wal_file_size 41 1024]]
do_test wal-11.7 {
  execsql { 
    SELECT count(*) FROM t1;
    PRAGMA integrity_check;
  }
} {16 ok}
do_test wal-11.8 {
  execsql { PRAGMA wal_checkpoint }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 41 1024]]
do_test wal-11.9 {
  db close
  list [expr [file size test.db]/1024] [log_deleted test.db-wal]
} {37 1}
sqlite3_wal db test.db
set nWal 39
if {[permutation]=="nommap"} {set nWal 37}
do_test wal-11.10 {
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 32
      SELECT count(*) FROM t1;
  }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.11 {
  execsql {
      SELECT count(*) FROM t1;
    ROLLBACK;
    SELECT count(*) FROM t1;
  }
} {32 16}
do_test wal-11.12 {
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.13 {
  execsql {
    INSERT INTO t1 VALUES( blob(900) );
    SELECT count(*) FROM t1;
    PRAGMA integrity_check;
  }
} {17 ok}
do_test wal-11.14 {
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size $nWal 1024]]


#-------------------------------------------------------------------------
# This block of tests, wal-12.*, tests the fix for a problem that 
# could occur if a log that is a prefix of an older log is written 
# into a reused log file.
#
reopen_db
do_test wal-12.1 {
  execsql {
    PRAGMA page_size = 1024;
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
    INSERT INTO t1 VALUES('A', 1);
  }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 1 [wal_file_size 5 1024]]
do_test wal-12.2 {
  db close
  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]
} {3 1}
do_test wal-12.3 {
  execsql { INSERT INTO t2 VALUES('B', 1) }
  list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
} {3 2}
do_test wal-12.4 {
  forcecopy test.db test2.db
  forcecopy test.db-wal test2.db-wal
  sqlite3_wal db2 test2.db
  execsql { SELECT * FROM t2 } db2
} {B 1}







|



|



|










|









|









|



|











|









|









|
















|








|



|







681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
do_test wal-11.1 {
  reopen_db
  execsql {
    PRAGMA cache_size = 10;
    PRAGMA page_size = 1024;
    CREATE TABLE t1(x PRIMARY KEY);
  }
  list [file_page_count test.db] [expr [file size test.db-wal]/1044]
} {1 3}
do_test wal-11.2 {
  execsql { PRAGMA wal_checkpoint }
  list [file_page_count test.db] [file size test.db-wal]
} [list 3 [wal_file_size 3 1024]]
do_test wal-11.3 {
  execsql { INSERT INTO t1 VALUES( blob(900) ) }
  list [file_page_count test.db] [file size test.db-wal]
} [list 3 [wal_file_size 4 1024]]

do_test wal-11.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 2
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 4
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 8
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 16
  }
  list [file_page_count test.db] [file size test.db-wal]
} [list 3 [wal_file_size 32 1024]]
do_test wal-11.5 {
  execsql { 
    SELECT count(*) FROM t1;
    PRAGMA integrity_check;
  }
} {16 ok}
do_test wal-11.6 {
  execsql COMMIT
  list [file_page_count test.db] [file size test.db-wal]
} [list 3 [wal_file_size 41 1024]]
do_test wal-11.7 {
  execsql { 
    SELECT count(*) FROM t1;
    PRAGMA integrity_check;
  }
} {16 ok}
do_test wal-11.8 {
  execsql { PRAGMA wal_checkpoint }
  list [file_page_count test.db] [file size test.db-wal]
} [list 37 [wal_file_size 41 1024]]
do_test wal-11.9 {
  db close
  list [file_page_count test.db] [log_deleted test.db-wal]
} {37 1}
sqlite3_wal db test.db
set nWal 39
if {[permutation]=="nommap"} {set nWal 37}
do_test wal-11.10 {
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 32
      SELECT count(*) FROM t1;
  }
  list [file_page_count test.db] [file size test.db-wal]
} [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.11 {
  execsql {
      SELECT count(*) FROM t1;
    ROLLBACK;
    SELECT count(*) FROM t1;
  }
} {32 16}
do_test wal-11.12 {
  list [file_page_count test.db] [file size test.db-wal]
} [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.13 {
  execsql {
    INSERT INTO t1 VALUES( blob(900) );
    SELECT count(*) FROM t1;
    PRAGMA integrity_check;
  }
} {17 ok}
do_test wal-11.14 {
  list [file_page_count test.db] [file size test.db-wal]
} [list 37 [wal_file_size $nWal 1024]]


#-------------------------------------------------------------------------
# This block of tests, wal-12.*, tests the fix for a problem that 
# could occur if a log that is a prefix of an older log is written 
# into a reused log file.
#
reopen_db
do_test wal-12.1 {
  execsql {
    PRAGMA page_size = 1024;
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
    INSERT INTO t1 VALUES('A', 1);
  }
  list [file_page_count test.db] [file size test.db-wal]
} [list 1 [wal_file_size 5 1024]]
do_test wal-12.2 {
  db close
  sqlite3 db test.db
  execsql {
    PRAGMA synchronous = normal;
    UPDATE t1 SET y = 0 WHERE x = 'A';
  }
  list [file_page_count test.db] [expr [file size test.db-wal]/1044]
} {3 1}
do_test wal-12.3 {
  execsql { INSERT INTO t2 VALUES('B', 1) }
  list [file_page_count test.db] [expr [file size test.db-wal]/1044]
} {3 2}
do_test wal-12.4 {
  forcecopy test.db test2.db
  forcecopy test.db-wal test2.db-wal
  sqlite3_wal db2 test2.db
  execsql { SELECT * FROM t2 } db2
} {B 1}
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
  set fd [open test.db-wal w]
  seek $fd [expr 200*1024*1024]
  puts $fd ""
  close $fd
  sqlite3 db test.db
  execsql { SELECT * FROM t2 }
} {B 2}
breakpoint
do_test wal-13.1.3 {
  db close
  file exists test.db-wal
} {0}

do_test wal-13.2.1 {
  sqlite3 db test.db







<







851
852
853
854
855
856
857

858
859
860
861
862
863
864
  set fd [open test.db-wal w]
  seek $fd [expr 200*1024*1024]
  puts $fd ""
  close $fd
  sqlite3 db test.db
  execsql { SELECT * FROM t2 }
} {B 2}

do_test wal-13.1.3 {
  db close
  file exists test.db-wal
} {0}

do_test wal-13.2.1 {
  sqlite3 db test.db
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  execsql { COMMIT } db2
  sqlite3_wal_checkpoint db
} {SQLITE_OK}
do_test wal-15.4.5 {
  sqlite3_errmsg db
} {not an error}
do_test wal-15.4.6 {
  file size test.db
} [expr 1024*2]

catch { db2 close }
catch { db close }

#-------------------------------------------------------------------------
# The following block of tests - wal-16.* - test that if a NULL pointer or
# an empty string is passed as the second argument of the wal_checkpoint()







|
|







1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  execsql { COMMIT } db2
  sqlite3_wal_checkpoint db
} {SQLITE_OK}
do_test wal-15.4.5 {
  sqlite3_errmsg db
} {not an error}
do_test wal-15.4.6 {
  list [file_page_count test.db] [file_page_size test.db]
} {2 1024}

catch { db2 close }
catch { db close }

#-------------------------------------------------------------------------
# The following block of tests - wal-16.* - test that if a NULL pointer or
# an empty string is passed as the second argument of the wal_checkpoint()
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
      CREATE TABLE aux.t2(a, b, PRIMARY KEY(a, b));

      INSERT INTO t2 VALUES(1, randomblob(1000));
      INSERT INTO t2 VALUES(2, randomblob(1000));
      INSERT INTO t1 SELECT * FROM t2;
    }
  
    list [file size test.db] [file size test.db-wal]
  } [list [expr 1*1024] [wal_file_size 10 1024]]
  do_test wal-16.$tn.3 {
    list [file size test2.db] [file size test2.db-wal]
  } [list [expr 1*1024] [wal_file_size 13 1024]]
  
  do_test wal-16.$tn.4 [list eval $ckpt_cmd] $ckpt_res
  
  do_test wal-16.$tn.5 {
    list [file size test.db] [file size test.db-wal]
  } [list [expr ($ckpt_main ? 7 : 1)*1024] [wal_file_size 10 1024]]

  do_test wal-16.$tn.6 {
    list [file size test2.db] [file size test2.db-wal]
  } [list [expr ($ckpt_aux ? 7 : 1)*1024] [wal_file_size 13 1024]]

  catch { db close }
}

#-------------------------------------------------------------------------
# The following tests - wal-17.* - attempt to verify that the correct
# number of "padding" frames are appended to the log file when a transaction







|
|

|
|




|
|


|
|







1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
      CREATE TABLE aux.t2(a, b, PRIMARY KEY(a, b));

      INSERT INTO t2 VALUES(1, randomblob(1000));
      INSERT INTO t2 VALUES(2, randomblob(1000));
      INSERT INTO t1 SELECT * FROM t2;
    }
  
    list [file_page_count test.db] [file size test.db-wal]
  } [list 1 [wal_file_size 10 1024]]
  do_test wal-16.$tn.3 {
    list [file_page_count test2.db] [file size test2.db-wal]
  } [list 1 [wal_file_size 13 1024]]
  
  do_test wal-16.$tn.4 [list eval $ckpt_cmd] $ckpt_res
  
  do_test wal-16.$tn.5 {
    list [file_page_count test.db] [file size test.db-wal]
  } [list [expr ($ckpt_main ? 7 : 1)] [wal_file_size 10 1024]]

  do_test wal-16.$tn.6 {
    list [file_page_count test2.db] [file size test2.db-wal]
  } [list [expr ($ckpt_aux ? 7 : 1)] [wal_file_size 13 1024]]

  catch { db close }
}

#-------------------------------------------------------------------------
# The following tests - wal-17.* - attempt to verify that the correct
# number of "padding" frames are appended to the log file when a transaction
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
    }
    execsql COMMIT

    file size test.db-wal
  } $logsize

  do_test wal-17.$tn.2 {
    file size test.db
  } 512

  do_test wal-17.$tn.3 {
    db close
    file size test.db
  } [expr 512*171]
}
sqlite3_test_control_pending_byte $old_pending_byte

#-------------------------------------------------------------------------
# This test - wal-18.* - verifies a couple of specific conditions that
# may be encountered while recovering a log file are handled correctly:
#







|
|



|
|







1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
    }
    execsql COMMIT

    file size test.db-wal
  } $logsize

  do_test wal-17.$tn.2 {
    file_page_count test.db
  } 1

  do_test wal-17.$tn.3 {
    db close
    file_page_count test.db
  } 171
}
sqlite3_test_control_pending_byte $old_pending_byte

#-------------------------------------------------------------------------
# This test - wal-18.* - verifies a couple of specific conditions that
# may be encountered while recovering a log file are handled correctly:
#
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
    INSERT INTO t1 VALUES(3, 4);          -- frames 3 and 4
    INSERT INTO t1 VALUES(5, 6);          -- frames 5 and 6
  }

  forcecopy test.db testX.db
  forcecopy test.db-wal testX.db-wal
  db close
  list [file size testX.db] [file size testX.db-wal]
} [list [expr 3*1024] [wal_file_size 6 1024]]

unset -nocomplain nFrame result
foreach {nFrame result} {
         0      {0 0}
         1      {0 0}
         2      {0 0 1 2}
         3      {0 0 1 2}







|
|







1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
    INSERT INTO t1 VALUES(3, 4);          -- frames 3 and 4
    INSERT INTO t1 VALUES(5, 6);          -- frames 5 and 6
  }

  forcecopy test.db testX.db
  forcecopy test.db-wal testX.db-wal
  db close
  list [file_page_count testX.db] [file size testX.db-wal]
} [list 3 [wal_file_size 6 1024]]

unset -nocomplain nFrame result
foreach {nFrame result} {
         0      {0 0}
         1      {0 0}
         2      {0 0 1 2}
         3      {0 0 1 2}
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
    forcedelete test.db-wal
  
    # Check that the database now exists and consists of three pages. And
    # that there is no associated wal file.
    #
    do_test wal-18.2.$tn.$pg.1 { file exists test.db-wal } 0
    do_test wal-18.2.$tn.$pg.2 { file exists test.db } 1
    do_test wal-18.2.$tn.$pg.3 { file size test.db } [expr 1024*3]
  
    do_test wal-18.2.$tn.$pg.4 {

      # Create a wal file that contains a single frame (database page
      # number $pg) with the commit flag set. The frame checksum is
      # correct, but the contents of the database page are corrupt.
      #







|







1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
    forcedelete test.db-wal
  
    # Check that the database now exists and consists of three pages. And
    # that there is no associated wal file.
    #
    do_test wal-18.2.$tn.$pg.1 { file exists test.db-wal } 0
    do_test wal-18.2.$tn.$pg.2 { file exists test.db } 1
    do_test wal-18.2.$tn.$pg.3 { file_page_count test.db } 3
  
    do_test wal-18.2.$tn.$pg.4 {

      # Create a wal file that contains a single frame (database page
      # number $pg) with the commit flag set. The frame checksum is
      # correct, but the contents of the database page are corrupt.
      #
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
} {1 2 3 4}
do_test wal-23.2 { set ::log } {}

do_test wal-23.3 {
  db close
  set ::log [list]
  faultsim_restore_and_reopen
  execsql { SELECT * FROM t1 }
} {1 2 3 4}
set nPage [expr 2+$AUTOVACUUM]
do_test wal-23.4 { 
  set ::log 
} [list SQLITE_OK "Recovered $nPage frames from WAL file $walfile"]


ifcapable autovacuum {







|
|







1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
} {1 2 3 4}
do_test wal-23.2 { set ::log } {}

do_test wal-23.3 {
  db close
  set ::log [list]
  faultsim_restore_and_reopen
  execsql { SELECT * FROM t1 ; PRAGMA page_size }
} {1 2 3 4 1024}
set nPage [expr 2+$AUTOVACUUM]
do_test wal-23.4 { 
  set ::log 
} [list SQLITE_OK "Recovered $nPage frames from WAL file $walfile"]


ifcapable autovacuum {

Changes to test/wal5.test.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }

set testprefix wal5

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 }


# 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.
#







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }

set testprefix wal5

proc db_page_count  {{file test.db}} { file_page_count $file }
proc wal_page_count {{file test.db}} { wal_frame_count ${file}-wal 1024 }


# 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.
#
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
        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 }







|
|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
        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));
      }
      list [file_page_count test.db] [file_page_size test.db]
    } {2 1024}

    # 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 }

Changes to test/wal9.test.

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
} {}

# Check file sizes are as expected. The real requirement here is that 
# the *shm file is now more than one chunk (>32KiB).
#
# The sizes of various files are slightly different in normal and 
# auto-vacuum mode.
do_test 1.3 { file size test.db     } {1024}
do_test 1.4 { expr {[file size test.db-wal]>(1500*1024)} } {1}
do_test 1.5 { expr {[file size test.db-shm]>32768} }       {1}
do_test 1.6 { 
  foreach {a b c} [db eval {PRAGMA wal_checkpoint}] break
  list [expr {$a==0}] [expr {$b>14500}] [expr {$c>14500}] [expr {$b==$c}]
} {1 1 1 1}








|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
} {}

# Check file sizes are as expected. The real requirement here is that 
# the *shm file is now more than one chunk (>32KiB).
#
# The sizes of various files are slightly different in normal and 
# auto-vacuum mode.
do_test 1.3 { file_page_count test.db } {1}
do_test 1.4 { expr {[file size test.db-wal]>(1500*1024)} } {1}
do_test 1.5 { expr {[file size test.db-shm]>32768} }       {1}
do_test 1.6 { 
  foreach {a b c} [db eval {PRAGMA wal_checkpoint}] break
  list [expr {$a==0}] [expr {$b>14500}] [expr {$c>14500}] [expr {$b==$c}]
} {1 1 1 1}

Changes to test/walbak.test.

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
      INSERT INTO t1 VALUES('I', 'one');
    COMMIT;
  }
} {wal}
do_test walbak-1.1 {
  forcedelete bak.db bak.db-journal bak.db-wal
  db backup bak.db
  file size bak.db
} [expr 3*1024]
do_test walbak-1.2 {
  sqlite3 db2 bak.db
  execsql { 
    SELECT * FROM t1;
    PRAGMA main.journal_mode;
  } db2
} {I one wal}







|
|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
      INSERT INTO t1 VALUES('I', 'one');
    COMMIT;
  }
} {wal}
do_test walbak-1.1 {
  forcedelete bak.db bak.db-journal bak.db-wal
  db backup bak.db
  file_page_count bak.db
} 3
do_test walbak-1.2 {
  sqlite3 db2 bak.db
  execsql { 
    SELECT * FROM t1;
    PRAGMA main.journal_mode;
  } db2
} {I one wal}
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
do_test walbak-1.4 {
  execsql { 
    VACUUM;
    PRAGMA main.journal_mode;
  }
} {wal}
do_test walbak-1.5 {
  list [file size test.db] [file size test.db-wal]
} [list 1024 [wal_file_size 6 1024]]
do_test walbak-1.6 {
  execsql { PRAGMA wal_checkpoint }
  list [file size test.db] [file size test.db-wal]
} [list [expr 3*1024] [wal_file_size 6 1024]]
do_test walbak-1.6.1 {
  hexio_read test.db 18 2
} {0202}







|
|







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
do_test walbak-1.4 {
  execsql { 
    VACUUM;
    PRAGMA main.journal_mode;
  }
} {wal}
do_test walbak-1.5 {
  list [file_page_count test.db] [file size test.db-wal]
} [list 1 [wal_file_size 6 1024]]
do_test walbak-1.6 {
  execsql { PRAGMA wal_checkpoint }
  list [file size test.db] [file size test.db-wal]
} [list [expr 3*1024] [wal_file_size 6 1024]]
do_test walbak-1.6.1 {
  hexio_read test.db 18 2
} {0202}

Changes to test/walcksum.test.

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
      INSERT INTO t1 VALUES(21, 'twentyone');
    }

    forcecopy test.db test2.db
    forcecopy test.db-wal test2.db-wal
    db close

    list [file size test2.db] [file size test2.db-wal]
  } [list [expr 1024*3] [wal_file_size 6 1024]]

  # Verify that the checksums are valid for all frames and that they
  # are calculated by interpreting data in native byte-order.
  #
  for {set f 1} {$f <= 6} {incr f} {
    do_test walcksum-1.$endian.2.$f {
      log_checksum_verify test2.db-wal $f $native







|
|







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
      INSERT INTO t1 VALUES(21, 'twentyone');
    }

    forcecopy test.db test2.db
    forcecopy test.db-wal test2.db-wal
    db close

    list [file_page_count test2.db] [file size test2.db-wal]
  } [list 3 [wal_file_size 6 1024]]

  # Verify that the checksums are valid for all frames and that they
  # are calculated by interpreting data in native byte-order.
  #
  for {set f 1} {$f <= 6} {incr f} {
    do_test walcksum-1.$endian.2.$f {
      log_checksum_verify test2.db-wal $f $native
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  # endianness as the existing frames. Check that this is the case.
  #
  do_test walcksum-1.$endian.5.0 {
    execsql { 
      PRAGMA synchronous = NORMAL;
      INSERT INTO t1 VALUES(34, 'thirtyfour');
    }
    list [file size test.db] [file size test.db-wal]
  } [list [expr 1024*3] [wal_file_size 8 1024]]
  for {set f 1} {$f <= 8} {incr f} {
    do_test walcksum-1.$endian.5.$f {
      log_checksum_verify test.db-wal $f $endian
    } {1}
  }

  # Now connect a second connection to the database. Check that this one







|
|







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  # endianness as the existing frames. Check that this is the case.
  #
  do_test walcksum-1.$endian.5.0 {
    execsql { 
      PRAGMA synchronous = NORMAL;
      INSERT INTO t1 VALUES(34, 'thirtyfour');
    }
    list [file_page_count test.db] [file size test.db-wal]
  } [list 3 [wal_file_size 8 1024]]
  for {set f 1} {$f <= 8} {incr f} {
    do_test walcksum-1.$endian.5.$f {
      log_checksum_verify test.db-wal $f $endian
    } {1}
  }

  # Now connect a second connection to the database. Check that this one
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    } db2
  } {ok 1 2 3 5 8 13 21 34}
  do_test walcksum-1.$endian.7.0 {
    execsql { 
      PRAGMA synchronous = NORMAL;
      INSERT INTO t1 VALUES(55, 'fiftyfive');
    } db2
    list [file size test.db] [file size test.db-wal]
  } [list [expr 1024*3] [wal_file_size 10 1024]]
  for {set f 1} {$f <= 10} {incr f} {
    do_test walcksum-1.$endian.7.$f {
      log_checksum_verify test.db-wal $f $endian
    } {1}
  }

  # Now that both the recoverer and non-recoverer have added frames to the







|
|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    } db2
  } {ok 1 2 3 5 8 13 21 34}
  do_test walcksum-1.$endian.7.0 {
    execsql { 
      PRAGMA synchronous = NORMAL;
      INSERT INTO t1 VALUES(55, 'fiftyfive');
    } db2
    list [file_page_count test.db] [file size test.db-wal]
  } [list 3 [wal_file_size 10 1024]]
  for {set f 1} {$f <= 10} {incr f} {
    do_test walcksum-1.$endian.7.$f {
      log_checksum_verify test.db-wal $f $endian
    } {1}
  }

  # Now that both the recoverer and non-recoverer have added frames to the

Changes to test/walhook.test.

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  set ::wal_hook [list]
  execsql { INSERT INTO t1 VALUES(1, 'one') }
  set ::wal_hook
} {main 5}
do_test walhook-1.3 {
  proc wal_hook {args} { db eval {PRAGMA wal_checkpoint}; return 0 }
  execsql { INSERT INTO t1 VALUES(2, 'two') }
  file size test.db
} [expr 3*1024]
do_test walhook-1.4 {
  proc wal_hook {zDb nEntry} { 
    execsql { PRAGMA wal_checkpoint }
    return 0
  }
  execsql { CREATE TABLE t2(a, b) }
  file size test.db







|
|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  set ::wal_hook [list]
  execsql { INSERT INTO t1 VALUES(1, 'one') }
  set ::wal_hook
} {main 5}
do_test walhook-1.3 {
  proc wal_hook {args} { db eval {PRAGMA wal_checkpoint}; return 0 }
  execsql { INSERT INTO t1 VALUES(2, 'two') }
  file_page_count test.db
} 3
do_test walhook-1.4 {
  proc wal_hook {zDb nEntry} { 
    execsql { PRAGMA wal_checkpoint }
    return 0
  }
  execsql { CREATE TABLE t2(a, b) }
  file size test.db

Changes to test/walmode.test.

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

do_test walmode-1.1 {
  set sqlite_sync_count 0
  execsql { PRAGMA page_size = 1024 }
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-1.2 {
  file size test.db
} {1024}

set expected_sync_count 3
if {$::tcl_platform(platform)!="windows"} {
  ifcapable dirsync {
    incr expected_sync_count
  }
}
do_test walmode-1.3 {
  set sqlite_sync_count
} $expected_sync_count

do_test walmode-1.4 {
  file exists test.db-wal
} {0}
do_test walmode-1.5 {
  execsql { CREATE TABLE t1(a, b) }
  file size test.db
} {1024}
do_test walmode-1.6 {
  file exists test.db-wal
} {1}
do_test walmode-1.7 {
  db close
  file exists test.db-wal
} {0}







|
|
















|
|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

do_test walmode-1.1 {
  set sqlite_sync_count 0
  execsql { PRAGMA page_size = 1024 }
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-1.2 {
  file_page_count test.db
} {1}

set expected_sync_count 3
if {$::tcl_platform(platform)!="windows"} {
  ifcapable dirsync {
    incr expected_sync_count
  }
}
do_test walmode-1.3 {
  set sqlite_sync_count
} $expected_sync_count

do_test walmode-1.4 {
  file exists test.db-wal
} {0}
do_test walmode-1.5 {
  execsql { CREATE TABLE t1(a, b) }
  file_page_count test.db
} {1}
do_test walmode-1.6 {
  file exists test.db-wal
} {1}
do_test walmode-1.7 {
  db close
  file exists test.db-wal
} {0}