]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Optimizations for fts5 queries that match against a specific column.
authordan <dan@noemail.net>
Thu, 28 May 2015 19:57:12 +0000 (19:57 +0000)
committerdan <dan@noemail.net>
Thu, 28 May 2015 19:57:12 +0000 (19:57 +0000)
FossilOrigin-Name: b29ac50af0491a780a5a4c0985d88d0e5e014ba3

ext/fts5/fts5_expr.c
ext/fts5/test/fts5aa.test
manifest
manifest.uuid

index 945bb637f8f9a3718e8b97c7606617f01d04c3c3..891bb30382219000b7413afa1fce22f00428009d 100644 (file)
@@ -652,6 +652,45 @@ static int fts5ExprNearNextRowidMatch(
   return rc;
 }
 
+/*
+** 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 ii;
+  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 += getVarint32(p, iCurrent);
+  }
+
+  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
+  ** not part of a varint */
+  while( p<pEnd && !(prev & 0x80) && *p!=0x01 ){
+    prev = *p++;
+  }
+  return p - (*pa);
+}
+
+
+
 /*
 ** Argument pNode points to a NEAR node. All individual term iterators 
 ** point to valid entries (not EOF).
@@ -674,26 +713,39 @@ static int fts5ExprNearNextMatch(
   Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_STRING) */
 ){
   Fts5ExprNearset *pNear = pNode->pNear;
+  int rc = SQLITE_OK;
 
-  if( pNear->nPhrase==1 
-   && pNear->apPhrase[0]->nTerm==1 
-   && pNear->iCol<0
-  ){
-    /* If this "NEAR" object is actually a single phrase that consists of
-    ** a single term only, then the row that it currently points to must
-    ** be a match. All that is required is to populate pPhrase->poslist
-    ** with the position-list data for the only term.  */
-    Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
-    Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
-    assert( pPhrase->poslist.nSpace==0 );
-    return sqlite3Fts5IterPoslist(pIter, 
-        (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
-    );
-  }else{
-    int rc = SQLITE_OK;
+  while( 1 ){
+    int i;
 
-    while( 1 ){
-      int i;
+    if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 ){
+      /* If this "NEAR" object is actually a single phrase that consists 
+      ** of a single term only, then grab pointers into the poslist
+      ** managed by the fts5_index.c iterator object. This is much faster 
+      ** than synthesizing a new poslist the way we have to for more
+      ** complicated phrase or NEAR expressions.  */
+      Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
+      Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
+      assert( pPhrase->poslist.nSpace==0 );
+      rc = sqlite3Fts5IterPoslist(pIter, 
+          (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &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( pNear->iCol<0 ) return rc;
+
+      pPhrase->poslist.n = fts5ExprExtractCol(
+          (const u8**)&pPhrase->poslist.p,
+          pPhrase->poslist.n,
+          pNear->iCol
+      );
+      if( pPhrase->poslist.n ) return rc;
+    }else{
 
       /* Advance the iterators until they all point to the same rowid */
       rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
@@ -711,7 +763,7 @@ static int fts5ExprNearNextMatch(
         }else{
           rc = sqlite3Fts5IterPoslistBuffer(
               pPhrase->aTerm[0].pIter, &pPhrase->poslist
-          );
+              );
         }
       }
 
@@ -722,17 +774,17 @@ static int fts5ExprNearNextMatch(
         }
         if( rc!=SQLITE_OK || bMatch ) break;
       }
-
-      /* If control flows to here, then the current rowid is not a match.
-      ** Advance all term iterators in all phrases to the next rowid. */
-      if( rc==SQLITE_OK ){
-        rc = fts5ExprNearAdvanceFirst(pExpr, pNode, 0, 0);
-      }
-      if( pNode->bEof || rc!=SQLITE_OK ) break;
     }
 
-    return rc;
+    /* If control flows to here, then the current rowid is not a match.
+    ** Advance all term iterators in all phrases to the next rowid. */
+    if( rc==SQLITE_OK ){
+      rc = fts5ExprNearAdvanceFirst(pExpr, pNode, 0, 0);
+    }
+    if( pNode->bEof || rc!=SQLITE_OK ) break;
   }
+
+  return rc;
 }
 
 /*
index 800215d2bb827f6d32a67317638797d837d3fee6..e7c37ccbf84c22a327b08305a10756c423bb0d11 100644 (file)
@@ -426,6 +426,12 @@ do_test 17.2 {
   set res
 } {{a b c} {a b c} {a b c}}
 
+reset_db
+do_execsql_test 18.1 {
+  CREATE VIRTUAL TABLE c2 USING fts5(x, y);
+  INSERT INTO c2 VALUES('x x x', 'x x x');
+  SELECT rowid FROM c2 WHERE c2 MATCH 'y:x';
+} {1}
 
 finish_test
 
index 328ed4e922ee13ce39a5f9dc8f006fddc3959403..887ea5a8a58d5c548a67a32256894c5c19be3fff 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\ssome\sdead\scode\sfrom\sfts5.\sAdd\sauxiliary\sfunction\sapi\stests\sto\sthe\ssame.
-D 2015-05-28T14:37:26.732
+C Optimizations\sfor\sfts5\squeries\sthat\smatch\sagainst\sa\sspecific\scolumn.
+D 2015-05-28T19:57:12.367
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2c28e557780395095c307a6e5cb539419027eb5e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -111,7 +111,7 @@ F ext/fts5/fts5Int.h 2ce5c5e68852dd16de404b7a9a2a78f4f4588eb4
 F ext/fts5/fts5_aux.c d53f00f31ad615ca4f139dd8751f9041afa00971
 F ext/fts5/fts5_buffer.c 861599a0abe2383f0cd0352c57001140a26b0930
 F ext/fts5/fts5_config.c 11f969ed711a0a8b611d47431d74c372ad78c713
-F ext/fts5/fts5_expr.c a8b31d363c02108dae01e13948661859f449ebb9
+F ext/fts5/fts5_expr.c c94983eaff58391d7c0d62e99de917cecd0f1dbc
 F ext/fts5/fts5_hash.c 54dd25348a46ea62ea96322c572e08cd1fb37304
 F ext/fts5/fts5_index.c a693ba741b82539da5779329214e5d2609e82e5f
 F ext/fts5/fts5_storage.c 5d2b51adb304643d8f825ba89283d628418b20c2
@@ -122,7 +122,7 @@ F ext/fts5/fts5_vocab.c 1f8543b2c1ae4427f127a911bc8e60873fcd7bf9
 F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
 F ext/fts5/test/fts5_common.tcl 6d663e8c3d8409857363f66560df96b8ca813e79
-F ext/fts5/test/fts5aa.test 26f1a462213f3aa067c208bd508d6218c54a620f
+F ext/fts5/test/fts5aa.test 5f73afe6a1394fdba9bc18302876ded81021bee6
 F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
 F ext/fts5/test/fts5ac.test 05008e00bd2761cc45df838a0988ecf318cbe1fd
 F ext/fts5/test/fts5ad.test 312f3c8ed9592533499c5b94d2059ae6382913a0
@@ -1331,7 +1331,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P aef89d9f6aa536efee347367558cf5d4ea81b238
-R bb8e2d4390fd848d148991824b1dfd3a
+P 0f9df202cc58097afddb8dad662b7c7fdc2c7d0c
+R f25569d3bfd1393da78f5986e0e8acff
 U dan
-Z cb932577f097e506aa4f837dda1f2a1b
+Z d652fde1b36e85f62688dc3a9737ccda
index d0242f4b60e0620c386f8d44a84e1848c3594b84..4025ca1b11263a73f45eac6c0cacb92aafda72d2 100644 (file)
@@ -1 +1 @@
-0f9df202cc58097afddb8dad662b7c7fdc2c7d0c
\ No newline at end of file
+b29ac50af0491a780a5a4c0985d88d0e5e014ba3
\ No newline at end of file