xref: /sqlite-3.40.0/test/fts3malloc.test (revision 91f0ce39)
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