xref: /sqlite-3.40.0/ext/fts5/test/fts5fault4.test (revision f703b42d)
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#
12# This file is focused on OOM errors.
13#
14
15source [file join [file dirname [info script]] fts5_common.tcl]
16source $testdir/malloc_common.tcl
17set testprefix fts5fault4
18
19# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
20ifcapable !fts5 {
21  finish_test
22  return
23}
24
25set ::TMPDBERROR [list 1 \
26  {unable to open a temporary database file for storing temporary tables}
27]
28
29#-------------------------------------------------------------------------
30# An OOM while dropping an fts5 table.
31#
32db func rnddoc fts5_rnddoc
33do_test 1.0 {
34  execsql { CREATE VIRTUAL TABLE xx USING fts5(x) }
35} {}
36faultsim_save_and_close
37
38do_faultsim_test 1 -faults oom-* -prep {
39  faultsim_restore_and_reopen
40  execsql { SELECT * FROM xx }
41} -body {
42  execsql { DROP TABLE xx }
43} -test {
44  faultsim_test_result [list 0 {}]
45}
46
47#-------------------------------------------------------------------------
48# An OOM while "reseeking" an FTS cursor.
49#
50do_execsql_test 3.0 {
51  CREATE VIRTUAL TABLE jj USING fts5(j);
52  INSERT INTO jj(rowid, j) VALUES(101, 'm t w t f s s');
53  INSERT INTO jj(rowid, j) VALUES(202, 't w t f s');
54  INSERT INTO jj(rowid, j) VALUES(303, 'w t f');
55  INSERT INTO jj(rowid, j) VALUES(404, 't');
56}
57faultsim_save_and_close
58
59do_faultsim_test 3 -faults oom-* -prep {
60  faultsim_restore_and_reopen
61  execsql { SELECT * FROM jj }
62} -body {
63  set res [list]
64  db eval { SELECT rowid FROM jj WHERE jj MATCH 't' } {
65    lappend res $rowid
66    if {$rowid==303} {
67      execsql { DELETE FROM jj WHERE rowid=404 }
68    }
69  }
70  set res
71} -test {
72  faultsim_test_result [list 0 {101 202 303}]
73}
74
75#-------------------------------------------------------------------------
76# An OOM within a special "*reads" query.
77#
78reset_db
79db func rnddoc fts5_rnddoc
80do_execsql_test 4.0 {
81  CREATE VIRTUAL TABLE x1 USING fts5(x);
82  INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
83
84  WITH ii(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<10 )
85  INSERT INTO x1 SELECT rnddoc(5) FROM ii;
86}
87
88set ::res [db eval {SELECT rowid, x1 FROM x1 WHERE x1 MATCH '*reads'}]
89
90do_faultsim_test 4 -faults oom-* -body {
91  db eval {SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'}
92} -test {
93  faultsim_test_result {0 {0 {} 3}}
94}
95
96#-------------------------------------------------------------------------
97# An OOM within a query that uses a custom rank function.
98#
99reset_db
100do_execsql_test 5.0 {
101  PRAGMA encoding='utf16';
102  CREATE VIRTUAL TABLE x2 USING fts5(x);
103  INSERT INTO x2(rowid, x) VALUES(10, 'a b c'); -- 3
104  INSERT INTO x2(rowid, x) VALUES(20, 'a b c'); -- 6
105  INSERT INTO x2(rowid, x) VALUES(30, 'a b c'); -- 2
106  INSERT INTO x2(rowid, x) VALUES(40, 'a b c'); -- 5
107  INSERT INTO x2(rowid, x) VALUES(50, 'a b c'); -- 1
108}
109
110proc rowidmod {cmd mod} {
111  set row [$cmd xRowid]
112  expr {$row % $mod}
113}
114sqlite3_fts5_create_function db rowidmod rowidmod
115
116do_faultsim_test 5.1 -faults oom-* -body {
117  db eval {
118    SELECT rowid || '-' || rank FROM x2 WHERE x2 MATCH 'b' AND
119    rank MATCH "rowidmod('7')" ORDER BY rank
120  }
121} -test {
122  faultsim_test_result {0 {50-1 30-2 10-3 40-5 20-6}}
123}
124
125proc rowidprefix {cmd prefix} {
126  set row [$cmd xRowid]
127  set {} "${row}-${prefix}"
128}
129sqlite3_fts5_create_function db rowidprefix rowidprefix
130
131set str [string repeat abcdefghijklmnopqrstuvwxyz 10]
132do_faultsim_test 5.2 -faults oom-* -body {
133  db eval "
134    SELECT rank, x FROM x2 WHERE x2 MATCH 'b' AND
135    rank MATCH 'rowidprefix(''$::str'')'
136    LIMIT 1
137  "
138} -test {
139  faultsim_test_result "0 {10-$::str {a b c}}"
140}
141
142
143#-------------------------------------------------------------------------
144# OOM errors within auxiliary functions.
145#
146reset_db
147do_execsql_test 6.0 {
148  CREATE VIRTUAL TABLE x3 USING fts5(xxx);
149  INSERT INTO x3 VALUES('a b c d c b a');
150  INSERT INTO x3 VALUES('a a a a a a a');
151  INSERT INTO x3 VALUES('a a a a a a a');
152}
153
154do_faultsim_test 6.1 -faults oom-t* -body {
155  db eval { SELECT highlight(x3, 0, '*', '*') FROM x3 WHERE x3 MATCH 'c' }
156} -test {
157  faultsim_test_result {0 {{a b *c* d *c* b a}}}
158}
159
160proc firstinst {cmd} {
161  foreach {p c o} [$cmd xInst 0] {}
162  expr $c*100 + $o
163}
164sqlite3_fts5_create_function db firstinst firstinst
165
166do_faultsim_test 6.2 -faults oom-t* -body {
167  db eval { SELECT firstinst(x3) FROM x3 WHERE x3 MATCH 'c' }
168} -test {
169  faultsim_test_result {0 2} {1 SQLITE_NOMEM}
170}
171
172proc previc {cmd} {
173  set res [$cmd xGetAuxdataInt 0]
174  $cmd xSetAuxdataInt [$cmd xInstCount]
175  return $res
176}
177sqlite3_fts5_create_function db previc  previc
178
179do_faultsim_test 6.2 -faults oom-t* -body {
180  db eval { SELECT previc(x3) FROM x3 WHERE x3 MATCH 'a' }
181} -test {
182  faultsim_test_result {0 {0 2 7}} {1 SQLITE_NOMEM}
183}
184
185#-------------------------------------------------------------------------
186# OOM error when querying for a phrase with many tokens.
187#
188reset_db
189do_execsql_test 7.0 {
190  CREATE VIRTUAL TABLE tt USING fts5(x, y);
191  INSERT INTO tt VALUES('f b g b c b', 'f a d c c b');  -- 1
192  INSERT INTO tt VALUES('d a e f e d', 'f b b d e e');  -- 2
193  INSERT INTO tt VALUES('f b g a d c', 'e f c f a d');  -- 3
194  INSERT INTO tt VALUES('f f c d g f', 'f a e b g b');  -- 4
195  INSERT INTO tt VALUES('a g b d a g', 'e g a e a c');  -- 5
196  INSERT INTO tt VALUES('c d b d e f', 'f g e g e e');  -- 6
197  INSERT INTO tt VALUES('e g f f b c', 'f c e f g f');  -- 7
198  INSERT INTO tt VALUES('e g c f c e', 'f e e a f g');  -- 8
199  INSERT INTO tt VALUES('e a e b e e', 'd c c f f f');  -- 9
200  INSERT INTO tt VALUES('f a g g c c', 'e g d g c e');  -- 10
201  INSERT INTO tt VALUES('c d b a e f', 'f g e h e e');  -- 11
202
203  CREATE VIRTUAL TABLE tt2 USING fts5(o);
204  INSERT INTO tt2(rowid, o) SELECT rowid, x||' '||y FROM tt;
205  INSERT INTO tt2(rowid, o) VALUES(12, 'a b c d e f g h i j k l');
206}
207
208do_faultsim_test 7.2 -faults oom-* -body {
209  db eval { SELECT rowid FROM tt WHERE tt MATCH 'f+g+e+g+e+e' }
210} -test {
211  faultsim_test_result {0 6} {1 SQLITE_NOMEM}
212}
213
214do_faultsim_test 7.3 -faults oom-* -body {
215  db eval { SELECT rowid FROM tt WHERE tt MATCH 'NEAR(a b c d e f)' }
216} -test {
217  faultsim_test_result {0 11} {1 SQLITE_NOMEM}
218}
219
220do_faultsim_test 7.4 -faults oom-t* -body {
221  db eval { SELECT rowid FROM tt2 WHERE tt2 MATCH '"g c f c e f e e a f"' }
222} -test {
223  faultsim_test_result {0 8} {1 SQLITE_NOMEM}
224}
225
226do_faultsim_test 7.5 -faults oom-* -body {
227  db eval {SELECT rowid FROM tt2 WHERE tt2 MATCH 'NEAR(a b c d e f g h i j k)'}
228} -test {
229  faultsim_test_result {0 12} {1 SQLITE_NOMEM}
230}
231
232do_faultsim_test 7.6 -faults oom-* -body {
233  db eval {SELECT rowid FROM tt WHERE tt MATCH 'y: "c c"'}
234} -test {
235  faultsim_test_result {0 {1 9}} {1 SQLITE_NOMEM}
236}
237
238#-------------------------------------------------------------------------
239#
240reset_db
241do_execsql_test 8.0 {
242  CREATE VIRTUAL TABLE tt USING fts5(x);
243  INSERT INTO tt(tt, rank) VALUES('pgsz', 32);
244  BEGIN;
245    INSERT INTO tt(rowid, x) VALUES(1, 'a b c d x x');
246    WITH ii(i) AS (SELECT 2 UNION ALL SELECT i+1 FROM ii WHERE i<99)
247      INSERT INTO tt(rowid, x) SELECT i, 'a b c x x d' FROM ii;
248    INSERT INTO tt(rowid, x) VALUES(100, 'a b c d x x');
249  COMMIT;
250}
251
252do_faultsim_test 8.1 -faults oom-t* -body {
253  db eval { SELECT rowid FROM tt WHERE tt MATCH 'NEAR(a b c d, 2)' }
254} -test {
255  faultsim_test_result {0 {1 100}} {1 SQLITE_NOMEM}
256}
257
258do_faultsim_test 8.2 -faults oom-t* -body {
259  db eval { SELECT count(*) FROM tt WHERE tt MATCH 'a OR d' }
260} -test {
261  faultsim_test_result {0 100} {1 SQLITE_NOMEM}
262}
263
264
265#-------------------------------------------------------------------------
266# Fault in NOT query.
267#
268reset_db
269do_execsql_test 9.0 {
270  CREATE VIRTUAL TABLE tt USING fts5(x);
271  INSERT INTO tt(tt, rank) VALUES('pgsz', 32);
272  BEGIN;
273    WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<200)
274      INSERT INTO tt(rowid, x)
275      SELECT i, CASE WHEN (i%50)==0 THEN 'a a a a a a' ELSE 'a x a x a x' END
276      FROM ii;
277  COMMIT;
278}
279
280do_faultsim_test 9.1 -faults oom-* -body {
281  db eval { SELECT rowid FROM tt WHERE tt MATCH 'a NOT x' }
282} -test {
283  faultsim_test_result {0 {50 100 150 200}} {1 SQLITE_NOMEM}
284}
285
286#-------------------------------------------------------------------------
287# OOM in fts5_expr() SQL function.
288#
289do_faultsim_test 10.1 -faults oom-t* -body {
290  db one { SELECT fts5_expr('a AND b NEAR(a b)') }
291} -test {
292  faultsim_test_result {0 {"a" AND "b" AND NEAR("a" "b", 10)}}
293}
294
295do_faultsim_test 10.2 -faults oom-t* -body {
296  db one { SELECT fts5_expr_tcl('x:"a b c" AND b NEAR(a b)', 'ns', 'x') }
297} -test {
298  set res {AND [ns -col 0 -- {a b c}] [ns -- {b}] [ns -near 10 -- {a} {b}]}
299  faultsim_test_result [list 0 $res]
300}
301
302do_faultsim_test 10.3 -faults oom-t* -body {
303  db one { SELECT fts5_expr('x:a', 'x') }
304} -test {
305  faultsim_test_result {0 {x : "a"}}
306}
307
308#-------------------------------------------------------------------------
309# OOM while configuring 'rank' option.
310#
311reset_db
312do_execsql_test 11.0 {
313  CREATE VIRTUAL TABLE ft USING fts5(x);
314}
315do_faultsim_test 11.1 -faults oom-t* -body {
316  db eval { INSERT INTO ft(ft, rank) VALUES('rank', 'bm25(10.0, 5.0)') }
317} -test {
318  faultsim_test_result {0 {}} {1 {disk I/O error}}
319}
320
321#-------------------------------------------------------------------------
322# OOM while creating an fts5vocab table.
323#
324reset_db
325do_execsql_test 12.0 {
326  CREATE VIRTUAL TABLE ft USING fts5(x);
327}
328faultsim_save_and_close
329do_faultsim_test 12.1 -faults oom-t* -prep {
330  faultsim_restore_and_reopen
331  db eval { SELECT * FROM sqlite_master }
332} -body {
333  db eval { CREATE VIRTUAL TABLE vv USING fts5vocab(ft, 'row') }
334} -test {
335  faultsim_test_result {0 {}}
336}
337
338#-------------------------------------------------------------------------
339# OOM while querying an fts5vocab table.
340#
341reset_db
342do_execsql_test 13.0 {
343  CREATE VIRTUAL TABLE ft USING fts5(x);
344  INSERT INTO ft VALUES('a b');
345  CREATE VIRTUAL TABLE vv USING fts5vocab(ft, 'row');
346}
347faultsim_save_and_close
348do_faultsim_test 13.1 -faults oom-t* -prep {
349  faultsim_restore_and_reopen
350  db eval { SELECT * FROM vv }
351} -body {
352  db eval { SELECT * FROM vv }
353} -test {
354  faultsim_test_result {0 {a 1 1 b 1 1}}
355}
356
357#-------------------------------------------------------------------------
358# OOM in multi-column token query.
359#
360reset_db
361do_execsql_test 13.0 {
362  CREATE VIRTUAL TABLE ft USING fts5(x, y, z);
363  INSERT INTO ft(ft, rank) VALUES('pgsz', 32);
364  INSERT INTO ft VALUES(
365      'x x x x x x x x x x x x x x x x',
366      'y y y y y y y y y y y y y y y y',
367      'z z z z z z z z x x x x x x x x'
368  );
369  INSERT INTO ft SELECT * FROM ft;
370  INSERT INTO ft SELECT * FROM ft;
371  INSERT INTO ft SELECT * FROM ft;
372  INSERT INTO ft SELECT * FROM ft;
373}
374faultsim_save_and_close
375do_faultsim_test 13.1 -faults oom-t* -prep {
376  faultsim_restore_and_reopen
377  db eval { SELECT * FROM ft }
378} -body {
379  db eval { SELECT rowid FROM ft WHERE ft MATCH '{x z}: x' }
380} -test {
381  faultsim_test_result {0 {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}}
382}
383
384#-------------------------------------------------------------------------
385# OOM in an "ALTER TABLE RENAME TO"
386#
387reset_db
388do_execsql_test 14.0 {
389  CREATE VIRTUAL TABLE "tbl one" USING fts5(x, y, z);
390}
391faultsim_save_and_close
392do_faultsim_test 14.1 -faults oom-t* -prep {
393  faultsim_restore_and_reopen
394  db eval { SELECT * FROM "tbl one" }
395} -body {
396  db eval { ALTER TABLE "tbl one" RENAME TO "tbl two" }
397} -test {
398  faultsim_test_result {0 {}} $::TMPDBERROR
399}
400
401finish_test
402