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 # Test that focus on incremental merges of segments.
15 source [file join [file dirname [info script]] fts5_common.tcl]
16 set testprefix fts5merge
18 # If SQLITE_ENABLE_FTS5 is defined, omit this file.
24 db func repeat [list string repeat]
26 #-------------------------------------------------------------------------
27 # Create an fts index so that:
29 # * the index consists of two top-level segments
30 # * each segment contains records related to $nRowPerSeg rows
31 # * all rows consist of tokens "x" and "y" only.
33 # Then run ('merge', 1) until everything is completely merged.
35 proc do_merge1_test {testname nRowPerSeg} {
36 set ::nRowPerSeg [expr $nRowPerSeg]
37 do_execsql_test $testname.0 {
38 DROP TABLE IF EXISTS x8;
39 CREATE VIRTUAL TABLE x8 USING fts5(i);
40 INSERT INTO x8(x8, rank) VALUES('pgsz', 32);
42 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg)
43 INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii;
45 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg)
46 INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii;
48 INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
51 for {set tn 1} {[lindex [fts5_level_segs x8] 0]>0} {incr tn} {
52 do_execsql_test $testname.$tn {
53 INSERT INTO x8(x8, rank) VALUES('merge', 1);
54 INSERT INTO x8(x8) VALUES('integrity-check');
59 do_test $testname.x [list expr "$tn < 5"] 1
68 do_merge1_test 1.7 100
70 #-------------------------------------------------------------------------
72 proc do_merge2_test {testname nRow} {
73 db func rnddoc fts5_rnddoc
75 do_execsql_test $testname.0 {
76 DROP TABLE IF EXISTS x8;
77 CREATE VIRTUAL TABLE x8 USING fts5(i);
78 INSERT INTO x8(x8, rank) VALUES('pgsz', 32);
83 for {set i 0} {$i < $::nRow} {incr i} {
84 execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) }
85 while {[not_merged x8]} {
87 INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
88 INSERT INTO x8(x8, rank) VALUES('merge', 1);
89 INSERT INTO x8(x8, rank) VALUES('usermerge', 16);
90 INSERT INTO x8(x8) VALUES('integrity-check');
96 proc not_merged {tbl} {
97 set segs [fts5_level_segs $tbl]
98 foreach s $segs { if {$s>1} { return 1 } }
103 do_merge2_test 2.2 10
104 do_merge2_test 2.3 20
106 #-------------------------------------------------------------------------
107 # Test that a merge will complete any merge that has already been
108 # started, even if the number of input segments is less than the current
109 # value of the 'usermerge' configuration parameter.
111 db func rnddoc fts5_rnddoc
113 do_execsql_test 3.1 {
114 DROP TABLE IF EXISTS x8;
115 CREATE VIRTUAL TABLE x8 USING fts5(i);
116 INSERT INTO x8(x8, rank) VALUES('pgsz', 32);
117 INSERT INTO x8 VALUES(rnddoc(100));
118 INSERT INTO x8 VALUES(rnddoc(100));
122 INSERT INTO x8(x8, rank) VALUES('usermerge', 4);
123 INSERT INTO x8(x8, rank) VALUES('merge', 1);
130 INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
131 INSERT INTO x8(x8, rank) VALUES('merge', 1);
137 execsql { INSERT INTO x8(x8, rank) VALUES('usermerge', 4) }
138 while {[not_merged x8]} {
139 execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1) }
144 #-------------------------------------------------------------------------
147 set x [lindex {a b c d e f g h i j} [expr int(rand()*10)]]
148 return [string repeat "$x " 30]
154 foreach x {a b c d e f g h i j} {
155 lappend res [db one {SELECT count(*) FROM x8 WHERE x8 MATCH $x}]
164 do_execsql_test 4.$tn.1 {
165 DROP TABLE IF EXISTS x8;
166 CREATE VIRTUAL TABLE x8 USING fts5(i);
167 INSERT INTO x8(x8, rank) VALUES('pgsz', $pgsz);
170 do_execsql_test 4.$tn.2 {
171 INSERT INTO x8(x8, rank) VALUES('merge', 1);
174 do_execsql_test 4.$tn.3 {
175 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100)
176 INSERT INTO x8 SELECT mydoc() FROM ii;
177 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100)
178 INSERT INTO x8 SELECT mydoc() FROM ii;
179 INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
183 for {set i 0} {$i < 20} {incr i} {
185 execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1); }
190 # db eval {SELECT fts5_decode(rowid, block) AS r FROM x8_data} { puts $r }
193 #-------------------------------------------------------------------------
194 # Test that the 'merge' command does not modify the database if there is
197 do_execsql_test 5.1 {
198 CREATE VIRTUAL TABLE x9 USING fts5(one, two);
199 INSERT INTO x9(x9, rank) VALUES('pgsz', 32);
200 INSERT INTO x9(x9, rank) VALUES('automerge', 2);
201 INSERT INTO x9(x9, rank) VALUES('usermerge', 2);
202 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
203 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
204 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
205 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
206 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
207 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
208 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
209 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100));
214 set nChange [db total_changes]
215 execsql { INSERT INTO x9(x9, rank) VALUES('merge', 1); }
216 set nChange [expr [db total_changes] - $nChange]
218 if {$nChange<2} break
223 #--------------------------------------------------------------------------
224 # Test that running 'merge' on an empty database does not cause a
228 do_execsql_test 6.0 {
229 CREATE VIRTUAL TABLE g1 USING fts5(a, b);
231 do_execsql_test 6.1 {
232 INSERT INTO g1(g1, rank) VALUES('merge', 10);
234 do_execsql_test 6.2 {
235 INSERT INTO g1(g1, rank) VALUES('merge', -10);
237 do_execsql_test 6.3 {
238 INSERT INTO g1(g1) VALUES('integrity-check');