]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Have NEAR queries use incremental merging. Fix issues surrounding the deferred token...
authordan <dan@noemail.net>
Tue, 7 Jun 2011 18:35:45 +0000 (18:35 +0000)
committerdan <dan@noemail.net>
Tue, 7 Jun 2011 18:35:45 +0000 (18:35 +0000)
FossilOrigin-Name: 9d10a6846b12a9cc8fd4fdc3affd931a27218b5a

ext/fts3/fts3.c
manifest
manifest.uuid
test/fts3defer2.test
test/fts3matchinfo.test

index 0ab0ecaef78c2a5c17f622fb1e8e1ca755ecfcc6..d3a49f9df64d319e1cf49749656fa5fb5150d4b3 100644 (file)
@@ -1069,7 +1069,6 @@ static int fts3InitVtab(
   p->nPendingData = 0;
   p->azColumn = (char **)&p[1];
   p->pTokenizer = pTokenizer;
-  p->nNodeSize = 1000;
   p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
   p->bHasDocsize = (isFts4 && bNoDocsize==0);
   p->bHasStat = isFts4;
@@ -1127,6 +1126,7 @@ static int fts3InitVtab(
   ** function sqlite3Fts3SegReaderCost() for details).
   */
   fts3DatabasePageSize(&rc, p);
+  p->nNodeSize = p->nPgsz-35;
 
   /* Declare the table schema to SQLite. */
   fts3DeclareVtab(&rc, p);
@@ -1862,7 +1862,19 @@ static int fts3PoslistPhraseMerge(
 }
 
 /*
-** Merge two position-lists as required by the NEAR operator.
+** Merge two position-lists as required by the NEAR operator. The argument
+** position lists correspond to the left and right phrases of an expression 
+** like:
+**
+**     "phrase 1" NEAR "phrase number 2"
+**
+** Position list *pp1 corresponds to the left-hand side of the NEAR 
+** expression and *pp2 to the right. As usual, the indexes in the position 
+** lists are the offsets of the last token in each phrase (tokens "1" and "2" 
+** in the example above).
+**
+** The output position list - written to *pp - is a copy of *pp2 with those
+** entries that are not sufficiently NEAR entries in *pp1 removed.
 */
 static int fts3PoslistNearMerge(
   char **pp,                      /* Output buffer */
@@ -1875,34 +1887,27 @@ static int fts3PoslistNearMerge(
   char *p1 = *pp1;
   char *p2 = *pp2;
 
-  if( !pp ){
-    if( fts3PoslistPhraseMerge(0, nRight, 0, 0, pp1, pp2) ) return 1;
-    *pp1 = p1;
-    *pp2 = p2;
-    return fts3PoslistPhraseMerge(0, nLeft, 0, 0, pp2, pp1);
-  }else{
-    char *pTmp1 = aTmp;
-    char *pTmp2;
-    char *aTmp2;
-    int res = 1;
-
-    fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2);
-    aTmp2 = pTmp2 = pTmp1;
-    *pp1 = p1;
-    *pp2 = p2;
-    fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1);
-    if( pTmp1!=aTmp && pTmp2!=aTmp2 ){
-      fts3PoslistMerge(pp, &aTmp, &aTmp2);
-    }else if( pTmp1!=aTmp ){
-      fts3PoslistCopy(pp, &aTmp);
-    }else if( pTmp2!=aTmp2 ){
-      fts3PoslistCopy(pp, &aTmp2);
-    }else{
-      res = 0;
-    }
+  char *pTmp1 = aTmp;
+  char *pTmp2;
+  char *aTmp2;
+  int res = 1;
 
-    return res;
+  fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2);
+  aTmp2 = pTmp2 = pTmp1;
+  *pp1 = p1;
+  *pp2 = p2;
+  fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1);
+  if( pTmp1!=aTmp && pTmp2!=aTmp2 ){
+    fts3PoslistMerge(pp, &aTmp, &aTmp2);
+  }else if( pTmp1!=aTmp ){
+    fts3PoslistCopy(pp, &aTmp);
+  }else if( pTmp2!=aTmp2 ){
+    fts3PoslistCopy(pp, &aTmp2);
+  }else{
+    res = 0;
   }
+
+  return res;
 }
 
 /* 
@@ -3244,6 +3249,7 @@ static void fts3EvalAllocateReaders(
   Fts3Cursor *pCsr, 
   Fts3Expr *pExpr, 
   int *pnToken,                   /* OUT: Total number of tokens in phrase. */
+  int *pnOr,                      /* OUT: Total number of OR nodes in expr. */
   int *pRc
 ){
   if( pExpr && SQLITE_OK==*pRc ){
@@ -3262,8 +3268,9 @@ static void fts3EvalAllocateReaders(
         }
       }
     }else{
-      fts3EvalAllocateReaders(pCsr, pExpr->pLeft, pnToken, pRc);
-      fts3EvalAllocateReaders(pCsr, pExpr->pRight, pnToken, pRc);
+      *pnOr += (pExpr->eType==FTSQUERY_OR);
+      fts3EvalAllocateReaders(pCsr, pExpr->pLeft, pnToken, pnOr, pRc);
+      fts3EvalAllocateReaders(pCsr, pExpr->pRight, pnToken, pnOr, pRc);
     }
   }
 }
@@ -3545,6 +3552,7 @@ static int fts3EvalPhraseNext(
 
   if( p->bIncr ){
     assert( p->nToken==1 );
+    assert( pDL->pNextDocid==0 );
     rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, 
         &pDL->iDocid, &pDL->pList, &pDL->nList
     );
@@ -3602,9 +3610,6 @@ static void fts3EvalStartReaders(
       pExpr->bDeferred = (i==nToken);
       *pRc = fts3EvalPhraseStart(pCsr, bOptOk, pExpr->pPhrase);
     }else{
-      if( pExpr->eType==FTSQUERY_NEAR ){
-        bOptOk = 0;
-      }
       fts3EvalStartReaders(pCsr, pExpr->pLeft, bOptOk, pRc);
       fts3EvalStartReaders(pCsr, pExpr->pRight, bOptOk, pRc);
       pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred);
@@ -3700,14 +3705,17 @@ static void fts3EvalNearTrim(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){
 typedef struct Fts3TokenAndCost Fts3TokenAndCost;
 struct Fts3TokenAndCost {
   Fts3PhraseToken *pToken;
+  Fts3Expr *pRoot;
   int nOvfl;
   int iCol;
 };
 
 static void fts3EvalTokenCosts(
   Fts3Cursor *pCsr, 
+  Fts3Expr *pRoot, 
   Fts3Expr *pExpr, 
   Fts3TokenAndCost **ppTC,
+  Fts3Expr ***ppOr,
   int *pRc
 ){
   if( *pRc==SQLITE_OK && pExpr ){
@@ -3716,13 +3724,19 @@ static void fts3EvalTokenCosts(
       int i;
       for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){
         Fts3TokenAndCost *pTC = (*ppTC)++;
+        pTC->pRoot = pRoot;
         pTC->pToken = &pPhrase->aToken[i];
         pTC->iCol = pPhrase->iColumn;
         *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl);
       }
-    }else if( pExpr->eType==FTSQUERY_AND ){
-      fts3EvalTokenCosts(pCsr, pExpr->pLeft, ppTC, pRc);
-      fts3EvalTokenCosts(pCsr, pExpr->pRight, ppTC, pRc);
+    }else if( pExpr->eType!=FTSQUERY_NOT ){
+      if( pExpr->eType==FTSQUERY_OR ){
+        pRoot = pExpr;
+        **ppOr = pExpr;
+        (*ppOr)++;
+      }
+      fts3EvalTokenCosts(pCsr, pRoot, pExpr->pLeft, ppTC, ppOr, pRc);
+      fts3EvalTokenCosts(pCsr, pRoot, pExpr->pRight, ppTC, ppOr, pRc);
     }
   }
 }
@@ -3773,13 +3787,87 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
   return SQLITE_OK;
 }
 
+static int fts3EvalSelectDeferred(
+  Fts3Cursor *pCsr,
+  Fts3Expr *pRoot,
+  Fts3TokenAndCost *aTC,
+  int nTC
+){
+  int nDocSize = 0;
+  int nDocEst = 0;
+  int rc = SQLITE_OK;
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+  int ii;
+
+  int nOvfl = 0;
+  int nTerm = 0;
+
+  for(ii=0; ii<nTC; ii++){
+    if( aTC[ii].pRoot==pRoot ){
+      nOvfl += aTC[ii].nOvfl;
+      nTerm++;
+    }
+  }
+  if( nOvfl==0 || nTerm<2 ) return SQLITE_OK;
+
+  rc = fts3EvalAverageDocsize(pCsr, &nDocSize);
+
+  for(ii=0; ii<nTerm && rc==SQLITE_OK; ii++){
+    int jj;
+    Fts3TokenAndCost *pTC = 0;
+
+    for(jj=0; jj<nTC; jj++){
+      if( aTC[jj].pToken && aTC[jj].pRoot==pRoot 
+       && (!pTC || aTC[jj].nOvfl<pTC->nOvfl) 
+      ){
+        pTC = &aTC[jj];
+      }
+    }
+    assert( pTC );
+
+    /* At this point pTC points to the cheapest remaining token. */
+    if( ii==0 ){
+      if( pTC->nOvfl ){
+        nDocEst = (pTC->nOvfl * pTab->nPgsz + pTab->nPgsz) / 10;
+      }else{
+        /* TODO: Fix this so that the doclist need not be read twice. */
+        Fts3PhraseToken *pToken = pTC->pToken;
+        int nList = 0;
+        char *pList = 0;
+        rc = fts3TermSelect(pTab, pToken, pTC->iCol, 1, &nList, &pList);
+        if( rc==SQLITE_OK ){
+          nDocEst = fts3DoclistCountDocids(1, pList, nList);
+        }
+        sqlite3_free(pList);
+        if( rc==SQLITE_OK ){
+          rc = sqlite3Fts3TermSegReaderCursor(pCsr, 
+              pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr
+          );
+        }
+      }
+    }else{
+      if( pTC->nOvfl>=(nDocEst*nDocSize) ){
+        Fts3PhraseToken *pToken = pTC->pToken;
+        rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol);
+        fts3SegReaderCursorFree(pToken->pSegcsr);
+        pToken->pSegcsr = 0;
+      }
+      nDocEst = 1 + (nDocEst/4);
+    }
+    pTC->pToken = 0;
+  }
+
+  return rc;
+}
+
 int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){
   Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
   int rc = SQLITE_OK;
   int nToken = 0;
+  int nOr = 0;
 
   /* Allocate a MultiSegReader for each token in the expression. */
-  fts3EvalAllocateReaders(pCsr, pExpr, &nToken, &rc);
+  fts3EvalAllocateReaders(pCsr, pExpr, &nToken, &nOr, &rc);
 
   /* Call fts3EvalPhraseStart() on all phrases in the expression. TODO:
   ** This call will eventually also be responsible for determining which
@@ -3799,23 +3887,35 @@ int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){
   **      call. This is known as a "deferred" token.
   */
 
-  /* If bOptOk is true, check if there are any tokens that can be 
-  ** deferred (strategy 3). */
+  /* If bOptOk is true, check if there are any tokens that should be deferred.
+  */
   if( rc==SQLITE_OK && bOptOk && nToken>1 && pTab->bHasStat ){
     Fts3TokenAndCost *aTC;
-    aTC = (Fts3TokenAndCost *)sqlite3_malloc(sizeof(Fts3TokenAndCost) * nToken);
+    Fts3Expr **apOr;
+    aTC = (Fts3TokenAndCost *)sqlite3_malloc(
+        sizeof(Fts3TokenAndCost) * nToken
+      + sizeof(Fts3Expr *) * nOr
+    );
+    apOr = (Fts3Expr **)&aTC[nToken];
+
     if( !aTC ){
       rc = SQLITE_NOMEM;
     }else{
       int ii;
-      int nDocEst = 0;
       int nDocSize;
       Fts3TokenAndCost *pTC = aTC;
+      Fts3Expr **ppOr = apOr;
 
-      rc = fts3EvalAverageDocsize(pCsr, &nDocSize);
-      fts3EvalTokenCosts(pCsr, pExpr, &pTC, &rc);
+      fts3EvalTokenCosts(pCsr, 0, pExpr, &pTC, &ppOr, &rc);
       nToken = pTC-aTC;
+      nOr = ppOr-apOr;
+
+      rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken);
+      for(ii=0; rc==SQLITE_OK && ii<nOr; ii++){
+        rc = fts3EvalSelectDeferred(pCsr, apOr[ii], aTC, nToken);
+      }
 
+#if 0
       for(ii=0; rc==SQLITE_OK && ii<nToken; ii++){
         int jj;
         pTC = 0;
@@ -3826,6 +3926,7 @@ int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){
         }
         assert( pTC );
 
+
         /* At this point pTC points to the cheapest remaining token. */
         if( ii==0 ){
           if( pTC->nOvfl ){
@@ -3857,15 +3958,13 @@ int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){
         }
         pTC->pToken = 0;
       }
+#endif
+
       sqlite3_free(aTC);
     }
   }
 
   fts3EvalStartReaders(pCsr, pExpr, bOptOk, &rc);
-
-  /* Fix the results of NEAR expressions. */
-  fts3EvalNearTrim(pCsr, pExpr, &rc);
-
   return rc;
 }
 
@@ -3878,6 +3977,98 @@ static void fts3EvalFreeDeferredDoclist(Fts3Phrase *pPhrase){
   }
 }
 
+static int fts3EvalNearTrim2(
+  int nNear,
+  char *aTmp,                     /* Temporary space to use */
+  char **paPoslist,               /* IN/OUT: Position list */
+  int *pnToken,                   /* IN/OUT: Tokens in phrase of *paPoslist */
+  Fts3Phrase *pPhrase             /* The phrase object to trim the doclist of */
+){
+  int nParam1 = nNear + pPhrase->nToken;
+  int nParam2 = nNear + *pnToken;
+  char *p2; 
+  char *pOut; 
+  int res;
+
+  p2 = pOut = pPhrase->doclist.pList;
+  res = fts3PoslistNearMerge(
+    &pOut, aTmp, nParam1, nParam2, paPoslist, &p2
+  );
+  pPhrase->doclist.nList = pOut - pPhrase->doclist.pList;
+  *paPoslist = pPhrase->doclist.pList;
+  *pnToken = pPhrase->nToken;
+
+  return res;
+}
+
+static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
+  int res = 1;
+
+  /* The following block runs if pExpr is the root of a NEAR query.
+  ** For example, the query:
+  **
+  **         "w" NEAR "x" NEAR "y" NEAR "z"
+  **
+  ** which is represented in tree form as:
+  **
+  **                               |
+  **                          +--NEAR--+      <-- root of NEAR query
+  **                          |        |
+  **                     +--NEAR--+   "z"
+  **                     |        |
+  **                +--NEAR--+   "y"
+  **                |        |
+  **               "w"      "x"
+  **
+  ** The right-hand child of a NEAR node is always a phrase. The 
+  ** left-hand child may be either a phrase or a NEAR node. There are
+  ** no exceptions to this.
+  */
+  if( *pRc==SQLITE_OK 
+   && pExpr->eType==FTSQUERY_NEAR 
+   && pExpr->bEof==0
+   && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
+  ){
+    Fts3Expr *p; 
+    int nTmp = 0;                 /* Bytes of temp space */
+    char *aTmp;                   /* Temp space for PoslistNearMerge() */
+
+    /* Allocate temporary working space. */
+    for(p=pExpr; p->pLeft; p=p->pLeft){
+      nTmp += p->pRight->pPhrase->doclist.nList;
+    }
+    nTmp += p->pPhrase->doclist.nList;
+    aTmp = sqlite3_malloc(nTmp*2);
+    if( !aTmp ){
+      *pRc = SQLITE_NOMEM;
+      res = 0;
+    }else{
+      char *aPoslist = p->pPhrase->doclist.pList;
+      int nToken = p->pPhrase->nToken;
+
+      for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
+        Fts3Phrase *pPhrase = p->pRight->pPhrase;
+        int nNear = p->nNear;
+        res = fts3EvalNearTrim2(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+      }
+  
+      aPoslist = pExpr->pRight->pPhrase->doclist.pList;
+      nToken = pExpr->pRight->pPhrase->nToken;
+      for(p=pExpr->pLeft; p && res; p=p->pLeft){
+        int nNear = p->pParent->nNear;
+        Fts3Phrase *pPhrase = (
+            p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
+        );
+        res = fts3EvalNearTrim2(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+      }
+    }
+
+    sqlite3_free(aTmp);
+  }
+
+  return res;
+}
+
 /*
 ** This macro is used by the fts3EvalNext() function. The two arguments are
 ** 64-bit docid values. If the current query is "ORDER BY docid ASC", then
@@ -3901,7 +4092,6 @@ static void fts3EvalNext(
       case FTSQUERY_AND: {
         Fts3Expr *pLeft = pExpr->pLeft;
         Fts3Expr *pRight = pExpr->pRight;
-
         assert( !pLeft->bDeferred || !pRight->bDeferred );
         if( pLeft->bDeferred ){
           fts3EvalNext(pCsr, pRight, pRc);
@@ -3924,7 +4114,7 @@ static void fts3EvalNext(
               fts3EvalNext(pCsr, pRight, pRc);
             }
           }
-    
+
           pExpr->iDocid = pLeft->iDocid;
           pExpr->bEof = (pLeft->bEof || pRight->bEof);
         }
@@ -3987,12 +4177,6 @@ static void fts3EvalNext(
         fts3EvalFreeDeferredDoclist(pPhrase);
         *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof);
         pExpr->iDocid = pPhrase->doclist.iDocid;
-#if 0
-        printf("token \"%.*s\" docid=%lld\n", 
-            pPhrase->aToken[0].n, pPhrase->aToken[0].z, pExpr->iDocid
-        );
-#endif
-        
         break;
       }
     }
@@ -4000,7 +4184,7 @@ static void fts3EvalNext(
 }
 
 static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){
-  int bHit = 0;
+  int bHit = 1;
   if( *pRc==SQLITE_OK ){
     switch( pExpr->eType ){
       case FTSQUERY_NEAR:
@@ -4008,15 +4192,40 @@ static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){
         bHit = (
             fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc)
          && fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc)
+         && fts3EvalNearTest(pExpr, pRc)
         );
+
+        /* If this is a NEAR node and the NEAR expression does not match
+        ** any rows, zero the doclist for all phrases involved in the NEAR.
+        ** This is because the snippet(), offsets() and matchinfo() functions
+        ** are not supposed to recognize any instances of phrases that are
+        ** part of unmatched NEAR queries. For example if this expression:
+        **
+        **    ... MATCH 'a OR (b NEAR c)'
+        **
+        ** is matched against a row containing:
+        **
+        **        'a b d e'
+        **
+        ** then any snippet() should ony highlight the "a" term, not the "b"
+        ** (as "b" is part of a non-matching NEAR clause).
+        */
+        if( pExpr->eType==FTSQUERY_NEAR && bHit==0 ){
+          Fts3Expr *p;
+          for(p=pExpr; p->pPhrase==0; p=p->pLeft){
+            p->pRight->pPhrase->doclist.pList = 0;
+          }
+          p->pPhrase->doclist.pList = 0;
+        }
+
         break;
 
-      case FTSQUERY_OR:
-        bHit = (
-            fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc)
-         || fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc)
-        );
+      case FTSQUERY_OR: {
+        int bHit1 = fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc);
+        int bHit2 = fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc);
+        bHit = bHit1 || bHit2;
         break;
+      }
 
       case FTSQUERY_NOT:
         bHit = (
@@ -4026,11 +4235,15 @@ static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){
         break;
 
       default: {
-        Fts3Phrase *pPhrase = pExpr->pPhrase;
-        fts3EvalFreeDeferredDoclist(pPhrase);
-        *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase);
-        bHit = (pPhrase->doclist.pList!=0);
-        pExpr->iDocid = pCsr->iPrevId;
+        if( pCsr->pDeferred ){
+          Fts3Phrase *pPhrase = pExpr->pPhrase;
+          fts3EvalFreeDeferredDoclist(pPhrase);
+          *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase);
+          bHit = (pPhrase->doclist.pList!=0);
+          pExpr->iDocid = pCsr->iPrevId;
+        }else{
+          bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId);
+        }
         break;
       }
     }
@@ -4052,11 +4265,12 @@ static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){
 static int fts3EvalLoadDeferred(Fts3Cursor *pCsr, int *pRc){
   int rc = *pRc;
   int bMiss = 0;
-  if( rc==SQLITE_OK && pCsr->pDeferred ){
-    rc = fts3CursorSeek(0, pCsr);
-    if( rc==SQLITE_OK ){
-      sqlite3Fts3FreeDeferredDoclists(pCsr);
-      rc = sqlite3Fts3CacheDeferredDoclists(pCsr);
+  if( rc==SQLITE_OK ){
+    if( pCsr->pDeferred ){
+      rc = fts3CursorSeek(0, pCsr);
+      if( rc==SQLITE_OK ){
+        rc = sqlite3Fts3CacheDeferredDoclists(pCsr);
+      }
     }
     bMiss = (0==fts3EvalDeferredTest(pCsr, pCsr->pExpr, &rc));
     sqlite3Fts3FreeDeferredDoclists(pCsr);
@@ -4151,6 +4365,13 @@ int sqlite3Fts3EvalPhraseDoclist(
     }
   }
 
+  if( rc==SQLITE_OK 
+   && pExpr->pParent 
+   && pExpr->pParent->eType==FTSQUERY_NEAR 
+  ){
+
+  }
+
   *pnList = pPhrase->doclist.nAll;
   *ppList = pPhrase->doclist.aAll;
   return rc;
index 8000db4360d864afbdb4cee804d27df265bc27c2..a97b87491f830cb53fe524652f0b98fd10d8d1a2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\sthe\slatest\strunk\schanges\sinto\sthe\sfts3-prefix-search\sbranch.
-D 2011-06-06T18:14:25.721
+C Have\sNEAR\squeries\suse\sincremental\smerging.\sFix\sissues\ssurrounding\sthe\sdeferred\stoken\soptimization.
+D 2011-06-07T18:35:45.780
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -61,7 +61,7 @@ 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 d0970d9fa0a63ac470007ac5e14645f5b874b70f
+F ext/fts3/fts3.c 9d2d2cab4d64f0769046d88b6740c6e1f229d1e3
 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
 F ext/fts3/fts3Int.h d76b021d5b7061eff7aa4055b5938eebef2bdb6a
 F ext/fts3/fts3_aux.c baed9dab7fb4604ae8cafdb2d7700abe93beffbe
@@ -464,14 +464,14 @@ F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
 F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
 F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
 F test/fts3defer.test 7c8a38d5f617d7b52ae1c43ed73c536e7e895a35
-F test/fts3defer2.test 288bef6de15557319b8c12d476ebdc83688ef96c
+F test/fts3defer2.test ad5bd3ae616fb719eb06b0a73eb5c8fb1c411989
 F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
 F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
 F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
 F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
 F test/fts3fault2.test dc96203af6ba31ce20163fc35460e1556e8edf4d
 F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b
-F test/fts3matchinfo.test cc0b009edbbf575283d5fdb53271179e0d8019ba
+F test/fts3matchinfo.test f424597b6843659ecbc2009e8823380233ebf375
 F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
 F test/fts3prefix.test 36246609111ec1683f7ea5ed27666ce2cefb5676
 F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2
@@ -943,7 +943,7 @@ F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
 F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d
-P 89f2f482e077241ac29a58eadf44a72a9c01f98c 98ccfa930e8e5f10808a518e3e22e85e8a8a65c2
-R b612d83743a894702aacbc42c433c9e9
-U drh
-Z c6414e08a953b76b4b33ed29bc763b72
+P 567dd84359218245d4e6887547e2a48881f2c8e0
+R 020efe4a51ef4472e0e5c3f4175d0de6
+U dan
+Z 740d1ddba83232619fca71041707ab60
index 577710ac6fdd1af463d6fbde8dca852bc6d26a5f..4da09088b83b82e886ee92a4b520cfccbc5a7d27 100644 (file)
@@ -1 +1 @@
-567dd84359218245d4e6887547e2a48881f2c8e0
\ No newline at end of file
+9d10a6846b12a9cc8fd4fdc3affd931a27218b5a
\ No newline at end of file
index 844180330042945198c7a231b473bb54fc6beea2..b7bf9235509bdf7bc50565edf30764e9a042a383 100644 (file)
@@ -48,17 +48,22 @@ do_execsql_test 1.1.4 {
   UPDATE t1_segments SET block = zeroblob(length(block)) WHERE length(block)>10000;
 } {2}
 
+do_execsql_test 1.2.0 {
+  SELECT content FROM t1 WHERE t1 MATCH 'f (e a)';
+} {{a b c d e f a x y}}
+
 do_execsql_test 1.2.1 {
   SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
 } {{a b c d e f a x y}}
 
+breakpoint
 do_execsql_test 1.2.2 {
   SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1, 'pcxnal'))
   FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
 } [list                              \
    {a b c d [e] [f] [a] x y}         \
    {0 1 8 1 0 0 10 1 0 2 12 1}       \
-   [list 3 1   1 1 1   1 8 8   1 8 8   8 5001 9]
+   [list 3 1   1 1 1   1 1 1   1 8 8   8 5001 9]
 ]
 
 do_execsql_test 1.2.3 {
@@ -67,7 +72,7 @@ do_execsql_test 1.2.3 {
 } [list                                 \
    {[a] b c d [e] [f] [a] x y}          \
    {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1}  \
-   [list 3 1   1 1 1   1 8 8   2 8 8   8 5001 9]
+   [list 3 1   1 1 1   1 1 1   2 8 8   8 5001 9]
 ]
 
 do_execsql_test 1.3.1 { DROP TABLE t1 }
@@ -99,8 +104,14 @@ foreach {tn sql} {
     [list 2 1  1 54 54  1 3 3  54 372 7]        \
   ]
 
-  set sqlite_fts3_enable_parentheses 1
   do_execsql_test 2.2.$tn.2 {
+    SELECT mit(matchinfo(t2, 'x')) FROM t2 WHERE t2 MATCH 'g z';
+  } [list                                       \
+    [list 1 2 2  1 54 54]                       \
+  ]
+
+  set sqlite_fts3_enable_parentheses 1
+  do_execsql_test 2.2.$tn.3 {
     SELECT mit(matchinfo(t2, 'x')) FROM t2 WHERE t2 MATCH 'g OR (g z)';
   } [list                                       \
     [list 1 2 2  1 2 2   1 54 54]               \
index 8f194e72cb38f078472393041643557474b4dca5..e26bcf105221ad950ead18c184ebb999f0401cb8 100644 (file)
@@ -68,7 +68,11 @@ do_execsql_test 3.1 {
 
 do_execsql_test 3.2 {
   CREATE VIRTUAL TABLE xx USING FTS4;
+}
+do_execsql_test 3.3 {
   SELECT * FROM xx WHERE xx MATCH 'abc';
+}
+do_execsql_test 3.4 {
   SELECT * FROM xx WHERE xx MATCH 'a b c';
 }