xref: /sqlite-3.40.0/test/fts3auto.test (revision 7d2a1be8)
199ebad90Sdan# 2011 June 10
299ebad90Sdan#
399ebad90Sdan#    May you do good and not evil.
499ebad90Sdan#    May you find forgiveness for yourself and forgive others.
599ebad90Sdan#    May you share freely, never taking more than you give.
699ebad90Sdan#
799ebad90Sdan#***********************************************************************
899ebad90Sdan#
999ebad90Sdan
1099ebad90Sdanset testdir [file dirname $argv0]
1199ebad90Sdansource $testdir/tester.tcl
1299ebad90Sdan
1399ebad90Sdan# If this build does not include FTS3, skip the tests in this file.
1499ebad90Sdan#
1599ebad90Sdanifcapable !fts3 { finish_test ; return }
1699ebad90Sdansource $testdir/fts3_common.tcl
1799ebad90Sdansource $testdir/malloc_common.tcl
1899ebad90Sdan
193fd65192Sdanset testprefix fts3auto
203fd65192Sdanset sfep $sqlite_fts3_enable_parentheses
213fd65192Sdanset sqlite_fts3_enable_parentheses 1
2299ebad90Sdan
233fd65192Sdan#--------------------------------------------------------------------------
24db27fc07Sdan# Start of Tcl infrastructure used by tests. The entry points are:
25db27fc07Sdan#
26db27fc07Sdan#   do_fts3query_test
27db27fc07Sdan#   fts3_make_deferrable
28db27fc07Sdan#   fts3_zero_long_segments
2999ebad90Sdan#
30653265d9Sdan
31db27fc07Sdan#
32653265d9Sdan#    do_fts3query_test TESTNAME ?OPTIONS? TABLE MATCHEXPR
33653265d9Sdan#
34653265d9Sdan# This proc runs several test cases on FTS3/4 table $TABLE using match
35653265d9Sdan# expression $MATCHEXPR. All documents in $TABLE must be formatted so that
36653265d9Sdan# they can be "tokenized" using the Tcl list commands (llength, lindex etc.).
37653265d9Sdan# The name and column names used by $TABLE must not require any quoting or
38653265d9Sdan# escaping when used in SQL statements.
39653265d9Sdan#
40653265d9Sdan# $MATCHINFO may be any expression accepted by the FTS4 MATCH operator,
41653265d9Sdan# except that the "<column-name>:token" syntax is not supported. Tcl list
42653265d9Sdan# commands are used to tokenize the expression. Any parenthesis must appear
43653265d9Sdan# either as separate list elements, or as the first (for opening) or last
44653265d9Sdan# (for closing) character of a list element. i.e. the expression "(a OR b)c"
45653265d9Sdan# will not be parsed correctly, but "( a OR b) c" will.
46653265d9Sdan#
472cf1a1deSdan# Available OPTIONS are:
482cf1a1deSdan#
492cf1a1deSdan#     -deferred TOKENLIST
502cf1a1deSdan#
512cf1a1deSdan# If the "deferred" option is supplied, it is passed a list of tokens that
522cf1a1deSdan# are deferred by FTS and result in the relevant matchinfo() stats being an
532cf1a1deSdan# approximation.
542cf1a1deSdan#
55653265d9Sdanset sqlite_fts3_enable_parentheses 1
562cf1a1deSdanproc do_fts3query_test {tn args} {
57653265d9Sdan
582cf1a1deSdan  set nArg [llength $args]
592cf1a1deSdan  if {$nArg < 2 || ($nArg % 2)} {
602cf1a1deSdan    set cmd do_fts3query_test
612cf1a1deSdan    error "wrong # args: should be \"$cmd ?-deferred LIST? TABLE MATCHEXPR\""
622cf1a1deSdan  }
632cf1a1deSdan  set tbl   [lindex $args [expr $nArg-2]]
642cf1a1deSdan  set match [lindex $args [expr $nArg-1]]
652cf1a1deSdan  set deferred [list]
662cf1a1deSdan
672cf1a1deSdan  foreach {k v} [lrange $args 0 [expr $nArg-3]] {
682cf1a1deSdan    switch -- $k {
692cf1a1deSdan      -deferred {
704dc3d73dSdan        ifcapable fts4_deferred { set deferred $v }
712cf1a1deSdan      }
722cf1a1deSdan      default {
732cf1a1deSdan        error "bad option \"$k\": must be -deferred"
742cf1a1deSdan      }
752cf1a1deSdan    }
762cf1a1deSdan  }
772cf1a1deSdan
785cfed52dSdan  get_near_results $tbl $match $deferred aHit
795cfed52dSdan  get_near_results $tbl [string map {AND OR} $match] $deferred aMatchinfo
80653265d9Sdan
81653265d9Sdan  set matchinfo_asc [list]
825cfed52dSdan  foreach docid [lsort -integer -incr [array names aHit]] {
83653265d9Sdan    lappend matchinfo_asc $docid $aMatchinfo($docid)
84653265d9Sdan  }
85653265d9Sdan  set matchinfo_desc [list]
865cfed52dSdan  foreach docid [lsort -integer -decr [array names aHit]] {
87653265d9Sdan    lappend matchinfo_desc $docid $aMatchinfo($docid)
88653265d9Sdan  }
89653265d9Sdan
905cfed52dSdan  set title "(\"$match\" -> [llength [array names aHit]] rows)"
91653265d9Sdan
92653265d9Sdan  do_execsql_test $tn$title.1 "
93653265d9Sdan    SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid ASC
945cfed52dSdan  " [lsort -integer -incr [array names aHit]]
95653265d9Sdan
96653265d9Sdan  do_execsql_test $tn$title.2 "
97653265d9Sdan    SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid DESC
985cfed52dSdan  " [lsort -integer -decr [array names aHit]]
99653265d9Sdan
100653265d9Sdan  do_execsql_test $tn$title.3 "
101653265d9Sdan    SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl
102653265d9Sdan    WHERE $tbl MATCH '$match' ORDER BY docid DESC
103653265d9Sdan  " $matchinfo_desc
104653265d9Sdan
105653265d9Sdan  do_execsql_test $tn$title.4 "
106653265d9Sdan    SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl
107653265d9Sdan    WHERE $tbl MATCH '$match' ORDER BY docid ASC
108653265d9Sdan  " $matchinfo_asc
109653265d9Sdan}
110653265d9Sdan
111da7b4561Sdan#    fts3_make_deferrable TABLE TOKEN ?NROW?
112db27fc07Sdan#
113da7b4561Sdanproc fts3_make_deferrable {tbl token {nRow 0}} {
114db27fc07Sdan
115db27fc07Sdan  set stmt [sqlite3_prepare db "SELECT * FROM $tbl" -1 dummy]
116db27fc07Sdan  set name [sqlite3_column_name $stmt 0]
117db27fc07Sdan  sqlite3_finalize $stmt
118db27fc07Sdan
119da7b4561Sdan  if {$nRow==0} {
120db27fc07Sdan    set nRow [db one "SELECT count(*) FROM $tbl"]
121da7b4561Sdan  }
122db27fc07Sdan  set pgsz [db one "PRAGMA page_size"]
123db27fc07Sdan  execsql BEGIN
124db27fc07Sdan  for {set i 0} {$i < ($nRow * $pgsz * 1.2)/100} {incr i} {
125db27fc07Sdan    set doc [string repeat "$token " 100]
126db27fc07Sdan    execsql "INSERT INTO $tbl ($name) VALUES(\$doc)"
127db27fc07Sdan  }
128db27fc07Sdan  execsql "INSERT INTO $tbl ($name) VALUES('aaaaaaa ${token}aaaaa')"
129db27fc07Sdan  execsql COMMIT
130db27fc07Sdan
131db27fc07Sdan  return [expr $nRow*$pgsz]
132db27fc07Sdan}
133db27fc07Sdan
134db27fc07Sdan#    fts3_zero_long_segments TABLE ?LIMIT?
135db27fc07Sdan#
136db27fc07Sdanproc fts3_zero_long_segments {tbl limit} {
1370f0d3ddfSdrh  sqlite3_db_config db DEFENSIVE 0
138db27fc07Sdan  execsql "
139db27fc07Sdan    UPDATE ${tbl}_segments
140db27fc07Sdan    SET block = zeroblob(length(block))
141db27fc07Sdan    WHERE length(block)>$limit
142db27fc07Sdan  "
143db27fc07Sdan  return [db changes]
144db27fc07Sdan}
145db27fc07Sdan
146653265d9Sdan
14799ebad90Sdanproc mit {blob} {
14899ebad90Sdan  set scan(littleEndian) i*
14999ebad90Sdan  set scan(bigEndian) I*
15099ebad90Sdan  binary scan $blob $scan($::tcl_platform(byteOrder)) r
15199ebad90Sdan  return $r
15299ebad90Sdan}
15399ebad90Sdandb func mit mit
15499ebad90Sdan
155b727d679Sdanproc fix_phrase_expr {cols expr colfiltervar} {
156b727d679Sdan  upvar $colfiltervar iColFilter
157b727d679Sdan
15899ebad90Sdan  set out [list]
159b727d679Sdan  foreach t $expr {
160b727d679Sdan    if {[string match *:* $t]} {
161b727d679Sdan      set col [lindex [split $t :] 0]
162b727d679Sdan      set t   [lindex [split $t :] 1]
163b727d679Sdan      set iCol [lsearch $cols $col]
164b727d679Sdan      if {$iCol<0} { error "unknown column: $col" }
165b727d679Sdan      if {$iColFilter < 0} {
166b727d679Sdan        set iColFilter $iCol
167b727d679Sdan      } elseif {$iColFilter != $iCol} {
168b727d679Sdan        set iColFilter [llength $cols]
169b727d679Sdan      }
170b727d679Sdan    }
171b727d679Sdan    lappend out $t
172b727d679Sdan  }
173b727d679Sdan
174b727d679Sdan  return $out
175b727d679Sdan}
176b727d679Sdan
177b727d679Sdanproc fix_near_expr {cols expr colfiltervar} {
178b727d679Sdan  upvar $colfiltervar iColFilter
179b727d679Sdan
180b727d679Sdan  set iColFilter -1
181b727d679Sdan
182b727d679Sdan  set out [list]
183b727d679Sdan  lappend out [fix_phrase_expr $cols [lindex $expr 0] iColFilter]
18499ebad90Sdan  foreach {a b} [lrange $expr 1 end] {
18599ebad90Sdan    if {[string match -nocase near $a]}   { set a 10 }
18699ebad90Sdan    if {[string match -nocase near/* $a]} { set a [string range $a 5 end] }
18799ebad90Sdan    lappend out $a
188b727d679Sdan    lappend out [fix_phrase_expr $cols $b iColFilter]
18999ebad90Sdan  }
19099ebad90Sdan  return $out
19199ebad90Sdan}
19299ebad90Sdan
1932cf1a1deSdanproc get_single_near_results {tbl expr deferred arrayvar nullvar} {
1943fd65192Sdan  upvar $arrayvar aMatchinfo
1953fd65192Sdan  upvar $nullvar nullentry
1963fd65192Sdan  catch {array unset aMatchinfo}
19799ebad90Sdan
198b727d679Sdan  set cols [list]
199b727d679Sdan  set miss [list]
200b727d679Sdan  db eval "PRAGMA table_info($tbl)" A { lappend cols $A(name) ; lappend miss 0 }
201b727d679Sdan  set expr [fix_near_expr $cols $expr iColFilter]
20299ebad90Sdan
20399ebad90Sdan  # Calculate the expected results using [fts3_near_match]. The following
20499ebad90Sdan  # loop populates the "hits" and "counts" arrays as follows:
20599ebad90Sdan  #
20699ebad90Sdan  #   1. For each document in the table that matches the NEAR expression,
20799ebad90Sdan  #      hits($docid) is set to 1. The set of docids that match the expression
20899ebad90Sdan  #      can therefore be found using [array names hits].
20999ebad90Sdan  #
21099ebad90Sdan  #   2. For each column of each document in the table, counts($docid,$iCol)
21199ebad90Sdan  #      is set to the -phrasecountvar output.
21299ebad90Sdan  #
21399ebad90Sdan  set res [list]
21499ebad90Sdan  catch { array unset hits }
21599ebad90Sdan  db eval "SELECT docid, * FROM $tbl" d {
21699ebad90Sdan    set iCol 0
21799ebad90Sdan    foreach col [lrange $d(*) 1 end] {
21899ebad90Sdan      set docid $d(docid)
219b727d679Sdan      if {$iColFilter<0 || $iCol==$iColFilter} {
22099ebad90Sdan        set hit [fts3_near_match $d($col) $expr -p counts($docid,$iCol)]
22199ebad90Sdan        if {$hit} { set hits($docid) 1 }
222b727d679Sdan      } else {
223b727d679Sdan        set counts($docid,$iCol) $miss
224b727d679Sdan      }
22599ebad90Sdan      incr iCol
22699ebad90Sdan    }
22799ebad90Sdan  }
22899ebad90Sdan  set nPhrase [expr ([llength $expr]+1)/2]
22999ebad90Sdan  set nCol $iCol
23099ebad90Sdan
23199ebad90Sdan  # This block populates the nHit and nDoc arrays. For each phrase/column
23299ebad90Sdan  # in the query/table, array elements are set as follows:
23399ebad90Sdan  #
23499ebad90Sdan  #   nHit($iPhrase,$iCol) - Total number of hits for phrase $iPhrase in
23599ebad90Sdan  #                          column $iCol.
23699ebad90Sdan  #
23799ebad90Sdan  #   nDoc($iPhrase,$iCol) - Number of documents with at least one hit for
23899ebad90Sdan  #                          phrase $iPhrase in column $iCol.
23999ebad90Sdan  #
24099ebad90Sdan  for {set iPhrase 0} {$iPhrase < $nPhrase} {incr iPhrase} {
24199ebad90Sdan    for {set iCol 0} {$iCol < $nCol} {incr iCol} {
24299ebad90Sdan      set nHit($iPhrase,$iCol) 0
24399ebad90Sdan      set nDoc($iPhrase,$iCol) 0
24499ebad90Sdan    }
24599ebad90Sdan  }
24699ebad90Sdan  foreach key [array names counts] {
24799ebad90Sdan    set iCol [lindex [split $key ,] 1]
24899ebad90Sdan    set iPhrase 0
24999ebad90Sdan    foreach c $counts($key) {
2502f779343Sdan      if {$c>0} { incr nDoc($iPhrase,$iCol) 1 }
2512f779343Sdan      incr nHit($iPhrase,$iCol) $c
25299ebad90Sdan      incr iPhrase
25399ebad90Sdan    }
25499ebad90Sdan  }
25599ebad90Sdan
2562cf1a1deSdan  if {[llength $deferred] && [llength $expr]==1} {
2572f779343Sdan    set phrase [lindex $expr 0]
2582f779343Sdan    set rewritten [list]
2592f779343Sdan    set partial 0
2602f779343Sdan    foreach tok $phrase {
2612cf1a1deSdan      if {[lsearch $deferred $tok]>=0} {
2622f779343Sdan        lappend rewritten *
2632f779343Sdan      } else {
2642f779343Sdan        lappend rewritten $tok
2652f779343Sdan        set partial 1
2662f779343Sdan      }
2672f779343Sdan    }
2682f779343Sdan    if {$partial==0} {
2692f779343Sdan      set tblsize [db one "SELECT count(*) FROM $tbl"]
2702f779343Sdan      for {set iCol 0} {$iCol < $nCol} {incr iCol} {
2712f779343Sdan        set nHit(0,$iCol) $tblsize
2722f779343Sdan        set nDoc(0,$iCol) $tblsize
2732f779343Sdan      }
2742f779343Sdan    } elseif {$rewritten != $phrase} {
2752f779343Sdan      while {[lindex $rewritten end] == "*"} {
2762f779343Sdan        set rewritten [lrange $rewritten 0 end-1]
2772f779343Sdan      }
2782f779343Sdan      while {[lindex $rewritten 0] == "*"} {
2792f779343Sdan        set rewritten [lrange $rewritten 1 end]
2802f779343Sdan      }
2812cf1a1deSdan      get_single_near_results $tbl [list $rewritten] {} aRewrite nullentry
2822f779343Sdan      foreach docid [array names hits] {
2832f779343Sdan        set aMatchinfo($docid) $aRewrite($docid)
2842f779343Sdan      }
2852f779343Sdan      return
2862f779343Sdan    }
2872f779343Sdan  }
2882f779343Sdan
28999ebad90Sdan  # Set up the aMatchinfo array. For each document, set aMatchinfo($docid) to
29099ebad90Sdan  # contain the output of matchinfo('x') for the document.
29199ebad90Sdan  #
29299ebad90Sdan  foreach docid [array names hits] {
29399ebad90Sdan    set mi [list]
29499ebad90Sdan    for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
29599ebad90Sdan      for {set iCol 0} {$iCol<$nCol} {incr iCol} {
29699ebad90Sdan        lappend mi [lindex $counts($docid,$iCol) $iPhrase]
29799ebad90Sdan        lappend mi $nHit($iPhrase,$iCol)
2982f779343Sdan        lappend mi $nDoc($iPhrase,$iCol)
29999ebad90Sdan      }
30099ebad90Sdan    }
30199ebad90Sdan    set aMatchinfo($docid) $mi
30299ebad90Sdan  }
30399ebad90Sdan
3043fd65192Sdan  # Set up the nullentry output.
3053fd65192Sdan  #
3063fd65192Sdan  set nullentry [list]
3073fd65192Sdan  for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
3083fd65192Sdan    for {set iCol 0} {$iCol<$nCol} {incr iCol} {
3092f779343Sdan      lappend nullentry 0 $nHit($iPhrase,$iCol) $nDoc($iPhrase,$iCol)
3103fd65192Sdan    }
3113fd65192Sdan  }
3123fd65192Sdan}
3133fd65192Sdan
3143fd65192Sdan
3153fd65192Sdanproc matching_brackets {expr} {
3163fd65192Sdan  if {[string range $expr 0 0]!="(" || [string range $expr end end] !=")"} {
3173fd65192Sdan    return 0
3183fd65192Sdan  }
3193fd65192Sdan
3203fd65192Sdan  set iBracket 1
3213fd65192Sdan  set nExpr [string length $expr]
3223fd65192Sdan  for {set i 1} {$iBracket && $i < $nExpr} {incr i} {
3233fd65192Sdan    set c [string range $expr $i $i]
3243fd65192Sdan    if {$c == "("} {incr iBracket}
3253fd65192Sdan    if {$c == ")"} {incr iBracket -1}
3263fd65192Sdan  }
3273fd65192Sdan
3283fd65192Sdan  return [expr ($iBracket==0 && $i==$nExpr)]
3293fd65192Sdan}
3303fd65192Sdan
3312cf1a1deSdanproc get_near_results {tbl expr deferred arrayvar {nullvar ""}} {
3323fd65192Sdan  upvar $arrayvar aMatchinfo
3333fd65192Sdan  if {$nullvar != ""} { upvar $nullvar nullentry }
3343fd65192Sdan
3353fd65192Sdan  set expr [string trim $expr]
3363fd65192Sdan  while { [matching_brackets $expr] } {
3373fd65192Sdan    set expr [string trim [string range $expr 1 end-1]]
3383fd65192Sdan  }
3393fd65192Sdan
3403fd65192Sdan  set prec(NOT) 1
3413fd65192Sdan  set prec(AND) 2
3423fd65192Sdan  set prec(OR)  3
3433fd65192Sdan
3443fd65192Sdan  set currentprec 0
3453fd65192Sdan  set iBracket 0
3463fd65192Sdan  set expr_length [llength $expr]
3473fd65192Sdan  for {set i 0} {$i < $expr_length} {incr i} {
3483fd65192Sdan    set op [lindex $expr $i]
3493fd65192Sdan    if {$iBracket==0 && [info exists prec($op)] && $prec($op)>=$currentprec } {
3503fd65192Sdan      set opidx $i
3513fd65192Sdan      set currentprec $prec($op)
3523fd65192Sdan    } else {
3533fd65192Sdan      for {set j 0} {$j < [string length $op]} {incr j} {
3543fd65192Sdan        set c [string range $op $j $j]
3553fd65192Sdan        if {$c == "("} { incr iBracket +1 }
3563fd65192Sdan        if {$c == ")"} { incr iBracket -1 }
3573fd65192Sdan      }
3583fd65192Sdan    }
3593fd65192Sdan  }
3603fd65192Sdan  if {$iBracket!=0} { error "mismatched brackets in: $expr" }
3613fd65192Sdan
3623fd65192Sdan  if {[info exists opidx]==0} {
3632cf1a1deSdan    get_single_near_results $tbl $expr $deferred aMatchinfo nullentry
3643fd65192Sdan  } else {
3653fd65192Sdan    set eLeft  [lrange $expr 0 [expr $opidx-1]]
3663fd65192Sdan    set eRight [lrange $expr [expr $opidx+1] end]
3673fd65192Sdan
3682cf1a1deSdan    get_near_results $tbl $eLeft  $deferred aLeft  nullleft
3692cf1a1deSdan    get_near_results $tbl $eRight $deferred aRight nullright
3703fd65192Sdan
3713fd65192Sdan    switch -- [lindex $expr $opidx] {
3723fd65192Sdan      "NOT" {
3733fd65192Sdan        foreach hit [array names aLeft] {
3743fd65192Sdan          if {0==[info exists aRight($hit)]} {
3753fd65192Sdan            set aMatchinfo($hit) $aLeft($hit)
3763fd65192Sdan          }
3773fd65192Sdan        }
3783fd65192Sdan        set nullentry $nullleft
3793fd65192Sdan      }
3803fd65192Sdan
3813fd65192Sdan      "AND" {
3823fd65192Sdan        foreach hit [array names aLeft] {
3833fd65192Sdan          if {[info exists aRight($hit)]} {
3843fd65192Sdan            set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)]
3853fd65192Sdan          }
3863fd65192Sdan        }
3873fd65192Sdan        set nullentry [concat $nullleft $nullright]
3883fd65192Sdan      }
3893fd65192Sdan
3903fd65192Sdan      "OR" {
3913fd65192Sdan        foreach hit [array names aLeft] {
3923fd65192Sdan          if {[info exists aRight($hit)]} {
3933fd65192Sdan            set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)]
3943fd65192Sdan            unset aRight($hit)
3953fd65192Sdan          } else {
3963fd65192Sdan            set aMatchinfo($hit) [concat $aLeft($hit) $nullright]
3973fd65192Sdan          }
3983fd65192Sdan        }
3993fd65192Sdan        foreach hit [array names aRight] {
4003fd65192Sdan          set aMatchinfo($hit) [concat $nullleft $aRight($hit)]
4013fd65192Sdan        }
4023fd65192Sdan
4033fd65192Sdan        set nullentry [concat $nullleft $nullright]
4043fd65192Sdan      }
4053fd65192Sdan    }
4063fd65192Sdan  }
4073fd65192Sdan}
4083fd65192Sdan
4093fd65192Sdan
4103fd65192Sdan# End of test procs. Actual tests are below this line.
4113fd65192Sdan#--------------------------------------------------------------------------
4123fd65192Sdan
4133fd65192Sdan#--------------------------------------------------------------------------
4143fd65192Sdan# The following test cases - fts3auto-1.* - focus on testing the Tcl
4153fd65192Sdan# command [fts3_near_match], which is used by other tests in this file.
4163fd65192Sdan#
4173fd65192Sdanproc test_fts3_near_match {tn doc expr res} {
4183fd65192Sdan  fts3_near_match $doc $expr -phrasecountvar p
4193fd65192Sdan  uplevel do_test [list $tn] [list [list set {} $p]] [list $res]
4203fd65192Sdan}
4213fd65192Sdan
4223fd65192Sdantest_fts3_near_match 1.1.1 {a b c a b} a                   {2}
4233fd65192Sdantest_fts3_near_match 1.1.2 {a b c a b} {a 5 b 6 c}         {2 2 1}
4243fd65192Sdantest_fts3_near_match 1.1.3 {a b c a b} {"a b"}             {2}
4253fd65192Sdantest_fts3_near_match 1.1.4 {a b c a b} {"b c"}             {1}
4263fd65192Sdantest_fts3_near_match 1.1.5 {a b c a b} {"c c"}             {0}
4273fd65192Sdan
4283fd65192Sdantest_fts3_near_match 1.2.1 "a b c d e f g" {b 2 f}         {0 0}
4293fd65192Sdantest_fts3_near_match 1.2.2 "a b c d e f g" {b 3 f}         {1 1}
4303fd65192Sdantest_fts3_near_match 1.2.3 "a b c d e f g" {f 2 b}         {0 0}
4313fd65192Sdantest_fts3_near_match 1.2.4 "a b c d e f g" {f 3 b}         {1 1}
4323fd65192Sdantest_fts3_near_match 1.2.5 "a b c d e f g" {"a b" 2 "f g"} {0 0}
4333fd65192Sdantest_fts3_near_match 1.2.6 "a b c d e f g" {"a b" 3 "f g"} {1 1}
4343fd65192Sdan
4353fd65192Sdanset 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"
4363fd65192Sdantest_fts3_near_match 1.3.1 $A {"c d" 5 "i j" 1 "e f"}      {0 0 0}
4373fd65192Sdantest_fts3_near_match 1.3.2 $A {"c d" 5 "i j" 2 "e f"}      {1 1 1}
4383fd65192Sdan
4393fd65192Sdan#--------------------------------------------------------------------------
4403fd65192Sdan# Test cases fts3auto-2.* run some simple tests using the
4412f779343Sdan# [do_fts3query_test] proc.
4423fd65192Sdan#
4433fd65192Sdanforeach {tn create} {
4442f779343Sdan  1    "fts4(a, b)"
4452f779343Sdan  2    "fts4(a, b, order=DESC)"
4462f779343Sdan  3    "fts4(a, b, order=ASC)"
4472f779343Sdan  4    "fts4(a, b, prefix=1)"
4482f779343Sdan  5    "fts4(a, b, order=DESC, prefix=1)"
4492f779343Sdan  6    "fts4(a, b, order=ASC, prefix=1)"
4503fd65192Sdan} {
4513fd65192Sdan  do_test 2.$tn.1 {
4523fd65192Sdan    catchsql { DROP TABLE t1 }
4532f779343Sdan    execsql  "CREATE VIRTUAL TABLE t1 USING $create"
45499ebad90Sdan    for {set i 0} {$i<32} {incr i} {
45599ebad90Sdan      set doc [list]
45699ebad90Sdan      if {$i&0x01} {lappend doc one}
45799ebad90Sdan      if {$i&0x02} {lappend doc two}
45899ebad90Sdan      if {$i&0x04} {lappend doc three}
45999ebad90Sdan      if {$i&0x08} {lappend doc four}
46099ebad90Sdan      if {$i&0x10} {lappend doc five}
46199ebad90Sdan      execsql { INSERT INTO t1 VALUES($doc, null) }
46299ebad90Sdan    }
46399ebad90Sdan  } {}
4642f779343Sdan
4653fd65192Sdan  foreach {tn2 expr} {
46699ebad90Sdan    1     {one}
46799ebad90Sdan    2     {one NEAR/1 five}
46899ebad90Sdan    3     {t*}
46999ebad90Sdan    4     {t* NEAR/0 five}
47099ebad90Sdan    5     {o* NEAR/1 f*}
47199ebad90Sdan    6     {one NEAR five NEAR two NEAR four NEAR three}
4723fd65192Sdan    7     {one NEAR xyz}
4733fd65192Sdan    8     {one OR two}
4743fd65192Sdan    9     {one AND two}
4753fd65192Sdan    10    {one NOT two}
4763fd65192Sdan    11    {one AND two OR three}
4773fd65192Sdan    12    {three OR one AND two}
4783fd65192Sdan    13    {(three OR one) AND two}
4793fd65192Sdan    14    {(three OR one) AND two NOT (five NOT four)}
4803fd65192Sdan    15    {"one two"}
4813fd65192Sdan    16    {"one two" NOT "three four"}
48299ebad90Sdan  } {
4832f779343Sdan    do_fts3query_test 2.$tn.2.$tn2 t1 $expr
4842f779343Sdan  }
4852f779343Sdan}
4862f779343Sdan
4872f779343Sdan#--------------------------------------------------------------------------
4882f779343Sdan# Some test cases involving deferred tokens.
4892f779343Sdan#
4902f779343Sdan
4912f779343Sdanforeach {tn create} {
4922f779343Sdan  1    "fts4(x)"
4932f779343Sdan  2    "fts4(x, order=DESC)"
4942f779343Sdan} {
4952f779343Sdan  catchsql { DROP TABLE t1 }
4962f779343Sdan  execsql  "CREATE VIRTUAL TABLE t1 USING $create"
4972f779343Sdan  do_execsql_test 3.$tn.1 {
498653265d9Sdan    INSERT INTO t1(docid, x) VALUES(-2, 'a b c d e f g h i j k');
499653265d9Sdan    INSERT INTO t1(docid, x) VALUES(-1, 'b c d e f g h i j k a');
500653265d9Sdan    INSERT INTO t1(docid, x) VALUES(0, 'c d e f g h i j k a b');
501653265d9Sdan    INSERT INTO t1(docid, x) VALUES(1, 'd e f g h i j k a b c');
502653265d9Sdan    INSERT INTO t1(docid, x) VALUES(2, 'e f g h i j k a b c d');
503653265d9Sdan    INSERT INTO t1(docid, x) VALUES(3, 'f g h i j k a b c d e');
504653265d9Sdan    INSERT INTO t1(docid, x) VALUES(4, 'a c e g i k');
505653265d9Sdan    INSERT INTO t1(docid, x) VALUES(5, 'a d g j');
506653265d9Sdan    INSERT INTO t1(docid, x) VALUES(6, 'c a b');
5072f779343Sdan  }
5082f779343Sdan
509db27fc07Sdan  set limit [fts3_make_deferrable t1 c]
5102f779343Sdan
511db27fc07Sdan  do_fts3query_test 3.$tn.2.1 t1 {a OR c}
5122f779343Sdan
5134dc3d73dSdan  ifcapable fts4_deferred {
5144dc3d73dSdan    do_test 3.$tn.3 { fts3_zero_long_segments t1 $limit } {1}
5154dc3d73dSdan  }
516db27fc07Sdan
5172cf1a1deSdan  foreach {tn2 expr def} {
5182cf1a1deSdan    1     {a NEAR c}            {}
5192cf1a1deSdan    2     {a AND c}             c
5202cf1a1deSdan    3     {"a c"}               c
5212cf1a1deSdan    4     {"c a"}               c
5222cf1a1deSdan    5     {"a c" NEAR/1 g}      {}
5232cf1a1deSdan    6     {"a c" NEAR/0 g}      {}
5242f779343Sdan  } {
525db27fc07Sdan    do_fts3query_test 3.$tn.4.$tn2 -deferred $def t1 $expr
5262cf1a1deSdan  }
5272cf1a1deSdan}
5282cf1a1deSdan
5292cf1a1deSdan#--------------------------------------------------------------------------
5302cf1a1deSdan#
5312cf1a1deSdanforeach {tn create} {
5322cf1a1deSdan  1    "fts4(x, y)"
5332cf1a1deSdan  2    "fts4(x, y, order=DESC)"
534db27fc07Sdan  3    "fts4(x, y, order=DESC, prefix=2)"
5352cf1a1deSdan} {
5362cf1a1deSdan
537db27fc07Sdan  execsql [subst {
538db27fc07Sdan    DROP TABLE t1;
539db27fc07Sdan    CREATE VIRTUAL TABLE t1 USING $create;
540db27fc07Sdan    INSERT INTO t1 VALUES('one two five four five', '');
541db27fc07Sdan    INSERT INTO t1 VALUES('', 'one two five four five');
542db27fc07Sdan    INSERT INTO t1 VALUES('one two', 'five four five');
543db27fc07Sdan  }]
5442cf1a1deSdan
545db27fc07Sdan  do_fts3query_test 4.$tn.1.1 t1 {one AND five}
546db27fc07Sdan  do_fts3query_test 4.$tn.1.2 t1 {one NEAR five}
547db27fc07Sdan  do_fts3query_test 4.$tn.1.3 t1 {one NEAR/1 five}
548db27fc07Sdan  do_fts3query_test 4.$tn.1.4 t1 {one NEAR/2 five}
549db27fc07Sdan  do_fts3query_test 4.$tn.1.5 t1 {one NEAR/3 five}
550db27fc07Sdan
551db27fc07Sdan  do_test 4.$tn.2 {
552db27fc07Sdan    set limit [fts3_make_deferrable t1 five]
553db27fc07Sdan    execsql { INSERT INTO t1(t1) VALUES('optimize') }
5544dc3d73dSdan    ifcapable fts4_deferred {
555db27fc07Sdan      expr {[fts3_zero_long_segments t1 $limit]>0}
5564dc3d73dSdan    } else {
5574dc3d73dSdan      expr 1
5584dc3d73dSdan    }
559db27fc07Sdan  } {1}
560db27fc07Sdan
561db27fc07Sdan  do_fts3query_test 4.$tn.3.1 -deferred five t1 {one AND five}
562db27fc07Sdan  do_fts3query_test 4.$tn.3.2 -deferred five t1 {one NEAR five}
563db27fc07Sdan  do_fts3query_test 4.$tn.3.3 -deferred five t1 {one NEAR/1 five}
564db27fc07Sdan  do_fts3query_test 4.$tn.3.4 -deferred five t1 {one NEAR/2 five}
565d4d21feaSdan
566db27fc07Sdan  do_fts3query_test 4.$tn.3.5 -deferred five t1 {one NEAR/3 five}
567db27fc07Sdan
568db27fc07Sdan  do_fts3query_test 4.$tn.4.1 -deferred fi* t1 {on* AND fi*}
569db27fc07Sdan  do_fts3query_test 4.$tn.4.2 -deferred fi* t1 {on* NEAR fi*}
570db27fc07Sdan  do_fts3query_test 4.$tn.4.3 -deferred fi* t1 {on* NEAR/1 fi*}
571db27fc07Sdan  do_fts3query_test 4.$tn.4.4 -deferred fi* t1 {on* NEAR/2 fi*}
572db27fc07Sdan  do_fts3query_test 4.$tn.4.5 -deferred fi* t1 {on* NEAR/3 fi*}
573804725a6Sdrh
574*7d2a1be8Sdan  ifcapable fts4_deferred {
575804725a6Sdrh    db eval {UPDATE t1_stat SET value=x'' WHERE id=0}
576804725a6Sdrh    do_catchsql_test 4.$tn.4.6 {
577804725a6Sdrh      SELECT docid FROM t1 WHERE t1 MATCH 'on* NEAR/3 fi*'
578804725a6Sdrh    } {1 {database disk image is malformed}}
57999ebad90Sdan  }
580*7d2a1be8Sdan}
58199ebad90Sdan
582376d1e5cSdan#--------------------------------------------------------------------------
583376d1e5cSdan# The following test cases - fts3auto-5.* - focus on using prefix indexes.
584376d1e5cSdan#
585376d1e5cSdanset chunkconfig [fts3_configure_incr_load 1 1]
586d4d21feaSdanforeach {tn create pending} {
587d4d21feaSdan  1    "fts4(a, b)"                                  1
588b727d679Sdan  2    "fts4(a, b, order=ASC, prefix=1)"             1
589585db0e2Sdan  3    "fts4(a, b, order=ASC,  prefix=\"1,3\")"      0
590585db0e2Sdan  4    "fts4(a, b, order=DESC, prefix=\"2,4\")"      0
591585db0e2Sdan  5    "fts4(a, b, order=DESC, prefix=\"1\")"        0
592585db0e2Sdan  6    "fts4(a, b, order=ASC,  prefix=\"1,3\")"      0
593376d1e5cSdan} {
594376d1e5cSdan
595376d1e5cSdan  execsql [subst {
596d4d21feaSdan    DROP TABLE IF EXISTS t1;
597376d1e5cSdan    CREATE VIRTUAL TABLE t1 USING $create;
598376d1e5cSdan  }]
599376d1e5cSdan
600d4d21feaSdan  if {$pending} {execsql BEGIN}
601d4d21feaSdan
602376d1e5cSdan  foreach {a b} {
603376d1e5cSdan    "the song of songs which is solomons"
604376d1e5cSdan    "let him kiss me with the kisses of his mouth for thy love is better than wine"
605376d1e5cSdan    "because of the savour of thy good ointments thy name is as ointment poured forth therefore do the virgins love thee"
606376d1e5cSdan    "draw me we will run after thee the king hath brought me into his chambers we will be glad and rejoice in thee we will remember thy love more than wine the upright love thee"
607376d1e5cSdan    "i am black but comely o ye daughters of jerusalem as the tents of kedar as the curtains of solomon"
608376d1e5cSdan    "look not upon me because i am black because the sun hath looked upon me my mothers children were angry with me they made me the keeper of the vineyards but mine own vineyard have i not kept"
609376d1e5cSdan    "tell me o thou whom my soul loveth where thou feedest where thou makest thy flock to rest at noon for why should i be as one that turneth aside by the flocks of thy companions?"
610376d1e5cSdan    "if thou know not o thou fairest among women go thy way forth by the footsteps of the flock and feed thy kids beside the shepherds tents"
611376d1e5cSdan    "i have compared thee o my love to a company of horses in pharaohs chariots"
612376d1e5cSdan    "thy cheeks are comely with rows of jewels thy neck with chains of gold"
613376d1e5cSdan    "we will make thee borders of gold with studs of silver"
614376d1e5cSdan    "while the king sitteth at his table my spikenard sendeth forth the smell thereof"
615376d1e5cSdan    "a bundle of myrrh is my wellbeloved unto me he shall lie all night betwixt my breasts"
616376d1e5cSdan    "my beloved is unto me as a cluster of camphire in the vineyards of en gedi"
617376d1e5cSdan    "behold thou art fair my love behold thou art fair thou hast doves eyes"
618376d1e5cSdan    "behold thou art fair my beloved yea pleasant also our bed is green"
619376d1e5cSdan    "the beams of our house are cedar and our rafters of fir"
620376d1e5cSdan  } {
621376d1e5cSdan    execsql {INSERT INTO t1(a, b) VALUES($a, $b)}
622376d1e5cSdan  }
623376d1e5cSdan
624d4d21feaSdan
625376d1e5cSdan  do_fts3query_test 5.$tn.1.1 t1 {s*}
626376d1e5cSdan  do_fts3query_test 5.$tn.1.2 t1 {so*}
627376d1e5cSdan  do_fts3query_test 5.$tn.1.3 t1 {"s* o*"}
628376d1e5cSdan  do_fts3query_test 5.$tn.1.4 t1 {b* NEAR/3 a*}
629d4d21feaSdan  do_fts3query_test 5.$tn.1.5 t1 {a*}
630d4d21feaSdan  do_fts3query_test 5.$tn.1.6 t1 {th* NEAR/5 a* NEAR/5 w*}
631d4d21feaSdan  do_fts3query_test 5.$tn.1.7 t1 {"b* th* art* fair*"}
632d4d21feaSdan
633d4d21feaSdan  if {$pending} {execsql COMMIT}
634376d1e5cSdan}
635376d1e5cSdaneval fts3_configure_incr_load $chunkconfig
636376d1e5cSdan
637b727d679Sdanforeach {tn pending create} {
638b727d679Sdan  1    0 "fts4(a, b, c, d)"
639b727d679Sdan  2    1 "fts4(a, b, c, d)"
640b727d679Sdan  3    0 "fts4(a, b, c, d, order=DESC)"
641b727d679Sdan  4    1 "fts4(a, b, c, d, order=DESC)"
642b727d679Sdan} {
643b727d679Sdan  execsql [subst {
644b727d679Sdan    DROP TABLE IF EXISTS t1;
645b727d679Sdan    CREATE VIRTUAL TABLE t1 USING $create;
646b727d679Sdan  }]
647b727d679Sdan
648b727d679Sdan
649b727d679Sdan  if {$pending} { execsql BEGIN }
650b727d679Sdan
651b727d679Sdan  foreach {a b c d} {
652b727d679Sdan    "A B C" "D E F" "G H I" "J K L"
653b727d679Sdan    "B C D" "E F G" "H I J" "K L A"
654b727d679Sdan    "C D E" "F G H" "I J K" "L A B"
655b727d679Sdan    "D E F" "G H I" "J K L" "A B C"
656b727d679Sdan    "E F G" "H I J" "K L A" "B C D"
657b727d679Sdan    "F G H" "I J K" "L A B" "C D E"
658b727d679Sdan  } {
659b727d679Sdan    execsql { INSERT INTO t1 VALUES($a, $b, $c, $d) }
660b727d679Sdan  }
661b727d679Sdan
662b727d679Sdan  do_fts3query_test 6.$tn.1 t1 {b:G}
663b727d679Sdan  do_fts3query_test 6.$tn.2 t1 {b:G AND c:I}
664b727d679Sdan  do_fts3query_test 6.$tn.3 t1 {b:G NEAR c:I}
665b727d679Sdan  do_fts3query_test 6.$tn.4 t1 {a:C OR b:G OR c:K OR d:C}
6665cfed52dSdan
667b727d679Sdan  do_fts3query_test 6.$tn.5 t1 {a:G OR b:G}
668b727d679Sdan
669b727d679Sdan  catchsql { COMMIT }
670b727d679Sdan}
671b727d679Sdan
672da7b4561Sdanforeach {tn create} {
673da7b4561Sdan  1    "fts4(x)"
674da7b4561Sdan  2    "fts4(x, order=DESC)"
675da7b4561Sdan} {
676da7b4561Sdan  execsql [subst {
677da7b4561Sdan    DROP TABLE IF EXISTS t1;
678da7b4561Sdan    CREATE VIRTUAL TABLE t1 USING $create;
679da7b4561Sdan  }]
680da7b4561Sdan
681da7b4561Sdan  foreach {x} {
682da7b4561Sdan    "F E N O T K X V A X I E X A P G Q V H U"
683da7b4561Sdan    "R V A E T C V Q N I E L O N U G J K L U"
684da7b4561Sdan    "U Y I G W M V F J L X I D C H F P J Q B"
685da7b4561Sdan    "S G D Z X R P G S S Y B K A S G A I L L"
686da7b4561Sdan    "L S I C H T Z S R Q P R N K J X L F M J"
687da7b4561Sdan    "C C C D P X B Z C M A D A C X S B T X V"
688da7b4561Sdan    "W Y J M D R G V R K B X S A W R I T N C"
689da7b4561Sdan    "P K L W T M S P O Y Y V V O E H Q A I R"
690da7b4561Sdan    "C D Y I C Z F H J C O Y A Q F L S B D K"
691da7b4561Sdan    "P G S C Y C Y V I M B D S Z D D Y W I E"
692da7b4561Sdan    "Z K Z U E E S F Y X T U A L W O U J C Q"
693da7b4561Sdan    "P A T Z S W L P L Q V Y Y I P W U X S S"
694da7b4561Sdan    "I U I H U O F Z F R H R F T N D X A G M"
695da7b4561Sdan    "N A B M S H K X S O Y D T X S B R Y H Z"
696da7b4561Sdan    "L U D A S K I L S V Z J P U B E B Y H M"
697da7b4561Sdan  } {
698da7b4561Sdan    execsql { INSERT INTO t1 VALUES($x) }
699da7b4561Sdan  }
700da7b4561Sdan
701da7b4561Sdan  # Add extra documents to the database such that token "B" will be considered
702da7b4561Sdan  # deferrable if considering the other tokens means that 2 or fewer documents
703da7b4561Sdan  # will be loaded into memory.
704da7b4561Sdan  #
705da7b4561Sdan  fts3_make_deferrable t1 B 2
706da7b4561Sdan
707da7b4561Sdan  # B is not deferred in either of the first two tests below, since filtering
708da7b4561Sdan  # on "M" or "D" returns 10 documents or so. But filtering on "M * D" only
709da7b4561Sdan  # returns 2, so B is deferred in this case.
710da7b4561Sdan  #
711da7b4561Sdan  do_fts3query_test 7.$tn.1             t1 {"M B"}
712da7b4561Sdan  do_fts3query_test 7.$tn.2             t1 {"B D"}
713da7b4561Sdan  do_fts3query_test 7.$tn.3 -deferred B t1 {"M B D"}
714da7b4561Sdan}
715da7b4561Sdan
7163fd65192Sdanset sqlite_fts3_enable_parentheses $sfep
71799ebad90Sdanfinish_test
718