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

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

Overview
Comment:Merge the fix to PRAGMA data_version and testing improvements from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 86e39123c1bca457672bc63eff00a823745077e5
User & Date: drh 2014-12-31 14:27:29
Context
2015-01-08
20:06
Merge recent enhancements from trunk, including test scripts enhancements and the removal of limits on the number of terms in a VALUES clause. check-in: 5a2dec55 user: drh tags: sessions
2014-12-31
14:27
Merge the fix to PRAGMA data_version and testing improvements from trunk. check-in: 86e39123 user: drh tags: sessions
14:18
Make sure PRAGMA data_version is updated even if the cache is empty when another connection changes the database. check-in: cf48eb60 user: drh tags: trunk
2014-12-22
18:48
Merge the PRAGMA data_version redefinition and other fixes from trunk. check-in: 315243e4 user: drh tags: sessions
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

535
536
537
538
539
540
541





542
543
544
545
546
547
548
...
980
981
982
983
984
985
986




























987
988
989
990
991
992
993
		-o $@ $(TOP)/src/shell.c libsqlite3.la \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

mptester$(EXE):	sqlite3.c $(TOP)/mptest/mptest.c
	$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
		$(TLIBS) -rpath "$(libdir)"







# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
................................................................................
	$(LTLINK) -I. -o $@ $(TOP)/tool/logest.c

wordcount$(TEXE):	$(TOP)/test/wordcount.c sqlite3.c
	$(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.c $(TLIBS)

speedtest1$(TEXE):	$(TOP)/test/wordcount.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS)





























# Standard install and cleanup targets
#
lib_install:	libsqlite3.la
	$(INSTALL) -d $(DESTDIR)$(libdir)
	$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
	







>
>
>
>
>







 







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







535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
...
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
		-o $@ $(TOP)/src/shell.c libsqlite3.la \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

mptester$(EXE):	sqlite3.c $(TOP)/mptest/mptest.c
	$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
		$(TLIBS) -rpath "$(libdir)"

mptest:	mptester$(EXE)
	rm -f mptest1.db
	./mptester$(EXE) mptest1.db $(TOP)/mptest/crash01.test
	rm -f mptest2.db
	./mptester$(EXE) mptest2.db $(TOP)/mptest/multiwrite01.test

# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
................................................................................
	$(LTLINK) -I. -o $@ $(TOP)/tool/logest.c

wordcount$(TEXE):	$(TOP)/test/wordcount.c sqlite3.c
	$(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.c $(TLIBS)

speedtest1$(TEXE):	$(TOP)/test/wordcount.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS)

# This target will fail if the SQLite amalgamation contains any exported
# symbols that do not begin with "sqlite3_". It is run as part of the
# releasetest.tcl script.
#
checksymbols: sqlite3.lo
	nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0
	echo '0 errors out of 1 tests'

# The next two rules are used to support the "threadtest" target. Building
# threadtest runs a few thread-safety tests that are implemented in C. This
# target is invoked by the releasetest.tcl script.
# 
THREADTEST3_SRC = $(TOP)/test/threadtest3.c    \
                  $(TOP)/test/tt3_checkpoint.c \
                  $(TOP)/test/tt3_index.c      \
                  $(TOP)/test/tt3_vacuum.c      \
                  $(TOP)/test/tt3_stress.c      \
                  $(TOP)/test/tt3_lookaside1.c

threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC)
	$(LTLINK) $(TOP)/test/threadtest3.c sqlite3.lo -o $@ $(TLIBS)

threadtest: threadtest3$(TEXE)
	./threadtest3$(TEXE)

releasetest:	
	$(TCLSH_CMD) $(TOP)/test/releasetest.tcl

# Standard install and cleanup targets
#
lib_install:	libsqlite3.la
	$(INSTALL) -d $(DESTDIR)$(libdir)
	$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
	

Changes to mptest/mptest.c.

1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
    }
    sqlite3_finalize(pStmt);
  }
  sqlite3_close(g.db);  
  maybeClose(g.pLog);
  maybeClose(g.pErrLog);
  if( iClient==0 ){
    printf("Summary: %d errors in %d tests\n", g.nError, g.nTest);
  }
  return g.nError>0;
}







|



1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
    }
    sqlite3_finalize(pStmt);
  }
  sqlite3_close(g.db);  
  maybeClose(g.pLog);
  maybeClose(g.pErrLog);
  if( iClient==0 ){
    printf("Summary: %d errors out of %d tests\n", g.nError, g.nTest);
  }
  return g.nError>0;
}

Changes to src/btree.c.

6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
....
9142
9143
9144
9145
9146
9147
9148
9149
        memcpy(apCell[nCell], &pOld->aData[8], 4);
      }else{
        assert( leafCorrection==4 );
        if( szCell[nCell]<4 ){
          /* Do not allow any cells smaller than 4 bytes. If a smaller cell
          ** does exist, pad it with 0x00 bytes. */
          assert( szCell[nCell]==3 );
          assert( apCell[nCell]==&pTemp[iSpace1-3] );
          pTemp[iSpace1++] = 0x00;
          szCell[nCell] = 4;
        }
      }
      nCell++;
    }
  }

................................................................................
int sqlite3BtreeIsReadonly(Btree *p){
  return (p->pBt->btsFlags & BTS_READ_ONLY)!=0;
}

/*
** Return the size of the header added to each page by this module.
*/
int sqlite3HeaderSizeBtree(void){ return sizeof(MemPage); }







|
|







 







|
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
....
9142
9143
9144
9145
9146
9147
9148
9149
        memcpy(apCell[nCell], &pOld->aData[8], 4);
      }else{
        assert( leafCorrection==4 );
        if( szCell[nCell]<4 ){
          /* Do not allow any cells smaller than 4 bytes. If a smaller cell
          ** does exist, pad it with 0x00 bytes. */
          assert( szCell[nCell]==3 );
          assert( apCell[nCell]==&aSpace1[iSpace1-3] );
          aSpace1[iSpace1++] = 0x00;
          szCell[nCell] = 4;
        }
      }
      nCell++;
    }
  }

................................................................................
int sqlite3BtreeIsReadonly(Btree *p){
  return (p->pBt->btsFlags & BTS_READ_ONLY)!=0;
}

/*
** Return the size of the header added to each page by this module.
*/
int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }

Changes to src/build.c.

1709
1710
1711
1712
1713
1714
1715













1716
1717
1718
1719
1720
1721
1722
    assert( pParse->pNewTable==pTab );
    pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
    if( pPk==0 ) return;
    pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
    pTab->iPKey = -1;
  }else{
    pPk = sqlite3PrimaryKeyIndex(pTab);













  }
  pPk->isCovering = 1;
  assert( pPk!=0 );
  nPk = pPk->nKeyCol;

  /* Make sure every column of the PRIMARY KEY is NOT NULL */
  for(i=0; i<nPk; i++){







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







1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
    assert( pParse->pNewTable==pTab );
    pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
    if( pPk==0 ) return;
    pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
    pTab->iPKey = -1;
  }else{
    pPk = sqlite3PrimaryKeyIndex(pTab);
    /*
    ** Remove all redundant columns from the PRIMARY KEY.  For example, change
    ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)".  Later
    ** code assumes the PRIMARY KEY contains no repeated columns.
    */
    for(i=j=1; i<pPk->nKeyCol; i++){
      if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){
        pPk->nColumn--;
      }else{
        pPk->aiColumn[j++] = pPk->aiColumn[i];
      }
    }
    pPk->nKeyCol = j;
  }
  pPk->isCovering = 1;
  assert( pPk!=0 );
  nPk = pPk->nKeyCol;

  /* Make sure every column of the PRIMARY KEY is NOT NULL */
  for(i=0; i<nPk; i++){

Changes to src/main.c.

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
...
267
268
269
270
271
272
273







274
275
276
277
278
279
280
#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
/*
** If the following function pointer is not NULL and if
** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
** I/O active are written using this function.  These messages
** are intended for debugging activity only.
*/
void (*sqlite3IoTrace)(const char*, ...) = 0;
#endif

/*
** If the following global variable points to a string which is the
** name of a directory, then that directory will be used to store
** temporary files.
**
................................................................................
** there are outstanding database connections or memory allocations or
** while any part of SQLite is otherwise in use in any thread.  This
** routine is not threadsafe.  But it is safe to invoke this routine
** on when SQLite is already shut down.  If SQLite is already shut down
** when this routine is invoked, then this routine is a harmless no-op.
*/
int sqlite3_shutdown(void){







  if( sqlite3GlobalConfig.isInit ){
#ifdef SQLITE_EXTRA_SHUTDOWN
    void SQLITE_EXTRA_SHUTDOWN(void);
    SQLITE_EXTRA_SHUTDOWN();
#endif
    sqlite3_os_end();
    sqlite3_reset_auto_extension();







|







 







>
>
>
>
>
>
>







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
/*
** If the following function pointer is not NULL and if
** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
** I/O active are written using this function.  These messages
** are intended for debugging activity only.
*/
/* not-private */ void (*sqlite3IoTrace)(const char*, ...) = 0;
#endif

/*
** If the following global variable points to a string which is the
** name of a directory, then that directory will be used to store
** temporary files.
**
................................................................................
** there are outstanding database connections or memory allocations or
** while any part of SQLite is otherwise in use in any thread.  This
** routine is not threadsafe.  But it is safe to invoke this routine
** on when SQLite is already shut down.  If SQLite is already shut down
** when this routine is invoked, then this routine is a harmless no-op.
*/
int sqlite3_shutdown(void){
#ifdef SQLITE_OMIT_WSD
  int rc = sqlite3_wsd_init(4096, 24);
  if( rc!=SQLITE_OK ){
    return rc;
  }
#endif

  if( sqlite3GlobalConfig.isInit ){
#ifdef SQLITE_EXTRA_SHUTDOWN
    void SQLITE_EXTRA_SHUTDOWN(void);
    SQLITE_EXTRA_SHUTDOWN();
#endif
    sqlite3_os_end();
    sqlite3_reset_auto_extension();

Changes to src/os_unix.c.

3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715

3716
3717
3718
3719
3720
3721
3722
3723
3724
3725



3726
3727
3728

3729


3730
3731
3732
3733
3734
3735
3736
      ** or an error number on  failure". See the manpage for details. */
      int err;
      do{
        err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
      }while( err==EINTR );
      if( err ) return SQLITE_IOERR_WRITE;
#else
      /* If the OS does not have posix_fallocate(), fake it. First use
      ** ftruncate() to set the file size, then write a single byte to
      ** the last byte in each block within the extended region. This
      ** is the same technique used by glibc to implement posix_fallocate()

      ** on systems that do not have a real fallocate() system call.
      */
      int nBlk = buf.st_blksize;  /* File-system block size */
      i64 iWrite;                 /* Next offset to write to */

      if( robust_ftruncate(pFile->h, nSize) ){
        pFile->lastErrno = errno;
        return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
      }
      iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;



      while( iWrite<nSize ){
        int nWrite = seekAndWrite(pFile, iWrite, "", 1);
        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;

        iWrite += nBlk;


      }
#endif
    }
  }

#if SQLITE_MAX_MMAP_SIZE>0
  if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){







|
|
|
|
>
|




<
<
<
<

>
>
>
|


>
|
>
>







3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721




3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
      ** or an error number on  failure". See the manpage for details. */
      int err;
      do{
        err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
      }while( err==EINTR );
      if( err ) return SQLITE_IOERR_WRITE;
#else
      /* If the OS does not have posix_fallocate(), fake it. Write a 
      ** single byte to the last byte in each block that falls entirely
      ** within the extended region. Then, if required, a single byte
      ** at offset (nSize-1), to set the size of the file correctly.
      ** This is a similar technique to that used by glibc on systems
      ** that do not have a real fallocate() call.
      */
      int nBlk = buf.st_blksize;  /* File-system block size */
      i64 iWrite;                 /* Next offset to write to */





      iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
      assert( iWrite>=buf.st_size );
      assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
      assert( ((iWrite+1)%nBlk)==0 );
      for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
        int nWrite = seekAndWrite(pFile, iWrite, "", 1);
        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
      }
      if( nSize%nBlk ){
        int nWrite = seekAndWrite(pFile, nSize-1, "", 1);
        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
      }
#endif
    }
  }

#if SQLITE_MAX_MMAP_SIZE>0
  if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){

Changes to src/pager.c.

643
644
645
646
647
648
649

650
651
652
653
654
655
656
....
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
....
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
....
5298
5299
5300
5301
5302
5303
5304

5305
5306
5307
5308
5309
5310
5311
....
5447
5448
5449
5450
5451
5452
5453

5454
5455
5456
5457
5458
5459
5460
  u8 eState;                  /* Pager state (OPEN, READER, WRITER_LOCKED..) */
  u8 eLock;                   /* Current lock held on database file */
  u8 changeCountDone;         /* Set after incrementing the change-counter */
  u8 setMaster;               /* True if a m-j name has been written to jrnl */
  u8 doNotSpill;              /* Do not spill the cache when non-zero */
  u8 subjInMemory;            /* True to use in-memory sub-journals */
  u8 bUseFetch;               /* True to use xFetch() */

  Pgno dbSize;                /* Number of pages in the database */
  Pgno dbOrigSize;            /* dbSize before the current transaction */
  Pgno dbFileSize;            /* Number of pages in the database file */
  Pgno dbHintSize;            /* Value passed to FCNTL_SIZE_HINT call */
  int errCode;                /* One of several kinds of errors */
  int nRec;                   /* Pages journalled since last j-header written */
  u32 cksumInit;              /* Quasi-random value added to every checksum */
................................................................................
static int pagerAcquireMapPage(
  Pager *pPager,                  /* Pager object */
  Pgno pgno,                      /* Page number */
  void *pData,                    /* xFetch()'d data for this page */
  PgHdr **ppPage                  /* OUT: Acquired page object */
){
  PgHdr *p;                       /* Memory mapped page to return */

  if( pPager->pMmapFreelist ){
    *ppPage = p = pPager->pMmapFreelist;
    pPager->pMmapFreelist = p->pDirty;
    p->pDirty = 0;
    memset(p->pExtra, 0, pPager->nExtra);
  }else{
    *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
................................................................................

      assert( pPager->eState==PAGER_OPEN );
      assert( (pPager->eLock==SHARED_LOCK)
           || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
      );
    }

    if( !pPager->tempFile && (
        pPager->pBackup 
     || sqlite3PcachePagecount(pPager->pPCache)>0 
     || USEFETCH(pPager)
    )){
      /* The shared-lock has just been acquired on the database file
      ** and there are already pages in the cache (from a previous
      ** read or write transaction).  Check to see if the database
      ** has been modified.  If the database has changed, flush the
      ** cache.
      **
      ** Database changes is detected by looking at 15 bytes beginning
      ** at offset 24 into the file.  The first 4 of these 16 bytes are
      ** a 32-bit counter that is incremented with each change.  The
      ** other bytes change randomly with each file change when
      ** a codec is in use.
      ** 
................................................................................
  assert( pPager->eState>=PAGER_READER );
  assert( assert_pager_state(pPager) );
  assert( noContent==0 || bMmapOk==0 );

  if( pgno==0 ){
    return SQLITE_CORRUPT_BKPT;
  }


  /* If the pager is in the error state, return an error immediately. 
  ** Otherwise, request the page from the PCache layer. */
  if( pPager->errCode!=SQLITE_OK ){
    rc = pPager->errCode;
  }else{
    if( bMmapOk && pagerUseWal(pPager) ){
................................................................................
*/
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
  sqlite3_pcache_page *pPage;
  assert( pPager!=0 );
  assert( pgno!=0 );
  assert( pPager->pPCache!=0 );
  pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);

  return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
}

/*
** Release a page reference.
**
** If the number of references to the page drop to zero, then the







>







 







|







 







|
|
|
|
|
|
<
<
<
<







 







>







 







>







643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
....
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
....
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137




5138
5139
5140
5141
5142
5143
5144
....
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
....
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
  u8 eState;                  /* Pager state (OPEN, READER, WRITER_LOCKED..) */
  u8 eLock;                   /* Current lock held on database file */
  u8 changeCountDone;         /* Set after incrementing the change-counter */
  u8 setMaster;               /* True if a m-j name has been written to jrnl */
  u8 doNotSpill;              /* Do not spill the cache when non-zero */
  u8 subjInMemory;            /* True to use in-memory sub-journals */
  u8 bUseFetch;               /* True to use xFetch() */
  u8 hasBeenUsed;             /* True if any content previously read from this pager*/
  Pgno dbSize;                /* Number of pages in the database */
  Pgno dbOrigSize;            /* dbSize before the current transaction */
  Pgno dbFileSize;            /* Number of pages in the database file */
  Pgno dbHintSize;            /* Value passed to FCNTL_SIZE_HINT call */
  int errCode;                /* One of several kinds of errors */
  int nRec;                   /* Pages journalled since last j-header written */
  u32 cksumInit;              /* Quasi-random value added to every checksum */
................................................................................
static int pagerAcquireMapPage(
  Pager *pPager,                  /* Pager object */
  Pgno pgno,                      /* Page number */
  void *pData,                    /* xFetch()'d data for this page */
  PgHdr **ppPage                  /* OUT: Acquired page object */
){
  PgHdr *p;                       /* Memory mapped page to return */
  
  if( pPager->pMmapFreelist ){
    *ppPage = p = pPager->pMmapFreelist;
    pPager->pMmapFreelist = p->pDirty;
    p->pDirty = 0;
    memset(p->pExtra, 0, pPager->nExtra);
  }else{
    *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
................................................................................

      assert( pPager->eState==PAGER_OPEN );
      assert( (pPager->eLock==SHARED_LOCK)
           || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
      );
    }

    if( !pPager->tempFile && pPager->hasBeenUsed ){
      /* The shared-lock has just been acquired then check to
      ** see if the database has been modified.  If the database has changed,
      ** flush the cache.  The pPager->hasBeenUsed flag prevents this from
      ** occurring on the very first access to a file, in order to save a
      ** single unnecessary sqlite3OsRead() call at the start-up.




      **
      ** Database changes is detected by looking at 15 bytes beginning
      ** at offset 24 into the file.  The first 4 of these 16 bytes are
      ** a 32-bit counter that is incremented with each change.  The
      ** other bytes change randomly with each file change when
      ** a codec is in use.
      ** 
................................................................................
  assert( pPager->eState>=PAGER_READER );
  assert( assert_pager_state(pPager) );
  assert( noContent==0 || bMmapOk==0 );

  if( pgno==0 ){
    return SQLITE_CORRUPT_BKPT;
  }
  pPager->hasBeenUsed = 1;

  /* If the pager is in the error state, return an error immediately. 
  ** Otherwise, request the page from the PCache layer. */
  if( pPager->errCode!=SQLITE_OK ){
    rc = pPager->errCode;
  }else{
    if( bMmapOk && pagerUseWal(pPager) ){
................................................................................
*/
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
  sqlite3_pcache_page *pPage;
  assert( pPager!=0 );
  assert( pgno!=0 );
  assert( pPager->pPCache!=0 );
  pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
  assert( pPage==0 || pPager->hasBeenUsed );
  return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
}

/*
** Release a page reference.
**
** If the number of references to the page drop to zero, then the

Changes to src/pcache.c.

192
193
194
195
196
197
198
199

200
201
202
203
204
205
206
...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
** are no outstanding page references when this function is called.
*/
int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
  assert( pCache->nRef==0 && pCache->pDirty==0 );
  if( pCache->szPage ){
    sqlite3_pcache *pNew;
    pNew = sqlite3GlobalConfig.pcache2.xCreate(
                szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable

    );
    if( pNew==0 ) return SQLITE_NOMEM;
    sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
    if( pCache->pCache ){
      sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
    }
    pCache->pCache = pNew;
................................................................................
  sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
}

/*
** Return the size of the header added by this middleware layer
** in the page-cache hierarchy.
*/
int sqlite3HeaderSizePcache(void){ return sizeof(PgHdr); }


#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
** For all dirty pages currently in the cache, invoke the specified
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
** defined.







|
>







 







|







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
...
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
** are no outstanding page references when this function is called.
*/
int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
  assert( pCache->nRef==0 && pCache->pDirty==0 );
  if( pCache->szPage ){
    sqlite3_pcache *pNew;
    pNew = sqlite3GlobalConfig.pcache2.xCreate(
                szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
                pCache->bPurgeable
    );
    if( pNew==0 ) return SQLITE_NOMEM;
    sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
    if( pCache->pCache ){
      sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
    }
    pCache->pCache = pNew;
................................................................................
  sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
}

/*
** Return the size of the header added by this middleware layer
** in the page-cache hierarchy.
*/
int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }


#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
** For all dirty pages currently in the cache, invoke the specified
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
** defined.

Changes to src/pcache1.c.

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
  p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
  if( !pPg || !p ){
    pcache1Free(pPg);
    sqlite3_free(p);
    pPg = 0;
  }
#else
  pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra);
  p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
  pcache1EnterMutex(pCache->pGroup);

  if( pPg ){
    p->page.pBuf = pPg;
    p->page.pExtra = &p[1];
................................................................................
  };
  sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
}

/*
** Return the size of the header on each page of this PCACHE implementation.
*/
int sqlite3HeaderSizePcache1(void){ return sizeof(PgHdr1); }

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
** held by the pager system. Memory in use by any SQLite pager allocated
** by the current thread may be sqlite3_free()ed.
**







|







 







|







292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
  p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
  if( !pPg || !p ){
    pcache1Free(pPg);
    sqlite3_free(p);
    pPg = 0;
  }
#else
  pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
  p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
  pcache1EnterMutex(pCache->pGroup);

  if( pPg ){
    p->page.pBuf = pPg;
    p->page.pExtra = &p[1];
................................................................................
  };
  sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
}

/*
** Return the size of the header on each page of this PCACHE implementation.
*/
int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
** held by the pager system. Memory in use by any SQLite pager allocated
** by the current thread may be sqlite3_free()ed.
**

Changes to src/sqlite.h.in.

1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
** This configuration should not be used if an application-define page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
** configuration option.
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 32768) plus some extra bytes for each
** page header.  ^The number of extra bytes needed by the page header
** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option 
** to [sqlite3_config()].
** ^It is harmless, apart from the wasted memory,
** for the sz parameter to be larger than necessary.  The first
** argument should pointer to an 8-byte aligned block of memory that
** is at least sz*N bytes of memory, otherwise subsequent behavior is







|







1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
** This configuration should not be used if an application-define page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
** configuration option.
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header.  ^The number of extra bytes needed by the page header
** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option 
** to [sqlite3_config()].
** ^It is harmless, apart from the wasted memory,
** for the sz parameter to be larger than necessary.  The first
** argument should pointer to an 8-byte aligned block of memory that
** is at least sz*N bytes of memory, otherwise subsequent behavior is

Changes to src/test1.c.

3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
  rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0);
  free(zCopy);
  zTail = &zSql[(zTail - zCopy)];

  assert(rc==SQLITE_OK || pStmt==0);
  Tcl_ResetResult(interp);
  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( zTail && objc>=5 ){
    if( bytes>=0 ){
      bytes = bytes - (int)(zTail-zSql);
    }
    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
  }
  if( rc!=SQLITE_OK ){
    assert( pStmt==0 );







|







3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
  rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0);
  free(zCopy);
  zTail = &zSql[(zTail - zCopy)];

  assert(rc==SQLITE_OK || pStmt==0);
  Tcl_ResetResult(interp);
  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( rc==SQLITE_OK && zTail && objc>=5 ){
    if( bytes>=0 ){
      bytes = bytes - (int)(zTail-zSql);
    }
    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
  }
  if( rc!=SQLITE_OK ){
    assert( pStmt==0 );

Changes to src/vdbesort.c.

1128
1129
1130
1131
1132
1133
1134
1135
1136
1137



1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
** the VFS has memory mapped it.
**
** Whether or not the file does end up memory mapped of course depends on
** the specific VFS implementation.
*/
static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
  if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){
    int rc = sqlite3OsTruncate(pFd, nByte);
    if( rc==SQLITE_OK ){
      void *p = 0;



      sqlite3OsFetch(pFd, 0, (int)nByte, &p);
      sqlite3OsUnfetch(pFd, 0, p);
    }
  }
}
#else
# define vdbeSorterExtendFile(x,y,z)
#endif

/*







<
<
|
>
>
>
|
|
<







1128
1129
1130
1131
1132
1133
1134


1135
1136
1137
1138
1139
1140

1141
1142
1143
1144
1145
1146
1147
** the VFS has memory mapped it.
**
** Whether or not the file does end up memory mapped of course depends on
** the specific VFS implementation.
*/
static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
  if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){


    void *p = 0;
    int chunksize = 4*1024;
    sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
    sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
    sqlite3OsFetch(pFd, 0, (int)nByte, &p);
    sqlite3OsUnfetch(pFd, 0, p);

  }
}
#else
# define vdbeSorterExtendFile(x,y,z)
#endif

/*

Changes to src/wal.c.

2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
    if( rc!=SQLITE_OK ){
      return rc;
    }
    nCollide = HASHTABLE_NSLOT;
    for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
      u32 iFrame = aHash[iKey] + iZero;
      if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
        /* assert( iFrame>iRead ); -- not true if there is corruption */
        iRead = iFrame;
      }
      if( (nCollide--)==0 ){
        return SQLITE_CORRUPT_BKPT;
      }
    }
  }







|







2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
    if( rc!=SQLITE_OK ){
      return rc;
    }
    nCollide = HASHTABLE_NSLOT;
    for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
      u32 iFrame = aHash[iKey] + iZero;
      if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
        assert( iFrame>iRead || CORRUPT_DB );
        iRead = iFrame;
      }
      if( (nCollide--)==0 ){
        return SQLITE_CORRUPT_BKPT;
      }
    }
  }

Changes to test/e_walauto.test.

62
63
64
65
66
67
68

69
70
71
72
73
74
75
    }
  }
} {

  eval $code

  reset_db

  do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal}
  do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) }
  set shmfd [open "test.db-shm" rb]

  # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to
  # having the auto-checkpoint enabled with a threshold of 1000 or
  # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages.







>







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    }
  }
} {

  eval $code

  reset_db
  execsql { PRAGMA auto_vacuum = 0 }
  do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal}
  do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) }
  set shmfd [open "test.db-shm" rb]

  # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to
  # having the auto-checkpoint enabled with a threshold of 1000 or
  # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages.

Changes to test/e_walckpt.test.

243
244
245
246
247
248
249

250
251
252
253
254
255
256
...
702
703
704
705
706
707
708

709
710
711
712
713
714
715
  testvfs tvfs
  tvfs filter xWrite
  sqlite3 db test.db -vfs tvfs
  sqlite3 db2 test.db -vfs tvfs

  do_test $tn.3.2.1 {
    db2 eval {

      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(x, y);
      INSERT INTO t1 VALUES(1,2);
      INSERT INTO t1 VALUES(3,4);
      INSERT INTO t1 VALUES(5,6);
    }
    file size test.db-wal
................................................................................
}

reset_db
sqlite3 db2 test.db

do_test 6.1 {
  execsql {

    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
  }
  file size test.db-wal
} [wal_file_size 3 1024]








>







 







>







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
...
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
  testvfs tvfs
  tvfs filter xWrite
  sqlite3 db test.db -vfs tvfs
  sqlite3 db2 test.db -vfs tvfs

  do_test $tn.3.2.1 {
    db2 eval {
      PRAGMA auto_vacuum = 0;
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(x, y);
      INSERT INTO t1 VALUES(1,2);
      INSERT INTO t1 VALUES(3,4);
      INSERT INTO t1 VALUES(5,6);
    }
    file size test.db-wal
................................................................................
}

reset_db
sqlite3 db2 test.db

do_test 6.1 {
  execsql {
    PRAGMA auto_vacuum = 0; 
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
  }
  file size test.db-wal
} [wal_file_size 3 1024]

Changes to test/notify2.test.

97
98
99
100
101
102
103


104
105
106
107
108
109
110
...
124
125
126
127
128
129
130

131
132
133
134
135
136
137
...
150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
...
200
201
202
203
204
205
206
207


208
209
210
211
212
213
214
...
221
222
223
224
225
226
227
228








229
230
231
232
233
234
235
236
237


238









239
240
241
242
  opendb

  #after 2000

  # This loop runs for ~20 seconds.
  #
  set iStart [clock_seconds]


  while { ([clock_seconds]-$iStart) < $nSecond } {

    # Each transaction does 3 operations. Each operation is either a read
    # or write of a randomly selected table (t1, t2 or t3). Set the variables
    # $SQL(1), $SQL(2) and $SQL(3) to the SQL commands used to implement
    # each operation.
    #
................................................................................
            DROP INDEX IF EXISTS yyy.xxx_i;
      }
      ]]
    }

    # Execute the SQL transaction.
    #

    set rc [catch { execsql_blocking $::DB "
        BEGIN;
          $SQL(1);
          $SQL(2);
          $SQL(3);
        COMMIT;
      "
................................................................................
      # Hit some other kind of error. This is a malfunction.
      error $msg
    } else {
      # No error occurred. Check that any SELECT statements in the transaction
      # returned "1". Otherwise, the invariant was false, indicating that
      # some malfunction has occurred.
      foreach r $msg { if {$r != 1} { puts "Invariant check failed: $msg" } }

    }
  }

  # Close the database connection and return 0.
  #
  sqlite3_close $::DB
  expr 0
}

foreach {iTest xStep xPrepare} {
  1 sqlite3_blocking_step sqlite3_blocking_prepare_v2
  2 sqlite3_step          sqlite3_nonblocking_prepare_v2
} {
  forcedelete test.db test2.db test3.db
................................................................................
  unset -nocomplain finished
  for {set ii 0} {$ii < $nThread} {incr ii} {
    thread_spawn finished($ii) $ThreadSetup $ThreadProgram
  }
  for {set ii 0} {$ii < $nThread} {incr ii} {
    do_test notify2-$iTest.2.$ii {
      if {![info exists finished($ii)]} { vwait finished($ii) }
      set finished($ii)


    } {0}
  }

  # Count the total number of succesful writes.
  do_test notify2-$iTest.3.1 {
    sqlite3 db test.db
    execsql {
................................................................................
           + (SELECT max(a) FROM t3)
    }]
    db close
  } {}
}

# The following tests checks to make sure sqlite3_blocking_step() is
# faster than sqlite3_step().  blocking_step() is always faster on








# multi-core and is usually faster on single-core.  But sometimes, by
# chance, step() will be faster on a single core, in which case the
# following test will fail.
#
puts "The following test seeks to demonstrate that the sqlite3_unlock_notify()"
puts "interface helps multi-core systems to run faster.  This test sometimes"
puts "fails on single-core machines."
puts [array get anWrite]
do_test notify2-3 {


  expr {$anWrite(sqlite3_blocking_step) > $anWrite(sqlite3_step)}









} {1}

sqlite3_enable_shared_cache $::enable_shared_cache
finish_test







>
>







 







>







 







>






|







 







|
>
>







 







|
>
>
>
>
>
>
>
>
|
|



|
|


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




97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
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
266
267
  opendb

  #after 2000

  # This loop runs for ~20 seconds.
  #
  set iStart [clock_seconds]
  set nOp 0
  set nAttempt 0
  while { ([clock_seconds]-$iStart) < $nSecond } {

    # Each transaction does 3 operations. Each operation is either a read
    # or write of a randomly selected table (t1, t2 or t3). Set the variables
    # $SQL(1), $SQL(2) and $SQL(3) to the SQL commands used to implement
    # each operation.
    #
................................................................................
            DROP INDEX IF EXISTS yyy.xxx_i;
      }
      ]]
    }

    # Execute the SQL transaction.
    #
    incr nAttempt
    set rc [catch { execsql_blocking $::DB "
        BEGIN;
          $SQL(1);
          $SQL(2);
          $SQL(3);
        COMMIT;
      "
................................................................................
      # Hit some other kind of error. This is a malfunction.
      error $msg
    } else {
      # No error occurred. Check that any SELECT statements in the transaction
      # returned "1". Otherwise, the invariant was false, indicating that
      # some malfunction has occurred.
      foreach r $msg { if {$r != 1} { puts "Invariant check failed: $msg" } }
      incr nOp
    }
  }

  # Close the database connection and return 0.
  #
  sqlite3_close $::DB
  list $nOp $nAttempt
}

foreach {iTest xStep xPrepare} {
  1 sqlite3_blocking_step sqlite3_blocking_prepare_v2
  2 sqlite3_step          sqlite3_nonblocking_prepare_v2
} {
  forcedelete test.db test2.db test3.db
................................................................................
  unset -nocomplain finished
  for {set ii 0} {$ii < $nThread} {incr ii} {
    thread_spawn finished($ii) $ThreadSetup $ThreadProgram
  }
  for {set ii 0} {$ii < $nThread} {incr ii} {
    do_test notify2-$iTest.2.$ii {
      if {![info exists finished($ii)]} { vwait finished($ii) }
      incr anSuccess($xStep) [lindex $finished($ii) 0]
      incr anAttempt($xStep) [lindex $finished($ii) 1]
      expr 0
    } {0}
  }

  # Count the total number of succesful writes.
  do_test notify2-$iTest.3.1 {
    sqlite3 db test.db
    execsql {
................................................................................
           + (SELECT max(a) FROM t3)
    }]
    db close
  } {}
}

# The following tests checks to make sure sqlite3_blocking_step() is
# faster than sqlite3_step(). "Faster" in this case means uses fewer
# CPU cycles. This is not always the same as faster in wall-clock time 
# for this type of test. The number of CPU cycles per transaction is 
# roughly proportional to the number of attempts made (i.e. one plus the 
# number of SQLITE_BUSY or SQLITE_LOCKED errors that require the transaction 
# to be retried). So this test just measures that a greater percentage of
# transactions attempted using blocking_step() succeed.
#
# The blocking_step() function is almost always faster on multi-core and is
# usually faster on single-core.  But sometimes, by chance, step() will be
# faster on a single core, in which case the
# following test will fail.
#
puts "The following test seeks to demonstrate that the sqlite3_unlock_notify()"
puts "interface helps multi-core systems to run more efficiently.  This test"
puts "sometimes fails on single-core machines."
puts [array get anWrite]
do_test notify2-3 {
  set blocking [expr {
    double($anSuccess(sqlite3_blocking_step)) /
    double($anAttempt(sqlite3_blocking_step)) 
  }]
  set non [expr {
    double($anSuccess(sqlite3_step)) /
    double($anAttempt(sqlite3_step)) 
  }]
  puts -nonewline [format " blocking: %.1f%% non-blocking %.1f%% ..." \
    [expr $blocking*100.0] [expr $non*100.0]]

  expr {$blocking > $non}
} {1}

sqlite3_enable_shared_cache $::enable_shared_cache
finish_test

Changes to test/permutations.test.

140
141
142
143
144
145
146
147
148
149
150



151

152
153
154
155
156
157
158
...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault*
]

test_suite "mmap" -prefix "mm-" -description {
  Similar to veryquick. Except with memory mapping disabled.
} -presql {
  pragma mmap_size = 268435456;
} -files [



  test_set $allquicktests -exclude *malloc* *ioerr* *fault* -include malloc.test

]

test_suite "valgrind" -prefix "" -description {
  Run the "veryquick" test suite with a couple of multi-process tests (that
  fail under valgrind) omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test atof1.test
................................................................................

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

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







|



>
>
>
|
>







 







|







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault*
]

test_suite "mmap" -prefix "mm-" -description {
  Similar to veryquick. Except with memory mapping enabled.
} -presql {
  pragma mmap_size = 268435456;
} -files [
  # Do not run pragma3.test, as it depends on the values returned by
  # "PRAGMA data_version". And if mmap is being used these are often,
  # but not always, one greater than if it were not.
  test_set $allquicktests -exclude *malloc* *ioerr* *fault* pragma3.test \
    -include malloc.test
]

test_suite "valgrind" -prefix "" -description {
  Run the "veryquick" test suite with a couple of multi-process tests (that
  fail under valgrind) omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test atof1.test
................................................................................

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

  zerodamage.test

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

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

Changes to test/pragma3.test.

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
60
61
62
63
64
65
66

67
68
69
70
71
72
73
...
212
213
214
215
216
217
218



219


220
221
222
223
224
225
226
...
237
238
239
240
241
242
243

244
245
246
  PRAGMA main.data_version=1234;
  PRAGMA main.data_version;
} {1 1}

# EVIDENCE-OF: R-27726-60934 The "PRAGMA data_version" command provides
# an indication that the database file has been modified.
#
# EVIDENCE-OF: R-25838-33704 The "PRAGMA data_version" value is
# unchanced for commits made on the same database connection.
#
do_execsql_test pragma3-110 {
  PRAGMA data_version;
  BEGIN IMMEDIATE;
  PRAGMA data_version;
  CREATE TABLE t1(a);
  INSERT INTO t1 VALUES(100),(200),(300);
................................................................................
  BEGIN IMMEDIATE;
  PRAGMA data_version;
  INSERT INTO t1 VALUES(400),(500);
  PRAGMA data_version;
  COMMIT;
  SELECT * FROM t1;
  PRAGMA data_version;

} {1 1 1 100 200 300 400 500 1}

# EVIDENCE-OF: R-63005-41812 The integer values returned by two
# invocations of "PRAGMA data_version" from the same connection will be
# different if changes were committed to the database by any other
# connection in the interim.
#
................................................................................
  db2 close
  db close
  sqlite3_enable_shared_cache $::enable_shared_cache
}

# Make sure this also works in WAL mode
#



ifcapable wal {


  sqlite3 db test.db
  db eval {PRAGMA journal_mode=WAL}
  sqlite3 db2 test.db
  do_test pragma3-400 {
    db eval {
      PRAGMA data_version;
      PRAGMA journal_mode;
................................................................................
  do_test pragma3-420 {
    db eval {UPDATE t1 SET a=111*(a/100); PRAGMA data_version; SELECT * FROM t1}
  } {2 111 222}
  do_test pragma3-430 {
    db2 eval {PRAGMA data_version; SELECT * FROM t1;}
  } {3 111 222}
  db2 close

}

finish_test







|
|







 







>







 







>
>
>

>
>







 







>



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
...
243
244
245
246
247
248
249
250
251
252
253
  PRAGMA main.data_version=1234;
  PRAGMA main.data_version;
} {1 1}

# EVIDENCE-OF: R-27726-60934 The "PRAGMA data_version" command provides
# an indication that the database file has been modified.
#
# EVIDENCE-OF: R-47505-58569 The "PRAGMA data_version" value is
# unchanged for commits made on the same database connection.
#
do_execsql_test pragma3-110 {
  PRAGMA data_version;
  BEGIN IMMEDIATE;
  PRAGMA data_version;
  CREATE TABLE t1(a);
  INSERT INTO t1 VALUES(100),(200),(300);
................................................................................
  BEGIN IMMEDIATE;
  PRAGMA data_version;
  INSERT INTO t1 VALUES(400),(500);
  PRAGMA data_version;
  COMMIT;
  SELECT * FROM t1;
  PRAGMA data_version;
  PRAGMA shrink_memory;
} {1 1 1 100 200 300 400 500 1}

# EVIDENCE-OF: R-63005-41812 The integer values returned by two
# invocations of "PRAGMA data_version" from the same connection will be
# different if changes were committed to the database by any other
# connection in the interim.
#
................................................................................
  db2 close
  db close
  sqlite3_enable_shared_cache $::enable_shared_cache
}

# Make sure this also works in WAL mode
#
# This will not work with the in-memory journal permutation, as opening
# [db2] switches the journal mode back to "memory"
#
ifcapable wal {
if {[permutation]!="inmemory_journal"} {

  sqlite3 db test.db
  db eval {PRAGMA journal_mode=WAL}
  sqlite3 db2 test.db
  do_test pragma3-400 {
    db eval {
      PRAGMA data_version;
      PRAGMA journal_mode;
................................................................................
  do_test pragma3-420 {
    db eval {UPDATE t1 SET a=111*(a/100); PRAGMA data_version; SELECT * FROM t1}
  } {2 111 222}
  do_test pragma3-430 {
    db2 eval {PRAGMA data_version; SELECT * FROM t1;}
  } {3 111 222}
  db2 close
}
}

finish_test

Deleted test/releasetest.mk.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
########################################################
TOP=/home/drh/sqlite/sqlite

TCL_FLAGS=-I/home/drh/tcltk/86linux
LIBTCL=/home/drh/tcltk/86linux/libtcl8.6.a -lm -ldl -lpthread

BCC = gcc
TCC = gcc -ansi -g $(CFLAGS)
NAWK   = awk
AR     = ar cr
RANLIB = ranlib
THREADLIB = -lpthread -ldl -lz
include $(TOP)/main.mk
########################################################
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























Changes to test/releasetest.tcl.


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
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
...
204
205
206
207
208
209
210
211
212
213



214
215
216
217
218
219
220
...
222
223
224
225
226
227
228
229
230


231




























232
233
234
235
236
237
238
239
240
241
242
243
244
...
254
255
256
257
258
259
260
261
262
263
264



265
266
267
268
269
270
271
272
273
274



275




276

277


278
279
280

281
282


283

































284


285
286
287
288
289
290
291
292
293
294
295
296



297
298
299
300
301
302


303
304

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321



























322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
...
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







384
385
386


set rcsid {$Id: $}

# Documentation for this script. This may be output to stderr
# if the script is invoked incorrectly. See the [process_options]
# proc below.
#
set ::USAGE_MESSAGE {
This Tcl script is used to test the various configurations required
before releasing a new version. Supported command line options (all 
optional) are:

    -makefile PATH-TO-MAKEFILE           (default "releasetest.mk")
    -platform PLATFORM                   (see below)
    -quick    BOOLEAN                    (default "0")
    -config   CONFIGNAME                 (Run only CONFIGNAME)





The default value for -makefile is "./releasetest.mk".


The script determines the default value for -platform using the
$tcl_platform(os) and $tcl_platform(machine) variables. Supported 
platforms are "Linux-x86", "Linux-x86_64" and "Darwin-i386".

If the -quick option is set to true, then the "veryquick.test" script
is run for all compilation configurations. Otherwise, sometimes "all.test"
is run, sometimes "veryquick.test".

Almost any SQLite makefile (except those generated by configure - see below)
should work. The following properties are required:

  * The makefile should support the "fulltest" target.
  * The makefile should support the variable "OPTS" as a way to pass
    options from the make command line to lemon and the C compiler.

More precisely, the following invocation must be supported:

  make -f $::MAKEFILE fulltest OPTS="-DSQLITE_SECURE_DELETE=1 -DSQLITE_DEBUG=1"

Makefiles generated by the sqlite configure program cannot be used as
they do not respect the OPTS variable.

Example Makefile contents:

  ########################################################
  TOP=/home/dan/work/sqlite/sqlite

  TCL_FLAGS=-I/home/dan/tcl/include
  LIBTCL=-L/home/dan/tcl/lib -ltcl

  BCC = gcc
  TCC = gcc -ansi -g $(CFLAGS)
  NAWK   = awk
  AR     = ar cr
  RANLIB = ranlib
  THREADLIB = -lpthread -ldl
  include $(TOP)/main.mk
  ########################################################
}

array set ::Configs {
  "Default" {
    -O2
  }
  "Ftrapv" {
................................................................................
    -DSQLITE_ENABLE_MEMSYS5=1
    -DSQLITE_ENABLE_MEMSYS3=1
    -DSQLITE_ENABLE_COLUMN_METADATA=1
    -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
    -DSQLITE_SECURE_DELETE=1
    -DSQLITE_SOUNDEX=1
    -DSQLITE_ENABLE_ATOMIC_WRITE=1
    -DSQLITE_ENABLE_IOTRACE=1
    -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
    -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
  }
  "Debug-One" {
    -O2
    -DSQLITE_DEBUG=1
    -DSQLITE_MEMDEBUG=1
................................................................................
    -DUSE_PREAD=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_ENABLE_FTS3=1
    -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
    -DSQLITE_DEFAULT_CACHE_SIZE=1000
    -DSQLITE_MAX_LENGTH=2147483645
    -DSQLITE_MAX_VARIABLE_NUMBER=500000
    -DSQLITE_DEBUG=1 
    -DSQLITE_PREFER_PROXY_LOCKING=1
  }
  "Extra-Robustness" {
    -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
    -DSQLITE_MAX_ATTACHED=62
  }
  "Devkit" {
................................................................................
    -DHAVE_USLEEP=1
  }
}

array set ::Platforms {
  Linux-x86_64 {
    "Check-Symbols"           checksymbols
    "Debug-One"               test
    "Secure-Delete"           test
    "Unlock-Notify"           "QUICKTEST_INCLUDE=notify2.test test"
    "Update-Delete-Limit"     test
    "Extra-Robustness"        test
    "Device-Two"              test
    "Ftrapv"                  test
    "No-lookaside"            test
................................................................................
    "Devkit"                  test
    "Unlock-Notify"           "QUICKTEST_INCLUDE=notify2.test test"
    "Device-One"              test
    "Device-Two"              test
    "Default"                 "threadtest fulltest"
  }
  Darwin-i386 {
    "Locking-Style"           test
    "OS-X"                    "threadtest fulltest"
  }



}


# End of configuration section.
#########################################################################
#########################################################################

................................................................................
  foreach {v t} $value {
    if {0==[info exists ::Configs($v)]} {
      puts stderr "No such configuration: \"$v\""
      exit -1
    }
  }
}

proc run_test_suite {name testtarget config} {


  




























  # Tcl variable $opts is used to build up the value used to set the 
  # OPTS Makefile variable. Variable $cflags holds the value for
  # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but
  # CFLAGS is only passed to gcc.
  #
  set cflags ""
  set opts ""
  foreach arg $config {
    if {[string match -D* $arg]} {
      lappend opts $arg
    } else {
      lappend cflags $arg
    }
................................................................................

  if {$::tcl_platform(platform)=="windows"} {
    append opts " -DSQLITE_OS_WIN=1"
  } else {
    append opts " -DSQLITE_OS_UNIX=1"
  }

  # Run the test.
  #
  set makefile [file normalize $::MAKEFILE]
  file mkdir $dir



  puts -nonewline "Testing configuration \"$name\" (logfile=$dir/test.log)..."
  flush stdout

  set makecmd [concat                                  \
    [list exec make -C $dir -f $makefile clean]        \
    $testtarget                                        \
    [list CFLAGS=$cflags OPTS=$opts >& $dir/test.log]  \
  ]

  set tm1 [clock seconds] 



  set rc [catch $makecmd]




  set tm2 [clock seconds]




  set minutes [expr {($tm2-$tm1)/60}]
  set seconds [expr {($tm2-$tm1)%60}]
  puts -nonewline [format " (%d:%.2d) " $minutes $seconds]

  if {$rc} {
    puts "FAILED."


  } else {

































    puts "Ok."


  }
}


# This proc processes the command line options passed to this script.
# Currently the only option supported is "-makefile", default
# "releasetest.mk". Set the ::MAKEFILE variable to the value of this
# option.
#
proc process_options {argv} {
  set ::MAKEFILE releasetest.mk                       ;# Default value
  set ::QUICK    0                                    ;# Default value



  set config {}
  set platform $::tcl_platform(os)-$::tcl_platform(machine)

  for {set i 0} {$i < [llength $argv]} {incr i} {
    switch -- [lindex $argv $i] {
      -makefile {


        incr i
        set ::MAKEFILE [lindex $argv $i]

      }

      -platform {
        incr i
        set platform [lindex $argv $i]
      }

      -quick {
        incr i
        set ::QUICK [lindex $argv $i]
      }

      -config {
        incr i
        set config [lindex $argv $i]
      }
  



























      default {
        puts stderr ""
        puts stderr [string trim $::USAGE_MESSAGE]
        exit -1
      }
    }
  }

  set ::MAKEFILE [file normalize $::MAKEFILE]

  if {0==[info exists ::Platforms($platform)]} {
    puts "Unknown platform: $platform"
    puts -nonewline "Set the -platform option to "
    set print [list]
    foreach p [array names ::Platforms] {
      lappend print "\"$p\""
    }
................................................................................

  if {$config!=""} {
    if {[llength $config]==1} {lappend config fulltest}
    set ::CONFIGLIST $config
  } else {
    set ::CONFIGLIST $::Platforms($platform)
  }
  puts "Running the following configurations for $platform:"
  puts "    [string trim $::CONFIGLIST]"





}

# Main routine.
#
proc main {argv} {

  # Process any command line options.
  process_options $argv







  foreach {zConfig target} $::CONFIGLIST {
    if {$::QUICK} {set target test}

    set config_options $::Configs($zConfig)


    run_test_suite $zConfig $target $config_options

    # If the configuration included the SQLITE_DEBUG option, then remove
    # it and run veryquick.test. If it did not include the SQLITE_DEBUG option
    # add it and run veryquick.test.
    if {$target!="checksymbols"} {
      set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*]


      if {$debug_idx < 0} {


        run_test_suite "${zConfig}_debug" test [
          concat $config_options -DSQLITE_DEBUG=1
        ]
      } else {



        run_test_suite "${zConfig}_ndebug" test [
          lreplace $config_options $debug_idx $debug_idx
        ]
      }
    }

  }







}

main $argv
>
|
<
<






|


|
|
<
|
>
>
>
>

|
>

|
|


<
<
<
<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<







 







|







 







|







 







|


>
>
>







 








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




|







 







<
<
<
|
>
>
>
|
|
|
<
<
<
<
|
<
|
>
>
>
|
>
>
>
>

>

>
>
|
|
<
>
|
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>










|
|
>
>
>




|
|
>
>

<
>








<
|






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








<
<







 







|

>
>
>
>
>








>

>
>
>
>
>


>


>





|

>
>

>
>
|
<
<

>
>
>
|
<
<


|
|
>
>
>
>
>
>
>



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
..
61
62
63
64
65
66
67

68
69
70
71
72
73
74
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
...
195
196
197
198
199
200
201
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
...
257
258
259
260
261
262
263



264
265
266
267
268
269
270




271

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
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
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405


406
407
408
409
410
411
412
...
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464


465
466
467
468
469


470
471
472
473
474
475
476
477
478
479
480
481
482
483
#!/usr/bin/tclsh
#


# Documentation for this script. This may be output to stderr
# if the script is invoked incorrectly. See the [process_options]
# proc below.
#
set ::USAGE_MESSAGE {
This Tcl script is used to test the various configurations required
before releasing a new version. Supported command line options (all
optional) are:

    --srcdir   TOP-OF-SQLITE-TREE      (see below)
    --platform PLATFORM                (see below)

    --config   CONFIGNAME              (Run only CONFIGNAME)
    --quick                            (Run "veryquick.test" only)
    --buildonly                        (Just build testfixture - do not run)
    --dryrun                           (Print what would have happened)
    --info                             (Show diagnostic info)

The default value for --srcdir is the parent of the directory holding
this script.

The script determines the default value for --platform using the
$tcl_platform(os) and $tcl_platform(machine) variables. Supported
platforms are "Linux-x86", "Linux-x86_64" and "Darwin-i386".





Every test begins with a fresh run of the configure script at the top
of the SQLite source tree.




























}

array set ::Configs {
  "Default" {
    -O2
  }
  "Ftrapv" {
................................................................................
    -DSQLITE_ENABLE_MEMSYS5=1
    -DSQLITE_ENABLE_MEMSYS3=1
    -DSQLITE_ENABLE_COLUMN_METADATA=1
    -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
    -DSQLITE_SECURE_DELETE=1
    -DSQLITE_SOUNDEX=1
    -DSQLITE_ENABLE_ATOMIC_WRITE=1

    -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
    -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
  }
  "Debug-One" {
    -O2
    -DSQLITE_DEBUG=1
    -DSQLITE_MEMDEBUG=1
................................................................................
    -DUSE_PREAD=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_ENABLE_FTS3=1
    -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
    -DSQLITE_DEFAULT_CACHE_SIZE=1000
    -DSQLITE_MAX_LENGTH=2147483645
    -DSQLITE_MAX_VARIABLE_NUMBER=500000
    -DSQLITE_DEBUG=1
    -DSQLITE_PREFER_PROXY_LOCKING=1
  }
  "Extra-Robustness" {
    -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
    -DSQLITE_MAX_ATTACHED=62
  }
  "Devkit" {
................................................................................
    -DHAVE_USLEEP=1
  }
}

array set ::Platforms {
  Linux-x86_64 {
    "Check-Symbols"           checksymbols
    "Debug-One"               "mptest test"
    "Secure-Delete"           test
    "Unlock-Notify"           "QUICKTEST_INCLUDE=notify2.test test"
    "Update-Delete-Limit"     test
    "Extra-Robustness"        test
    "Device-Two"              test
    "Ftrapv"                  test
    "No-lookaside"            test
................................................................................
    "Devkit"                  test
    "Unlock-Notify"           "QUICKTEST_INCLUDE=notify2.test test"
    "Device-One"              test
    "Device-Two"              test
    "Default"                 "threadtest fulltest"
  }
  Darwin-i386 {
    "Locking-Style"           "mptest test"
    "OS-X"                    "threadtest fulltest"
  }
  "Windows NT-intel" {
    "Default"                 "mptest fulltestonly"
  }
}


# End of configuration section.
#########################################################################
#########################################################################

................................................................................
  foreach {v t} $value {
    if {0==[info exists ::Configs($v)]} {
      puts stderr "No such configuration: \"$v\""
      exit -1
    }
  }
}

# Open the file $logfile and look for a report on the number of errors
# and the number of test cases run.  Add these values to the global
# $::NERRCASE and $::NTESTCASE variables.
#
# If any errors occur, then write into $errmsgVar the text of an appropriate
# one-line error message to show on the output.
#
proc count_tests_and_errors {logfile rcVar errmsgVar} {
  if {$::DRYRUN} return
  upvar 1 $rcVar rc $errmsgVar errmsg
  set fd [open $logfile rb]
  set seen 0
  while {![eof $fd]} {
    set line [gets $fd]
    if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} {
      incr ::NERRCASE $nerr
      incr ::NTESTCASE $ntest
      set seen 1
      if {$nerr>0} {
        set rc 1
        set errmsg $line
      }
    }
  }
  close $fd
  if {!$seen} {
    set rc 1
    set errmsg "Test did not complete"
  }
}

proc run_test_suite {name testtarget config} {
  # Tcl variable $opts is used to build up the value used to set the
  # OPTS Makefile variable. Variable $cflags holds the value for
  # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but
  # CFLAGS is only passed to gcc.
  #
  set cflags "-g"
  set opts ""
  foreach arg $config {
    if {[string match -D* $arg]} {
      lappend opts $arg
    } else {
      lappend cflags $arg
    }
................................................................................

  if {$::tcl_platform(platform)=="windows"} {
    append opts " -DSQLITE_OS_WIN=1"
  } else {
    append opts " -DSQLITE_OS_UNIX=1"
  }




  dryrun file mkdir $dir
  if {!$::DRYRUN} {
    set title ${name}($testtarget)
    set n [string length $title]
    puts -nonewline "${title}[string repeat . [expr {54-$n}]]"
    flush stdout
  }






  set tm1 [clock seconds]
  set origdir [pwd]
  dryrun cd $dir
  set errmsg {}
  set rc [catch [configureCommand]]
  if {!$rc} {
    set rc [catch [makeCommand $testtarget $cflags $opts]]
    count_tests_and_errors test.log rc errmsg
  }
  set tm2 [clock seconds]
  dryrun cd $origdir

  if {!$::DRYRUN} {
    set hours [expr {($tm2-$tm2)/3600}]
    set minutes [expr {(($tm2-$tm1)/60)%60}]
    set seconds [expr {($tm2-$tm1)%60}]

    set tm [format (%02d:%02d:%02d) $hours $minutes $seconds]
    if {$rc} {
      puts " FAIL $tm"
      incr ::NERR
      if {$errmsg!=""} {puts "     $errmsg"}
    } else {
      puts " Ok   $tm"
    }
  }
}

# The following procedure returns the "configure" command to be exectued for
# the current platform, which may be Windows (via MinGW, etc).
#
proc configureCommand {} {
  set result [list dryrun exec]
  if {$::tcl_platform(platform)=="windows"} {
    lappend result sh
  }
  lappend result $::SRCDIR/configure -enable-load-extension >& test.log
}

# The following procedure returns the "make" command to be executed for the
# specified targets, compiler flags, and options.
#
proc makeCommand { targets cflags opts } {
  set result [list dryrun exec make clean]
  foreach target $targets {
    lappend result $target
  }
  lappend result CFLAGS=$cflags OPTS=$opts >>& test.log
}

# The following procedure either prints its arguments (if ::DRYRUN is true)
# or executes the command of its arguments in the calling context
# (if ::DRYRUN is false).
#
proc dryrun {args} {
  if {$::DRYRUN} {
    puts $args
  } else {
    uplevel 1 $args
  }
}


# This proc processes the command line options passed to this script.
# Currently the only option supported is "-makefile", default
# "releasetest.mk". Set the ::MAKEFILE variable to the value of this
# option.
#
proc process_options {argv} {
  set ::SRCDIR    [file normalize [file dirname [file dirname $::argv0]]]
  set ::QUICK     0
  set ::BUILDONLY 0
  set ::DRYRUN    0
  set ::EXEC      exec
  set config {}
  set platform $::tcl_platform(os)-$::tcl_platform(machine)

  for {set i 0} {$i < [llength $argv]} {incr i} {
    set x [lindex $argv $i]
    if {[regexp {^--[a-z]} $x]} {set x [string range $x 1 end]}
    switch -- $x {
      -srcdir {
        incr i

        set ::SRCDIR [file normalize [lindex $argv $i]]
      }

      -platform {
        incr i
        set platform [lindex $argv $i]
      }

      -quick {

        set ::QUICK 1
      }

      -config {
        incr i
        set config [lindex $argv $i]
      }

      -buildonly {
        set ::BUILDONLY 1
      }

      -dryrun {
        set ::DRYRUN 1
      }

      -info {
        puts "Command-line Options:"
        puts "   --srcdir $::SRCDIR"
        puts "   --platform [list $platform]"
        puts "   --config [list $config]"
        if {$::QUICK}     {puts "   --quick"}
        if {$::BUILDONLY} {puts "   --buildonly"}
        if {$::DRYRUN}    {puts "   --dryrun"}
        puts "\nAvailable --platform options:"
        foreach y [lsort [array names ::Platforms]] {
          puts "   [list $y]"
        }
        puts "\nAvailable --config options:"
        foreach y [lsort [array names ::Configs]] {
          puts "   [list $y]"
        }
        exit
      }

      default {
        puts stderr ""
        puts stderr [string trim $::USAGE_MESSAGE]
        exit -1
      }
    }
  }



  if {0==[info exists ::Platforms($platform)]} {
    puts "Unknown platform: $platform"
    puts -nonewline "Set the -platform option to "
    set print [list]
    foreach p [array names ::Platforms] {
      lappend print "\"$p\""
    }
................................................................................

  if {$config!=""} {
    if {[llength $config]==1} {lappend config fulltest}
    set ::CONFIGLIST $config
  } else {
    set ::CONFIGLIST $::Platforms($platform)
  }
  puts "Running the following test configurations for $platform:"
  puts "    [string trim $::CONFIGLIST]"
  puts -nonewline "Flags:"
  if {$::DRYRUN} {puts -nonewline " --dryrun"}
  if {$::BUILDONLY} {puts -nonewline " --buildonly"}
  if {$::QUICK} {puts -nonewline " --quick"}
  puts ""
}

# Main routine.
#
proc main {argv} {

  # Process any command line options.
  process_options $argv
  puts [string repeat * 70]

  set ::NERR 0
  set ::NTEST 0
  set ::NTESTCASE 0
  set ::NERRCASE 0
  set STARTTIME [clock seconds]
  foreach {zConfig target} $::CONFIGLIST {
    if {$::QUICK} {set target test}
    if {$::BUILDONLY} {set target testfixture}
    set config_options $::Configs($zConfig)

    incr NTEST
    run_test_suite $zConfig $target $config_options

    # If the configuration included the SQLITE_DEBUG option, then remove
    # it and run veryquick.test. If it did not include the SQLITE_DEBUG option
    # add it and run veryquick.test.
    if {$target!="checksymbols" && !$::BUILDONLY} {
      set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*]
      set xtarget $target
      regsub -all {fulltest[a-z]+} $xtarget test xtarget
      if {$debug_idx < 0} {
        incr NTEST
        append config_options " -DSQLITE_DEBUG=1"
        run_test_suite "${zConfig}_debug" $xtarget $config_options


      } else {
        incr NTEST
        regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $config_options { } config_options
        regsub { *-DSQLITE_DEBUG[^ ]* *} $config_options { } config_options
        run_test_suite "${zConfig}_ndebug" $xtarget $config_options


      }
    }
  }

  set elapsetime [expr {[clock seconds]-$STARTTIME}]
  set hr [expr {$elapsetime/3600}]
  set min [expr {($elapsetime/60)%60}]
  set sec [expr {$elapsetime%60}]
  set etime [format (%02d:%02d:%02d) $hr $min $sec]
  puts [string repeat * 70]
  puts "$::NERRCASE failures of $::NTESTCASE tests run in $etime"
}

main $argv

Changes to test/threadtest3.c.

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
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
...
444
445
446
447
448
449
450
451

452
453
454
455
456
457
458
...
781
782
783
784
785
786
787

788
789
790
791
792
793
794
...
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
....
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
....
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
....
1464
1465
1466
1467
1468
1469
1470

1471
1472
1473
1474
1475
1476

1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489

/*











** The code in this file runs a few multi-threaded test cases using the
** SQLite library. It can be compiled to an executable on unix using the
** following command:
**
**   gcc -O2 threadtest3.c sqlite3.c -ldl -lpthread -lm
**
** Then run the compiled program. The exit status is non-zero if any tests
** failed (hopefully there is also some output to stdout to clarify what went
** wrong).
**
** There are three parts to the code in this file, in the following order:


**
**   1. Code for the SQL aggregate function md5sum() copied from 
**      tclsqlite.c in the SQLite distribution. The names of all the 
**      types and functions in this section begin with "MD5" or "md5".
**
**   2. A set of utility functions that may be used to implement
**      multi-threaded test cases. These are all called by test code
**      via macros that help with error reporting. The macros are defined
**      immediately below this comment.
**
**   3. The test code itself. And a main() routine to drive the test 
**      code.

*/

/*************************************************************************
** Start of test code/infrastructure interface macros.
**
** The following macros constitute the interface between the test
** programs and the test infrastructure. Test infrastructure code 
** does not itself use any of these macros. Test code should not
** call any of the macroname_x() functions directly.
**
** See the header comments above the corresponding macroname_x()
** function for a description of each interface.


*/


/* Database functions */
#define opendb(w,x,y,z)         (SEL(w), opendb_x(w,x,y,z))
#define closedb(y,z)            (SEL(y), closedb_x(y,z))

/* Functions to execute SQL */
#define sql_script(x,y,z)       (SEL(x), sql_script_x(x,y,z))
................................................................................
  char zBuf[33];
  p = sqlite3_aggregate_context(context, sizeof(*p));
  MD5Final(digest,p);
  MD5DigestToBase16(digest, zBuf);
  sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}

/*************************************************************************
** End of copied md5sum() code.
*/

typedef sqlite3_int64 i64;

typedef struct Error Error;
typedef struct Sqlite Sqlite;
typedef struct Statement Statement;

................................................................................
  p->zErr = 0;
  p->rc = 0;
}

static void print_err(Error *p){
  if( p->rc!=SQLITE_OK ){
    printf("Error: (%d) \"%s\" at line %d\n", p->rc, p->zErr, p->iLine);
    nGlobalErr++;

  }
}

static void print_and_free_err(Error *p){
  print_err(p);
  free_err(p);
}
................................................................................
    pNext = p->pNext;
    int rc;
    rc = pthread_join(p->tid, &ret);
    if( rc!=0 ){
      if( pErr->rc==SQLITE_OK ) system_error(pErr, rc);
    }else{
      printf("Thread %d says: %s\n", p->iTid, (ret==0 ? "..." : (char *)ret));

    }
    sqlite3_free(p);
  }
  pThreads->pThread = 0;
}

static i64 filesize_x(
................................................................................
    }else{
      ret = (t >= timelimit);
    }
  }
  return ret;
}

/* 
** The "Set Error Line" macro.
*/
#define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__))


/*************************************************************************
**************************************************************************
**************************************************************************
** End infrastructure. Begin tests.
*/

................................................................................
#include "tt3_index.c"
#include "tt3_lookaside1.c"
#include "tt3_vacuum.c"
#include "tt3_stress.c"

int main(int argc, char **argv){
  struct ThreadTest {
    void (*xTest)(int);
    const char *zTest;
    int nMs;
  } aTest[] = {
    { walthread1, "walthread1", 20000 },
    { walthread2, "walthread2", 20000 },
    { walthread3, "walthread3", 20000 },
    { walthread4, "walthread4", 20000 },
    { walthread5, "walthread5",  1000 },
    { walthread5, "walthread5",  1000 },
................................................................................
    { lookaside1,          "lookaside1", 10000 },
    { vacuum1,             "vacuum1", 10000 },
    { stress1,             "stress1", 10000 },
    { stress2,             "stress2", 60000 },
  };

  int i;
  int bTestfound = 0;

  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);

  for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
    char const *z = aTest[i].zTest;
    if( argc>1 ){
................................................................................
      for(iArg=1; iArg<argc; iArg++){
        if( 0==sqlite3_strglob(argv[iArg], z) ) break;
      }
      if( iArg==argc ) continue;
    }

    printf("Running %s for %d seconds...\n", z, aTest[i].nMs/1000);

    aTest[i].xTest(aTest[i].nMs);
    bTestfound++;
  }
  if( bTestfound==0 ) goto usage;

  printf("Total of %d errors across all tests\n", nGlobalErr);

  return (nGlobalErr>0 ? 255 : 0);

 usage:
  printf("Usage: %s [testname|testprefix*]...\n", argv[0]);
  printf("Available tests are:\n");
  for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
    printf("   %s\n", aTest[i].zTest);
  }

  return 254;
}


<

>
>
>
>
>
>
>
>
>
>
>






|
|
|

|
>
>

<
<
|
|
|
|
<
<

<
<
>


<
<
<
<
<
<
<
<
<
<
>
>

>







 







|

|







 







|
>







 







>







 







<
<
<
<
<







 







|
|
|







 







|







 







>

|

|

<
>











<
<

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
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
...
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
...
896
897
898
899
900
901
902





903
904
905
906
907
908
909
....
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
....
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
....
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473

1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485



/*
** 2010-07-22
**
** 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.
**
*************************************************************************
**
** The code in this file runs a few multi-threaded test cases using the
** SQLite library. It can be compiled to an executable on unix using the
** following command:
**
**   gcc -O2 threadtest3.c sqlite3.c -ldl -lpthread -lm
**
** Even though threadtest3.c is the only C source code file mentioned on
** the compiler command-line, #include macros are used to pull in additional
** C code files named "tt3_*.c".
**
** After compiling, run this program with an optional argument telling
** which test to run.  All tests are run if no argument is given.  The
** argument can be a glob pattern to match multiple tests.  Examples:
**


**        ./a.out                 -- Run all tests
**        ./a.out walthread3      -- Run the "walthread3" test
**        ./a.out 'wal*'          -- Run all of the wal* tests
**        ./a.out --help          -- List all available tests


**


** The exit status is non-zero if any test fails.
*/











/* 
** The "Set Error Line" macro.
*/
#define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__))

/* Database functions */
#define opendb(w,x,y,z)         (SEL(w), opendb_x(w,x,y,z))
#define closedb(y,z)            (SEL(y), closedb_x(y,z))

/* Functions to execute SQL */
#define sql_script(x,y,z)       (SEL(x), sql_script_x(x,y,z))
................................................................................
  char zBuf[33];
  p = sqlite3_aggregate_context(context, sizeof(*p));
  MD5Final(digest,p);
  MD5DigestToBase16(digest, zBuf);
  sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}

/*
** End of copied md5sum() code.
**************************************************************************/

typedef sqlite3_int64 i64;

typedef struct Error Error;
typedef struct Sqlite Sqlite;
typedef struct Statement Statement;

................................................................................
  p->zErr = 0;
  p->rc = 0;
}

static void print_err(Error *p){
  if( p->rc!=SQLITE_OK ){
    printf("Error: (%d) \"%s\" at line %d\n", p->rc, p->zErr, p->iLine);
    if( sqlite3_strglob("* - no such table: *",p->zErr)!=0 ) nGlobalErr++;
    fflush(stdout);
  }
}

static void print_and_free_err(Error *p){
  print_err(p);
  free_err(p);
}
................................................................................
    pNext = p->pNext;
    int rc;
    rc = pthread_join(p->tid, &ret);
    if( rc!=0 ){
      if( pErr->rc==SQLITE_OK ) system_error(pErr, rc);
    }else{
      printf("Thread %d says: %s\n", p->iTid, (ret==0 ? "..." : (char *)ret));
      fflush(stdout);
    }
    sqlite3_free(p);
  }
  pThreads->pThread = 0;
}

static i64 filesize_x(
................................................................................
    }else{
      ret = (t >= timelimit);
    }
  }
  return ret;
}







/*************************************************************************
**************************************************************************
**************************************************************************
** End infrastructure. Begin tests.
*/

................................................................................
#include "tt3_index.c"
#include "tt3_lookaside1.c"
#include "tt3_vacuum.c"
#include "tt3_stress.c"

int main(int argc, char **argv){
  struct ThreadTest {
    void (*xTest)(int);   /* Routine for running this test */
    const char *zTest;    /* Name of this test */
    int nMs;              /* How long to run this test, in milliseconds */
  } aTest[] = {
    { walthread1, "walthread1", 20000 },
    { walthread2, "walthread2", 20000 },
    { walthread3, "walthread3", 20000 },
    { walthread4, "walthread4", 20000 },
    { walthread5, "walthread5",  1000 },
    { walthread5, "walthread5",  1000 },
................................................................................
    { lookaside1,          "lookaside1", 10000 },
    { vacuum1,             "vacuum1", 10000 },
    { stress1,             "stress1", 10000 },
    { stress2,             "stress2", 60000 },
  };

  int i;
  int nTestfound = 0;

  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);

  for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
    char const *z = aTest[i].zTest;
    if( argc>1 ){
................................................................................
      for(iArg=1; iArg<argc; iArg++){
        if( 0==sqlite3_strglob(argv[iArg], z) ) break;
      }
      if( iArg==argc ) continue;
    }

    printf("Running %s for %d seconds...\n", z, aTest[i].nMs/1000);
    fflush(stdout);
    aTest[i].xTest(aTest[i].nMs);
    nTestfound++;
  }
  if( nTestfound==0 ) goto usage;


  printf("%d errors out of %d tests\n", nGlobalErr, nTestfound);
  return (nGlobalErr>0 ? 255 : 0);

 usage:
  printf("Usage: %s [testname|testprefix*]...\n", argv[0]);
  printf("Available tests are:\n");
  for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
    printf("   %s\n", aTest[i].zTest);
  }

  return 254;
}


Changes to test/tt3_checkpoint.c.

1
2
3
4
5
6
7
8
9
...
142
143
144
145
146
147
148
149
150
/*
** 2001 September 15
**
** 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.
................................................................................
  CheckpointStarvationCtx ctx = { SQLITE_CHECKPOINT_RESTART, 0 };
  checkpoint_starvation_main(nMs, &ctx);
  if( ctx.nMaxFrame>CHECKPOINT_STARVATION_FRAMELIMIT+10 ){
    test_error(&err, "WAL grew too large - %d frames", ctx.nMaxFrame);
  }
  print_and_free_err(&err);
}



|







 







<
<
1
2
3
4
5
6
7
8
9
...
142
143
144
145
146
147
148


/*
** 2011-02-02
**
** 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.
................................................................................
  CheckpointStarvationCtx ctx = { SQLITE_CHECKPOINT_RESTART, 0 };
  checkpoint_starvation_main(nMs, &ctx);
  if( ctx.nMaxFrame>CHECKPOINT_STARVATION_FRAMELIMIT+10 ){
    test_error(&err, "WAL grew too large - %d frames", ctx.nMaxFrame);
  }
  print_and_free_err(&err);
}


Changes to test/wal5.test.

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
384
385
386
387
388
389
390
391
392
393
394
395
  #
  do_multiclient_test tn {

    code1 $do_wal_checkpoint
    code2 $do_wal_checkpoint
    code3 $do_wal_checkpoint

    do_test 3.$tn.1 {
      sql1 {
        PRAGMA page_size = 1024;

        PRAGMA journal_mode = WAL;
        PRAGMA synchronous = normal;
        CREATE TABLE t1(x, y);
        CREATE INDEX i1 ON t1(x, y);
        INSERT INTO t1 VALUES(1, 2);
        INSERT INTO t1 VALUES(3, 4);
      }
      file size test.db-wal
    } [wal_file_size 8 1024]

    do_test 3.$tn.2 { do_wal_checkpoint db -mode truncate } {0 0 0}
    do_test 3.$tn.3 { file size test.db-wal } 0

    do_test 3.$tn.4 {
      sql2 { SELECT * FROM t1 }
    } {1 2 3 4}

    do_test 3.$tn.5 {
      sql2 { INSERT INTO t1 VALUES('a', 'b') }
      file size test.db-wal
    } [wal_file_size 2 1024]

  }
}


finish_test







|


>










|
|

|



|









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
384
385
386
387
388
389
390
391
392
393
394
395
396
  #
  do_multiclient_test tn {

    code1 $do_wal_checkpoint
    code2 $do_wal_checkpoint
    code3 $do_wal_checkpoint

    do_test 4.$tn.1 {
      sql1 {
        PRAGMA page_size = 1024;
        PRAGMA auto_vacuum = 0;
        PRAGMA journal_mode = WAL;
        PRAGMA synchronous = normal;
        CREATE TABLE t1(x, y);
        CREATE INDEX i1 ON t1(x, y);
        INSERT INTO t1 VALUES(1, 2);
        INSERT INTO t1 VALUES(3, 4);
      }
      file size test.db-wal
    } [wal_file_size 8 1024]

    do_test 4.$tn.2 { do_wal_checkpoint db -mode truncate } {0 0 0}
    do_test 4.$tn.3 { file size test.db-wal } 0

    do_test 4.$tn.4 {
      sql2 { SELECT * FROM t1 }
    } {1 2 3 4}

    do_test 4.$tn.5 {
      sql2 { INSERT INTO t1 VALUES('a', 'b') }
      file size test.db-wal
    } [wal_file_size 2 1024]

  }
}


finish_test

Added test/without_rowid6.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
# 2014-12-28
#
# 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.
#
#***********************************************************************
#
# Verify that WITHOUT ROWID tables work correctly when the PRIMARY KEY
# has redundant columns.
#

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

do_execsql_test without_rowid6-100 {
  CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,a,b,c,d,a,b,c)) WITHOUT ROWID;
  CREATE INDEX t1a ON t1(b, b);
  WITH RECURSIVE
    c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<1000)
  INSERT INTO t1(a,b,c,d,e) SELECT i, i+1000, printf('x%dy',i), 0, 0 FROM c;
  ANALYZE;
} {}
do_execsql_test without_rowid6-110 {
  SELECT c FROM t1 WHERE a=123;
} {x123y}
do_execsql_test without_rowid6-120 {
  SELECT c FROM t1 WHERE b=1123;
} {x123y}
do_execsql_test without_rowid6-130 {
  SELECT c FROM t1 ORDER BY a DESC LIMIT 5;
} {x1000y x999y x998y x997y x996y}
do_execsql_test without_rowid6-140 {
  SELECT c FROM t1 ORDER BY b LIMIT 5;
} {x1y x2y x3y x4y x5y}


finish_test

Changes to tool/mksqlite3c.tcl.

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
            set line {const char sqlite3_version[] = SQLITE_VERSION;}
          }
          regsub {^SQLITE_EXTERN } $line {} line
          puts $out "SQLITE_API $line"
        }
      } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
        regsub {^SQLITE_EXTERN } $line {} line
        puts $out "SQLITE_PRIVATE $line"
      } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
        puts $out "SQLITE_PRIVATE $line"
      } else {
        puts $out $line
      }
    } else {
      puts $out $line







|







210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
            set line {const char sqlite3_version[] = SQLITE_VERSION;}
          }
          regsub {^SQLITE_EXTERN } $line {} line
          puts $out "SQLITE_API $line"
        }
      } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
        regsub {^SQLITE_EXTERN } $line {} line
        puts $out $line
      } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
        puts $out "SQLITE_PRIVATE $line"
      } else {
        puts $out $line
      }
    } else {
      puts $out $line