modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/fts5/test/fts5merge.test (about) 1 # 2014 Dec 20 2 # 3 # The author disclaims copyright to this source code. In place of 4 # a legal notice, here is a blessing: 5 # 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. 9 # 10 #*********************************************************************** 11 # 12 # Test that focus on incremental merges of segments. 13 # 14 15 source [file join [file dirname [info script]] fts5_common.tcl] 16 set testprefix fts5merge 17 18 # If SQLITE_ENABLE_FTS5 is defined, omit this file. 19 ifcapable !fts5 { 20 finish_test 21 return 22 } 23 24 db func repeat [list string repeat] 25 26 #------------------------------------------------------------------------- 27 # Create an fts index so that: 28 # 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. 32 # 33 # Then run ('merge', 1) until everything is completely merged. 34 # 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); 41 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; 44 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; 47 48 INSERT INTO x8(x8, rank) VALUES('usermerge', 2); 49 } 50 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 } 58 59 do_test $testname.x [list expr "$tn < 5"] 1 60 } 61 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 69 70 #------------------------------------------------------------------------- 71 # 72 proc do_merge2_test {testname nRow} { 73 db func rnddoc fts5_rnddoc 74 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 } 80 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 } {} 95 } 96 proc not_merged {tbl} { 97 set segs [fts5_level_segs $tbl] 98 foreach s $segs { if {$s>1} { return 1 } } 99 return 0 100 } 101 102 do_merge2_test 2.1 5 103 do_merge2_test 2.2 10 104 do_merge2_test 2.3 20 105 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. 110 # 111 db func rnddoc fts5_rnddoc 112 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)); 119 } 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} 127 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} 135 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} 143 144 #------------------------------------------------------------------------- 145 # 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] 149 } 150 db func mydoc mydoc 151 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 158 } 159 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 } 169 170 do_execsql_test 4.$tn.2 { 171 INSERT INTO x8(x8, rank) VALUES('merge', 1); 172 } 173 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 } 181 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 } 191 } 192 193 #------------------------------------------------------------------------- 194 # Test that the 'merge' command does not modify the database if there is 195 # no work to do. 196 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)); 210 } 211 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 } {} 221 222 223 #-------------------------------------------------------------------------- 224 # Test that running 'merge' on an empty database does not cause a 225 # problem. 226 # 227 reset_db 228 do_execsql_test 6.0 { 229 CREATE VIRTUAL TABLE g1 USING fts5(a, b); 230 } 231 do_execsql_test 6.1 { 232 INSERT INTO g1(g1, rank) VALUES('merge', 10); 233 } 234 do_execsql_test 6.2 { 235 INSERT INTO g1(g1, rank) VALUES('merge', -10); 236 } 237 do_execsql_test 6.3 { 238 INSERT INTO g1(g1) VALUES('integrity-check'); 239 } 240 241 242 243 finish_test