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 #***********************************************************************
12 # This file contains tests focused on the integrity-check procedure.
15 source [file join [file dirname [info script]] fts5_common.tcl]
16 set testprefix fts5integrity
18 # If SQLITE_ENABLE_FTS5 is defined, omit this file.
25 CREATE VIRTUAL TABLE xx USING fts5(x);
26 INSERT INTO xx VALUES('term');
29 INSERT INTO xx(xx) VALUES('integrity-check');
33 CREATE VIRTUAL TABLE yy USING fts5(x, prefix=1);
34 INSERT INTO yy VALUES('term');
37 INSERT INTO yy(yy) VALUES('integrity-check');
40 #--------------------------------------------------------------------
43 CREATE VIRTUAL TABLE zz USING fts5(z);
44 INSERT INTO zz(zz, rank) VALUES('pgsz', 32);
45 INSERT INTO zz VALUES('b b b b b b b b b b b b b b');
46 INSERT INTO zz SELECT z FROM zz;
47 INSERT INTO zz SELECT z FROM zz;
48 INSERT INTO zz SELECT z FROM zz;
49 INSERT INTO zz SELECT z FROM zz;
50 INSERT INTO zz SELECT z FROM zz;
51 INSERT INTO zz SELECT z FROM zz;
52 INSERT INTO zz(zz) VALUES('optimize');
55 do_execsql_test 3.1 { INSERT INTO zz(zz) VALUES('integrity-check'); }
57 #--------------------------------------------------------------------
58 # Mess around with a docsize record. And the averages record. Then
59 # check that integrity-check picks it up.
62 CREATE VIRTUAL TABLE aa USING fts5(zz);
63 INSERT INTO aa(zz) VALUES('a b c d e');
64 INSERT INTO aa(zz) VALUES('a b c d');
65 INSERT INTO aa(zz) VALUES('a b c');
66 INSERT INTO aa(zz) VALUES('a b');
67 INSERT INTO aa(zz) VALUES('a');
68 SELECT length(sz) FROM aa_docsize;
71 INSERT INTO aa(aa) VALUES('integrity-check');
74 sqlite3_db_config db DEFENSIVE 0
75 do_catchsql_test 4.2 {
77 UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3;
78 INSERT INTO aa(aa) VALUES('integrity-check');
79 } {1 {database disk image is malformed}}
80 do_execsql_test 4.2.1 {
81 PRAGMA integrity_check(aa);
82 } {{malformed inverted index for FTS5 table main.aa}}
84 do_catchsql_test 4.3 {
87 UPDATE aa_data SET block = X'44' WHERE rowid = 1;
88 INSERT INTO aa(aa) VALUES('integrity-check');
89 } {1 {database disk image is malformed}}
91 do_catchsql_test 4.4 {
94 INSERT INTO aa_docsize VALUES(23, X'04');
95 INSERT INTO aa(aa) VALUES('integrity-check');
96 } {1 {database disk image is malformed}}
98 do_catchsql_test 4.5 {
101 INSERT INTO aa_docsize VALUES(23, X'00');
102 INSERT INTO aa_content VALUES(23, '');
103 INSERT INTO aa(aa) VALUES('integrity-check');
104 } {1 {database disk image is malformed}}
106 #db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM zz_data} {puts $r}
112 #-------------------------------------------------------------------------
113 # Test that integrity-check works on a reasonably large db with many
116 # Document generator command.
119 for {set i 0} {$i<$n} {incr i} {
120 lappend doc [format %.5d [expr int(rand()*10000)]]
124 db func rnddoc rnddoc
127 do_execsql_test 5.0 {
128 CREATE VIRTUAL TABLE gg USING fts5(a, prefix="1,2,3");
129 INSERT INTO gg(gg, rank) VALUES('pgsz', 256);
130 INSERT INTO gg VALUES(rnddoc(20));
131 INSERT INTO gg SELECT rnddoc(20) FROM gg;
132 INSERT INTO gg SELECT rnddoc(20) FROM gg;
133 INSERT INTO gg SELECT rnddoc(20) FROM gg;
134 INSERT INTO gg SELECT rnddoc(20) FROM gg;
135 INSERT INTO gg SELECT rnddoc(20) FROM gg;
136 INSERT INTO gg SELECT rnddoc(20) FROM gg;
137 INSERT INTO gg SELECT rnddoc(20) FROM gg;
138 INSERT INTO gg SELECT rnddoc(20) FROM gg;
139 INSERT INTO gg SELECT rnddoc(20) FROM gg;
140 INSERT INTO gg SELECT rnddoc(20) FROM gg;
141 INSERT INTO gg SELECT rnddoc(20) FROM gg;
144 do_execsql_test 5.1 {
145 INSERT INTO gg(gg) VALUES('integrity-check');
148 do_execsql_test 5.2 {
149 INSERT INTO gg(gg) VALUES('optimize');
152 do_execsql_test 5.3 {
153 INSERT INTO gg(gg) VALUES('integrity-check');
158 for {set i 0} {$i < 10000} {incr i} {
159 set T [format %.5d $i]
160 set res [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC }]
161 set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }]
162 if {$res == [lsort -integer $res2]} { incr ok }
169 for {set i 0} {$i < 100} {incr i} {
170 set T "[format %.3d $i]*"
171 set res [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC }]
172 set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }]
173 if {$res == [lsort -integer $res2]} { incr ok }
178 #-------------------------------------------------------------------------
188 do_execsql_test 6.$tn.1 {
189 DROP TABLE IF EXISTS hh;
190 CREATE VIRTUAL TABLE hh USING fts5(y);
191 INSERT INTO hh(hh, rank) VALUES('pgsz', $pgsz);
193 WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999)
194 INSERT INTO hh SELECT printf('%.3d%.3d%.3d %.3d%.3d%.3d',i,i,i,i+1,i+1,i+1)
197 WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999)
198 INSERT INTO hh SELECT printf('%.3d%.3d%.3d %.3d%.3d%.3d',i,i,i,i+1,i+1,i+1)
201 INSERT INTO hh(hh) VALUES('optimize');
206 for {set i 0} {$i < 1000} {incr i} {
207 set T [format %.3d%.3d%.3d $i $i $i]
208 set res [db eval { SELECT rowid FROM hh($T) ORDER BY rowid ASC }]
209 set res2 [db eval { SELECT rowid FROM hh($T) ORDER BY rowid DESC }]
210 if {$res == [lsort -integer $res2]} { incr ok }
216 #-------------------------------------------------------------------------
219 do_execsql_test 7.0 {
220 PRAGMA encoding = 'UTF-16';
221 CREATE VIRTUAL TABLE vt0 USING fts5(c0);
222 INSERT INTO vt0 VALUES (x'46f0');
223 SELECT quote(c0) FROM vt0;
225 do_execsql_test 7.1 {
226 INSERT INTO vt0(vt0) VALUES('integrity-check');
228 do_execsql_test 7.2 {
229 INSERT INTO vt0(vt0) VALUES('rebuild');
231 do_execsql_test 7.3 {
232 INSERT INTO vt0(vt0) VALUES('integrity-check');
234 do_execsql_test 7.4 {
235 UPDATE vt0 SET c0='';
237 do_execsql_test 7.5 {
238 INSERT INTO vt0(vt0) VALUES('integrity-check');
241 #-------------------------------------------------------------------------
245 do_execsql_test 8.0 {
246 PRAGMA locking_mode = EXCLUSIVE;
247 PRAGMA journal_mode = PERSIST;
248 CREATE VIRTUAL TABLE vt0 USING fts5(c0);
249 } {exclusive persist}
250 do_execsql_test 8.1 {
253 do_execsql_test 8.2 {
254 INSERT INTO vt0(vt0) VALUES('integrity-check');
257 do_execsql_test 8.1 {
258 INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2);
261 #-------------------------------------------------------------------------
265 do_execsql_test 9.0 {
266 PRAGMA encoding = 'UTF16';
267 CREATE VIRTUAL TABLE vt0 USING fts5(c0);
270 #explain_i { SELECT quote(SUBSTR(x'37', 0)); }
271 #execsql { PRAGMA vdbe_trace = 1 }
272 do_execsql_test 9.1.1 {
273 SELECT quote(SUBSTR(x'37', 0));
275 do_execsql_test 9.1.2 {
279 do_execsql_test 9.2 {
280 INSERT INTO vt0 VALUES (SUBSTR(x'37', 0));
281 -- INSERT INTO vt0 VALUES (x'37');
283 do_execsql_test 9.3 {
284 INSERT INTO vt0(vt0) VALUES('integrity-check');
287 #-------------------------------------------------------------------------
289 do_execsql_test 10.0 {
290 CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b);
291 CREATE VIRTUAL TABLE vt0 USING fts5(a, b, content=t1);
292 INSERT INTO vt0(rowid, a, b) VALUES(1, 'abc', 'def');
294 do_catchsql_test 10.1 {
295 INSERT INTO vt0(vt0) VALUES('integrity-check');
297 do_catchsql_test 10.2 {
298 INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0);
300 do_catchsql_test 10.3 {
301 INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
302 } {1 {database disk image is malformed}}
303 do_catchsql_test 10.3 {
304 INSERT INTO t1 VALUES(1, 'abc', 'def');
305 INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
308 do_execsql_test 10.4 {
309 CREATE VIRTUAL TABLE vt1 USING fts5(a, b, content=);
310 INSERT INTO vt1(rowid, a, b) VALUES(1, 'abc', 'def');
313 do_catchsql_test 10.5.1 {
314 INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0);
316 do_catchsql_test 10.5.2 {
317 INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
319 do_catchsql_test 10.5.3 {
320 INSERT INTO vt0(vt0) VALUES('integrity-check');
324 proc slang {in} {return [string map {th d e eh} $in]}
325 db function slang -deterministic -innocuous slang
326 do_execsql_test 11.0 {
327 CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT AS (slang(b)));
328 INSERT INTO t1(b) VALUES('the quick fox jumps over the lazy brown dog');
330 } {{deh quick fox jumps ovehr deh lazy brown dog}}
332 do_execsql_test 11.1 {
333 CREATE VIRTUAL TABLE t2 USING fts5(content="t1", c);
334 INSERT INTO t2(t2) VALUES('rebuild');
335 SELECT rowid FROM t2 WHERE t2 MATCH 'deh';
338 do_execsql_test 11.2 {
339 PRAGMA integrity_check(t2);
346 # FTS5 integrity-check does not care if the content table is unreadable or
347 # does not exist. It only looks for internal inconsistencies in the
350 do_execsql_test 11.3 {
351 PRAGMA integrity_check(t2);
353 do_execsql_test 11.4 {
355 PRAGMA integrity_check(t2);
358 #-------------------------------------------------------------------
361 do_execsql_test 12.1 {
362 CREATE VIRTUAL TABLE x1 USING fts5(a, b);
363 INSERT INTO x1 VALUES('one', 'two');
364 INSERT INTO x1 VALUES('three', 'four');
365 INSERT INTO x1 VALUES('five', 'six');
368 do_execsql_test 12.2 {
369 PRAGMA integrity_check
373 sqlite3 db test.db -readonly 1
376 PRAGMA integrity_check
378 do_execsql_test 12.3 {
379 PRAGMA integrity_check
383 #-------------------------------------------------------------------
385 do_execsql_test 13.1 {
386 CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=ascii);
387 INSERT INTO t1 VALUES('a b c'), ('d e f');
388 PRAGMA integrity_check;
393 do_catchsql_test 13.2 {
394 PRAGMA integrity_check;
397 do_execsql_test 13.3 {
398 PRAGMA writable_schema = 1;
399 UPDATE sqlite_schema SET sql = 'CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=blah)'
406 do_catchsql_test 13.4 {
407 PRAGMA integrity_check;
408 } {1 {no such tokenizer: blah}}