]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add coverage tests for fts3_snippet.c. Also fixes related to the same.
authordan <dan@noemail.net>
Fri, 15 Jan 2010 17:25:52 +0000 (17:25 +0000)
committerdan <dan@noemail.net>
Fri, 15 Jan 2010 17:25:52 +0000 (17:25 +0000)
FossilOrigin-Name: 5e9d8ccae9731f380527463ef87ddcd216b4b721

ext/fts3/fts3_snippet.c
manifest
manifest.uuid
test/fts3_common.tcl
test/fts3snippet.test

index 9299a0e71425430e345162665824714eabec531f..f73d4263969158a885aa2ef1e5959912aa924fc6 100644 (file)
@@ -179,7 +179,7 @@ static int fts3ExprNearTrim(Fts3Expr *pExpr){
 
   assert( pExpr->eType==FTSQUERY_PHRASE );
   while( rc==SQLITE_OK
-   && pExpr->aDoclist && pParent 
+   && pParent 
    && pParent->eType==FTSQUERY_NEAR 
    && pParent->pRight==pExpr 
   ){
@@ -768,8 +768,9 @@ static void fts3LoadColumnlistCounts(char **pp, u32 *aOut, int isGlobal){
       pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
     }
     nHit = fts3ColumnlistCount(&pCsr);
+    assert( nHit>0 );
     if( isGlobal ){
-      if( nHit ) aOut[iCol*3+1]++;
+      aOut[iCol*3+1]++;
     }
     aOut[iCol*3] += nHit;
   }
@@ -914,13 +915,17 @@ void sqlite3Fts3Snippet(
   SnippetFragment aSnippet[4];    /* Maximum of 4 fragments per snippet */
   int nFToken = -1;               /* Number of tokens in each fragment */
 
-  do {
+  for(nSnippet=1; 1; nSnippet++){
+
     int iSnip;                    /* Loop counter 0..nSnippet-1 */
     u64 mCovered = 0;             /* Bitmask of phrases covered by snippet */
     u64 mSeen = 0;                /* Bitmask of phrases seen by BestSnippet() */
 
-    nSnippet++;
-    nFToken = (nToken+nSnippet-1) / nSnippet;
+    if( nToken>=0 ){
+      nFToken = (nToken+nSnippet-1) / nSnippet;
+    }else{
+      nFToken = -1 * nToken;
+    }
 
     for(iSnip=0; iSnip<nSnippet; iSnip++){
       int iBestScore = -1;        /* Best score of columns checked so far */
@@ -956,8 +961,8 @@ void sqlite3Fts3Snippet(
     ** one of the nSnippet snippet fragments, break out of the loop.
     */
     assert( (mCovered&mSeen)==mCovered );
-    if( mSeen==mCovered ) break;
-  }while( nSnippet<SizeofArray(aSnippet) );
+    if( mSeen==mCovered || nSnippet==SizeofArray(aSnippet) ) break;
+  }
 
   assert( nFToken>0 );
 
@@ -1063,11 +1068,13 @@ void sqlite3Fts3Offsets(
     const char *zDoc;
     int nDoc;
 
-    /* Initialize the contents of sCtx.aTerm[] for column iCol. */
+    /* Initialize the contents of sCtx.aTerm[] for column iCol. There is 
+    ** no way that this operation can fail, so the return code from
+    ** fts3ExprIterate() can be discarded.
+    */
     sCtx.iCol = iCol;
     sCtx.iTerm = 0;
-    rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void *)&sCtx);
-    if( rc!=SQLITE_OK ) goto offsets_out;
+    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void *)&sCtx);
 
     /* Retreive the text stored in column iCol. If an SQL NULL is stored 
     ** in column iCol, jump immediately to the next iteration of the loop.
@@ -1127,7 +1134,7 @@ void sqlite3Fts3Offsets(
       }
     }
     if( rc==SQLITE_DONE ){
-      rc = SQLITE_ERROR;
+      rc = SQLITE_CORRUPT;
     }
 
     pMod->xClose(pC);
index bc8d87b9a6b55ec6ea2f762b5d54284c31118df0..702bbbe31ee58e0b3c37772b2fe1ce7708435603 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sa\stest\sto\se_fts3.test\sfor\sthe\smatchinfo\sexample\sin\sfts3.html.
-D 2010-01-14T11:45:04
+C Add\scoverage\stests\sfor\sfts3_snippet.c.\sAlso\sfixes\srelated\sto\sthe\ssame.
+D 2010-01-15T17:25:53
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -64,7 +64,7 @@ F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
 F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
 F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
 F ext/fts3/fts3_porter.c a651e287e02b49b565a6ccf9441959d434489156
-F ext/fts3/fts3_snippet.c fdc2c12e9387d140f3b4422caa4adcbc9c8eddc9
+F ext/fts3/fts3_snippet.c e5bce65adf33452f02528bce694487172e8f8d2d
 F ext/fts3/fts3_tokenizer.c 1a49ee3d79cbf0b9386250370d9cbfe4bb89c8ff
 F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
 F ext/fts3/fts3_tokenizer1.c 11a604a53cff5e8c28882727bf794e5252e5227b
@@ -377,7 +377,7 @@ F test/fts2q.test b2fbbe038b7a31a52a6079b215e71226d8c6a682
 F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e
 F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a
 F test/fts3.test ae0433b09b12def08105640e57693726c4949338
-F test/fts3_common.tcl 2a2044688ce3addb1dd58d3d846c574cf4b7bbcd
+F test/fts3_common.tcl 1d887ded06dac9b993cfb175618df7f70c796de2
 F test/fts3aa.test 5327d4c1d9b6c61021696746cc9a6cdc5bf159c0
 F test/fts3ab.test 09aeaa162aee6513d9ff336b6932211008b9d1f9
 F test/fts3ac.test fc1ac42c33f8a66d48ae41e4728f7ca4b6dfc950
@@ -405,7 +405,7 @@ F test/fts3malloc.test d02ee86b21edd2b43044e0d6dfdcd26cb6efddcb
 F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
 F test/fts3query.test 154fe4b015fd61af523ee083570a134f508f5be7
 F test/fts3rnd.test 2f5761db9dd92f6fe09d08976ac658ef521846ed
-F test/fts3snippet.test 16a05b313bf85da4d0b5cb683549fc2279430fbe
+F test/fts3snippet.test 3562e7e765bb3a8efeb425ad4fdcff5793219b7d
 F test/func.test af106ed834001738246d276659406823e35cde7b
 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
 F test/fuzz.test a4174c3009a3e2c2e14b31b364ebf7ddb49de2c9
@@ -785,7 +785,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P da7abe05887d1ad52552d8ce3a153a0a76f96c5a
-R 5042b01c82f71d4627ff255b6d524663
+P e5336edc55313afac11ea085257cb6e75a0287a7
+R 3dd015be1ba4e72ecda3f74bc253611f
 U dan
-Z 872dd4d3d7fbe754f123dcb0fa0c8e61
+Z bf82d4cd440faa8bc0ad658561804fcb
index ef9357e7dedb5f61fcfd837700b64eea1a257d30..b7ff368a58e0454adf1291f871a47262995557ea 100644 (file)
@@ -1 +1 @@
-e5336edc55313afac11ea085257cb6e75a0287a7
\ No newline at end of file
+5e9d8ccae9731f380527463ef87ddcd216b4b721
\ No newline at end of file
index 1914803b3e34539daaad227c126c60150e5fc94e..ce6678d63a59e5bdc68d2a84b4e10c1f3501dc3b 100644 (file)
@@ -326,7 +326,7 @@ proc doPassiveTest {isRestart name sql catchres} {
 
   switch $::DO_MALLOC_TEST {
     0 { # No malloc failures.
-      do_test $name [list catchsql $sql] $catchres
+      do_test $name [list set {} [uplevel [list catchsql $sql]]] $catchres
       return
     }
     1 { # Simulate transient failures.
index 0f848981d2d86d87bfb4a488e6c25b9569dec308..179c16bcacd44d55e88a8d5fcf5acb6653841fcd 100644 (file)
@@ -9,12 +9,21 @@
 #
 #*************************************************************************
 #
+# The tests in this file test the FTS3 auxillary functions offsets(), 
+# snippet() and matchinfo() work. At time of writing, running this file 
+# provides full coverage of fts3_snippet.c.
+#
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
 # If SQLITE_ENABLE_FTS3 is not defined, omit this file.
 ifcapable !fts3 { finish_test ; return }
+source $testdir/fts3_common.tcl
+source $testdir/malloc_common.tcl
+
+set sqlite_fts3_enable_parentheses 1
+set DO_MALLOC_TEST 0
 
 # Transform the list $L to its "normal" form. So that it can be compared to
 # another list with the same set of elements using [string compare].
@@ -25,84 +34,404 @@ proc normalize {L} {
   return $ret
 }
 
-do_test fts3snippet-1.1 {
-  execsql {
-    CREATE VIRTUAL TABLE ft USING fts3;
-    INSERT INTO ft VALUES('xxx xxx xxx xxx');
-  }
-} {}
-
-do_test fts3snippet-1.2 {
-  execsql { SELECT offsets(ft) FROM ft WHERE ft MATCH 'xxx' }
-} {{0 0 0 3 0 0 4 3 0 0 8 3 0 0 12 3}}
-
-do_test fts3snippet-1.3 {
-  execsql { SELECT offsets(ft) FROM ft WHERE ft MATCH '"xxx xxx"' }
-} [list [normalize {
-    0 0  0 3 
-    0 0  4 3 
-    0 1  4 3 
-    0 0  8 3 
-    0 1  8 3 
-    0 1 12 3
-}]]
-
-
-do_test fts3snippet-1.4 {
-  execsql { SELECT offsets(ft) FROM ft WHERE ft MATCH '"xxx xxx" xxx' }
-} [list [normalize {
-    0 0  0 3 
-    0 2  0 3 
-    0 0  4 3 
-    0 1  4 3 
-    0 2  4 3 
-    0 0  8 3 
-    0 1  8 3 
-    0 2  8 3 
-    0 1 12 3
-    0 2 12 3
-}]]
-
-do_test fts3snippet-1.5 {
-  execsql { SELECT offsets(ft) FROM ft WHERE ft MATCH 'xxx "xxx xxx"' }
-} [list [normalize {
-    0 0  0 3 
-    0 1  0 3 
-    0 0  4 3 
-    0 1  4 3 
-    0 2  4 3 
-    0 0  8 3 
-    0 1  8 3 
-    0 2  8 3 
-    0 0 12 3
-    0 2 12 3
-}]]
-
-do_test fts3snippet-2.1 {
-  execsql {
-    DROP TABLE IF EXISTS ft;
-    CREATE VIRTUAL TABLE ft USING fts3;
-    INSERT INTO ft VALUES('one two three four five six seven eight nine ten');
-  }
-} {}
-foreach {tn expr res} {
-   1 one       "[one] two three four five..."
-   2 two       "one [two] three four five..."
-   3 three     "one two [three] four five..."
-   4 four      "...two three [four] five six..."
-   5 five      "...three four [five] six seven..."
-   6 six       "...four five [six] seven eight..."
-   7 seven     "...five six [seven] eight nine..."
-   8 eight     "...six seven [eight] nine ten"
-   9 nine      "...six seven eight [nine] ten"
-  10 ten       "...six seven eight nine [ten]"
+proc do_offsets_test {name expr args} {
+  set result [list]
+  foreach a $args {
+    lappend result [normalize $a]
+  }
+  do_select_test $name {
+    SELECT offsets(ft) FROM ft WHERE ft MATCH $expr
+  } $result
+}
+  
+# Document text used by a few tests. Contains the English names of all
+# integers between 1 and 300.
+#
+set numbers [normalize {
+  one two three four five six seven eight nine ten eleven twelve thirteen
+  fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone
+  twentytwo twentythree twentyfour twentyfive twentysix twentyseven
+  twentyeight twentynine thirty thirtyone thirtytwo thirtythree thirtyfour
+  thirtyfive thirtysix thirtyseven thirtyeight thirtynine forty fortyone
+  fortytwo fortythree fortyfour fortyfive fortysix fortyseven fortyeight
+  fortynine fifty fiftyone fiftytwo fiftythree fiftyfour fiftyfive fiftysix
+  fiftyseven fiftyeight fiftynine sixty sixtyone sixtytwo sixtythree sixtyfour
+  sixtyfive sixtysix sixtyseven sixtyeight sixtynine seventy seventyone
+  seventytwo seventythree seventyfour seventyfive seventysix seventyseven
+  seventyeight seventynine eighty eightyone eightytwo eightythree eightyfour
+  eightyfive eightysix eightyseven eightyeight eightynine ninety ninetyone
+  ninetytwo ninetythree ninetyfour ninetyfive ninetysix ninetyseven
+  ninetyeight ninetynine onehundred onehundredone onehundredtwo
+  onehundredthree onehundredfour onehundredfive onehundredsix onehundredseven
+  onehundredeight onehundrednine onehundredten onehundredeleven
+  onehundredtwelve onehundredthirteen onehundredfourteen onehundredfifteen
+  onehundredsixteen onehundredseventeen onehundredeighteen onehundrednineteen
+  onehundredtwenty onehundredtwentyone onehundredtwentytwo
+  onehundredtwentythree onehundredtwentyfour onehundredtwentyfive
+  onehundredtwentysix onehundredtwentyseven onehundredtwentyeight
+  onehundredtwentynine onehundredthirty onehundredthirtyone
+  onehundredthirtytwo onehundredthirtythree onehundredthirtyfour
+  onehundredthirtyfive onehundredthirtysix onehundredthirtyseven
+  onehundredthirtyeight onehundredthirtynine onehundredforty
+  onehundredfortyone onehundredfortytwo onehundredfortythree
+  onehundredfortyfour onehundredfortyfive onehundredfortysix
+  onehundredfortyseven onehundredfortyeight onehundredfortynine
+  onehundredfifty onehundredfiftyone onehundredfiftytwo onehundredfiftythree
+  onehundredfiftyfour onehundredfiftyfive onehundredfiftysix
+  onehundredfiftyseven onehundredfiftyeight onehundredfiftynine
+  onehundredsixty onehundredsixtyone onehundredsixtytwo onehundredsixtythree
+  onehundredsixtyfour onehundredsixtyfive onehundredsixtysix
+  onehundredsixtyseven onehundredsixtyeight onehundredsixtynine
+  onehundredseventy onehundredseventyone onehundredseventytwo
+  onehundredseventythree onehundredseventyfour onehundredseventyfive
+  onehundredseventysix onehundredseventyseven onehundredseventyeight
+  onehundredseventynine onehundredeighty onehundredeightyone
+  onehundredeightytwo onehundredeightythree onehundredeightyfour
+  onehundredeightyfive onehundredeightysix onehundredeightyseven
+  onehundredeightyeight onehundredeightynine onehundredninety
+  onehundredninetyone onehundredninetytwo onehundredninetythree
+  onehundredninetyfour onehundredninetyfive onehundredninetysix
+  onehundredninetyseven onehundredninetyeight onehundredninetynine twohundred
+  twohundredone twohundredtwo twohundredthree twohundredfour twohundredfive
+  twohundredsix twohundredseven twohundredeight twohundrednine twohundredten
+  twohundredeleven twohundredtwelve twohundredthirteen twohundredfourteen
+  twohundredfifteen twohundredsixteen twohundredseventeen twohundredeighteen
+  twohundrednineteen twohundredtwenty twohundredtwentyone twohundredtwentytwo
+  twohundredtwentythree twohundredtwentyfour twohundredtwentyfive
+  twohundredtwentysix twohundredtwentyseven twohundredtwentyeight
+  twohundredtwentynine twohundredthirty twohundredthirtyone
+  twohundredthirtytwo twohundredthirtythree twohundredthirtyfour
+  twohundredthirtyfive twohundredthirtysix twohundredthirtyseven
+  twohundredthirtyeight twohundredthirtynine twohundredforty
+  twohundredfortyone twohundredfortytwo twohundredfortythree
+  twohundredfortyfour twohundredfortyfive twohundredfortysix
+  twohundredfortyseven twohundredfortyeight twohundredfortynine
+  twohundredfifty twohundredfiftyone twohundredfiftytwo twohundredfiftythree
+  twohundredfiftyfour twohundredfiftyfive twohundredfiftysix
+  twohundredfiftyseven twohundredfiftyeight twohundredfiftynine
+  twohundredsixty twohundredsixtyone twohundredsixtytwo twohundredsixtythree
+  twohundredsixtyfour twohundredsixtyfive twohundredsixtysix
+  twohundredsixtyseven twohundredsixtyeight twohundredsixtynine
+  twohundredseventy twohundredseventyone twohundredseventytwo
+  twohundredseventythree twohundredseventyfour twohundredseventyfive
+  twohundredseventysix twohundredseventyseven twohundredseventyeight
+  twohundredseventynine twohundredeighty twohundredeightyone
+  twohundredeightytwo twohundredeightythree twohundredeightyfour
+  twohundredeightyfive twohundredeightysix twohundredeightyseven
+  twohundredeightyeight twohundredeightynine twohundredninety
+  twohundredninetyone twohundredninetytwo twohundredninetythree
+  twohundredninetyfour twohundredninetyfive twohundredninetysix
+  twohundredninetyseven twohundredninetyeight twohundredninetynine
+  threehundred
+}]
+
+foreach {DO_MALLOC_TEST enc} {
+  0 utf8
+  1 utf8
+  1 utf16
 } {
-  do_test fts3snippet-2.2.$tn {
+
+  db close
+  file delete -force test.db
+  sqlite3 db test.db
+  db eval "PRAGMA encoding = \"$enc\""
+
+  # Set variable $T to the test name prefix for this iteration of the loop.
+  #
+  set T "fts3snippet-$enc"
+
+  ##########################################################################
+  # Test the offset function.
+  #
+  do_test $T.1.1 {
+    execsql {
+      CREATE VIRTUAL TABLE ft USING fts3;
+      INSERT INTO ft VALUES('xxx xxx xxx xxx');
+    }
+  } {}
+  do_offsets_test $T.1.2 {xxx} {0 0 0 3 0 0 4 3 0 0 8 3 0 0 12 3}
+  do_offsets_test $T.1.3 {"xxx xxx"} {
+      0 0  0 3     0 0  4 3     0 1  4 3     0 0  8 3 
+      0 1  8 3     0 1 12 3
+  }
+  do_offsets_test $T.1.4 {"xxx xxx" xxx} {
+      0 0  0 3     0 2  0 3     0 0  4 3     0 1  4 3 
+      0 2  4 3     0 0  8 3     0 1  8 3     0 2  8 3 
+      0 1 12 3     0 2 12 3
+  }
+  do_offsets_test $T.1.5 {xxx "xxx xxx"} {
+      0 0  0 3     0 1  0 3     0 0  4 3     0 1  4 3 
+      0 2  4 3     0 0  8 3     0 1  8 3     0 2  8 3 
+      0 0 12 3     0 2 12 3
+  }
+
+  do_test $T.9.1 {
+    set v1 [lrange $numbers 0 99]
+    execsql {
+      DROP TABLE IF EXISTS ft;
+      CREATE VIRTUAL TABLE ft USING fts3(a, b);
+      INSERT INTO ft VALUES($v1, $numbers);
+      INSERT INTO ft VALUES($v1, NULL);
+    }
+  } {}
+
+  set off [string first "twohundred " $numbers]
+  do_offsets_test $T.9.1 {twohundred} [list 1 0 $off 10]
+
+  set off [string first "onehundred " $numbers]
+  do_offsets_test $T.9.2 {onehundred} \
+    [list 0 0 $off 10 1 0 $off 10] [list 0 0 $off 10]
+
+  # Test a corruption case:
+  execsql { UPDATE ft_content SET c1b = 'hello world' WHERE c1b = $numbers }
+  do_error_test $T.9.3 {
+    SELECT offsets(ft) FROM ft WHERE ft MATCH 'onehundred'
+  } {database disk image is malformed}
+  
+  ##########################################################################
+  # Test the snippet function.
+  #
+  proc do_snippet_test {name expr iCol nTok args} {
+    set res [list]
+    foreach a $args { lappend res [string trim $a] }
+    do_select_test $name {
+      SELECT snippet(ft,'{','}','...',$iCol,$nTok) FROM ft WHERE ft MATCH $expr
+    } $res
+  }
+  do_test $T.2.1 {
+    execsql {
+      DROP TABLE IF EXISTS ft;
+      CREATE VIRTUAL TABLE ft USING fts3;
+      INSERT INTO ft VALUES('one two three four five six seven eight nine ten');
+    }
+  } {}
+  do_snippet_test $T.2.2  one    0 5 "{one} two three four five..."
+  do_snippet_test $T.2.3  two    0 5 "one {two} three four five..."
+  do_snippet_test $T.2.4  three  0 5 "one two {three} four five..."
+  do_snippet_test $T.2.5  four   0 5 "...two three {four} five six..."
+  do_snippet_test $T.2.6  five   0 5 "...three four {five} six seven..."
+  do_snippet_test $T.2.7  six    0 5 "...four five {six} seven eight..."
+  do_snippet_test $T.2.8  seven  0 5 "...five six {seven} eight nine..."
+  do_snippet_test $T.2.9  eight  0 5 "...six seven {eight} nine ten"
+  do_snippet_test $T.2.10 nine   0 5 "...six seven eight {nine} ten"
+  do_snippet_test $T.2.11 ten    0 5 "...six seven eight nine {ten}"
+  
+  do_test $T.3.1 {
+    execsql {
+      INSERT INTO ft VALUES(
+           'one two three four five '
+        || 'six seven eight nine ten '
+        || 'eleven twelve thirteen fourteen fifteen '
+        || 'sixteen seventeen eighteen nineteen twenty '
+        || 'one two three four five '
+        || 'six seven eight nine ten '
+        || 'eleven twelve thirteen fourteen fifteen '
+        || 'sixteen seventeen eighteen nineteen twenty'
+      );
+    }
+  } {}
+  
+  do_snippet_test $T.3.2 {one nine} 0 5 {
+     {one} two three...eight {nine} ten
+  } {
+     {one} two three...eight {nine} ten...
+  }
+  
+  do_snippet_test $T.3.3 {one nine} 0 -5 {
+     {one} two three four five...six seven eight {nine} ten
+  } {
+     {one} two three four five...seven eight {nine} ten eleven...
+  }
+  do_snippet_test $T.3.3 {one nineteen} 0 -5 {
+     ...eighteen {nineteen} twenty {one} two...
+  }
+  do_snippet_test $T.3.4 {two nineteen} 0 -5 {
+     ...eighteen {nineteen} twenty one {two}...
+  }
+  do_snippet_test $T.3.5 {three nineteen} 0 -5 {
+     ...{nineteen} twenty one two {three}...
+  }
+  
+  do_snippet_test $T.3.6 {four nineteen} 0 -5 {
+     ...two three {four} five six...seventeen eighteen {nineteen} twenty one...
+  }
+  do_snippet_test $T.3.7 {four NEAR nineteen} 0 -5 {
+     ...seventeen eighteen {nineteen} twenty one...two three {four} five six...
+  }
+  
+  do_snippet_test $T.3.8 {four nineteen} 0 5 {
+     ...three {four} five...eighteen {nineteen} twenty...
+  }
+  do_snippet_test $T.3.9 {four NEAR nineteen} 0 5 {
+     ...eighteen {nineteen} twenty...three {four} five...
+  }
+  do_snippet_test $T.3.10 {four NEAR nineteen} 0 -5 {
+     ...seventeen eighteen {nineteen} twenty one...two three {four} five six...
+  }
+  do_snippet_test $T.3.11 {four NOT (nineteen twentyone)} 0 5 {
+     ...two three {four} five six...
+  } {
+     ...two three {four} five six...
+  }
+  do_snippet_test $T.3.12 {four OR nineteen NEAR twentyone} 0 5 {
+     ...two three {four} five six...
+  } {
+     ...two three {four} five six...
+  }
+  
+  do_test $T.5.1 {
+    execsql {
+      DROP TABLE IF EXISTS ft;
+      CREATE VIRTUAL TABLE ft USING fts3(a, b, c);
+      INSERT INTO ft VALUES(
+        'one two three four five', 
+        'four five six seven eight', 
+        'seven eight nine ten eleven'
+      );
+    }
+  } {}
+  
+  do_snippet_test $T.5.2 {five} -1 3 {...three four {five}}
+  do_snippet_test $T.5.3 {five}  0 3 {...three four {five}}
+  do_snippet_test $T.5.4 {five}  1 3 {four {five} six...}
+  do_snippet_test $T.5.5 {five}  2 3 {seven eight nine...}
+  
+  do_test $T.5.6 {
+    execsql { UPDATE ft SET b = NULL }
+  } {}
+  
+  do_snippet_test $T.5.7  {five} -1 3 {...three four {five}}
+  do_snippet_test $T.5.8  {five}  0 3 {...three four {five}}
+  do_snippet_test $T.5.9  {five}  1 3 {}
+  do_snippet_test $T.5.10 {five}  2 3 {seven eight nine...}
+  
+  do_snippet_test $T.5.11 {one "seven eight nine"} -1 -3 {
+    {one} two three...{seven} {eight} {nine}...
+  }
+
+  do_test $T.6.1 {
+    execsql {
+      DROP TABLE IF EXISTS ft;
+      CREATE VIRTUAL TABLE ft USING fts3(x);
+      INSERT INTO ft VALUES($numbers);
+    }
+  } {}
+  do_snippet_test $T.6.2 {
+    one fifty onehundred onehundredfifty twohundredfifty threehundred
+  } -1 4 {
+    {one}...{fifty}...{onehundred}...{onehundredfifty}...
+  }
+  do_snippet_test $T.6.3 {
+    one fifty onehundred onehundredfifty twohundredfifty threehundred
+  } -1 -4 {
+    {one} two three four...fortyeight fortynine {fifty} fiftyone...ninetyeight ninetynine {onehundred} onehundredone...onehundredfortyeight onehundredfortynine {onehundredfifty} onehundredfiftyone...
+  }
+
+  do_test $T.7.1 {
     execsql {
-      SELECT snippet(ft, '[', ']', '...', 0, 5) FROM ft WHERE ft MATCH $expr
+      BEGIN;
+        DROP TABLE IF EXISTS ft;
+        CREATE VIRTUAL TABLE ft USING fts3(x);
+    }
+    set testresults [list]
+    for {set i 1} {$i < 150} {incr i} {
+      set commas [string repeat , $i]
+      execsql {INSERT INTO ft VALUES('one' || $commas || 'two')}
+      lappend testresults "{one}$commas{two}"
     }
-  } [list $res]
+    execsql COMMIT
+  } {}
+  do_snippet_test $T.7.2 {one two} -1 3 {*}$testresults
+  
+  ##########################################################################
+  # Test the matchinfo function.
+  #
+  proc mit {blob} {
+    set scan(littleEndian) i*
+    set scan(bigEndian) I*
+    binary scan $blob $scan($::tcl_platform(byteOrder)) r
+    return $r
+  }
+  db func mit mit
+  proc do_matchinfo_test {name expr args} {
+    set res [list]
+    foreach a $args { lappend res [normalize $a] }
+    do_select_test $name {
+      SELECT mit(matchinfo(ft)) FROM ft WHERE ft MATCH $expr
+    } $res
+  }
+  do_test $T.4.1 {
+    set ten {one two three four five six seven eight nine ten}
+    execsql {
+      DROP TABLE IF EXISTS ft;
+      CREATE VIRTUAL TABLE ft USING fts3;
+      INSERT INTO ft VALUES($ten);
+      INSERT INTO ft VALUES($ten || ' ' || $ten);
+    }
+  } {}
+  
+  do_matchinfo_test $T.4.2 "one" {1 1  1 3 2} {1 1  2 3 2}
+  do_matchinfo_test $T.4.3 "one NEAR/3 ten" {2 1  1 1 1 1 1 1}
+  do_matchinfo_test $T.4.4 "five NEAR/4 ten" \
+    {2 1  1 3 2  1 3 2} {2 1  2 3 2  2 3 2}
+  do_matchinfo_test $T.4.5 "six NEAR/3 ten NEAR/3 two" \
+    {3 1  1 1 1  1 1 1  1 1 1}
+  do_matchinfo_test $T.4.6 "five NEAR/4 ten NEAR/3 two" \
+    {3 1  2 2 1  1 1 1  1 1 1}
+
+  do_test $T.8.1 {
+    execsql {
+      DROP TABLE IF EXISTS ft;
+      CREATE VIRTUAL TABLE ft USING fts3(x, y);
+    }
+    foreach n {1 2 3} {
+      set v1 [lrange $numbers 0 [expr $n*100]]
+      set v2 [string trim [string repeat "$numbers " $n]]
+      set docid [expr $n * 1000000]
+      execsql { INSERT INTO ft(docid, x, y) VALUES($docid, $v1, $v2) }
+    }
+  } {}
+  do_matchinfo_test $T.8.2 {two*}     \
+    { 1 2    1   105 3   101 606 3}   \
+    { 1 2    3   105 3   202 606 3}   \
+    { 1 2    101 105 3   303 606 3}
+
+  do_matchinfo_test $T.8.4 {"one* two*"}  \
+    { 1 2    1 5 3   2 12 3}              \
+    { 1 2    2 5 3   4 12 3}              \
+    { 1 2    2 5 3   6 12 3}
+
+  do_matchinfo_test $T.8.5 {twohundredfifty}  \
+    { 1 2    0 1 1   1 6 3}                   \
+    { 1 2    0 1 1   2 6 3}                   \
+    { 1 2    1 1 1   3 6 3}
+
+  do_matchinfo_test $T.8.6 {"threehundred one"} \
+    { 1 2    0 0 0   1 3 2}                     \
+    { 1 2    0 0 0   2 3 2}
+
+  do_matchinfo_test $T.8.7 {one OR fivehundred} \
+    { 2 2    1 3 3   1 6 3   0 0 0   0 0 0 }    \
+    { 2 2    1 3 3   2 6 3   0 0 0   0 0 0 }    \
+    { 2 2    1 3 3   3 6 3   0 0 0   0 0 0 }
+
+  do_matchinfo_test $T.8.8 {two OR "threehundred one"} \
+    { 2 2    1 3 3   1 6 3   0 0 0   0 3 2 }           \
+    { 2 2    1 3 3   2 6 3   0 0 0   1 3 2 }           \
+    { 2 2    1 3 3   3 6 3   0 0 0   2 3 2 }
+
+  do_select_test $T.8.9 {
+    SELECT mit(matchinfo(ft)), mit(matchinfo(ft))
+    FROM ft WHERE ft MATCH 'two OR "threehundred one"' 
+  } [normalize {
+    {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
+    {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
+    {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
+    {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
+    {2 2 1 3 3 3 6 3 0 0 0 2 3 2}          
+    {2 2 1 3 3 3 6 3 0 0 0 2 3 2}
+  }]
 }
 
+set sqlite_fts3_enable_parentheses 0
 finish_test
-