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