1*99ebad90Sdan# 2011 June 10 2*99ebad90Sdan# 3*99ebad90Sdan# May you do good and not evil. 4*99ebad90Sdan# May you find forgiveness for yourself and forgive others. 5*99ebad90Sdan# May you share freely, never taking more than you give. 6*99ebad90Sdan# 7*99ebad90Sdan#*********************************************************************** 8*99ebad90Sdan# 9*99ebad90Sdan 10*99ebad90Sdanset testdir [file dirname $argv0] 11*99ebad90Sdansource $testdir/tester.tcl 12*99ebad90Sdan 13*99ebad90Sdan# If this build does not include FTS3, skip the tests in this file. 14*99ebad90Sdan# 15*99ebad90Sdanifcapable !fts3 { finish_test ; return } 16*99ebad90Sdansource $testdir/fts3_common.tcl 17*99ebad90Sdansource $testdir/malloc_common.tcl 18*99ebad90Sdan 19*99ebad90Sdanset testprefix fts3rnd2 20*99ebad90Sdan 21*99ebad90Sdanproc test_fts3_near_match {tn doc expr res} { 22*99ebad90Sdan fts3_near_match $doc $expr -phrasecountvar p 23*99ebad90Sdan uplevel do_test [list $tn] [list [list set {} $p]] [list $res] 24*99ebad90Sdan} 25*99ebad90Sdan 26*99ebad90Sdan# Simple test cases for C routine [fts3_near_match]. 27*99ebad90Sdan# 28*99ebad90Sdantest_fts3_near_match 1.1.1 {a b c a b} a {2} 29*99ebad90Sdantest_fts3_near_match 1.1.2 {a b c a b} {a 5 b 6 c} {2 2 1} 30*99ebad90Sdantest_fts3_near_match 1.1.3 {a b c a b} {"a b"} {2} 31*99ebad90Sdantest_fts3_near_match 1.1.4 {a b c a b} {"b c"} {1} 32*99ebad90Sdantest_fts3_near_match 1.1.5 {a b c a b} {"c c"} {0} 33*99ebad90Sdan 34*99ebad90Sdantest_fts3_near_match 1.2.1 "a b c d e f g" {b 2 f} {0 0} 35*99ebad90Sdantest_fts3_near_match 1.2.2 "a b c d e f g" {b 3 f} {1 1} 36*99ebad90Sdantest_fts3_near_match 1.2.3 "a b c d e f g" {f 2 b} {0 0} 37*99ebad90Sdantest_fts3_near_match 1.2.4 "a b c d e f g" {f 3 b} {1 1} 38*99ebad90Sdantest_fts3_near_match 1.2.5 "a b c d e f g" {"a b" 2 "f g"} {0 0} 39*99ebad90Sdantest_fts3_near_match 1.2.6 "a b c d e f g" {"a b" 3 "f g"} {1 1} 40*99ebad90Sdan 41*99ebad90Sdanset A "a b c d e f g h i j k l m n o p q r s t u v w x y z" 42*99ebad90Sdantest_fts3_near_match 1.3.1 $A {"c d" 5 "i j" 1 "e f"} {0 0 0} 43*99ebad90Sdantest_fts3_near_match 1.3.2 $A {"c d" 5 "i j" 2 "e f"} {1 1 1} 44*99ebad90Sdan 45*99ebad90Sdanproc mit {blob} { 46*99ebad90Sdan set scan(littleEndian) i* 47*99ebad90Sdan set scan(bigEndian) I* 48*99ebad90Sdan binary scan $blob $scan($::tcl_platform(byteOrder)) r 49*99ebad90Sdan return $r 50*99ebad90Sdan} 51*99ebad90Sdandb func mit mit 52*99ebad90Sdan 53*99ebad90Sdanproc fix_near_expr {expr} { 54*99ebad90Sdan set out [list] 55*99ebad90Sdan lappend out [lindex $expr 0] 56*99ebad90Sdan foreach {a b} [lrange $expr 1 end] { 57*99ebad90Sdan if {[string match -nocase near $a]} { set a 10 } 58*99ebad90Sdan if {[string match -nocase near/* $a]} { set a [string range $a 5 end] } 59*99ebad90Sdan lappend out $a 60*99ebad90Sdan lappend out $b 61*99ebad90Sdan } 62*99ebad90Sdan return $out 63*99ebad90Sdan} 64*99ebad90Sdan 65*99ebad90Sdanproc do_near_test {tn tbl expr} { 66*99ebad90Sdan 67*99ebad90Sdan set expr [fix_near_expr $expr] 68*99ebad90Sdan 69*99ebad90Sdan # Create the MATCH expression from $expr 70*99ebad90Sdan # 71*99ebad90Sdan set match [lindex $expr 0] 72*99ebad90Sdan if {[llength $match]>1} { 73*99ebad90Sdan set match "\"$match\"" 74*99ebad90Sdan } 75*99ebad90Sdan foreach {nNear phrase} [lrange $expr 1 end] { 76*99ebad90Sdan if {[llength $phrase]>1} { 77*99ebad90Sdan append match " NEAR/$nNear \"$phrase\"" 78*99ebad90Sdan } else { 79*99ebad90Sdan append match " NEAR/$nNear $phrase" 80*99ebad90Sdan } 81*99ebad90Sdan } 82*99ebad90Sdan 83*99ebad90Sdan # Calculate the expected results using [fts3_near_match]. The following 84*99ebad90Sdan # loop populates the "hits" and "counts" arrays as follows: 85*99ebad90Sdan # 86*99ebad90Sdan # 1. For each document in the table that matches the NEAR expression, 87*99ebad90Sdan # hits($docid) is set to 1. The set of docids that match the expression 88*99ebad90Sdan # can therefore be found using [array names hits]. 89*99ebad90Sdan # 90*99ebad90Sdan # 2. For each column of each document in the table, counts($docid,$iCol) 91*99ebad90Sdan # is set to the -phrasecountvar output. 92*99ebad90Sdan # 93*99ebad90Sdan set res [list] 94*99ebad90Sdan catch { array unset hits } 95*99ebad90Sdan db eval "SELECT docid, * FROM $tbl" d { 96*99ebad90Sdan set iCol 0 97*99ebad90Sdan foreach col [lrange $d(*) 1 end] { 98*99ebad90Sdan set docid $d(docid) 99*99ebad90Sdan set hit [fts3_near_match $d($col) $expr -p counts($docid,$iCol)] 100*99ebad90Sdan if {$hit} { set hits($docid) 1 } 101*99ebad90Sdan incr iCol 102*99ebad90Sdan } 103*99ebad90Sdan } 104*99ebad90Sdan set nPhrase [expr ([llength $expr]+1)/2] 105*99ebad90Sdan set nCol $iCol 106*99ebad90Sdan 107*99ebad90Sdan # This block populates the nHit and nDoc arrays. For each phrase/column 108*99ebad90Sdan # in the query/table, array elements are set as follows: 109*99ebad90Sdan # 110*99ebad90Sdan # nHit($iPhrase,$iCol) - Total number of hits for phrase $iPhrase in 111*99ebad90Sdan # column $iCol. 112*99ebad90Sdan # 113*99ebad90Sdan # nDoc($iPhrase,$iCol) - Number of documents with at least one hit for 114*99ebad90Sdan # phrase $iPhrase in column $iCol. 115*99ebad90Sdan # 116*99ebad90Sdan for {set iPhrase 0} {$iPhrase < $nPhrase} {incr iPhrase} { 117*99ebad90Sdan for {set iCol 0} {$iCol < $nCol} {incr iCol} { 118*99ebad90Sdan set nHit($iPhrase,$iCol) 0 119*99ebad90Sdan set nDoc($iPhrase,$iCol) 0 120*99ebad90Sdan } 121*99ebad90Sdan } 122*99ebad90Sdan foreach key [array names counts] { 123*99ebad90Sdan set iCol [lindex [split $key ,] 1] 124*99ebad90Sdan set iPhrase 0 125*99ebad90Sdan foreach c $counts($key) { 126*99ebad90Sdan if {$c>0} { incr nHit($iPhrase,$iCol) 1 } 127*99ebad90Sdan incr nDoc($iPhrase,$iCol) $c 128*99ebad90Sdan incr iPhrase 129*99ebad90Sdan } 130*99ebad90Sdan } 131*99ebad90Sdan 132*99ebad90Sdan # Set up the aMatchinfo array. For each document, set aMatchinfo($docid) to 133*99ebad90Sdan # contain the output of matchinfo('x') for the document. 134*99ebad90Sdan # 135*99ebad90Sdan foreach docid [array names hits] { 136*99ebad90Sdan set mi [list] 137*99ebad90Sdan for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { 138*99ebad90Sdan for {set iCol 0} {$iCol<$nCol} {incr iCol} { 139*99ebad90Sdan lappend mi [lindex $counts($docid,$iCol) $iPhrase] 140*99ebad90Sdan lappend mi $nDoc($iPhrase,$iCol) 141*99ebad90Sdan lappend mi $nHit($iPhrase,$iCol) 142*99ebad90Sdan } 143*99ebad90Sdan } 144*99ebad90Sdan set aMatchinfo($docid) $mi 145*99ebad90Sdan } 146*99ebad90Sdan 147*99ebad90Sdan set matchinfo_asc [list] 148*99ebad90Sdan foreach docid [lsort -integer -incr [array names aMatchinfo]] { 149*99ebad90Sdan lappend matchinfo_asc $docid $aMatchinfo($docid) 150*99ebad90Sdan } 151*99ebad90Sdan set matchinfo_desc [list] 152*99ebad90Sdan foreach docid [lsort -integer -decr [array names aMatchinfo]] { 153*99ebad90Sdan lappend matchinfo_desc $docid $aMatchinfo($docid) 154*99ebad90Sdan } 155*99ebad90Sdan 156*99ebad90Sdan set title "(\"$match\" -> [llength [array names hits]] rows)" 157*99ebad90Sdan 158*99ebad90Sdan do_execsql_test $tn$title.1 " 159*99ebad90Sdan SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid ASC 160*99ebad90Sdan " [lsort -integer -incr [array names hits]] 161*99ebad90Sdan 162*99ebad90Sdan do_execsql_test $tn$title.2 " 163*99ebad90Sdan SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid DESC 164*99ebad90Sdan " [lsort -integer -decr [array names hits]] 165*99ebad90Sdan 166*99ebad90Sdan do_execsql_test $tn$title.3 " 167*99ebad90Sdan SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl 168*99ebad90Sdan WHERE $tbl MATCH '$match' ORDER BY docid DESC 169*99ebad90Sdan " $matchinfo_desc 170*99ebad90Sdan 171*99ebad90Sdan do_execsql_test $tn$title.4 " 172*99ebad90Sdan SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl 173*99ebad90Sdan WHERE $tbl MATCH '$match' ORDER BY docid ASC 174*99ebad90Sdan " $matchinfo_asc 175*99ebad90Sdan} 176*99ebad90Sdan 177*99ebad90Sdando_test 2.1 { 178*99ebad90Sdan execsql { CREATE VIRTUAL TABLE t1 USING fts3(a, b) } 179*99ebad90Sdan for {set i 0} {$i<32} {incr i} { 180*99ebad90Sdan set doc [list] 181*99ebad90Sdan if {$i&0x01} {lappend doc one} 182*99ebad90Sdan if {$i&0x02} {lappend doc two} 183*99ebad90Sdan if {$i&0x04} {lappend doc three} 184*99ebad90Sdan if {$i&0x08} {lappend doc four} 185*99ebad90Sdan if {$i&0x10} {lappend doc five} 186*99ebad90Sdan execsql { INSERT INTO t1 VALUES($doc, null) } 187*99ebad90Sdan } 188*99ebad90Sdan} {} 189*99ebad90Sdanforeach {tn expr} { 190*99ebad90Sdan 1 {one} 191*99ebad90Sdan 2 {one NEAR/1 five} 192*99ebad90Sdan 3 {t*} 193*99ebad90Sdan 4 {t* NEAR/0 five} 194*99ebad90Sdan 5 {o* NEAR/1 f*} 195*99ebad90Sdan 6 {one NEAR five NEAR two NEAR four NEAR three} 196*99ebad90Sdan} { 197*99ebad90Sdan do_near_test 2.2.$tn t1 $expr 198*99ebad90Sdan} 199*99ebad90Sdan 200*99ebad90Sdanfinish_test 201*99ebad90Sdan 202