]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Improvements to the way fts3 reads the full-text index.
authordan <dan@noemail.net>
Tue, 17 Nov 2009 12:52:10 +0000 (12:52 +0000)
committerdan <dan@noemail.net>
Tue, 17 Nov 2009 12:52:10 +0000 (12:52 +0000)
FossilOrigin-Name: 45c051e78651d8204c17cecdda2bde705698881f

ext/fts3/fts3.c
ext/fts3/fts3Int.h
ext/fts3/fts3_write.c
manifest
manifest.uuid
test/fts3malloc.test

index 93ad7a9f8a2fdcfbece1675efbfd6da386bdb632..08d4311163da97e22f168ec19921aa8f0cffa4ca 100644 (file)
@@ -905,7 +905,7 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
 static int fts3ReadBlock(
   Fts3Table *p,
   sqlite3_int64 iBlock,
-  char **pzBlock,
+  char const **pzBlock,
   int *pnBlock
 ){
   sqlite3_stmt *pStmt;
@@ -928,27 +928,28 @@ static int fts3ReadBlock(
 }
 
 /*
-** The buffer pointed to by argument zNode (size nNode bytes) contains a
-** b-tree segment interior node. This function inspects the sub-tree headed
-** by the node to determine the range of leaf-nodes (if any) that may 
-** contain a term that matches the contents of buffer zTerm (size nTerm 
-** bytes). If the isPrefix parameter is true, then the range of leaves
-** returned are those that may contain any term for which zTerm/nTerm is
-** a prefix.
-**
-** If successful, SQLITE_OK is returned. The blockid of the first leaf in the
-** selected range is written to piStart before returning. The blockid of the
-** final leaf in the selected range is written to *piEnd.
+** The buffer pointed to by argument zNode (size nNode bytes) contains the
+** root node of a b-tree segment. The segment is guaranteed to be at least
+** one level high (i.e. the root node is not also a leaf). If successful,
+** this function locates the leaf node of the segment that may contain the 
+** term specified by arguments zTerm and nTerm and writes its block number 
+** to *piLeaf.
+**
+** It is possible that the returned leaf node does not contain the specified
+** term. However, if the segment does contain said term, it is stored on
+** the identified leaf node. Because this function only inspects interior
+** segment nodes (and never loads leaf nodes into memory), it is not possible
+** to be sure.
+**
+** If an error occurs, an error code other than SQLITE_OK is returned.
 */ 
-static int fts3SelectLeaves(
+static int fts3SelectLeaf(
   Fts3Table *p,                   /* Virtual table handle */
   const char *zTerm,              /* Term to select leaves for */
   int nTerm,                      /* Size of term zTerm in bytes */
-  int isPrefix,                   /* True for a prefix search */
   const char *zNode,              /* Buffer containing segment interior node */
   int nNode,                      /* Size of buffer at zNode */
-  sqlite3_int64 *piStart,         /* First selected leaf */
-  sqlite3_int64 *piEnd            /* Second selected leaf */
+  sqlite3_int64 *piLeaf           /* Selected leaf node */
 ){
   int rc = SQLITE_OK;             /* Return code */
   const char *zCsr = zNode;       /* Cursor to iterate through node */
@@ -956,79 +957,67 @@ static int fts3SelectLeaves(
   char *zBuffer = 0;              /* Buffer to load terms into */
   int nAlloc = 0;                 /* Size of allocated buffer */
 
-  int iHeight;                    /* Height of this node in tree */
-  sqlite3_int64 iChild;
-  sqlite3_int64 iStart = 0;
-  sqlite3_int64 iEnd;
-
-  zCsr += sqlite3Fts3GetVarint32(zCsr, &iHeight);
-  zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
-
-  while( zCsr<zEnd ){
-    int nSuffix;                  /* Size of term suffix */
-    int nPrefix = 0;              /* Size of term prefix */
-    int nBuffer;                  /* Total term size */
-    int nMin;                     /* Minimum of nBuffer and nTerm */
-    int cmp;                      /* Result of comparing term and buffer */
-
-    /* Load the next term on the node into zBuffer */
-    if( zBuffer ){
-      zCsr += sqlite3Fts3GetVarint32(zCsr, &nPrefix);
-    }
-    zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
-    if( nPrefix+nSuffix>nAlloc ){
-      char *zNew;
-      nAlloc = (nPrefix+nSuffix) * 2;
-      zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
-      if( !zNew ){
-        sqlite3_free(zBuffer);
-        return SQLITE_NOMEM;
+  while( 1 ){
+    int iHeight;                  /* Height of this node in tree */
+    sqlite3_int64 iChild;         /* Block id of child node to descend to */
+    int nBlock;                   /* Size of child node in bytes */
+
+    zCsr += sqlite3Fts3GetVarint32(zCsr, &iHeight);
+    zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
+  
+    while( zCsr<zEnd ){
+      int nSuffix;                /* Size of term suffix */
+      int nPrefix = 0;            /* Size of term prefix */
+      int nBuffer;                /* Total term size */
+      int nMin;                   /* Minimum of nBuffer and nTerm */
+  
+      /* Load the next term on the node into zBuffer */
+      if( zBuffer ){
+        zCsr += sqlite3Fts3GetVarint32(zCsr, &nPrefix);
       }
-      zBuffer = zNew;
-    }
-    memcpy(&zBuffer[nPrefix], zCsr, nSuffix);
-    nBuffer = nPrefix + nSuffix;
-    zCsr += nSuffix;
-
-    /* Compare the term we are searching for with the term just loaded from
-    ** the interior node. If variable cmp is greater than or equal to zero, 
-    ** then all terms on the sub-tree headed by node iChild are smaller than 
-    ** zTerm. No need to search iChild.
-    **
-    ** If variable cmp is less than zero, then the sub-tree headed by 
+      zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
+      if( nPrefix+nSuffix>nAlloc ){
+        char *zNew;
+        nAlloc = (nPrefix+nSuffix) * 2;
+        zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
+        if( !zNew ){
+          sqlite3_free(zBuffer);
+          return SQLITE_NOMEM;
+        }
+        zBuffer = zNew;
+      }
+      memcpy(&zBuffer[nPrefix], zCsr, nSuffix);
+      nBuffer = nPrefix + nSuffix;
+      zCsr += nSuffix;
+  
+      /* Compare the term we are searching for with the term just loaded from
+      ** the interior node. If the specified term is greater than or equal
+      ** to the term from the interior node, then all terms on the sub-tree 
+      ** headed by node iChild are smaller than zTerm. No need to search 
+      ** iChild.
+      **
+      ** If the interior node term is larger than the specified term, then
+      ** the tree headed by iChild may contain the specified term.
+      */
+      nMin = (nBuffer>nTerm ? nTerm : nBuffer);
+      if( memcmp(zTerm, zBuffer, nMin)<0 ) break;
+      iChild++;
+    };
+
+    /* If (iHeight==1), the children of this interior node are leaves. The
+    ** specified term may be present on leaf node iChild.
     */
-    nMin = (nBuffer>nTerm ? nTerm : nBuffer);
-    cmp = memcmp(zTerm, zBuffer, nMin);
-    if( isPrefix && cmp==0 && iStart==0 ){
-      iStart = iChild;
+    if( iHeight==1 ){
+      *piLeaf = iChild;
+      break;
     }
-    if( cmp<0 ) break;
-    iChild++;
-  };
-  iEnd = iChild;
-  if( iStart==0 ) iStart = iChild;
-  sqlite3_free(zBuffer);
 
-  if( iHeight==1 ){
-    if( piEnd ) *piEnd = iEnd;
-    if( piStart ) *piStart = iStart;
-  }else{
-    char *zBlock;
-    int nBlock;
-    if( piEnd ){
-      rc = fts3ReadBlock(p, iEnd, &zBlock, &nBlock);
-      if( rc==SQLITE_OK ){
-        rc = fts3SelectLeaves(p,zTerm,nTerm,isPrefix,zBlock,nBlock,0,piEnd);
-      }
-    }
-    if( piStart && rc==SQLITE_OK ){
-      rc = fts3ReadBlock(p, iStart, &zBlock, &nBlock);
-      if( rc==SQLITE_OK ){
-        rc = fts3SelectLeaves(p,zTerm,nTerm,isPrefix,zBlock,nBlock,piStart,0);
-      }
-    }
+    /* Descend to interior node iChild. */
+    rc = fts3ReadBlock(p, iChild, &zCsr, &nBlock);
+    if( rc!=SQLITE_OK ) break;
+    zEnd = &zCsr[nBlock];
   }
-
+  sqlite3_free(zBuffer);
   return rc;
 }
 
@@ -1409,7 +1398,6 @@ static int fts3DoclistMerge(
           return SQLITE_NOMEM;
         }
       }
-      (mergetype==MERGE_NEAR ? 0 : &p);
 
       while( p1 && p2 ){
         if( i1==i2 ){
@@ -1444,58 +1432,54 @@ static int fts3DoclistMerge(
   return SQLITE_OK;
 }
 
+/* 
+** A pointer to an instance of this structure is used as the context 
+** argument to sqlite3Fts3SegReaderIterate()
+*/
 typedef struct TermSelect TermSelect;
 struct TermSelect {
-  char const *zTerm;
-  int nTerm;
-  int isPrefix;
   int isReqPos;
   char *aOutput;                  /* Malloc'd output buffer */
   int nOutput;                    /* Size of output in bytes */
 };
 
 static int fts3TermSelectCb(
-  Fts3Table *p,
-  void *pContext,
+  Fts3Table *p,                   /* Virtual table object */
+  void *pContext,                 /* Pointer to TermSelect structure */
   char *zTerm,
   int nTerm,
   char *aDoclist,
   int nDoclist
 ){
   TermSelect *pTS = (TermSelect *)pContext;
+  int nNew = pTS->nOutput + nDoclist;
 
-  if( (pTS->nTerm==nTerm || (pTS->isPrefix && pTS->nTerm<nTerm))
-   && 0==memcmp(zTerm, pTS->zTerm, pTS->nTerm) 
-  ){
-    int nNew = pTS->nOutput + nDoclist;
-    char *aNew = sqlite3_malloc(nNew);
-    if( !aNew ){
-      return SQLITE_NOMEM;
-    }
-
-    if( pTS->nOutput==0 ){
-      /* If this is the first term selected, copy the doclist to the output
-      ** buffer using memcpy(). TODO: Add a way to transfer control of the
-      ** aDoclist buffer from the caller so as to avoid the memcpy().
-      */
-      memcpy(aNew, aDoclist, nDoclist);
-    }else{
-      /* The output buffer is not empty. Merge doclist aDoclist with the
-      ** existing output. This can only happen with prefix-searches (as
-      ** searches for exact terms return exactly one doclist).
-      */
-      int mergetype = (pTS->isReqPos ? MERGE_POS_OR : MERGE_OR);
-      assert( pTS->isPrefix );
-      fts3DoclistMerge(mergetype, 0, 0,
-          aNew, &nNew, pTS->aOutput, pTS->nOutput, aDoclist, nDoclist
-      );
-    }
+  char *aNew = sqlite3_malloc(nNew);
+  if( !aNew ){
+    return SQLITE_NOMEM;
+  }
 
-    sqlite3_free(pTS->aOutput);
-    pTS->aOutput = aNew;
-    pTS->nOutput = nNew;
+  if( pTS->nOutput==0 ){
+    /* If this is the first term selected, copy the doclist to the output
+    ** buffer using memcpy(). TODO: Add a way to transfer control of the
+    ** aDoclist buffer from the caller so as to avoid the memcpy().
+    */
+    memcpy(aNew, aDoclist, nDoclist);
+  }else{
+    /* The output buffer is not empty. Merge doclist aDoclist with the
+    ** existing output. This can only happen with prefix-searches (as
+    ** searches for exact terms return exactly one doclist).
+    */
+    int mergetype = (pTS->isReqPos ? MERGE_POS_OR : MERGE_OR);
+    fts3DoclistMerge(mergetype, 0, 0,
+        aNew, &nNew, pTS->aOutput, pTS->nOutput, aDoclist, nDoclist
+    );
   }
 
+  sqlite3_free(pTS->aOutput);
+  pTS->aOutput = aNew;
+  pTS->nOutput = nNew;
+
   return SQLITE_OK;
 }
 
@@ -1522,13 +1506,13 @@ static int fts3TermSelect(
 ){
   int i;
   TermSelect tsc;
+  Fts3SegFilter filter;           /* Segment term filter configuration */
   Fts3SegReader **apSegment = 0;  /* Array of segments to read data from */
   int nSegment = 0;               /* Size of apSegment array */
   int nAlloc = 0;                 /* Allocated size of segment array */
   int rc;                         /* Return code */
   sqlite3_stmt *pStmt;            /* SQL statement to scan %_segdir table */
   int iAge = 0;                   /* Used to assign ages to segments */
-  int flags;
 
   /* Loop through the entire %_segdir table. For each segment, create a
   ** Fts3SegReader to iterate through the subset of the segment leaves
@@ -1552,10 +1536,10 @@ static int fts3TermSelect(
       */
       rc = sqlite3Fts3SegReaderNew(p, iAge, 0, 0, 0, zRoot, nRoot, &pNew);
     }else{
-      sqlite3_int64 i1, i2;
-      rc = fts3SelectLeaves(p, zTerm, nTerm, isPrefix, zRoot, nRoot, &i1, &i2);
+      sqlite3_int64 i1;
+      rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1);
       if( rc==SQLITE_OK ){
-        assert( i1 && i2 );
+        sqlite3_int64 i2 = sqlite3_column_int64(pStmt, 3);
         rc = sqlite3Fts3SegReaderNew(p, iAge, i1, i2, 0, 0, 0, &pNew);
       }
     }
@@ -1585,16 +1569,17 @@ static int fts3TermSelect(
   }
 
   memset(&tsc, 0, sizeof(TermSelect));
-  tsc.zTerm = zTerm;
-  tsc.nTerm = nTerm;
-  tsc.isPrefix = isPrefix;
   tsc.isReqPos = isReqPos;
 
-  flags = FTS3_SEGMENT_IGNORE_EMPTY 
+  filter.flags = FTS3_SEGMENT_IGNORE_EMPTY 
+        | (isPrefix ? FTS3_SEGMENT_PREFIX : 0)
         | (isReqPos ? FTS3_SEGMENT_REQUIRE_POS : 0)
         | (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0);
-  rc = sqlite3Fts3SegReaderIterate(p, apSegment, nSegment, flags,
-      iColumn, fts3TermSelectCb, (void *)&tsc
+  filter.iCol = iColumn;
+  filter.zTerm = zTerm;
+  filter.nTerm = nTerm;
+  rc = sqlite3Fts3SegReaderIterate(p, apSegment, nSegment, &filter,
+      fts3TermSelectCb, (void *)&tsc
   );
 
   if( rc==SQLITE_OK ){
index ff285e19928247786bfb415e3174cb43b33e41ec..4c668256424d2f673d61c6af1967cf85f47c6fc0 100644 (file)
@@ -58,6 +58,7 @@ typedef struct Fts3Cursor Fts3Cursor;
 typedef struct Fts3Expr Fts3Expr;
 typedef struct Fts3Phrase Fts3Phrase;
 typedef struct Fts3SegReader Fts3SegReader;
+typedef struct Fts3SegFilter Fts3SegFilter;
 
 /*
 ** A connection to a fulltext index is an instance of the following
@@ -123,14 +124,14 @@ struct Fts3Cursor {
 ** of tokens in the string.
 */
 struct Fts3Phrase {
-  int nToken;          /* Number of tokens in the phrase */
-  int iColumn;         /* Index of column this phrase must match */
-  int isNot;           /* Phrase prefixed by unary not (-) operator */
+  int nToken;                /* Number of tokens in the phrase */
+  int iColumn;               /* Index of column this phrase must match */
+  int isNot;                 /* Phrase prefixed by unary not (-) operator */
   struct PhraseToken {
-    char *z;              /* Text of the token */
-    int n;                /* Number of bytes in buffer pointed to by z */
-    int isPrefix;         /* True if token ends in with a "*" character */
-  } aToken[1];         /* One entry for each token in the phrase */
+    char *z;                 /* Text of the token */
+    int n;                   /* Number of bytes in buffer pointed to by z */
+    int isPrefix;            /* True if token ends in with a "*" character */
+  } aToken[1];               /* One entry for each token in the phrase */
 };
 
 /*
@@ -178,12 +179,21 @@ int sqlite3Fts3Optimize(Fts3Table *);
 #define FTS3_SEGMENT_REQUIRE_POS   0x00000001
 #define FTS3_SEGMENT_IGNORE_EMPTY  0x00000002
 #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004
+#define FTS3_SEGMENT_PREFIX        0x00000008
+
+struct Fts3SegFilter {
+  const char *zTerm;
+  int nTerm;
+  int iCol;
+  int flags;
+};
 
 int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
   sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
 void sqlite3Fts3SegReaderFree(Fts3SegReader *);
+
 int sqlite3Fts3SegReaderIterate(
-  Fts3Table *, Fts3SegReader **, int, int, int, 
+  Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
   int (*)(Fts3Table *, void *, char *, int, char *, int),  void *
 );
 
index cd83e692e2cf85f85ce4136c912033c5e8e91a61..f4b8a9b2ec4a70b4a68bf8a886ebbbeb85b60f79 100644 (file)
@@ -873,6 +873,33 @@ static int fts3SegReaderCmp2(Fts3SegReader *pLhs, Fts3SegReader *pRhs){
   return rc;
 }
 
+/*
+** Compare the term that the Fts3SegReader object passed as the first argument
+** points to with the term specified by arguments zTerm and nTerm. 
+**
+** If the pSeg iterator is already at EOF, return 0. Otherwise, return
+** -ve if the pSeg term is less than zTerm/nTerm, 0 if the two terms are
+** equal, or +ve if the pSeg term is greater than zTerm/nTerm.
+*/
+static int fts3SegReaderTermCmp(
+  Fts3SegReader *pSeg,            /* Segment reader object */
+  const char *zTerm,              /* Term to compare to */
+  int nTerm                       /* Size of term zTerm in bytes */
+){
+  int res = 0;
+  if( pSeg->aNode ){
+    if( pSeg->nTerm>nTerm ){
+      res = memcmp(pSeg->zTerm, zTerm, nTerm);
+    }else{
+      res = memcmp(pSeg->zTerm, zTerm, pSeg->nTerm);
+    }
+    if( res==0 ){
+      res = pSeg->nTerm-nTerm;
+    }
+  }
+  return res;
+}
+
 /*
 ** Argument apSegment is an array of nSegment elements. It is known that
 ** the final (nSegment-nSuspect) members are already in sorted order
@@ -1427,8 +1454,9 @@ static void fts3ColumnFilter(int iCol, char **ppList, int *pnList){
   int nList = *pnList;
   char *pEnd = &pList[nList];
   int iCurrent = 0;
-
   char *p = pList;
+
+  assert( iCol>=0 );
   while( 1 ){
     char c = 0;
     while( p<pEnd && (c | *p)&0xFE ) c = *p++ & 0x80;
@@ -1467,8 +1495,7 @@ int sqlite3Fts3SegReaderIterate(
   Fts3Table *p,                   /* Virtual table handle */
   Fts3SegReader **apSegment,      /* Array of Fts3SegReader objects */
   int nSegment,                   /* Size of apSegment array */
-  int flags,                      /* Flags mask */
-  int iCol,                       /* Column to filter for */
+  Fts3SegFilter *pFilter,         /* Restrictions on range of iteration */
   int (*xFunc)(Fts3Table *, void *, char *, int, char *, int),  /* Callback */
   void *pContext                  /* Callback context (2nd argument) */
 ){
@@ -1477,9 +1504,28 @@ int sqlite3Fts3SegReaderIterate(
   int nAlloc = 0;                 /* Allocated size of aBuffer buffer */
   int rc = SQLITE_OK;             /* Return code */
 
-  int isIgnoreEmpty  = (flags&FTS3_SEGMENT_IGNORE_EMPTY);
-  int isRequirePos = (flags&FTS3_SEGMENT_REQUIRE_POS);
-  int isColFilter = (flags&FTS3_SEGMENT_COLUMN_FILTER);
+  int isIgnoreEmpty =  (pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY);
+  int isRequirePos =   (pFilter->flags & FTS3_SEGMENT_REQUIRE_POS);
+  int isColFilter =    (pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER);
+  int isPrefix =       (pFilter->flags & FTS3_SEGMENT_PREFIX);
+
+  /* If the Fts3SegFilter defines a specific term (or term prefix) to search 
+  ** for, then advance each segment iterator until it points to a term of
+  ** equal or greater value than the specified term. This prevents many
+  ** unnecessary merge/sort operations for the case where single segment
+  ** b-tree leaf nodes contain more than one term.
+  */
+  if( pFilter->zTerm ){
+    int nTerm = pFilter->nTerm;
+    char *zTerm = pFilter->zTerm;
+    for(i=0; i<nSegment; i++){
+      Fts3SegReader *pSeg = apSegment[i];
+      while( fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 ){
+        rc = fts3SegReaderNext(pSeg);
+        if( rc!=SQLITE_OK ) goto finished;
+      }
+    }
+  }
 
   fts3SegReaderSort(apSegment, nSegment, nSegment, fts3SegReaderCmp);
   while( apSegment[0]->aNode ){
@@ -1487,6 +1533,22 @@ int sqlite3Fts3SegReaderIterate(
     char *zTerm = apSegment[0]->zTerm;
     int nMerge = 1;
 
+    /* If this is a prefix-search, and if the term that apSegment[0] points
+    ** to does not share a suffix with pFilter->zTerm/nTerm, then all 
+    ** required callbacks have been made. In this case exit early.
+    **
+    ** Similarly, if this is a search for an exact match, and the first term
+    ** of segment apSegment[0] is not a match, exit early.
+    */
+    if( pFilter->zTerm ){
+      if( nTerm<pFilter->nTerm 
+       || (!isPrefix && nTerm>pFilter->nTerm)
+       || memcmp(zTerm, pFilter->zTerm, pFilter->nTerm) 
+    ){
+        goto finished;
+      }
+    }
+
     while( nMerge<nSegment 
         && apSegment[nMerge]->aNode
         && apSegment[nMerge]->nTerm==nTerm 
@@ -1527,9 +1589,8 @@ int sqlite3Fts3SegReaderIterate(
           j++;
         }
 
-        assert( iCol>=0 || isColFilter==0 );
         if( isColFilter ){
-          fts3ColumnFilter(iCol, &pList, &nList);
+          fts3ColumnFilter(pFilter->iCol, &pList, &nList);
         }
 
         if( !isIgnoreEmpty || nList>0 ){
@@ -1562,6 +1623,14 @@ int sqlite3Fts3SegReaderIterate(
       }
     }
 
+    /* If there is a term specified to filter on, and this is not a prefix
+    ** search, return now. The callback that corresponds to the required
+    ** term (if such a term exists in the index) has already been made.
+    */
+    if( pFilter->zTerm && !isPrefix ){
+      goto finished;
+    }
+
     for(i=0; i<nMerge; i++){
       rc = fts3SegReaderNext(apSegment[i]);
       if( rc!=SQLITE_OK ) goto finished;
@@ -1594,6 +1663,7 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
   SegmentWriter *pWriter = 0;
   int nSegment = 0;               /* Number of segments being merged */
   Fts3SegReader **apSegment = 0;  /* Array of Segment iterators */
+  Fts3SegFilter filter;           /* Segment term filter condition */
 
   if( iLevel<0 ){
     /* This call is to merge all segments in the database to a single
@@ -1646,10 +1716,11 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
   pStmt = 0;
   if( rc!=SQLITE_OK ) goto finished;
 
-  rc = sqlite3Fts3SegReaderIterate(
-      p, apSegment, nSegment, 
-      (iLevel<0 ? FTS3_SEGMENT_IGNORE_EMPTY : 0)|FTS3_SEGMENT_REQUIRE_POS, 
-      0, fts3MergeCallback, (void *)&pWriter
+  memset(&filter, 0, sizeof(Fts3SegFilter));
+  filter.flags = FTS3_SEGMENT_REQUIRE_POS;
+  filter.flags |= (iLevel<0 ? FTS3_SEGMENT_IGNORE_EMPTY : 0);
+  rc = sqlite3Fts3SegReaderIterate(p, apSegment, nSegment,
+      &filter, fts3MergeCallback, (void *)&pWriter
   );
   if( rc!=SQLITE_OK ) goto finished;
 
index 6a7164ad9b4887c21bbc5fd0ac8805130d73f668..07d603effa60db5377ffd0639bdb17b1a5e43e98 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sa\sfew\sextra\scoverage\stest\scases\sfor\sfts3.
-D 2009-11-16T16:36:23
+C Improvements\sto\sthe\sway\sfts3\sreads\sthe\sfull-text\sindex.
+D 2009-11-17T12:52:10
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 53f3dfa49f28ab5b80cb083fb7c9051e596bcfa1
 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 4d701e31cb32cfb9b535edcc33271d8bcb2fa76f
+F ext/fts3/fts3.c a72c19fa6270b5f88ad9b1215c821f7082164655
 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h f8419da445790c0666d4b4d72dc15a07dd7ae93e
+F ext/fts3/fts3Int.h 5c040c0fb47ed81aaba589a55a7455c980592bea
 F ext/fts3/fts3_expr.c bdf11f3602f62f36f0e42823680bf22033dae0de
 F ext/fts3/fts3_hash.c 1af1833a4d581ee8d668bb71f5a500f7a0104982
 F ext/fts3/fts3_hash.h 39524725425078bf9e814e9569c74a8e5a21b9fb
@@ -68,7 +68,7 @@ F ext/fts3/fts3_snippet.c 8ea9619247ac61c79aca650fc3307b8b4097b5f3
 F ext/fts3/fts3_tokenizer.c 185a212670a9bbdeb5cad6942305e681bce5c87b
 F ext/fts3/fts3_tokenizer.h 7ff73caa3327589bf6550f60d93ebdd1f6a0fb5c
 F ext/fts3/fts3_tokenizer1.c 0a5bcc579f35de5d24a9345d7908dc25ae403ee7
-F ext/fts3/fts3_write.c 4285a2804ef308ed2eef946dae20d9d0361554d0
+F ext/fts3/fts3_write.c edf123f978fca3d26707452a380fa169849eb655
 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
 F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
 F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2
@@ -398,7 +398,7 @@ F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
 F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
 F test/fts3expr.test 05dab77387801e4900009917bb18f556037d82da
 F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
-F test/fts3malloc.test ed11f188d03560d7f44bd5c126ac004f011cc719
+F test/fts3malloc.test cda1b22d8c86c3e434d93b63f2fc7a0191fb6d30
 F test/fts3near.test dc196dd17b4606f440c580d45b3d23aa975fd077
 F test/func.test af106ed834001738246d276659406823e35cde7b
 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
@@ -772,7 +772,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P d3cae986ee1a176b1b015c3cebcd58ff0c3bdf92
-R 4deae89fec5a2f223cc1fc606b6691c8
+P f29c8fcade4aadeae3824975cf59f306c11c906b
+R a419bf1bcdd810be07b904f21b0a1ef0
 U dan
-Z 34f2a8a40095974f35e0328293748f2b
+Z 4e40dbade582f444c0b93ffcad88c385
index 0bd900101800f837f49565e94fbb65e7e6249660..7c6488660213430441e753ab0f50aab3420036c5 100644 (file)
@@ -1 +1 @@
-f29c8fcade4aadeae3824975cf59f306c11c906b
\ No newline at end of file
+45c051e78651d8204c17cecdda2bde705698881f
\ No newline at end of file
index 78998354d9c0cb60aa4e771a8e08de1816cbaa49..f600fa9d61e89857b618bd4cc1207c0a75cf2318 100644 (file)
@@ -181,17 +181,24 @@ do_write_test fts3_malloc-1.6 sqlite_master {
 }
 
 # Test the xConnect/xDisconnect methods:
-db eval { ATTACH 'test2.db' AS aux }
-do_write_test fts3_malloc-1.6 aux.sqlite_master {
-  CREATE VIRTUAL TABLE aux.ft7 USING fts3(a, b, c);
-}
-do_write_test fts3_malloc-1.6 aux.sqlite_master {
-  CREATE VIRTUAL TABLE aux.ft7 USING fts3(a, b, c);
-}
+#db eval { ATTACH 'test2.db' AS aux }
+#do_write_test fts3_malloc-1.6 aux.sqlite_master {
+#  CREATE VIRTUAL TABLE aux.ft7 USING fts3(a, b, c);
+#}
+#do_write_test fts3_malloc-1.6 aux.sqlite_master {
+#  CREATE VIRTUAL TABLE aux.ft7 USING fts3(a, b, c);
+#}
 
 
 
 do_test fts3_malloc-2.0 {
+  execsql { 
+    DROP TABLE ft1;
+    DROP TABLE ft2;
+    DROP TABLE ft3;
+    DROP TABLE ft4;
+    DROP TABLE ft6;
+  }
   execsql { CREATE VIRTUAL TABLE ft USING fts3(a, b) }
   for {set ii 1} {$ii < 32} {incr ii} {
     set a [list]