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