Home | History | Annotate | Download | only in test
      1 # 2010 January 07
      2 #
      3 # The author disclaims copyright to this source code.  In place of
      4 # a legal notice, here is a blessing:
      5 #
      6 #    May you do good and not evil.
      7 #    May you find forgiveness for yourself and forgive others.
      8 #    May you share freely, never taking more than you give.
      9 #
     10 #*************************************************************************
     11 #
     12 # The tests in this file test the FTS3 auxillary functions offsets(), 
     13 # snippet() and matchinfo() work. At time of writing, running this file 
     14 # provides full coverage of fts3_snippet.c.
     15 #
     16 
     17 set testdir [file dirname $argv0]
     18 source $testdir/tester.tcl
     19 
     20 # If SQLITE_ENABLE_FTS3 is not defined, omit this file.
     21 ifcapable !fts3 { finish_test ; return }
     22 source $testdir/fts3_common.tcl
     23 
     24 set sqlite_fts3_enable_parentheses 1
     25 set DO_MALLOC_TEST 0
     26 
     27 # Transform the list $L to its "normal" form. So that it can be compared to
     28 # another list with the same set of elements using [string compare].
     29 #
     30 proc normalize {L} {
     31   set ret [list]
     32   foreach l $L {lappend ret $l}
     33   return $ret
     34 }
     35 
     36 proc do_offsets_test {name expr args} {
     37   set result [list]
     38   foreach a $args {
     39     lappend result [normalize $a]
     40   }
     41   do_select_test $name {
     42     SELECT offsets(ft) FROM ft WHERE ft MATCH $expr
     43   } $result
     44 }
     45   
     46 # Document text used by a few tests. Contains the English names of all
     47 # integers between 1 and 300.
     48 #
     49 set numbers [normalize {
     50   one two three four five six seven eight nine ten eleven twelve thirteen
     51   fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone
     52   twentytwo twentythree twentyfour twentyfive twentysix twentyseven
     53   twentyeight twentynine thirty thirtyone thirtytwo thirtythree thirtyfour
     54   thirtyfive thirtysix thirtyseven thirtyeight thirtynine forty fortyone
     55   fortytwo fortythree fortyfour fortyfive fortysix fortyseven fortyeight
     56   fortynine fifty fiftyone fiftytwo fiftythree fiftyfour fiftyfive fiftysix
     57   fiftyseven fiftyeight fiftynine sixty sixtyone sixtytwo sixtythree sixtyfour
     58   sixtyfive sixtysix sixtyseven sixtyeight sixtynine seventy seventyone
     59   seventytwo seventythree seventyfour seventyfive seventysix seventyseven
     60   seventyeight seventynine eighty eightyone eightytwo eightythree eightyfour
     61   eightyfive eightysix eightyseven eightyeight eightynine ninety ninetyone
     62   ninetytwo ninetythree ninetyfour ninetyfive ninetysix ninetyseven
     63   ninetyeight ninetynine onehundred onehundredone onehundredtwo
     64   onehundredthree onehundredfour onehundredfive onehundredsix onehundredseven
     65   onehundredeight onehundrednine onehundredten onehundredeleven
     66   onehundredtwelve onehundredthirteen onehundredfourteen onehundredfifteen
     67   onehundredsixteen onehundredseventeen onehundredeighteen onehundrednineteen
     68   onehundredtwenty onehundredtwentyone onehundredtwentytwo
     69   onehundredtwentythree onehundredtwentyfour onehundredtwentyfive
     70   onehundredtwentysix onehundredtwentyseven onehundredtwentyeight
     71   onehundredtwentynine onehundredthirty onehundredthirtyone
     72   onehundredthirtytwo onehundredthirtythree onehundredthirtyfour
     73   onehundredthirtyfive onehundredthirtysix onehundredthirtyseven
     74   onehundredthirtyeight onehundredthirtynine onehundredforty
     75   onehundredfortyone onehundredfortytwo onehundredfortythree
     76   onehundredfortyfour onehundredfortyfive onehundredfortysix
     77   onehundredfortyseven onehundredfortyeight onehundredfortynine
     78   onehundredfifty onehundredfiftyone onehundredfiftytwo onehundredfiftythree
     79   onehundredfiftyfour onehundredfiftyfive onehundredfiftysix
     80   onehundredfiftyseven onehundredfiftyeight onehundredfiftynine
     81   onehundredsixty onehundredsixtyone onehundredsixtytwo onehundredsixtythree
     82   onehundredsixtyfour onehundredsixtyfive onehundredsixtysix
     83   onehundredsixtyseven onehundredsixtyeight onehundredsixtynine
     84   onehundredseventy onehundredseventyone onehundredseventytwo
     85   onehundredseventythree onehundredseventyfour onehundredseventyfive
     86   onehundredseventysix onehundredseventyseven onehundredseventyeight
     87   onehundredseventynine onehundredeighty onehundredeightyone
     88   onehundredeightytwo onehundredeightythree onehundredeightyfour
     89   onehundredeightyfive onehundredeightysix onehundredeightyseven
     90   onehundredeightyeight onehundredeightynine onehundredninety
     91   onehundredninetyone onehundredninetytwo onehundredninetythree
     92   onehundredninetyfour onehundredninetyfive onehundredninetysix
     93   onehundredninetyseven onehundredninetyeight onehundredninetynine twohundred
     94   twohundredone twohundredtwo twohundredthree twohundredfour twohundredfive
     95   twohundredsix twohundredseven twohundredeight twohundrednine twohundredten
     96   twohundredeleven twohundredtwelve twohundredthirteen twohundredfourteen
     97   twohundredfifteen twohundredsixteen twohundredseventeen twohundredeighteen
     98   twohundrednineteen twohundredtwenty twohundredtwentyone twohundredtwentytwo
     99   twohundredtwentythree twohundredtwentyfour twohundredtwentyfive
    100   twohundredtwentysix twohundredtwentyseven twohundredtwentyeight
    101   twohundredtwentynine twohundredthirty twohundredthirtyone
    102   twohundredthirtytwo twohundredthirtythree twohundredthirtyfour
    103   twohundredthirtyfive twohundredthirtysix twohundredthirtyseven
    104   twohundredthirtyeight twohundredthirtynine twohundredforty
    105   twohundredfortyone twohundredfortytwo twohundredfortythree
    106   twohundredfortyfour twohundredfortyfive twohundredfortysix
    107   twohundredfortyseven twohundredfortyeight twohundredfortynine
    108   twohundredfifty twohundredfiftyone twohundredfiftytwo twohundredfiftythree
    109   twohundredfiftyfour twohundredfiftyfive twohundredfiftysix
    110   twohundredfiftyseven twohundredfiftyeight twohundredfiftynine
    111   twohundredsixty twohundredsixtyone twohundredsixtytwo twohundredsixtythree
    112   twohundredsixtyfour twohundredsixtyfive twohundredsixtysix
    113   twohundredsixtyseven twohundredsixtyeight twohundredsixtynine
    114   twohundredseventy twohundredseventyone twohundredseventytwo
    115   twohundredseventythree twohundredseventyfour twohundredseventyfive
    116   twohundredseventysix twohundredseventyseven twohundredseventyeight
    117   twohundredseventynine twohundredeighty twohundredeightyone
    118   twohundredeightytwo twohundredeightythree twohundredeightyfour
    119   twohundredeightyfive twohundredeightysix twohundredeightyseven
    120   twohundredeightyeight twohundredeightynine twohundredninety
    121   twohundredninetyone twohundredninetytwo twohundredninetythree
    122   twohundredninetyfour twohundredninetyfive twohundredninetysix
    123   twohundredninetyseven twohundredninetyeight twohundredninetynine
    124   threehundred
    125 }]
    126 
    127 foreach {DO_MALLOC_TEST enc} {
    128   0 utf8
    129   1 utf8
    130   1 utf16
    131 } {
    132 
    133   db close
    134   file delete -force test.db
    135   sqlite3 db test.db
    136   sqlite3_db_config_lookaside db 0 0 0
    137   db eval "PRAGMA encoding = \"$enc\""
    138 
    139   # Set variable $T to the test name prefix for this iteration of the loop.
    140   #
    141   set T "fts3snippet-$enc"
    142 
    143   ##########################################################################
    144   # Test the offset function.
    145   #
    146   do_test $T.1.1 {
    147     execsql {
    148       CREATE VIRTUAL TABLE ft USING fts3;
    149       INSERT INTO ft VALUES('xxx xxx xxx xxx');
    150     }
    151   } {}
    152   do_offsets_test $T.1.2 {xxx} {0 0 0 3 0 0 4 3 0 0 8 3 0 0 12 3}
    153   do_offsets_test $T.1.3 {"xxx xxx"} {
    154       0 0  0 3     0 0  4 3     0 1  4 3     0 0  8 3 
    155       0 1  8 3     0 1 12 3
    156   }
    157   do_offsets_test $T.1.4 {"xxx xxx" xxx} {
    158       0 0  0 3     0 2  0 3     0 0  4 3     0 1  4 3 
    159       0 2  4 3     0 0  8 3     0 1  8 3     0 2  8 3 
    160       0 1 12 3     0 2 12 3
    161   }
    162   do_offsets_test $T.1.5 {xxx "xxx xxx"} {
    163       0 0  0 3     0 1  0 3     0 0  4 3     0 1  4 3 
    164       0 2  4 3     0 0  8 3     0 1  8 3     0 2  8 3 
    165       0 0 12 3     0 2 12 3
    166   }
    167 
    168   do_test $T.2.1 {
    169     set v1 [lrange $numbers 0 99]
    170     execsql {
    171       DROP TABLE IF EXISTS ft;
    172       CREATE VIRTUAL TABLE ft USING fts3(a, b);
    173       INSERT INTO ft VALUES($v1, $numbers);
    174       INSERT INTO ft VALUES($v1, NULL);
    175     }
    176   } {}
    177 
    178   set off [string first "twohundred " $numbers]
    179   do_offsets_test $T.2.1 {twohundred} [list 1 0 $off 10]
    180 
    181   set off [string first "onehundred " $numbers]
    182   do_offsets_test $T.2.2 {onehundred} \
    183     [list 0 0 $off 10 1 0 $off 10] [list 0 0 $off 10]
    184 
    185   # Test a corruption case:
    186   execsql { UPDATE ft_content SET c1b = 'hello world' WHERE c1b = $numbers }
    187   do_error_test $T.2.3 {
    188     SELECT offsets(ft) FROM ft WHERE ft MATCH 'onehundred'
    189   } {database disk image is malformed}
    190   
    191   ##########################################################################
    192   # Test the snippet function.
    193   #
    194   proc do_snippet_test {name expr iCol nTok args} {
    195     set res [list]
    196     foreach a $args { lappend res [string trim $a] }
    197     do_select_test $name {
    198       SELECT snippet(ft,'{','}','...',$iCol,$nTok) FROM ft WHERE ft MATCH $expr
    199     } $res
    200   }
    201   do_test $T.3.1 {
    202     execsql {
    203       DROP TABLE IF EXISTS ft;
    204       CREATE VIRTUAL TABLE ft USING fts3;
    205       INSERT INTO ft VALUES('one two three four five six seven eight nine ten');
    206     }
    207   } {}
    208   do_snippet_test $T.3.2  one    0 5 "{one} two three four five..."
    209   do_snippet_test $T.3.3  two    0 5 "one {two} three four five..."
    210   do_snippet_test $T.3.4  three  0 5 "one two {three} four five..."
    211   do_snippet_test $T.3.5  four   0 5 "...two three {four} five six..."
    212   do_snippet_test $T.3.6  five   0 5 "...three four {five} six seven..."
    213   do_snippet_test $T.3.7  six    0 5 "...four five {six} seven eight..."
    214   do_snippet_test $T.3.8  seven  0 5 "...five six {seven} eight nine..."
    215   do_snippet_test $T.3.9  eight  0 5 "...six seven {eight} nine ten"
    216   do_snippet_test $T.3.10 nine   0 5 "...six seven eight {nine} ten"
    217   do_snippet_test $T.3.11 ten    0 5 "...six seven eight nine {ten}"
    218   
    219   do_test $T.4.1 {
    220     execsql {
    221       INSERT INTO ft VALUES(
    222            'one two three four five '
    223         || 'six seven eight nine ten '
    224         || 'eleven twelve thirteen fourteen fifteen '
    225         || 'sixteen seventeen eighteen nineteen twenty '
    226         || 'one two three four five '
    227         || 'six seven eight nine ten '
    228         || 'eleven twelve thirteen fourteen fifteen '
    229         || 'sixteen seventeen eighteen nineteen twenty'
    230       );
    231     }
    232   } {}
    233   
    234   do_snippet_test $T.4.2 {one nine} 0 5 {
    235      {one} two three...eight {nine} ten
    236   } {
    237      {one} two three...eight {nine} ten...
    238   }
    239   
    240   do_snippet_test $T.4.3 {one nine} 0 -5 {
    241      {one} two three four five...six seven eight {nine} ten
    242   } {
    243      {one} two three four five...seven eight {nine} ten eleven...
    244   }
    245   do_snippet_test $T.4.3 {one nineteen} 0 -5 {
    246      ...eighteen {nineteen} twenty {one} two...
    247   }
    248   do_snippet_test $T.4.4 {two nineteen} 0 -5 {
    249      ...eighteen {nineteen} twenty one {two}...
    250   }
    251   do_snippet_test $T.4.5 {three nineteen} 0 -5 {
    252      ...{nineteen} twenty one two {three}...
    253   }
    254   
    255   do_snippet_test $T.4.6 {four nineteen} 0 -5 {
    256      ...two three {four} five six...seventeen eighteen {nineteen} twenty one...
    257   }
    258   do_snippet_test $T.4.7 {four NEAR nineteen} 0 -5 {
    259      ...seventeen eighteen {nineteen} twenty one...two three {four} five six...
    260   }
    261   
    262   do_snippet_test $T.4.8 {four nineteen} 0 5 {
    263      ...three {four} five...eighteen {nineteen} twenty...
    264   }
    265   do_snippet_test $T.4.9 {four NEAR nineteen} 0 5 {
    266      ...eighteen {nineteen} twenty...three {four} five...
    267   }
    268   do_snippet_test $T.4.10 {four NEAR nineteen} 0 -5 {
    269      ...seventeen eighteen {nineteen} twenty one...two three {four} five six...
    270   }
    271   do_snippet_test $T.4.11 {four NOT (nineteen twentyone)} 0 5 {
    272      ...two three {four} five six...
    273   } {
    274      ...two three {four} five six...
    275   }
    276   do_snippet_test $T.4.12 {four OR nineteen NEAR twentyone} 0 5 {
    277      ...two three {four} five six...
    278   } {
    279      ...two three {four} five six...
    280   }
    281   
    282   do_test $T.5.1 {
    283     execsql {
    284       DROP TABLE IF EXISTS ft;
    285       CREATE VIRTUAL TABLE ft USING fts3(a, b, c);
    286       INSERT INTO ft VALUES(
    287         'one two three four five', 
    288         'four five six seven eight', 
    289         'seven eight nine ten eleven'
    290       );
    291     }
    292   } {}
    293   
    294   do_snippet_test $T.5.2 {five} -1 3 {...three four {five}}
    295   do_snippet_test $T.5.3 {five}  0 3 {...three four {five}}
    296   do_snippet_test $T.5.4 {five}  1 3 {four {five} six...}
    297   do_snippet_test $T.5.5 {five}  2 3 {seven eight nine...}
    298   
    299   do_test $T.5.6 {
    300     execsql { UPDATE ft SET b = NULL }
    301   } {}
    302   
    303   do_snippet_test $T.5.7  {five} -1 3 {...three four {five}}
    304   do_snippet_test $T.5.8  {five}  0 3 {...three four {five}}
    305   do_snippet_test $T.5.9  {five}  1 3 {}
    306   do_snippet_test $T.5.10 {five}  2 3 {seven eight nine...}
    307   
    308   do_snippet_test $T.5.11 {one "seven eight nine"} -1 -3 {
    309     {one} two three...{seven} {eight} {nine}...
    310   }
    311 
    312   do_test $T.6.1 {
    313     execsql {
    314       DROP TABLE IF EXISTS ft;
    315       CREATE VIRTUAL TABLE ft USING fts3(x);
    316       INSERT INTO ft VALUES($numbers);
    317     }
    318   } {}
    319   do_snippet_test $T.6.2 {
    320     one fifty onehundred onehundredfifty twohundredfifty threehundred
    321   } -1 4 {
    322     {one}...{fifty}...{onehundred}...{onehundredfifty}...
    323   }
    324   do_snippet_test $T.6.3 {
    325     one fifty onehundred onehundredfifty twohundredfifty threehundred
    326   } -1 -4 {
    327     {one} two three four...fortyeight fortynine {fifty} fiftyone...ninetyeight ninetynine {onehundred} onehundredone...onehundredfortyeight onehundredfortynine {onehundredfifty} onehundredfiftyone...
    328   }
    329 
    330   do_test $T.7.1 {
    331     execsql {
    332       BEGIN;
    333         DROP TABLE IF EXISTS ft;
    334         CREATE VIRTUAL TABLE ft USING fts3(x);
    335     }
    336     set testresults [list]
    337     for {set i 1} {$i < 150} {incr i} {
    338       set commas [string repeat , $i]
    339       execsql {INSERT INTO ft VALUES('one' || $commas || 'two')}
    340       lappend testresults "{one}$commas{two}"
    341     }
    342     execsql COMMIT
    343   } {}
    344   eval [list do_snippet_test $T.7.2 {one two} -1 3] $testresults
    345   
    346   ##########################################################################
    347   # Test the matchinfo function.
    348   #
    349   proc mit {blob} {
    350     set scan(littleEndian) i*
    351     set scan(bigEndian) I*
    352     binary scan $blob $scan($::tcl_platform(byteOrder)) r
    353     return $r
    354   }
    355   db func mit mit
    356   proc do_matchinfo_test {name expr args} {
    357     set res [list]
    358     foreach a $args { lappend res [normalize $a] }
    359     do_select_test $name {
    360       SELECT mit(matchinfo(ft)) FROM ft WHERE ft MATCH $expr
    361     } $res
    362   }
    363   do_test $T.8.1 {
    364     set ten {one two three four five six seven eight nine ten}
    365     execsql {
    366       DROP TABLE IF EXISTS ft;
    367       CREATE VIRTUAL TABLE ft USING fts3;
    368       INSERT INTO ft VALUES($ten);
    369       INSERT INTO ft VALUES($ten || ' ' || $ten);
    370     }
    371   } {}
    372   
    373   do_matchinfo_test $T.8.2 "one" {1 1  1 3 2} {1 1  2 3 2}
    374   do_matchinfo_test $T.8.3 "one NEAR/3 ten" {2 1  1 1 1 1 1 1}
    375   do_matchinfo_test $T.8.4 "five NEAR/4 ten" \
    376     {2 1  1 3 2  1 3 2} {2 1  2 3 2  2 3 2}
    377   do_matchinfo_test $T.8.5 "six NEAR/3 ten NEAR/3 two" \
    378     {3 1  1 1 1  1 1 1  1 1 1}
    379   do_matchinfo_test $T.8.6 "five NEAR/4 ten NEAR/3 two" \
    380     {3 1  2 2 1  1 1 1  1 1 1}
    381 
    382   do_test $T.9.1 {
    383     execsql {
    384       DROP TABLE IF EXISTS ft;
    385       CREATE VIRTUAL TABLE ft USING fts3(x, y);
    386     }
    387     foreach n {1 2 3} {
    388       set v1 [lrange $numbers 0 [expr $n*100]]
    389       set v2 [string trim [string repeat "$numbers " $n]]
    390       set docid [expr $n * 1000000]
    391       execsql { INSERT INTO ft(docid, x, y) VALUES($docid, $v1, $v2) }
    392     }
    393   } {}
    394   do_matchinfo_test $T.9.2 {two*}     \
    395     { 1 2    1   105 3   101 606 3}   \
    396     { 1 2    3   105 3   202 606 3}   \
    397     { 1 2    101 105 3   303 606 3}
    398 
    399   do_matchinfo_test $T.9.4 {"one* two*"}  \
    400     { 1 2    1 5 3   2 12 3}              \
    401     { 1 2    2 5 3   4 12 3}              \
    402     { 1 2    2 5 3   6 12 3}
    403 
    404   do_matchinfo_test $T.9.5 {twohundredfifty}  \
    405     { 1 2    0 1 1   1 6 3}                   \
    406     { 1 2    0 1 1   2 6 3}                   \
    407     { 1 2    1 1 1   3 6 3}
    408 
    409   do_matchinfo_test $T.9.6 {"threehundred one"} \
    410     { 1 2    0 0 0   1 3 2}                     \
    411     { 1 2    0 0 0   2 3 2}
    412 
    413   do_matchinfo_test $T.9.7 {one OR fivehundred} \
    414     { 2 2    1 3 3   1 6 3   0 0 0   0 0 0 }    \
    415     { 2 2    1 3 3   2 6 3   0 0 0   0 0 0 }    \
    416     { 2 2    1 3 3   3 6 3   0 0 0   0 0 0 }
    417 
    418   do_matchinfo_test $T.9.8 {two OR "threehundred one"} \
    419     { 2 2    1 3 3   1 6 3   0 0 0   0 3 2 }           \
    420     { 2 2    1 3 3   2 6 3   0 0 0   1 3 2 }           \
    421     { 2 2    1 3 3   3 6 3   0 0 0   2 3 2 }
    422 
    423   do_select_test $T.9.9 {
    424     SELECT mit(matchinfo(ft)), mit(matchinfo(ft))
    425     FROM ft WHERE ft MATCH 'two OR "threehundred one"' 
    426   } [normalize {
    427     {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
    428     {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
    429     {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
    430     {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
    431     {2 2 1 3 3 3 6 3 0 0 0 2 3 2}          
    432     {2 2 1 3 3 3 6 3 0 0 0 2 3 2}
    433   }]
    434 
    435   # EVIDENCE-OF: R-40630-02268 If used within a SELECT that uses the
    436   # "query by rowid" or "linear scan" strategies, then the snippet and
    437   # offsets both return an empty string, and the matchinfo function
    438   # returns a blob value zero bytes in size.
    439   #
    440   set r 1000000                   ;# A rowid that exists in table ft
    441   do_select_test $T.10.0 { SELECT rowid FROM ft WHERE rowid = $r } $r
    442   do_select_test $T.10.1 {
    443     SELECT length(offsets(ft)), typeof(offsets(ft)) FROM ft;
    444   } {0 text 0 text 0 text}
    445   do_select_test $T.10.2 {
    446     SELECT length(offsets(ft)), typeof(offsets(ft)) FROM ft WHERE rowid = $r
    447   } {0 text}
    448   do_select_test $T.10.3 {
    449     SELECT length(snippet(ft)), typeof(snippet(ft)) FROM ft;
    450   } {0 text 0 text 0 text}
    451   do_select_test $T.10.4 {
    452     SELECT length(snippet(ft)), typeof(snippet(ft)) FROM ft WHERE rowid = $r;
    453   } {0 text}
    454   do_select_test $T.10.5 {
    455     SELECT length(matchinfo(ft)), typeof(matchinfo(ft)) FROM ft;
    456   } {0 blob 0 blob 0 blob}
    457   do_select_test $T.10.6 {
    458     SELECT length(matchinfo(ft)), typeof(matchinfo(ft)) FROM ft WHERE rowid = $r
    459   } {0 blob}
    460 }
    461 
    462 set sqlite_fts3_enable_parentheses 0
    463 finish_test
    464