/ Check-in [7c57bdbc]
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:Add the Bitvec object for tracking which pages have been journalled. This reduces memory consumption and runs faster than the bitmap approach it replaced. (CVS 4794)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7c57bdbcdb84d95419ec7029d2e13c593854a8d8
User & Date: drh 2008-02-18 14:47:34
Context
2008-02-18
22:24
Add the memory fault simulator to mem5.c. Enable soft heap limit on mem5.c. Limit the size of hash tables and the vdbefifo when using mem5.c. (CVS 4795) check-in: 63da5d97 user: drh tags: trunk
14:47
Add the Bitvec object for tracking which pages have been journalled. This reduces memory consumption and runs faster than the bitmap approach it replaced. (CVS 4794) check-in: 7c57bdbc user: drh tags: trunk
2008-02-16
16:21
The power-of-two first-fit memory allocator is now working. (CVS 4793) check-in: d134d29c user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to main.mk.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
..
81
82
83
84
85
86
87

88
89
90
91
92
93
94

# This is how we compile
#
TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src

# Object files for the SQLite library.
#
LIBOBJ+= alter.o analyze.o attach.o auth.o btmutex.o btree.o build.o \
         callback.o complete.o date.o delete.o \
         expr.o fault.o func.o hash.o insert.o journal.o loadext.o \
         main.o malloc.o mem1.o mem2.o mem3.o mem4.o mem5.o \
         mutex.o mutex_os2.o mutex_unix.o mutex_w32.o \
         opcodes.o os.o os_os2.o os_unix.o os_win.o \
         pager.o parse.o pragma.o prepare.o printf.o random.o \
         select.o table.o $(TCLOBJ) tokenize.o trigger.o \
................................................................................
# All of the source code files.
#
SRC = \
  $(TOP)/src/alter.c \
  $(TOP)/src/analyze.c \
  $(TOP)/src/attach.c \
  $(TOP)/src/auth.c \

  $(TOP)/src/btmutex.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/btree.h \
  $(TOP)/src/btreeInt.h \
  $(TOP)/src/build.c \
  $(TOP)/src/callback.c \
  $(TOP)/src/complete.c \







|







 







>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
..
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

# This is how we compile
#
TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src

# Object files for the SQLite library.
#
LIBOBJ+= alter.o analyze.o attach.o auth.o bitvec.o btmutex.o btree.o build.o \
         callback.o complete.o date.o delete.o \
         expr.o fault.o func.o hash.o insert.o journal.o loadext.o \
         main.o malloc.o mem1.o mem2.o mem3.o mem4.o mem5.o \
         mutex.o mutex_os2.o mutex_unix.o mutex_w32.o \
         opcodes.o os.o os_os2.o os_unix.o os_win.o \
         pager.o parse.o pragma.o prepare.o printf.o random.o \
         select.o table.o $(TCLOBJ) tokenize.o trigger.o \
................................................................................
# All of the source code files.
#
SRC = \
  $(TOP)/src/alter.c \
  $(TOP)/src/analyze.c \
  $(TOP)/src/attach.c \
  $(TOP)/src/auth.c \
  $(TOP)/src/bitvec.c \
  $(TOP)/src/btmutex.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/btree.h \
  $(TOP)/src/btreeInt.h \
  $(TOP)/src/build.c \
  $(TOP)/src/callback.c \
  $(TOP)/src/complete.c \

Added src/bitvec.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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
** 2008 February 16
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements an object that represents a fixed-length
** bitmap.  Bits are numbered starting with 1.
**
** A bitmap is used to record what pages a database file have been
** journalled during a transaction.  Usually only a few pages are
** journalled.  So the bitmap is usually sparse and has low cardinality.
** But sometimes (for example when during a DROP of a large table) most
** or all of the pages get journalled.  In those cases, the bitmap becomes
** dense.  The algorithm needs to handle both cases well.
**
** The size of the bitmap is fixed when the object is created.
**
** All bits are clear when the bitmap is created.  Individual bits
** may be set or cleared one at a time.
**
** Test operations are about 100 times more common that set operations.
** Clear operations are exceedingly rare.  There are usually between
** 5 and 500 set operations per Bitvec object, though the number of sets can
** sometimes grow into tens of thousands or larger.  The size of the
** Bitvec object is the number of pages in the database file at the
** start of a transaction, and is thus usually less than a few thousand,
** but can be as large as 2 billion for a really big database.
**
** @(#) $Id: bitvec.c,v 1.1 2008/02/18 14:47:34 drh Exp $
*/
#include "sqliteInt.h"

#define BITVEC_SZ        512
#define BITVEC_NCHAR     (BITVEC_SZ-12)
#define BITVEC_NBIT      (BITVEC_NCHAR*8)
#define BITVEC_NINT      ((BITVEC_SZ-12)/4)
#define BITVEC_MXHASH    (BITVEC_NINT/2)
#define BITVEC_NPTR      ((BITVEC_SZ-12)/8)

#define BITVEC_HASH(X)   (((X)*37)%BITVEC_NINT)

/*
** A bitmap is an instance of the following structure.
**
** This bitmap records the existance of zero or more bits
** with values between 1 and iSize, inclusive.
**
** There are three possible representations of the bitmap.
** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight
** bitmap.  The least significant bit is bit 1.
**
** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is
** a hash table that will hold up to BITVEC_MXHASH distinct values.
**
** Otherwise, the value i is redirected into one of BITVEC_NPTR
** sub-bitmaps pointed to by Bitvec.u.apSub[].  Each subbitmap
** handles up to iDivisor separate values of i.  apSub[0] holds
** values between 1 and iDivisor.  apSub[1] holds values between
** iDivisor+1 and 2*iDivisor.  apSub[N] holds values between
** N*iDivisor+1 and (N+1)*iDivisor.  Each subbitmap is normalized
** to hold deal with values between 1 and iDivisor.
*/
struct Bitvec {
  u32 iSize;      /* Maximum bit index */
  u32 nSet;       /* Number of bits that are set */
  u32 iDivisor;   /* Number of bits handled by each apSub[] entry */
  union {
    u8 aBitmap[BITVEC_NCHAR];    /* Bitmap representation */
    u32 aHash[BITVEC_NINT];      /* Hash table representation */
    Bitvec *apSub[BITVEC_NPTR];  /* Recursive representation */
  } u;
};

/*
** Create a new bitmap object able to handle bits between 0 and iSize,
** inclusive.  Return a pointer to the new object.  Return NULL if 
** malloc fails.
*/
Bitvec *sqlite3BitvecCreate(u32 iSize){
  Bitvec *p;
  assert( sizeof(*p)==BITVEC_SZ );
  p = sqlite3MallocZero( sizeof(*p) );
  if( p ){
    p->iSize = iSize;
  }
  return p;
}

/*
** Check to see if the i-th bit is set.  Return true or false.
** If p is NULL (if the bitmap has not been created) or if
** i is out of range, then return false.
*/
int sqlite3BitvecTest(Bitvec *p, u32 i){
  assert( i>0 );
  if( p==0 ) return 0;
  if( i>p->iSize ) return 0;
  if( p->iSize<=BITVEC_NBIT ){
    i--;
    return (p->u.aBitmap[i/8] & (1<<(i&7)))!=0;
  }
  if( p->iDivisor>0 ){
    u32 bin = (i-1)/p->iDivisor;
    i = (i-1)%p->iDivisor + 1;
    return sqlite3BitvecTest(p->u.apSub[bin], i);
  }else{
    u32 h = BITVEC_HASH(i);
    while( p->u.aHash[h] ){
      if( p->u.aHash[h]==i ) return 1;
      h++;
      if( h>=BITVEC_NINT ) h = 0;
    }
    return 0;
  }
}

/*
** Set the i-th bit.  Return 0 on success and an error code if
** anything goes wrong.
*/
int sqlite3BitvecSet(Bitvec *p, u32 i){
  u32 h;
  assert( p!=0 );
  if( p->iSize<=BITVEC_NBIT ){
    i--;
    p->u.aBitmap[i/8] |= 1 << (i&7);
    return SQLITE_OK;
  }
  if( p->iDivisor ){
    u32 bin = (i-1)/p->iDivisor;
    i = (i-1)%p->iDivisor + 1;
    if( p->u.apSub[bin]==0 ){
      sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1);
      p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
      sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0);
      if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
    }
    return sqlite3BitvecSet(p->u.apSub[bin], i);
  }
  h = BITVEC_HASH(i);
  while( p->u.aHash[h] ){
    if( p->u.aHash[h]==i ) return SQLITE_OK;
    h++;
    if( h==BITVEC_NINT ) h = 0;
  }
  p->nSet++;
  if( p->nSet>=BITVEC_MXHASH ){
    int j, rc;
    u32 aiValues[BITVEC_NINT];
    memcpy(aiValues, p->u.aHash, sizeof(aiValues));
    memset(p->u.apSub, 0, sizeof(p->u.apSub[0])*BITVEC_NPTR);
    p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
    sqlite3BitvecSet(p, i);
    for(rc=j=0; j<BITVEC_NINT; j++){
      if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
    }
    return rc;
  }
  p->u.aHash[h] = i;
  return SQLITE_OK;
}

/*
** Clear the i-th bit.  Return 0 on success and an error code if
** anything goes wrong.
*/
void sqlite3BitvecClear(Bitvec *p, u32 i){
  assert( p!=0 );
  if( p->iSize<=BITVEC_NBIT ){
    i--;
    p->u.aBitmap[i/8] &= ~(1 << (i&7));
  }else if( p->iDivisor ){
    u32 bin = (i-1)/p->iDivisor;
    i = (i-1)%p->iDivisor + 1;
    if( p->u.apSub[bin] ){
      sqlite3BitvecClear(p->u.apSub[bin], i);
    }
  }else{
    int j;
    u32 aiValues[BITVEC_NINT];
    memcpy(aiValues, p->u.aHash, sizeof(aiValues));
    memset(p->u.aHash, 0, sizeof(p->u.aHash[0])*BITVEC_NINT);
    p->nSet = 0;
    for(j=0; j<BITVEC_NINT; j++){
      if( aiValues[j] && aiValues[j]!=i ) sqlite3BitvecSet(p, aiValues[j]);
    }
  }
}

/*
** Destroy a bitmap object.  Reclaim all memory used.
*/
void sqlite3BitvecDestroy(Bitvec *p){
  if( p==0 ) return;
  if( p->iDivisor ){
    int i;
    for(i=0; i<BITVEC_NPTR; i++){
      sqlite3BitvecDestroy(p->u.apSub[i]);
    }
  }
  sqlite3_free(p);
}

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
....
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
....
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
....
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
....
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
....
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
....
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
....
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
....
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
....
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
....
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
....
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
....
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
....
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
....
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
....
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
....
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
....
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
....
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.406 2008/02/14 23:26:56 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include <assert.h>
#include <string.h>

/*
................................................................................
**     This is true if the original page has been written into the main
**     rollback journal.  This is always false for new pages added to
**     the end of the database file during the current transaction.
**     And this flag says nothing about whether or not the journal
**     has been synced to disk.  For pages that are in the original
**     database file, the following expression should always be true:
**
**       inJournal = (pPager->aInJournal[(pgno-1)/8] & (1<<((pgno-1)%8))!=0
**
**     The pPager->aInJournal[] array is only valid for the original
**     pages of the database, not new pages that are added to the end
**     of the database, so obviously the above expression cannot be
**     valid for new pages.  For new pages inJournal is always 0.
**
** dirty
**
**     When true, this means that the content of the page has been
................................................................................
  int stmtNRec;               /* Number of records in stmt subjournal */
  int nExtra;                 /* Add this many bytes to each in-memory page */
  int pageSize;               /* Number of bytes in a page */
  int nPage;                  /* Total number of in-memory pages */
  int nRef;                   /* Number of in-memory pages with PgHdr.nRef>0 */
  int mxPage;                 /* Maximum number of pages to hold in cache */
  Pgno mxPgno;                /* Maximum allowed size of the database */
  u8 *aInJournal;             /* One bit for each page in the database file */
  u8 *aInStmt;                /* One bit for each page in the database */
  char *zFilename;            /* Name of the database file */
  char *zJournal;             /* Name of the journal file */
  char *zDirectory;           /* Directory hold database and journal files */
  char *zStmtJrnl;            /* Name of the statement journal file */
  sqlite3_file *fd, *jfd;     /* File descriptors for database and journal */
  sqlite3_file *stfd;         /* File descriptor for the statement subjournal*/
  BusyHandler *pBusyHandler;  /* Pointer to sqlite.busyHandler */
................................................................................
** of an in-memory database).
*/
static int pageInStatement(PgHdr *pPg){
  Pager *pPager = pPg->pPager;
  if( MEMDB ){
    return PGHDR_TO_HIST(pPg, pPager)->inStmt;
  }else{
    Pgno pgno = pPg->pgno;
    u8 *a = pPager->aInStmt;
    return (a && (int)pgno<=pPager->stmtSize && (a[pgno/8] & (1<<(pgno&7))));
  }
}

/*
** Change the size of the pager hash table to N.  N must be a power
** of two.
*/
................................................................................
      ** cache can be discarded and the error code safely cleared.
      */
      if( pPager->errCode ){
        pPager->errCode = SQLITE_OK;
        pager_reset(pPager);
        if( pPager->stmtOpen ){
          sqlite3OsClose(pPager->stfd);
          sqlite3_free(pPager->aInStmt);
          pPager->aInStmt = 0;
        }
        if( pPager->journalOpen ){
          sqlite3OsClose(pPager->jfd);
          pPager->journalOpen = 0;
          sqlite3_free(pPager->aInJournal);
          pPager->aInJournal = 0;
        }
        pPager->stmtOpen = 0;
        pPager->stmtInUse = 0;
        pPager->journalOff = 0;
        pPager->journalStarted = 0;
        pPager->stmtAutoopen = 0;
        pPager->origDbSize = 0;
................................................................................
    }else{
      sqlite3OsClose(pPager->jfd);
      pPager->journalOpen = 0;
      if( rc==SQLITE_OK ){
        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
      }
    }
    sqlite3_free( pPager->aInJournal );
    pPager->aInJournal = 0;
    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
      pPg->inJournal = 0;
      pPg->dirty = 0;
      pPg->needSync = 0;
      pPg->alwaysRollback = 0;
#ifdef SQLITE_CHECK_PAGES
      pPg->pageHash = pager_pagehash(pPg);
#endif
    }
    pPager->pDirty = 0;
    pPager->dirtyCache = 0;
    pPager->nRec = 0;
  }else{
    assert( pPager->aInJournal==0 );
    assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
  }

  if( !pPager->exclusiveMode ){
    rc2 = osUnlock(pPager->fd, SHARED_LOCK);
    pPager->state = PAGER_SHARED;
  }else if( pPager->state==PAGER_SYNCED ){
................................................................................
  enable_simulated_io_errors();
  PAGERTRACE2("CLOSE %d\n", PAGERID(pPager));
  IOTRACE(("CLOSE %p\n", pPager))
  assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
  if( pPager->journalOpen ){
    sqlite3OsClose(pPager->jfd);
  }
  sqlite3_free(pPager->aInJournal);
  if( pPager->stmtOpen ){
    sqlite3OsClose(pPager->stfd);
  }
  sqlite3OsClose(pPager->fd);
  /* Temp files are automatically deleted by the OS
  ** if( pPager->tempFile ){
  **   sqlite3OsDelete(pPager->zFilename);
................................................................................
    rc = pagerAllocatePage(pPager, &pPg);
    if( rc!=SQLITE_OK ){
      return rc;
    }

    pPg->pgno = pgno;
    assert( !MEMDB || pgno>pPager->stmtSize );
    if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
#if 0
      sqlite3CheckMemory(pPager->aInJournal, pgno/8);
#endif
      assert( pPager->journalOpen );
      pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
      pPg->needSync = 0;
    }else{
      pPg->inJournal = 0;
      pPg->needSync = 0;
    }

    makeClean(pPg);
    pPg->nRef = 1;

    pPager->nRef++;
    if( pPager->nExtra>0 ){
      memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
................................................................................
  int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE);

  int rc;
  assert( !MEMDB );
  assert( pPager->state>=PAGER_RESERVED );
  assert( pPager->journalOpen==0 );
  assert( pPager->useJournal );
  assert( pPager->aInJournal==0 );
  sqlite3PagerPagecount(pPager);
  pagerLeave(pPager);
  pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 );
  pagerEnter(pPager);
  if( pPager->aInJournal==0 ){
    rc = SQLITE_NOMEM;
    goto failed_to_open_journal;
  }

  if( pPager->tempFile ){
    flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
  }else{
................................................................................
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
  }
  return rc;

failed_to_open_journal:
  sqlite3_free(pPager->aInJournal);
  pPager->aInJournal = 0;
  return rc;
}

/*
** Acquire a write-lock on the database.  The lock is removed when
** the any of the following happen:
**
................................................................................
int sqlite3PagerBegin(DbPage *pPg, int exFlag){
  Pager *pPager = pPg->pPager;
  int rc = SQLITE_OK;
  pagerEnter(pPager);
  assert( pPg->nRef>0 );
  assert( pPager->state!=PAGER_UNLOCK );
  if( pPager->state==PAGER_SHARED ){
    assert( pPager->aInJournal==0 );
    if( MEMDB ){
      pPager->state = PAGER_EXCLUSIVE;
      pPager->origDbSize = pPager->dbSize;
    }else{
      rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
      if( rc==SQLITE_OK ){
        pPager->state = PAGER_RESERVED;
................................................................................
    /* This happens when the pager was in exclusive-access mode last
    ** time a (read or write) transaction was successfully concluded
    ** by this connection. Instead of deleting the journal file it was 
    ** kept open and truncated to 0 bytes.
    */
    assert( pPager->nRec==0 );
    assert( pPager->origDbSize==0 );
    assert( pPager->aInJournal==0 );
    sqlite3PagerPagecount(pPager);
    pagerLeave(pPager);
    pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 );
    pagerEnter(pPager);
    if( !pPager->aInJournal ){
      rc = SQLITE_NOMEM;
    }else{
      pPager->origDbSize = pPager->dbSize;
      rc = writeJournalHdr(pPager);
    }
  }
  assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK );
................................................................................
          ** transaction will be rolled back by the layer above.
          */
          if( rc!=SQLITE_OK ){
            return rc;
          }

          pPager->nRec++;
          assert( pPager->aInJournal!=0 );
          pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
          pPg->needSync = !pPager->noSync;
          if( pPager->stmtInUse ){
            pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
          }
        }
      }else{
        pPg->needSync = !pPager->journalStarted && !pPager->noSync;
        PAGERTRACE4("APPEND %d page %d needSync=%d\n",
                PAGERID(pPager), pPg->pgno, pPg->needSync);
      }
................................................................................
          rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
        }
        PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        pPager->stmtNRec++;
        assert( pPager->aInStmt!=0 );
        pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
      }
    }
  }

  /* Update the database size and return.
  */
  assert( pPager->state>=PAGER_SHARED );
................................................................................
    assert(nPage>0);
    assert(pg1<=pPg->pgno);
    assert((pg1+nPage)>pPg->pgno);

    for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
      Pgno pg = pg1+ii;
      PgHdr *pPage;
      if( !pPager->aInJournal || pg==pPg->pgno || 
          pg>pPager->origDbSize || !(pPager->aInJournal[pg/8]&(1<<(pg&7)))
      ) {
        if( pg!=PAGER_MJ_PGNO(pPager) ){
          rc = sqlite3PagerGet(pPager, pg, &pPage);
          if( rc==SQLITE_OK ){
            rc = pager_write(pPage);
            if( pPage->needSync ){
              needSync = 1;
            }
................................................................................
  assert( !MEMDB );    /* For a memdb, pPager->journalOpen is always 0 */

  /* Check that PagerWrite() has not yet been called on this page, and
  ** that the page existed when the transaction started.
  */
  assert( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize );

  assert( pPager->aInJournal!=0 );
  pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
  pPg->inJournal = 1;
  pPg->needRead = 0;
  if( pPager->stmtInUse ){
    assert( pPager->stmtSize <= pPager->origDbSize );
    pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
  }
  PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager));
  IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno))
  pagerLeave(pPager);
}


................................................................................
        /* If this transaction has made the database smaller, then all pages
        ** being discarded by the truncation must be written to the journal
        ** file.
        */
        Pgno i;
        int iSkip = PAGER_MJ_PGNO(pPager);
        for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
          if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
            rc = sqlite3PagerGet(pPager, i, &pPg);
            if( rc!=SQLITE_OK ) goto sync_exit;
            rc = sqlite3PagerWrite(pPg);
            sqlite3PagerUnref(pPg);
            if( rc!=SQLITE_OK ) goto sync_exit;
          }
        } 
................................................................................
  }
  if( !pPager->journalOpen ){
    pPager->stmtAutoopen = 1;
    return SQLITE_OK;
  }
  assert( pPager->journalOpen );
  pagerLeave(pPager);
  assert( pPager->aInStmt==0 );
  pPager->aInStmt = sqlite3MallocZero( pPager->dbSize/8 + 1 );
  pagerEnter(pPager);
  if( pPager->aInStmt==0 ){
    /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
    return SQLITE_NOMEM;
  }
#ifndef NDEBUG
  rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize);
  if( rc ) goto stmt_begin_failed;
  assert( pPager->stmtJSize == pPager->journalOff );
................................................................................
    pPager->stmtOpen = 1;
    pPager->stmtNRec = 0;
  }
  pPager->stmtInUse = 1;
  return SQLITE_OK;
 
stmt_begin_failed:
  if( pPager->aInStmt ){
    sqlite3_free(pPager->aInStmt);
    pPager->aInStmt = 0;
  }
  return rc;
}
int sqlite3PagerStmtBegin(Pager *pPager){
  int rc;
  pagerEnter(pPager);
  rc = pagerStmtBegin(pPager);
................................................................................
int sqlite3PagerStmtCommit(Pager *pPager){
  pagerEnter(pPager);
  if( pPager->stmtInUse ){
    PgHdr *pPg, *pNext;
    PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
    if( !MEMDB ){
      /* sqlite3OsTruncate(pPager->stfd, 0); */
      sqlite3_free( pPager->aInStmt );
      pPager->aInStmt = 0;
    }else{
      for(pPg=pPager->pStmt; pPg; pPg=pNext){
        PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
        pNext = pHist->pNextStmt;
        assert( pHist->inStmt );
        pHist->inStmt = 0;
        pHist->pPrevStmt = pHist->pNextStmt = 0;
................................................................................
    assert( pPgOld->nRef==0 );
    unlinkHashChain(pPager, pPgOld);
    makeClean(pPgOld);
    pPg->needSync = pPgOld->needSync;
  }else{
    pPg->needSync = 0;
  }
  if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
    pPg->inJournal =  (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
  }else{
    pPg->inJournal = 0;
    assert( pPg->needSync==0 || (int)pgno>pPager->origDbSize );
  }

  /* Change the page number for pPg and insert it into the new hash-chain. */
  assert( pgno!=0 );
  pPg->pgno = pgno;
  h = pgno & (pPager->nHash-1);
  if( pPager->aHash[h] ){
    assert( pPager->aHash[h]->pPrevHash==0 );
................................................................................
  makeDirty(pPg);
  pPager->dirtyCache = 1;

  if( needSyncPgno ){
    /* If needSyncPgno is non-zero, then the journal file needs to be 
    ** sync()ed before any data is written to database file page needSyncPgno.
    ** Currently, no such page exists in the page-cache and the 
    ** Pager.aInJournal bit has been set. This needs to be remedied by loading
    ** the page into the pager-cache and setting the PgHdr.needSync flag.
    **
    ** If the attempt to load the page into the page-cache fails, (due
    ** to a malloc() or IO failure), clear the bit in the aInJournal[]
    ** array. Otherwise, if the page is loaded and written again in
    ** this transaction, it may be written to the database file before
    ** it is synced into the journal file. This way, it may end up in
    ** the journal file twice, but that is not a problem.
    **
    ** The sqlite3PagerGet() call may cause the journal to sync. So make
    ** sure the Pager.needSync flag is set too.
    */
    int rc;
    PgHdr *pPgHdr;
    assert( pPager->needSync );
    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
    if( rc!=SQLITE_OK ){
      if( pPager->aInJournal && (int)needSyncPgno<=pPager->origDbSize ){
        pPager->aInJournal[needSyncPgno/8] &= ~(1<<(needSyncPgno&7));
      }
      pagerLeave(pPager);
      return rc;
    }
    pPager->needSync = 1;
    pPgHdr->needSync = 1;
    pPgHdr->inJournal = 1;







|







 







|

|







 







|
|







 







|
<
<







 







|
|




|
|







 







|
|













|







 







|







 







<
<
<
<
<
<
<
<
|
|
<







 







|


|

|







 







|
|







 







|







 







|


|

|







 







|
|


|







 







|
|







 







|
<
<







 







|
|




|







 







|







 







|
|

|







 







|
|
|







 







|
|







 







<
<
<
|
<
<







 







|



|













|
|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
662
663
664
665
666
667
668
669


670
671
672
673
674
675
676
....
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
....
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
....
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
....
3619
3620
3621
3622
3623
3624
3625








3626
3627

3628
3629
3630
3631
3632
3633
3634
....
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
....
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
....
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
....
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
....
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
....
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
....
4212
4213
4214
4215
4216
4217
4218
4219


4220
4221
4222
4223
4224
4225
4226
....
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
....
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
....
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
....
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
....
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
....
5010
5011
5012
5013
5014
5015
5016



5017


5018
5019
5020
5021
5022
5023
5024
....
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.407 2008/02/18 14:47:34 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include <assert.h>
#include <string.h>

/*
................................................................................
**     This is true if the original page has been written into the main
**     rollback journal.  This is always false for new pages added to
**     the end of the database file during the current transaction.
**     And this flag says nothing about whether or not the journal
**     has been synced to disk.  For pages that are in the original
**     database file, the following expression should always be true:
**
**       inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno)
**
**     The pPager->pInJournal object is only valid for the original
**     pages of the database, not new pages that are added to the end
**     of the database, so obviously the above expression cannot be
**     valid for new pages.  For new pages inJournal is always 0.
**
** dirty
**
**     When true, this means that the content of the page has been
................................................................................
  int stmtNRec;               /* Number of records in stmt subjournal */
  int nExtra;                 /* Add this many bytes to each in-memory page */
  int pageSize;               /* Number of bytes in a page */
  int nPage;                  /* Total number of in-memory pages */
  int nRef;                   /* Number of in-memory pages with PgHdr.nRef>0 */
  int mxPage;                 /* Maximum number of pages to hold in cache */
  Pgno mxPgno;                /* Maximum allowed size of the database */
  Bitvec *pInJournal;         /* One bit for each page in the database file */
  Bitvec *pInStmt;            /* One bit for each page in the database */
  char *zFilename;            /* Name of the database file */
  char *zJournal;             /* Name of the journal file */
  char *zDirectory;           /* Directory hold database and journal files */
  char *zStmtJrnl;            /* Name of the statement journal file */
  sqlite3_file *fd, *jfd;     /* File descriptors for database and journal */
  sqlite3_file *stfd;         /* File descriptor for the statement subjournal*/
  BusyHandler *pBusyHandler;  /* Pointer to sqlite.busyHandler */
................................................................................
** of an in-memory database).
*/
static int pageInStatement(PgHdr *pPg){
  Pager *pPager = pPg->pPager;
  if( MEMDB ){
    return PGHDR_TO_HIST(pPg, pPager)->inStmt;
  }else{
    return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno);


  }
}

/*
** Change the size of the pager hash table to N.  N must be a power
** of two.
*/
................................................................................
      ** cache can be discarded and the error code safely cleared.
      */
      if( pPager->errCode ){
        pPager->errCode = SQLITE_OK;
        pager_reset(pPager);
        if( pPager->stmtOpen ){
          sqlite3OsClose(pPager->stfd);
          sqlite3BitvecDestroy(pPager->pInStmt);
          pPager->pInStmt = 0;
        }
        if( pPager->journalOpen ){
          sqlite3OsClose(pPager->jfd);
          pPager->journalOpen = 0;
          sqlite3BitvecDestroy(pPager->pInJournal);
          pPager->pInJournal = 0;
        }
        pPager->stmtOpen = 0;
        pPager->stmtInUse = 0;
        pPager->journalOff = 0;
        pPager->journalStarted = 0;
        pPager->stmtAutoopen = 0;
        pPager->origDbSize = 0;
................................................................................
    }else{
      sqlite3OsClose(pPager->jfd);
      pPager->journalOpen = 0;
      if( rc==SQLITE_OK ){
        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
      }
    }
    sqlite3BitvecDestroy(pPager->pInJournal);
    pPager->pInJournal = 0;
    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
      pPg->inJournal = 0;
      pPg->dirty = 0;
      pPg->needSync = 0;
      pPg->alwaysRollback = 0;
#ifdef SQLITE_CHECK_PAGES
      pPg->pageHash = pager_pagehash(pPg);
#endif
    }
    pPager->pDirty = 0;
    pPager->dirtyCache = 0;
    pPager->nRec = 0;
  }else{
    assert( pPager->pInJournal==0 );
    assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
  }

  if( !pPager->exclusiveMode ){
    rc2 = osUnlock(pPager->fd, SHARED_LOCK);
    pPager->state = PAGER_SHARED;
  }else if( pPager->state==PAGER_SYNCED ){
................................................................................
  enable_simulated_io_errors();
  PAGERTRACE2("CLOSE %d\n", PAGERID(pPager));
  IOTRACE(("CLOSE %p\n", pPager))
  assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
  if( pPager->journalOpen ){
    sqlite3OsClose(pPager->jfd);
  }
  sqlite3BitvecDestroy(pPager->pInJournal);
  if( pPager->stmtOpen ){
    sqlite3OsClose(pPager->stfd);
  }
  sqlite3OsClose(pPager->fd);
  /* Temp files are automatically deleted by the OS
  ** if( pPager->tempFile ){
  **   sqlite3OsDelete(pPager->zFilename);
................................................................................
    rc = pagerAllocatePage(pPager, &pPg);
    if( rc!=SQLITE_OK ){
      return rc;
    }

    pPg->pgno = pgno;
    assert( !MEMDB || pgno>pPager->stmtSize );








    pPg->inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno);
    pPg->needSync = 0;


    makeClean(pPg);
    pPg->nRef = 1;

    pPager->nRef++;
    if( pPager->nExtra>0 ){
      memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
................................................................................
  int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE);

  int rc;
  assert( !MEMDB );
  assert( pPager->state>=PAGER_RESERVED );
  assert( pPager->journalOpen==0 );
  assert( pPager->useJournal );
  assert( pPager->pInJournal==0 );
  sqlite3PagerPagecount(pPager);
  pagerLeave(pPager);
  pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
  pagerEnter(pPager);
  if( pPager->pInJournal==0 ){
    rc = SQLITE_NOMEM;
    goto failed_to_open_journal;
  }

  if( pPager->tempFile ){
    flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
  }else{
................................................................................
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
  }
  return rc;

failed_to_open_journal:
  sqlite3BitvecDestroy(pPager->pInJournal);
  pPager->pInJournal = 0;
  return rc;
}

/*
** Acquire a write-lock on the database.  The lock is removed when
** the any of the following happen:
**
................................................................................
int sqlite3PagerBegin(DbPage *pPg, int exFlag){
  Pager *pPager = pPg->pPager;
  int rc = SQLITE_OK;
  pagerEnter(pPager);
  assert( pPg->nRef>0 );
  assert( pPager->state!=PAGER_UNLOCK );
  if( pPager->state==PAGER_SHARED ){
    assert( pPager->pInJournal==0 );
    if( MEMDB ){
      pPager->state = PAGER_EXCLUSIVE;
      pPager->origDbSize = pPager->dbSize;
    }else{
      rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
      if( rc==SQLITE_OK ){
        pPager->state = PAGER_RESERVED;
................................................................................
    /* This happens when the pager was in exclusive-access mode last
    ** time a (read or write) transaction was successfully concluded
    ** by this connection. Instead of deleting the journal file it was 
    ** kept open and truncated to 0 bytes.
    */
    assert( pPager->nRec==0 );
    assert( pPager->origDbSize==0 );
    assert( pPager->pInJournal==0 );
    sqlite3PagerPagecount(pPager);
    pagerLeave(pPager);
    pPager->pInJournal = sqlite3BitvecCreate( pPager->dbSize );
    pagerEnter(pPager);
    if( !pPager->pInJournal ){
      rc = SQLITE_NOMEM;
    }else{
      pPager->origDbSize = pPager->dbSize;
      rc = writeJournalHdr(pPager);
    }
  }
  assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK );
................................................................................
          ** transaction will be rolled back by the layer above.
          */
          if( rc!=SQLITE_OK ){
            return rc;
          }

          pPager->nRec++;
          assert( pPager->pInJournal!=0 );
          sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
          pPg->needSync = !pPager->noSync;
          if( pPager->stmtInUse ){
            sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
          }
        }
      }else{
        pPg->needSync = !pPager->journalStarted && !pPager->noSync;
        PAGERTRACE4("APPEND %d page %d needSync=%d\n",
                PAGERID(pPager), pPg->pgno, pPg->needSync);
      }
................................................................................
          rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
        }
        PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        pPager->stmtNRec++;
        assert( pPager->pInStmt!=0 );
        sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
      }
    }
  }

  /* Update the database size and return.
  */
  assert( pPager->state>=PAGER_SHARED );
................................................................................
    assert(nPage>0);
    assert(pg1<=pPg->pgno);
    assert((pg1+nPage)>pPg->pgno);

    for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
      Pgno pg = pg1+ii;
      PgHdr *pPage;
      if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){


        if( pg!=PAGER_MJ_PGNO(pPager) ){
          rc = sqlite3PagerGet(pPager, pg, &pPage);
          if( rc==SQLITE_OK ){
            rc = pager_write(pPage);
            if( pPage->needSync ){
              needSync = 1;
            }
................................................................................
  assert( !MEMDB );    /* For a memdb, pPager->journalOpen is always 0 */

  /* Check that PagerWrite() has not yet been called on this page, and
  ** that the page existed when the transaction started.
  */
  assert( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize );

  assert( pPager->pInJournal!=0 );
  sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
  pPg->inJournal = 1;
  pPg->needRead = 0;
  if( pPager->stmtInUse ){
    assert( pPager->stmtSize <= pPager->origDbSize );
    sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
  }
  PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager));
  IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno))
  pagerLeave(pPager);
}


................................................................................
        /* If this transaction has made the database smaller, then all pages
        ** being discarded by the truncation must be written to the journal
        ** file.
        */
        Pgno i;
        int iSkip = PAGER_MJ_PGNO(pPager);
        for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
          if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
            rc = sqlite3PagerGet(pPager, i, &pPg);
            if( rc!=SQLITE_OK ) goto sync_exit;
            rc = sqlite3PagerWrite(pPg);
            sqlite3PagerUnref(pPg);
            if( rc!=SQLITE_OK ) goto sync_exit;
          }
        } 
................................................................................
  }
  if( !pPager->journalOpen ){
    pPager->stmtAutoopen = 1;
    return SQLITE_OK;
  }
  assert( pPager->journalOpen );
  pagerLeave(pPager);
  assert( pPager->pInStmt==0 );
  pPager->pInStmt = sqlite3BitvecCreate(pPager->dbSize);
  pagerEnter(pPager);
  if( pPager->pInStmt==0 ){
    /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
    return SQLITE_NOMEM;
  }
#ifndef NDEBUG
  rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize);
  if( rc ) goto stmt_begin_failed;
  assert( pPager->stmtJSize == pPager->journalOff );
................................................................................
    pPager->stmtOpen = 1;
    pPager->stmtNRec = 0;
  }
  pPager->stmtInUse = 1;
  return SQLITE_OK;
 
stmt_begin_failed:
  if( pPager->pInStmt ){
    sqlite3BitvecDestroy(pPager->pInStmt);
    pPager->pInStmt = 0;
  }
  return rc;
}
int sqlite3PagerStmtBegin(Pager *pPager){
  int rc;
  pagerEnter(pPager);
  rc = pagerStmtBegin(pPager);
................................................................................
int sqlite3PagerStmtCommit(Pager *pPager){
  pagerEnter(pPager);
  if( pPager->stmtInUse ){
    PgHdr *pPg, *pNext;
    PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
    if( !MEMDB ){
      /* sqlite3OsTruncate(pPager->stfd, 0); */
      sqlite3BitvecDestroy(pPager->pInStmt);
      pPager->pInStmt = 0;
    }else{
      for(pPg=pPager->pStmt; pPg; pPg=pNext){
        PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
        pNext = pHist->pNextStmt;
        assert( pHist->inStmt );
        pHist->inStmt = 0;
        pHist->pPrevStmt = pHist->pNextStmt = 0;
................................................................................
    assert( pPgOld->nRef==0 );
    unlinkHashChain(pPager, pPgOld);
    makeClean(pPgOld);
    pPg->needSync = pPgOld->needSync;
  }else{
    pPg->needSync = 0;
  }



  pPg->inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno);



  /* Change the page number for pPg and insert it into the new hash-chain. */
  assert( pgno!=0 );
  pPg->pgno = pgno;
  h = pgno & (pPager->nHash-1);
  if( pPager->aHash[h] ){
    assert( pPager->aHash[h]->pPrevHash==0 );
................................................................................
  makeDirty(pPg);
  pPager->dirtyCache = 1;

  if( needSyncPgno ){
    /* If needSyncPgno is non-zero, then the journal file needs to be 
    ** sync()ed before any data is written to database file page needSyncPgno.
    ** Currently, no such page exists in the page-cache and the 
    ** Pager.pInJournal bit has been set. This needs to be remedied by loading
    ** the page into the pager-cache and setting the PgHdr.needSync flag.
    **
    ** If the attempt to load the page into the page-cache fails, (due
    ** to a malloc() or IO failure), clear the bit in the pInJournal[]
    ** array. Otherwise, if the page is loaded and written again in
    ** this transaction, it may be written to the database file before
    ** it is synced into the journal file. This way, it may end up in
    ** the journal file twice, but that is not a problem.
    **
    ** The sqlite3PagerGet() call may cause the journal to sync. So make
    ** sure the Pager.needSync flag is set too.
    */
    int rc;
    PgHdr *pPgHdr;
    assert( pPager->needSync );
    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
    if( rc!=SQLITE_OK ){
      if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){
        sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
      }
      pagerLeave(pPager);
      return rc;
    }
    pPager->needSync = 1;
    pPgHdr->needSync = 1;
    pPgHdr->inJournal = 1;

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
359
360
361
362
363
364
365

366
367
368
369
370
371
372
....
1755
1756
1757
1758
1759
1760
1761






1762
1763
1764
1765
1766
1767
1768
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.662 2008/02/14 23:26:56 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** The macro unlikely() is a hint that surrounds a boolean
** expression that is usually false.  Macro likely() surrounds
................................................................................
#define ArraySize(X)    (sizeof(X)/sizeof(X[0]))

/*
** Forward references to structures
*/
typedef struct AggInfo AggInfo;
typedef struct AuthContext AuthContext;

typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
................................................................................
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);







void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);

#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
  int sqlite3ViewGetColumnNames(Parse*,Table*);
#else
# define sqlite3ViewGetColumnNames(A,B) 0
#endif







|







 







>







 







>
>
>
>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
....
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.663 2008/02/18 14:47:34 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** The macro unlikely() is a hint that surrounds a boolean
** expression that is usually false.  Macro likely() surrounds
................................................................................
#define ArraySize(X)    (sizeof(X)/sizeof(X[0]))

/*
** Forward references to structures
*/
typedef struct AggInfo AggInfo;
typedef struct AuthContext AuthContext;
typedef struct Bitvec Bitvec;
typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
................................................................................
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);

Bitvec *sqlite3BitvecCreate(u32);
int sqlite3BitvecTest(Bitvec*, u32);
int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32);
void sqlite3BitvecDestroy(Bitvec*);

void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);

#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
  int sqlite3ViewGetColumnNames(Parse*,Table*);
#else
# define sqlite3ViewGetColumnNames(A,B) 0
#endif

Changes to src/test2.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
557
558
559
560
561
562
563


































































































564
565
566
567
568
569
570
...
590
591
592
593
594
595
596





597
598
599
600
601
602
603
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the pager.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test2.c,v 1.52 2007/09/03 15:19:35 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*
................................................................................
    Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}
#endif



































































































/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest2_Init(Tcl_Interp *interp){
  extern int sqlite3_io_error_persist;
  extern int sqlite3_io_error_pending;
  extern int sqlite3_io_error_hit;
................................................................................
    { "page_read",               (Tcl_CmdProc*)page_read           },
    { "page_write",              (Tcl_CmdProc*)page_write          },
    { "page_number",             (Tcl_CmdProc*)page_number         },
    { "pager_truncate",          (Tcl_CmdProc*)pager_truncate      },
#ifndef SQLITE_OMIT_DISKIO
    { "fake_big_file",           (Tcl_CmdProc*)fake_big_file       },
#endif





  };
  int i;
  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }
  Tcl_LinkVar(interp, "sqlite_io_error_pending",
     (char*)&sqlite3_io_error_pending, TCL_LINK_INT);







|







 







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







 







>
>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
...
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the pager.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test2.c,v 1.53 2008/02/18 14:47:34 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*
................................................................................
    Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}
#endif

/*
**   sqlite3BitvecCreate SIZE
**   sqlite3BitvecTest POINTER N
**   sqlite3BitvecSet POINTER N
**   sqlite3BitvecClear POINTER N
**   sqlite3BitvecDestroy POINTER
*/
static int testBitvecCreate(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  int size;
  Bitvec *p;
  char zBuf[100];
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 
           (void*)0);
  }
  if( Tcl_GetInt(interp, argv[1], &size) ) return TCL_ERROR;
  p = sqlite3BitvecCreate(size);
  sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",p);
  Tcl_AppendResult(interp, zBuf, 0);
  return TCL_OK;
}  
static int testBitvecTest(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  int N;
  Bitvec *p;
  char zBuf[100];
  if( argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"", 
           (void*)0);
  }
  p = (Bitvec*)sqlite3TextToPtr(argv[1]);
  if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR;
  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3BitvecTest(p,N));
  Tcl_AppendResult(interp, zBuf, 0);
  return TCL_OK;
}  
static int testBitvecSet(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  int N;
  Bitvec *p;
  char zBuf[100];
  if( argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"", 
           (void*)0);
  }
  p = (Bitvec*)sqlite3TextToPtr(argv[1]);
  if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR;
  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3BitvecSet(p,N));
  Tcl_AppendResult(interp, zBuf, 0);
  return TCL_OK;
}  
static int testBitvecClear(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  int N;
  Bitvec *p;
  if( argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"", 
           (void*)0);
  }
  p = (Bitvec*)sqlite3TextToPtr(argv[1]);
  if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR;
  sqlite3BitvecClear(p,N);
  return TCL_OK;
}  
static int testBitvecDestroy(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  Bitvec *p;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR\"", 
           (void*)0);
  }
  p = (Bitvec*)sqlite3TextToPtr(argv[1]);
  sqlite3BitvecDestroy(p);
  return TCL_OK;
}  
       

/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest2_Init(Tcl_Interp *interp){
  extern int sqlite3_io_error_persist;
  extern int sqlite3_io_error_pending;
  extern int sqlite3_io_error_hit;
................................................................................
    { "page_read",               (Tcl_CmdProc*)page_read           },
    { "page_write",              (Tcl_CmdProc*)page_write          },
    { "page_number",             (Tcl_CmdProc*)page_number         },
    { "pager_truncate",          (Tcl_CmdProc*)pager_truncate      },
#ifndef SQLITE_OMIT_DISKIO
    { "fake_big_file",           (Tcl_CmdProc*)fake_big_file       },
#endif
    { "sqlite3BitvecCreate",     (Tcl_CmdProc*)testBitvecCreate    },
    { "sqlite3BitvecTest",       (Tcl_CmdProc*)testBitvecTest      },
    { "sqlite3BitvecSet",        (Tcl_CmdProc*)testBitvecSet       },
    { "sqlite3BitvecClear",      (Tcl_CmdProc*)testBitvecClear     },
    { "sqlite3BitvecDestroy",    (Tcl_CmdProc*)testBitvecDestroy   },
  };
  int i;
  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }
  Tcl_LinkVar(interp, "sqlite_io_error_pending",
     (char*)&sqlite3_io_error_pending, TCL_LINK_INT);

Added test/bitvec.test.































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# 2008 February 18
#
# 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.
#
#***********************************************************************
#
# Unit testing of the Bitvec object.
#
# $Id: bitvec.test,v 1.1 2008/02/18 14:47:34 drh Exp $
#

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

#ifcapable !subquery {
#  finish_test
#  return
#}

do_test bitvec-1.1 {
  set PTR [sqlite3BitvecCreate 4000]
  for {set i 1} {$i<=4000} {incr i} {
    if {$i%1000==999} continue
    sqlite3BitvecSet $PTR $i
  }
  set r {}
  for {set i 1} {$i<=4000} {incr i} {
    if {![sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {999 1999 2999 3999}
do_test bitvec-1.2 {
  set PTR [sqlite3BitvecCreate 4001]
  for {set i 1} {$i<=4001} {incr i} {
    if {$i%1000==999} continue
    sqlite3BitvecSet $PTR $i
  }
  set r {}
  for {set i 1} {$i<=4001} {incr i} {
    if {![sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {999 1999 2999 3999}
do_test bitvec-1.3 {
  set PTR [sqlite3BitvecCreate 40000]
  for {set i 1} {$i<=40000} {incr i} {
    if {$i%10000==9999} continue
    sqlite3BitvecSet $PTR $i
  }
  set r {}
  for {set i 1} {$i<=40000} {incr i} {
    if {![sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {9999 19999 29999 39999}
do_test bitvec-1.4 {
  set PTR [sqlite3BitvecCreate 2000000000]
  for {set i 1000000} {$i<=1001000} {incr i} {
    if {$i%1000==789} continue
    sqlite3BitvecSet $PTR $i
  }
  set r {}
  for {set i 1000000} {$i<=1001000} {incr i} {
    if {![sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {1000789}

do_test bitvec-2.1 {
  set PTR [sqlite3BitvecCreate 4000]
  for {set i 1} {$i<=4000} {incr i 2} {
    sqlite3BitvecSet $PTR $i
  }
  for {set i 1} {$i<=4000} {incr i} {
    sqlite3BitvecClear $PTR $i
  }
  set r {}
  for {set i 1} {$i<=4000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {}
do_test bitvec-2.2 {
  set PTR [sqlite3BitvecCreate 4001]
  for {set i 1} {$i<=101} {incr i 2} {
    sqlite3BitvecSet $PTR $i
  }
  for {set i 1} {$i<=99} {incr i} {
    sqlite3BitvecClear $PTR $i
  }
  set r {}
  for {set i 1} {$i<=4000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {101}
do_test bitvec-2.3 {
  set PTR [sqlite3BitvecCreate 4001]
  for {set i 1} {$i<=101} {incr i} {
    sqlite3BitvecSet $PTR $i
  }
  for {set i 1} {$i<=99} {incr i} {
    sqlite3BitvecClear $PTR $i
  }
  set r {}
  for {set i 1} {$i<=4000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {100 101}
do_test bitvec-2.4 {
  set PTR [sqlite3BitvecCreate 5000]
  for {set i 1} {$i<=5000} {incr i} {
    sqlite3BitvecSet $PTR $i
    if {$i%1000!=456} {sqlite3BitvecClear $PTR $i}
  }
  set r {}
  for {set i 1} {$i<=5000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {456 1456 2456 3456 4456}

do_test bitvec-3.1 {
  set PTR [sqlite3BitvecCreate 2000000000]
  for {set i 2000000} {$i<=3000000} {incr i 100000} {
    for {set j $i} {$j<=$i+50} {incr j} {
      sqlite3BitvecSet $PTR $i
    }
    for {set j $i} {$j<=$i+50} {incr j} {
      sqlite3BitvecClear $PTR $i
    }
  }
  set r {}
  for {set i 2000000} {$i<=3000000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {}
do_test bitvec-3.2 {
  set PTR [sqlite3BitvecCreate 200000]
  for {set i 1000} {$i<=190000} {incr i 10000} {
    for {set j $i} {$j<=$i+50} {incr j} {
      sqlite3BitvecSet $PTR $i
    }
    for {set j $i} {$j<=$i+50} {incr j} {
      sqlite3BitvecClear $PTR $i
    }
  }
  set r {}
  for {set i 1} {$i<=200000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {}
do_test bitvec-3.3 {
  set PTR [sqlite3BitvecCreate 200000]
  for {set i 1000} {$i<=190000} {incr i 10000} {
    for {set j $i} {$j<=$i+500} {incr j} {
      sqlite3BitvecSet $PTR $i
    }
    for {set j $i} {$j<=$i+500} {incr j} {
      sqlite3BitvecClear $PTR $i
    }
  }
  set r {}
  for {set i 1} {$i<=200000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {}
do_test bitvec-3.4 {
  set PTR [sqlite3BitvecCreate 2000]
  for {set i 10} {$i<=1900} {incr i 100} {
    for {set j $i} {$j<=$i+50} {incr j} {
      sqlite3BitvecSet $PTR $i
    }
    for {set j $i} {$j<=$i+50} {incr j} {
      sqlite3BitvecClear $PTR $i
    }
  }
  set r {}
  for {set i 1} {$i<=2000} {incr i} {
    if {[sqlite3BitvecTest $PTR $i]} {lappend r $i}
  }
  sqlite3BitvecDestroy $PTR
  set r
} {}


finish_test

Changes to tool/mksqlite3c.tcl.

221
222
223
224
225
226
227

228
229
230
231
232
233
234
   hash.c
   opcodes.c

   os_os2.c
   os_unix.c
   os_win.c


   pager.c

   btmutex.c   
   btree.c

   vdbefifo.c
   vdbemem.c







>







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
   hash.c
   opcodes.c

   os_os2.c
   os_unix.c
   os_win.c

   bitvec.c
   pager.c

   btmutex.c   
   btree.c

   vdbefifo.c
   vdbemem.c