1# 2009 October 22 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 contains tests to verify that malloc() errors that occur 13# within the FTS3 module code are handled correctly. 14# 15 16set testdir [file dirname $argv0] 17source $testdir/tester.tcl 18ifcapable !fts3 { finish_test ; return } 19source $testdir/malloc_common.tcl 20source $testdir/fts3_common.tcl 21 22set sqlite_fts3_enable_parentheses 1 23 24if 0 { 25do_malloc_test fts3_malloc-1.1 -sqlbody { 26 CREATE VIRTUAL TABLE ft USING fts3(a, b, c); 27} 28do_malloc_test fts3_malloc-1.2 -sqlprep { 29 CREATE VIRTUAL TABLE ft USING fts3(a, b, c); 30} -sqlbody { 31 DROP TABLE ft; 32} 33} 34 35set DO_MALLOC_TEST 0 36 37#------------------------------------------------------------------------- 38# This proc is used to test a single SELECT statement. Parameter $name is 39# passed a name for the test case (i.e. "fts3_malloc-1.4.1") and parameter 40# $sql is passed the text of the SELECT statement. Parameter $result is 41# set to the expected output if the SELECT statement is successfully 42# executed using [db eval]. 43# 44# Example: 45# 46# do_select_test testcase-1.1 "SELECT 1+1, 1+2" {1 2} 47# 48# If global variable DO_MALLOC_TEST is set to a non-zero value, or if 49# it is not defined at all, then OOM testing is performed on the SELECT 50# statement. Each OOM test case is said to pass if either (a) executing 51# the SELECT statement succeeds and the results match those specified 52# by parameter $result, or (b) TCL throws an "out of memory" error. 53# 54# If DO_MALLOC_TEST is defined and set to zero, then the SELECT statement 55# is executed just once. In this case the test case passes if the results 56# match the expected results passed via parameter $result. 57# 58proc do_select_test {name sql result} { 59 60 if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 } 61 62 if {$::DO_MALLOC_TEST } { 63 set answers [list {1 {out of memory}} [list 0 $result]] 64 set modes [list 100000 transient 1 persistent] 65 } else { 66 set answers [list [list 0 $result]] 67 set modes [list 0 nofail] 68 } 69 set str [join $answers " OR "] 70 71 foreach {nRepeat zName} $modes { 72 for {set iFail 1} 1 {incr iFail} { 73 if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat} 74 75 set res [catchsql $sql] 76 if {[lsearch $answers $res]>=0} { 77 set res $str 78 } 79 do_test $name.$zName.$iFail [list set {} $res] $str 80 set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] 81 if {$nFail==0} break 82 } 83 } 84} 85 86#------------------------------------------------------------------------- 87# Test a single write to the database. In this case a "write" is a 88# DELETE, UPDATE or INSERT statement. 89# 90# If OOM testing is performed, there are several acceptable outcomes: 91# 92# 1) The write succeeds. No error is returned. 93# 94# 2) An "out of memory" exception is thrown and: 95# 96# a) The statement has no effect, OR 97# b) The current transaction is rolled back, OR 98# c) The statement succeeds. This can only happen if the connection 99# is in auto-commit mode (after the statement is executed, so this 100# includes COMMIT statements). 101# 102# If the write operation eventually succeeds, zero is returned. If a 103# transaction is rolled back, non-zero is returned. 104# 105# Parameter $name is the name to use for the test case (or test cases). 106# The second parameter, $tbl, should be the name of the database table 107# being modified. Parameter $sql contains the SQL statement to test. 108# 109proc do_write_test {name tbl sql} { 110 # Figure out an statement to get a checksum for table $tbl. 111 db eval "SELECT * FROM $tbl" V break 112 set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl" 113 114 # Calculate the initial table checksum. 115 set cksum1 [db one $cksumsql] 116 117 if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 } 118 119 if {$::DO_MALLOC_TEST } { 120 set answers [list {1 {out of memory}} {0 {}}] 121 set modes [list 100000 transient 1 persistent] 122 } else { 123 set answers [list {0 {}}] 124 set modes [list 0 nofail] 125 } 126 set str [join $answers " OR "] 127 128 foreach {nRepeat zName} $modes { 129 for {set iFail 1} 1 {incr iFail} { 130 if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat} 131 132 set res [catchsql $sql] 133 set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] 134 if {$nFail==0} { 135 do_test $name.$zName.$iFail [list set {} $res] {0 {}} 136 return 137 } else { 138 if {[lsearch $answers $res]>=0} { 139 set res $str 140 } 141 do_test $name.$zName.$iFail [list set {} $res] $str 142 set cksum2 [db one $cksumsql] 143 if {$cksum1 != $cksum2} return 144 } 145 } 146 } 147} 148 149proc normal_list {l} { 150 set ret [list] 151 foreach elem $l {lappend ret $elem} 152 set ret 153} 154 155db close 156file delete -force test.db test.db-journal 157sqlite3 db test.db 158sqlite3_db_config_lookaside db 0 0 0 159 160do_test fts3_malloc-2.0 { 161 execsql { CREATE VIRTUAL TABLE ft USING fts3(a, b) } 162 for {set ii 1} {$ii < 32} {incr ii} { 163 set a [list] 164 set b [list] 165 if {$ii & 0x01} {lappend a one ; lappend b neung} 166 if {$ii & 0x02} {lappend a two ; lappend b song } 167 if {$ii & 0x04} {lappend a three ; lappend b sahm } 168 if {$ii & 0x08} {lappend a four ; lappend b see } 169 if {$ii & 0x10} {lappend a five ; lappend b hah } 170 execsql { INSERT INTO ft VALUES($a, $b) } 171 } 172} {} 173 174foreach {tn sql result} { 175 1 "SELECT count(*) FROM sqlite_master" {5} 176 2 "SELECT * FROM ft WHERE docid = 1" {one neung} 177 3 "SELECT * FROM ft WHERE docid = 2" {two song} 178 4 "SELECT * FROM ft WHERE docid = 3" {{one two} {neung song}} 179 180 5 "SELECT a FROM ft" { 181 {one} {two} {one two} 182 {three} {one three} {two three} 183 {one two three} {four} {one four} 184 {two four} {one two four} {three four} 185 {one three four} {two three four} {one two three four} 186 {five} {one five} {two five} 187 {one two five} {three five} {one three five} 188 {two three five} {one two three five} {four five} 189 {one four five} {two four five} {one two four five} 190 {three four five} {one three four five} {two three four five} 191 {one two three four five} 192 } 193 194 6 "SELECT a FROM ft WHERE a MATCH 'one'" { 195 {one} {one two} {one three} {one two three} 196 {one four} {one two four} {one three four} {one two three four} 197 {one five} {one two five} {one three five} {one two three five} 198 {one four five} {one two four five} 199 {one three four five} {one two three four five} 200 } 201 202 7 "SELECT a FROM ft WHERE a MATCH 'o*'" { 203 {one} {one two} {one three} {one two three} 204 {one four} {one two four} {one three four} {one two three four} 205 {one five} {one two five} {one three five} {one two three five} 206 {one four five} {one two four five} 207 {one three four five} {one two three four five} 208 } 209 210 8 "SELECT a FROM ft WHERE a MATCH 'o* t*'" { 211 {one two} {one three} {one two three} 212 {one two four} {one three four} {one two three four} 213 {one two five} {one three five} {one two three five} 214 {one two four five} {one three four five} {one two three four five} 215 } 216 217 9 "SELECT a FROM ft WHERE a MATCH '\"o* t*\"'" { 218 {one two} {one three} {one two three} 219 {one two four} {one three four} {one two three four} 220 {one two five} {one three five} {one two three five} 221 {one two four five} {one three four five} {one two three four five} 222 } 223 224 10 {SELECT a FROM ft WHERE a MATCH '"o* f*"'} { 225 {one four} {one five} {one four five} 226 } 227 228 11 {SELECT a FROM ft WHERE a MATCH '"one two three"'} { 229 {one two three} 230 {one two three four} 231 {one two three five} 232 {one two three four five} 233 } 234 235 12 {SELECT a FROM ft WHERE a MATCH '"two three four"'} { 236 {two three four} 237 {one two three four} 238 {two three four five} 239 {one two three four five} 240 } 241 242 12 {SELECT a FROM ft WHERE a MATCH '"two three" five'} { 243 {two three five} {one two three five} 244 {two three four five} {one two three four five} 245 } 246 247 13 {SELECT a FROM ft WHERE ft MATCH '"song sahm" hah'} { 248 {two three five} {one two three five} 249 {two three four five} {one two three four five} 250 } 251 252 14 {SELECT a FROM ft WHERE b MATCH 'neung'} { 253 {one} {one two} 254 {one three} {one two three} 255 {one four} {one two four} 256 {one three four} {one two three four} 257 {one five} {one two five} 258 {one three five} {one two three five} 259 {one four five} {one two four five} 260 {one three four five} {one two three four five} 261 } 262 263 15 {SELECT a FROM ft WHERE b MATCH '"neung song sahm"'} { 264 {one two three} {one two three four} 265 {one two three five} {one two three four five} 266 } 267 268 16 {SELECT a FROM ft WHERE b MATCH 'hah "song sahm"'} { 269 {two three five} {one two three five} 270 {two three four five} {one two three four five} 271 } 272 273 17 {SELECT a FROM ft WHERE b MATCH 'song OR sahm'} { 274 {two} {one two} {three} 275 {one three} {two three} {one two three} 276 {two four} {one two four} {three four} 277 {one three four} {two three four} {one two three four} 278 {two five} {one two five} {three five} 279 {one three five} {two three five} {one two three five} 280 {two four five} {one two four five} {three four five} 281 {one three four five} {two three four five} {one two three four five} 282 } 283 284 18 {SELECT a FROM ft WHERE a MATCH 'three NOT two'} { 285 {three} {one three} {three four} 286 {one three four} {three five} {one three five} 287 {three four five} {one three four five} 288 } 289 290 19 {SELECT a FROM ft WHERE b MATCH 'sahm NOT song'} { 291 {three} {one three} {three four} 292 {one three four} {three five} {one three five} 293 {three four five} {one three four five} 294 } 295 296 20 {SELECT a FROM ft WHERE ft MATCH 'sahm NOT song'} { 297 {three} {one three} {three four} 298 {one three four} {three five} {one three five} 299 {three four five} {one three four five} 300 } 301 302 21 {SELECT a FROM ft WHERE b MATCH 'neung NEAR song NEAR sahm'} { 303 {one two three} {one two three four} 304 {one two three five} {one two three four five} 305 } 306 307} { 308 set result [normal_list $result] 309 do_select_test fts3_malloc-2.$tn $sql $result 310} 311 312do_test fts3_malloc-3.0 { 313 execsql BEGIN 314 for {set ii 32} {$ii < 1024} {incr ii} { 315 set a [list] 316 set b [list] 317 if {$ii & 0x0001} {lappend a one ; lappend b neung } 318 if {$ii & 0x0002} {lappend a two ; lappend b song } 319 if {$ii & 0x0004} {lappend a three ; lappend b sahm } 320 if {$ii & 0x0008} {lappend a four ; lappend b see } 321 if {$ii & 0x0010} {lappend a five ; lappend b hah } 322 if {$ii & 0x0020} {lappend a six ; lappend b hok } 323 if {$ii & 0x0040} {lappend a seven ; lappend b jet } 324 if {$ii & 0x0080} {lappend a eight ; lappend b bairt } 325 if {$ii & 0x0100} {lappend a nine ; lappend b gow } 326 if {$ii & 0x0200} {lappend a ten ; lappend b sip } 327 execsql { INSERT INTO ft VALUES($a, $b) } 328 } 329 execsql COMMIT 330} {} 331foreach {tn sql result} { 332 1 "SELECT count(*) FROM ft" {1023} 333 334 2 "SELECT a FROM ft WHERE a MATCH 'one two three four five six seven eight'" { 335 {one two three four five six seven eight} 336 {one two three four five six seven eight nine} 337 {one two three four five six seven eight ten} 338 {one two three four five six seven eight nine ten} 339 } 340 341 3 {SELECT count(*), sum(docid) FROM ft WHERE a MATCH 'o*'} { 342 512 262144 343 } 344 345 4 {SELECT count(*), sum(docid) FROM ft WHERE a MATCH '"two three four"'} { 346 128 66368 347 } 348} { 349 set result [normal_list $result] 350 do_select_test fts3_malloc-3.$tn $sql $result 351} 352 353do_test fts3_malloc-4.0 { 354 execsql { DELETE FROM ft WHERE docid>=32 } 355} {} 356foreach {tn sql} { 357 1 "DELETE FROM ft WHERE ft MATCH 'one'" 358 2 "DELETE FROM ft WHERE ft MATCH 'three'" 359 3 "DELETE FROM ft WHERE ft MATCH 'five'" 360} { 361 do_write_test fts3_malloc-4.1.$tn ft_content $sql 362} 363do_test fts3_malloc-4.2 { 364 execsql { SELECT a FROM ft } 365} {two four {two four}} 366 367 368finish_test 369 370