1290283feSshess# 2007 April 26 2290283feSshess# 3290283feSshess# The author disclaims copyright to this source code. 4290283feSshess# 5290283feSshess#************************************************************************* 6290283feSshess# This file implements tests for prefix-searching in the fts2 7290283feSshess# component of the SQLite library. 8290283feSshess# 9*85b623f2Sdrh# $Id: fts2n.test,v 1.2 2007/12/13 21:54:11 drh Exp $ 10290283feSshess# 11290283feSshess 12290283feSshessset testdir [file dirname $argv0] 13290283feSshesssource $testdir/tester.tcl 14290283feSshess 15290283feSshess# If SQLITE_ENABLE_FTS2 is defined, omit this file. 16290283feSshessifcapable !fts2 { 17290283feSshess finish_test 18290283feSshess return 19290283feSshess} 20290283feSshess 21290283feSshess# A large string to prime the pump with. 22290283feSshessset text { 23290283feSshess Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas 24290283feSshess iaculis mollis ipsum. Praesent rhoncus placerat justo. Duis non quam 25290283feSshess sed turpis posuere placerat. Curabitur et lorem in lorem porttitor 26290283feSshess aliquet. Pellentesque bibendum tincidunt diam. Vestibulum blandit 27290283feSshess ante nec elit. In sapien diam, facilisis eget, dictum sed, viverra 28290283feSshess at, felis. Vestibulum magna. Sed magna dolor, vestibulum rhoncus, 29290283feSshess ornare vel, vulputate sit amet, felis. Integer malesuada, tellus at 30290283feSshess luctus gravida, diam nunc porta nibh, nec imperdiet massa metus eu 31290283feSshess lectus. Aliquam nisi. Nunc fringilla nulla at lectus. Suspendisse 32290283feSshess potenti. Cum sociis natoque penatibus et magnis dis parturient 33290283feSshess montes, nascetur ridiculus mus. Pellentesque odio nulla, feugiat eu, 34290283feSshess suscipit nec, consequat quis, risus. 35290283feSshess} 36290283feSshess 37290283feSshessdb eval { 38290283feSshess CREATE VIRTUAL TABLE t1 USING fts2(c); 39290283feSshess 40290283feSshess INSERT INTO t1(rowid, c) VALUES(1, $text); 41290283feSshess INSERT INTO t1(rowid, c) VALUES(2, 'Another lovely row'); 42290283feSshess} 43290283feSshess 44290283feSshess# Exact match 45290283feSshessdo_test fts2n-1.1 { 46290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lorem'" 47290283feSshess} {1} 48290283feSshess 49290283feSshess# And a prefix 50290283feSshessdo_test fts2n-1.2 { 51290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lore*'" 52290283feSshess} {1} 53290283feSshess 54290283feSshess# Prefix includes exact match 55290283feSshessdo_test fts2n-1.3 { 56290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lorem*'" 57290283feSshess} {1} 58290283feSshess 59290283feSshess# Make certain everything isn't considered a prefix! 60290283feSshessdo_test fts2n-1.4 { 61290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lore'" 62290283feSshess} {} 63290283feSshess 64290283feSshess# Prefix across multiple rows. 65290283feSshessdo_test fts2n-1.5 { 66290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lo*'" 67290283feSshess} {1 2} 68290283feSshess 69290283feSshess# Likewise, with multiple hits in one document. 70290283feSshessdo_test fts2n-1.6 { 71290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'l*'" 72290283feSshess} {1 2} 73290283feSshess 74290283feSshess# Prefix which should only hit one document. 75290283feSshessdo_test fts2n-1.7 { 76290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lov*'" 77290283feSshess} {2} 78290283feSshess 79290283feSshess# * not at end is dropped. 80290283feSshessdo_test fts2n-1.8 { 81290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lo *'" 82290283feSshess} {} 83290283feSshess 84290283feSshess# Stand-alone * is dropped. 85290283feSshessdo_test fts2n-1.9 { 86290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '*'" 87290283feSshess} {} 88290283feSshess 89290283feSshess# Phrase-query prefix. 90290283feSshessdo_test fts2n-1.10 { 91290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"lovely r*\"'" 92290283feSshess} {2} 93290283feSshessdo_test fts2n-1.11 { 94290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"lovely r\"'" 95290283feSshess} {} 96290283feSshess 97290283feSshess# Phrase query with multiple prefix matches. 98290283feSshessdo_test fts2n-1.12 { 99290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"a* l*\"'" 100290283feSshess} {1 2} 101290283feSshess 102290283feSshess# Phrase query with multiple prefix matches. 103290283feSshessdo_test fts2n-1.13 { 104290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"a* l* row\"'" 105290283feSshess} {2} 106290283feSshess 107290283feSshess 108290283feSshess 109290283feSshess 110290283feSshess# Test across updates (and, by implication, deletes). 111290283feSshess 112290283feSshess# Version of text without "lorem". 113290283feSshessregsub -all {[Ll]orem} $text '' ntext 114290283feSshess 115290283feSshessdb eval { 116290283feSshess CREATE VIRTUAL TABLE t2 USING fts2(c); 117290283feSshess 118290283feSshess INSERT INTO t2(rowid, c) VALUES(1, $text); 119290283feSshess INSERT INTO t2(rowid, c) VALUES(2, 'Another lovely row'); 120290283feSshess UPDATE t2 SET c = $ntext WHERE rowid = 1; 121290283feSshess} 122290283feSshess 123290283feSshess# Can't see lorem as an exact match. 124290283feSshessdo_test fts2n-2.1 { 125290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lorem'" 126290283feSshess} {} 127290283feSshess 128290283feSshess# Can't see a prefix of lorem, either. 129290283feSshessdo_test fts2n-2.2 { 130290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lore*'" 131290283feSshess} {} 132290283feSshess 133290283feSshess# Can see lovely in the other document. 134290283feSshessdo_test fts2n-2.3 { 135290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lo*'" 136290283feSshess} {2} 137290283feSshess 138290283feSshess# Can still see other hits. 139290283feSshessdo_test fts2n-2.4 { 140290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'l*'" 141290283feSshess} {1 2} 142290283feSshess 143290283feSshess# Prefix which should only hit one document. 144290283feSshessdo_test fts2n-2.5 { 145290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lov*'" 146290283feSshess} {2} 147290283feSshess 148290283feSshess 149290283feSshess 150290283feSshess# Test with a segment which will have multiple levels in the tree. 151290283feSshess 152290283feSshess# Build a big document with lots of unique terms. 153290283feSshessset bigtext $text 154290283feSshessforeach c {a b c d e} { 155290283feSshess regsub -all {[A-Za-z]+} $bigtext "&$c" t 156290283feSshess append bigtext $t 157290283feSshess} 158290283feSshess 159290283feSshess# Populate a table with many copies of the big document, so that we 160290283feSshess# can test the number of hits found. Populate $ret with the expected 161290283feSshess# hit counts for each row. offsets() returns 4 elements for every 162290283feSshess# hit. We'll have 6 hits for row 1, 1 for row 2, and 6*(2^5)==192 for 163290283feSshess# $bigtext. 164290283feSshessset ret {6 1} 165290283feSshessdb eval { 166290283feSshess BEGIN; 167290283feSshess CREATE VIRTUAL TABLE t3 USING fts2(c); 168290283feSshess 169290283feSshess INSERT INTO t3(rowid, c) VALUES(1, $text); 170290283feSshess INSERT INTO t3(rowid, c) VALUES(2, 'Another lovely row'); 171290283feSshess} 172290283feSshessfor {set i 0} {$i<100} {incr i} { 173290283feSshess db eval {INSERT INTO t3(rowid, c) VALUES(3+$i, $bigtext)} 174290283feSshess lappend ret 192 175290283feSshess} 176290283feSshessdb eval {COMMIT;} 177290283feSshess 178290283feSshess# Test that we get the expected number of hits. 179290283feSshessdo_test fts2n-3.1 { 180290283feSshess set t {} 181290283feSshess db eval {SELECT offsets(t3) as o FROM t3 WHERE t3 MATCH 'l*'} { 182290283feSshess set l [llength $o] 183290283feSshess lappend t [expr {$l/4}] 184290283feSshess } 185290283feSshess set t 186290283feSshess} $ret 187290283feSshess 188290283feSshess# TODO(shess) It would be useful to test a couple edge cases, but I 189290283feSshess# don't know if we have the precision to manage it from here at this 190290283feSshess# time. Prefix hits can cross leaves, which the code above _should_ 191290283feSshess# hit by virtue of size. There are two variations on this. If the 192290283feSshess# tree is 2 levels high, the code will find the leaf-node extent 193*85b623f2Sdrh# directly, but if its higher, the code will have to follow two 194290283feSshess# separate interior branches down the tree. Both should be tested. 195290283feSshess 196290283feSshessfinish_test 197