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.
7 #***********************************************************************
10 set testdir [file dirname $argv0]
11 source $testdir/tester.tcl
13 # If this build does not include FTS3, skip the tests in this file.
15 ifcapable !fts3 { finish_test ; return }
16 source $testdir/fts3_common.tcl
17 source $testdir/malloc_common.tcl
19 set testprefix fts3auto
20 set sfep $sqlite_fts3_enable_parentheses
21 set sqlite_fts3_enable_parentheses 1
23 #--------------------------------------------------------------------------
24 # Start of Tcl infrastructure used by tests. The entry points are:
27 # fts3_make_deferrable
28 # fts3_zero_long_segments
32 # do_fts3query_test TESTNAME ?OPTIONS? TABLE MATCHEXPR
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.
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.
47 # Available OPTIONS are:
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
55 set sqlite_fts3_enable_parentheses 1
56 proc do_fts3query_test {tn args} {
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\""
63 set tbl [lindex $args [expr $nArg-2]]
64 set match [lindex $args [expr $nArg-1]]
67 foreach {k v} [lrange $args 0 [expr $nArg-3]] {
70 ifcapable fts4_deferred { set deferred $v }
73 error "bad option \"$k\": must be -deferred"
78 get_near_results $tbl $match $deferred aHit
79 get_near_results $tbl [string map {AND OR} $match] $deferred aMatchinfo
81 set matchinfo_asc [list]
82 foreach docid [lsort -integer -incr [array names aHit]] {
83 lappend matchinfo_asc $docid $aMatchinfo($docid)
85 set matchinfo_desc [list]
86 foreach docid [lsort -integer -decr [array names aHit]] {
87 lappend matchinfo_desc $docid $aMatchinfo($docid)
90 set title "(\"$match\" -> [llength [array names aHit]] rows)"
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]]
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]]
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
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
111 # fts3_make_deferrable TABLE TOKEN ?NROW?
113 proc fts3_make_deferrable {tbl token {nRow 0}} {
115 set stmt [sqlite3_prepare db "SELECT * FROM $tbl" -1 dummy]
116 set name [sqlite3_column_name $stmt 0]
117 sqlite3_finalize $stmt
120 set nRow [db one "SELECT count(*) FROM $tbl"]
122 set pgsz [db one "PRAGMA page_size"]
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)"
128 execsql "INSERT INTO $tbl ($name) VALUES('aaaaaaa ${token}aaaaa')"
131 return [expr $nRow*$pgsz]
134 # fts3_zero_long_segments TABLE ?LIMIT?
136 proc fts3_zero_long_segments {tbl limit} {
138 UPDATE ${tbl}_segments
139 SET block = zeroblob(length(block))
140 WHERE length(block)>$limit
147 set scan(littleEndian) i*
148 set scan(bigEndian) I*
149 binary scan $blob $scan($::tcl_platform(byteOrder)) r
154 proc fix_phrase_expr {cols expr colfiltervar} {
155 upvar $colfiltervar iColFilter
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} {
166 } elseif {$iColFilter != $iCol} {
167 set iColFilter [llength $cols]
176 proc fix_near_expr {cols expr colfiltervar} {
177 upvar $colfiltervar iColFilter
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] }
187 lappend out [fix_phrase_expr $cols $b iColFilter]
192 proc get_single_near_results {tbl expr deferred arrayvar nullvar} {
193 upvar $arrayvar aMatchinfo
194 upvar $nullvar nullentry
195 catch {array unset aMatchinfo}
199 db eval "PRAGMA table_info($tbl)" A { lappend cols $A(name) ; lappend miss 0 }
200 set expr [fix_near_expr $cols $expr iColFilter]
202 # Calculate the expected results using [fts3_near_match]. The following
203 # loop populates the "hits" and "counts" arrays as follows:
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].
209 # 2. For each column of each document in the table, counts($docid,$iCol)
210 # is set to the -phrasecountvar output.
213 catch { array unset hits }
214 db eval "SELECT docid, * FROM $tbl" d {
216 foreach col [lrange $d(*) 1 end] {
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 }
222 set counts($docid,$iCol) $miss
227 set nPhrase [expr ([llength $expr]+1)/2]
230 # This block populates the nHit and nDoc arrays. For each phrase/column
231 # in the query/table, array elements are set as follows:
233 # nHit($iPhrase,$iCol) - Total number of hits for phrase $iPhrase in
236 # nDoc($iPhrase,$iCol) - Number of documents with at least one hit for
237 # phrase $iPhrase in column $iCol.
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
245 foreach key [array names counts] {
246 set iCol [lindex [split $key ,] 1]
248 foreach c $counts($key) {
249 if {$c>0} { incr nDoc($iPhrase,$iCol) 1 }
250 incr nHit($iPhrase,$iCol) $c
255 if {[llength $deferred] && [llength $expr]==1} {
256 set phrase [lindex $expr 0]
259 foreach tok $phrase {
260 if {[lsearch $deferred $tok]>=0} {
263 lappend rewritten $tok
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
273 } elseif {$rewritten != $phrase} {
274 while {[lindex $rewritten end] == "*"} {
275 set rewritten [lrange $rewritten 0 end-1]
277 while {[lindex $rewritten 0] == "*"} {
278 set rewritten [lrange $rewritten 1 end]
280 get_single_near_results $tbl [list $rewritten] {} aRewrite nullentry
281 foreach docid [array names hits] {
282 set aMatchinfo($docid) $aRewrite($docid)
288 # Set up the aMatchinfo array. For each document, set aMatchinfo($docid) to
289 # contain the output of matchinfo('x') for the document.
291 foreach docid [array names hits] {
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)
300 set aMatchinfo($docid) $mi
303 # Set up the nullentry output.
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)
314 proc matching_brackets {expr} {
315 if {[string range $expr 0 0]!="(" || [string range $expr end end] !=")"} {
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}
327 return [expr ($iBracket==0 && $i==$nExpr)]
330 proc get_near_results {tbl expr deferred arrayvar {nullvar ""}} {
331 upvar $arrayvar aMatchinfo
332 if {$nullvar != ""} { upvar $nullvar nullentry }
334 set expr [string trim $expr]
335 while { [matching_brackets $expr] } {
336 set expr [string trim [string range $expr 1 end-1]]
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 } {
350 set currentprec $prec($op)
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 }
359 if {$iBracket!=0} { error "mismatched brackets in: $expr" }
361 if {[info exists opidx]==0} {
362 get_single_near_results $tbl $expr $deferred aMatchinfo nullentry
364 set eLeft [lrange $expr 0 [expr $opidx-1]]
365 set eRight [lrange $expr [expr $opidx+1] end]
367 get_near_results $tbl $eLeft $deferred aLeft nullleft
368 get_near_results $tbl $eRight $deferred aRight nullright
370 switch -- [lindex $expr $opidx] {
372 foreach hit [array names aLeft] {
373 if {0==[info exists aRight($hit)]} {
374 set aMatchinfo($hit) $aLeft($hit)
377 set nullentry $nullleft
381 foreach hit [array names aLeft] {
382 if {[info exists aRight($hit)]} {
383 set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)]
386 set nullentry [concat $nullleft $nullright]
390 foreach hit [array names aLeft] {
391 if {[info exists aRight($hit)]} {
392 set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)]
395 set aMatchinfo($hit) [concat $aLeft($hit) $nullright]
398 foreach hit [array names aRight] {
399 set aMatchinfo($hit) [concat $nullleft $aRight($hit)]
402 set nullentry [concat $nullleft $nullright]
409 # End of test procs. Actual tests are below this line.
410 #--------------------------------------------------------------------------
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.
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]
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}
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}
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}
438 #--------------------------------------------------------------------------
439 # Test cases fts3auto-2.* run some simple tests using the
440 # [do_fts3query_test] proc.
442 foreach {tn create} {
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)"
451 catchsql { DROP TABLE t1 }
452 execsql "CREATE VIRTUAL TABLE t1 USING $create"
453 for {set i 0} {$i<32} {incr i} {
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) }
470 6 {one NEAR five NEAR two NEAR four NEAR three}
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)}
480 16 {"one two" NOT "three four"}
482 do_fts3query_test 2.$tn.2.$tn2 t1 $expr
486 #--------------------------------------------------------------------------
487 # Some test cases involving deferred tokens.
490 foreach {tn create} {
492 2 "fts4(x, order=DESC)"
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');
508 set limit [fts3_make_deferrable t1 c]
510 do_fts3query_test 3.$tn.2.1 t1 {a OR c}
512 ifcapable fts4_deferred {
513 do_test 3.$tn.3 { fts3_zero_long_segments t1 $limit } {1}
516 foreach {tn2 expr def} {
521 5 {"a c" NEAR/1 g} {}
522 6 {"a c" NEAR/0 g} {}
524 do_fts3query_test 3.$tn.4.$tn2 -deferred $def t1 $expr
528 #--------------------------------------------------------------------------
530 foreach {tn create} {
532 2 "fts4(x, y, order=DESC)"
533 3 "fts4(x, y, order=DESC, prefix=2)"
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');
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}
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}
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}
565 do_fts3query_test 4.$tn.3.5 -deferred five t1 {one NEAR/3 five}
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*}
574 #--------------------------------------------------------------------------
575 # The following test cases - fts3auto-5.* - focus on using prefix indexes.
577 set chunkconfig [fts3_configure_incr_load 1 1]
578 foreach {tn create pending} {
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
588 DROP TABLE IF EXISTS t1;
589 CREATE VIRTUAL TABLE t1 USING $create;
592 if {$pending} {execsql BEGIN}
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 wine"
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 we 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 flocks of thy companions?"
602 "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"
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 thereof"
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"
613 execsql {INSERT INTO t1(a, b) VALUES($a, $b)}
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*"}
625 if {$pending} {execsql COMMIT}
627 eval fts3_configure_incr_load $chunkconfig
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)"
636 DROP TABLE IF EXISTS t1;
637 CREATE VIRTUAL TABLE t1 USING $create;
641 if {$pending} { execsql BEGIN }
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"
651 execsql { INSERT INTO t1 VALUES($a, $b, $c, $d) }
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}
659 do_fts3query_test 6.$tn.5 t1 {a:G OR b:G}
664 foreach {tn create} {
666 2 "fts4(x, order=DESC)"
669 DROP TABLE IF EXISTS t1;
670 CREATE VIRTUAL TABLE t1 USING $create;
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"
690 execsql { INSERT INTO t1 VALUES($x) }
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.
697 fts3_make_deferrable t1 B 2
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.
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"}
708 set sqlite_fts3_enable_parentheses $sfep