xref: /sqlite-3.40.0/test/fts3auto.test (revision 99ebad90)
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