]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further tweaks to improve fts5 prefix query performance.
authordan <dan@noemail.net>
Mon, 12 Oct 2015 19:12:29 +0000 (19:12 +0000)
committerdan <dan@noemail.net>
Mon, 12 Oct 2015 19:12:29 +0000 (19:12 +0000)
FossilOrigin-Name: 1c20c1c28b56411f106cf2f6961b3ad4b4d6f6c8

ext/fts5/fts5Int.h
ext/fts5/fts5_buffer.c
ext/fts5/fts5_expr.c
ext/fts5/fts5_index.c
ext/fts5/fts5_main.c
ext/fts5/fts5_vocab.c
ext/fts5/test/fts5simple.test
manifest
manifest.uuid

index ce066f2aa8b2fa39b21da1ed1108b4167014f712..3671da1f125f7fb5bd4e47e6f241863b6536d9a5 100644 (file)
@@ -254,7 +254,6 @@ int sqlite3Fts5Get32(const u8*);
 typedef struct Fts5PoslistReader Fts5PoslistReader;
 struct Fts5PoslistReader {
   /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */
-  int iCol;                       /* If (iCol>=0), this column only */
   const u8 *a;                    /* Position list to iterate through */
   int n;                          /* Size of buffer at a[] in bytes */
   int i;                          /* Current offset in a[] */
@@ -266,7 +265,6 @@ struct Fts5PoslistReader {
   i64 iPos;                       /* (iCol<<32) + iPos */
 };
 int sqlite3Fts5PoslistReaderInit(
-  int iCol,                       /* If (iCol>=0), this column only */
   const u8 *a, int n,             /* Poslist buffer to iterate through */
   Fts5PoslistReader *pIter        /* Iterator object to initialize */
 );
@@ -347,7 +345,7 @@ int sqlite3Fts5IterEof(Fts5IndexIter*);
 int sqlite3Fts5IterNext(Fts5IndexIter*);
 int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
 i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
-int sqlite3Fts5IterPoslist(Fts5IndexIter*, const u8 **pp, int *pn, i64 *pi);
+int sqlite3Fts5IterPoslist(Fts5IndexIter*,Fts5Colset*, const u8**, int*, i64*);
 int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf);
 
 /*
index e7e8d6d663c4bef65f864a7d4a818e9061931c83..68f24bf18b6040047e31fd4933811a793758494e 100644 (file)
@@ -203,26 +203,20 @@ int sqlite3Fts5PoslistNext64(
 ** if the iterator reaches EOF, or false otherwise.
 */
 int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){
-  if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) 
-   || (pIter->iCol>=0 && (pIter->iPos >> 32) > pIter->iCol)
-  ){
+  if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) ){
     pIter->bEof = 1;
   }
   return pIter->bEof;
 }
 
 int sqlite3Fts5PoslistReaderInit(
-  int iCol,                       /* If (iCol>=0), this column only */
   const u8 *a, int n,             /* Poslist buffer to iterate through */
   Fts5PoslistReader *pIter        /* Iterator object to initialize */
 ){
   memset(pIter, 0, sizeof(*pIter));
   pIter->a = a;
   pIter->n = n;
-  pIter->iCol = iCol;
-  do {
-    sqlite3Fts5PoslistReaderNext(pIter);
-  }while( pIter->bEof==0 && (pIter->iPos >> 32)<iCol );
+  sqlite3Fts5PoslistReaderNext(pIter);
   return pIter->bEof;
 }
 
index 02351478a0dd1500231db413767207f75713d41e..a8a8363a4ee6f437225c578cd68bc12ccae75117 100644 (file)
@@ -309,6 +309,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
 */
 static int fts5ExprSynonymPoslist(
   Fts5ExprTerm *pTerm, 
+  Fts5Colset *pColset,
   i64 iRowid,
   int *pbDel,                     /* OUT: Caller should sqlite3_free(*pa) */
   u8 **pa, int *pn
@@ -327,7 +328,7 @@ static int fts5ExprSynonymPoslist(
       const u8 *a;
       int n;
       i64 dummy;
-      rc = sqlite3Fts5IterPoslist(pIter, &a, &n, &dummy);
+      rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
       if( rc!=SQLITE_OK ) goto synonym_poslist_out;
       if( nIter==nAlloc ){
         int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
@@ -341,7 +342,7 @@ static int fts5ExprSynonymPoslist(
         if( aIter!=aStatic ) sqlite3_free(aIter);
         aIter = aNew;
       }
-      sqlite3Fts5PoslistReaderInit(-1, a, n, &aIter[nIter]);
+      sqlite3Fts5PoslistReaderInit(a, n, &aIter[nIter]);
       assert( aIter[nIter].bEof==0 );
       nIter++;
     }
@@ -409,13 +410,7 @@ static int fts5ExprPhraseIsMatch(
   Fts5PoslistReader *aIter = aStatic;
   int i;
   int rc = SQLITE_OK;
-  int iCol = -1;
   
-  if( pColset && pColset->nCol==1 ){
-    iCol = pColset->aiCol[0];
-    pColset = 0;
-  }
-
   fts5BufferZero(&pPhrase->poslist);
 
   /* If the aStatic[] array is not large enough, allocate a large array
@@ -435,12 +430,14 @@ static int fts5ExprPhraseIsMatch(
     int bFlag = 0;
     const u8 *a = 0;
     if( pTerm->pSynonym ){
-      rc = fts5ExprSynonymPoslist(pTerm, pNode->iRowid, &bFlag, (u8**)&a, &n);
+      rc = fts5ExprSynonymPoslist(
+          pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
+      );
     }else{
-      rc = sqlite3Fts5IterPoslist(pTerm->pIter, &a, &n, &dummy);
+      rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
     }
     if( rc!=SQLITE_OK ) goto ismatch_out;
-    sqlite3Fts5PoslistReaderInit(iCol, a, n, &aIter[i]);
+    sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
     aIter[i].bFlag = bFlag;
     if( aIter[i].bEof ) goto ismatch_out;
   }
@@ -463,11 +460,9 @@ static int fts5ExprPhraseIsMatch(
       }
     }while( bMatch==0 );
 
-    if( pColset==0 || fts5ExprColsetTest(pColset, FTS5_POS2COLUMN(iPos)) ){
-      /* Append position iPos to the output */
-      rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
-      if( rc!=SQLITE_OK ) goto ismatch_out;
-    }
+    /* Append position iPos to the output */
+    rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
+    if( rc!=SQLITE_OK ) goto ismatch_out;
 
     for(i=0; i<pPhrase->nTerm; i++){
       if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
@@ -762,61 +757,6 @@ static int fts5ExprSynonymAdvanceto(
   return bEof;
 }
 
-/*
-** IN/OUT parameter (*pa) points to a position list n bytes in size. If
-** the position list contains entries for column iCol, then (*pa) is set
-** to point to the sub-position-list for that column and the number of
-** bytes in it returned. Or, if the argument position list does not
-** contain any entries for column iCol, return 0.
-*/
-static int fts5ExprExtractCol(
-  const u8 **pa,                  /* IN/OUT: Pointer to poslist */
-  int n,                          /* IN: Size of poslist in bytes */
-  int iCol                        /* Column to extract from poslist */
-){
-  int iCurrent = 0;
-  const u8 *p = *pa;
-  const u8 *pEnd = &p[n];         /* One byte past end of position list */
-  u8 prev = 0;
-
-  while( iCol!=iCurrent ){
-    /* Advance pointer p until it points to pEnd or an 0x01 byte that is
-    ** not part of a varint */
-    while( (prev & 0x80) || *p!=0x01 ){
-      prev = *p++;
-      if( p==pEnd ) return 0;
-    }
-    *pa = p++;
-    p += fts5GetVarint32(p, iCurrent);
-  }
-
-  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
-  ** not part of a varint */
-  assert( (prev & 0x80)==0 );
-  while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){
-    prev = *p++;
-  }
-  return p - (*pa);
-}
-
-static int fts5ExprExtractColset (
-  Fts5Colset *pColset,            /* Colset to filter on */
-  const u8 *pPos, int nPos,       /* Position list */
-  Fts5Buffer *pBuf                /* Output buffer */
-){
-  int rc = SQLITE_OK;
-  int i;
-
-  fts5BufferZero(pBuf);
-  for(i=0; i<pColset->nCol; i++){
-    const u8 *pSub = pPos;
-    int nSub = fts5ExprExtractCol(&pSub, nPos, pColset->aiCol[i]);
-    if( nSub ){
-      fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
-    }
-  }
-  return rc;
-}
 
 static int fts5ExprNearTest(
   int *pRc,
@@ -864,34 +804,15 @@ static int fts5ExprTokenTest(
   Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
   Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
   Fts5Colset *pColset = pNear->pColset;
-  const u8 *pPos;
-  int nPos;
   int rc;
 
   assert( pNode->eType==FTS5_TERM );
   assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
   assert( pPhrase->aTerm[0].pSynonym==0 );
 
-  rc = sqlite3Fts5IterPoslist(pIter, &pPos, &nPos, &pNode->iRowid);
-
-  /* If the term may match any column, then this must be a match. 
-  ** Return immediately in this case. Otherwise, try to find the
-  ** part of the poslist that corresponds to the required column.
-  ** If it can be found, return. If it cannot, the next iteration
-  ** of the loop will test the next rowid in the database for this
-  ** term.  */
-  if( pColset==0 ){
-    assert( pPhrase->poslist.nSpace==0 );
-    pPhrase->poslist.p = (u8*)pPos;
-    pPhrase->poslist.n = nPos;
-  }else if( pColset->nCol==1 ){
-    assert( pPhrase->poslist.nSpace==0 );
-    pPhrase->poslist.n = fts5ExprExtractCol(&pPos, nPos, pColset->aiCol[0]);
-    pPhrase->poslist.p = (u8*)pPos;
-  }else if( rc==SQLITE_OK ){
-    rc = fts5ExprExtractColset(pColset, pPos, nPos, &pPhrase->poslist);
-  }
-
+  rc = sqlite3Fts5IterPoslist(pIter, pColset, 
+      (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
+  );
   pNode->bNomatch = (pPhrase->poslist.n==0);
   return rc;
 }
index ec9ed3b9218de4297cf40455fdbcd9503d51e5bb..6c731432fe48864a4d0817fb14a78dd958346c5c 100644 (file)
@@ -511,8 +511,9 @@ struct Fts5IndexIter {
 
   int nSeg;                       /* Size of aSeg[] array */
   int bRev;                       /* True to iterate in reverse order */
-  int bSkipEmpty;                 /* True to skip deleted entries */
-  int bEof;                       /* True at EOF */
+  u8 bSkipEmpty;                  /* True to skip deleted entries */
+  u8 bEof;                        /* True at EOF */
+  u8 bFiltered;                   /* True if column-filter already applied */
 
   i64 iSwitchRowid;               /* Firstest rowid of other than aFirst[1] */
   Fts5CResult *aFirst;            /* Current merge state (see above) */
@@ -1457,7 +1458,8 @@ static void fts5SegIterNextPage(
 */
 static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
   int nSz;
-  int n = fts5GetVarint32(p, nSz);
+  int n = 0;
+  fts5FastGetVarint32(p, n, nSz);
   assert_nc( nSz>=0 );
   *pnSz = nSz/2;
   *pbDel = nSz & 0x0001;
@@ -1478,13 +1480,12 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
 static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
   if( p->rc==SQLITE_OK ){
     int iOff = pIter->iLeafOffset;  /* Offset to read at */
+    int nSz;
     ASSERT_SZLEAF_OK(pIter->pLeaf);
-    if( iOff>=pIter->pLeaf->szLeaf ){
-      p->rc = FTS5_CORRUPT;
-    }else{
-      const u8 *a = &pIter->pLeaf->p[iOff];
-      pIter->iLeafOffset += fts5GetPoslistSize(a, &pIter->nPos, &pIter->bDel);
-    }
+    fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
+    pIter->bDel = (nSz & 0x0001);
+    pIter->nPos = nSz>>1;
+    pIter->iLeafOffset = iOff;
   }
 }
 
@@ -2725,6 +2726,7 @@ static void fts5MultiIterNew2(
   if( pNew ){
     Fts5SegIter *pIter = &pNew->aSeg[1];
 
+    pNew->bFiltered = 1;
     pIter->flags = FTS5_SEGITER_ONETERM;
     if( pData->szLeaf>0 ){
       pIter->pLeaf = pData;
@@ -3940,7 +3942,7 @@ static void fts5PoslistCallback(
 ){
   assert_nc( nChunk>=0 );
   if( nChunk>0 ){
-    fts5BufferAppendBlob(&p->rc, (Fts5Buffer*)pContext, nChunk, pChunk);
+    fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
   }
 }
 
@@ -3980,7 +3982,7 @@ static void fts5PoslistFilterCallback(
       fts5FastGetVarint32(pChunk, i, iCol);
       if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
         pCtx->eState = 1;
-        fts5BufferAppendVarint(&p->rc, pCtx->pBuf, 1);
+        fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
       }else{
         pCtx->eState = 0;
       }
@@ -3992,7 +3994,7 @@ static void fts5PoslistFilterCallback(
         i++;
       }
       if( pCtx->eState ){
-        fts5BufferAppendBlob(&p->rc, pCtx->pBuf, i-iStart, &pChunk[iStart]);
+        fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
       }
       if( i<nChunk ){
         int iCol;
@@ -4004,7 +4006,7 @@ static void fts5PoslistFilterCallback(
           fts5FastGetVarint32(pChunk, i, iCol);
           pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
           if( pCtx->eState ){
-            fts5BufferAppendBlob(&p->rc, pCtx->pBuf, i-iStart, &pChunk[iStart]);
+            fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
             iStart = i;
           }
         }
@@ -4025,56 +4027,123 @@ static void fts5SegiterPoslist(
   Fts5Colset *pColset,
   Fts5Buffer *pBuf
 ){
-  if( pColset==0 ){
-    fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
-  }else{
-    PoslistCallbackCtx sCtx;
-    sCtx.pBuf = pBuf;
-    sCtx.pColset = pColset;
-    sCtx.eState = pColset ? fts5IndexColsetTest(pColset, 0) : 1;
-    assert( sCtx.eState==0 || sCtx.eState==1 );
-    fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
+  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
+    if( pColset==0 ){
+      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
+    }else{
+      PoslistCallbackCtx sCtx;
+      sCtx.pBuf = pBuf;
+      sCtx.pColset = pColset;
+      sCtx.eState = pColset ? fts5IndexColsetTest(pColset, 0) : 1;
+      assert( sCtx.eState==0 || sCtx.eState==1 );
+      fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
+    }
+  }
+}
+
+/*
+** IN/OUT parameter (*pa) points to a position list n bytes in size. If
+** the position list contains entries for column iCol, then (*pa) is set
+** to point to the sub-position-list for that column and the number of
+** bytes in it returned. Or, if the argument position list does not
+** contain any entries for column iCol, return 0.
+*/
+static int fts5IndexExtractCol(
+  const u8 **pa,                  /* IN/OUT: Pointer to poslist */
+  int n,                          /* IN: Size of poslist in bytes */
+  int iCol                        /* Column to extract from poslist */
+){
+  int iCurrent = 0;               /* Anything before the first 0x01 is col 0 */
+  const u8 *p = *pa;
+  const u8 *pEnd = &p[n];         /* One byte past end of position list */
+  u8 prev = 0;
+
+  while( iCol!=iCurrent ){
+    /* Advance pointer p until it points to pEnd or an 0x01 byte that is
+    ** not part of a varint */
+    while( (prev & 0x80) || *p!=0x01 ){
+      prev = *p++;
+      if( p==pEnd ) return 0;
+    }
+    *pa = p++;
+    p += fts5GetVarint32(p, iCurrent);
+  }
+
+  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
+  ** not part of a varint */
+  assert( (prev & 0x80)==0 );
+  while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){
+    prev = *p++;
   }
+  return p - (*pa);
 }
 
+
 /*
 ** Iterator pMulti currently points to a valid entry (not EOF). This
-** function appends a copy of the position-list of the entry pMulti 
-** currently points to to buffer pBuf.
+** function appends the following to buffer pBuf:
+**
+**   * The varint iDelta, and
+**   * the position list that currently points to, including the size field.
+**
+** If argument pColset is NULL, then the position list is filtered according
+** to pColset before being appended to the buffer. If this means there are
+** no entries in the position list, nothing is appended to the buffer (not
+** even iDelta).
 **
-** If an error occurs, an error code is left in p->rc. It is assumed
-** no error has already occurred when this function is called.
+** If an error occurs, an error code is left in p->rc. 
 */
-static int fts5MultiIterPoslist(
+static int fts5AppendPoslist(
   Fts5Index *p,
+  i64 iDelta,
   Fts5IndexIter *pMulti,
   Fts5Colset *pColset,
   Fts5Buffer *pBuf
 ){
   if( p->rc==SQLITE_OK ){
-    int iSz;
-    int iData;
-
     Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
     assert( fts5MultiIterEof(p, pMulti)==0 );
-
-    /* WRITEPOSLISTSIZE */
-    iSz = pBuf->n;
-    fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2);
-    iData = pBuf->n;
-
-    fts5SegiterPoslist(p, pSeg, pColset, pBuf);
-
-    if( pColset ){
-      int nActual = pBuf->n - iData;
-      if( nActual!=pSeg->nPos ){
-        /* WRITEPOSLISTSIZE */
-        if( nActual==0 ){
-          return 1;
+    assert( pSeg->nPos>0 );
+    if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
+      int iSv1;
+      int iSv2;
+      int iData;
+
+      /* Append iDelta */
+      iSv1 = pBuf->n;
+      fts5BufferSafeAppendVarint(pBuf, iDelta);
+
+      /* WRITEPOSLISTSIZE */
+      iSv2 = pBuf->n;
+      fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2);
+      iData = pBuf->n;
+
+      if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf 
+       && (pColset==0 || pColset->nCol==1)
+      ){
+        const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
+        int nPos;
+        if( pColset ){
+          nPos = fts5IndexExtractCol(&pPos, pSeg->nPos, pColset->aiCol[0]);
         }else{
-          int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2));
-          while( iSz<(iData-nReq) ){ pBuf->p[iSz++] = 0x80; }
-          sqlite3Fts5PutVarint(&pBuf->p[iSz], nActual*2);
+          nPos = pSeg->nPos;
+        }
+        fts5BufferSafeAppendBlob(pBuf, pPos, nPos);
+      }else{
+        fts5SegiterPoslist(p, pSeg, pColset, pBuf);
+      }
+
+      if( pColset ){
+        int nActual = pBuf->n - iData;
+        if( nActual!=pSeg->nPos ){
+          if( nActual==0 ){
+            pBuf->n = iSv1;
+            return 1;
+          }else{
+            int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2));
+            while( iSv2<(iData-nReq) ){ pBuf->p[iSv2++] = 0x80; }
+            sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
+          }
         }
       }
     }
@@ -4282,15 +4351,8 @@ static void fts5SetupPrefixIter(
         iLastRowid = 0;
       }
 
-      if( 0==sqlite3Fts5BufferGrow(&p->rc, &doclist, 9) ){
-        int iSave = doclist.n;
-        assert( doclist.n!=0 || iLastRowid==0 );
-        fts5BufferSafeAppendVarint(&doclist, iRowid - iLastRowid);
-        if( fts5MultiIterPoslist(p, p1, pColset, &doclist) ){
-          doclist.n = iSave;
-        }else{
-          iLastRowid = iRowid;
-        }
+      if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
+        iLastRowid = iRowid;
       }
     }
 
@@ -4648,6 +4710,26 @@ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){
 }
 
 
+static int fts5IndexExtractColset (
+  Fts5Colset *pColset,            /* Colset to filter on */
+  const u8 *pPos, int nPos,       /* Position list */
+  Fts5Buffer *pBuf                /* Output buffer */
+){
+  int rc = SQLITE_OK;
+  int i;
+
+  fts5BufferZero(pBuf);
+  for(i=0; i<pColset->nCol; i++){
+    const u8 *pSub = pPos;
+    int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
+    if( nSub ){
+      fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
+    }
+  }
+  return rc;
+}
+
+
 /*
 ** Return a pointer to a buffer containing a copy of the position list for
 ** the current entry. Output variable *pn is set to the size of the buffer 
@@ -4658,6 +4740,7 @@ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){
 */
 int sqlite3Fts5IterPoslist(
   Fts5IndexIter *pIter, 
+  Fts5Colset *pColset,            /* Column filter (or NULL) */
   const u8 **pp,                  /* OUT: Pointer to position-list data */
   int *pn,                        /* OUT: Size of position-list in bytes */
   i64 *piRowid                    /* OUT: Current rowid */
@@ -4665,13 +4748,25 @@ int sqlite3Fts5IterPoslist(
   Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
   assert( pIter->pIndex->rc==SQLITE_OK );
   *piRowid = pSeg->iRowid;
-  *pn = pSeg->nPos;
-  if( pSeg->iLeafOffset+pSeg->nPos <= pSeg->pLeaf->szLeaf ){
-    *pp = &pSeg->pLeaf->p[pSeg->iLeafOffset];
+  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
+    u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
+    if( pColset==0 || pIter->bFiltered ){
+      *pn = pSeg->nPos;
+      *pp = pPos;
+    }else if( pColset->nCol==1 ){
+      *pp = pPos;
+      *pn = fts5IndexExtractCol(pp, pSeg->nPos, pColset->aiCol[0]);
+    }else{
+      fts5BufferZero(&pIter->poslist);
+      fts5IndexExtractColset(pColset, pPos, pSeg->nPos, &pIter->poslist);
+      *pp = pIter->poslist.p;
+      *pn = pIter->poslist.n;
+    }
   }else{
     fts5BufferZero(&pIter->poslist);
-    fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist);
+    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
     *pp = pIter->poslist.p;
+    *pn = pIter->poslist.n;
   }
   return fts5IndexReturn(pIter->pIndex);
 }
@@ -4868,10 +4963,10 @@ static int fts5QueryCksum(
     const u8 *pPos;
     int nPos;
     i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
-    rc = sqlite3Fts5IterPoslist(pIdxIter, &pPos, &nPos, &dummy);
+    rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy);
     if( rc==SQLITE_OK ){
       Fts5PoslistReader sReader;
-      for(sqlite3Fts5PoslistReaderInit(-1, pPos, nPos, &sReader);
+      for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader);
           sReader.bEof==0;
           sqlite3Fts5PoslistReaderNext(&sReader)
       ){
index c2a37171ec01a03c0940a4dd6a1dd5b87eea9221..eba8a6cbce06541a2f875070944d012e9a0ca6e9 100644 (file)
@@ -1643,7 +1643,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
     for(i=0; i<nIter; i++){
       const u8 *a;
       int n = fts5CsrPoslist(pCsr, i, &a);
-      sqlite3Fts5PoslistReaderInit(-1, a, n, &aIter[i]);
+      sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
     }
 
     while( 1 ){
index 1f80adc372b8704527815b911b65cb1678849623..21b09448b1b65b3e9048d571451effa57b51a57a 100644 (file)
@@ -349,7 +349,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
         i64 iPos = 0;               /* 64-bit position read from poslist */
         int iOff = 0;               /* Current offset within position list */
 
-        rc = sqlite3Fts5IterPoslist(pCsr->pIter, &pPos, &nPos, &dummy);
+        rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
         if( rc==SQLITE_OK ){
           if( pTab->eType==FTS5_VOCAB_ROW ){
             while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
index 67fc494435cc65db61145ed3f1a9b890b48d0223..9175e420a21774487122d7c9f2a7d286944ea82c 100644 (file)
@@ -251,6 +251,10 @@ do_execsql_test 10.1 {
   SELECT rowid FROM t3('c: c*');
 } {2}
 
+do_execsql_test 10.2 {
+  SELECT rowid FROM t3('b: acb');
+} {2}
+
 #-------------------------------------------------------------------------
 # Test that character 0x1A is allowed in fts5 barewords.
 #
@@ -281,6 +285,20 @@ do_test 11.5 {
   catchsql "SELECT rowid FROM t4('d\x19')"
 } {/fts5: syntax error/}
 
+#-------------------------------------------------------------------------
+#
+do_test 12.1 {
+  execsql {
+    CREATE VIRTUAL TABLE xx USING fts5(x,y);
+    BEGIN;
+      INSERT INTO xx VALUES('1 2 3', 'a b c');
+  }
+} {}
+
+do_execsql_test 12.2 {
+  SELECT rowid FROM xx('x:a');
+  COMMIT;
+} {}
 
 finish_test
 
index 3e2bd9208d77c85e57327578111c055a72f6ac9c..534a14bd88162760a795870533d967edcad536e9 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Change\sall\sreferences\sto\s3.8.12\sinto\s3.9.0.\s\sComment\schanges\sonly\s-\sno\nchanges\sto\scode.
-D 2015-10-12T04:56:12.349
+C Further\stweaks\sto\simprove\sfts5\sprefix\squery\sperformance.
+D 2015-10-12T19:12:29.091
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in f0088ff0d2ac949fce6de7c00f13a99ac5bdb663
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -106,21 +106,21 @@ F ext/fts3/unicode/mkunicode.tcl 95cf7ec186e48d4985e433ff8a1c89090a774252
 F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
 F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
 F ext/fts5/fts5.h 98f802fe41481f9d797fce496f0fefcad72c7782
-F ext/fts5/fts5Int.h ed6c05b803e0bacf85228a8d255853e89796f6f5
+F ext/fts5/fts5Int.h 38667e39859ff3f3bc91f47efe672023a145a118
 F ext/fts5/fts5_aux.c b09aa27dcdaa3d50a30be433fddaa48a50aa827b
-F ext/fts5/fts5_buffer.c b2fb69c1ee3378956c0d9ee964d61b59d296afaf
+F ext/fts5/fts5_buffer.c e99224a316cc5b2c574ccccdc7f2344bca54784d
 F ext/fts5/fts5_config.c 57ee5fe71578cb494574fc0e6e51acb9a22a8695
-F ext/fts5/fts5_expr.c 1df899afed24c9c6195eea1780dcc56fcd1d1139
+F ext/fts5/fts5_expr.c 17a945210cbc0cd29f03a87fd30ab7bf994ed16c
 F ext/fts5/fts5_hash.c 4bf4b99708848357b8a2b5819e509eb6d3df9246
-F ext/fts5/fts5_index.c e03217c37f344f79673be385de6b03f732291000
-F ext/fts5/fts5_main.c 36fa4fe8b80ba5d596fa6afb910d195f148fd9d2
+F ext/fts5/fts5_index.c f73968357818455039ecb79dcd4b082c3baaeaeb
+F ext/fts5/fts5_main.c bf43550b8e9a68514abd179500f1917a2256cd7a
 F ext/fts5/fts5_storage.c df061a5caf9e50fbbd43113009b5b248362f4995
 F ext/fts5/fts5_tcl.c 3bf445e66de32137d4693694ff7b1fd6074e32bd
 F ext/fts5/fts5_test_mi.c e96be827aa8f571031e65e481251dc1981d608bf
 F ext/fts5/fts5_tokenize.c f380f46f341af9c9a9908e1aade685ba1eaa157a
 F ext/fts5/fts5_unicode2.c 78273fbd588d1d9bd0a7e4e0ccc9207348bae33c
 F ext/fts5/fts5_varint.c 3f86ce09cab152e3d45490d7586b7ed2e40c13f1
-F ext/fts5/fts5_vocab.c 17320c476a5296ee475ab616d95fd10515bacfec
+F ext/fts5/fts5_vocab.c a05027ab6abb692ad27654c85137a4f1061a159e
 F ext/fts5/fts5parse.y e83dca6028e3309178d05b5bd920e372dc295d35
 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
 F ext/fts5/test/fts5_common.tcl 51f7ef3af444b89c6f6ce3896a0ac349ff4e996d
@@ -175,7 +175,7 @@ F ext/fts5/test/fts5rank.test 11dcebba31d822f7e99685b4ea2c2ae3ec0b16f1
 F ext/fts5/test/fts5rebuild.test 03935f617ace91ed23a6099c7c74d905227ff29b
 F ext/fts5/test/fts5restart.test c17728fdea26e7d0f617d22ad5b4b2862b994c17
 F ext/fts5/test/fts5rowid.test 400384798349d658eaf06aefa1e364957d5d4821
-F ext/fts5/test/fts5simple.test 85bbb268e01d2e3527d70a7fa511ddc3bba2ccc0
+F ext/fts5/test/fts5simple.test f8463172dc2d4bf9f74c78e9df9c83e942c63a94
 F ext/fts5/test/fts5synonym.test cf88c0a56d5ea9591e3939ef1f6e294f7f2d0671
 F ext/fts5/test/fts5tokenizer.test ea4df698b35cc427ebf2ba22829d0e28386d8c89
 F ext/fts5/test/fts5unicode.test fbef8d8a3b4b88470536cc57604a82ca52e51841
@@ -1390,7 +1390,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 9ab9c8c6d747647f8ade58c2c4812fc69a813368
-R 84edb3e7271e5a0e0aa256262a048c3a
-U drh
-Z 934ebb8a1ac47019300027e32a36b72c
+P 6f2858f6817ca70c132f0437ac2f0f74deb273d2
+R 648c7563956f80fd03a6301b24b597df
+U dan
+Z 3852831c6b0a26fcaca66c9a24d96d73
index f2eda9b02dd356cbd19ed79ea1cb7b44666bc557..976558fcea0a58c48d185c6ced15405d51e7eadc 100644 (file)
@@ -1 +1 @@
-6f2858f6817ca70c132f0437ac2f0f74deb273d2
\ No newline at end of file
+1c20c1c28b56411f106cf2f6961b3ad4b4d6f6c8
\ No newline at end of file