diff options
Diffstat (limited to 'ext/fts5/test/fts5integrity.test')
-rw-r--r-- | ext/fts5/test/fts5integrity.test | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test new file mode 100644 index 0000000..1bb3675 --- /dev/null +++ b/ext/fts5/test/fts5integrity.test @@ -0,0 +1,384 @@ +# 2015 Jan 13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file contains tests focused on the integrity-check procedure. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5integrity + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE xx USING fts5(x); + INSERT INTO xx VALUES('term'); +} +do_execsql_test 1.1 { + INSERT INTO xx(xx) VALUES('integrity-check'); +} + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE yy USING fts5(x, prefix=1); + INSERT INTO yy VALUES('term'); +} +do_execsql_test 2.1 { + INSERT INTO yy(yy) VALUES('integrity-check'); +} + +#-------------------------------------------------------------------- +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE zz USING fts5(z); + INSERT INTO zz(zz, rank) VALUES('pgsz', 32); + INSERT INTO zz VALUES('b b b b b b b b b b b b b b'); + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz(zz) VALUES('optimize'); +} + +do_execsql_test 3.1 { INSERT INTO zz(zz) VALUES('integrity-check'); } + +#-------------------------------------------------------------------- +# Mess around with a docsize record. And the averages record. Then +# check that integrity-check picks it up. +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE aa USING fts5(zz); + INSERT INTO aa(zz) VALUES('a b c d e'); + INSERT INTO aa(zz) VALUES('a b c d'); + INSERT INTO aa(zz) VALUES('a b c'); + INSERT INTO aa(zz) VALUES('a b'); + INSERT INTO aa(zz) VALUES('a'); + SELECT length(sz) FROM aa_docsize; +} {1 1 1 1 1} +do_execsql_test 4.1 { + INSERT INTO aa(aa) VALUES('integrity-check'); +} + +sqlite3_db_config db DEFENSIVE 0 +do_catchsql_test 4.2 { + BEGIN; + UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3; + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} +do_execsql_test 4.2.1 { + PRAGMA integrity_check(aa); +} {{malformed inverted index for FTS5 table main.aa}} + +do_catchsql_test 4.3 { + ROLLBACK; + BEGIN; + UPDATE aa_data SET block = X'44' WHERE rowid = 1; + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +do_catchsql_test 4.4 { + ROLLBACK; + BEGIN; + INSERT INTO aa_docsize VALUES(23, X'04'); + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +do_catchsql_test 4.5 { + ROLLBACK; + BEGIN; + INSERT INTO aa_docsize VALUES(23, X'00'); + INSERT INTO aa_content VALUES(23, ''); + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM zz_data} {puts $r} +#exit + +execsql { ROLLBACK } + + +#------------------------------------------------------------------------- +# Test that integrity-check works on a reasonably large db with many +# different terms. + +# Document generator command. +proc rnddoc {n} { + set doc [list] + for {set i 0} {$i<$n} {incr i} { + lappend doc [format %.5d [expr int(rand()*10000)]] + } + return $doc +} +db func rnddoc rnddoc + +expr srand(0) +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE gg USING fts5(a, prefix="1,2,3"); + INSERT INTO gg(gg, rank) VALUES('pgsz', 256); + INSERT INTO gg VALUES(rnddoc(20)); + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; +} + +do_execsql_test 5.1 { + INSERT INTO gg(gg) VALUES('integrity-check'); +} + +do_execsql_test 5.2 { + INSERT INTO gg(gg) VALUES('optimize'); +} + +do_execsql_test 5.3 { + INSERT INTO gg(gg) VALUES('integrity-check'); +} + +do_test 5.4.1 { + set ok 0 + for {set i 0} {$i < 10000} {incr i} { + set T [format %.5d $i] + set res [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC }] + set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }] + if {$res == [lsort -integer $res2]} { incr ok } + } + set ok +} {10000} + +do_test 5.4.2 { + set ok 0 + for {set i 0} {$i < 100} {incr i} { + set T "[format %.3d $i]*" + set res [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC }] + set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }] + if {$res == [lsort -integer $res2]} { incr ok } + } + set ok +} {100} + +#------------------------------------------------------------------------- +# Similar to 5.*. +# +foreach {tn pgsz} { + 1 32 + 2 36 + 3 40 + 4 44 + 5 48 +} { + do_execsql_test 6.$tn.1 { + DROP TABLE IF EXISTS hh; + CREATE VIRTUAL TABLE hh USING fts5(y); + INSERT INTO hh(hh, rank) VALUES('pgsz', $pgsz); + + WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999) + INSERT INTO hh SELECT printf('%.3d%.3d%.3d %.3d%.3d%.3d',i,i,i,i+1,i+1,i+1) + FROM s; + + WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999) + INSERT INTO hh SELECT printf('%.3d%.3d%.3d %.3d%.3d%.3d',i,i,i,i+1,i+1,i+1) + FROM s; + + INSERT INTO hh(hh) VALUES('optimize'); + } + + do_test 6.$tn.2 { + set ok 0 + for {set i 0} {$i < 1000} {incr i} { + set T [format %.3d%.3d%.3d $i $i $i] + set res [db eval { SELECT rowid FROM hh($T) ORDER BY rowid ASC }] + set res2 [db eval { SELECT rowid FROM hh($T) ORDER BY rowid DESC }] + if {$res == [lsort -integer $res2]} { incr ok } + } + set ok + } {1000} +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 7.0 { + PRAGMA encoding = 'UTF-16'; + CREATE VIRTUAL TABLE vt0 USING fts5(c0); + INSERT INTO vt0 VALUES (x'46f0'); + SELECT quote(c0) FROM vt0; +} {X'46F0'} +do_execsql_test 7.1 { + INSERT INTO vt0(vt0) VALUES('integrity-check'); +} +do_execsql_test 7.2 { + INSERT INTO vt0(vt0) VALUES('rebuild'); +} +do_execsql_test 7.3 { + INSERT INTO vt0(vt0) VALUES('integrity-check'); +} +do_execsql_test 7.4 { + UPDATE vt0 SET c0=''; +} +do_execsql_test 7.5 { + INSERT INTO vt0(vt0) VALUES('integrity-check'); +} + +#------------------------------------------------------------------------- +# Ticket 7a458c2a5f4 +# +reset_db +do_execsql_test 8.0 { + PRAGMA locking_mode = EXCLUSIVE; + PRAGMA journal_mode = PERSIST; + CREATE VIRTUAL TABLE vt0 USING fts5(c0); +} {exclusive persist} +do_execsql_test 8.1 { + PRAGMA data_version +} {1} +do_execsql_test 8.2 { + INSERT INTO vt0(vt0) VALUES('integrity-check'); + PRAGMA data_version; +} {1} +do_execsql_test 8.1 { + INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2); +} + +#------------------------------------------------------------------------- +# Ticket [771fe617] +# +reset_db +do_execsql_test 9.0 { + PRAGMA encoding = 'UTF16'; + CREATE VIRTUAL TABLE vt0 USING fts5(c0); +} + +#explain_i { SELECT quote(SUBSTR(x'37', 0)); } +#execsql { PRAGMA vdbe_trace = 1 } +do_execsql_test 9.1.1 { + SELECT quote(SUBSTR(x'37', 0)); +} {X'37'} +do_execsql_test 9.1.2 { + SELECT quote(x'37'); +} {X'37'} + +do_execsql_test 9.2 { + INSERT INTO vt0 VALUES (SUBSTR(x'37', 0)); +-- INSERT INTO vt0 VALUES (x'37'); +} +do_execsql_test 9.3 { + INSERT INTO vt0(vt0) VALUES('integrity-check'); +} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 10.0 { + CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b); + CREATE VIRTUAL TABLE vt0 USING fts5(a, b, content=t1); + INSERT INTO vt0(rowid, a, b) VALUES(1, 'abc', 'def'); +} +do_catchsql_test 10.1 { + INSERT INTO vt0(vt0) VALUES('integrity-check'); +} {0 {}} +do_catchsql_test 10.2 { + INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0); +} {0 {}} +do_catchsql_test 10.3 { + INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1); +} {1 {database disk image is malformed}} +do_catchsql_test 10.3 { + INSERT INTO t1 VALUES(1, 'abc', 'def'); + INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1); +} {0 {}} + +do_execsql_test 10.4 { + CREATE VIRTUAL TABLE vt1 USING fts5(a, b, content=); + INSERT INTO vt1(rowid, a, b) VALUES(1, 'abc', 'def'); +} + +do_catchsql_test 10.5.1 { + INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0); +} {0 {}} +do_catchsql_test 10.5.2 { + INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1); +} {0 {}} +do_catchsql_test 10.5.3 { + INSERT INTO vt0(vt0) VALUES('integrity-check'); +} {0 {}} + +reset_db +proc slang {in} {return [string map {th d e eh} $in]} +db function slang -deterministic -innocuous slang +do_execsql_test 11.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT AS (slang(b))); + INSERT INTO t1(b) VALUES('the quick fox jumps over the lazy brown dog'); + SELECT c FROM t1; +} {{deh quick fox jumps ovehr deh lazy brown dog}} + +do_execsql_test 11.1 { + CREATE VIRTUAL TABLE t2 USING fts5(content="t1", c); + INSERT INTO t2(t2) VALUES('rebuild'); + SELECT rowid FROM t2 WHERE t2 MATCH 'deh'; +} {1} + +do_execsql_test 11.2 { + PRAGMA integrity_check(t2); +} {ok} +db close +sqlite3 db test.db + +# FIX ME? +# +# FTS5 integrity-check does not care if the content table is unreadable or +# does not exist. It only looks for internal inconsistencies in the +# inverted index. +# +do_execsql_test 11.3 { + PRAGMA integrity_check(t2); +} {ok} +do_execsql_test 11.4 { + DROP TABLE t1; + PRAGMA integrity_check(t2); +} {ok} + +#------------------------------------------------------------------- +reset_db + +do_execsql_test 12.1 { + CREATE VIRTUAL TABLE x1 USING fts5(a, b); + INSERT INTO x1 VALUES('one', 'two'); + INSERT INTO x1 VALUES('three', 'four'); + INSERT INTO x1 VALUES('five', 'six'); +} + +do_execsql_test 12.2 { + PRAGMA integrity_check +} {ok} + +db close +sqlite3 db test.db -readonly 1 + +explain_i { + PRAGMA integrity_check + } +do_execsql_test 12.3 { + PRAGMA integrity_check +} {ok} + + + +finish_test |