modernc.org/cc@v1.0.1/v2/testdata/_sqlite/test/corrupt2.test (about)

     1  # 2004 August 30
     2  #
     3  # The author disclaims copyright to this source code.  In place of
     4  # a legal notice, here is a blessing:
     5  #
     6  #    May you do good and not evil.
     7  #    May you find forgiveness for yourself and forgive others.
     8  #    May you share freely, never taking more than you give.
     9  #
    10  #***********************************************************************
    11  # This file implements regression tests for SQLite library.
    12  #
    13  # This file implements tests to make sure SQLite does not crash or
    14  # segfault if it sees a corrupt database file.
    15  #
    16  # $Id: corrupt2.test,v 1.20 2009/04/06 17:50:03 danielk1977 Exp $
    17  
    18  set testdir [file dirname $argv0]
    19  source $testdir/tester.tcl
    20  set testprefix corrupt2
    21  
    22  # Do not use a codec for tests in this file, as the database file is
    23  # manipulated directly using tcl scripts (using the [hexio_write] command).
    24  #
    25  do_not_use_codec
    26  
    27  # These tests deal with corrupt database files
    28  #
    29  database_may_be_corrupt
    30  
    31  set presql ""
    32  catch { set presql "$::G(perm:presql);" }
    33  unset -nocomplain ::G(perm:presql)
    34  
    35  # The following tests - corrupt2-1.* - create some databases corrupted in
    36  # specific ways and ensure that SQLite detects them as corrupt.
    37  #
    38  do_test corrupt2-1.1 {
    39    execsql {
    40      PRAGMA auto_vacuum=0;
    41      PRAGMA page_size=1024;
    42      CREATE TABLE abc(a, b, c);
    43    }
    44  } {}
    45  
    46  do_test corrupt2-1.2 {
    47  
    48    # Corrupt the 16 byte magic string at the start of the file
    49    forcedelete corrupt.db
    50    forcedelete corrupt.db-journal
    51    forcecopy test.db corrupt.db
    52    set f [open corrupt.db RDWR]
    53    seek $f 8 start
    54    puts $f blah
    55    close $f
    56  
    57    sqlite3 db2 corrupt.db
    58    catchsql "
    59      $::presql
    60      SELECT * FROM sqlite_master;
    61    " db2
    62  } {1 {file is not a database}}
    63  
    64  do_test corrupt2-1.3 {
    65    db2 close
    66  
    67    # Corrupt the page-size (bytes 16 and 17 of page 1).
    68    forcedelete corrupt.db
    69    forcedelete corrupt.db-journal
    70    forcecopy test.db corrupt.db
    71    set f [open corrupt.db RDWR]
    72    fconfigure $f -encoding binary
    73    seek $f 16 start
    74    puts -nonewline $f "\x00\xFF"
    75    close $f
    76  
    77    sqlite3 db2 corrupt.db
    78    catchsql "
    79      $::presql
    80      SELECT * FROM sqlite_master;
    81    " db2
    82  } {1 {file is not a database}}
    83  
    84  do_test corrupt2-1.4 {
    85    db2 close
    86  
    87    # Corrupt the free-block list on page 1.
    88    forcedelete corrupt.db
    89    forcedelete corrupt.db-journal
    90    forcecopy test.db corrupt.db
    91    set f [open corrupt.db RDWR]
    92    fconfigure $f -encoding binary
    93    seek $f 101 start
    94    puts -nonewline $f "\xFF\xFF"
    95    close $f
    96  
    97    sqlite3 db2 corrupt.db
    98    catchsql "
    99      $::presql
   100      SELECT * FROM sqlite_master;
   101    " db2
   102  } {1 {database disk image is malformed}}
   103  
   104  do_test corrupt2-1.5 {
   105    db2 close
   106  
   107    # Corrupt the free-block list on page 1.
   108    forcedelete corrupt.db
   109    forcedelete corrupt.db-journal
   110    forcecopy test.db corrupt.db
   111    set f [open corrupt.db RDWR]
   112    fconfigure $f -encoding binary
   113    seek $f 101 start
   114    puts -nonewline $f "\x00\xC8"
   115    seek $f 200 start
   116    puts -nonewline $f "\x00\x00"
   117    puts -nonewline $f "\x10\x00"
   118    close $f
   119  
   120    sqlite3 db2 corrupt.db
   121    catchsql "
   122      $::presql
   123      SELECT * FROM sqlite_master;
   124    " db2
   125  } {1 {database disk image is malformed}}
   126  db2 close
   127  
   128  # Corrupt a database by having 2 indices of the same name:
   129  do_test corrupt2-2.1 {
   130  
   131    forcedelete corrupt.db
   132    forcedelete corrupt.db-journal
   133    forcecopy test.db corrupt.db
   134  
   135    sqlite3 db2 corrupt.db 
   136    execsql "
   137      $::presql
   138      CREATE INDEX a1 ON abc(a);
   139      CREATE INDEX a2 ON abc(b);
   140      PRAGMA writable_schema = 1;
   141      UPDATE sqlite_master 
   142        SET name = 'a3', sql = 'CREATE INDEX a3' || substr(sql, 16, 10000)
   143        WHERE type = 'index';
   144      PRAGMA writable_schema = 0;
   145    " db2
   146  
   147    db2 close
   148    sqlite3 db2 corrupt.db 
   149    catchsql "
   150      $::presql
   151      SELECT * FROM sqlite_master;
   152    " db2
   153  } {1 {malformed database schema (a3) - index a3 already exists}}
   154  
   155  db2 close
   156  
   157  do_test corrupt2-3.1 {
   158    forcedelete corrupt.db
   159    forcedelete corrupt.db-journal
   160    sqlite3 db2 corrupt.db 
   161  
   162    execsql "
   163      $::presql
   164      PRAGMA auto_vacuum = 1;
   165      PRAGMA page_size = 1024;
   166      CREATE TABLE t1(a, b, c);
   167      CREATE TABLE t2(a, b, c);
   168      INSERT INTO t2 VALUES(randomblob(100), randomblob(100), randomblob(100));
   169      INSERT INTO t2 SELECT * FROM t2;
   170      INSERT INTO t2 SELECT * FROM t2;
   171      INSERT INTO t2 SELECT * FROM t2;
   172      INSERT INTO t2 SELECT * FROM t2;
   173    " db2
   174  
   175    db2 close
   176  
   177    # On the root page of table t2 (page 4), set one of the child page-numbers
   178    # to 0. This corruption will be detected when SQLite attempts to update
   179    # the pointer-map after moving the content of page 4 to page 3 as part
   180    # of the DROP TABLE operation below.
   181    #
   182    set fd [open corrupt.db r+]
   183    fconfigure $fd -encoding binary -translation binary
   184    seek $fd [expr 1024*3 + 12]
   185    set zCelloffset [read $fd 2]
   186    binary scan $zCelloffset S iCelloffset
   187    seek $fd [expr 1024*3 + $iCelloffset]
   188    puts -nonewline $fd "\00\00\00\00" 
   189    close $fd
   190  
   191    sqlite3 db2 corrupt.db 
   192    catchsql "
   193      $::presql
   194      DROP TABLE t1;
   195    " db2
   196  } {1 {database disk image is malformed}}
   197  
   198  do_test corrupt2-4.1 {
   199    catchsql {
   200      SELECT * FROM t2;
   201    } db2
   202  } {1 {database disk image is malformed}}
   203  
   204  db2 close
   205  
   206  unset -nocomplain result
   207  do_test corrupt2-5.1 {
   208    forcedelete corrupt.db
   209    forcedelete corrupt.db-journal
   210    sqlite3 db2 corrupt.db 
   211  
   212    execsql "
   213      $::presql
   214      PRAGMA auto_vacuum = 0;
   215      PRAGMA page_size = 1024;
   216      CREATE TABLE t1(a, b, c);
   217      CREATE TABLE t2(a, b, c);
   218      INSERT INTO t2 VALUES(randomblob(100), randomblob(100), randomblob(100));
   219      INSERT INTO t2 SELECT * FROM t2;
   220      INSERT INTO t2 SELECT * FROM t2;
   221      INSERT INTO t2 SELECT * FROM t2;
   222      INSERT INTO t2 SELECT * FROM t2;
   223      INSERT INTO t1 SELECT * FROM t2;
   224    " db2
   225  
   226    db2 close
   227  
   228    # This block links a page from table t2 into the t1 table structure.
   229    #
   230    set fd [open corrupt.db r+]
   231    fconfigure $fd -encoding binary -translation binary
   232    seek $fd [expr 1024 + 12]
   233    set zCelloffset [read $fd 2]
   234    binary scan $zCelloffset S iCelloffset
   235    seek $fd [expr 1024 + $iCelloffset]
   236    set zChildPage [read $fd 4]
   237    seek $fd [expr 2*1024 + 12]
   238    set zCelloffset [read $fd 2]
   239    binary scan $zCelloffset S iCelloffset
   240    seek $fd [expr 2*1024 + $iCelloffset]
   241    puts -nonewline $fd $zChildPage
   242    close $fd
   243  
   244    sqlite3 db2 corrupt.db 
   245    db2 eval $::presql
   246    db2 eval {SELECT rowid FROM t1} {
   247      set result [db2 eval {pragma integrity_check}]
   248      break
   249    }
   250    set result
   251  } {{*** in database main ***
   252  On tree page 2 cell 0: 2nd reference to page 10
   253  Page 4 is never used}}
   254  
   255  db2 close
   256  
   257  proc corruption_test {args} {
   258    set A(-corrupt) {}
   259    set A(-sqlprep) {}
   260    set A(-tclprep) {}
   261    array set A $args
   262  
   263    catch {db close}
   264    forcedelete corrupt.db
   265    forcedelete corrupt.db-journal
   266  
   267    sqlite3 db corrupt.db 
   268    db eval $::presql
   269    eval $A(-tclprep)
   270    db eval $A(-sqlprep)
   271    db close
   272  
   273    eval $A(-corrupt)
   274  
   275    sqlite3 db corrupt.db
   276    eval $A(-test)
   277  }
   278  
   279  ifcapable autovacuum {
   280    # The tests within this block - corrupt2-6.* - aim to test corruption
   281    # detection within an incremental-vacuum. When an incremental-vacuum
   282    # step is executed, the last non-free page of the database file is 
   283    # moved into a free space in the body of the file. After doing so,
   284    # the page reference in the parent page must be updated to refer
   285    # to the new location. These tests test the outcome of corrupting
   286    # that page reference before performing the incremental vacuum.
   287    #
   288  
   289    # The last page in the database page is the second page 
   290    # in an overflow chain.
   291    #
   292    corruption_test -sqlprep {
   293      PRAGMA auto_vacuum = incremental;
   294      PRAGMA page_size = 1024;
   295      CREATE TABLE t1(a, b);
   296      INSERT INTO t1 VALUES(1, randomblob(2500));
   297      INSERT INTO t1 VALUES(2, randomblob(2500));
   298      DELETE FROM t1 WHERE a = 1;
   299    } -corrupt {
   300      hexio_write corrupt.db [expr 1024*5] 00000008
   301    } -test {
   302      do_test corrupt2-6.1 {
   303        catchsql " $::presql pragma incremental_vacuum = 1 "
   304      } {1 {database disk image is malformed}}
   305    }
   306  
   307    # The last page in the database page is a non-root b-tree page.
   308    #
   309    corruption_test -sqlprep {
   310      PRAGMA auto_vacuum = incremental;
   311      PRAGMA page_size = 1024;
   312      CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   313      INSERT INTO t1 VALUES(1, randomblob(2500));
   314      INSERT INTO t1 VALUES(2, randomblob(50));
   315      INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   316      INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   317      INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   318      INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   319      DELETE FROM t1 WHERE a = 1;
   320    } -corrupt {
   321      hexio_write corrupt.db [expr 1024*2 + 8] 00000009
   322    } -test {
   323      do_test corrupt2-6.2 {
   324        catchsql " $::presql pragma incremental_vacuum = 1 "
   325      } {1 {database disk image is malformed}}
   326    }
   327  
   328    # Set up a pointer-map entry so that the last page of the database
   329    # file appears to be a b-tree root page. This should be detected
   330    # as corruption.
   331    #
   332    corruption_test -sqlprep {
   333      PRAGMA auto_vacuum = incremental;
   334      PRAGMA page_size = 1024;
   335      CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   336      INSERT INTO t1 VALUES(1, randomblob(2500));
   337      INSERT INTO t1 VALUES(2, randomblob(2500));
   338      INSERT INTO t1 VALUES(3, randomblob(2500));
   339      DELETE FROM t1 WHERE a = 1;
   340    } -corrupt {
   341      set nPage [expr [file size corrupt.db] / 1024]
   342      hexio_write corrupt.db [expr 1024 + ($nPage-3)*5] 010000000
   343    } -test {
   344      do_test corrupt2-6.3 {
   345        catchsql " $::presql pragma incremental_vacuum = 1 "
   346      } {1 {database disk image is malformed}}
   347    }
   348  
   349    if {![nonzero_reserved_bytes]} {
   350      corruption_test -sqlprep {
   351        PRAGMA auto_vacuum = 1;
   352        PRAGMA page_size = 1024;
   353        CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   354        INSERT INTO t1 VALUES(1, randomblob(2500));
   355        DELETE FROM t1 WHERE a = 1;
   356      } -corrupt {
   357        set nAppend [expr 1024*207 - [file size corrupt.db]]
   358        set fd [open corrupt.db r+]
   359        seek $fd 0 end
   360        puts -nonewline $fd [string repeat x $nAppend]
   361        close $fd
   362        hexio_write corrupt.db 28 00000000
   363      } -test {
   364        do_test corrupt2-6.4 {
   365          catchsql " 
   366            $::presql 
   367            BEGIN EXCLUSIVE;
   368            COMMIT;
   369          "
   370        } {1 {database disk image is malformed}}
   371      }
   372    }
   373  }
   374  
   375  
   376  set sqlprep {
   377    PRAGMA auto_vacuum = 0;
   378    PRAGMA page_size = 1024;
   379    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   380    CREATE INDEX i1 ON t1(b);
   381    INSERT INTO t1 VALUES(1, randomblob(50));
   382    INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   383    INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   384    INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   385    INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   386    INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   387    INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
   388  }
   389  
   390  corruption_test -sqlprep $sqlprep -corrupt {
   391    # Set the page-flags of one of the leaf pages of the index B-Tree to
   392    # 0x0D (interpreted by SQLite as "leaf page of a table B-Tree").
   393    #
   394    set fd [open corrupt.db r+]
   395    fconfigure $fd -translation binary -encoding binary
   396    seek $fd [expr 1024*2 + 8] 
   397    set zRightChild [read $fd 4]
   398    binary scan $zRightChild I iRightChild
   399    seek $fd [expr 1024*($iRightChild-1)]
   400    puts -nonewline $fd "\x0D"
   401    close $fd
   402  } -test {
   403    do_test corrupt2-7.1 {
   404      catchsql " $::presql SELECT b FROM t1 ORDER BY b ASC "
   405    } {1 {database disk image is malformed}}
   406  }
   407  
   408  corruption_test -sqlprep $sqlprep -corrupt {
   409    # Mess up the page-header of one of the leaf pages of the index B-Tree.
   410    # The corruption is detected as part of an OP_Prev opcode.
   411    #
   412    set fd [open corrupt.db r+]
   413    fconfigure $fd -translation binary -encoding binary
   414    seek $fd [expr 1024*2 + 12] 
   415    set zCellOffset [read $fd 2]
   416    binary scan $zCellOffset S iCellOffset
   417    seek $fd [expr 1024*2 + $iCellOffset]
   418    set zChild [read $fd 4]
   419    binary scan $zChild I iChild
   420    seek $fd [expr 1024*($iChild-1)+3]
   421    puts -nonewline $fd "\xFFFF"
   422    close $fd
   423  } -test {
   424    do_test corrupt2-7.1 {
   425      catchsql " $::presql SELECT b FROM t1 ORDER BY b DESC "
   426    } {1 {database disk image is malformed}}
   427  }
   428  
   429  corruption_test -sqlprep $sqlprep -corrupt {
   430    # Set the page-flags of one of the leaf pages of the table B-Tree to
   431    # 0x0A (interpreted by SQLite as "leaf page of an index B-Tree").
   432    #
   433    set fd [open corrupt.db r+]
   434    fconfigure $fd -translation binary -encoding binary
   435    seek $fd [expr 1024*1 + 8] 
   436    set zRightChild [read $fd 4]
   437    binary scan $zRightChild I iRightChild
   438    seek $fd [expr 1024*($iRightChild-1)]
   439    puts -nonewline $fd "\x0A"
   440    close $fd
   441  } -test {
   442    do_test corrupt2-8.1 {
   443      catchsql " $::presql SELECT * FROM t1 WHERE rowid=1000 "
   444    } {1 {database disk image is malformed}}
   445  }
   446  
   447  corruption_test -sqlprep {
   448    CREATE TABLE t1(a, b, c); CREATE TABLE t8(a, b, c); CREATE TABLE tE(a, b, c);
   449    CREATE TABLE t2(a, b, c); CREATE TABLE t9(a, b, c); CREATE TABLE tF(a, b, c);
   450    CREATE TABLE t3(a, b, c); CREATE TABLE tA(a, b, c); CREATE TABLE tG(a, b, c);
   451    CREATE TABLE t4(a, b, c); CREATE TABLE tB(a, b, c); CREATE TABLE tH(a, b, c);
   452    CREATE TABLE t5(a, b, c); CREATE TABLE tC(a, b, c); CREATE TABLE tI(a, b, c);
   453    CREATE TABLE t6(a, b, c); CREATE TABLE tD(a, b, c); CREATE TABLE tJ(a, b, c);
   454    CREATE TABLE x1(a, b, c); CREATE TABLE x8(a, b, c); CREATE TABLE xE(a, b, c);
   455    CREATE TABLE x2(a, b, c); CREATE TABLE x9(a, b, c); CREATE TABLE xF(a, b, c);
   456    CREATE TABLE x3(a, b, c); CREATE TABLE xA(a, b, c); CREATE TABLE xG(a, b, c);
   457    CREATE TABLE x4(a, b, c); CREATE TABLE xB(a, b, c); CREATE TABLE xH(a, b, c);
   458    CREATE TABLE x5(a, b, c); CREATE TABLE xC(a, b, c); CREATE TABLE xI(a, b, c);
   459    CREATE TABLE x6(a, b, c); CREATE TABLE xD(a, b, c); CREATE TABLE xJ(a, b, c);
   460  } -corrupt {
   461    set fd [open corrupt.db r+]
   462    fconfigure $fd -translation binary -encoding binary
   463    seek $fd 108
   464    set zRightChild [read $fd 4]
   465    binary scan $zRightChild I iRightChild
   466    seek $fd [expr 1024*($iRightChild-1)+3]
   467    puts -nonewline $fd "\x00\x00"
   468    close $fd
   469  } -test {
   470    do_test corrupt2-9.1 {
   471      catchsql " $::presql SELECT sql FROM sqlite_master "
   472    } {1 {database disk image is malformed}}
   473  }
   474  
   475  corruption_test -sqlprep {
   476    CREATE TABLE t1(a, b, c);
   477    CREATE TABLE t2(a, b, c);
   478    PRAGMA writable_schema = 1;
   479    UPDATE sqlite_master SET rootpage = NULL WHERE name = 't2';
   480  } -test {
   481    do_test corrupt2-10.1 {
   482      catchsql " $::presql SELECT * FROM t2 "
   483    } {1 {malformed database schema (t2)}}
   484    do_test corrupt2-10.2 {
   485      sqlite3_errcode db
   486    } {SQLITE_CORRUPT}
   487  }
   488  
   489  corruption_test -sqlprep {
   490    PRAGMA auto_vacuum = incremental;
   491    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   492    CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
   493    INSERT INTO t1 VALUES(1, randstr(100,100));
   494    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   495    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   496    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   497    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   498    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   499    INSERT INTO t2 SELECT * FROM t1;
   500    DELETE FROM t1;
   501  } -corrupt {
   502    set offset [expr [file size corrupt.db] - 1024]
   503    hexio_write corrupt.db $offset FF 
   504    hexio_write corrupt.db 24   12345678
   505  } -test {
   506    do_test corrupt2-11.1 {
   507      catchsql " $::presql PRAGMA incremental_vacuum "
   508    } {1 {database disk image is malformed}}
   509  }
   510  corruption_test -sqlprep {
   511    PRAGMA auto_vacuum = incremental;
   512    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   513    CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
   514    INSERT INTO t1 VALUES(1, randstr(100,100));
   515    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   516    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   517    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   518    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   519    INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
   520    INSERT INTO t2 SELECT * FROM t1;
   521    DELETE FROM t1;
   522  } -corrupt {
   523    set pgno [expr [file size corrupt.db] / 1024]
   524    hexio_write corrupt.db [expr 1024+5*($pgno-3)] 03 
   525    hexio_write corrupt.db 24   12345678
   526  } -test {
   527    do_test corrupt2-12.1 {
   528      catchsql " $::presql PRAGMA incremental_vacuum "
   529    } {1 {database disk image is malformed}}
   530  }
   531  
   532  ifcapable autovacuum {
   533    # It is not possible for the last page in a database file to be the
   534    # pending-byte page (AKA the locking page). This test verifies that if
   535    # an attempt is made to commit a transaction to such an auto-vacuum 
   536    # database SQLITE_CORRUPT is returned.
   537    #
   538    corruption_test -tclprep {
   539      db eval { 
   540        PRAGMA auto_vacuum = full;
   541        PRAGMA page_size = 1024;
   542        CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   543        INSERT INTO t1 VALUES(NULL, randstr(50,50));
   544      }
   545      for {set ii 0} {$ii < 10} {incr ii} {
   546        db eval " $::presql INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 "
   547      }
   548    } -corrupt {
   549      do_test corrupt2-13.1 {
   550        file size corrupt.db
   551      } $::sqlite_pending_byte
   552      hexio_write corrupt.db [expr $::sqlite_pending_byte+1023] 00
   553      hexio_write corrupt.db 28 00000000
   554    } -test {
   555      do_test corrupt2-13.2 {
   556        file size corrupt.db
   557      } [expr $::sqlite_pending_byte + 1024]
   558      do_test corrupt2-13.3 {
   559        catchsql { DELETE FROM t1 WHERE rowid < 30; }
   560      } {1 {database disk image is malformed}}
   561    }
   562  }
   563  
   564  #-------------------------------------------------------------------------
   565  # Test that PRAGMA integrity_check detects cases where the freelist-count
   566  # header field is smaller than the actual number of pages on the freelist.
   567  #
   568  
   569  reset_db
   570  do_execsql_test 14.0 {
   571    PRAGMA auto_vacuum = 0;
   572    CREATE TABLE t1(x);
   573    INSERT INTO t1 VALUES(randomblob(3500));
   574    DELETE FROM t1;
   575  }
   576  
   577  do_execsql_test 14.1 {
   578    PRAGMA integrity_check;
   579    PRAGMA freelist_count;
   580  } {ok 3}
   581  
   582  # There are now 3 free pages. Modify the header-field so that it 
   583  # (incorrectly) says that just 2 are free.
   584  do_test 14.2 {
   585    db close
   586    hexio_write test.db 36 [hexio_render_int32 2]
   587    sqlite3 db test.db
   588    execsql { PRAGMA freelist_count }
   589  } {2}
   590  
   591  do_execsql_test 14.3 {
   592    PRAGMA integrity_check;
   593  } {{*** in database main ***
   594  Main freelist: free-page count in header is too small}}
   595  
   596  # Use 2 of the free pages on the free-list.
   597  #
   598  do_execsql_test 14.4 {
   599    INSERT INTO t1 VALUES(randomblob(2500));
   600    PRAGMA freelist_count;
   601  } {0}
   602  
   603  do_execsql_test 14.5 {
   604    PRAGMA integrity_check;
   605  } {{*** in database main ***
   606  Page 3 is never used}}
   607  
   608  
   609  finish_test
   610  
   611  finish_test