OLD | NEW |
| (Empty) |
1 # 2008 June 26 | |
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 focus | |
12 # of this script is testing the FTS3 module's optimize() function. | |
13 # | |
14 | |
15 set testdir [file dirname $argv0] | |
16 source $testdir/tester.tcl | |
17 source $testdir/fts3_common.tcl | |
18 | |
19 # If SQLITE_ENABLE_FTS3 is not defined, omit this file. | |
20 ifcapable !fts3 { | |
21 finish_test | |
22 return | |
23 } | |
24 | |
25 #************************************************************************* | |
26 # Utility function to check for the expected terms in the segment | |
27 # level/index. _all version does same but for entire index. | |
28 proc check_terms {test level index terms} { | |
29 set where "level = $level AND idx = $index" | |
30 do_test $test.terms [list fts3_terms t1 $where] $terms | |
31 } | |
32 proc check_terms_all {test terms} { | |
33 do_test $test.terms [list fts3_terms t1 1] $terms | |
34 } | |
35 | |
36 # Utility function to check for the expected doclist for the term in | |
37 # segment level/index. _all version does same for entire index. | |
38 proc check_doclist {test level index term doclist} { | |
39 set where "level = $level AND idx = $index" | |
40 do_test $test.doclist [list fts3_doclist t1 $term $where] $doclist | |
41 } | |
42 proc check_doclist_all {test term doclist} { | |
43 do_test $test.doclist [list fts3_doclist t1 $term 1] $doclist | |
44 } | |
45 | |
46 #************************************************************************* | |
47 # Test results when all rows are deleted and one is added back. | |
48 # Previously older segments would continue to exist, but now the index | |
49 # should be dropped when the table is empty. The results should look | |
50 # exactly like we never added the earlier rows in the first place. | |
51 db eval { | |
52 DROP TABLE IF EXISTS t1; | |
53 CREATE VIRTUAL TABLE t1 USING fts3(c); | |
54 INSERT INTO t1 (docid, c) VALUES (1, 'This is a test'); | |
55 INSERT INTO t1 (docid, c) VALUES (2, 'That was a test'); | |
56 INSERT INTO t1 (docid, c) VALUES (3, 'This is a test'); | |
57 DELETE FROM t1 WHERE 1=1; -- Delete each row rather than dropping table. | |
58 INSERT INTO t1 (docid, c) VALUES (1, 'This is a test'); | |
59 } | |
60 | |
61 # Should be a single initial segment. | |
62 do_test fts3d-1.segments { | |
63 execsql { | |
64 SELECT level, idx FROM t1_segdir ORDER BY level, idx; | |
65 } | |
66 } {0 0} | |
67 do_test fts3d-1.matches { | |
68 execsql { | |
69 SELECT OFFSETS(t1) FROM t1 | |
70 WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid; | |
71 } | |
72 } {{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}} | |
73 | |
74 check_terms_all fts3d-1.1 {a is test this} | |
75 check_doclist_all fts3d-1.1.1 a {[1 0[2]]} | |
76 check_doclist_all fts3d-1.1.2 is {[1 0[1]]} | |
77 check_doclist_all fts3d-1.1.3 test {[1 0[3]]} | |
78 check_doclist_all fts3d-1.1.4 this {[1 0[0]]} | |
79 | |
80 check_terms fts3d-1.2 0 0 {a is test this} | |
81 check_doclist fts3d-1.2.1 0 0 a {[1 0[2]]} | |
82 check_doclist fts3d-1.2.2 0 0 is {[1 0[1]]} | |
83 check_doclist fts3d-1.2.3 0 0 test {[1 0[3]]} | |
84 check_doclist fts3d-1.2.4 0 0 this {[1 0[0]]} | |
85 | |
86 #************************************************************************* | |
87 # Test results when everything is optimized manually. | |
88 # NOTE(shess): This is a copy of fts3c-1.3. I've pulled a copy here | |
89 # because fts3d-2 and fts3d-3 should have identical results. | |
90 db eval { | |
91 DROP TABLE IF EXISTS t1; | |
92 CREATE VIRTUAL TABLE t1 USING fts3(c); | |
93 INSERT INTO t1 (docid, c) VALUES (1, 'This is a test'); | |
94 INSERT INTO t1 (docid, c) VALUES (2, 'That was a test'); | |
95 INSERT INTO t1 (docid, c) VALUES (3, 'This is a test'); | |
96 DELETE FROM t1 WHERE docid IN (1,3); | |
97 DROP TABLE IF EXISTS t1old; | |
98 ALTER TABLE t1 RENAME TO t1old; | |
99 CREATE VIRTUAL TABLE t1 USING fts3(c); | |
100 INSERT INTO t1 (docid, c) SELECT docid, c FROM t1old; | |
101 DROP TABLE t1old; | |
102 } | |
103 | |
104 # Should be a single optimal segment with the same logical results. | |
105 do_test fts3d-2.segments { | |
106 execsql { | |
107 SELECT level, idx FROM t1_segdir ORDER BY level, idx; | |
108 } | |
109 } {0 0} | |
110 do_test fts3d-2.matches { | |
111 execsql { | |
112 SELECT OFFSETS(t1) FROM t1 | |
113 WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid; | |
114 } | |
115 } {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}} | |
116 | |
117 check_terms_all fts3d-2.1 {a test that was} | |
118 check_doclist_all fts3d-2.1.1 a {[2 0[2]]} | |
119 check_doclist_all fts3d-2.1.2 test {[2 0[3]]} | |
120 check_doclist_all fts3d-2.1.3 that {[2 0[0]]} | |
121 check_doclist_all fts3d-2.1.4 was {[2 0[1]]} | |
122 | |
123 check_terms fts3d-2.2 0 0 {a test that was} | |
124 check_doclist fts3d-2.2.1 0 0 a {[2 0[2]]} | |
125 check_doclist fts3d-2.2.2 0 0 test {[2 0[3]]} | |
126 check_doclist fts3d-2.2.3 0 0 that {[2 0[0]]} | |
127 check_doclist fts3d-2.2.4 0 0 was {[2 0[1]]} | |
128 | |
129 #************************************************************************* | |
130 # Test results when everything is optimized via optimize(). | |
131 db eval { | |
132 DROP TABLE IF EXISTS t1; | |
133 CREATE VIRTUAL TABLE t1 USING fts3(c); | |
134 INSERT INTO t1 (docid, c) VALUES (1, 'This is a test'); | |
135 INSERT INTO t1 (docid, c) VALUES (2, 'That was a test'); | |
136 INSERT INTO t1 (docid, c) VALUES (3, 'This is a test'); | |
137 DELETE FROM t1 WHERE docid IN (1,3); | |
138 SELECT OPTIMIZE(t1) FROM t1 LIMIT 1; | |
139 } | |
140 | |
141 # Should be a single optimal segment with the same logical results. | |
142 do_test fts3d-3.segments { | |
143 execsql { | |
144 SELECT level, idx FROM t1_segdir ORDER BY level, idx; | |
145 } | |
146 } {0 0} | |
147 do_test fts3d-3.matches { | |
148 execsql { | |
149 SELECT OFFSETS(t1) FROM t1 | |
150 WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid; | |
151 } | |
152 } {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}} | |
153 | |
154 check_terms_all fts3d-3.1 {a test that was} | |
155 check_doclist_all fts3d-3.1.1 a {[2 0[2]]} | |
156 check_doclist_all fts3d-3.1.2 test {[2 0[3]]} | |
157 check_doclist_all fts3d-3.1.3 that {[2 0[0]]} | |
158 check_doclist_all fts3d-3.1.4 was {[2 0[1]]} | |
159 | |
160 check_terms fts3d-3.2 0 0 {a test that was} | |
161 check_doclist fts3d-3.2.1 0 0 a {[2 0[2]]} | |
162 check_doclist fts3d-3.2.2 0 0 test {[2 0[3]]} | |
163 check_doclist fts3d-3.2.3 0 0 that {[2 0[0]]} | |
164 check_doclist fts3d-3.2.4 0 0 was {[2 0[1]]} | |
165 | |
166 #************************************************************************* | |
167 # Test optimize() against a table involving segment merges. | |
168 # NOTE(shess): Since there's no transaction, each of the INSERT/UPDATE | |
169 # statements generates a segment. | |
170 db eval { | |
171 DROP TABLE IF EXISTS t1; | |
172 CREATE VIRTUAL TABLE t1 USING fts3(c); | |
173 | |
174 INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test'); | |
175 INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test'); | |
176 INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test'); | |
177 | |
178 UPDATE t1 SET c = 'This is a test one' WHERE rowid = 1; | |
179 UPDATE t1 SET c = 'That was a test one' WHERE rowid = 2; | |
180 UPDATE t1 SET c = 'This is a test one' WHERE rowid = 3; | |
181 | |
182 UPDATE t1 SET c = 'This is a test two' WHERE rowid = 1; | |
183 UPDATE t1 SET c = 'That was a test two' WHERE rowid = 2; | |
184 UPDATE t1 SET c = 'This is a test two' WHERE rowid = 3; | |
185 | |
186 UPDATE t1 SET c = 'This is a test three' WHERE rowid = 1; | |
187 UPDATE t1 SET c = 'That was a test three' WHERE rowid = 2; | |
188 UPDATE t1 SET c = 'This is a test three' WHERE rowid = 3; | |
189 | |
190 UPDATE t1 SET c = 'This is a test four' WHERE rowid = 1; | |
191 UPDATE t1 SET c = 'That was a test four' WHERE rowid = 2; | |
192 UPDATE t1 SET c = 'This is a test four' WHERE rowid = 3; | |
193 | |
194 UPDATE t1 SET c = 'This is a test' WHERE rowid = 1; | |
195 UPDATE t1 SET c = 'That was a test' WHERE rowid = 2; | |
196 UPDATE t1 SET c = 'This is a test' WHERE rowid = 3; | |
197 } | |
198 | |
199 # 2 segments in level 0, 1 in level 1 (18 segments created, 16 | |
200 # merged). | |
201 do_test fts3d-4.segments { | |
202 execsql { | |
203 SELECT level, idx FROM t1_segdir ORDER BY level, idx; | |
204 } | |
205 } {0 0 0 1 1 0} | |
206 | |
207 do_test fts3d-4.matches { | |
208 execsql { | |
209 SELECT OFFSETS(t1) FROM t1 | |
210 WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid; | |
211 } | |
212 } [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \ | |
213 {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \ | |
214 {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}] | |
215 | |
216 puts [db eval {SELECT c FROM t1 } ] | |
217 check_terms_all fts3d-4.1 {a four is test that this was} | |
218 check_doclist_all fts3d-4.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]} | |
219 check_doclist_all fts3d-4.1.2 four {} | |
220 check_doclist_all fts3d-4.1.3 is {[1 0[1]] [3 0[1]]} | |
221 #check_doclist_all fts3d-4.1.4 one {} | |
222 check_doclist_all fts3d-4.1.5 test {[1 0[3]] [2 0[3]] [3 0[3]]} | |
223 check_doclist_all fts3d-4.1.6 that {[2 0[0]]} | |
224 check_doclist_all fts3d-4.1.7 this {[1 0[0]] [3 0[0]]} | |
225 #check_doclist_all fts3d-4.1.8 three {} | |
226 #check_doclist_all fts3d-4.1.9 two {} | |
227 check_doclist_all fts3d-4.1.10 was {[2 0[1]]} | |
228 | |
229 check_terms fts3d-4.2 0 0 {a four test that was} | |
230 check_doclist fts3d-4.2.1 0 0 a {[2 0[2]]} | |
231 check_doclist fts3d-4.2.2 0 0 four {[2]} | |
232 check_doclist fts3d-4.2.3 0 0 test {[2 0[3]]} | |
233 check_doclist fts3d-4.2.4 0 0 that {[2 0[0]]} | |
234 check_doclist fts3d-4.2.5 0 0 was {[2 0[1]]} | |
235 | |
236 check_terms fts3d-4.3 0 1 {a four is test this} | |
237 check_doclist fts3d-4.3.1 0 1 a {[3 0[2]]} | |
238 check_doclist fts3d-4.3.2 0 1 four {[3]} | |
239 check_doclist fts3d-4.3.3 0 1 is {[3 0[1]]} | |
240 check_doclist fts3d-4.3.4 0 1 test {[3 0[3]]} | |
241 check_doclist fts3d-4.3.5 0 1 this {[3 0[0]]} | |
242 | |
243 check_terms fts3d-4.4 1 0 {a four is test that this was} | |
244 check_doclist fts3d-4.4.1 1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]} | |
245 check_doclist fts3d-4.4.2 1 0 four {[2 0[4]] [3 0[4]]} | |
246 check_doclist fts3d-4.4.3 1 0 is {[1 0[1]] [3 0[1]]} | |
247 #check_doclist fts3d-4.4.4 1 0 one {[1] [2] [3]} | |
248 check_doclist fts3d-4.4.5 1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]} | |
249 check_doclist fts3d-4.4.6 1 0 that {[2 0[0]]} | |
250 check_doclist fts3d-4.4.7 1 0 this {[1 0[0]] [3 0[0]]} | |
251 #check_doclist fts3d-4.4.8 1 0 three {[1] [2] [3]} | |
252 #check_doclist fts3d-4.4.9 1 0 two {[1] [2] [3]} | |
253 check_doclist fts3d-4.4.10 1 0 was {[2 0[1]]} | |
254 | |
255 # Optimize should leave the result in the level of the highest-level | |
256 # prior segment. | |
257 do_test fts3d-4.5 { | |
258 execsql { | |
259 SELECT OPTIMIZE(t1) FROM t1 LIMIT 1; | |
260 SELECT level, idx FROM t1_segdir ORDER BY level, idx; | |
261 } | |
262 } {{Index optimized} 1 0} | |
263 | |
264 # Identical to fts3d-4.matches. | |
265 do_test fts3d-4.5.matches { | |
266 execsql { | |
267 SELECT OFFSETS(t1) FROM t1 | |
268 WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid; | |
269 } | |
270 } [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \ | |
271 {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \ | |
272 {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}] | |
273 | |
274 check_terms_all fts3d-4.5.1 {a is test that this was} | |
275 check_doclist_all fts3d-4.5.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]} | |
276 check_doclist_all fts3d-4.5.1.2 is {[1 0[1]] [3 0[1]]} | |
277 check_doclist_all fts3d-4.5.1.3 test {[1 0[3]] [2 0[3]] [3 0[3]]} | |
278 check_doclist_all fts3d-4.5.1.4 that {[2 0[0]]} | |
279 check_doclist_all fts3d-4.5.1.5 this {[1 0[0]] [3 0[0]]} | |
280 check_doclist_all fts3d-4.5.1.6 was {[2 0[1]]} | |
281 | |
282 check_terms fts3d-4.5.2 1 0 {a is test that this was} | |
283 check_doclist fts3d-4.5.2.1 1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]} | |
284 check_doclist fts3d-4.5.2.2 1 0 is {[1 0[1]] [3 0[1]]} | |
285 check_doclist fts3d-4.5.2.3 1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]} | |
286 check_doclist fts3d-4.5.2.4 1 0 that {[2 0[0]]} | |
287 check_doclist fts3d-4.5.2.5 1 0 this {[1 0[0]] [3 0[0]]} | |
288 check_doclist fts3d-4.5.2.6 1 0 was {[2 0[1]]} | |
289 | |
290 # Re-optimizing does nothing. | |
291 do_test fts3d-5.0 { | |
292 execsql { | |
293 SELECT OPTIMIZE(t1) FROM t1 LIMIT 1; | |
294 SELECT level, idx FROM t1_segdir ORDER BY level, idx; | |
295 } | |
296 } {{Index already optimal} 1 0} | |
297 | |
298 # Even if we move things around, still does nothing. | |
299 do_test fts3d-5.1 { | |
300 execsql { | |
301 UPDATE t1_segdir SET level = 2 WHERE level = 1 AND idx = 0; | |
302 SELECT OPTIMIZE(t1) FROM t1 LIMIT 1; | |
303 SELECT level, idx FROM t1_segdir ORDER BY level, idx; | |
304 } | |
305 } {{Index already optimal} 2 0} | |
306 | |
307 | |
308 # ALTER TABLE RENAME should work regardless of the database encoding. | |
309 # | |
310 do_test fts3d-6.0 { | |
311 db close | |
312 forcedelete test.db | |
313 sqlite3 db test.db | |
314 db eval { | |
315 PRAGMA encoding=UTF8; | |
316 CREATE VIRTUAL TABLE fts USING fts3(a,b,c); | |
317 SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; | |
318 } | |
319 } {fts_content fts_segdir fts_segments} | |
320 do_test fts3d-6.1 { | |
321 db eval { | |
322 ALTER TABLE fts RENAME TO xyz; | |
323 SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; | |
324 } | |
325 } {xyz_content xyz_segdir xyz_segments} | |
326 do_test fts3d-6.2 { | |
327 db close | |
328 forcedelete test.db | |
329 sqlite3 db test.db | |
330 db eval { | |
331 PRAGMA encoding=UTF16le; | |
332 CREATE VIRTUAL TABLE fts USING fts3(a,b,c); | |
333 SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; | |
334 } | |
335 } {fts_content fts_segdir fts_segments} | |
336 do_test fts3d-6.3 { | |
337 db eval { | |
338 ALTER TABLE fts RENAME TO xyz; | |
339 SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; | |
340 } | |
341 } {xyz_content xyz_segdir xyz_segments} | |
342 do_test fts3d-6.4 { | |
343 db close | |
344 forcedelete test.db | |
345 sqlite3 db test.db | |
346 db eval { | |
347 PRAGMA encoding=UTF16be; | |
348 CREATE VIRTUAL TABLE fts USING fts3(a,b,c); | |
349 SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; | |
350 } | |
351 } {fts_content fts_segdir fts_segments} | |
352 do_test fts3d-6.5 { | |
353 db eval { | |
354 ALTER TABLE fts RENAME TO xyz; | |
355 SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; | |
356 } | |
357 } {xyz_content xyz_segdir xyz_segments} | |
358 | |
359 # ALTER TABLE RENAME on an FTS3 table following an incr-merge op. | |
360 # | |
361 do_test fts3d-6.6 { | |
362 execsql { INSERT INTO xyz(xyz) VALUES('merge=2,2') } | |
363 sqlite3 db test.db | |
364 execsql { | |
365 ALTER TABLE xyz RENAME TO ott; | |
366 SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; | |
367 } | |
368 } {ott_content ott_segdir ott_segments ott_stat} | |
369 | |
370 | |
371 finish_test | |
OLD | NEW |