Snapshot of upstream SQLite 3.46.1
[sqlcipher.git] / ext / fts5 / test / fts5merge.test
blob3b86167b0d5bc65036e685fcde650eabde92d521
1 # 2014 Dec 20
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.
19 ifcapable !fts5 {
20   finish_test
21   return
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);
49   }
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');
55     }
56     if {$tn>5} break
57   }
59   do_test $testname.x [list expr "$tn < 5"] 1
62 do_merge1_test 1.1   1
63 do_merge1_test 1.2   2
64 do_merge1_test 1.3   3
65 do_merge1_test 1.4   4
66 do_merge1_test 1.5  10
67 do_merge1_test 1.6  20
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);
79   }
81   set ::nRow $nRow
82   do_test $testname.1 {
83     for {set i 0} {$i < $::nRow} {incr i} {
84       execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) }
85       while {[not_merged x8]} {
86         execsql {
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');
91         }
92       }
93     }
94   } {}
96 proc not_merged {tbl} {
97   set segs [fts5_level_segs $tbl]
98   foreach s $segs { if {$s>1} { return 1 } }
99   return 0
102 do_merge2_test 2.1    5
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));
120 do_test 3.2 {
121   execsql {
122     INSERT INTO x8(x8, rank) VALUES('usermerge', 4);
123     INSERT INTO x8(x8, rank) VALUES('merge', 1);
124   }
125   fts5_level_segs x8
126 } {2}
128 do_test 3.3 {
129   execsql {
130     INSERT INTO x8(x8, rank) VALUES('usermerge', 2);
131     INSERT INTO x8(x8, rank) VALUES('merge', 1);
132   }
133   fts5_level_segs x8
134 } {2 1}
136 do_test 3.4 {
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) }
140   }
141   fts5_level_segs x8
142 } {0 1}
144 #-------------------------------------------------------------------------
146 proc mydoc {} {
147   set x [lindex {a b c d e f g h i j} [expr int(rand()*10)]]
148   return [string repeat "$x " 30]
150 db func mydoc mydoc
152 proc mycount {} {
153   set res [list]
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}]
156   }
157   set res
160   #1 32
161 foreach {tn pgsz} {
162   2 1000
163 } {
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);
168   }
170   do_execsql_test 4.$tn.2 {
171     INSERT INTO x8(x8, rank) VALUES('merge', 1);
172   }
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);
180   }
182   set expect [mycount]
183     for {set i 0} {$i < 20} {incr i} {
184       do_test 4.$tn.4.$i {
185         execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1); }
186         mycount
187       } $expect
188       break
189     }
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
195 # no work to do. 
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));
212 do_test 5.2 {
213   while 1 {
214     set nChange [db total_changes]
215     execsql { INSERT INTO x9(x9, rank) VALUES('merge', 1); }
216     set nChange [expr [db total_changes] - $nChange]
217     #puts $nChange
218     if {$nChange<2} break
219   }
220 } {}
223 #--------------------------------------------------------------------------
224 # Test that running 'merge' on an empty database does not cause a 
225 # problem.
227 reset_db
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');
243 finish_test