1# 2014 June 17 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. The 12# focus of this script is testing the FTS5 module. 13# 14 15source [file join [file dirname [info script]] fts5_common.tcl] 16source $testdir/malloc_common.tcl 17set testprefix fts5fault1 18 19# If SQLITE_ENABLE_FTS3 is defined, omit this file. 20ifcapable !fts5 { 21 finish_test 22 return 23} 24 25# Simple tests: 26# 27# 1: CREATE VIRTUAL TABLE 28# 2: INSERT statement 29# 3: DELETE statement 30# 4: MATCH expressions 31# 32# 33 34faultsim_save_and_close 35do_faultsim_test 1 -faults ioerr-t* -prep { 36 faultsim_restore_and_reopen 37} -body { 38 execsql { CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3') } 39} -test { 40 faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} 41} 42 43reset_db 44do_execsql_test 2.0 { 45 CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3'); 46} 47faultsim_save_and_close 48do_faultsim_test 2 -prep { 49 faultsim_restore_and_reopen 50} -body { 51 execsql { 52 INSERT INTO t1 VALUES('a b c', 'a bc def ghij klmno'); 53 } 54} -test { 55 faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} 56} 57 58reset_db 59do_execsql_test 3.0 { 60 CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3'); 61 INSERT INTO t1 VALUES('a b c', 'a bc def ghij klmno'); 62} 63faultsim_save_and_close 64do_faultsim_test 3 -prep { 65 faultsim_restore_and_reopen 66} -body { 67 execsql { DELETE FROM t1 } 68} -test { 69 faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} 70} 71 72reset_db 73do_execsql_test 4.0 { 74 CREATE VIRTUAL TABLE t2 USING fts5(a, b); 75 INSERT INTO t2 VALUES('m f a jj th q gi ar', 'hj n h h sg j i m'); 76 INSERT INTO t2 VALUES('nr s t g od j kf h', 'sb h aq rg op rb n nl'); 77 INSERT INTO t2 VALUES('do h h pb p p q fr', 'c rj qs or cr a l i'); 78 INSERT INTO t2 VALUES('lk gp t i lq mq qm p', 'h mr g f op ld aj h'); 79 INSERT INTO t2 VALUES('ct d sq kc qi k f j', 'sn gh c of g s qt q'); 80 INSERT INTO t2 VALUES('d ea d d om mp s ab', 'dm hg l df cm ft pa c'); 81 INSERT INTO t2 VALUES('tc dk c jn n t sr ge', 'a a kn bc n i af h'); 82 INSERT INTO t2 VALUES('ie ii d i b sa qo rf', 'a h m aq i b m fn'); 83 INSERT INTO t2 VALUES('gs r fo a er m h li', 'tm c p gl eb ml q r'); 84 INSERT INTO t2 VALUES('k fe fd rd a gi ho kk', 'ng m c r d ml rm r'); 85} 86faultsim_save_and_close 87 88foreach {tn expr res} { 89 1 { dk } 7 90 2 { m f } 1 91 3 { f* } {1 3 4 5 6 8 9 10} 92 4 { m OR f } {1 4 5 8 9 10} 93 5 { sn + gh } {5} 94 6 { "sn gh" } {5} 95 7 { NEAR(r a, 5) } {9} 96 8 { m* f* } {1 4 6 8 9 10} 97 9 { m* + f* } {1 8} 98 10 { c NOT p } {5 6 7 10} 99} { 100 do_faultsim_test 4.$tn -prep { 101 faultsim_restore_and_reopen 102 } -body " 103 execsql { SELECT rowid FROM t2 WHERE t2 MATCH '$expr' } 104 " -test " 105 faultsim_test_result {[list 0 $res]} {1 {vtable constructor failed: t2}} 106 " 107} 108 109 110#------------------------------------------------------------------------- 111# The following tests use a larger database populated with random data. 112# 113# The database page size is set to 512 bytes and the FTS5 page size left 114# at the default 1000 bytes. This means that reading a node may require 115# pulling an overflow page from disk, which is an extra opportunity for 116# an error to occur. 117# 118reset_db 119do_execsql_test 5.0.1 { 120 PRAGMA main.page_size = 512; 121 CREATE VIRTUAL TABLE x1 USING fts5(a, b); 122 PRAGMA main.page_size; 123} {512} 124 125proc rnddoc {n} { 126 set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] 127 set doc [list] 128 for {set i 0} {$i < $n} {incr i} { 129 lappend doc [string map $map [format %.3d [expr int(rand()*1000)]]] 130 } 131 set doc 132} 133db func rnddoc rnddoc 134 135do_execsql_test 5.0.2 { 136 WITH r(a, b) AS ( 137 SELECT rnddoc(6), rnddoc(6) UNION ALL 138 SELECT rnddoc(6), rnddoc(6) FROM r 139 ) 140 INSERT INTO x1 SELECT * FROM r LIMIT 10000; 141} 142 143set res [db one { 144 SELECT count(*) FROM x1 WHERE x1.a LIKE '%abc%' OR x1.b LIKE '%abc%'} 145] 146 147do_faultsim_test 5.1 -faults oom* -body { 148 execsql { SELECT count(*) FROM x1 WHERE x1 MATCH 'abc' } 149} -test { 150 faultsim_test_result [list 0 $::res] 151} 152do_faultsim_test 5.2 -faults oom* -body { 153 execsql { SELECT count(*) FROM x1 WHERE x1 MATCH 'abcd' } 154} -test { 155 faultsim_test_result [list 0 0] 156} 157 158proc test_astar {a b} { 159 return [expr { [regexp {a[^ ][^ ]} $a] || [regexp {a[^ ][^ ]} $b] }] 160} 161db func test_astar test_astar 162 163set res [db one { SELECT count(*) FROM x1 WHERE test_astar(a, b) } ] 164do_faultsim_test 5.3 -faults oom* -body { 165 execsql { SELECT count(*) FROM x1 WHERE x1 MATCH 'a*' } 166} -test { 167 faultsim_test_result [list 0 $::res] 168} 169 170do_faultsim_test 5.4 -faults oom* -prep { 171 db close 172 sqlite3 db test.db 173} -body { 174 execsql { INSERT INTO x1 VALUES('a b c d', 'e f g h') } 175} -test { 176 faultsim_test_result [list 0 {}] 177} 178 179do_faultsim_test 5.5.1 -faults oom* -body { 180 execsql { 181 SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid=1 182 } 183} -test { 184 faultsim_test_result [list 0 1] 185} 186do_faultsim_test 5.5.2 -faults oom* -body { 187 execsql { 188 SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid=10 189 } 190} -test { 191 faultsim_test_result [list 0 1] 192} 193do_faultsim_test 5.5.3 -faults oom* -body { 194 execsql { 195 SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid = ( 196 SELECT min(rowid) FROM x1_data WHERE rowid>20 197 ) 198 } 199} -test { 200 faultsim_test_result [list 0 1] 201} 202do_faultsim_test 5.5.4 -faults oom* -body { 203 execsql { 204 SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid = ( 205 SELECT max(rowid) FROM x1_data 206 ) 207 } 208} -test { 209 faultsim_test_result [list 0 1] 210} 211 212#------------------------------------------------------------------------- 213# 214reset_db 215do_execsql_test 6.0 { 216 CREATE VIRTUAL TABLE x1 USING fts5(x); 217 INSERT INTO x1(x1, rank) VALUES('automerge', 0); 218 219 INSERT INTO x1 VALUES('a b c'); -- 1 220 INSERT INTO x1 VALUES('a b c'); -- 2 221 INSERT INTO x1 VALUES('a b c'); -- 3 222 INSERT INTO x1 VALUES('a b c'); -- 4 223 INSERT INTO x1 VALUES('a b c'); -- 5 224 INSERT INTO x1 VALUES('a b c'); -- 6 225 INSERT INTO x1 VALUES('a b c'); -- 7 226 INSERT INTO x1 VALUES('a b c'); -- 8 227 INSERT INTO x1 VALUES('a b c'); -- 9 228 INSERT INTO x1 VALUES('a b c'); -- 10 229 INSERT INTO x1 VALUES('a b c'); -- 11 230 INSERT INTO x1 VALUES('a b c'); -- 12 231 INSERT INTO x1 VALUES('a b c'); -- 13 232 INSERT INTO x1 VALUES('a b c'); -- 14 233 INSERT INTO x1 VALUES('a b c'); -- 15 234 235 SELECT count(*) FROM x1_data; 236} {17} 237 238faultsim_save_and_close 239 240do_faultsim_test 6.1 -faults oom* -prep { 241 faultsim_restore_and_reopen 242} -body { 243 execsql { INSERT INTO x1 VALUES('d e f') } 244} -test { 245 faultsim_test_result [list 0 {}] 246 if {$testrc==0} { 247 set nCnt [db one {SELECT count(*) FROM x1_data}] 248 if {$nCnt!=3} { error "expected 3 entries but there are $nCnt" } 249 } 250} 251 252do_faultsim_test 6.2 -faults oom* -prep { 253 faultsim_restore_and_reopen 254} -body { 255 execsql { INSERT INTO x1(x1, rank) VALUES('pgsz', 32) } 256} -test { 257 faultsim_test_result [list 0 {}] 258} 259 260do_faultsim_test 6.3 -faults oom-* -prep { 261 faultsim_restore_and_reopen 262} -body { 263 execsql { INSERT INTO x1(x1) VALUES('integrity-check') } 264} -test { 265 faultsim_test_result [list 0 {}] 266} 267 268do_faultsim_test 6.4 -faults oom-* -prep { 269 faultsim_restore_and_reopen 270} -body { 271 execsql { INSERT INTO x1(x1) VALUES('optimize') } 272} -test { 273 faultsim_test_result [list 0 {}] 274} 275 276#------------------------------------------------------------------------- 277# 278do_faultsim_test 7.0 -faults oom* -prep { 279 catch { db close } 280} -body { 281 sqlite3 db test.db 282} -test { 283 faultsim_test_result [list 0 {}] {1 {}} {1 {initialization of fts5 failed: }} 284} 285 286#------------------------------------------------------------------------- 287# A prefix query against a large document set. 288# 289proc rnddoc {n} { 290 set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] 291 set doc [list] 292 for {set i 0} {$i < $n} {incr i} { 293 lappend doc "x[string map $map [format %.3d [expr int(rand()*1000)]]]" 294 } 295 set doc 296} 297 298reset_db 299db func rnddoc rnddoc 300 301do_test 8.0 { 302 execsql { CREATE VIRTUAL TABLE x1 USING fts5(a) } 303 set ::res [list] 304 for {set i 1} {$i<100} {incr i 1} { 305 execsql { INSERT INTO x1 VALUES( rnddoc(50) ) } 306 lappend ::res $i 307 } 308} {} 309 310do_faultsim_test 8.1 -faults oom* -prep { 311} -body { 312 execsql { 313 SELECT rowid FROM x1 WHERE x1 MATCH 'x*' 314 } 315} -test { 316 faultsim_test_result [list 0 $::res] 317} 318 319#------------------------------------------------------------------------- 320# Segment promotion. 321# 322do_test 9.0 { 323 reset_db 324 db func rnddoc fts5_rnddoc 325 execsql { 326 CREATE VIRTUAL TABLE s2 USING fts5(x); 327 INSERT INTO s2(s2, rank) VALUES('pgsz', 32); 328 INSERT INTO s2(s2, rank) VALUES('automerge', 0); 329 } 330 331 for {set i 1} {$i <= 16} {incr i} { 332 execsql { INSERT INTO s2 VALUES(rnddoc(5)) } 333 } 334 fts5_level_segs s2 335} {0 1} 336set insert_doc [db one {SELECT rnddoc(160)}] 337faultsim_save_and_close 338 339do_faultsim_test 9.1 -faults oom-* -prep { 340 faultsim_restore_and_reopen 341} -body { 342 execsql { INSERT INTO s2 VALUES($::insert_doc) } 343} -test { 344 faultsim_test_result {0 {}} 345 if {$testrc==0} { 346 set ls [fts5_level_segs s2] 347 if {$ls != "2 0"} { error "fts5_level_segs says {$ls}" } 348 } 349} 350 351 352 353finish_test 354