Snapshot of upstream SQLite 3.46.1
[sqlcipher.git] / ext / fts5 / test / fts5integrity.test
blob5ed659b1fda89ce229e95b04482548bf72197bf3
1 # 2015 Jan 13
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.
19 ifcapable !fts5 {
20   finish_test
21   return
24 do_execsql_test 1.0 {
25   CREATE VIRTUAL TABLE xx USING fts5(x);
26   INSERT INTO xx VALUES('term');
28 do_execsql_test 1.1 {
29   INSERT INTO xx(xx) VALUES('integrity-check');
32 do_execsql_test 2.0 {
33   CREATE VIRTUAL TABLE yy USING fts5(x, prefix=1);
34   INSERT INTO yy VALUES('term');
36 do_execsql_test 2.1 {
37   INSERT INTO yy(yy) VALUES('integrity-check');
40 #--------------------------------------------------------------------
42 do_execsql_test 3.0 {
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.
61 do_execsql_test 4.0 {
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;
69 } {1 1 1 1 1}
70 do_execsql_test 4.1 { 
71   INSERT INTO aa(aa) VALUES('integrity-check'); 
74 sqlite3_db_config db DEFENSIVE 0
75 do_catchsql_test 4.2 { 
76   BEGIN;
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 { 
85   ROLLBACK;
86   BEGIN;
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 { 
92   ROLLBACK;
93   BEGIN;
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 { 
99   ROLLBACK;
100   BEGIN;
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}
107 #exit
109 execsql { ROLLBACK }
112 #-------------------------------------------------------------------------
113 # Test that integrity-check works on a reasonably large db with many
114 # different terms.
116 # Document generator command.
117 proc rnddoc {n} {
118   set doc [list]
119   for {set i 0} {$i<$n} {incr i} {
120     lappend doc [format %.5d [expr int(rand()*10000)]]
121   }
122   return $doc
124 db func rnddoc rnddoc
126 expr srand(0)
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');
156 do_test 5.4.1 {
157   set ok 0
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 }
163   }
164   set ok
165 } {10000}
167 do_test 5.4.2 {
168   set ok 0
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 }
174   }
175   set ok
176 } {100}
178 #-------------------------------------------------------------------------
179 # Similar to 5.*.
181 foreach {tn pgsz} {
182   1  32
183   2  36
184   3  40
185   4  44
186   5  48
187 } {
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)
195      FROM s;
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)
199      FROM s;
201     INSERT INTO hh(hh) VALUES('optimize');
202   }
204   do_test 6.$tn.2 {
205     set ok 0
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 }
211     }
212     set ok
213   } {1000}
216 #-------------------------------------------------------------------------
218 reset_db
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;
224 } {X'46F0'}
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 #-------------------------------------------------------------------------
242 # Ticket 7a458c2a5f4
244 reset_db
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 {
251   PRAGMA data_version
252 } {1}
253 do_execsql_test 8.2 {
254   INSERT INTO vt0(vt0) VALUES('integrity-check');
255   PRAGMA data_version;
256 } {1}
257 do_execsql_test 8.1 {
258   INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2);
261 #-------------------------------------------------------------------------
262 # Ticket [771fe617]
264 reset_db
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));
274 } {X'37'}
275 do_execsql_test 9.1.2 {
276   SELECT quote(x'37');
277 } {X'37'}
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 #-------------------------------------------------------------------------
288 reset_db
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');
296 } {0 {}}
297 do_catchsql_test 10.2 {
298   INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0);
299 } {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);
306 } {0 {}}
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);
315 } {0 {}}
316 do_catchsql_test 10.5.2 {
317   INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
318 } {0 {}}
319 do_catchsql_test 10.5.3 {
320   INSERT INTO vt0(vt0) VALUES('integrity-check');
321 } {0 {}}
323 reset_db
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');
329   SELECT c FROM t1;
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';
336 } {1}
338 do_execsql_test 11.2 {
339   PRAGMA integrity_check(t2);
340 } {ok}
341 db close
342 sqlite3 db test.db
344 # FIX ME?
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
348 # inverted index.
350 do_execsql_test 11.3 {
351   PRAGMA integrity_check(t2);
352 } {ok}
353 do_execsql_test 11.4 {
354   DROP TABLE t1;
355   PRAGMA integrity_check(t2);
356 } {ok}
358 #-------------------------------------------------------------------
359 reset_db
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
370 } {ok}
372 db close
373 sqlite3 db test.db -readonly 1
375 explain_i {
376   PRAGMA integrity_check
377   }
378 do_execsql_test 12.3 {
379   PRAGMA integrity_check
380 } {ok}
383 #-------------------------------------------------------------------
384 reset_db
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;
389 } {ok}
391 db close
392 sqlite3 db test.db
393 do_catchsql_test 13.2 {
394   PRAGMA integrity_check;
395 } {0 ok}
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)'
400   WHERE name = 't1';
403 db close
404 sqlite3 db test.db
405 breakpoint
406 do_catchsql_test 13.4 {
407   PRAGMA integrity_check;
408 } {1 {no such tokenizer: blah}}
411 finish_test