1: # 2011 January 27
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 FTS3 module.
13: #
14:
15: set testdir [file dirname $argv0]
16: source $testdir/tester.tcl
17: ifcapable !fts3 { finish_test ; return }
18: set ::testprefix fts3aux1
19:
20: do_execsql_test 1.1 {
21: CREATE VIRTUAL TABLE t1 USING fts4;
22: INSERT INTO t1 VALUES('one two three four');
23: INSERT INTO t1 VALUES('three four five six');
24: INSERT INTO t1 VALUES('one three five seven');
25:
26: CREATE VIRTUAL TABLE terms USING fts4aux(t1);
27: SELECT term, documents, occurrences FROM terms WHERE col = '*';
28: } {
29: five 2 2 four 2 2 one 2 2 seven 1 1
30: six 1 1 three 3 3 two 1 1
31: }
32:
33: do_execsql_test 1.2 {
34: INSERT INTO t1 VALUES('one one one three three three');
35: SELECT term, documents, occurrences FROM terms WHERE col = '*';
36: } {
37: five 2 2 four 2 2 one 3 5 seven 1 1
38: six 1 1 three 4 6 two 1 1
39: }
40:
41: do_execsql_test 1.3.1 { DELETE FROM t1; }
42: do_execsql_test 1.3.2 {
43: SELECT term, documents, occurrences FROM terms WHERE col = '*';
44: }
45:
46: do_execsql_test 1.4 {
47: INSERT INTO t1 VALUES('a b a b a b a');
48: INSERT INTO t1 SELECT * FROM t1;
49: INSERT INTO t1 SELECT * FROM t1;
50: INSERT INTO t1 SELECT * FROM t1;
51: INSERT INTO t1 SELECT * FROM t1;
52: INSERT INTO t1 SELECT * FROM t1;
53: INSERT INTO t1 SELECT * FROM t1;
54: INSERT INTO t1 SELECT * FROM t1;
55: INSERT INTO t1 SELECT * FROM t1;
56: SELECT term, documents, occurrences FROM terms WHERE col = '*';
57: } {a 256 1024 b 256 768}
58:
59: #-------------------------------------------------------------------------
60: # The following tests verify that the fts4aux module uses the full-text
61: # index to reduce the number of rows scanned in the following circumstances:
62: #
63: # * when there is equality comparison against the term column using the
64: # BINARY collating sequence.
65: #
66: # * when there is a range constraint on the term column using the BINARY
67: # collating sequence.
68: #
69: # And also uses the full-text index to optimize ORDER BY clauses of the
70: # form "ORDER BY term ASC" or equivalent.
71: #
72: # Test organization is:
73: #
74: # fts3aux1-2.1.*: equality constraints.
75: # fts3aux1-2.2.*: range constraints.
76: # fts3aux1-2.3.*: ORDER BY optimization.
77: #
78:
79: do_execsql_test 2.0 {
80: DROP TABLE t1;
81: DROP TABLE terms;
82:
83: CREATE VIRTUAL TABLE x1 USING fts4(x);
84: INSERT INTO x1(x1) VALUES('nodesize=24');
85: CREATE VIRTUAL TABLE terms USING fts4aux(x1);
86:
87: CREATE VIEW terms_v AS
88: SELECT term, documents, occurrences FROM terms WHERE col = '*';
89:
90: INSERT INTO x1 VALUES('braes brag bragged bragger bragging');
91: INSERT INTO x1 VALUES('brags braid braided braiding braids');
92: INSERT INTO x1 VALUES('brain brainchild brained braining brains');
93: INSERT INTO x1 VALUES('brainstem brainstems brainstorm brainstorms');
94: }
95:
96: proc rec {varname x} {
97: global $varname
98: incr $varname
99: return 1
100: }
101: db func rec rec
102:
103: # Use EQP to show that the WHERE expression "term='braid'" uses a different
104: # index number (1) than "+term='braid'" (0).
105: #
106: do_execsql_test 2.1.1.1 {
107: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid'
108: } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)} }
109: do_execsql_test 2.1.1.2 {
110: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid'
111: } {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}}
112:
113: # Now show that using "term='braid'" means the virtual table returns
114: # only 1 row to SQLite, but "+term='braid'" means all 19 are returned.
115: #
116: do_test 2.1.2.1 {
117: set cnt 0
118: execsql { SELECT * FROM terms_v WHERE rec('cnt', term) AND term='braid' }
119: set cnt
120: } {2}
121: do_test 2.1.2.2 {
122: set cnt 0
123: execsql { SELECT * FROM terms_v WHERE rec('cnt', term) AND +term='braid' }
124: set cnt
125: } {38}
126:
127: # Similar to the test immediately above, but using a term ("breakfast") that
128: # is not featured in the dataset.
129: #
130: do_test 2.1.3.1 {
131: set cnt 0
132: execsql { SELECT * FROM terms_v WHERE rec('cnt', term) AND term='breakfast' }
133: set cnt
134: } {0}
135: do_test 2.1.3.2 {
136: set cnt 0
137: execsql { SELECT * FROM terms_v WHERE rec('cnt', term) AND +term='breakfast' }
138: set cnt
139: } {38}
140:
141: do_execsql_test 2.1.4.1 { SELECT * FROM terms_v WHERE term='braid' } {braid 1 1}
142: do_execsql_test 2.1.4.2 { SELECT * FROM terms_v WHERE +term='braid'} {braid 1 1}
143: do_execsql_test 2.1.4.3 { SELECT * FROM terms_v WHERE term='breakfast' } {}
144: do_execsql_test 2.1.4.4 { SELECT * FROM terms_v WHERE +term='breakfast' } {}
145:
146: do_execsql_test 2.1.4.5 { SELECT * FROM terms_v WHERE term='cba' } {}
147: do_execsql_test 2.1.4.6 { SELECT * FROM terms_v WHERE +term='cba' } {}
148: do_execsql_test 2.1.4.7 { SELECT * FROM terms_v WHERE term='abc' } {}
149: do_execsql_test 2.1.4.8 { SELECT * FROM terms_v WHERE +term='abc' } {}
150:
151: # Special case: term=NULL
152: #
153: do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {}
154:
155: do_execsql_test 2.2.1.1 {
156: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain'
157: } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2: (~0 rows)} }
158: do_execsql_test 2.2.1.2 {
159: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain'
160: } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} }
161:
162: do_execsql_test 2.2.1.3 {
163: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain'
164: } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4: (~0 rows)} }
165: do_execsql_test 2.2.1.4 {
166: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain'
167: } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} }
168:
169: do_execsql_test 2.2.1.5 {
170: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain'
171: } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6: (~0 rows)} }
172: do_execsql_test 2.2.1.6 {
173: EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain'
174: } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} }
175:
176: do_test 2.2.2.1 {
177: set cnt 0
178: execsql { SELECT * FROM terms WHERE rec('cnt', term) AND term>'brain' }
179: set cnt
180: } {18}
181: do_test 2.2.2.2 {
182: set cnt 0
183: execsql { SELECT * FROM terms WHERE rec('cnt', term) AND +term>'brain' }
184: set cnt
185: } {38}
186: do_execsql_test 2.2.2.3 {
187: SELECT term, documents, occurrences FROM terms_v WHERE term>'brain'
188: } {
189: brainchild 1 1 brained 1 1 braining 1 1 brains 1 1
190: brainstem 1 1 brainstems 1 1 brainstorm 1 1 brainstorms 1 1
191: }
192: do_execsql_test 2.2.2.4 {
193: SELECT term, documents, occurrences FROM terms_v WHERE +term>'brain'
194: } {
195: brainchild 1 1 brained 1 1 braining 1 1 brains 1 1
196: brainstem 1 1 brainstems 1 1 brainstorm 1 1 brainstorms 1 1
197: }
198: do_execsql_test 2.2.2.5 {
199: SELECT term, documents, occurrences FROM terms_v WHERE term>='brain'
200: } {
201: brain 1 1
202: brainchild 1 1 brained 1 1 braining 1 1 brains 1 1
203: brainstem 1 1 brainstems 1 1 brainstorm 1 1 brainstorms 1 1
204: }
205: do_execsql_test 2.2.2.6 {
206: SELECT term, documents, occurrences FROM terms_v WHERE +term>='brain'
207: } {
208: brain 1 1
209: brainchild 1 1 brained 1 1 braining 1 1 brains 1 1
210: brainstem 1 1 brainstems 1 1 brainstorm 1 1 brainstorms 1 1
211: }
212:
213: do_execsql_test 2.2.2.7 {
214: SELECT term, documents, occurrences FROM terms_v WHERE term>='abc'
215: } {
216: braes 1 1 brag 1 1 bragged 1 1 bragger 1 1
217: bragging 1 1 brags 1 1 braid 1 1 braided 1 1
218: braiding 1 1 braids 1 1 brain 1 1 brainchild 1 1
219: brained 1 1 braining 1 1 brains 1 1 brainstem 1 1
220: brainstems 1 1 brainstorm 1 1 brainstorms 1 1
221: }
222: do_execsql_test 2.2.2.8 {
223: SELECT term, documents, occurrences FROM terms_v WHERE +term>='abc'
224: } {
225: braes 1 1 brag 1 1 bragged 1 1 bragger 1 1
226: bragging 1 1 brags 1 1 braid 1 1 braided 1 1
227: braiding 1 1 braids 1 1 brain 1 1 brainchild 1 1
228: brained 1 1 braining 1 1 brains 1 1 brainstem 1 1
229: brainstems 1 1 brainstorm 1 1 brainstorms 1 1
230: }
231:
232: do_execsql_test 2.2.2.9 {
233: SELECT term, documents, occurrences FROM terms_v WHERE term>='brainstorms'
234: } {brainstorms 1 1}
235: do_execsql_test 2.2.2.10 {
236: SELECT term, documents, occurrences FROM terms_v WHERE term>='brainstorms'
237: } {brainstorms 1 1}
238: do_execsql_test 2.2.2.11 { SELECT * FROM terms_v WHERE term>'brainstorms' } {}
239: do_execsql_test 2.2.2.12 { SELECT * FROM terms_v WHERE term>'brainstorms' } {}
240:
241: do_execsql_test 2.2.2.13 { SELECT * FROM terms_v WHERE term>'cba' } {}
242: do_execsql_test 2.2.2.14 { SELECT * FROM terms_v WHERE term>'cba' } {}
243:
244: do_test 2.2.3.1 {
245: set cnt 0
246: execsql { SELECT * FROM terms WHERE rec('cnt', term) AND term<'brain' }
247: set cnt
248: } {22}
249: do_test 2.2.3.2 {
250: set cnt 0
251: execsql { SELECT * FROM terms WHERE rec('cnt', term) AND +term<'brain' }
252: set cnt
253: } {38}
254: do_execsql_test 2.2.3.3 {
255: SELECT term, documents, occurrences FROM terms_v WHERE term<'brain'
256: } {
257: braes 1 1 brag 1 1 bragged 1 1 bragger 1 1 bragging 1 1
258: brags 1 1 braid 1 1 braided 1 1 braiding 1 1 braids 1 1
259: }
260: do_execsql_test 2.2.3.4 {
261: SELECT term, documents, occurrences FROM terms_v WHERE +term<'brain'
262: } {
263: braes 1 1 brag 1 1 bragged 1 1 bragger 1 1 bragging 1 1
264: brags 1 1 braid 1 1 braided 1 1 braiding 1 1 braids 1 1
265: }
266: do_execsql_test 2.2.3.5 {
267: SELECT term, documents, occurrences FROM terms_v WHERE term<='brain'
268: } {
269: braes 1 1 brag 1 1 bragged 1 1 bragger 1 1 bragging 1 1
270: brags 1 1 braid 1 1 braided 1 1 braiding 1 1 braids 1 1
271: brain 1 1
272: }
273: do_execsql_test 2.2.3.6 {
274: SELECT term, documents, occurrences FROM terms_v WHERE +term<='brain'
275: } {
276: braes 1 1 brag 1 1 bragged 1 1 bragger 1 1 bragging 1 1
277: brags 1 1 braid 1 1 braided 1 1 braiding 1 1 braids 1 1
278: brain 1 1
279: }
280:
281: do_test 2.2.4.1 {
282: set cnt 0
283: execsql {
284: SELECT term, documents, occurrences FROM terms
285: WHERE rec('cnt', term) AND term BETWEEN 'brags' AND 'brain'
286: }
287: set cnt
288: } {12}
289: do_test 2.2.4.2 {
290: set cnt 0
291: execsql {
292: SELECT term, documents, occurrences FROM terms
293: WHERE rec('cnt', term) AND +term BETWEEN 'brags' AND 'brain'
294: }
295: set cnt
296: } {38}
297: do_execsql_test 2.2.4.3 {
298: SELECT term, documents, occurrences FROM terms_v
299: WHERE rec('cnt', term) AND term BETWEEN 'brags' AND 'brain'
300: } {
301: brags 1 1 braid 1 1 braided 1 1 braiding 1 1 braids 1 1 brain 1 1
302: }
303: do_execsql_test 2.2.4.4 {
304: SELECT term, documents, occurrences FROM terms_v
305: WHERE rec('cnt', term) AND +term BETWEEN 'brags' AND 'brain'
306: } {
307: brags 1 1 braid 1 1 braided 1 1 braiding 1 1 braids 1 1 brain 1 1
308: }
309: do_execsql_test 2.2.4.5 {
310: SELECT term, documents, occurrences FROM terms_v
311: WHERE rec('cnt', term) AND term > 'brags' AND term < 'brain'
312: } {
313: braid 1 1 braided 1 1 braiding 1 1 braids 1 1
314: }
315: do_execsql_test 2.2.4.6 {
316: SELECT term, documents, occurrences FROM terms_v
317: WHERE rec('cnt', term) AND +term > 'brags' AND +term < 'brain'
318: } {
319: braid 1 1 braided 1 1 braiding 1 1 braids 1 1
320: }
321:
322: # Check that "ORDER BY term ASC" and equivalents are sorted by the
323: # virtual table implementation. Any other ORDER BY clause requires
324: # SQLite to sort results using a temporary b-tree.
325: #
326: foreach {tn sort orderby} {
327: 1 0 "ORDER BY term ASC"
328: 2 0 "ORDER BY term"
329: 3 1 "ORDER BY term DESC"
330: 4 1 "ORDER BY documents ASC"
331: 5 1 "ORDER BY documents"
332: 6 1 "ORDER BY documents DESC"
333: 7 1 "ORDER BY occurrences ASC"
334: 8 1 "ORDER BY occurrences"
335: 9 1 "ORDER BY occurrences DESC"
336: } {
337:
338: set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}]
339: if {$sort} { lappend res 0 0 0 {USE TEMP B-TREE FOR ORDER BY} }
340:
341: set sql "SELECT * FROM terms $orderby"
342: do_execsql_test 2.3.1.$tn "EXPLAIN QUERY PLAN $sql" $res
343: }
344:
345: #-------------------------------------------------------------------------
346: # The next set of tests, fts3aux1-3.*, test error conditions in the
347: # fts4aux module. Except, fault injection testing (OOM, IO error etc.) is
348: # done in fts3fault2.test
349: #
350:
351: do_execsql_test 3.1.1 {
352: CREATE VIRTUAL TABLE t2 USING fts4;
353: }
354:
355: do_catchsql_test 3.1.2 {
356: CREATE VIRTUAL TABLE terms2 USING fts4aux;
357: } {1 {wrong number of arguments to fts4aux constructor}}
358: do_catchsql_test 3.1.3 {
359: CREATE VIRTUAL TABLE terms2 USING fts4aux(t2, t2);
360: } {1 {wrong number of arguments to fts4aux constructor}}
361:
362: do_execsql_test 3.2.1 {
363: CREATE VIRTUAL TABLE terms3 USING fts4aux(does_not_exist)
364: }
365: do_catchsql_test 3.2.2 {
366: SELECT * FROM terms3
367: } {1 {SQL logic error or missing database}}
368: do_catchsql_test 3.2.3 {
369: SELECT * FROM terms3 WHERE term = 'abc'
370: } {1 {SQL logic error or missing database}}
371:
372: do_catchsql_test 3.3.1 {
373: INSERT INTO terms VALUES(1,2,3);
374: } {1 {table terms may not be modified}}
375: do_catchsql_test 3.3.2 {
376: DELETE FROM terms
377: } {1 {table terms may not be modified}}
378: do_catchsql_test 3.3.3 {
379: UPDATE terms set documents = documents+1;
380: } {1 {table terms may not be modified}}
381:
382:
383: #-------------------------------------------------------------------------
384: # The following tests - fts4aux-4.* - test that joins work with fts4aux
385: # tables. And that fts4aux provides reasonably sane cost information via
386: # xBestIndex to the query planner.
387: #
388: db close
389: forcedelete test.db
390: sqlite3 db test.db
391: do_execsql_test 4.1 {
392: CREATE VIRTUAL TABLE x1 USING fts4(x);
393: CREATE VIRTUAL TABLE terms USING fts4aux(x1);
394: CREATE TABLE x2(y);
395: CREATE TABLE x3(y);
396: CREATE INDEX i1 ON x3(y);
397:
398: INSERT INTO x1 VALUES('a b c d e');
399: INSERT INTO x1 VALUES('f g h i j');
400: INSERT INTO x1 VALUES('k k l l a');
401:
402: INSERT INTO x2 SELECT term FROM terms WHERE col = '*';
403: INSERT INTO x3 SELECT term FROM terms WHERE col = '*';
404: }
405:
406: proc do_plansql_test {tn sql r} {
407: uplevel do_execsql_test $tn [list "EXPLAIN QUERY PLAN $sql ; $sql"] [list $r]
408: }
409:
410: do_plansql_test 4.2 {
411: SELECT y FROM x2, terms WHERE y = term AND col = '*'
412: } {
413: 0 0 0 {SCAN TABLE x2 (~1000000 rows)}
414: 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)}
415: a b c d e f g h i j k l
416: }
417:
418: do_plansql_test 4.3 {
419: SELECT y FROM terms, x2 WHERE y = term AND col = '*'
420: } {
421: 0 0 1 {SCAN TABLE x2 (~1000000 rows)}
422: 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)}
423: a b c d e f g h i j k l
424: }
425:
426: do_plansql_test 4.4 {
427: SELECT y FROM x3, terms WHERE y = term AND col = '*'
428: } {
429: 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}
430: 0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)}
431: a b c d e f g h i j k l
432: }
433:
434: do_plansql_test 4.5 {
435: SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*'
436: } {
437: 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}
438: 0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)}
439: a k l
440: }
441:
442: #-------------------------------------------------------------------------
443: # The following tests check that fts4aux can handle an fts table with an
444: # odd name (one that requires quoting for use in SQL statements). And that
445: # the argument to the fts4aux constructor is properly dequoted before use.
446: #
447: #
448: do_execsql_test 5.1 {
449: CREATE VIRTUAL TABLE "abc '!' def" USING fts4(x, y);
450: INSERT INTO "abc '!' def" VALUES('XX', 'YY');
451:
452: CREATE VIRTUAL TABLE terms3 USING fts4aux("abc '!' def");
453: SELECT * FROM terms3;
454: } {xx * 1 1 xx 0 1 1 yy * 1 1 yy 1 1 1}
455:
456: do_execsql_test 5.2 {
457: CREATE VIRTUAL TABLE "%%^^%%" USING fts4aux('abc ''!'' def');
458: SELECT * FROM "%%^^%%";
459: } {xx * 1 1 xx 0 1 1 yy * 1 1 yy 1 1 1}
460:
461:
462: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>