3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
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.
10 #*************************************************************************
11 # This file implements regression tests for SQLite library. The
12 # focus of this script is testing the FTS5 module.
15 source [file join [file dirname [info script]] fts5_common.tcl]
18 # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
24 foreach_detail_mode $::testprefix {
27 CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
28 SELECT name, sql FROM sqlite_master;
30 t1 {CREATE VIRTUAL TABLE t1 USING fts5(a, b, c)}
31 t1_data {CREATE TABLE 't1_data'(id INTEGER PRIMARY KEY, block BLOB)}
32 t1_idx {CREATE TABLE 't1_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID}
33 t1_content {CREATE TABLE 't1_content'(id INTEGER PRIMARY KEY, c0, c1, c2)}
34 t1_docsize {CREATE TABLE 't1_docsize'(id INTEGER PRIMARY KEY, sz BLOB)}
35 t1_config {CREATE TABLE 't1_config'(k PRIMARY KEY, v) WITHOUT ROWID}
40 SELECT name, sql FROM sqlite_master;
43 #-------------------------------------------------------------------------
47 CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
50 INSERT INTO t1 VALUES('a b c', 'd e f');
54 execsql { SELECT fts5_decode(id, block) FROM t1_data WHERE id==10 }
55 } {/{{structure} {lvl=0 nMerge=0 nSeg=1 {id=[0123456789]* leaves=1..1}}}/}
57 foreach w {a b c d e f} {
58 do_execsql_test 2.3.$w.asc {
59 SELECT rowid FROM t1 WHERE t1 MATCH $w;
61 do_execsql_test 2.3.$w.desc {
62 SELECT rowid FROM t1 WHERE t1 MATCH $w ORDER BY rowid DESC;
67 INSERT INTO t1(t1) VALUES('integrity-check');
71 #-------------------------------------------------------------------------
75 CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
78 1 {g f d b f} {h h e i a}
79 2 {f i g j e} {i j c f f}
80 3 {e e i f a} {e h f d f}
81 4 {h j f j i} {h a c f j}
82 5 {d b j c g} {f e i b e}
83 6 {a j a e e} {j d f d e}
84 7 {g i j c h} {j d h c a}
85 8 {j j i d d} {e e d f b}
86 9 {c j j d c} {h j i f g}
87 10 {b f h i a} {c f b b j}
89 do_execsql_test 3.$i.1 { INSERT INTO t1 VALUES($x, $y) }
90 do_execsql_test 3.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
91 if {[set_test_counter errors]} break
94 #-------------------------------------------------------------------------
98 CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
99 INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
102 1 {g f d b f} {h h e i a}
103 2 {f i g j e} {i j c f f}
104 3 {e e i f a} {e h f d f}
105 4 {h j f j i} {h a c f j}
106 5 {d b j c g} {f e i b e}
107 6 {a j a e e} {j d f d e}
108 7 {g i j c h} {j d h c a}
109 8 {j j i d d} {e e d f b}
110 9 {c j j d c} {h j i f g}
111 10 {b f h i a} {c f b b j}
113 do_execsql_test 4.$i.1 { INSERT INTO t1 VALUES($x, $y) }
114 do_execsql_test 4.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
115 if {[set_test_counter errors]} break
118 #-------------------------------------------------------------------------
121 do_execsql_test 5.0 {
122 CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
123 INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
126 1 {dd abc abc abc abcde} {aaa dd ddd ddd aab}
127 2 {dd aab d aaa b} {abcde c aaa aaa aaa}
128 3 {abcde dd b b dd} {abc abc d abc ddddd}
129 4 {aaa abcde dddd dddd abcde} {abc b b abcde abc}
130 5 {aab dddd d dddd c} {ddd abcde dddd abcde c}
131 6 {ddd dd b aab abcde} {d ddddd dddd c abc}
132 7 {d ddddd ddd c abcde} {c aab d abcde ddd}
133 8 {abcde aaa aab c c} {ddd c dddd b aaa}
134 9 {abcde aab ddddd c aab} {dddd dddd b c dd}
135 10 {ddd abcde dddd dd c} {dddd c c d abcde}
137 do_execsql_test 5.$i.1 { INSERT INTO t1 VALUES($x, $y) }
138 do_execsql_test 5.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
139 if {[set_test_counter errors]} break
142 #-------------------------------------------------------------------------
145 do_execsql_test 6.0 {
146 CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
147 INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
150 do_execsql_test 6.1 {
151 INSERT INTO t1(rowid, x, y) VALUES(22, 'a b c', 'c b a');
152 REPLACE INTO t1(rowid, x, y) VALUES(22, 'd e f', 'f e d');
155 do_execsql_test 6.2 {
156 INSERT INTO t1(t1) VALUES('integrity-check')
159 do_execsql_test 6.3 {
160 REPLACE INTO t1(rowid, x, y) VALUES('22', 'l l l', 'l l l');
163 do_execsql_test 6.4 {
164 REPLACE INTO t1(x, y) VALUES('x y z', 'x y z');
167 do_execsql_test 6.5 {
168 INSERT INTO t1(t1) VALUES('integrity-check')
171 do_execsql_test 6.6 {
172 SELECT rowid, * FROM t1;
178 #-------------------------------------------------------------------------
182 do_execsql_test 7.0 {
183 CREATE VIRTUAL TABLE t1 USING fts5(x,y,z);
184 INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
188 set v [list aaa aab abc abcde b c d dd ddd dddd ddddd]
190 for {set j 0} {$j < 20} {incr j} {
191 lappend ret [lindex $v [expr int(rand()*[llength $v])]]
196 proc dump_structure {} {
197 db eval {SELECT fts5_decode(id, block) AS t FROM t1_data WHERE id=10} {
198 foreach lvl [lrange $t 1 end] {
199 set seg [string repeat . [expr [llength $lvl]-2]]
200 puts "[lrange $lvl 0 1] $seg"
205 for {set i 1} {$i <= 10} {incr i} {
207 for {set j 0} {$j < 10} {incr j} {
211 set rowid [expr int(rand() * 100)]
212 execsql { REPLACE INTO t1(rowid,x,y,z) VALUES($rowid, $x, $y, $z) }
214 execsql { INSERT INTO t1(t1) VALUES('integrity-check'); }
216 if {[set_test_counter errors]} break
219 #-------------------------------------------------------------------------
222 do_execsql_test 8.0 {
223 CREATE VIRTUAL TABLE t1 USING fts5(x, prefix="1,2,3");
224 INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
227 do_execsql_test 8.1 {
228 INSERT INTO t1 VALUES('the quick brown fox');
229 INSERT INTO t1(t1) VALUES('integrity-check');
233 #-------------------------------------------------------------------------
239 do_execsql_test 9.0 {
240 CREATE VIRTUAL TABLE t1 USING fts5(x,y,z, prefix="1,2,3");
241 INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
245 set v [list aaa aab abc abcde b c d dd ddd dddd ddddd]
247 for {set j 0} {$j < 20} {incr j} {
248 lappend ret [lindex $v [expr int(rand()*[llength $v])]]
253 proc dump_structure {} {
254 db eval {SELECT fts5_decode(id, block) AS t FROM t1_data WHERE id=10} {
255 foreach lvl [lrange $t 1 end] {
256 set seg [string repeat . [expr [llength $lvl]-2]]
257 puts "[lrange $lvl 0 1] $seg"
262 for {set i 1} {$i <= 10} {incr i} {
264 for {set j 0} {$j < 100} {incr j} {
268 set rowid [expr int(rand() * 100)]
269 execsql { REPLACE INTO t1(rowid,x,y,z) VALUES($rowid, $x, $y, $z) }
271 execsql { INSERT INTO t1(t1) VALUES('integrity-check'); }
273 if {[set_test_counter errors]} break
277 #-------------------------------------------------------------------------
280 do_execsql_test 10.0 {
281 CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
284 1 {g f d b f} {h h e i a}
285 2 {f i g j e} {i j c f f}
286 3 {e e i f a} {e h f d f}
287 4 {h j f j i} {h a c f j}
288 5 {d b j c g} {f e i b e}
289 6 {a j a e e} {j d f d e}
290 7 {g i j c h} {j d h c a}
291 8 {j j i d d} {e e d f b}
292 9 {c j j d c} {h j i f g}
293 10 {b f h i a} {c f b b j}
295 foreach {rowid x y} $d10 {
296 do_execsql_test 10.1.$rowid.1 { INSERT INTO t1 VALUES($x, $y) }
297 do_execsql_test 10.1.$rowid.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
299 foreach rowid {5 9 8 1 2 4 10 7 3 5 6} {
300 do_execsql_test 10.2.$rowid.1 { DELETE FROM t1 WHERE rowid = $rowid }
301 do_execsql_test 10.2.$rowid.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
303 foreach {rowid x y} $d10 {
304 do_execsql_test 10.3.$rowid.1 { INSERT INTO t1 VALUES($x, $y) }
305 do_execsql_test 10.3.$rowid.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
308 do_execsql_test 10.4.1 { DELETE FROM t1 }
309 do_execsql_test 10.4.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
311 #-------------------------------------------------------------------------
313 do_catchsql_test 11.1 {
314 CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL%);
315 } {1 {reserved fts5 column name: rank}}
316 do_catchsql_test 11.2 {
317 CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL%);
318 } {1 {reserved fts5 table name: rank}}
319 do_catchsql_test 11.3 {
320 CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL%);
321 } {1 {reserved fts5 column name: rowid}}
323 #-------------------------------------------------------------------------
325 do_execsql_test 12.1 {
326 CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL%);
329 do_catchsql_test 12.2 {
330 SELECT t2 FROM t2 WHERE t2 MATCH '*stuff'
331 } {1 {unknown special query: stuff}}
334 set res [db eval { SELECT t2 FROM t2 WHERE t2 MATCH '* reads ' }]
335 string is integer $res
338 #-------------------------------------------------------------------------
341 do_execsql_test 13.1 {
342 CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%);
343 INSERT INTO t1(rowid, x) VALUES(1, 'o n e'), (2, 't w o');
346 do_execsql_test 13.2 {
347 SELECT rowid FROM t1 WHERE t1 MATCH 'o';
350 do_execsql_test 13.4 {
351 DELETE FROM t1 WHERE rowid=2;
354 do_execsql_test 13.5 {
355 SELECT rowid FROM t1 WHERE t1 MATCH 'o';
358 do_execsql_test 13.6 {
359 SELECT rowid FROM t1 WHERE t1 MATCH '""';
362 #-------------------------------------------------------------------------
365 do_execsql_test 14.1 {
366 CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
367 INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
369 SELECT NULL, 'xyz xyz xyz xyz xyz xyz'
371 SELECT NULL, 'xyz xyz xyz xyz xyz xyz' FROM d
373 INSERT INTO t1 SELECT * FROM d LIMIT 200;
376 do_execsql_test 15.x {
377 INSERT INTO t1(t1) VALUES('integrity-check');
382 db eval { SELECT * FROM t1 WHERE t1 MATCH 'xyz' } {
385 CREATE TABLE t2(a, b);
396 db eval { SELECT * FROM t1 WHERE t1 MATCH 'xyz' } {
399 CREATE TABLE t2(a, b);
408 do_execsql_test 15.0 {
409 INSERT INTO t1(t1) VALUES('integrity-check');
411 sqlite3_db_config db DEFENSIVE 0
412 do_execsql_test 15.1 {
413 UPDATE t1_content SET c1 = 'xyz xyz xyz xyz xyz abc' WHERE rowid = 1;
415 do_catchsql_test 15.2 {
416 INSERT INTO t1(t1) VALUES('integrity-check');
417 } {1 {database disk image is malformed}}
419 #-------------------------------------------------------------------------
421 do_execsql_test 16.1 {
422 CREATE VIRTUAL TABLE n1 USING fts5(a);
423 INSERT INTO n1 VALUES('a b c d');
427 db eval { UPDATE n1_config SET v=50 WHERE k='version' }
428 set fd [db incrblob main n1_data block 10]
429 fconfigure $fd -encoding binary -translation binary
430 # puts -nonewline $fd "\x44\x45"
435 # This test case corrupts the structure record within the first invocation
436 # of function funk(). Which used to cause the bm25() function to throw an
437 # exception. But since bm25() can now used the cached structure record,
438 # it never sees the corruption introduced by funk() and so the following
439 # statement no longer fails.
441 do_catchsql_test 16.2 {
442 SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
444 # {1 {SQL logic error}}
446 #-------------------------------------------------------------------------
449 do_execsql_test 17.1 {
450 CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL%);
451 INSERT INTO b2 VALUES('a');
452 INSERT INTO b2 VALUES('b');
453 INSERT INTO b2 VALUES('c');
458 db eval { SELECT * FROM b2 ORDER BY rowid ASC } {
459 lappend res [execsql { SELECT * FROM b2 ORDER BY rowid ASC }]
462 } {{a b c} {a b c} {a b c}}
464 if {[string match n* %DETAIL%]==0} {
466 do_execsql_test 17.3 {
467 CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL%);
468 INSERT INTO c2 VALUES('x x x', 'x x x');
469 SELECT rowid FROM c2 WHERE c2 MATCH 'y:x';
473 #-------------------------------------------------------------------------
476 do_execsql_test 17.1 {
477 CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL%);
478 INSERT INTO uio VALUES(NULL);
479 INSERT INTO uio SELECT NULL FROM uio;
480 INSERT INTO uio SELECT NULL FROM uio;
481 INSERT INTO uio SELECT NULL FROM uio;
482 INSERT INTO uio SELECT NULL FROM uio;
483 INSERT INTO uio SELECT NULL FROM uio;
484 INSERT INTO uio SELECT NULL FROM uio;
485 INSERT INTO uio SELECT NULL FROM uio;
486 INSERT INTO uio SELECT NULL FROM uio;
487 SELECT count(*) FROM uio;
490 do_execsql_test 17.2 {
491 SELECT count(*) FROM uio WHERE rowid BETWEEN 8 AND 17
493 do_execsql_test 17.3 {
494 SELECT rowid FROM uio WHERE rowid BETWEEN 8 AND 17
495 } {8 9 10 11 12 13 14 15 16 17}
496 do_execsql_test 17.4 {
497 SELECT rowid FROM uio WHERE rowid BETWEEN 8 AND 17 ORDER BY rowid DESC
498 } {17 16 15 14 13 12 11 10 9 8}
499 do_execsql_test 17.5 {
500 SELECT count(*) FROM uio
503 do_execsql_test 17.6 {
504 INSERT INTO uio(rowid) VALUES(9223372036854775807);
505 INSERT INTO uio(rowid) VALUES(-9223372036854775808);
506 SELECT count(*) FROM uio;
508 do_execsql_test 17.7 {
509 SELECT min(rowid), max(rowid) FROM uio;
510 } {-9223372036854775808 9223372036854775807}
512 do_execsql_test 17.8 {
513 INSERT INTO uio DEFAULT VALUES;
514 SELECT min(rowid), max(rowid), count(*) FROM uio;
515 } {-9223372036854775808 9223372036854775807 259}
517 do_execsql_test 17.9 {
518 SELECT min(rowid), max(rowid), count(*) FROM uio WHERE rowid < 10;
519 } {-9223372036854775808 9 10}
521 #--------------------------------------------------------------------
523 do_execsql_test 18.1 {
524 CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
525 CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL%);
526 INSERT INTO t1 VALUES('abc*', NULL);
527 INSERT INTO t2 VALUES(1, 'abcdefg');
529 do_execsql_test 18.2 {
530 SELECT t1.rowid, t2.rowid FROM t1, t2 WHERE t2 MATCH t1.a AND t1.rowid = t2.c
532 do_execsql_test 18.3 {
533 SELECT t1.rowid, t2.rowid FROM t2, t1 WHERE t2 MATCH t1.a AND t1.rowid = t2.c
536 #--------------------------------------------------------------------
537 # fts5 table in the temp schema.
540 do_execsql_test 19.0 {
541 CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL%);
542 INSERT INTO t1 VALUES('x y z');
543 INSERT INTO t1 VALUES('w x 1');
544 SELECT rowid FROM t1 WHERE t1 MATCH 'x';
547 #--------------------------------------------------------------------
548 # Test that 6 and 7 byte varints can be read.
551 do_execsql_test 20.0 {
552 CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL%);
555 0 [expr 1<<36] [expr 2<<36] [expr 1<<43] [expr 2<<43]
559 execsql { INSERT INTO tmp(rowid, x) VALUES($id, 'x y z') }
561 execsql { SELECT rowid FROM tmp WHERE tmp MATCH 'y' }
564 #--------------------------------------------------------------------
565 # Test that a DROP TABLE may be executed within a transaction that
566 # writes to an FTS5 table.
568 do_execsql_test 21.0 {
569 CREATE TEMP TABLE t8(a, b);
570 CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL%);
573 do_execsql_test 21.1 {
575 INSERT INTO ft VALUES('a b c');
580 do_execsql_test 22.0 {
581 CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL%);
582 INSERT INTO t9(rowid, x) VALUES(2, 'bbb');
584 INSERT INTO t9(rowid, x) VALUES(1, 'aaa');
585 DELETE FROM t9 WHERE rowid = 2;
586 INSERT INTO t9(rowid, x) VALUES(3, 'bbb');
590 do_execsql_test 22.1 {
591 SELECT rowid FROM t9('a*')
594 #-------------------------------------------------------------------------
595 do_execsql_test 23.0 {
596 CREATE VIRTUAL TABLE t10 USING fts5(x, detail=%DETAIL%);
599 do_execsql_test 23.1 {
600 SELECT * FROM t11, t10 WHERE t11.x = t10.x AND t10.rowid IS NULL;
602 do_execsql_test 23.2 {
603 SELECT * FROM t11, t10 WHERE t10.rowid IS NULL;
606 #-------------------------------------------------------------------------
607 do_execsql_test 24.0 {
608 CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL%);
609 INSERT INTO t12 VALUES('aaaa');
611 do_execsql_test 24.1 {
613 DELETE FROM t12 WHERE rowid=1;
614 SELECT * FROM t12('aaaa');
615 INSERT INTO t12 VALUES('aaaa');
618 do_execsql_test 24.2 {
619 INSERT INTO t12(t12) VALUES('integrity-check');
621 do_execsql_test 24.3 {
622 SELECT * FROM t12('aaaa');
625 #-------------------------------------------------------------------------
626 do_execsql_test 25.0 {
627 CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL%);
629 do_execsql_test 25.1 {
631 INSERT INTO t13 VALUES('AAAA');
632 SELECT * FROM t13('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB*');