/ Check-in [b13e497a]
Login

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

Overview
Comment:Change incremental vacuum to be triggered by a pragma rather than a command. We have a lot to learn about this yet and we do not want to paint ourselves into a corner by commiting to specific syntax too early. (CVS 3921)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b13e497a326697ab42b429993a1eee7df3c0c3eb
User & Date: drh 2007-05-04 18:30:41
Context
2007-05-04
18:36
Test interaction of incremental io and other database writes. (CVS 3922) check-in: 4516416b user: danielk1977 tags: trunk
18:30
Change incremental vacuum to be triggered by a pragma rather than a command. We have a lot to learn about this yet and we do not want to paint ourselves into a corner by commiting to specific syntax too early. (CVS 3921) check-in: b13e497a user: drh tags: trunk
17:07
Tighter compression of the keyword hash table. (CVS 3920) check-in: 68121676 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
....
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.424 2007/05/04 16:14:38 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................

  if( pParse->nErr ){
    sqliteFree(pKey);
    pKey = 0;
  }
  return pKey;
}

#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** This is called to compile a statement of the form "INCREMENTAL VACUUM".
*/
void sqlite3IncrVacuum(Parse *pParse, Token *pLimit){
  Vdbe *v = sqlite3GetVdbe(pParse);
  int iLimit;
  if( pLimit==0 || !sqlite3GetInt32((char*)pLimit->z, &iLimit) ){
    iLimit = 0x7fffffff;
  }
  if( v ){
    int addr;
    sqlite3BeginWriteOperation(pParse, 0, 0);
    sqlite3VdbeAddOp(v, OP_MemInt, iLimit, 0);
    addr = sqlite3VdbeAddOp(v, OP_IncrVacuum, 0, 0);
    sqlite3VdbeAddOp(v, OP_Callback, 0, 0);
    sqlite3VdbeAddOp(v, OP_MemIncr, -1, 0);
    sqlite3VdbeAddOp(v, OP_IfMemPos, 0, addr);
    sqlite3VdbeJumpHere(v, addr);
  }
}
#endif /* #ifndef SQLITE_OMIT_AUTOVACUUM */







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
....
3347
3348
3349
3350
3351
3352
3353























**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.425 2007/05/04 18:30:41 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................

  if( pParse->nErr ){
    sqliteFree(pKey);
    pKey = 0;
  }
  return pKey;
}























Changes to src/parse.y.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
...
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.221 2007/05/04 16:14:38 drh Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
// fallback to ID if they will not parse as their original value.
// This obviates the need for the "id" nonterminal.
//
%fallback ID
  ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
  DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
  INCREMENTAL IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN
  QUERY KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
  TEMP TRIGGER VACUUM VIEW VIRTUAL
%ifdef SQLITE_OMIT_COMPOUND_SELECT
  EXCEPT INTERSECT UNION
%endif SQLITE_OMIT_COMPOUND_SELECT
  REINDEX RENAME CTIME_KW IF
  .
................................................................................
%ifndef SQLITE_OMIT_VACUUM
%ifndef SQLITE_OMIT_ATTACH
cmd ::= VACUUM.                {sqlite3Vacuum(pParse);}
cmd ::= VACUUM nm.             {sqlite3Vacuum(pParse);}
%endif  SQLITE_OMIT_ATTACH
%endif  SQLITE_OMIT_VACUUM

%ifndef  SQLITE_OMIT_AUTOVACUUM
cmd ::= INCREMENTAL VACUUM.              {sqlite3IncrVacuum(pParse, 0);}
cmd ::= INCREMENTAL VACUUM INTEGER(X).   {sqlite3IncrVacuum(pParse, &X);}
%endif

///////////////////////////// The PRAGMA command /////////////////////////////
//
%ifndef SQLITE_OMIT_PRAGMA
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y).  {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y).  {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
  sqlite3Pragma(pParse,&X,&Z,&Y,1);







|







 







|







 







<
<
<
<
<







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
...
899
900
901
902
903
904
905





906
907
908
909
910
911
912
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.222 2007/05/04 18:30:41 drh Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
// fallback to ID if they will not parse as their original value.
// This obviates the need for the "id" nonterminal.
//
%fallback ID
  ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
  DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
  IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN
  QUERY KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
  TEMP TRIGGER VACUUM VIEW VIRTUAL
%ifdef SQLITE_OMIT_COMPOUND_SELECT
  EXCEPT INTERSECT UNION
%endif SQLITE_OMIT_COMPOUND_SELECT
  REINDEX RENAME CTIME_KW IF
  .
................................................................................
%ifndef SQLITE_OMIT_VACUUM
%ifndef SQLITE_OMIT_ATTACH
cmd ::= VACUUM.                {sqlite3Vacuum(pParse);}
cmd ::= VACUUM nm.             {sqlite3Vacuum(pParse);}
%endif  SQLITE_OMIT_ATTACH
%endif  SQLITE_OMIT_VACUUM






///////////////////////////// The PRAGMA command /////////////////////////////
//
%ifndef SQLITE_OMIT_PRAGMA
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y).  {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y).  {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
  sqlite3Pragma(pParse,&X,&Z,&Y,1);

Changes to src/pragma.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
410
411
412
413
414
415
416





















417
418
419
420
421
422
423
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.133 2007/04/26 14:42:36 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/* Ignore this whole file if pragmas are disabled
*/
................................................................................
      if( eAuto>=0 ){
        sqlite3BtreeSetAutoVacuum(pBt, eAuto);
      }
    }
  }else
#endif






















#ifndef SQLITE_OMIT_PAGER_PRAGMAS
  /*
  **  PRAGMA [database.]cache_size
  **  PRAGMA [database.]cache_size=N
  **
  ** The first form reports the current local setting for the
  ** page cache size.  The local setting can be different from







|







 







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







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
410
411
412
413
414
415
416
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
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.134 2007/05/04 18:30:41 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/* Ignore this whole file if pragmas are disabled
*/
................................................................................
      if( eAuto>=0 ){
        sqlite3BtreeSetAutoVacuum(pBt, eAuto);
      }
    }
  }else
#endif

  /*
  **  PRAGMA [database.]incremental_vacuum(N)
  **
  ** Do N steps of incremental vacuuming on a database.
  */
#ifndef SQLITE_OMIT_AUTOVACUUM
  if( sqlite3StrICmp(zLeft,"incremental_vacuum")==0 ){
    int iLimit, addr;
    if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
      iLimit = 0x7fffffff;
    }
    sqlite3BeginWriteOperation(pParse, 0, iDb);
    sqlite3VdbeAddOp(v, OP_MemInt, iLimit, 0);
    addr = sqlite3VdbeAddOp(v, OP_IncrVacuum, iDb, 0);
    sqlite3VdbeAddOp(v, OP_Callback, 0, 0);
    sqlite3VdbeAddOp(v, OP_MemIncr, -1, 0);
    sqlite3VdbeAddOp(v, OP_IfMemPos, 0, addr);
    sqlite3VdbeJumpHere(v, addr);
  }else
#endif

#ifndef SQLITE_OMIT_PAGER_PRAGMAS
  /*
  **  PRAGMA [database.]cache_size
  **  PRAGMA [database.]cache_size=N
  **
  ** The first form reports the current local setting for the
  ** page cache size.  The local setting can be different from

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
**    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.555 2007/05/04 16:14:38 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

#if defined(SQLITE_TCL) || defined(TCLSH)
# include <tcl.h>
#endif
................................................................................
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
int sqlite3Reprepare(Vdbe*);
void sqlite3IncrVacuum(Parse *pParse, Token*);

#ifdef SQLITE_SSE
#include "sseInt.h"
#endif

/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable







|







 







<







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1910
1911
1912
1913
1914
1915
1916

1917
1918
1919
1920
1921
1922
1923
**    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.556 2007/05/04 18:30:41 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

#if defined(SQLITE_TCL) || defined(TCLSH)
# include <tcl.h>
#endif
................................................................................
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
int sqlite3Reprepare(Vdbe*);


#ifdef SQLITE_SSE
#include "sseInt.h"
#endif

/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610



4611
4612
4613
4614
4615
4616
4617
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.606 2007/05/04 13:15:56 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
  rc = sqlite3RunVacuum(&p->zErrMsg, db);
  if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
  break;
}
#endif

#if !defined(SQLITE_OMIT_AUTOVACUUM)
/* Opcode: IncrVacuum * P2 *
**
** Perform a single step of the incremental vacuum procedure on
** the main database. If the vacuum has finished, jump to instruction
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: {        /* no-push */
  Btree *pBt = db->aDb[0].pBt;



  rc = sqlite3BtreeIncrVacuum(pBt);
  if( rc==SQLITE_DONE ){
    pc = pOp->p2 - 1;
    rc = SQLITE_OK;
  }
  break;
}







|







 







|


|



|
>
>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.607 2007/05/04 18:30:41 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
  rc = sqlite3RunVacuum(&p->zErrMsg, db);
  if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
  break;
}
#endif

#if !defined(SQLITE_OMIT_AUTOVACUUM)
/* Opcode: IncrVacuum P1 P2 *
**
** Perform a single step of the incremental vacuum procedure on
** the P1 database. If the vacuum has finished, jump to instruction
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: {        /* no-push */
  Btree *pBt;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  pBt = db->aDb[pOp->p1].pBt;
  rc = sqlite3BtreeIncrVacuum(pBt);
  if( rc==SQLITE_DONE ){
    pc = pOp->p2 - 1;
    rc = SQLITE_OK;
  }
  break;
}

Changes to test/incrvacuum.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
...
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
...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the incremental vacuum feature.
#
# Note: There are also some tests for incremental vacuum and IO 
# errors in incrvacuum_ioerr.test.
#
# $Id: incrvacuum.test,v 1.5 2007/05/02 17:54:56 drh Exp $

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

# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum || !pragma} {
................................................................................
    INSERT INTO tbl2 VALUES('hello world');
  }
  expr {[file size test.db] / 1024}
} {3}

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

#---------------------------------------------------------------------
# The following tests - incrvacuum-5.* - test incremental vacuum
................................................................................
do_test incrvacuum-5.1.1 {
  expr {[file size test.db] / 1024}
} {3}
do_test incrvacuum-5.1.2 {
  execsql {
    BEGIN;
    DROP TABLE tbl2;
    INCREMENTAL VACUUM;
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {1}

do_test incrvacuum-5.2.1 {
  set ::str [string repeat abcdefghij 110]
  execsql {
    BEGIN;
    CREATE TABLE tbl1(a);
    INSERT INTO tbl1 VALUES($::str);
    INCREMENTAL VACUUM;                 -- this is a no-op.
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {4}
do_test incrvacuum-5.2.2 {
  set ::str [string repeat abcdefghij 110]
  execsql {
................................................................................
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {7}
do_test incrvacuum-5.2.3 {
  execsql {
    BEGIN;
    INCREMENTAL VACUUM;                  -- Vacuum up the two pages.
    CREATE TABLE tbl2(b);                -- Use one free page as a table root.
    INSERT INTO tbl2 VALUES('a nice string');
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {6}
do_test incrvacuum-5.2.4 {
................................................................................
    SELECT * FROM tbl2;
  }
} {{a nice string}}
do_test incrvacuum-5.2.5 {
  execsql {
    DROP TABLE tbl1;
    DROP TABLE tbl2;
    INCREMENTAL VACUUM;
  }
  expr {[file size test.db] / 1024}
} {1}


# Test cases incrvacuum-5.3.* use the following list as input data.
# Two new databases are opened, one with incremental vacuum enabled,
................................................................................
} {
  INSERT INTO t1 VALUES($::str1, $::str2);
  INSERT INTO t1 VALUES($::str1||$::str2, $::str2||$::str1);
  INSERT INTO t2 SELECT b, a FROM t1;
  INSERT INTO t2 SELECT a, b FROM t1;
  INSERT INTO t1 SELECT b, a FROM t2;
  UPDATE t2 SET b = '';
  INCREMENTAL VACUUM;
} {
  UPDATE t2 SET b = (SELECT b FROM t1 WHERE t1.oid = t2.oid);
  INCREMENTAL VACUUM;
} {
  CREATE TABLE t3(a, b);
  INSERT INTO t3 SELECT * FROM t2;
  DROP TABLE t2;
  INCREMENTAL VACUUM;
} {
  CREATE INDEX t3_i ON t3(a);
  COMMIT;
} {
  BEGIN;
  DROP INDEX t3_i;
  INCREMENTAL VACUUM;
  INSERT INTO t3 VALUES('hello', 'world');
  ROLLBACK;
} {
  INSERT INTO t3 VALUES('hello', 'world');
}
]

................................................................................
  # Then drop tbl1 so that when an incr vacuum is run the pages
  # of tbl2 have to be moved to fill the gap.
  #
  do_test incrvacuum-6.${jj}.1 {
    execsql {
      DROP TABLE IF EXISTS tbl1;
      DROP TABLE IF EXISTS tbl2;
      INCREMENTAL VACUUM;
      CREATE TABLE tbl1(a, b);
      CREATE TABLE tbl2(a, b);
      BEGIN;
    }
    for {set ii 0} {$ii < 1000} {incr ii} {
      db eval {INSERT INTO tbl1 VALUES($ii, $ii || $ii)}
    }
................................................................................
  # Run a linear scan query on tbl2. After reading ($jj*100) rows, 
  # run the incremental vacuum to shrink the database.
  #
  do_test incrvacuum-6.${jj}.2 {
    set ::nRow 0
    db eval {SELECT a FROM tbl2} {} {
      if {$a == [expr $jj*100]} {
        db eval {INCREMENTAL VACUUM}
      }
      incr ::nRow
    }
    list [expr {[file size test.db] / 1024}] $nRow
  } {19 1000}
}

................................................................................
#
set ::iWrite 1
while 1 {
  do_test incrvacuum-7.${::iWrite}.1 {
    execsql {
      DROP TABLE IF EXISTS tbl1;
      DROP TABLE IF EXISTS tbl2;
      INCREMENTAL VACUUM;
      CREATE TABLE tbl1(a, b);
      CREATE TABLE tbl2(a, b);
      BEGIN;
    }
    for {set ii 0} {$ii < 1000} {incr ii} {
      db eval {INSERT INTO tbl1 VALUES($ii, $ii || $ii)}
    }
................................................................................
      DROP TABLE tbl1;
    }
    expr {[file size test.db] / 1024}
  } {36}

  do_test incrvacuum-7.${::iWrite}.2 {
    set ::nRow 0
    db eval {INCREMENTAL VACUUM} {
      incr ::nRow
      if {$::nRow == $::iWrite} {
        db eval {
          CREATE TABLE tbl1(a, b);
          INSERT INTO tbl1 VALUES('hello', 'world');
        }
      }







|







 







|







 







|







 







|











|







 







|







 







|







 







|


|




|






|







 







|







 







|







 







|







 







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
...
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
...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the incremental vacuum feature.
#
# Note: There are also some tests for incremental vacuum and IO 
# errors in incrvacuum_ioerr.test.
#
# $Id: incrvacuum.test,v 1.6 2007/05/04 18:30:41 drh Exp $

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

# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum || !pragma} {
................................................................................
    INSERT INTO tbl2 VALUES('hello world');
  }
  expr {[file size test.db] / 1024}
} {3}

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

#---------------------------------------------------------------------
# The following tests - incrvacuum-5.* - test incremental vacuum
................................................................................
do_test incrvacuum-5.1.1 {
  expr {[file size test.db] / 1024}
} {3}
do_test incrvacuum-5.1.2 {
  execsql {
    BEGIN;
    DROP TABLE tbl2;
    PRAGMA incremental_vacuum;
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {1}

do_test incrvacuum-5.2.1 {
  set ::str [string repeat abcdefghij 110]
  execsql {
    BEGIN;
    CREATE TABLE tbl1(a);
    INSERT INTO tbl1 VALUES($::str);
    PRAGMA incremental_vacuum;                 -- this is a no-op.
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {4}
do_test incrvacuum-5.2.2 {
  set ::str [string repeat abcdefghij 110]
  execsql {
................................................................................
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {7}
do_test incrvacuum-5.2.3 {
  execsql {
    BEGIN;
    PRAGMA incremental_vacuum;           -- Vacuum up the two pages.
    CREATE TABLE tbl2(b);                -- Use one free page as a table root.
    INSERT INTO tbl2 VALUES('a nice string');
    COMMIT;
  }
  expr {[file size test.db] / 1024}
} {6}
do_test incrvacuum-5.2.4 {
................................................................................
    SELECT * FROM tbl2;
  }
} {{a nice string}}
do_test incrvacuum-5.2.5 {
  execsql {
    DROP TABLE tbl1;
    DROP TABLE tbl2;
    PRAGMA incremental_vacuum;
  }
  expr {[file size test.db] / 1024}
} {1}


# Test cases incrvacuum-5.3.* use the following list as input data.
# Two new databases are opened, one with incremental vacuum enabled,
................................................................................
} {
  INSERT INTO t1 VALUES($::str1, $::str2);
  INSERT INTO t1 VALUES($::str1||$::str2, $::str2||$::str1);
  INSERT INTO t2 SELECT b, a FROM t1;
  INSERT INTO t2 SELECT a, b FROM t1;
  INSERT INTO t1 SELECT b, a FROM t2;
  UPDATE t2 SET b = '';
  PRAGMA incremental_vacuum;
} {
  UPDATE t2 SET b = (SELECT b FROM t1 WHERE t1.oid = t2.oid);
  PRAGMA incremental_vacuum;
} {
  CREATE TABLE t3(a, b);
  INSERT INTO t3 SELECT * FROM t2;
  DROP TABLE t2;
  PRAGMA incremental_vacuum;
} {
  CREATE INDEX t3_i ON t3(a);
  COMMIT;
} {
  BEGIN;
  DROP INDEX t3_i;
  PRAGMA incremental_vacuum;
  INSERT INTO t3 VALUES('hello', 'world');
  ROLLBACK;
} {
  INSERT INTO t3 VALUES('hello', 'world');
}
]

................................................................................
  # Then drop tbl1 so that when an incr vacuum is run the pages
  # of tbl2 have to be moved to fill the gap.
  #
  do_test incrvacuum-6.${jj}.1 {
    execsql {
      DROP TABLE IF EXISTS tbl1;
      DROP TABLE IF EXISTS tbl2;
      PRAGMA incremental_vacuum;
      CREATE TABLE tbl1(a, b);
      CREATE TABLE tbl2(a, b);
      BEGIN;
    }
    for {set ii 0} {$ii < 1000} {incr ii} {
      db eval {INSERT INTO tbl1 VALUES($ii, $ii || $ii)}
    }
................................................................................
  # Run a linear scan query on tbl2. After reading ($jj*100) rows, 
  # run the incremental vacuum to shrink the database.
  #
  do_test incrvacuum-6.${jj}.2 {
    set ::nRow 0
    db eval {SELECT a FROM tbl2} {} {
      if {$a == [expr $jj*100]} {
        db eval {PRAGMA incremental_vacuum}
      }
      incr ::nRow
    }
    list [expr {[file size test.db] / 1024}] $nRow
  } {19 1000}
}

................................................................................
#
set ::iWrite 1
while 1 {
  do_test incrvacuum-7.${::iWrite}.1 {
    execsql {
      DROP TABLE IF EXISTS tbl1;
      DROP TABLE IF EXISTS tbl2;
      PRAGMA incremental_vacuum;
      CREATE TABLE tbl1(a, b);
      CREATE TABLE tbl2(a, b);
      BEGIN;
    }
    for {set ii 0} {$ii < 1000} {incr ii} {
      db eval {INSERT INTO tbl1 VALUES($ii, $ii || $ii)}
    }
................................................................................
      DROP TABLE tbl1;
    }
    expr {[file size test.db] / 1024}
  } {36}

  do_test incrvacuum-7.${::iWrite}.2 {
    set ::nRow 0
    db eval {PRAGMA incremental_vacuum} {
      incr ::nRow
      if {$::nRow == $::iWrite} {
        db eval {
          CREATE TABLE tbl1(a, b);
          INSERT INTO tbl1 VALUES('hello', 'world');
        }
      }

Changes to test/incrvacuum2.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
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
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the incremental vacuum feature.
#
# $Id: incrvacuum2.test,v 1.1 2007/05/04 16:14:39 drh Exp $

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

# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum || !pragma} {
................................................................................
  file size test.db
} {32768}

# Vacuum off a single page.
#
do_test incrvacuum2-1.2 {
  execsql {
    INCREMENTAL VACUUM 1
  }
  file size test.db
} {31744}

# Vacuum off five pages
#
do_test incrvacuum2-1.3 {
  execsql {
    INCREMENTAL VACUUM 5
  }
  file size test.db
} {26624}

# Vacuum off all the rest
#
do_test incrvacuum2-1.4 {
  execsql {
    INCREMENTAL VACUUM 1000
  }
  file size test.db
} {3072}

















































finish_test







|







 







|








|








|




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

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
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
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the incremental vacuum feature.
#
# $Id: incrvacuum2.test,v 1.2 2007/05/04 18:30:41 drh Exp $

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

# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum || !pragma} {
................................................................................
  file size test.db
} {32768}

# Vacuum off a single page.
#
do_test incrvacuum2-1.2 {
  execsql {
    PRAGMA incremental_vacuum(1);
  }
  file size test.db
} {31744}

# Vacuum off five pages
#
do_test incrvacuum2-1.3 {
  execsql {
    PRAGMA incremental_vacuum(5);
  }
  file size test.db
} {26624}

# Vacuum off all the rest
#
do_test incrvacuum2-1.4 {
  execsql {
    PRAGMA incremental_vacuum(1000);
  }
  file size test.db
} {3072}

# Make sure incremental vacuum works on attached databases.
#
do_test incrvacuum2-2.1 {
  file delete -force test2.db test2.db-journal
  execsql {
    ATTACH DATABASE 'test2.db' AS aux;
    PRAGMA aux.auto_vacuum=incremental;
    CREATE TABLE aux.t2(x);
    INSERT INTO t2 VALUES(zeroblob(30000));
    INSERT INTO t1 SELECT * FROM t2;
    DELETE FROM t2;
    DELETE FROM t1;
  }
  list [file size test.db] [file size test2.db]
} {32768 32768}
do_test incrvacuum2-2.2 {
  execsql {
    PRAGMA aux.incremental_vacuum(1)
  }
  list [file size test.db] [file size test2.db]
} {32768 31744}
do_test incrvacuum2-2.3 {
  execsql {
    PRAGMA aux.incremental_vacuum(5)
  }
  list [file size test.db] [file size test2.db]
} {32768 26624}
do_test incrvacuum2-2.4 {
  execsql {
    PRAGMA main.incremental_vacuum(5)
  }
  list [file size test.db] [file size test2.db]
} {27648 26624}
do_test incrvacuum2-2.5 {
  execsql {
    PRAGMA aux.incremental_vacuum
  }
  list [file size test.db] [file size test2.db]
} {27648 3072}
do_test incrvacuum2-2.6 {
  execsql {
    PRAGMA incremental_vacuum(1)
  }
  list [file size test.db] [file size test2.db]
} {26624 3072}

 

finish_test

Changes to test/incrvacuum_ioerr.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# This file implements regression tests for SQLite library.  The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
# 
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: incrvacuum_ioerr.test,v 1.1 2007/04/28 15:47:45 danielk1977 Exp $

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

# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum} {
................................................................................
  PRAGMA auto_vacuum = 'incremental';
  CREATE TABLE abc(a);
  INSERT INTO abc VALUES(randstr(1500,1500));
} -sqlbody {
  BEGIN;
  CREATE TABLE abc2(a);
  DELETE FROM abc;
  INCREMENTAL VACUUM;
  COMMIT;
}

# do_ioerr_test incrvacuum-ioerr-3 -start 1 -cksum 1 -tclprep {
#   db eval {
#     PRAGMA auto_vacuum = 'full';
#     PRAGMA cache_size = 10;
................................................................................
  }
  for {set ii 0} {$ii < 25} {incr ii} {
    db eval {INSERT INTO abc VALUES(randstr(1500,1500))}
  }
  db eval COMMIT
} -sqlbody {
  BEGIN;
  INCREMENTAL VACUUM;
  DELETE FROM abc WHERE (oid%3)==0;
  INCREMENTAL VACUUM;
  INSERT INTO abc SELECT a || '1234567890' FROM abc WHERE oid%2;
  INCREMENTAL VACUUM;
  CREATE INDEX abc_i ON abc(a);
  DELETE FROM abc WHERE (oid%2)==0;
  INCREMENTAL VACUUM;
  DROP INDEX abc_i;
  INCREMENTAL VACUUM;
  COMMIT;
}
finish_test








|







 







|







 







|

|

|


|

|



<
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

# This file implements regression tests for SQLite library.  The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
# 
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: incrvacuum_ioerr.test,v 1.2 2007/05/04 18:30:41 drh Exp $

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

# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum} {
................................................................................
  PRAGMA auto_vacuum = 'incremental';
  CREATE TABLE abc(a);
  INSERT INTO abc VALUES(randstr(1500,1500));
} -sqlbody {
  BEGIN;
  CREATE TABLE abc2(a);
  DELETE FROM abc;
  PRAGMA incremental_vacuum;
  COMMIT;
}

# do_ioerr_test incrvacuum-ioerr-3 -start 1 -cksum 1 -tclprep {
#   db eval {
#     PRAGMA auto_vacuum = 'full';
#     PRAGMA cache_size = 10;
................................................................................
  }
  for {set ii 0} {$ii < 25} {incr ii} {
    db eval {INSERT INTO abc VALUES(randstr(1500,1500))}
  }
  db eval COMMIT
} -sqlbody {
  BEGIN;
  PRAGMA incremental_vacuum;
  DELETE FROM abc WHERE (oid%3)==0;
  PRAGMA incremental_vacuum;
  INSERT INTO abc SELECT a || '1234567890' FROM abc WHERE oid%2;
  PRAGMA incremental_vacuum;
  CREATE INDEX abc_i ON abc(a);
  DELETE FROM abc WHERE (oid%2)==0;
  PRAGMA incremental_vacuum;
  DROP INDEX abc_i;
  PRAGMA incremental_vacuum;
  COMMIT;
}
finish_test

Changes to tool/mkkeywordhash.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
** A header comment placed at the beginning of generated code.
*/
static const char zHdr[] = 
  "/***** This file contains automatically generated code ******\n"
  "**\n"
  "** The code in this file has been automatically generated by\n"
  "**\n"
  "**     $Header: /home/drh/sqlite/trans/cvs/sqlite/sqlite/tool/mkkeywordhash.c,v 1.29 2007/05/04 17:07:53 drh Exp $\n"
  "**\n"
  "** The code in this file implements a function that determines whether\n"
  "** or not a given identifier is really an SQL keyword.  The same thing\n"
  "** might be implemented more directly using a hand-written hash table.\n"
  "** But by using this automatically generated code, the size of the code\n"
  "** is substantially reduced.  This is important for embedded applications\n"
  "** on platforms with limited memory.\n"
................................................................................
  { "GLOB",             "TK_LIKE_KW",      ALWAYS                 },
  { "GROUP",            "TK_GROUP",        ALWAYS                 },
  { "HAVING",           "TK_HAVING",       ALWAYS                 },
  { "IF",               "TK_IF",           ALWAYS                 },
  { "IGNORE",           "TK_IGNORE",       CONFLICT|TRIGGER       },
  { "IMMEDIATE",        "TK_IMMEDIATE",    ALWAYS                 },
  { "IN",               "TK_IN",           ALWAYS                 },
  { "INCREMENTAL",      "TK_INCREMENTAL",  AUTOVACUUM             },
  { "INDEX",            "TK_INDEX",        ALWAYS                 },
  { "INITIALLY",        "TK_INITIALLY",    FKEY                   },
  { "INNER",            "TK_JOIN_KW",      ALWAYS                 },
  { "INSERT",           "TK_INSERT",       ALWAYS                 },
  { "INSTEAD",          "TK_INSTEAD",      TRIGGER                },
  { "INTERSECT",        "TK_INTERSECT",    COMPOUND               },
  { "INTO",             "TK_INTO",         ALWAYS                 },







|







 







<







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
195
196
197
198
199
200
201

202
203
204
205
206
207
208
** A header comment placed at the beginning of generated code.
*/
static const char zHdr[] = 
  "/***** This file contains automatically generated code ******\n"
  "**\n"
  "** The code in this file has been automatically generated by\n"
  "**\n"
  "**     $Header: /home/drh/sqlite/trans/cvs/sqlite/sqlite/tool/mkkeywordhash.c,v 1.30 2007/05/04 18:30:41 drh Exp $\n"
  "**\n"
  "** The code in this file implements a function that determines whether\n"
  "** or not a given identifier is really an SQL keyword.  The same thing\n"
  "** might be implemented more directly using a hand-written hash table.\n"
  "** But by using this automatically generated code, the size of the code\n"
  "** is substantially reduced.  This is important for embedded applications\n"
  "** on platforms with limited memory.\n"
................................................................................
  { "GLOB",             "TK_LIKE_KW",      ALWAYS                 },
  { "GROUP",            "TK_GROUP",        ALWAYS                 },
  { "HAVING",           "TK_HAVING",       ALWAYS                 },
  { "IF",               "TK_IF",           ALWAYS                 },
  { "IGNORE",           "TK_IGNORE",       CONFLICT|TRIGGER       },
  { "IMMEDIATE",        "TK_IMMEDIATE",    ALWAYS                 },
  { "IN",               "TK_IN",           ALWAYS                 },

  { "INDEX",            "TK_INDEX",        ALWAYS                 },
  { "INITIALLY",        "TK_INITIALLY",    FKEY                   },
  { "INNER",            "TK_JOIN_KW",      ALWAYS                 },
  { "INSERT",           "TK_INSERT",       ALWAYS                 },
  { "INSTEAD",          "TK_INSTEAD",      TRIGGER                },
  { "INTERSECT",        "TK_INTERSECT",    COMPOUND               },
  { "INTO",             "TK_INTO",         ALWAYS                 },