1# 2012 March 06 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# This file implements regression tests for SQLite library. The 12# focus of this script is testing the incremental merge function. 13# 14 15set testdir [file dirname $argv0] 16source $testdir/tester.tcl 17source $testdir/fts3_common.tcl 18 19# If SQLITE_ENABLE_FTS3 is defined, omit this file. 20ifcapable !fts3 { 21 finish_test 22 return 23} 24 25proc fts3_integrity_check {tbl} { 26 db eval "INSERT INTO $tbl ($tbl) VALUES('integrity-check')" 27 return "ok" 28} 29 30foreach mod {fts3 fts4} { 31 set ::testprefix fts4merge-$mod 32 reset_db 33 34 #------------------------------------------------------------------------- 35 # Test cases 1.* 36 # 37 do_test 1.0 { fts3_build_db_1 -module $mod 1004 } {} 38 do_test 1.1 { fts3_integrity_check t1 } {ok} 39 do_execsql_test 1.1 { 40 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level 41 } { 42 0 {0 1 2 3 4 5 6 7 8 9 10 11} 43 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13} 44 2 {0 1 2} 45 } 46 47 for {set i 0} {$i<20} {incr i} { 48 do_execsql_test 1.2.$i.1 { INSERT INTO t1(t1) VALUES('merge=1') } 49 do_test 1.2.$i.2 { fts3_integrity_check t1 } ok 50 do_execsql_test 1.2.$i.3 { 51 SELECT docid FROM t1 WHERE t1 MATCH 'zero one two three' 52 } {123 132 213 231 312 321} 53 } 54 55 do_execsql_test 1.3 { 56 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level 57 } { 58 0 {0 1 2 3} 59 1 {0 1 2 3 4 5 6} 60 2 {0 1 2 3} 61 } 62 63 for {set i 0} {$i<100} {incr i} { 64 do_execsql_test 1.4.$i { INSERT INTO t1(t1) VALUES('merge=1,4') } 65 do_test 1.4.$i.2 { fts3_integrity_check t1 } ok 66 do_execsql_test 1.4.$i.3 { 67 SELECT docid FROM t1 WHERE t1 MATCH 'zero one two three' 68 } {123 132 213 231 312 321} 69 } 70 71 do_execsql_test 1.5 { 72 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level 73 } { 74 2 {0 1} 75 3 0 76 } 77 78 #------------------------------------------------------------------------- 79 # Test cases 2.* test that errors in the xxx part of the 'merge=xxx' are 80 # handled correctly. 81 # 82 do_execsql_test 2.0 "CREATE VIRTUAL TABLE t2 USING $mod" 83 84 foreach {tn arg} { 85 1 {merge=abc} 86 2 {merge=%%%} 87 3 {merge=,} 88 4 {merge=5,} 89 5 {merge=6,%} 90 6 {merge=6,six} 91 7 {merge=6,1} 92 8 {merge=6,0} 93 } { 94 do_catchsql_test 2.$tn { 95 INSERT INTO t2(t2) VALUES($arg); 96 } {1 {SQL logic error or missing database}} 97 } 98 99 #------------------------------------------------------------------------- 100 # Test cases 3.* 101 # 102 do_test 3.0 { 103 reset_db 104 execsql { PRAGMA page_size = 512 } 105 fts3_build_db_2 -module $mod 30040 106 } {} 107 do_test 3.1 { fts3_integrity_check t2 } {ok} 108 109 do_execsql_test 3.2 { 110 SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level 111 } { 112 0 {0 1 2 3 4 5 6} 113 1 {0 1 2 3 4} 114 2 {0 1 2 3 4} 115 3 {0 1 2 3 4 5 6} 116 } 117 118 do_execsql_test 3.3 { 119 INSERT INTO t2(t2) VALUES('merge=1000000,2'); 120 SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level 121 } { 122 0 0 123 2 0 124 3 0 125 4 0 126 6 0 127 } 128 129 #------------------------------------------------------------------------- 130 # Test cases 4.* 131 # 132 reset_db 133 do_execsql_test 4.1 " 134 PRAGMA page_size = 512; 135 CREATE VIRTUAL TABLE t4 USING $mod; 136 PRAGMA main.page_size; 137 " {512} 138 139 do_test 4.2 { 140 foreach x {a c b d e f g h i j k l m n o p} { 141 execsql "INSERT INTO t4 VALUES('[string repeat $x 600]')" 142 } 143 execsql {SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level} 144 } {0 {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15}} 145 146 foreach {tn expect} { 147 1 "0 {0 1 2 3 4 5 6 7 8 9 10 11 12 13} 1 0" 148 2 "0 {0 1 2 3 4 5 6 7 8 9 10 11 12} 1 0" 149 3 "0 {0 1 2 3 4 5 6 7 8 9 10 11} 1 0" 150 4 "0 {0 1 2 3 4 5 6 7 8 9 10} 1 0" 151 5 "0 {0 1 2 3 4 5 6 7 8 9} 1 0" 152 6 "0 {0 1 2 3 4 5 6 7 8} 1 0" 153 7 "0 {0 1 2 3 4 5 6 7} 1 0" 154 8 "0 {0 1 2 3 4 5 6} 1 0" 155 9 "0 {0 1 2 3 4 5} 1 0" 156 } { 157 do_execsql_test 4.3.$tn { 158 INSERT INTO t4(t4) VALUES('merge=1,16'); 159 SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level; 160 } $expect 161 } 162 163 do_execsql_test 4.4.1 { 164 SELECT quote(value) FROM t4_stat WHERE rowid=1 165 } {X'0006'} 166 167 do_execsql_test 4.4.2 { 168 DELETE FROM t4_stat WHERE rowid=1; 169 INSERT INTO t4(t4) VALUES('merge=1,12'); 170 SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level; 171 } "0 {0 1 2 3 4 5} 1 0" 172 173 174 #------------------------------------------------------------------------- 175 # Test cases 5.* 176 # 177 # Test that if a crisis-merge occurs that disrupts an ongoing incremental 178 # merge, the next call to "merge=A,B" identifies this and starts a new 179 # incremental merge. There are two scenarios: 180 # 181 # * There are less segments on the input level that the disrupted 182 # incremental merge operated on, or 183 # 184 # * Sufficient segments exist on the input level but the segments 185 # contain keys smaller than the largest key in the potential output 186 # segment. 187 # 188 do_test 5.1 { 189 reset_db 190 fts3_build_db_1 -module $mod 1000 191 } {} 192 193 do_execsql_test 5.2 { 194 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level; 195 } { 196 0 {0 1 2 3 4 5 6 7} 197 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13} 198 2 {0 1 2} 199 } 200 201 do_execsql_test 5.3 { 202 INSERT INTO t1(t1) VALUES('merge=1,5'); 203 INSERT INTO t1(t1) VALUES('merge=1,5'); 204 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level; 205 } { 206 0 {0 1 2} 207 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14} 208 2 {0 1 2 3} 209 } 210 211 do_execsql_test 5.4 {SELECT quote(value) from t1_stat WHERE rowid=1} {X'0105'} 212 do_test 5.5 { 213 foreach docid [execsql {SELECT docid FROM t1}] { 214 execsql {INSERT INTO t1 SELECT * FROM t1 WHERE docid=$docid} 215 } 216 } {} 217 218 do_execsql_test 5.6 {SELECT quote(value) from t1_stat WHERE rowid=1} {X'0105'} 219 220 do_execsql_test 5.7 { 221 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level; 222 SELECT quote(value) from t1_stat WHERE rowid=1; 223 } { 224 0 {0 1 2 3 4 5 6 7 8 9 10} 225 1 {0 1 2 3 4 5 6 7 8 9 10 11 12} 226 2 {0 1 2 3 4 5 6 7} 227 X'0105' 228 } 229 230 do_execsql_test 5.8 { 231 INSERT INTO t1(t1) VALUES('merge=1,6'); 232 INSERT INTO t1(t1) VALUES('merge=1,6'); 233 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level; 234 SELECT quote(value) from t1_stat WHERE rowid=1; 235 } { 236 0 {0 1 2 3 4} 237 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13} 238 2 {0 1 2 3 4 5 6 7 8} X'0106' 239 } 240 241 do_test 5.8.1 { fts3_integrity_check t1 } ok 242 243 do_test 5.9 { 244 set L [expr 16*16*7 + 16*3 + 12] 245 foreach docid [execsql { 246 SELECT docid FROM t1 UNION ALL SELECT docid FROM t1 LIMIT $L 247 }] { 248 execsql {INSERT INTO t1 SELECT * FROM t1 WHERE docid=$docid} 249 } 250 } {} 251 252 do_execsql_test 5.10 { 253 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level; 254 SELECT quote(value) from t1_stat WHERE rowid=1; 255 } { 256 0 0 1 {0 1} 2 0 3 0 X'0106' 257 } 258 259 do_execsql_test 5.11 { 260 INSERT INTO t1(t1) VALUES('merge=1,6'); 261 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level; 262 SELECT quote(value) from t1_stat WHERE rowid=1; 263 } { 264 0 0 1 {0 1} 2 0 3 0 X'' 265 } 266 267 #------------------------------------------------------------------------- 268 # Test cases 6.* 269 # 270 # At one point the following test caused an assert() to fail (because the 271 # second 'merge=1,2' operation below actually "merges" a single input 272 # segment, which was unexpected). 273 # 274 do_test 6.1 { 275 reset_db 276 set a [string repeat a 900] 277 set b [string repeat b 900] 278 set c [string repeat c 900] 279 set d [string repeat d 900] 280 281 execsql "CREATE VIRTUAL TABLE t1 USING $mod" 282 execsql { 283 BEGIN; 284 INSERT INTO t1 VALUES($a); 285 INSERT INTO t1 VALUES($b); 286 COMMIT; 287 BEGIN; 288 INSERT INTO t1 VALUES($c); 289 INSERT INTO t1 VALUES($d); 290 COMMIT; 291 } 292 293 execsql { 294 INSERT INTO t1(t1) VALUES('merge=1,2'); 295 INSERT INTO t1(t1) VALUES('merge=1,2'); 296 } 297 } {} 298 299 #------------------------------------------------------------------------- 300 # Test cases 7.* 301 # 302 # Test that the value returned by sqlite3_total_changes() increases by 303 # 1 following a no-op "merge=A,B", or by more than 1 if actual work is 304 # performed. 305 # 306 do_test 7.0 { 307 reset_db 308 fts3_build_db_1 -module $mod 1000 309 } {} 310 311 do_execsql_test 7.1 { 312 SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level 313 } { 314 0 {0 1 2 3 4 5 6 7} 315 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13} 316 2 {0 1 2} 317 } 318 do_test 7.2 { 319 set x [db total_changes] 320 execsql { INSERT INTO t1(t1) VALUES('merge=2,10') } 321 expr { ([db total_changes] - $x)>1 } 322 } {1} 323 do_test 7.3 { 324 set x [db total_changes] 325 execsql { INSERT INTO t1(t1) VALUES('merge=200,10') } 326 expr { ([db total_changes] - $x)>1 } 327 } {1} 328 do_test 7.4 { 329 set x [db total_changes] 330 execsql { INSERT INTO t1(t1) VALUES('merge=200,10') } 331 expr { ([db total_changes] - $x)>1 } 332 } {0} 333 do_test 7.5 { 334 set x [db total_changes] 335 execsql { INSERT INTO t1(t1) VALUES('merge=200,10') } 336 expr { ([db total_changes] - $x)>1 } 337 } {0} 338 339} 340 341finish_test 342