SQLite

Check-in [c570903608]
Login

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

Overview
Comment:Merge the latest trunk changes into the sessions branch.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: c5709036087b6b4fb6391ab7e4b4b870aac87a31
User & Date: drh 2011-08-03 21:46:58.295
Context
2011-08-26
19:20
Merge the latest trunk changes into the sessions branch. (check-in: eb036d6f81 user: drh tags: sessions)
2011-08-03
21:46
Merge the latest trunk changes into the sessions branch. (check-in: c570903608 user: drh tags: sessions)
21:32
Avoid segfaulting on an incremental blob write if SQLITE_ENABLE_PREUPDATE_HOOK set but no pre-update hooks are defined. (check-in: 62c4463404 user: drh tags: sessions)
16:40
Update the OP_Move opcode to shift the pScopyFrom pointer of aliases when compiled with SQLITE_DEBUG. Ticket [d63523637517386191]. (check-in: a2135ad130 user: drh tags: trunk)
Changes
Unified Diff Show Whitespace Changes Patch
Changes to doc/lemon.html.
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
tokens) and it honors the same commenting conventions as C and C++.</p>

<h3>Terminals and Nonterminals</h3>

<p>A terminal symbol (token) is any string of alphanumeric
and underscore characters
that begins with an upper case letter.
A terminal can contain lower class letters after the first character,
but the usual convention is to make terminals all upper case.
A nonterminal, on the other hand, is any string of alphanumeric
and underscore characters than begins with a lower case letter.
Again, the usual convention is to make nonterminals use all lower
case letters.</p>

<p>In Lemon, terminal and nonterminal symbols do not need to 







|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
tokens) and it honors the same commenting conventions as C and C++.</p>

<h3>Terminals and Nonterminals</h3>

<p>A terminal symbol (token) is any string of alphanumeric
and underscore characters
that begins with an upper case letter.
A terminal can contain lowercase letters after the first character,
but the usual convention is to make terminals all upper case.
A nonterminal, on the other hand, is any string of alphanumeric
and underscore characters than begins with a lower case letter.
Again, the usual convention is to make nonterminals use all lower
case letters.</p>

<p>In Lemon, terminal and nonterminal symbols do not need to 
Changes to src/os_common.h.
26
27
28
29
30
31
32



33
34
35
36
37
38
39
40
** switch.  The following code should catch this problem at compile-time.
*/
#ifdef MEMORY_DEBUG
# error "The MEMORY_DEBUG macro is obsolete.  Use SQLITE_DEBUG instead."
#endif

#ifdef SQLITE_DEBUG



int sqlite3OSTrace = 0;
#define OSTRACE(X)          if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
#define OSTRACE(X)
#endif

/*
** Macros for performance tracing.  Normally turned off.  Only works







>
>
>
|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
** switch.  The following code should catch this problem at compile-time.
*/
#ifdef MEMORY_DEBUG
# error "The MEMORY_DEBUG macro is obsolete.  Use SQLITE_DEBUG instead."
#endif

#ifdef SQLITE_DEBUG
# ifndef SQLITE_DEBUG_OS_TRACE
#   define SQLITE_DEBUG_OS_TRACE 0
# endif
  int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
#define OSTRACE(X)          if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
#define OSTRACE(X)
#endif

/*
** Macros for performance tracing.  Normally turned off.  Only works
Changes to src/os_unix.c.
248
249
250
251
252
253
254

255
256
257
258
259
260
261
};

/*
** Allowed values for the unixFile.ctrlFlags bitmask:
*/
#define UNIXFILE_EXCL   0x01     /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02     /* Connection is read only */


/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

/*







>







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
};

/*
** Allowed values for the unixFile.ctrlFlags bitmask:
*/
#define UNIXFILE_EXCL   0x01     /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02     /* Connection is read only */
#define UNIXFILE_PERSIST_WAL 0x04     /* Persistent WAL mode */

/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

/*
3391
3392
3393
3394
3395
3396
3397
3398
3399

3400
3401
3402
3403
3404





3405
3406
3407
3408
3409
3410
3411
** file-control operation.
**
** If the user has configured a chunk-size for this file, it could be
** that the file needs to be extended at this point. Otherwise, the
** SQLITE_FCNTL_SIZE_HINT operation is a no-op for Unix.
*/
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
  if( pFile->szChunk ){
    i64 nSize;                    /* Required file size */

    struct stat buf;              /* Used to hold return values of fstat() */
   
    if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;

    nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;





    if( nSize>(i64)buf.st_size ){

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
      /* The code below is handling the return value of osFallocate() 
      ** correctly. posix_fallocate() is defined to "returns zero on success, 
      ** or an error number on  failure". See the manpage for details. */
      int err;







|

>




|
>
>
>
>
>







3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
** file-control operation.
**
** If the user has configured a chunk-size for this file, it could be
** that the file needs to be extended at this point. Otherwise, the
** SQLITE_FCNTL_SIZE_HINT operation is a no-op for Unix.
*/
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
  { /* preserve indentation of removed "if" */
    i64 nSize;                    /* Required file size */
    i64 szChunk;                  /* Chunk size */
    struct stat buf;              /* Used to hold return values of fstat() */
   
    if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;

    szChunk = pFile->szChunk;
    if( szChunk==0 ){
      nSize = nByte;
    }else{
      nSize = ((nByte+szChunk-1) / szChunk) * szChunk;
    }
    if( nSize>(i64)buf.st_size ){

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
      /* The code below is handling the return value of osFallocate() 
      ** correctly. posix_fallocate() is defined to "returns zero on success, 
      ** or an error number on  failure". See the manpage for details. */
      int err;
3440
3441
3442
3443
3444
3445
3446

3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461











3462
3463
3464
3465
3466
3467
3468
  return SQLITE_OK;
}

/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){

  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((unixFile*)id)->eFileLock;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = ((unixFile*)id)->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      ((unixFile*)id)->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);











    }
#ifndef NDEBUG
    /* The pager calls this method to signal that it has done
    ** a rollback and that the database is therefore unchanged and
    ** it hence it is OK for the transaction change counter to be
    ** unchanged.
    */







>


|



|



|



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







3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
  return SQLITE_OK;
}

/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  unixFile *pFile = (unixFile*)id;
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = pFile->eFileLock;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = pFile->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      pFile->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      return fcntlSizeHint(pFile, *(i64 *)pArg);
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      int bPersist = *(int*)pArg;
      if( bPersist<0 ){
        *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
      }else if( bPersist==0 ){
        pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
      }else{
        pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
      }
      return SQLITE_OK;
    }
#ifndef NDEBUG
    /* The pager calls this method to signal that it has done
    ** a rollback and that the database is therefore unchanged and
    ** it hence it is OK for the transaction change counter to be
    ** unchanged.
    */
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
  ** almost certain that an open() call on the same path will also fail.
  ** For this reason, if an error occurs in the stat() call here, it is
  ** ignored and -1 is returned. The caller will try to open a new file
  ** descriptor on the same path, fail, and return an error to SQLite.
  **
  ** Even if a subsequent open() call does succeed, the consequences of
  ** not searching for a resusable file descriptor are not dire.  */
  if( 0==stat(zPath, &sStat) ){
    unixInodeInfo *pInode;

    unixEnterMutex();
    pInode = inodeList;
    while( pInode && (pInode->fileId.dev!=sStat.st_dev
                     || pInode->fileId.ino!=sStat.st_ino) ){
       pInode = pInode->pNext;







|







4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
  ** almost certain that an open() call on the same path will also fail.
  ** For this reason, if an error occurs in the stat() call here, it is
  ** ignored and -1 is returned. The caller will try to open a new file
  ** descriptor on the same path, fail, and return an error to SQLite.
  **
  ** Even if a subsequent open() call does succeed, the consequences of
  ** not searching for a resusable file descriptor are not dire.  */
  if( 0==osStat(zPath, &sStat) ){
    unixInodeInfo *pInode;

    unixEnterMutex();
    pInode = inodeList;
    while( pInode && (pInode->fileId.dev!=sStat.st_dev
                     || pInode->fileId.ino!=sStat.st_ino) ){
       pInode = pInode->pNext;
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
    */
    nDb = sqlite3Strlen30(zPath) - 1; 
    while( nDb>0 && zPath[nDb]!='-' ) nDb--;
    if( nDb==0 ) return SQLITE_OK;
    memcpy(zDb, zPath, nDb);
    zDb[nDb] = '\0';

    if( 0==stat(zDb, &sStat) ){
      *pMode = sStat.st_mode & 0777;
    }else{
      rc = SQLITE_IOERR_FSTAT;
    }
  }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    *pMode = 0600;
  }







|







4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
    */
    nDb = sqlite3Strlen30(zPath) - 1; 
    while( nDb>0 && zPath[nDb]!='-' ) nDb--;
    if( nDb==0 ) return SQLITE_OK;
    memcpy(zDb, zPath, nDb);
    zDb[nDb] = '\0';

    if( 0==osStat(zDb, &sStat) ){
      *pMode = sStat.st_mode & 0777;
    }else{
      rc = SQLITE_IOERR_FSTAT;
    }
  }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    *pMode = 0600;
  }
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214

    default:
      assert(!"Invalid flags argument");
  }
  *pResOut = (osAccess(zPath, amode)==0);
  if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
    struct stat buf;
    if( 0==stat(zPath, &buf) && buf.st_size==0 ){
      *pResOut = 0;
    }
  }
  return SQLITE_OK;
}









|







5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233

    default:
      assert(!"Invalid flags argument");
  }
  *pResOut = (osAccess(zPath, amode)==0);
  if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
    struct stat buf;
    if( 0==osStat(zPath, &buf) && buf.st_size==0 ){
      *pResOut = 0;
    }
  }
  return SQLITE_OK;
}


Changes to src/os_win.c.
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
  const sqlite3_io_methods *pMethod; /*** Must be first ***/
  sqlite3_vfs *pVfs;      /* The VFS used to open this file */
  HANDLE h;               /* Handle for accessing the file */
  unsigned char locktype; /* Type of lock currently held on this file */
  short sharedLockByte;   /* Randomly chosen byte used as a shared lock */

  DWORD lastErrno;        /* The Windows errno from the last I/O error */
  DWORD sectorSize;       /* Sector size of the device file is on */
  winShm *pShm;           /* Instance of shared memory on this file */
  const char *zPath;      /* Full pathname of this file */
  int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */







|

>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
  const sqlite3_io_methods *pMethod; /*** Must be first ***/
  sqlite3_vfs *pVfs;      /* The VFS used to open this file */
  HANDLE h;               /* Handle for accessing the file */
  u8 locktype;            /* Type of lock currently held on this file */
  short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
  u8 bPersistWal;         /* True to persist WAL files */
  DWORD lastErrno;        /* The Windows errno from the last I/O error */
  DWORD sectorSize;       /* Sector size of the device file is on */
  winShm *pShm;           /* Instance of shared memory on this file */
  const char *zPath;      /* Full pathname of this file */
  int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
1331
1332
1333
1334
1335
1336
1337

1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356









1357
1358
1359
1360
1361
1362
1363
  return rc;
}

/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){

  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((winFile*)id)->locktype;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = (int)((winFile*)id)->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      ((winFile*)id)->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 sz = *(sqlite3_int64*)pArg;
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;









    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_WIN32_AV_RETRY: {
      int *a = (int*)pArg;
      if( a[0]>0 ){







>


|



|



|








>
>
>
>
>
>
>
>
>







1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
  return rc;
}

/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){
  winFile *pFile = (winFile*)id;
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = pFile->locktype;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = (int)pFile->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      pFile->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 sz = *(sqlite3_int64*)pArg;
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      int bPersist = *(int*)pArg;
      if( bPersist<0 ){
        *(int*)pArg = pFile->bPersistWal;
      }else{
        pFile->bPersistWal = bPersist!=0;
      }
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_WIN32_AV_RETRY: {
      int *a = (int*)pArg;
      if( a[0]>0 ){
2448
2449
2450
2451
2452
2453
2454

2455
2456
2457
2458
2459

2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470

2471
2472
2473
2474
2475
2476
2477

  SimulateIOError( return SQLITE_IOERR_ACCESS; );
  zConverted = convertUtf8Filename(zFilename);
  if( zConverted==0 ){
    return SQLITE_NOMEM;
  }
  if( isNT() ){

    WIN32_FILE_ATTRIBUTE_DATA sAttrData;
    memset(&sAttrData, 0, sizeof(sAttrData));
    if( GetFileAttributesExW((WCHAR*)zConverted,
                             GetFileExInfoStandard, 
                             &sAttrData) ){

      /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
      ** as if it does not exist.
      */
      if(    flags==SQLITE_ACCESS_EXISTS
          && sAttrData.nFileSizeHigh==0 
          && sAttrData.nFileSizeLow==0 ){
        attr = INVALID_FILE_ATTRIBUTES;
      }else{
        attr = sAttrData.dwFileAttributes;
      }
    }else{

      if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
        winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
        free(zConverted);
        return SQLITE_IOERR_ACCESS;
      }else{
        attr = INVALID_FILE_ATTRIBUTES;
      }







>


|

|
>











>







2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491

  SimulateIOError( return SQLITE_IOERR_ACCESS; );
  zConverted = convertUtf8Filename(zFilename);
  if( zConverted==0 ){
    return SQLITE_NOMEM;
  }
  if( isNT() ){
    int cnt = 0;
    WIN32_FILE_ATTRIBUTE_DATA sAttrData;
    memset(&sAttrData, 0, sizeof(sAttrData));
    while( !(rc = GetFileAttributesExW((WCHAR*)zConverted,
                             GetFileExInfoStandard, 
                             &sAttrData)) && retryIoerr(&cnt) ){}
    if( rc ){
      /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
      ** as if it does not exist.
      */
      if(    flags==SQLITE_ACCESS_EXISTS
          && sAttrData.nFileSizeHigh==0 
          && sAttrData.nFileSizeLow==0 ){
        attr = INVALID_FILE_ATTRIBUTES;
      }else{
        attr = sAttrData.dwFileAttributes;
      }
    }else{
      logIoerr(cnt);
      if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
        winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
        free(zConverted);
        return SQLITE_IOERR_ACCESS;
      }else{
        attr = INVALID_FILE_ATTRIBUTES;
      }
2488
2489
2490
2491
2492
2493
2494

2495
2496
2497
2498
2499
2500
2501
2502
  free(zConverted);
  switch( flags ){
    case SQLITE_ACCESS_READ:
    case SQLITE_ACCESS_EXISTS:
      rc = attr!=INVALID_FILE_ATTRIBUTES;
      break;
    case SQLITE_ACCESS_READWRITE:

      rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
      break;
    default:
      assert(!"Invalid flags argument");
  }
  *pResOut = rc;
  return SQLITE_OK;
}







>
|







2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
  free(zConverted);
  switch( flags ){
    case SQLITE_ACCESS_READ:
    case SQLITE_ACCESS_EXISTS:
      rc = attr!=INVALID_FILE_ATTRIBUTES;
      break;
    case SQLITE_ACCESS_READWRITE:
      rc = attr!=INVALID_FILE_ATTRIBUTES &&
             (attr & FILE_ATTRIBUTE_READONLY)==0;
      break;
    default:
      assert(!"Invalid flags argument");
  }
  *pResOut = rc;
  return SQLITE_OK;
}
Changes to src/sqlite.h.in.
749
750
751
752
753
754
755














756
757
758
759
760
761
762
763
764
765

766
767
768
769
770
771
772
** within the same process.  The argument is a pointer to an array of two
** integers where the first integer i the new retry count and the second
** integer is the delay.  If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
** interrogated.  The zDbName parameter is ignored.
** 














*/
#define SQLITE_FCNTL_LOCKSTATE        1
#define SQLITE_GET_LOCKPROXYFILE      2
#define SQLITE_SET_LOCKPROXYFILE      3
#define SQLITE_LAST_ERRNO             4
#define SQLITE_FCNTL_SIZE_HINT        5
#define SQLITE_FCNTL_CHUNK_SIZE       6
#define SQLITE_FCNTL_FILE_POINTER     7
#define SQLITE_FCNTL_SYNC_OMITTED     8
#define SQLITE_FCNTL_WIN32_AV_RETRY   9


/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only







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










>







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
** within the same process.  The argument is a pointer to an array of two
** integers where the first integer i the new retry count and the second
** integer is the delay.  If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
** interrogated.  The zDbName parameter is ignored.
** 
** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
** persistent [WAL | Write AHead Log] setting.  By default, the auxiliary
** write ahead log and shared memory files used for transaction control
** are automatically deleted when the latest connection to the database
** closes.  Setting persistent WAL mode causes those files to persist after
** close.  Persisting the files is useful when other processes that do not
** have write permission on the directory containing the database file want
** to read the database file, as the WAL and shared memory files must exist
** in order for the database to be readable.  The fourth parameter to
** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
** That integer is 0 to disable persistent WAL mode or 1 to enable persistent
** WAL mode.  If the integer is -1, then it is overwritten with the current
** WAL persistence setting.
** 
*/
#define SQLITE_FCNTL_LOCKSTATE        1
#define SQLITE_GET_LOCKPROXYFILE      2
#define SQLITE_SET_LOCKPROXYFILE      3
#define SQLITE_LAST_ERRNO             4
#define SQLITE_FCNTL_SIZE_HINT        5
#define SQLITE_FCNTL_CHUNK_SIZE       6
#define SQLITE_FCNTL_FILE_POINTER     7
#define SQLITE_FCNTL_SYNC_OMITTED     8
#define SQLITE_FCNTL_WIN32_AV_RETRY   9
#define SQLITE_FCNTL_PERSIST_WAL     10

/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only
Changes to src/test1.c.
5125
5126
5127
5128
5129
5130
5131
































5132
5133
5134
5135
5136
5137
5138
  if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
  sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}


































/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(







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







5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
  if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
  sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}

/*
** tclcmd:   file_control_persist_wal DB PERSIST-FLAG
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_PERSIST_WAL opcode.
*/
static int file_control_persist_wal(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  int rc;
  int bPersist;
  char z[100];

  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
  sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}


/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(
5924
5925
5926
5927
5928
5929
5930

5931
5932
5933
5934
5935
5936
5937
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },

     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },







>







5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
     { "file_control_persist_wal",    file_control_persist_wal,     0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },
Changes to src/test_multiplex.c.
410
411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
static void multiplexSubClose(
  multiplexGroup *pGroup,
  int iChunk,
  sqlite3_vfs *pOrigVfs
){
  sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
  if( pSubOpen ){
    if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
    pSubOpen->pMethods->xClose(pSubOpen);

    sqlite3_free(pGroup->aReal[iChunk].p);
  }
  sqlite3_free(pGroup->aReal[iChunk].z);
  memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
}

/*







<

>







410
411
412
413
414
415
416

417
418
419
420
421
422
423
424
425
static void multiplexSubClose(
  multiplexGroup *pGroup,
  int iChunk,
  sqlite3_vfs *pOrigVfs
){
  sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
  if( pSubOpen ){

    pSubOpen->pMethods->xClose(pSubOpen);
    if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
    sqlite3_free(pGroup->aReal[iChunk].p);
  }
  sqlite3_free(pGroup->aReal[iChunk].z);
  memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
}

/*
Changes to src/vdbe.c.
1033
1034
1035
1036
1037
1038
1039





1040
1041
1042
1043
1044
1045
1046
    assert( pOut<=&aMem[p->nMem] );
    assert( pIn1<=&aMem[p->nMem] );
    assert( memIsValid(pIn1) );
    memAboutToChange(p, pOut);
    zMalloc = pOut->zMalloc;
    pOut->zMalloc = 0;
    sqlite3VdbeMemMove(pOut, pIn1);





    pIn1->zMalloc = zMalloc;
    REGISTER_TRACE(p2++, pOut);
    pIn1++;
    pOut++;
  }
  break;
}







>
>
>
>
>







1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
    assert( pOut<=&aMem[p->nMem] );
    assert( pIn1<=&aMem[p->nMem] );
    assert( memIsValid(pIn1) );
    memAboutToChange(p, pOut);
    zMalloc = pOut->zMalloc;
    pOut->zMalloc = 0;
    sqlite3VdbeMemMove(pOut, pIn1);
#ifdef SQLITE_DEBUG
    if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){
      pOut->pScopyFrom += p1 - pOp->p2;
    }
#endif
    pIn1->zMalloc = zMalloc;
    REGISTER_TRACE(p2++, pOut);
    pIn1++;
    pOut++;
  }
  break;
}
Changes to src/wal.c.
1800
1801
1802
1803
1804
1805
1806

1807
1808
1809
1810
1811
1812

1813
1814
1815
1816
1817
1818
1819
1820
    ** the database. In this case checkpoint the database and unlink both
    ** the wal and wal-index files.
    **
    ** The EXCLUSIVE lock is not released before returning.
    */
    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){

      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
      }
      rc = sqlite3WalCheckpoint(
          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
      );

      if( rc==SQLITE_OK ){
        isDelete = 1;
      }
    }

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){







>






>
|







1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
    ** the database. In this case checkpoint the database and unlink both
    ** the wal and wal-index files.
    **
    ** The EXCLUSIVE lock is not released before returning.
    */
    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){
      int bPersistWal = -1;
      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
      }
      rc = sqlite3WalCheckpoint(
          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
      );
      sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal);
      if( rc==SQLITE_OK && bPersistWal!=1 ){
        isDelete = 1;
      }
    }

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){
Changes to src/where.c.
2138
2139
2140
2141
2142
2143
2144

2145
2146
2147
2148
2149
2150
2151
  ** to this virtual table */
  for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    if( pTerm->leftCursor != pSrc->iCursor ) continue;
    assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
    testcase( pTerm->eOperator==WO_IN );
    testcase( pTerm->eOperator==WO_ISNULL );
    if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;

    nTerm++;
  }

  /* If the ORDER BY clause contains only columns in the current 
  ** virtual table then allocate space for the aOrderBy part of
  ** the sqlite3_index_info structure.
  */







>







2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
  ** to this virtual table */
  for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    if( pTerm->leftCursor != pSrc->iCursor ) continue;
    assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
    testcase( pTerm->eOperator==WO_IN );
    testcase( pTerm->eOperator==WO_ISNULL );
    if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
    if( pTerm->wtFlags & TERM_VNULL ) continue;
    nTerm++;
  }

  /* If the ORDER BY clause contains only columns in the current 
  ** virtual table then allocate space for the aOrderBy part of
  ** the sqlite3_index_info structure.
  */
2188
2189
2190
2191
2192
2193
2194

2195
2196
2197
2198
2199
2200
2201

  for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    if( pTerm->leftCursor != pSrc->iCursor ) continue;
    assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
    testcase( pTerm->eOperator==WO_IN );
    testcase( pTerm->eOperator==WO_ISNULL );
    if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;

    pIdxCons[j].iColumn = pTerm->u.leftColumn;
    pIdxCons[j].iTermOffset = i;
    pIdxCons[j].op = (u8)pTerm->eOperator;
    /* The direct assignment in the previous line is possible only because
    ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
    ** following asserts verify this fact. */
    assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );







>







2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203

  for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    if( pTerm->leftCursor != pSrc->iCursor ) continue;
    assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
    testcase( pTerm->eOperator==WO_IN );
    testcase( pTerm->eOperator==WO_ISNULL );
    if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
    if( pTerm->wtFlags & TERM_VNULL ) continue;
    pIdxCons[j].iColumn = pTerm->u.leftColumn;
    pIdxCons[j].iTermOffset = i;
    pIdxCons[j].op = (u8)pTerm->eOperator;
    /* The direct assignment in the previous line is possible only because
    ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
    ** following asserts verify this fact. */
    assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
Changes to test/permutations.test.
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  e_fts3.test fts3cov.test fts3malloc.test fts3rnd.test
  fts3snippet.test

  # Exclude test scripts that use tcl IO to access journal files or count
  # the number of fsync() calls.
  pager.test exclusive.test jrnlmode.test sync.test misc1.test 
  journal1.test conflict.test crash8.test tkt3457.test io.test
  journal3.test

  pager1.test async4.test corrupt.test filefmt.test pager2.test
  corrupt5.test corruptA.test pageropt.test

  # Exclude stmt.test, which expects sub-journals to use temporary files.
  stmt.test

  # WAL mode is different.
  wal* tkt-2d1a5c67d.test
}]

ifcapable mem3 {
  test_suite "memsys3" -description {
    Run tests using the allocator in mem3.c.
  } -files [test_set $::allquicktests -exclude {
    autovacuum.test           delete3.test              manydb.test







|








|







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  e_fts3.test fts3cov.test fts3malloc.test fts3rnd.test
  fts3snippet.test

  # Exclude test scripts that use tcl IO to access journal files or count
  # the number of fsync() calls.
  pager.test exclusive.test jrnlmode.test sync.test misc1.test 
  journal1.test conflict.test crash8.test tkt3457.test io.test
  journal3.test 8_3_names.test

  pager1.test async4.test corrupt.test filefmt.test pager2.test
  corrupt5.test corruptA.test pageropt.test

  # Exclude stmt.test, which expects sub-journals to use temporary files.
  stmt.test

  # WAL mode is different.
  wal* tkt-2d1a5c67d.test backcompat.test
}]

ifcapable mem3 {
  test_suite "memsys3" -description {
    Run tests using the allocator in mem3.c.
  } -files [test_set $::allquicktests -exclude {
    autovacuum.test           delete3.test              manydb.test
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
} -initialize {
  catch {db close}
  register_jt_vfs -default ""
} -shutdown {
  unregister_jt_vfs
} -files [test_set $::allquicktests -exclude {
  wal* incrvacuum.test ioerr.test corrupt4.test io.test crash8.test 
  async4.test bigfile.test
}]

if {[info commands register_demovfs] != ""} {
  test_suite "demovfs" -description {
    Check that the demovfs (code in test_demovfs.c) more or less works.
  } -initialize {
    register_demovfs







|







725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
} -initialize {
  catch {db close}
  register_jt_vfs -default ""
} -shutdown {
  unregister_jt_vfs
} -files [test_set $::allquicktests -exclude {
  wal* incrvacuum.test ioerr.test corrupt4.test io.test crash8.test 
  async4.test bigfile.test backcompat.test
}]

if {[info commands register_demovfs] != ""} {
  test_suite "demovfs" -description {
    Check that the demovfs (code in test_demovfs.c) more or less works.
  } -initialize {
    register_demovfs
868
869
870
871
872
873
874
875
      if {[llength $argv]>1} { set extra [list -files [lrange $argv 1 end]] }
      eval run_tests $suite $::testspec($suite) $extra
    }
  }
  main $argv
  finish_test
}








<
868
869
870
871
872
873
874

      if {[llength $argv]>1} { set extra [list -files [lrange $argv 1 end]] }
      eval run_tests $suite $::testspec($suite) $extra
    }
  }
  main $argv
  finish_test
}

Added test/tkt-d635236375.test.












































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 2011 August 3
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing that bug [d63523637517386191d634e]
# has been fixed.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

set ::testprefix tkt-d635236375

do_test 1.0 {
  execsql {
    CREATE TABLE t1(id1 INTEGER PRIMARY KEY);
    INSERT INTO t1 VALUES(9999);
    CREATE TABLE t2(id2 INTEGER PRIMARY KEY);
    INSERT INTO t2 VALUES(12345);
    INSERT INTO t2 VALUES(54321);
    SELECT DISTINCT id1 AS x, id1 AS y FROM t1, t2;
  }
} {9999 9999}
do_test 1.1 {
  execsql {
    SELECT count(*) FROM t1, t2 GROUP BY id1, id1;
  }
} {2}


finish_test
Added test/vtabF.test.


























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 2011 Aug 1
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. 
# This file checks to make sure IS NOT NULL constraints work on
# virtual tables.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !vtab||!schema_pragmas { finish_test ; return }

# Register the echo module
register_echo_module [sqlite3_connection_pointer db]

do_test vtabE-1.1 {
  execsql {
    CREATE TABLE t1(a, b);
    CREATE INDEX i1 ON t1(a);
    CREATE INDEX i2 ON t1(b);
    INSERT INTO t1 VALUES(10,110);
    INSERT INTO t1 VALUES(11,111);
    INSERT INTO t1 SELECT a+2, b+2 FROM t1;
    INSERT INTO t1 SELECT null, b+4 FROM t1;
    INSERT INTO t1 SELECT null, b+8 FROM t1;
    INSERT INTO t1 SELECT null, b+16 FROM t1;
    ANALYZE;
    CREATE VIRTUAL TABLE tv1 USING echo(t1);
    SELECT b FROM t1 WHERE a IS NOT NULL;
  }
} {110 111 112 113}
do_test vtabE-1.2 {
  execsql {SELECT b FROM tv1 WHERE a IS NOT NULL}
} {110 111 112 113}


finish_test
Changes to test/wal5.test.
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
    } {}
    do_test 2.3.$tn.2 { file_page_counts } {1 5 1 5}
    do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
    do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
    do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
    do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7}
    do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 7 5}
    if {$tcl_platform(platform) == "windows"} {
        # on unix, the size_hint is a no-op if no chunk size is set.
        # the windows implementation does not have a similar check,
        # and because of this, the db file size has an extra page.
        do_test 2.3.$tn.8 { file_page_counts } {2 7 2 7}
    } {
        do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7}
    }
  }

  # Check that checkpoints block on the correct locks. And respond correctly
  # if they cannot obtain those locks. There are three locks that a checkpoint
  # may block on (in the following order):
  #
  #   1. The writer lock: FULL and RESTART checkpoints block until any writer







<
<
<
<

<
<
<







231
232
233
234
235
236
237




238



239
240
241
242
243
244
245
    } {}
    do_test 2.3.$tn.2 { file_page_counts } {1 5 1 5}
    do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
    do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
    do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
    do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7}
    do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 7 5}




        do_test 2.3.$tn.8 { file_page_counts } {2 7 2 7}



  }

  # Check that checkpoints block on the correct locks. And respond correctly
  # if they cannot obtain those locks. There are three locks that a checkpoint
  # may block on (in the following order):
  #
  #   1. The writer lock: FULL and RESTART checkpoints block until any writer
346
347
348
349
350
351
352
353

    do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0}
  }
}


finish_test








<
339
340
341
342
343
344
345


    do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0}
  }
}


finish_test

Added test/walpersist.test.








































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
# 2011 July 26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains tests for using WAL with persistent WAL file mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
set ::testprefix walpersist

do_test walpersist-1.0 {
  db eval {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(randomblob(5000));
  }
  file exists test.db-wal
} {1}
do_test walpersist-1.1 {
  file exists test.db-shm
} {1}
do_test walpersist-1.2 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 0 0}
do_test walpersist-1.3 {
  sqlite3 db test.db
  db eval {SELECT length(a) FROM t1}
} {5000}
do_test walpersist-1.4 {
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}
do_test walpersist-1.5 {
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.6 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.7 {
  file_control_persist_wal db -1
} {0 1}
do_test walpersist-1.8 {
  file_control_persist_wal db 0
} {0 0}
do_test walpersist-1.9 {
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.10 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.11 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}

  


finish_test
Changes to test/win32lock.test.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
       set ::msg
    } {disk I/O error}
    break
  } else {
    do_test win32lock-1.2-$delay1 {
       set ::msg
    } {1 100000 2 50000 3 25000 4 12500}
    if {$::log!=""} {
      do_test win32lock-1.2-$delay1-log1 {
        regsub {\d+} $::log # x
        set x
      } {{delayed #ms for lock/sharing conflict}}
    }
    incr delay1 50
  }







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
       set ::msg
    } {disk I/O error}
    break
  } else {
    do_test win32lock-1.2-$delay1 {
       set ::msg
    } {1 100000 2 50000 3 25000 4 12500}
    if {[info exists ::log] && $::log!=""} {
      do_test win32lock-1.2-$delay1-log1 {
        regsub {\d+} $::log # x
        set x
      } {{delayed #ms for lock/sharing conflict}}
    }
    incr delay1 50
  }