| OLD | NEW | 
| (Empty) |  | 
 |    1 # 2011 June 10 | 
 |    2 # | 
 |    3 #    May you do good and not evil. | 
 |    4 #    May you find forgiveness for yourself and forgive others. | 
 |    5 #    May you share freely, never taking more than you give. | 
 |    6 # | 
 |    7 #*********************************************************************** | 
 |    8 # | 
 |    9  | 
 |   10 set testdir [file dirname $argv0] | 
 |   11 source $testdir/tester.tcl | 
 |   12  | 
 |   13 # If this build does not include FTS3, skip the tests in this file. | 
 |   14 # | 
 |   15 ifcapable !fts3 { finish_test ; return } | 
 |   16 source $testdir/fts3_common.tcl | 
 |   17 source $testdir/malloc_common.tcl | 
 |   18  | 
 |   19 set testprefix fts3auto | 
 |   20 set sfep $sqlite_fts3_enable_parentheses | 
 |   21 set sqlite_fts3_enable_parentheses 1 | 
 |   22  | 
 |   23 #-------------------------------------------------------------------------- | 
 |   24 # Start of Tcl infrastructure used by tests. The entry points are: | 
 |   25 # | 
 |   26 #   do_fts3query_test | 
 |   27 #   fts3_make_deferrable | 
 |   28 #   fts3_zero_long_segments  | 
 |   29 # | 
 |   30  | 
 |   31 # | 
 |   32 #    do_fts3query_test TESTNAME ?OPTIONS? TABLE MATCHEXPR | 
 |   33 # | 
 |   34 # This proc runs several test cases on FTS3/4 table $TABLE using match | 
 |   35 # expression $MATCHEXPR. All documents in $TABLE must be formatted so that | 
 |   36 # they can be "tokenized" using the Tcl list commands (llength, lindex etc.). | 
 |   37 # The name and column names used by $TABLE must not require any quoting or | 
 |   38 # escaping when used in SQL statements. | 
 |   39 # | 
 |   40 # $MATCHINFO may be any expression accepted by the FTS4 MATCH operator,  | 
 |   41 # except that the "<column-name>:token" syntax is not supported. Tcl list | 
 |   42 # commands are used to tokenize the expression. Any parenthesis must appear | 
 |   43 # either as separate list elements, or as the first (for opening) or last | 
 |   44 # (for closing) character of a list element. i.e. the expression "(a OR b)c" | 
 |   45 # will not be parsed correctly, but "( a OR b) c" will. | 
 |   46 # | 
 |   47 # Available OPTIONS are: | 
 |   48 # | 
 |   49 #     -deferred TOKENLIST | 
 |   50 # | 
 |   51 # If the "deferred" option is supplied, it is passed a list of tokens that | 
 |   52 # are deferred by FTS and result in the relevant matchinfo() stats being an | 
 |   53 # approximation.  | 
 |   54 # | 
 |   55 set sqlite_fts3_enable_parentheses 1 | 
 |   56 proc do_fts3query_test {tn args} { | 
 |   57  | 
 |   58   set nArg [llength $args] | 
 |   59   if {$nArg < 2 || ($nArg % 2)} { | 
 |   60     set cmd do_fts3query_test | 
 |   61     error "wrong # args: should be \"$cmd ?-deferred LIST? TABLE MATCHEXPR\"" | 
 |   62   } | 
 |   63   set tbl   [lindex $args [expr $nArg-2]] | 
 |   64   set match [lindex $args [expr $nArg-1]] | 
 |   65   set deferred [list] | 
 |   66  | 
 |   67   foreach {k v} [lrange $args 0 [expr $nArg-3]] { | 
 |   68     switch -- $k { | 
 |   69       -deferred { | 
 |   70         ifcapable fts4_deferred { set deferred $v } | 
 |   71       } | 
 |   72       default { | 
 |   73         error "bad option \"$k\": must be -deferred" | 
 |   74       } | 
 |   75     } | 
 |   76   } | 
 |   77  | 
 |   78   get_near_results $tbl $match $deferred aHit | 
 |   79   get_near_results $tbl [string map {AND OR} $match] $deferred aMatchinfo | 
 |   80  | 
 |   81   set matchinfo_asc [list] | 
 |   82   foreach docid [lsort -integer -incr [array names aHit]] { | 
 |   83     lappend matchinfo_asc $docid $aMatchinfo($docid) | 
 |   84   } | 
 |   85   set matchinfo_desc [list] | 
 |   86   foreach docid [lsort -integer -decr [array names aHit]] { | 
 |   87     lappend matchinfo_desc $docid $aMatchinfo($docid) | 
 |   88   } | 
 |   89  | 
 |   90   set title "(\"$match\" -> [llength [array names aHit]] rows)" | 
 |   91  | 
 |   92   do_execsql_test $tn$title.1 " | 
 |   93     SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid ASC | 
 |   94   " [lsort -integer -incr [array names aHit]]  | 
 |   95  | 
 |   96   do_execsql_test $tn$title.2 " | 
 |   97     SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid DESC | 
 |   98   " [lsort -integer -decr [array names aHit]]  | 
 |   99  | 
 |  100   do_execsql_test $tn$title.3 " | 
 |  101     SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl  | 
 |  102     WHERE $tbl MATCH '$match' ORDER BY docid DESC | 
 |  103   " $matchinfo_desc | 
 |  104  | 
 |  105   do_execsql_test $tn$title.4 " | 
 |  106     SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl  | 
 |  107     WHERE $tbl MATCH '$match' ORDER BY docid ASC | 
 |  108   " $matchinfo_asc | 
 |  109 } | 
 |  110  | 
 |  111 #    fts3_make_deferrable TABLE TOKEN ?NROW? | 
 |  112 # | 
 |  113 proc fts3_make_deferrable {tbl token {nRow 0}} { | 
 |  114  | 
 |  115   set stmt [sqlite3_prepare db "SELECT * FROM $tbl" -1 dummy] | 
 |  116   set name [sqlite3_column_name $stmt 0] | 
 |  117   sqlite3_finalize $stmt | 
 |  118  | 
 |  119   if {$nRow==0} { | 
 |  120     set nRow [db one "SELECT count(*) FROM $tbl"] | 
 |  121   } | 
 |  122   set pgsz [db one "PRAGMA page_size"] | 
 |  123   execsql BEGIN | 
 |  124   for {set i 0} {$i < ($nRow * $pgsz * 1.2)/100} {incr i} { | 
 |  125     set doc [string repeat "$token " 100] | 
 |  126     execsql "INSERT INTO $tbl ($name) VALUES(\$doc)" | 
 |  127   } | 
 |  128   execsql "INSERT INTO $tbl ($name) VALUES('aaaaaaa ${token}aaaaa')" | 
 |  129   execsql COMMIT | 
 |  130  | 
 |  131   return [expr $nRow*$pgsz] | 
 |  132 } | 
 |  133  | 
 |  134 #    fts3_zero_long_segments TABLE ?LIMIT? | 
 |  135 # | 
 |  136 proc fts3_zero_long_segments {tbl limit} { | 
 |  137   execsql "  | 
 |  138     UPDATE ${tbl}_segments  | 
 |  139     SET block = zeroblob(length(block))  | 
 |  140     WHERE length(block)>$limit | 
 |  141   " | 
 |  142   return [db changes] | 
 |  143 } | 
 |  144  | 
 |  145  | 
 |  146 proc mit {blob} { | 
 |  147   set scan(littleEndian) i* | 
 |  148   set scan(bigEndian) I* | 
 |  149   binary scan $blob $scan($::tcl_platform(byteOrder)) r | 
 |  150   return $r | 
 |  151 } | 
 |  152 db func mit mit | 
 |  153  | 
 |  154 proc fix_phrase_expr {cols expr colfiltervar} { | 
 |  155   upvar $colfiltervar iColFilter | 
 |  156  | 
 |  157   set out [list] | 
 |  158   foreach t $expr { | 
 |  159     if {[string match *:* $t]} { | 
 |  160       set col [lindex [split $t :] 0] | 
 |  161       set t   [lindex [split $t :] 1] | 
 |  162       set iCol [lsearch $cols $col] | 
 |  163       if {$iCol<0} { error "unknown column: $col" } | 
 |  164       if {$iColFilter < 0} { | 
 |  165         set iColFilter $iCol | 
 |  166       } elseif {$iColFilter != $iCol} { | 
 |  167         set iColFilter [llength $cols] | 
 |  168       } | 
 |  169     } | 
 |  170     lappend out $t | 
 |  171   } | 
 |  172  | 
 |  173   return $out | 
 |  174 } | 
 |  175  | 
 |  176 proc fix_near_expr {cols expr colfiltervar} {  | 
 |  177   upvar $colfiltervar iColFilter | 
 |  178   | 
 |  179   set iColFilter -1 | 
 |  180  | 
 |  181   set out [list] | 
 |  182   lappend out [fix_phrase_expr $cols [lindex $expr 0] iColFilter] | 
 |  183   foreach {a b} [lrange $expr 1 end] { | 
 |  184     if {[string match -nocase near $a]}   { set a 10 } | 
 |  185     if {[string match -nocase near/* $a]} { set a [string range $a 5 end] } | 
 |  186     lappend out $a | 
 |  187     lappend out [fix_phrase_expr $cols $b iColFilter] | 
 |  188   } | 
 |  189   return $out | 
 |  190 } | 
 |  191  | 
 |  192 proc get_single_near_results {tbl expr deferred arrayvar nullvar} { | 
 |  193   upvar $arrayvar aMatchinfo | 
 |  194   upvar $nullvar nullentry | 
 |  195   catch {array unset aMatchinfo} | 
 |  196  | 
 |  197   set cols [list] | 
 |  198   set miss [list] | 
 |  199   db eval "PRAGMA table_info($tbl)" A { lappend cols $A(name) ; lappend miss 0 } | 
 |  200   set expr [fix_near_expr $cols $expr iColFilter] | 
 |  201  | 
 |  202   # Calculate the expected results using [fts3_near_match]. The following | 
 |  203   # loop populates the "hits" and "counts" arrays as follows: | 
 |  204   #  | 
 |  205   #   1. For each document in the table that matches the NEAR expression, | 
 |  206   #      hits($docid) is set to 1. The set of docids that match the expression | 
 |  207   #      can therefore be found using [array names hits]. | 
 |  208   # | 
 |  209   #   2. For each column of each document in the table, counts($docid,$iCol) | 
 |  210   #      is set to the -phrasecountvar output. | 
 |  211   # | 
 |  212   set res [list] | 
 |  213   catch { array unset hits } | 
 |  214   db eval "SELECT docid, * FROM $tbl" d { | 
 |  215     set iCol 0 | 
 |  216     foreach col [lrange $d(*) 1 end] { | 
 |  217       set docid $d(docid) | 
 |  218       if {$iColFilter<0 || $iCol==$iColFilter} { | 
 |  219         set hit [fts3_near_match $d($col) $expr -p counts($docid,$iCol)] | 
 |  220         if {$hit} { set hits($docid) 1 } | 
 |  221       } else { | 
 |  222         set counts($docid,$iCol) $miss | 
 |  223       } | 
 |  224       incr iCol | 
 |  225     } | 
 |  226   } | 
 |  227   set nPhrase [expr ([llength $expr]+1)/2] | 
 |  228   set nCol $iCol | 
 |  229  | 
 |  230   # This block populates the nHit and nDoc arrays. For each phrase/column | 
 |  231   # in the query/table, array elements are set as follows: | 
 |  232   # | 
 |  233   #   nHit($iPhrase,$iCol) - Total number of hits for phrase $iPhrase in  | 
 |  234   #                          column $iCol. | 
 |  235   # | 
 |  236   #   nDoc($iPhrase,$iCol) - Number of documents with at least one hit for | 
 |  237   #                          phrase $iPhrase in column $iCol. | 
 |  238   # | 
 |  239   for {set iPhrase 0} {$iPhrase < $nPhrase} {incr iPhrase} { | 
 |  240     for {set iCol 0} {$iCol < $nCol} {incr iCol} { | 
 |  241       set nHit($iPhrase,$iCol) 0 | 
 |  242       set nDoc($iPhrase,$iCol) 0 | 
 |  243     } | 
 |  244   } | 
 |  245   foreach key [array names counts] { | 
 |  246     set iCol [lindex [split $key ,] 1] | 
 |  247     set iPhrase 0 | 
 |  248     foreach c $counts($key) { | 
 |  249       if {$c>0} { incr nDoc($iPhrase,$iCol) 1 } | 
 |  250       incr nHit($iPhrase,$iCol) $c | 
 |  251       incr iPhrase | 
 |  252     } | 
 |  253   } | 
 |  254  | 
 |  255   if {[llength $deferred] && [llength $expr]==1} { | 
 |  256     set phrase [lindex $expr 0] | 
 |  257     set rewritten [list] | 
 |  258     set partial 0 | 
 |  259     foreach tok $phrase { | 
 |  260       if {[lsearch $deferred $tok]>=0} { | 
 |  261         lappend rewritten * | 
 |  262       } else { | 
 |  263         lappend rewritten $tok | 
 |  264         set partial 1 | 
 |  265       } | 
 |  266     } | 
 |  267     if {$partial==0} { | 
 |  268       set tblsize [db one "SELECT count(*) FROM $tbl"] | 
 |  269       for {set iCol 0} {$iCol < $nCol} {incr iCol} { | 
 |  270         set nHit(0,$iCol) $tblsize | 
 |  271         set nDoc(0,$iCol) $tblsize | 
 |  272       } | 
 |  273     } elseif {$rewritten != $phrase} { | 
 |  274       while {[lindex $rewritten end] == "*"} { | 
 |  275         set rewritten [lrange $rewritten 0 end-1] | 
 |  276       } | 
 |  277       while {[lindex $rewritten 0] == "*"} { | 
 |  278         set rewritten [lrange $rewritten 1 end] | 
 |  279       } | 
 |  280       get_single_near_results $tbl [list $rewritten] {} aRewrite nullentry | 
 |  281       foreach docid [array names hits] { | 
 |  282         set aMatchinfo($docid) $aRewrite($docid) | 
 |  283       } | 
 |  284       return | 
 |  285     } | 
 |  286   } | 
 |  287  | 
 |  288   # Set up the aMatchinfo array. For each document, set aMatchinfo($docid) to | 
 |  289   # contain the output of matchinfo('x') for the document. | 
 |  290   # | 
 |  291   foreach docid [array names hits] { | 
 |  292     set mi [list] | 
 |  293     for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { | 
 |  294       for {set iCol 0} {$iCol<$nCol} {incr iCol} { | 
 |  295         lappend mi [lindex $counts($docid,$iCol) $iPhrase] | 
 |  296         lappend mi $nHit($iPhrase,$iCol) | 
 |  297         lappend mi $nDoc($iPhrase,$iCol) | 
 |  298       } | 
 |  299     } | 
 |  300     set aMatchinfo($docid) $mi | 
 |  301   } | 
 |  302  | 
 |  303   # Set up the nullentry output. | 
 |  304   # | 
 |  305   set nullentry [list] | 
 |  306   for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { | 
 |  307     for {set iCol 0} {$iCol<$nCol} {incr iCol} { | 
 |  308       lappend nullentry 0 $nHit($iPhrase,$iCol) $nDoc($iPhrase,$iCol) | 
 |  309     } | 
 |  310   } | 
 |  311 } | 
 |  312  | 
 |  313  | 
 |  314 proc matching_brackets {expr} { | 
 |  315   if {[string range $expr 0 0]!="(" || [string range $expr end end] !=")"} {  | 
 |  316     return 0  | 
 |  317   } | 
 |  318  | 
 |  319   set iBracket 1 | 
 |  320   set nExpr [string length $expr] | 
 |  321   for {set i 1} {$iBracket && $i < $nExpr} {incr i} { | 
 |  322     set c [string range $expr $i $i] | 
 |  323     if {$c == "("} {incr iBracket} | 
 |  324     if {$c == ")"} {incr iBracket -1} | 
 |  325   } | 
 |  326  | 
 |  327   return [expr ($iBracket==0 && $i==$nExpr)] | 
 |  328 } | 
 |  329  | 
 |  330 proc get_near_results {tbl expr deferred arrayvar {nullvar ""}} { | 
 |  331   upvar $arrayvar aMatchinfo | 
 |  332   if {$nullvar != ""} { upvar $nullvar nullentry } | 
 |  333  | 
 |  334   set expr [string trim $expr] | 
 |  335   while { [matching_brackets $expr] } { | 
 |  336     set expr [string trim [string range $expr 1 end-1]] | 
 |  337   } | 
 |  338  | 
 |  339   set prec(NOT) 1 | 
 |  340   set prec(AND) 2 | 
 |  341   set prec(OR)  3 | 
 |  342  | 
 |  343   set currentprec 0 | 
 |  344   set iBracket 0 | 
 |  345   set expr_length [llength $expr] | 
 |  346   for {set i 0} {$i < $expr_length} {incr i} { | 
 |  347     set op [lindex $expr $i] | 
 |  348     if {$iBracket==0 && [info exists prec($op)] && $prec($op)>=$currentprec } { | 
 |  349       set opidx $i | 
 |  350       set currentprec $prec($op) | 
 |  351     } else { | 
 |  352       for {set j 0} {$j < [string length $op]} {incr j} { | 
 |  353         set c [string range $op $j $j] | 
 |  354         if {$c == "("} { incr iBracket +1 } | 
 |  355         if {$c == ")"} { incr iBracket -1 } | 
 |  356       } | 
 |  357     } | 
 |  358   } | 
 |  359   if {$iBracket!=0} { error "mismatched brackets in: $expr" } | 
 |  360  | 
 |  361   if {[info exists opidx]==0} { | 
 |  362     get_single_near_results $tbl $expr $deferred aMatchinfo nullentry | 
 |  363   } else { | 
 |  364     set eLeft  [lrange $expr 0 [expr $opidx-1]] | 
 |  365     set eRight [lrange $expr [expr $opidx+1] end] | 
 |  366  | 
 |  367     get_near_results $tbl $eLeft  $deferred aLeft  nullleft | 
 |  368     get_near_results $tbl $eRight $deferred aRight nullright | 
 |  369  | 
 |  370     switch -- [lindex $expr $opidx] { | 
 |  371       "NOT" { | 
 |  372         foreach hit [array names aLeft] { | 
 |  373           if {0==[info exists aRight($hit)]} { | 
 |  374             set aMatchinfo($hit) $aLeft($hit) | 
 |  375           } | 
 |  376         } | 
 |  377         set nullentry $nullleft | 
 |  378       } | 
 |  379  | 
 |  380       "AND" { | 
 |  381         foreach hit [array names aLeft] { | 
 |  382           if {[info exists aRight($hit)]} { | 
 |  383             set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)] | 
 |  384           } | 
 |  385         } | 
 |  386         set nullentry [concat $nullleft $nullright] | 
 |  387       } | 
 |  388  | 
 |  389       "OR" { | 
 |  390         foreach hit [array names aLeft] { | 
 |  391           if {[info exists aRight($hit)]} { | 
 |  392             set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)] | 
 |  393             unset aRight($hit) | 
 |  394           } else { | 
 |  395             set aMatchinfo($hit) [concat $aLeft($hit) $nullright] | 
 |  396           } | 
 |  397         } | 
 |  398         foreach hit [array names aRight] { | 
 |  399           set aMatchinfo($hit) [concat $nullleft $aRight($hit)] | 
 |  400         } | 
 |  401  | 
 |  402         set nullentry [concat $nullleft $nullright] | 
 |  403       } | 
 |  404     } | 
 |  405   } | 
 |  406 } | 
 |  407  | 
 |  408  | 
 |  409 # End of test procs. Actual tests are below this line. | 
 |  410 #-------------------------------------------------------------------------- | 
 |  411  | 
 |  412 #-------------------------------------------------------------------------- | 
 |  413 # The following test cases - fts3auto-1.* - focus on testing the Tcl  | 
 |  414 # command [fts3_near_match], which is used by other tests in this file. | 
 |  415 # | 
 |  416 proc test_fts3_near_match {tn doc expr res} { | 
 |  417   fts3_near_match $doc $expr -phrasecountvar p | 
 |  418   uplevel do_test [list $tn] [list [list set {} $p]] [list $res] | 
 |  419 } | 
 |  420  | 
 |  421 test_fts3_near_match 1.1.1 {a b c a b} a                   {2} | 
 |  422 test_fts3_near_match 1.1.2 {a b c a b} {a 5 b 6 c}         {2 2 1} | 
 |  423 test_fts3_near_match 1.1.3 {a b c a b} {"a b"}             {2} | 
 |  424 test_fts3_near_match 1.1.4 {a b c a b} {"b c"}             {1} | 
 |  425 test_fts3_near_match 1.1.5 {a b c a b} {"c c"}             {0} | 
 |  426  | 
 |  427 test_fts3_near_match 1.2.1 "a b c d e f g" {b 2 f}         {0 0} | 
 |  428 test_fts3_near_match 1.2.2 "a b c d e f g" {b 3 f}         {1 1} | 
 |  429 test_fts3_near_match 1.2.3 "a b c d e f g" {f 2 b}         {0 0} | 
 |  430 test_fts3_near_match 1.2.4 "a b c d e f g" {f 3 b}         {1 1} | 
 |  431 test_fts3_near_match 1.2.5 "a b c d e f g" {"a b" 2 "f g"} {0 0} | 
 |  432 test_fts3_near_match 1.2.6 "a b c d e f g" {"a b" 3 "f g"} {1 1} | 
 |  433  | 
 |  434 set 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" | 
 |  435 test_fts3_near_match 1.3.1 $A {"c d" 5 "i j" 1 "e f"}      {0 0 0} | 
 |  436 test_fts3_near_match 1.3.2 $A {"c d" 5 "i j" 2 "e f"}      {1 1 1} | 
 |  437  | 
 |  438 #-------------------------------------------------------------------------- | 
 |  439 # Test cases fts3auto-2.* run some simple tests using the  | 
 |  440 # [do_fts3query_test] proc. | 
 |  441 # | 
 |  442 foreach {tn create} { | 
 |  443   1    "fts4(a, b)" | 
 |  444   2    "fts4(a, b, order=DESC)" | 
 |  445   3    "fts4(a, b, order=ASC)" | 
 |  446   4    "fts4(a, b, prefix=1)" | 
 |  447   5    "fts4(a, b, order=DESC, prefix=1)" | 
 |  448   6    "fts4(a, b, order=ASC, prefix=1)" | 
 |  449 } { | 
 |  450   do_test 2.$tn.1 { | 
 |  451     catchsql { DROP TABLE t1 } | 
 |  452     execsql  "CREATE VIRTUAL TABLE t1 USING $create" | 
 |  453     for {set i 0} {$i<32} {incr i} { | 
 |  454       set doc [list] | 
 |  455       if {$i&0x01} {lappend doc one} | 
 |  456       if {$i&0x02} {lappend doc two} | 
 |  457       if {$i&0x04} {lappend doc three} | 
 |  458       if {$i&0x08} {lappend doc four} | 
 |  459       if {$i&0x10} {lappend doc five} | 
 |  460       execsql { INSERT INTO t1 VALUES($doc, null) } | 
 |  461     } | 
 |  462   } {} | 
 |  463  | 
 |  464   foreach {tn2 expr} { | 
 |  465     1     {one} | 
 |  466     2     {one NEAR/1 five} | 
 |  467     3     {t*} | 
 |  468     4     {t* NEAR/0 five} | 
 |  469     5     {o* NEAR/1 f*} | 
 |  470     6     {one NEAR five NEAR two NEAR four NEAR three} | 
 |  471     7     {one NEAR xyz} | 
 |  472     8     {one OR two} | 
 |  473     9     {one AND two} | 
 |  474     10    {one NOT two} | 
 |  475     11    {one AND two OR three} | 
 |  476     12    {three OR one AND two} | 
 |  477     13    {(three OR one) AND two} | 
 |  478     14    {(three OR one) AND two NOT (five NOT four)} | 
 |  479     15    {"one two"} | 
 |  480     16    {"one two" NOT "three four"} | 
 |  481   } { | 
 |  482     do_fts3query_test 2.$tn.2.$tn2 t1 $expr | 
 |  483   } | 
 |  484 } | 
 |  485  | 
 |  486 #-------------------------------------------------------------------------- | 
 |  487 # Some test cases involving deferred tokens. | 
 |  488 # | 
 |  489  | 
 |  490 foreach {tn create} { | 
 |  491   1    "fts4(x)" | 
 |  492   2    "fts4(x, order=DESC)" | 
 |  493 } { | 
 |  494   catchsql { DROP TABLE t1 } | 
 |  495   execsql  "CREATE VIRTUAL TABLE t1 USING $create" | 
 |  496   do_execsql_test 3.$tn.1 { | 
 |  497     INSERT INTO t1(docid, x) VALUES(-2, 'a b c d e f g h i j k'); | 
 |  498     INSERT INTO t1(docid, x) VALUES(-1, 'b c d e f g h i j k a'); | 
 |  499     INSERT INTO t1(docid, x) VALUES(0, 'c d e f g h i j k a b'); | 
 |  500     INSERT INTO t1(docid, x) VALUES(1, 'd e f g h i j k a b c'); | 
 |  501     INSERT INTO t1(docid, x) VALUES(2, 'e f g h i j k a b c d'); | 
 |  502     INSERT INTO t1(docid, x) VALUES(3, 'f g h i j k a b c d e'); | 
 |  503     INSERT INTO t1(docid, x) VALUES(4, 'a c e g i k'); | 
 |  504     INSERT INTO t1(docid, x) VALUES(5, 'a d g j'); | 
 |  505     INSERT INTO t1(docid, x) VALUES(6, 'c a b'); | 
 |  506   } | 
 |  507  | 
 |  508   set limit [fts3_make_deferrable t1 c] | 
 |  509  | 
 |  510   do_fts3query_test 3.$tn.2.1 t1 {a OR c} | 
 |  511  | 
 |  512   ifcapable fts4_deferred { | 
 |  513     do_test 3.$tn.3 { fts3_zero_long_segments t1 $limit } {1} | 
 |  514   } | 
 |  515  | 
 |  516   foreach {tn2 expr def} { | 
 |  517     1     {a NEAR c}            {} | 
 |  518     2     {a AND c}             c | 
 |  519     3     {"a c"}               c | 
 |  520     4     {"c a"}               c | 
 |  521     5     {"a c" NEAR/1 g}      {} | 
 |  522     6     {"a c" NEAR/0 g}      {} | 
 |  523   } { | 
 |  524     do_fts3query_test 3.$tn.4.$tn2 -deferred $def t1 $expr | 
 |  525   } | 
 |  526 } | 
 |  527  | 
 |  528 #-------------------------------------------------------------------------- | 
 |  529 #  | 
 |  530 foreach {tn create} { | 
 |  531   1    "fts4(x, y)" | 
 |  532   2    "fts4(x, y, order=DESC)" | 
 |  533   3    "fts4(x, y, order=DESC, prefix=2)" | 
 |  534 } { | 
 |  535  | 
 |  536   execsql [subst { | 
 |  537     DROP TABLE t1; | 
 |  538     CREATE VIRTUAL TABLE t1 USING $create; | 
 |  539     INSERT INTO t1 VALUES('one two five four five', ''); | 
 |  540     INSERT INTO t1 VALUES('', 'one two five four five'); | 
 |  541     INSERT INTO t1 VALUES('one two', 'five four five'); | 
 |  542   }] | 
 |  543  | 
 |  544   do_fts3query_test 4.$tn.1.1 t1 {one AND five} | 
 |  545   do_fts3query_test 4.$tn.1.2 t1 {one NEAR five} | 
 |  546   do_fts3query_test 4.$tn.1.3 t1 {one NEAR/1 five} | 
 |  547   do_fts3query_test 4.$tn.1.4 t1 {one NEAR/2 five} | 
 |  548   do_fts3query_test 4.$tn.1.5 t1 {one NEAR/3 five} | 
 |  549  | 
 |  550   do_test 4.$tn.2 {  | 
 |  551     set limit [fts3_make_deferrable t1 five] | 
 |  552     execsql { INSERT INTO t1(t1) VALUES('optimize') } | 
 |  553     ifcapable fts4_deferred { | 
 |  554       expr {[fts3_zero_long_segments t1 $limit]>0} | 
 |  555     } else { | 
 |  556       expr 1 | 
 |  557     } | 
 |  558   } {1} | 
 |  559  | 
 |  560   do_fts3query_test 4.$tn.3.1 -deferred five t1 {one AND five} | 
 |  561   do_fts3query_test 4.$tn.3.2 -deferred five t1 {one NEAR five} | 
 |  562   do_fts3query_test 4.$tn.3.3 -deferred five t1 {one NEAR/1 five} | 
 |  563   do_fts3query_test 4.$tn.3.4 -deferred five t1 {one NEAR/2 five} | 
 |  564  | 
 |  565   do_fts3query_test 4.$tn.3.5 -deferred five t1 {one NEAR/3 five} | 
 |  566  | 
 |  567   do_fts3query_test 4.$tn.4.1 -deferred fi* t1 {on* AND fi*} | 
 |  568   do_fts3query_test 4.$tn.4.2 -deferred fi* t1 {on* NEAR fi*} | 
 |  569   do_fts3query_test 4.$tn.4.3 -deferred fi* t1 {on* NEAR/1 fi*} | 
 |  570   do_fts3query_test 4.$tn.4.4 -deferred fi* t1 {on* NEAR/2 fi*} | 
 |  571   do_fts3query_test 4.$tn.4.5 -deferred fi* t1 {on* NEAR/3 fi*} | 
 |  572 } | 
 |  573  | 
 |  574 #-------------------------------------------------------------------------- | 
 |  575 # The following test cases - fts3auto-5.* - focus on using prefix indexes. | 
 |  576 # | 
 |  577 set chunkconfig [fts3_configure_incr_load 1 1] | 
 |  578 foreach {tn create pending} { | 
 |  579   1    "fts4(a, b)"                                  1 | 
 |  580   2    "fts4(a, b, order=ASC, prefix=1)"             1 | 
 |  581   3    "fts4(a, b, order=ASC,  prefix=\"1,3\")"      0 | 
 |  582   4    "fts4(a, b, order=DESC, prefix=\"2,4\")"      0 | 
 |  583   5    "fts4(a, b, order=DESC, prefix=\"1\")"        0 | 
 |  584   6    "fts4(a, b, order=ASC,  prefix=\"1,3\")"      0 | 
 |  585 } { | 
 |  586  | 
 |  587   execsql [subst { | 
 |  588     DROP TABLE IF EXISTS t1; | 
 |  589     CREATE VIRTUAL TABLE t1 USING $create; | 
 |  590   }] | 
 |  591  | 
 |  592   if {$pending} {execsql BEGIN} | 
 |  593  | 
 |  594   foreach {a b} { | 
 |  595     "the song of songs which is solomons" | 
 |  596     "let him kiss me with the kisses of his mouth for thy love is better than wi
     ne" | 
 |  597     "because of the savour of thy good ointments thy name is as ointment poured 
     forth therefore do the virgins love thee" | 
 |  598     "draw me we will run after thee the king hath brought me into his chambers w
     e will be glad and rejoice in thee we will remember thy love more than wine the 
     upright love thee" | 
 |  599     "i am black but comely o ye daughters of jerusalem as the tents of kedar as 
     the curtains of solomon" | 
 |  600     "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" | 
 |  601     "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 floc
     ks of thy companions?" | 
 |  602     "if thou know not o thou fairest among women go thy way forth by the footste
     ps of the flock and feed thy kids beside the shepherds tents" | 
 |  603     "i have compared thee o my love to a company of horses in pharaohs chariots" | 
 |  604     "thy cheeks are comely with rows of jewels thy neck with chains of gold" | 
 |  605     "we will make thee borders of gold with studs of silver" | 
 |  606     "while the king sitteth at his table my spikenard sendeth forth the smell th
     ereof" | 
 |  607     "a bundle of myrrh is my wellbeloved unto me he shall lie all night betwixt 
     my breasts" | 
 |  608     "my beloved is unto me as a cluster of camphire in the vineyards of en gedi" | 
 |  609     "behold thou art fair my love behold thou art fair thou hast doves eyes" | 
 |  610     "behold thou art fair my beloved yea pleasant also our bed is green" | 
 |  611     "the beams of our house are cedar and our rafters of fir" | 
 |  612   } { | 
 |  613     execsql {INSERT INTO t1(a, b) VALUES($a, $b)} | 
 |  614   } | 
 |  615  | 
 |  616  | 
 |  617   do_fts3query_test 5.$tn.1.1 t1 {s*} | 
 |  618   do_fts3query_test 5.$tn.1.2 t1 {so*} | 
 |  619   do_fts3query_test 5.$tn.1.3 t1 {"s* o*"} | 
 |  620   do_fts3query_test 5.$tn.1.4 t1 {b* NEAR/3 a*} | 
 |  621   do_fts3query_test 5.$tn.1.5 t1 {a*} | 
 |  622   do_fts3query_test 5.$tn.1.6 t1 {th* NEAR/5 a* NEAR/5 w*} | 
 |  623   do_fts3query_test 5.$tn.1.7 t1 {"b* th* art* fair*"} | 
 |  624  | 
 |  625   if {$pending} {execsql COMMIT} | 
 |  626 } | 
 |  627 eval fts3_configure_incr_load $chunkconfig | 
 |  628  | 
 |  629 foreach {tn pending create} { | 
 |  630   1    0 "fts4(a, b, c, d)" | 
 |  631   2    1 "fts4(a, b, c, d)" | 
 |  632   3    0 "fts4(a, b, c, d, order=DESC)" | 
 |  633   4    1 "fts4(a, b, c, d, order=DESC)" | 
 |  634 } { | 
 |  635   execsql [subst { | 
 |  636     DROP TABLE IF EXISTS t1; | 
 |  637     CREATE VIRTUAL TABLE t1 USING $create; | 
 |  638   }] | 
 |  639  | 
 |  640  | 
 |  641   if {$pending} { execsql BEGIN } | 
 |  642  | 
 |  643   foreach {a b c d} { | 
 |  644     "A B C" "D E F" "G H I" "J K L" | 
 |  645     "B C D" "E F G" "H I J" "K L A" | 
 |  646     "C D E" "F G H" "I J K" "L A B" | 
 |  647     "D E F" "G H I" "J K L" "A B C" | 
 |  648     "E F G" "H I J" "K L A" "B C D" | 
 |  649     "F G H" "I J K" "L A B" "C D E" | 
 |  650   } { | 
 |  651     execsql { INSERT INTO t1 VALUES($a, $b, $c, $d) } | 
 |  652   } | 
 |  653  | 
 |  654   do_fts3query_test 6.$tn.1 t1 {b:G} | 
 |  655   do_fts3query_test 6.$tn.2 t1 {b:G AND c:I} | 
 |  656   do_fts3query_test 6.$tn.3 t1 {b:G NEAR c:I} | 
 |  657   do_fts3query_test 6.$tn.4 t1 {a:C OR b:G OR c:K OR d:C} | 
 |  658  | 
 |  659   do_fts3query_test 6.$tn.5 t1 {a:G OR b:G} | 
 |  660  | 
 |  661   catchsql { COMMIT } | 
 |  662 } | 
 |  663  | 
 |  664 foreach {tn create} { | 
 |  665   1    "fts4(x)" | 
 |  666   2    "fts4(x, order=DESC)" | 
 |  667 } { | 
 |  668   execsql [subst { | 
 |  669     DROP TABLE IF EXISTS t1; | 
 |  670     CREATE VIRTUAL TABLE t1 USING $create; | 
 |  671   }] | 
 |  672  | 
 |  673   foreach {x} { | 
 |  674     "F E N O T K X V A X I E X A P G Q V H U" | 
 |  675     "R V A E T C V Q N I E L O N U G J K L U" | 
 |  676     "U Y I G W M V F J L X I D C H F P J Q B" | 
 |  677     "S G D Z X R P G S S Y B K A S G A I L L" | 
 |  678     "L S I C H T Z S R Q P R N K J X L F M J" | 
 |  679     "C C C D P X B Z C M A D A C X S B T X V" | 
 |  680     "W Y J M D R G V R K B X S A W R I T N C" | 
 |  681     "P K L W T M S P O Y Y V V O E H Q A I R" | 
 |  682     "C D Y I C Z F H J C O Y A Q F L S B D K" | 
 |  683     "P G S C Y C Y V I M B D S Z D D Y W I E" | 
 |  684     "Z K Z U E E S F Y X T U A L W O U J C Q" | 
 |  685     "P A T Z S W L P L Q V Y Y I P W U X S S" | 
 |  686     "I U I H U O F Z F R H R F T N D X A G M" | 
 |  687     "N A B M S H K X S O Y D T X S B R Y H Z" | 
 |  688     "L U D A S K I L S V Z J P U B E B Y H M" | 
 |  689   } { | 
 |  690     execsql { INSERT INTO t1 VALUES($x) } | 
 |  691   } | 
 |  692  | 
 |  693   # Add extra documents to the database such that token "B" will be considered | 
 |  694   # deferrable if considering the other tokens means that 2 or fewer documents | 
 |  695   # will be loaded into memory. | 
 |  696   # | 
 |  697   fts3_make_deferrable t1 B 2 | 
 |  698  | 
 |  699   # B is not deferred in either of the first two tests below, since filtering | 
 |  700   # on "M" or "D" returns 10 documents or so. But filtering on "M * D" only | 
 |  701   # returns 2, so B is deferred in this case. | 
 |  702   # | 
 |  703   do_fts3query_test 7.$tn.1             t1 {"M B"} | 
 |  704   do_fts3query_test 7.$tn.2             t1 {"B D"} | 
 |  705   do_fts3query_test 7.$tn.3 -deferred B t1 {"M B D"} | 
 |  706 } | 
 |  707  | 
 |  708 set sqlite_fts3_enable_parentheses $sfep | 
 |  709 finish_test | 
| OLD | NEW |