]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix an incorrect assert() in fts3.c. Add further fts3 tests.
authordan <dan@noemail.net>
Thu, 3 Dec 2009 17:36:22 +0000 (17:36 +0000)
committerdan <dan@noemail.net>
Thu, 3 Dec 2009 17:36:22 +0000 (17:36 +0000)
FossilOrigin-Name: 75863c2d55e0801add5b8dcf88d575c5c870af04

ext/fts3/fts3.c
ext/fts3/fts3Int.h
ext/fts3/fts3_write.c
manifest
manifest.uuid
test/fts3malloc.test
test/fts3rnd.test [new file with mode: 0644]
test/quick.test

index ad3cf6f77321c2d74d9e4735679ac56ee226773f..cca04a573b00d4d7f32fe5e1e403a2e4641ea4e5 100644 (file)
@@ -473,11 +473,6 @@ static void fts3GetDeltaVarint2(char **pp, char *pEnd, sqlite3_int64 *pVal){
   }
 }
 
-
-static Fts3Table *cursor_vtab(Fts3Cursor *c){
-  return (Fts3Table *) c->base.pVtab;
-}
-
 /*
 ** The xDisconnect() virtual table method.
 */
@@ -650,6 +645,14 @@ int fts3InitVtab(
   int nDb;
   int nName;
 
+#ifdef SQLITE_TEST
+  char *zTestParam = 0;
+  if( strncmp(argv[argc-1], "test:", 5)==0 ){
+    zTestParam = argv[argc-1];
+    argc--;
+  }
+#endif
+
   const char *zTokenizer = 0;               /* Name of tokenizer to use */
   sqlite3_tokenizer *pTokenizer = 0;        /* Tokenizer for this table */
 
@@ -696,6 +699,7 @@ int fts3InitVtab(
   p->nPendingData = 0;
   p->azColumn = (char **)&p[1];
   p->pTokenizer = pTokenizer;
+  p->nNodeSize = 1000;
   zCsr = (char *)&p->azColumn[nCol];
 
   fts3HashInit(&p->pendingTerms, FTS3_HASH_STRING, 1);
@@ -739,6 +743,11 @@ int fts3InitVtab(
   rc = fts3DeclareVtab(p);
   if( rc!=SQLITE_OK ) goto fts3_init_out;
 
+#ifdef SQLITE_TEST
+  if( zTestParam ){
+    p->nNodeSize = atoi(&zTestParam[5]);
+  }
+#endif
   *ppVTab = &p->base;
 
 fts3_init_out:
@@ -1010,12 +1019,16 @@ static int fts3SelectLeaf(
   return rc;
 }
 
+/*
+** This function is used to create delta-encoded serialized lists of FTS3 
+** varints. Each call to this function appends a single varint to a list.
+*/
 static void fts3PutDeltaVarint(
-  char **pp, 
-  sqlite3_int64 *piPrev, 
-  sqlite3_int64 iVal
+  char **pp,                      /* IN/OUT: Output pointer */
+  sqlite3_int64 *piPrev,          /* IN/OUT: Previous value written to list */
+  sqlite3_int64 iVal              /* Write this value to the list */
 ){
-  assert( iVal-*piPrev > 0 );
+  assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
   *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
   *piPrev = iVal;
 }
@@ -1550,6 +1563,7 @@ static int fts3TermSelect(
         sqlite3_int64 i2 = sqlite3_column_int64(pStmt, 2);
         rc = sqlite3Fts3SegReaderNew(p, iAge, i1, i2, 0, 0, 0, &pNew);
       }
+      sqlite3Fts3ReadBlock(p, 0, 0, 0);
     }
     iAge++;
 
@@ -1699,6 +1713,9 @@ static int evalFts3Expr(
       if( SQLITE_OK==(rc = evalFts3Expr(p, pExpr->pRight, &aRight, &nRight))
        && SQLITE_OK==(rc = evalFts3Expr(p, pExpr->pLeft, &aLeft, &nLeft))
       ){
+        assert( pExpr->eType==FTSQUERY_NEAR || pExpr->eType==FTSQUERY_OR     
+            || pExpr->eType==FTSQUERY_AND  || pExpr->eType==FTSQUERY_NOT
+        );
         switch( pExpr->eType ){
           case FTSQUERY_NEAR: {
             Fts3Expr *pLeft;
@@ -1749,8 +1766,7 @@ static int evalFts3Expr(
             break;
           }
 
-          case FTSQUERY_AND:
-          case FTSQUERY_NOT: {
+          default: {
             assert( FTSQUERY_NOT==MERGE_NOT && FTSQUERY_AND==MERGE_AND );
             fts3DoclistMerge(pExpr->eType, 0, 0, aLeft, pnOut,
                 aLeft, nLeft, aRight, nRight
@@ -1865,38 +1881,6 @@ static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
   return ((Fts3Cursor *)pCursor)->isEof;
 }
 
-/* 
-** This is the xColumn method of the virtual table.  The SQLite
-** core calls this method during a query when it needs the value
-** of a column from the virtual table.  This method needs to use
-** one of the sqlite3_result_*() routines to store the requested
-** value back in the pContext.
-*/
-static int fts3ColumnMethod(sqlite3_vtab_cursor *pCursor,
-                          sqlite3_context *pContext, int idxCol){
-  Fts3Cursor *c = (Fts3Cursor *) pCursor;
-  Fts3Table *v = cursor_vtab(c);
-  int rc = fts3CursorSeek(c);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  }
-
-  if( idxCol<v->nColumn ){
-    sqlite3_value *pVal = sqlite3_column_value(c->pStmt, idxCol+1);
-    sqlite3_result_value(pContext, pVal);
-  }else if( idxCol==v->nColumn ){
-    /* The extra column whose name is the same as the table.
-    ** Return a blob which is a pointer to the cursor
-    */
-    sqlite3_result_blob(pContext, &c, sizeof(c), SQLITE_TRANSIENT);
-  }else if( idxCol==v->nColumn+1 ){
-    /* The docid column, which is an alias for rowid. */
-    sqlite3_value *pVal = sqlite3_column_value(c->pStmt, 0);
-    sqlite3_result_value(pContext, pVal);
-  }
-  return SQLITE_OK;
-}
-
 /* 
 ** This is the xRowid method. The SQLite core calls this routine to
 ** retrieve the rowid for the current row of the result set. fts3
@@ -1913,6 +1897,43 @@ static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
   return SQLITE_OK;
 }
 
+/* 
+** This is the xColumn method, called by SQLite to request a value from
+** the row that the supplied cursor currently points to.
+*/
+static int fts3ColumnMethod(
+  sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
+  sqlite3_context *pContext,      /* Context for sqlite3_result_xxx() calls */
+  int iCol                        /* Index of column to read value from */
+){
+  int rc;                         /* Return Code */
+  Fts3Cursor *pCsr = (Fts3Cursor *) pCursor;
+  Fts3Table *p = (Fts3Table *)pCursor->pVtab;
+
+  /* The column value supplied by SQLite must be in range. */
+  assert( iCol>=0 && iCol<=p->nColumn+1 );
+
+  rc = fts3CursorSeek(pCsr);
+  if( rc==SQLITE_OK ){
+    if( iCol==p->nColumn+1 ){
+      /* This call is a request for the "docid" column. Since "docid" is an 
+      ** alias for "rowid", use the xRowid() method to obtain the value.
+      */
+      sqlite3_int64 iRowid;
+      rc = fts3RowidMethod(pCursor, &iRowid);
+      sqlite3_result_int64(pContext, iRowid);
+    }else if( iCol==p->nColumn ){
+      /* The extra column whose name is the same as the table.
+      ** Return a blob which is a pointer to the cursor.
+      */
+      sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
+    }else{
+      sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1));
+    }
+  }
+  return rc;
+}
+
 /* 
 ** This function is the implementation of the xUpdate callback used by 
 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
index a4aeb4374a7a65eb12b54048e15f907a71357a82..d59478646baeefe2156606684644d3ee9cbe6e57 100644 (file)
@@ -115,6 +115,8 @@ struct Fts3Table {
   int nLeavesAlloc;               /* Allocated size of aLeavesStmt */
   sqlite3_stmt **aLeavesStmt;     /* Array of prepared zSelectLeaves stmts */
 
+  int nNodeSize;                  /* Soft limit for node size */
+
   /* The following hash table is used to buffer pending index updates during
   ** transactions. Variable nPendingData estimates the memory size of the 
   ** pending data, including hash table overhead, but not malloc overhead. 
index 3a2ed6e1667026f191dc1be5966e09143b64940c..d2401493183901b9771c15b3ef47ae6713b5282d 100644 (file)
@@ -24,9 +24,6 @@
 #include <assert.h>
 #include <stdlib.h>
 
-#define INTERIOR_MAX 2048         /* Soft limit for segment node size */
-#define LEAF_MAX 2048             /* Soft limit for segment leaf size */
-
 typedef struct PendingList PendingList;
 typedef struct SegmentNode SegmentNode;
 typedef struct SegmentWriter SegmentWriter;
@@ -279,16 +276,18 @@ int sqlite3Fts3ReadBlock(
   if( rc!=SQLITE_OK ) return rc;
   sqlite3_reset(pStmt);
 
-  sqlite3_bind_int64(pStmt, 1, iBlock);
-  rc = sqlite3_step(pStmt); 
-  if( rc!=SQLITE_ROW ){
-    return SQLITE_CORRUPT;
-  }
-
-  *pnBlock = sqlite3_column_bytes(pStmt, 0);
-  *pzBlock = (char *)sqlite3_column_blob(pStmt, 0);
-  if( !*pzBlock ){
-    return SQLITE_NOMEM;
+  if( pzBlock ){
+    sqlite3_bind_int64(pStmt, 1, iBlock);
+    rc = sqlite3_step(pStmt); 
+    if( rc!=SQLITE_ROW ){
+      return SQLITE_CORRUPT;
+    }
+  
+    *pnBlock = sqlite3_column_bytes(pStmt, 0);
+    *pzBlock = (char *)sqlite3_column_blob(pStmt, 0);
+    if( !*pzBlock ){
+      return SQLITE_NOMEM;
+    }
   }
   return SQLITE_OK;
 }
@@ -1193,13 +1192,13 @@ static int fts3NodeAddTerm(
     nSuffix = nTerm-nPrefix;
 
     nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix;
-    if( nReq<=INTERIOR_MAX || !pTree->zTerm ){
+    if( nReq<=p->nNodeSize || !pTree->zTerm ){
 
-      if( nReq>INTERIOR_MAX ){
+      if( nReq>p->nNodeSize ){
         /* An unusual case: this is the first term to be added to the node
-        ** and the static node buffer (INTERIOR_MAX bytes) is not large
+        ** and the static node buffer (p->nNodeSize bytes) is not large
         ** enough. Use a separately malloced buffer instead This wastes
-        ** INTERIOR_MAX bytes, but since this scenario only comes about when
+        ** p->nNodeSize bytes, but since this scenario only comes about when
         ** the database contain two terms that share a prefix of almost 2KB, 
         ** this is not expected to be a serious problem. 
         */
@@ -1248,7 +1247,7 @@ static int fts3NodeAddTerm(
   ** now. Instead, the term is inserted into the parent of pTree. If pTree 
   ** has no parent, one is created here.
   */
-  pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + INTERIOR_MAX);
+  pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize);
   if( !pNew ){
     return SQLITE_NOMEM;
   }
@@ -1401,9 +1400,9 @@ static int fts3SegWriterAdd(
     *ppWriter = pWriter;
 
     /* Allocate a buffer in which to accumulate data */
-    pWriter->aData = (char *)sqlite3_malloc(LEAF_MAX);
+    pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize);
     if( !pWriter->aData ) return SQLITE_NOMEM;
-    pWriter->nSize = LEAF_MAX;
+    pWriter->nSize = p->nNodeSize;
 
     /* Find the next free blockid in the %_segments table */
     rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pStmt, 0);
@@ -1427,7 +1426,7 @@ static int fts3SegWriterAdd(
     sqlite3Fts3VarintLen(nDoclist) +        /* Size of doclist */
     nDoclist;                               /* Doclist data */
 
-  if( nData>0 && nData+nReq>LEAF_MAX ){
+  if( nData>0 && nData+nReq>p->nNodeSize ){
     int rc;
 
     /* The current leaf node is full. Write it out to the database. */
index 57e4923111e2bc8e2ddbf4a5090b685cc36e0c81..f960c51a6782d852fb891f70c944b29f7b2b3775 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Updates\sto\sFTS3\sto\scorrect\scompiler\swarnings\sunder\sMSVC.
-D 2009-12-03T06:26:46
+C Fix\san\sincorrect\sassert()\sin\sfts3.c.\sAdd\sfurther\sfts3\stests.
+D 2009-12-03T17:36:22
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -56,9 +56,9 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
 F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c 8352dc3506c3b30fde126ea5da9c431d3c243522
+F ext/fts3/fts3.c b15d44a46f76b08806b75d70c44c62254269d619
 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h 515132f0ae6b35eccbeef72a2bafb16d7e251953
+F ext/fts3/fts3Int.h cc716c74afa7da8e0f8ef39404f33ea62a823eb3
 F ext/fts3/fts3_expr.c c18794a62c257d3456d3314c5a18e348ae0d84bd
 F ext/fts3/fts3_hash.c 18feef38fca216992725e9eae775a0c7735e6724
 F ext/fts3/fts3_hash.h d410ff2c93c81a56b927fcf07b2099ccbfa7a479
@@ -68,7 +68,7 @@ F ext/fts3/fts3_snippet.c 6c2eb6d872d66b2a9aa5663f2662e993f18a6496
 F ext/fts3/fts3_tokenizer.c 73a4e0e068720153901622f215298b73e7c976c7
 F ext/fts3/fts3_tokenizer.h 7ff73caa3327589bf6550f60d93ebdd1f6a0fb5c
 F ext/fts3/fts3_tokenizer1.c 11a604a53cff5e8c28882727bf794e5252e5227b
-F ext/fts3/fts3_write.c 6c59b1d6eed759815151298c132d79301c205fce
+F ext/fts3/fts3_write.c ec51fb6886f910e78ae32158ec0301aa675f52d8
 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
 F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
 F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2
@@ -400,8 +400,9 @@ F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
 F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
 F test/fts3expr.test 05dab77387801e4900009917bb18f556037d82da
 F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
-F test/fts3malloc.test efbd316eafe54471b7f68604c050418b31d1914e
+F test/fts3malloc.test d02ee86b21edd2b43044e0d6dfdcd26cb6efddcb
 F test/fts3near.test dc196dd17b4606f440c580d45b3d23aa975fd077
+F test/fts3rnd.test bbb85c6b2b55f15a8ecaaf1585a94845501f7369
 F test/func.test af106ed834001738246d276659406823e35cde7b
 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
 F test/fuzz.test a4174c3009a3e2c2e14b31b364ebf7ddb49de2c9
@@ -522,7 +523,7 @@ F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
 F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
-F test/quick.test 12fdc7656b4d20a537a686fb223eb99b5fe54483
+F test/quick.test 31d0c41d1602af5a2b402682770943b77d42d309
 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
@@ -775,7 +776,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P e3aa0870fce0666bf8c67ad6ec23e135d03b604a
-R 8d9ad89e2fac8a1d1d94a1d048213789
-U shaneh
-Z 7667ec8a886e15725b2ab6f5b341cdfd
+P 37495b55ffbdc2db4482367ac7d8e32d4d71d58e
+R cfd8087616225b6f440fa1c8b43bd349
+U dan
+Z bf00a60fa922c646641246a97c22e493
index 225ad7c04a54a8b964a1d7342bf0bbe90d6824d5..c0742dfffb4c59c429664ee2964e78e21b71df5b 100644 (file)
@@ -1 +1 @@
-37495b55ffbdc2db4482367ac7d8e32d4d71d58e
\ No newline at end of file
+75863c2d55e0801add5b8dcf88d575c5c870af04
\ No newline at end of file
index a1c0905136718d4b946e82a6e991a7e503da4dd7..920dc0c1d23c40f602a643db2e75d29d7af7e3e8 100644 (file)
@@ -36,126 +36,6 @@ set DO_MALLOC_TEST 1
 #
 #
 
-#-------------------------------------------------------------------------
-# This proc is used to test a single SELECT statement. Parameter $name is
-# passed a name for the test case (i.e. "fts3_malloc-1.4.1") and parameter
-# $sql is passed the text of the SELECT statement. Parameter $result is
-# set to the expected output if the SELECT statement is successfully
-# executed using [db eval].
-#
-# Example:
-#
-#   do_select_test testcase-1.1 "SELECT 1+1, 1+2" {1 2}
-#
-# If global variable DO_MALLOC_TEST is set to a non-zero value, or if
-# it is not defined at all, then OOM testing is performed on the SELECT
-# statement. Each OOM test case is said to pass if either (a) executing
-# the SELECT statement succeeds and the results match those specified
-# by parameter $result, or (b) TCL throws an "out of memory" error.
-#
-# If DO_MALLOC_TEST is defined and set to zero, then the SELECT statement
-# is executed just once. In this case the test case passes if the results
-# match the expected results passed via parameter $result.
-#
-proc do_select_test {name sql result} {
-  doPassiveTest $name $sql [list 0 $result]
-}
-
-proc do_error_test {name sql error} {
-  doPassiveTest $name $sql [list 1 $error]
-}
-
-proc doPassiveTest {name sql catchres} {
-  if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
-
-  if {$::DO_MALLOC_TEST} {
-    set answers [list {1 {out of memory}} $catchres]
-    set modes [list 100000 transient 1 persistent]
-  } else {
-    set answers [list $catchres]
-    set modes [list 0 nofail]
-  }
-  set str [join $answers " OR "]
-
-  foreach {nRepeat zName} $modes {
-    for {set iFail 1} 1 {incr iFail} {
-      if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat}
-
-      set res [catchsql $sql]
-      if {[lsearch $answers $res]>=0} {
-        set res $str
-      }
-      do_test $name.$zName.$iFail [list set {} $res] $str
-      set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
-      if {$nFail==0} break
-    }
-  }
-}
-
-
-#-------------------------------------------------------------------------
-# Test a single write to the database. In this case a  "write" is a 
-# DELETE, UPDATE or INSERT statement.
-#
-# If OOM testing is performed, there are several acceptable outcomes:
-#
-#   1) The write succeeds. No error is returned.
-#
-#   2) An "out of memory" exception is thrown and:
-#
-#     a) The statement has no effect, OR
-#     b) The current transaction is rolled back, OR
-#     c) The statement succeeds. This can only happen if the connection
-#        is in auto-commit mode (after the statement is executed, so this
-#        includes COMMIT statements).
-#
-# If the write operation eventually succeeds, zero is returned. If a
-# transaction is rolled back, non-zero is returned.
-#
-# Parameter $name is the name to use for the test case (or test cases).
-# The second parameter, $tbl, should be the name of the database table
-# being modified. Parameter $sql contains the SQL statement to test.
-#
-proc do_write_test {name tbl sql} {
-  if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
-
-  # Figure out an statement to get a checksum for table $tbl.
-  db eval "SELECT * FROM $tbl" V break
-  set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl"
-
-  # Calculate the initial table checksum.
-  set cksum1 [db one $cksumsql]
-
-
-  if {$::DO_MALLOC_TEST } {
-    set answers [list {1 {out of memory}} {0 {}}]
-    set modes [list 100000 transient 1 persistent]
-  } else {
-    set answers [list {0 {}}]
-    set modes [list 0 nofail]
-  }
-  set str [join $answers " OR "]
-
-  foreach {nRepeat zName} $modes {
-    for {set iFail 1} 1 {incr iFail} {
-      if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat}
-
-      set res [catchsql $sql]
-      set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
-      if {$nFail==0} {
-        do_test $name.$zName.$iFail [list set {} $res] {0 {}}
-        return
-      } else {
-        if {[lsearch $answers $res]>=0} {
-          set res $str
-        }
-        do_test $name.$zName.$iFail [list set {} $res] $str
-        set cksum2 [db one $cksumsql]
-        if {$cksum1 != $cksum2} return
-      }
-    }
-  }
-}
 
 proc normal_list {l} {
   set ret [list]
diff --git a/test/fts3rnd.test b/test/fts3rnd.test
new file mode 100644 (file)
index 0000000..ddea0ce
--- /dev/null
@@ -0,0 +1,148 @@
+# 2009 December 03
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Brute force (random data) tests for FTS3.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# If this build does not include FTS3, skip the tests in this file.
+#
+ifcapable !fts3 { finish_test ; return }
+source $testdir/fts3_common.tcl
+
+set nVocab 100
+set lVocab [list]
+
+# Generate a vocabulary of nVocab words. Each word is 3 characters long.
+#
+set lChar {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}
+for {set i 0} {$i < $nVocab} {incr i} {
+  set    word [lindex $lChar [expr int(rand()*26)]]
+  append word [lindex $lChar [expr int(rand()*26)]]
+  append word [lindex $lChar [expr int(rand()*26)]]
+  lappend lVocab $word
+}
+
+proc random_term {} {
+  lindex $::lVocab [expr {int(rand()*$::nVocab)}]
+}
+
+# Return a document consisting of $nWord arbitrarily selected terms
+# from the $::lVocab list.
+#
+proc generate_doc {nWord} {
+  set doc [list]
+  for {set i 0} {$i < $nWord} {incr i} {
+    lappend doc [random_term]
+  }
+  return $doc
+}
+
+
+
+# Primitives to update the table.
+#
+proc insert_row {rowid} {
+  set a [generate_doc [expr int((rand()*100))]]
+  set b [generate_doc [expr int((rand()*100))]]
+  set c [generate_doc [expr int((rand()*100))]]
+  execsql { INSERT INTO t1(docid, a, b, c) VALUES($rowid, $a, $b, $c) }
+  set ::t1($rowid) [list $a $b $c]
+}
+proc delete_row {rowid} {
+  execsql { DELETE FROM t1 WHERE rowid = $rowid }
+  catch {unset ::t1($rowid)}
+}
+proc update_row {rowid} {
+  set cols {a b c}
+  set iCol [expr int(rand()*3)]
+  set doc  [generate_doc [expr int((rand()*100))]]
+  lset ::t1($rowid) $iCol $doc
+  execsql "UPDATE t1 SET [lindex $cols $iCol] = \$doc WHERE rowid = \$rowid"
+}
+
+# Primitives to query the in-memory table.
+#
+proc simple_term {zTerm} {
+  set ret [list]
+  foreach {key value} [array get ::t1] {
+    if {[string first $zTerm $value]>=0} { lappend ret $key }
+  }
+  lsort -integer $ret
+}
+
+foreach nodesize {50 500 1000 2000} {
+  catch { array unset ::t1 }
+
+  # Create the FTS3 table. Populate it (and the Tcl array) with 100 rows.
+  #
+  db transaction {
+    catchsql { DROP TABLE t1 }
+    execsql "CREATE VIRTUAL TABLE t1 USING fts3(a, b, c, test:$nodesize)"
+    for {set i 0} {$i < 100} {incr i} { insert_row $i }
+  }
+  
+  for {set iTest 1} {$iTest <= 100} {incr iTest} {
+  
+    # Delete one row, update one row and insert one row.
+    #
+    set rows [array names ::t1]
+    set nRow [llength $rows]
+    set iUpdate [lindex $rows [expr {int(rand()*$nRow)}]]
+    set iDelete $iUpdate
+    while {$iDelete == $iUpdate} {
+      set iDelete [lindex $rows [expr {int(rand()*$nRow)}]]
+    }
+    set iInsert $iUpdate
+    while {[info exists ::t1($iInsert)]} {
+      set iInsert [expr {int(rand()*1000000)}]
+    }
+    db transaction {
+      insert_row $iInsert
+      update_row $iUpdate
+      delete_row $iDelete
+    }
+  
+    # Pick 10 terms from the vocabulary. Check that the results of querying
+    # the database for the set of documents containing each of these terms
+    # is the same as the result obtained by scanning the contents of the Tcl 
+    # array for each term.
+    #
+    set n [expr {$iTest % ([llength $::lVocab]-10)}]
+    foreach term [lrange $::lVocab $n [expr $n+10]] {
+      do_test fts3rnd-1.$nodesize.$iTest.$term {
+        execsql { SELECT docid FROM t1 WHERE t1 MATCH $term }
+      } [simple_term $term]
+    }
+
+    # Similar to the above, except for phrase queries.
+    #
+    for {set i 0} {$i < 10} {incr i} {
+      set term [list [random_term] [random_term]]
+      set match "\"$term\""
+      do_test fts3rnd-1.$nodesize.$iTest.$match {
+        execsql { SELECT docid FROM t1 WHERE t1 MATCH $match }
+      } [simple_term $term]
+    }
+    
+    # Three word phrases.
+    #
+    for {set i 0} {$i < 10} {incr i} {
+      set term [list [random_term] [random_term] [random_term]]
+      set match "\"$term\""
+      do_test fts3rnd-1.$nodesize.$iTest.$match {
+        execsql { SELECT docid FROM t1 WHERE t1 MATCH $match }
+      } [simple_term $term]
+    }
+  }
+}
+
+finish_test
+
index a56455a1416ce865ab7631ee244e75c42ffb2702..9006ef39bbe54503077770db536986b147ab9fe2 100644 (file)
@@ -57,7 +57,9 @@ set EXCLUDE {
   crash6.test
   crash7.test
   delete3.test
+  e_fts3.test
   fts3.test
+  fts3fuzz.test
   fkey_malloc.test
   fuzz.test
   fuzz3.test