/ Check-in [def3a016]
Login

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

Overview
Comment:Test cases and minor code changes to increase coverage of btree.c. (CVS 6456)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: def3a016914f683818b5f013ec4efecbb8fd4c0d
User & Date: danielk1977 2009-04-06 17:50:03
Context
2009-04-07
00:35
It is OK for a unix file descriptor to be zero. It just can't be negative. Adjust an assert accordingly. Ticket #3781. (CVS 6457) check-in: 47aa7eb0 user: drh tags: trunk
2009-04-06
17:50
Test cases and minor code changes to increase coverage of btree.c. (CVS 6456) check-in: def3a016 user: danielk1977 tags: trunk
15:55
Updates and clarification to the documentation of the sqlite3_temp_directory global variable. No changes to code. (CVS 6455) check-in: aea99c57 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
2578
2579
2580
2581
2582
2583
2584
2585




2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.590 2009/04/05 12:22:09 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

................................................................................
    Pgno nFin;
    Pgno nFree;
    Pgno nPtrmap;
    Pgno iFree;
    const int pgsz = pBt->pageSize;
    Pgno nOrig = pagerPagecount(pBt);

    if( PTRMAP_ISPAGE(pBt, nOrig) ){




      return SQLITE_CORRUPT_BKPT;
    }
    if( nOrig==PENDING_BYTE_PAGE(pBt) ){
      nOrig--;
    }
    nFree = get4byte(&pBt->pPage1->aData[36]);
    nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+pgsz/5)/(pgsz/5);
    nFin = nOrig - nFree - nPtrmap;
    if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<=PENDING_BYTE_PAGE(pBt) ){
      nFin--;
    }
    while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
      nFin--;
    }

    for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){







|







 







|
>
>
>
>


<
<
|



|







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591


2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.591 2009/04/06 17:50:03 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

................................................................................
    Pgno nFin;
    Pgno nFree;
    Pgno nPtrmap;
    Pgno iFree;
    const int pgsz = pBt->pageSize;
    Pgno nOrig = pagerPagecount(pBt);

    if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
      /* It is not possible to create a database for which the final page
      ** is either a pointer-map page or the pending-byte page. If one
      ** is encountered, this indicates corruption.
      */
      return SQLITE_CORRUPT_BKPT;
    }



    nFree = get4byte(&pBt->pPage1->aData[36]);
    nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+pgsz/5)/(pgsz/5);
    nFin = nOrig - nFree - nPtrmap;
    if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
      nFin--;
    }
    while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
      nFin--;
    }

    for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){

Changes to test/autovacuum.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
656
657
658
659
660
661
662
663








664























665
#    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 SELECT statement.
#
# $Id: autovacuum.test,v 1.28 2008/09/10 10:57:28 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} {
................................................................................
} {1}
do_test autovacuum-8.2 {
  db eval {BEGIN EXCLUSIVE}
  catchsql {PRAGMA auto_vacuum} db2
} {1 {database is locked}}
catch {db2 close}
catch {db eval {COMMIT}}
    
































finish_test







|







 







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

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
#    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 SELECT statement.
#
# $Id: autovacuum.test,v 1.29 2009/04/06 17:50:03 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} {
................................................................................
} {1}
do_test autovacuum-8.2 {
  db eval {BEGIN EXCLUSIVE}
  catchsql {PRAGMA auto_vacuum} db2
} {1 {database is locked}}
catch {db2 close}
catch {db eval {COMMIT}}

do_test autovacuum-9.1 {
  execsql {
    DROP TABLE t1;
    DROP TABLE t2;
    DROP TABLE t3;
    DROP TABLE t4;
    DROP TABLE t5;
    PRAGMA page_count;
  }
} {1}
do_test autovacuum-9.2 {
  file size test.db
} 1024
do_test autovacuum-9.3 {
  execsql {
    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
    INSERT INTO t1 VALUES(NULL, randstr(50,50));
  }
  for {set ii 0} {$ii < 10} {incr ii} {
    db eval { INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 }
  }
  file size test.db
} $::sqlite_pending_byte
do_test autovacuum-9.4 {
  execsql { INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 }
} {}
do_test autovacuum-9.5 {
  execsql { DELETE FROM t1 WHERE rowid > (SELECT max(a)/2 FROM t1) }
  file size test.db
} $::sqlite_pending_byte
 

finish_test

Changes to test/corrupt2.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
229
230
231
232
233
234
235


236
237
238
239
240
241
242

243
244
245
246
247
248
249
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
...
494
495
496
497
498
499
500
501































502
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt2.test,v 1.19 2009/04/02 18:28:08 danielk1977 Exp $

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

# The following tests - corrupt2-1.* - create some databases corrupted in
# specific ways and ensure that SQLite detects them as corrupt.
#
................................................................................
On tree page 2 cell 1: Child page depth differs
Page 4 is never used}}

db2 close

proc corruption_test {args} {
  set A(-corrupt) {}


  array set A $args

  catch {db close}
  file delete -force corrupt.db
  file delete -force corrupt.db-journal

  sqlite3 db corrupt.db 

  db eval $A(-sqlprep)
  db close

  eval $A(-corrupt)

  sqlite3 db corrupt.db
  eval $A(-test)
................................................................................
  hexio_write corrupt.db $offset FF 
  hexio_write corrupt.db 24   12345678
} -test {
  do_test corrupt2-11.1 {
    catchsql { PRAGMA incremental_vacuum }
  } {1 {database disk image is malformed}}
}

corruption_test -sqlprep {
  PRAGMA auto_vacuum = incremental;
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
  INSERT INTO t1 VALUES(1, randstr(100,100));
  INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
  INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
................................................................................
  hexio_write corrupt.db [expr 1024+5*($pgno-3)] 03 
  hexio_write corrupt.db 24   12345678
} -test {
  do_test corrupt2-12.1 {
    catchsql { PRAGMA incremental_vacuum }
  } {1 {database disk image is malformed}}
}
































finish_test







|







 







>
>







>







 







<







 








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

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
475
476
477
478
479
480
481

482
483
484
485
486
487
488
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt2.test,v 1.20 2009/04/06 17:50:03 danielk1977 Exp $

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

# The following tests - corrupt2-1.* - create some databases corrupted in
# specific ways and ensure that SQLite detects them as corrupt.
#
................................................................................
On tree page 2 cell 1: Child page depth differs
Page 4 is never used}}

db2 close

proc corruption_test {args} {
  set A(-corrupt) {}
  set A(-sqlprep) {}
  set A(-tclprep) {}
  array set A $args

  catch {db close}
  file delete -force corrupt.db
  file delete -force corrupt.db-journal

  sqlite3 db corrupt.db 
  eval $A(-tclprep)
  db eval $A(-sqlprep)
  db close

  eval $A(-corrupt)

  sqlite3 db corrupt.db
  eval $A(-test)
................................................................................
  hexio_write corrupt.db $offset FF 
  hexio_write corrupt.db 24   12345678
} -test {
  do_test corrupt2-11.1 {
    catchsql { PRAGMA incremental_vacuum }
  } {1 {database disk image is malformed}}
}

corruption_test -sqlprep {
  PRAGMA auto_vacuum = incremental;
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
  INSERT INTO t1 VALUES(1, randstr(100,100));
  INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
  INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
................................................................................
  hexio_write corrupt.db [expr 1024+5*($pgno-3)] 03 
  hexio_write corrupt.db 24   12345678
} -test {
  do_test corrupt2-12.1 {
    catchsql { PRAGMA incremental_vacuum }
  } {1 {database disk image is malformed}}
}

ifcapable autovacuum {
  # It is not possible for the last page in a database file to be the
  # pending-byte page (AKA the locking page). This test verifies that if
  # an attempt is made to commit a transaction to such an auto-vacuum 
  # database SQLITE_CORRUPT is returned.
  #
  corruption_test -tclprep {
    db eval { 
      PRAGMA auto_vacuum = full;
      PRAGMA page_size = 1024;
      CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
      INSERT INTO t1 VALUES(NULL, randstr(50,50));
    }
    for {set ii 0} {$ii < 10} {incr ii} {
      db eval { INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 }
    }
  } -corrupt {
    do_test corrupt2-13.1 {
      file size corrupt.db
    } $::sqlite_pending_byte
    hexio_write corrupt.db [expr $::sqlite_pending_byte+1023] 00
  } -test {
    do_test corrupt2-13.2 {
      file size corrupt.db
    } [expr $::sqlite_pending_byte + 1024]
    do_test corrupt2-13.3 {
      catchsql { DELETE FROM t1 WHERE rowid < 30; }
    } {1 {database disk image is malformed}}
  }
}

finish_test

Changes to test/delete.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
312
313
314
315
316
317
318


319



















320
#    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 DELETE FROM statement.
#
# $Id: delete.test,v 1.23 2008/04/19 20:53:26 drh Exp $

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

# Try to delete from a non-existant table.
#
do_test delete-1.1 {
................................................................................
integrity_check delete-8.7

# Need to do the following for tcl 8.5 on mac. On that configuration, the
# -readonly flag is taken so seriously that a subsequent [file delete -force]
# (required before the next test file can be executed) will fail.
#
catch {file attributes test.db -readonly 0}






















finish_test







|







 







>
>

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

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#    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 DELETE FROM statement.
#
# $Id: delete.test,v 1.24 2009/04/06 17:50:03 danielk1977 Exp $

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

# Try to delete from a non-existant table.
#
do_test delete-1.1 {
................................................................................
integrity_check delete-8.7

# Need to do the following for tcl 8.5 on mac. On that configuration, the
# -readonly flag is taken so seriously that a subsequent [file delete -force]
# (required before the next test file can be executed) will fail.
#
catch {file attributes test.db -readonly 0}
db close
file delete -force test.db test.db-journal

do_test delete-9.1 {
  sqlite3 db test.db
  execsql {
    CREATE TABLE t5(a, b);
    CREATE TABLE t6(c, d);
    INSERT INTO t5 VALUES(1, 2);
    INSERT INTO t5 VALUES(3, 4);
    INSERT INTO t5 VALUES(5, 6);
    INSERT INTO t6 VALUES('a', 'b');
    INSERT INTO t6 VALUES('c', 'd');
    INSERT INTO t6 VALUES('e', 'f');
    CREATE INDEX i5 ON t5(a);
  }
} {}
do_test delete-9.2 {
  explain { SELECT a, c, d FROM t5, t6 ORDER BY a } 
} {}


finish_test

Changes to test/ioerr.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
422
423
424
425
426
427
428
429






























430
# 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: ioerr.test,v 1.42 2008/11/26 07:40:30 danielk1977 Exp $

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

# If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error
# on the 8th IO operation in the SQL script below doesn't report an error.
#
................................................................................
  }
} -sqlbody {
  BEGIN;
  INSERT INTO t2 VALUES(randstr(22000,22000));
  DELETE FROM t1 WHERE oid = 83;
  COMMIT;
} 































finish_test







|







 








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

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# 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: ioerr.test,v 1.43 2009/04/06 17:50:03 danielk1977 Exp $

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

# If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error
# on the 8th IO operation in the SQL script below doesn't report an error.
#
................................................................................
  }
} -sqlbody {
  BEGIN;
  INSERT INTO t2 VALUES(randstr(22000,22000));
  DELETE FROM t1 WHERE oid = 83;
  COMMIT;
} 

# This test verifies that IO errors that occur within the obscure branch
# of code executed by tkt3762.test are correctly reported.
#
ifcapable vacuum&&autovacuum&&pragma {
  do_ioerr_test ioerr-16 -erc 1 -ckrefcount 1 -sqlprep {
    PRAGMA auto_vacuum=INCREMENTAL;
    PRAGMA page_size=1024;
    BEGIN;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES(zeroblob(900));
    INSERT INTO t1 VALUES(zeroblob(900));
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    DELETE FROM t1 WHERE rowid>202;
    COMMIT;
    VACUUM;
    PRAGMA cache_size = 10;
    BEGIN;
    DELETE FROM t1 WHERE rowid IN (10,11,12) ;
  } -sqlbody {
    PRAGMA incremental_vacuum(10);
    COMMIT;
  }
}

finish_test

Changes to test/tester.tcl.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.141 2009/03/26 17:13:06 danielk1977 Exp $

#
# What for user input before continuing.  This gives an opportunity
# to connect profiling tools to the process.
#
for {set i 0} {$i<[llength $argv]} {incr i} {
  if {[regexp {^-+pause$} [lindex $argv $i] all value]} {
................................................................................
  # TEMPORARY: For 3.5.9, disable testing of extended result codes. There are
  # a couple of obscure IO errors that do not return them.
  set ::ioerropts(-erc) 0

  set ::go 1
  #reset_prng_state
  save_prng_state
  for {set n $::ioerropts(-start)} {$::go && $n<200} {incr n} {
    set ::TN $n
    incr ::ioerropts(-count) -1
    if {$::ioerropts(-count)<0} break
 
    # Skip this IO error if it was specified with the "-exclude" option.
    if {[info exists ::ioerropts(-exclude)]} {
      if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.142 2009/04/06 17:50:03 danielk1977 Exp $

#
# What for user input before continuing.  This gives an opportunity
# to connect profiling tools to the process.
#
for {set i 0} {$i<[llength $argv]} {incr i} {
  if {[regexp {^-+pause$} [lindex $argv $i] all value]} {
................................................................................
  # TEMPORARY: For 3.5.9, disable testing of extended result codes. There are
  # a couple of obscure IO errors that do not return them.
  set ::ioerropts(-erc) 0

  set ::go 1
  #reset_prng_state
  save_prng_state
  for {set n $::ioerropts(-start)} {$::go} {incr n} {
    set ::TN $n
    incr ::ioerropts(-count) -1
    if {$::ioerropts(-count)<0} break
 
    # Skip this IO error if it was specified with the "-exclude" option.
    if {[info exists ::ioerropts(-exclude)]} {
      if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue