gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/avfs.test (about)

     1  # 2021-03-06
     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  # 
    12  # This file implements tests for the appendvfs extension.
    13  #
    14  # Tests performed:
    15  # avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file.
    16  # avfs-1.1. Test that the DB can be read with correct content upon reopen.
    17  # avfs-1.2. Test that an appendvfs DB can be added to a simple text file.
    18  # avfs-1.3. Test that the DB can be read with correct content upon reopen.
    19  # avfs-1.4. Test that appended DB is aligned to default page boundary.
    20  # avfs-2.1. Test that the simple text file retains its initial text.
    21  # avfs-3.1. Test that the appendvfs can grow and shrink, remaining intact.
    22  # avfs-3.2. Test that appendvfs is intact after grow/shrink/close/reopen.
    23  # avfs-3.3. Test that appendvfs can grow by many pages and be written.
    24  # avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
    25  # avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
    26  # avfs-4.1. Test shell's ability to append to a non-appendvfs file.
    27  # avfs-4.2. Test shell's ability to append to empty or nonexistent file.
    28  # avfs-4.3. Test shell's ability to reopen and alter an appendvfs file.
    29  # avfs-5.1. Test appendvfs refusal to open too-tiny DB appended onto ZLF.
    30  # avfs-5.2. Test appendvfs refusal to open too-tiny DB appended on other.
    31  # ...
    32  # (more to come)
    33  
    34  set testdir [file dirname $argv0]
    35  source $testdir/tester.tcl
    36  set ::testprefix avfs
    37  
    38  # Do not attempt this test if SQLITE_OMIT_VIRTUALTABLE is defined. 
    39  #
    40  ifcapable !vtab {
    41    finish_test
    42    return
    43  }
    44  
    45  set CLI [test_find_cli]
    46  db close
    47  # forcedelete test.db
    48  
    49  load_static_extension db appendvfs
    50  
    51  set ::fa avfs.adb
    52  set ::fza avfs.sdb
    53  forcedelete $::fa $::fza
    54  set ::result {}
    55  
    56  proc shellDoesAr {} {
    57    set shdo "sh_app1.sql"
    58    forcedelete $shdo
    59    set fd [open $shdo w]
    60    puts $fd ".help\n.q"
    61    close $fd
    62    set res [catchcmd "-batch -cmd \".read $shdo\""]
    63    return [regexp {^.archive} [lindex $res 1]]
    64  }
    65  
    66  set ::vf "&vfs=apndvfs"
    67  
    68  # Return file offset of appendvfs portion of a file, or {} if none such.
    69  proc fosAvfs {fname} {
    70    if {[file size $fname] < 25} {
    71      return {}
    72    }
    73    if {[catch {set fd [open $fname rb]}]} {
    74      return {}
    75    }
    76    seek $fd -25 end
    77    set am [read $fd 17]
    78    set ao [read $fd 8]
    79    close $fd
    80    if {$am ne "Start-Of-SQLite3-"} {
    81      return {}
    82    }
    83    binary scan $ao "W" rvo
    84    return $rvo
    85  }
    86  
    87  do_test 1.0 {
    88    set results {}
    89    set out [open $::fza wb]
    90    close $out
    91    sqlite3 adb "file:$::fza?mode=rwc$::vf" -uri 1
    92    adb eval {
    93      PRAGMA page_size=1024;
    94      PRAGMA cache_size=10;
    95      CREATE TABLE t1(a TEXT);
    96      INSERT INTO t1 VALUES ('dog'),('cat');
    97      SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
    98    } { lappend results $pets }
    99    adb close
   100    lappend results [fosAvfs $fza]
   101    set ::result [join $results " | "]
   102  } {cat,dog | 0}
   103  
   104  do_test 1.1 {
   105    set results {}
   106    sqlite3 adb "file:$::fza?mode=rw$::vf" -uri 1
   107    adb eval {
   108      SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
   109    } { lappend results $pets }
   110    adb close
   111    set ::result [join $results " | "]
   112  } {dog,cat}
   113  
   114  do_test 1.2 {
   115    set results {}
   116    set out [open $::fa wb]
   117    set ::tlo { "Just some text," "and more text," "ending at 3 lines." }
   118    puts $out [join $::tlo "\n"]
   119    close $out
   120    set adbSz [file size $::fa]
   121    sqlite3 adb "file:$::fa?mode=rwc$::vf" -uri 1
   122    adb eval {
   123      PRAGMA auto_vacuum = 0;
   124      PRAGMA page_size=512;
   125      PRAGMA cache_size=0;
   126      CREATE TABLE t1(a TEXT);
   127      INSERT INTO t1 VALUES ('dog'),('cat'),('pig');
   128      SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
   129    } { lappend results $pets }
   130    adb close
   131    set adaSz [file size $::fa]
   132    lappend results "Bytes before/after $adbSz/$adaSz"
   133    set ::result [join $results " | "]
   134  } {cat,dog,pig | Bytes before/after 50/5145}
   135  
   136  do_test 1.3 {
   137    set results {}
   138    sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
   139    adb eval {
   140      SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
   141    } { lappend results $pets }
   142    adb close
   143    set ::result [join $results " | "]
   144  } {pig,dog,cat}
   145  
   146  do_test 1.4 {
   147    set ::result [fosAvfs $fa]
   148  } {4096}
   149  
   150  do_test 2.1 {
   151    set in [open $::fa r]
   152    set tli {}
   153    for {set i [llength $::tlo]} {$i > 0} {incr i -1} {
   154      lappend tli [gets $in]
   155    }
   156    close $in
   157    if { [join $tli ":"] ne [join $::tlo ":"] } {
   158      set ::result "Appendee changed."
   159    } else {
   160      set ::result "Appendee intact."
   161    }
   162  } {Appendee intact.}
   163  
   164  # Set of repeatable random integers for a couple tests.
   165  set ::nrint 50000
   166  proc rint {v} {
   167    return [::tcl::mathfunc::int [expr $v * 100000]]
   168  }
   169  array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]]
   170  for {set i 1} {$i < $::nrint} {incr i} {
   171    set ::randints($i) [rint [::tcl::mathfunc::rand]]
   172  }
   173  
   174  do_test 3.1 {
   175    set results {}
   176    sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
   177    adb eval {
   178      DROP TABLE t1;
   179      PRAGMA cache_size=10;
   180      CREATE TABLE ri (i INTEGER);
   181      BEGIN;
   182    }
   183    for {set i 0} {$i < $::nrint} {incr i} {
   184      set r $::randints($i)
   185      set s $::randints([incr i])
   186      set t $::randints([incr i])
   187      set u $::randints([incr i])
   188      set v $::randints([incr i])
   189      adb eval {
   190        INSERT INTO ri VALUES ($r),($s),($t),($u),($v)
   191      }
   192    }
   193    adb eval {
   194      COMMIT;
   195      SELECT integrity_check as ic FROM pragma_integrity_check();
   196    } { lappend results $ic }
   197    set adbSz [file size $::fa]
   198    set qr {}
   199    adb eval {
   200      SELECT count(*) as ic FROM ri;
   201      DELETE FROM ri WHERE (i % 50) <> 25;
   202      SELECT integrity_check as ic FROM pragma_integrity_check();
   203      VACUUM;
   204      SELECT integrity_check as ic FROM pragma_integrity_check();
   205      SELECT count(*) as ic FROM ri;
   206    } { lappend qr $ic }
   207    adb close
   208    set adaSz [file size $::fa]
   209    set adba [expr ($adbSz + 0.1)/$adaSz]
   210    # lappend results $adba
   211    set results [concat $results [lrange $qr 0 2]]
   212    lappend results [expr {$adba > 10.0}]
   213    set ::result [join $results " | "]
   214  } "ok | $::nrint | ok | ok | 1"
   215  
   216  do_test 3.2 {
   217    set results {}
   218    sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
   219    adb eval {
   220      SELECT integrity_check as ic FROM pragma_integrity_check();
   221    } { lappend results $ic }
   222    adb close
   223    set ::result [join $results " | "]
   224  } {ok}
   225  
   226  # avfs-3.3. Test that appendvfs can grow by many pages and be written.
   227  do_test 3.3 {
   228    set results {}
   229    sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
   230    set npages 300
   231    adb eval { BEGIN }
   232    while {$npages > 0} {
   233      adb eval { INSERT INTO ri VALUES (randomblob(1500)) }
   234      incr npages -1
   235    }
   236    adb eval { COMMIT }
   237    adb eval {
   238      SELECT integrity_check as ic FROM pragma_integrity_check();
   239    } { lappend results $ic }
   240    adb close
   241    set adaSzr [expr [file size $::fa] / 300.0 / 1500 ]
   242    set okSzr [expr $adaSzr > 1.0 && $adaSzr < 1.3 ]
   243    lappend results $okSzr
   244    set ::result [join $results " | "]
   245  } {ok | 1}
   246  
   247  # avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
   248  do_test 3.4 {
   249    set results {}
   250    sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
   251    adb eval {
   252      SELECT integrity_check as ic FROM pragma_integrity_check();
   253    } { lappend results $ic }
   254    adb close
   255    set ::result $ic
   256  } {ok}
   257  
   258  # avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
   259  do_test 3.5 {
   260    set results {}
   261    set adbsz [file size $::fa]
   262    sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
   263    adb eval {
   264      DELETE FROM ri WHERE rowid % 8 <> 0;
   265      SELECT integrity_check as ic FROM pragma_integrity_check();
   266      VACUUM;
   267      SELECT integrity_check as ic FROM pragma_integrity_check();
   268    } { lappend results $ic }
   269    adb close
   270    set adasz [file size $::fa]
   271    lappend results [expr {$adbsz/$adasz > 5}]
   272    sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
   273    adb eval {
   274      SELECT integrity_check as ic FROM pragma_integrity_check();
   275    } { lappend results $ic }
   276    adb close
   277    set ::result [join $results " | "]
   278  } {ok | ok | 1 | ok}
   279  
   280  set ::cliDoesAr [shellDoesAr]
   281  
   282  do_test 4.1 {
   283    set shdo "sh_app1.sql"
   284    set shod "sh_app1.adb"
   285    forcedelete $shdo $shod
   286    set ofd [open $shdo w]
   287    if {$::cliDoesAr} {
   288      puts $ofd ".ar -c"
   289    } else {
   290      puts $ofd "pragma page_size=512;"
   291      puts $ofd "create table sqlar (a);"
   292    }
   293    puts $ofd ".tables"
   294    puts $ofd ".q"
   295    close $ofd
   296    set ofd [open $shod wb]
   297    puts $ofd "Some text."
   298    close $ofd
   299    set res [catchcmd "-append -batch -init $shdo $shod" ""]
   300    lappend res [fosAvfs $shod]
   301    forcedelete $shdo $shod
   302    set ::result [join $res " | "]
   303  } {0 | sqlar | 4096}
   304  
   305  do_test 4.2 {
   306    set shdo "sh_app1.sql"
   307    set shod "sh_app1.adb"
   308    forcedelete $shdo $shod
   309    set ofd [open $shdo w]
   310    if {$::cliDoesAr} {
   311      puts $ofd ".ar -c"
   312    } else {
   313      puts $ofd "pragma page_size=512;"
   314      puts $ofd "create table sqlar (a);"
   315    }
   316    puts $ofd ".tables"
   317    puts $ofd ".q"
   318    close $ofd
   319    set ofd [open $shod wb]
   320    close $ofd
   321    set res [catchcmd "-append -batch -init $shdo $shod" ""]
   322    lappend res [fosAvfs $shod]
   323    forcedelete $shdo ; # Leave $shod for next test.
   324    set ::result [join $res " | "]
   325  } {0 | sqlar | 0}
   326  
   327  do_test 4.3 {
   328    set shdo "sh_app1.sql"
   329    set shod "sh_app1.adb" ; # Same as test 4.2, reusing ADB.
   330    forcedelete $shdo
   331    set ofd [open $shdo w]
   332    if {$::cliDoesAr} {
   333      puts $ofd ".ar -u $shdo"
   334      puts $ofd "select count(*) from sqlar where name = '$shdo';"
   335    } else {
   336      puts $ofd "insert into sqlar values (1);"
   337      puts $ofd "select count(*) from sqlar;"
   338    }
   339    puts $ofd ".q"
   340    close $ofd
   341    set res [catchcmd "-append -batch -init $shdo $shod" ""]
   342    sqlite3 adb "file:$shod?mode=rw$::vf" -uri 1
   343    adb eval {
   344      SELECT count(*) as n FROM sqlar
   345    } { lappend res $n }
   346    adb close
   347    forcedelete $shdo $shod;
   348    set ::result [join $res " | "]
   349  } {0 | 1 | 1}
   350  
   351  do_test 5.1 {
   352    set fake "faketiny.sdb"
   353    forcedelete $fake
   354    set ofd [open $fake wb]
   355    puts -nonewline $ofd "SQLite format 3"
   356    puts -nonewline $ofd [binary format "c" 0]
   357    puts -nonewline $ofd "Start-Of-SQLite3-"
   358    puts -nonewline $ofd [binary format "W" 0]
   359    close $ofd
   360    if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
   361      set res "Open failed."
   362    } else {
   363      adb close
   364      set res "Opened when should not."
   365    }
   366    forcedelete $fake
   367    set ::result $res
   368  } {Open failed.}
   369  
   370  do_test 5.2 {
   371    set fake "faketiny.sdb"
   372    forcedelete $fake
   373    set ofd [open $fake wb]
   374    set fakeAppendee "Dog ate my homework.\n"
   375    puts -nonewline $ofd $fakeAppendee
   376    puts -nonewline $ofd "SQLite format 3"
   377    puts -nonewline $ofd [binary format "c" 0]
   378    puts -nonewline $ofd "Start-Of-SQLite3-"
   379    puts -nonewline $ofd [binary format "W" [string length $fakeAppendee]]
   380    close $ofd
   381    if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
   382      set res "Open failed."
   383    } else {
   384      adb close
   385      set res "Opened when should not."
   386    }
   387    forcedelete $fake
   388    set ::result $res
   389  } {Open failed.}
   390  
   391  forcedelete $::fa $::fza
   392  
   393  unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::nrint ::cliDoesAr
   394  
   395  finish_test