1*290283feSshess# 2007 April 26 2*290283feSshess# 3*290283feSshess# The author disclaims copyright to this source code. 4*290283feSshess# 5*290283feSshess#************************************************************************* 6*290283feSshess# This file implements tests for prefix-searching in the fts2 7*290283feSshess# component of the SQLite library. 8*290283feSshess# 9*290283feSshess# $Id: fts2n.test,v 1.1 2007/05/01 18:25:53 shess Exp $ 10*290283feSshess# 11*290283feSshess 12*290283feSshessset testdir [file dirname $argv0] 13*290283feSshesssource $testdir/tester.tcl 14*290283feSshess 15*290283feSshess# If SQLITE_ENABLE_FTS2 is defined, omit this file. 16*290283feSshessifcapable !fts2 { 17*290283feSshess finish_test 18*290283feSshess return 19*290283feSshess} 20*290283feSshess 21*290283feSshess# A large string to prime the pump with. 22*290283feSshessset text { 23*290283feSshess Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas 24*290283feSshess iaculis mollis ipsum. Praesent rhoncus placerat justo. Duis non quam 25*290283feSshess sed turpis posuere placerat. Curabitur et lorem in lorem porttitor 26*290283feSshess aliquet. Pellentesque bibendum tincidunt diam. Vestibulum blandit 27*290283feSshess ante nec elit. In sapien diam, facilisis eget, dictum sed, viverra 28*290283feSshess at, felis. Vestibulum magna. Sed magna dolor, vestibulum rhoncus, 29*290283feSshess ornare vel, vulputate sit amet, felis. Integer malesuada, tellus at 30*290283feSshess luctus gravida, diam nunc porta nibh, nec imperdiet massa metus eu 31*290283feSshess lectus. Aliquam nisi. Nunc fringilla nulla at lectus. Suspendisse 32*290283feSshess potenti. Cum sociis natoque penatibus et magnis dis parturient 33*290283feSshess montes, nascetur ridiculus mus. Pellentesque odio nulla, feugiat eu, 34*290283feSshess suscipit nec, consequat quis, risus. 35*290283feSshess} 36*290283feSshess 37*290283feSshessdb eval { 38*290283feSshess CREATE VIRTUAL TABLE t1 USING fts2(c); 39*290283feSshess 40*290283feSshess INSERT INTO t1(rowid, c) VALUES(1, $text); 41*290283feSshess INSERT INTO t1(rowid, c) VALUES(2, 'Another lovely row'); 42*290283feSshess} 43*290283feSshess 44*290283feSshess# Exact match 45*290283feSshessdo_test fts2n-1.1 { 46*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lorem'" 47*290283feSshess} {1} 48*290283feSshess 49*290283feSshess# And a prefix 50*290283feSshessdo_test fts2n-1.2 { 51*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lore*'" 52*290283feSshess} {1} 53*290283feSshess 54*290283feSshess# Prefix includes exact match 55*290283feSshessdo_test fts2n-1.3 { 56*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lorem*'" 57*290283feSshess} {1} 58*290283feSshess 59*290283feSshess# Make certain everything isn't considered a prefix! 60*290283feSshessdo_test fts2n-1.4 { 61*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lore'" 62*290283feSshess} {} 63*290283feSshess 64*290283feSshess# Prefix across multiple rows. 65*290283feSshessdo_test fts2n-1.5 { 66*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lo*'" 67*290283feSshess} {1 2} 68*290283feSshess 69*290283feSshess# Likewise, with multiple hits in one document. 70*290283feSshessdo_test fts2n-1.6 { 71*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'l*'" 72*290283feSshess} {1 2} 73*290283feSshess 74*290283feSshess# Prefix which should only hit one document. 75*290283feSshessdo_test fts2n-1.7 { 76*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lov*'" 77*290283feSshess} {2} 78*290283feSshess 79*290283feSshess# * not at end is dropped. 80*290283feSshessdo_test fts2n-1.8 { 81*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH 'lo *'" 82*290283feSshess} {} 83*290283feSshess 84*290283feSshess# Stand-alone * is dropped. 85*290283feSshessdo_test fts2n-1.9 { 86*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '*'" 87*290283feSshess} {} 88*290283feSshess 89*290283feSshess# Phrase-query prefix. 90*290283feSshessdo_test fts2n-1.10 { 91*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"lovely r*\"'" 92*290283feSshess} {2} 93*290283feSshessdo_test fts2n-1.11 { 94*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"lovely r\"'" 95*290283feSshess} {} 96*290283feSshess 97*290283feSshess# Phrase query with multiple prefix matches. 98*290283feSshessdo_test fts2n-1.12 { 99*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"a* l*\"'" 100*290283feSshess} {1 2} 101*290283feSshess 102*290283feSshess# Phrase query with multiple prefix matches. 103*290283feSshessdo_test fts2n-1.13 { 104*290283feSshess execsql "SELECT rowid FROM t1 WHERE t1 MATCH '\"a* l* row\"'" 105*290283feSshess} {2} 106*290283feSshess 107*290283feSshess 108*290283feSshess 109*290283feSshess 110*290283feSshess# Test across updates (and, by implication, deletes). 111*290283feSshess 112*290283feSshess# Version of text without "lorem". 113*290283feSshessregsub -all {[Ll]orem} $text '' ntext 114*290283feSshess 115*290283feSshessdb eval { 116*290283feSshess CREATE VIRTUAL TABLE t2 USING fts2(c); 117*290283feSshess 118*290283feSshess INSERT INTO t2(rowid, c) VALUES(1, $text); 119*290283feSshess INSERT INTO t2(rowid, c) VALUES(2, 'Another lovely row'); 120*290283feSshess UPDATE t2 SET c = $ntext WHERE rowid = 1; 121*290283feSshess} 122*290283feSshess 123*290283feSshess# Can't see lorem as an exact match. 124*290283feSshessdo_test fts2n-2.1 { 125*290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lorem'" 126*290283feSshess} {} 127*290283feSshess 128*290283feSshess# Can't see a prefix of lorem, either. 129*290283feSshessdo_test fts2n-2.2 { 130*290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lore*'" 131*290283feSshess} {} 132*290283feSshess 133*290283feSshess# Can see lovely in the other document. 134*290283feSshessdo_test fts2n-2.3 { 135*290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lo*'" 136*290283feSshess} {2} 137*290283feSshess 138*290283feSshess# Can still see other hits. 139*290283feSshessdo_test fts2n-2.4 { 140*290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'l*'" 141*290283feSshess} {1 2} 142*290283feSshess 143*290283feSshess# Prefix which should only hit one document. 144*290283feSshessdo_test fts2n-2.5 { 145*290283feSshess execsql "SELECT rowid FROM t2 WHERE t2 MATCH 'lov*'" 146*290283feSshess} {2} 147*290283feSshess 148*290283feSshess 149*290283feSshess 150*290283feSshess# Test with a segment which will have multiple levels in the tree. 151*290283feSshess 152*290283feSshess# Build a big document with lots of unique terms. 153*290283feSshessset bigtext $text 154*290283feSshessforeach c {a b c d e} { 155*290283feSshess regsub -all {[A-Za-z]+} $bigtext "&$c" t 156*290283feSshess append bigtext $t 157*290283feSshess} 158*290283feSshess 159*290283feSshess# Populate a table with many copies of the big document, so that we 160*290283feSshess# can test the number of hits found. Populate $ret with the expected 161*290283feSshess# hit counts for each row. offsets() returns 4 elements for every 162*290283feSshess# hit. We'll have 6 hits for row 1, 1 for row 2, and 6*(2^5)==192 for 163*290283feSshess# $bigtext. 164*290283feSshessset ret {6 1} 165*290283feSshessdb eval { 166*290283feSshess BEGIN; 167*290283feSshess CREATE VIRTUAL TABLE t3 USING fts2(c); 168*290283feSshess 169*290283feSshess INSERT INTO t3(rowid, c) VALUES(1, $text); 170*290283feSshess INSERT INTO t3(rowid, c) VALUES(2, 'Another lovely row'); 171*290283feSshess} 172*290283feSshessfor {set i 0} {$i<100} {incr i} { 173*290283feSshess db eval {INSERT INTO t3(rowid, c) VALUES(3+$i, $bigtext)} 174*290283feSshess lappend ret 192 175*290283feSshess} 176*290283feSshessdb eval {COMMIT;} 177*290283feSshess 178*290283feSshess# Test that we get the expected number of hits. 179*290283feSshessdo_test fts2n-3.1 { 180*290283feSshess set t {} 181*290283feSshess db eval {SELECT offsets(t3) as o FROM t3 WHERE t3 MATCH 'l*'} { 182*290283feSshess set l [llength $o] 183*290283feSshess lappend t [expr {$l/4}] 184*290283feSshess } 185*290283feSshess set t 186*290283feSshess} $ret 187*290283feSshess 188*290283feSshess# TODO(shess) It would be useful to test a couple edge cases, but I 189*290283feSshess# don't know if we have the precision to manage it from here at this 190*290283feSshess# time. Prefix hits can cross leaves, which the code above _should_ 191*290283feSshess# hit by virtue of size. There are two variations on this. If the 192*290283feSshess# tree is 2 levels high, the code will find the leaf-node extent 193*290283feSshess# directly, but if it's higher, the code will have to follow two 194*290283feSshess# separate interior branches down the tree. Both should be tested. 195*290283feSshess 196*290283feSshessfinish_test 197