github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/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    # Note: This test is no longer meaningful due to the deferred computation
    99    # of MemPage.nFree 
   100    catchsql {PRAGMA quick_check} db2
   101  } {0 {{*** in database main ***
   102  Page 1: free space corruption}}}
   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 {PRAGMA quick_check} db2
   122  } {0 {{*** in database main ***
   123  Page 1: free space corruption}}}
   124  db2 close
   125  
   126  # Corrupt a database by having 2 indices of the same name:
   127  do_test corrupt2-2.1 {
   128  
   129    forcedelete corrupt.db
   130    forcedelete corrupt.db-journal
   131    forcecopy test.db corrupt.db
   132  
   133    sqlite3 db2 corrupt.db 
   134    sqlite3_db_config db2 DEFENSIVE 0
   135    execsql "
   136      $::presql
   137      CREATE INDEX a1 ON abc(a);
   138      CREATE INDEX a2 ON abc(b);
   139      PRAGMA writable_schema = 1;
   140      UPDATE sqlite_master 
   141        SET name = 'a3', sql = 'CREATE INDEX a3' || substr(sql, 16, 10000)
   142        WHERE type = 'index';
   143      PRAGMA writable_schema = 0;
   144    " db2
   145  
   146    db2 close
   147    sqlite3 db2 corrupt.db 
   148    catchsql "
   149      $::presql
   150      SELECT * FROM sqlite_master;
   151    " db2
   152  } {1 {malformed database schema (a3) - index a3 already exists}}
   153  
   154  db2 close
   155  
   156  do_test corrupt2-3.1 {
   157    forcedelete corrupt.db
   158    forcedelete corrupt.db-journal
   159    sqlite3 db2 corrupt.db 
   160  
   161    execsql "
   162      $::presql
   163      PRAGMA auto_vacuum = 1;
   164      PRAGMA page_size = 1024;
   165      CREATE TABLE t1(a, b, c);
   166      CREATE TABLE t2(a, b, c);
   167      INSERT INTO t2 VALUES(randomblob(100), randomblob(100), randomblob(100));
   168      INSERT INTO t2 SELECT * FROM t2;
   169      INSERT INTO t2 SELECT * FROM t2;
   170      INSERT INTO t2 SELECT * FROM t2;
   171      INSERT INTO t2 SELECT * FROM t2;
   172    " db2
   173  
   174    db2 close
   175  
   176    # On the root page of table t2 (page 4), set one of the child page-numbers
   177    # to 0. This corruption will be detected when SQLite attempts to update
   178    # the pointer-map after moving the content of page 4 to page 3 as part
   179    # of the DROP TABLE operation below.
   180    #
   181    set fd [open corrupt.db r+]
   182    fconfigure $fd -encoding binary -translation binary
   183    seek $fd [expr 1024*3 + 12]
   184    set zCelloffset [read $fd 2]
   185    binary scan $zCelloffset S iCelloffset
   186    seek $fd [expr 1024*3 + $iCelloffset]
   187    puts -nonewline $fd "\00\00\00\00" 
   188    close $fd
   189  
   190    sqlite3 db2 corrupt.db 
   191    catchsql "
   192      $::presql
   193      DROP TABLE t1;
   194    " db2
   195  } {1 {database disk image is malformed}}
   196  
   197  do_test corrupt2-4.1 {
   198    catchsql {
   199      SELECT * FROM t2;
   200    } db2
   201  } {1 {database disk image is malformed}}
   202  
   203  db2 close
   204  
   205  unset -nocomplain result
   206  do_test corrupt2-5.1 {
   207    forcedelete corrupt.db
   208    forcedelete corrupt.db-journal
   209    sqlite3 db2 corrupt.db 
   210  
   211    execsql "
   212      $::presql
   213      PRAGMA auto_vacuum = 0;
   214      PRAGMA page_size = 1024;
   215      CREATE TABLE t1(a, b, c);
   216      CREATE TABLE t2(a, b, c);
   217      INSERT INTO t2 VALUES(randomblob(100), randomblob(100), randomblob(100));
   218      INSERT INTO t2 SELECT * FROM t2;
   219      INSERT INTO t2 SELECT * FROM t2;
   220      INSERT INTO t2 SELECT * FROM t2;
   221      INSERT INTO t2 SELECT * FROM t2;
   222      INSERT INTO t1 SELECT * FROM t2;
   223    " db2
   224  
   225    db2 close
   226  
   227    # This block links a page from table t2 into the t1 table structure.
   228    #
   229    set fd [open corrupt.db r+]
   230    fconfigure $fd -encoding binary -translation binary
   231    seek $fd [expr 1024 + 12]
   232    set zCelloffset [read $fd 2]
   233    binary scan $zCelloffset S iCelloffset
   234    seek $fd [expr 1024 + $iCelloffset]
   235    set zChildPage [read $fd 4]
   236    seek $fd [expr 2*1024 + 12]
   237    set zCelloffset [read $fd 2]
   238    binary scan $zCelloffset S iCelloffset
   239    seek $fd [expr 2*1024 + $iCelloffset]
   240    puts -nonewline $fd $zChildPage
   241    close $fd
   242  
   243    sqlite3 db2 corrupt.db 
   244    db2 eval $::presql
   245    db2 eval {SELECT rowid FROM t1} {
   246      set result [db2 eval {pragma integrity_check}]
   247      break
   248    }
   249    set result
   250  } {{*** in database main ***
   251  On tree page 2 cell 0: 2nd reference to page 10
   252  Page 4 is never used}}
   253  
   254  db2 close
   255  
   256  proc corruption_test {args} {
   257    set A(-corrupt) {}
   258    set A(-sqlprep) {}
   259    set A(-tclprep) {}
   260    array set A $args
   261  
   262    catch {db close}
   263    forcedelete corrupt.db
   264    forcedelete corrupt.db-journal
   265  
   266    sqlite3 db corrupt.db 
   267    sqlite3_db_config db DEFENSIVE 0
   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: size is 3 but should be 2}}
   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  Main freelist: size is 1 but should be 0}}
   607  
   608  
   609  finish_test
   610  
   611  finish_test