]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change fts5 expression processing to avoid linear scans of long doclists caused by...
authordan <dan@noemail.net>
Mon, 1 Jun 2015 09:15:20 +0000 (09:15 +0000)
committerdan <dan@noemail.net>
Mon, 1 Jun 2015 09:15:20 +0000 (09:15 +0000)
FossilOrigin-Name: ec69e09a55b4daf1c40aeaaf9ee95091fe86f5c0

ext/fts5/fts5_expr.c
ext/fts5/test/fts5_common.tcl
ext/fts5/test/fts5auto.test
manifest
manifest.uuid

index 1a5f2887f434eeab6980ba8b95ab1ae32a8eb715..9b3e04a74edec79680ed6d0002e34f271fc08436 100644 (file)
@@ -653,10 +653,8 @@ static int fts5ExprNearNextRowidMatch(
   Fts5ExprNode *pNode
 ){
   Fts5ExprNearset *pNear = pNode->pNear;
-  int rc = SQLITE_OK;
-  int i, j;                       /* Phrase and token index, respectively */
   i64 iLast;                      /* Lastest rowid any iterator points to */
-  int bMatch;                     /* True if all terms are at the same rowid */
+  int rc = SQLITE_OK;
 
   /* Initialize iLast, the "lastest" rowid any iterator points to. If the
   ** iterator skips through rowids in the default ascending order, this means
@@ -664,20 +662,24 @@ static int fts5ExprNearNextRowidMatch(
   ** means the minimum rowid.  */
   iLast = sqlite3Fts5IterRowid(pNear->apPhrase[0]->aTerm[0].pIter);
 
-  do {
-    bMatch = 1;
-    for(i=0; i<pNear->nPhrase; i++){
-      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
-      for(j=0; j<pPhrase->nTerm; j++){
-        Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
-        i64 iRowid = sqlite3Fts5IterRowid(pIter);
-        if( iRowid!=iLast ) bMatch = 0;
-        if( fts5ExprAdvanceto(pIter, pExpr->bDesc, &iLast, &rc, &pNode->bEof) ){
-          return rc;
+  if( pNear->nPhrase>1 || pNear->apPhrase[0]->nTerm>1 ){
+    int i, j;                     /* Phrase and token index, respectively */
+    int bMatch;                   /* True if all terms are at the same rowid */
+    do {
+      bMatch = 1;
+      for(i=0; i<pNear->nPhrase; i++){
+        Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+        for(j=0; j<pPhrase->nTerm; j++){
+          Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
+          i64 iRowid = sqlite3Fts5IterRowid(pIter);
+          if( iRowid!=iLast ) bMatch = 0;
+          if( fts5ExprAdvanceto(pIter, pExpr->bDesc, &iLast,&rc,&pNode->bEof) ){
+            return rc;
+          }
         }
       }
-    }
-  }while( bMatch==0 );
+    }while( bMatch==0 );
+  }
 
   pNode->iRowid = iLast;
   return rc;
@@ -738,6 +740,76 @@ static int fts5ExprExtractColset (
   return rc;
 }
 
+static int fts5ExprNearTest(
+  int *pRc,
+  Fts5Expr *pExpr,                /* Expression that pNear is a part of */
+  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_STRING) */
+){
+  Fts5ExprNearset *pNear = pNode->pNear;
+  int rc = *pRc;
+
+  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;
+    Fts5ExprColset *pColset = pNear->pColset;
+    const u8 *pPos;
+    int nPos;
+
+    if( rc!=SQLITE_OK ) return 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);
+    }
+
+    *pRc = rc;
+    return (pPhrase->poslist.n>0);
+  }else{
+    int i;
+
+    /* Check that each phrase in the nearset matches the current row.
+    ** Populate the pPhrase->poslist buffers at the same time. If any
+    ** phrase is not a match, break out of the loop early.  */
+    for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
+      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+      if( pPhrase->nTerm>1 || pNear->pColset ){
+        int bMatch = 0;
+        rc = fts5ExprPhraseIsMatch(pExpr, pNear->pColset, pPhrase, &bMatch);
+        if( bMatch==0 ) break;
+      }else{
+        rc = sqlite3Fts5IterPoslistBuffer(
+            pPhrase->aTerm[0].pIter, &pPhrase->poslist
+        );
+      }
+    }
+
+    *pRc = rc;
+    if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
+      return 1;
+    }
+  }
+
+  return 0;
+}
 
 /*
 ** Argument pNode points to a NEAR node. All individual term iterators 
@@ -760,72 +832,16 @@ static int fts5ExprNearNextMatch(
   Fts5Expr *pExpr,                /* Expression that pNear is a part of */
   Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_STRING) */
 ){
-  Fts5ExprNearset *pNear = pNode->pNear;
   int rc = SQLITE_OK;
 
+  assert( pNode->pNear );
   while( 1 ){
 
-    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;
-      Fts5ExprColset *pColset = pNear->pColset;
-      const u8 *pPos;
-      int nPos;
-
-      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);
-      }
-
-      if( pPhrase->poslist.n ) return rc;
-    }else{
-      int i;
+    /* Advance the iterators until they all point to the same rowid */
+    rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
+    if( rc!=SQLITE_OK || pNode->bEof ) break;
 
-      /* Advance the iterators until they all point to the same rowid */
-      rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
-      if( rc!=SQLITE_OK || pNode->bEof ) break;
-
-      /* Check that each phrase in the nearset matches the current row.
-      ** Populate the pPhrase->poslist buffers at the same time. If any
-      ** phrase is not a match, break out of the loop early.  */
-      for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
-        Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
-        if( pPhrase->nTerm>1 || pNear->pColset ){
-          int bMatch = 0;
-          rc = fts5ExprPhraseIsMatch(pExpr, pNear->pColset, pPhrase, &bMatch);
-          if( bMatch==0 ) break;
-        }else{
-          rc = sqlite3Fts5IterPoslistBuffer(
-              pPhrase->aTerm[0].pIter, &pPhrase->poslist
-          );
-        }
-      }
-
-      if( i==pNear->nPhrase ){
-        if( i==1 ) break;
-        if( fts5ExprNearIsMatch(&rc, pNear) ) break;
-      }
-    }
+    if( fts5ExprNearTest(&rc, pExpr, pNode) ) 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. */
@@ -942,10 +958,11 @@ static int fts5ExprNodeNext(
       };
 
       case FTS5_AND: {
-        rc = fts5ExprNodeNext(pExpr, pNode->pLeft, bFromValid, iFrom);
-        if( rc==SQLITE_OK ){
-          /* todo: update (iFrom/bFromValid) here */
-          rc = fts5ExprNodeNext(pExpr, pNode->pRight, bFromValid, iFrom);
+        Fts5ExprNode *pLeft = pNode->pLeft;
+        rc = fts5ExprNodeNext(pExpr, pLeft, bFromValid, iFrom);
+        if( rc==SQLITE_OK && pLeft->bEof==0 ){
+          assert( !bFromValid || fts5RowidCmp(pExpr, pLeft->iRowid, iFrom)>=0 );
+          rc = fts5ExprNodeNext(pExpr, pNode->pRight, 1, pLeft->iRowid);
         }
         break;
       }
@@ -994,6 +1011,67 @@ static int fts5ExprNodeNext(
   return rc;
 }
 
+static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
+  if( pNode->eType==FTS5_STRING ){
+    Fts5ExprNearset *pNear = pNode->pNear;
+    int i;
+    for(i=0; i<pNear->nPhrase; i++){
+      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+      pPhrase->poslist.n = 0;
+    }
+  }else{
+    fts5ExprNodeZeroPoslist(pNode->pLeft);
+    fts5ExprNodeZeroPoslist(pNode->pRight);
+  }
+}
+
+static int fts5ExprNodeTest(
+  int *pRc, 
+  Fts5Expr *pExpr, 
+  i64 iRowid,
+  Fts5ExprNode *pNode
+){
+  int bRes = 0;
+  if( pNode->bEof || pNode->iRowid!=iRowid ){
+    bRes = 0;
+  }else {
+    switch( pNode->eType ){
+      case FTS5_STRING:
+        bRes = fts5ExprNearTest(pRc, pExpr, pNode);
+        if( *pRc ) bRes = 0;
+        break;
+
+      case FTS5_AND: {
+        int bRes1 = fts5ExprNodeTest(pRc, pExpr, iRowid, pNode->pLeft);
+        int bRes2 = fts5ExprNodeTest(pRc, pExpr, iRowid, pNode->pRight);
+        assert( (bRes1==0 || bRes1==1) && (bRes2==0 || bRes2==1) );
+
+        bRes = (bRes1 && bRes2);
+        if( bRes1!=bRes2 ){
+          fts5ExprNodeZeroPoslist(bRes1 ? pNode->pLeft : pNode->pRight);
+        }
+        break;
+      }
+
+      case FTS5_OR: {
+        int bRes1 = fts5ExprNodeTest(pRc, pExpr, iRowid, pNode->pLeft);
+        int bRes2 = fts5ExprNodeTest(pRc, pExpr, iRowid, pNode->pRight);
+
+        bRes = (bRes1 || bRes2);
+        break;
+      }
+
+      default:
+        assert( pNode->eType==FTS5_NOT );
+        bRes = fts5ExprNodeTest(pRc, pExpr, iRowid, pNode->pLeft);
+        break;
+    }
+  }
+
+  return bRes;
+}
+
+
 static void fts5ExprSetEof(Fts5ExprNode *pNode){
   if( pNode ){
     pNode->bEof = 1;
@@ -1016,7 +1094,10 @@ static int fts5ExprNodeNextMatch(
     switch( pNode->eType ){
 
       case FTS5_STRING: {
+#if 0
         rc = fts5ExprNearNextMatch(pExpr, pNode);
+#endif
+        rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
         break;
       }
 
@@ -1065,7 +1146,7 @@ static int fts5ExprNodeNextMatch(
             cmp = fts5NodeCompare(pExpr, p1, p2);
           }
           assert( rc!=SQLITE_OK || cmp<=0 );
-          if( rc || cmp<0 ) break;
+          if( 0==fts5ExprNodeTest(&rc, pExpr, p1->iRowid, p2) ) break;
           rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
         }
         pNode->bEof = p1->bEof;
@@ -1096,7 +1177,10 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
 
     /* Attempt to advance to the first match */
     if( rc==SQLITE_OK && pNode->bEof==0 ){
+#if 0
       rc = fts5ExprNearNextMatch(pExpr, pNode);
+#endif
+      rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
     }
 
   }else{
@@ -1112,7 +1196,6 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
 }
 
 
-
 /*
 ** Begin iterating through the set of documents in index pIdx matched by
 ** the MATCH expression passed as the first argument. If the "bDesc" parameter
@@ -1123,11 +1206,18 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
 ** is not considered an error if the query does not match any documents.
 */
 int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, int bDesc){
+  Fts5ExprNode *pRoot = p->pRoot;
   int rc = SQLITE_OK;
-  if( p->pRoot ){
+  if( pRoot ){
     p->pIndex = pIdx;
     p->bDesc = bDesc;
-    rc = fts5ExprNodeFirst(p, p->pRoot);
+    rc = fts5ExprNodeFirst(p, pRoot);
+    if( pRoot->bEof==0 
+     && 0==fts5ExprNodeTest(&rc, p, pRoot->iRowid, pRoot) 
+     && rc==SQLITE_OK 
+    ){
+      rc = sqlite3Fts5ExprNext(p);
+    }
   }
   return rc;
 }
@@ -1140,7 +1230,12 @@ int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, int bDesc){
 */
 int sqlite3Fts5ExprNext(Fts5Expr *p){
   int rc;
-  rc = fts5ExprNodeNext(p, p->pRoot, 0, 0);
+  do {
+    rc = fts5ExprNodeNext(p, p->pRoot, 0, 0);
+  }while( p->pRoot->bEof==0 
+      && fts5ExprNodeTest(&rc, p, p->pRoot->iRowid, p->pRoot)==0 
+      && rc==SQLITE_OK 
+  );
   return rc;
 }
 
index e4a689bb729c6775fe679366a37ff8b1fb1b5315..deffec5c4a95859855e33a22f442d4f28af4f76e 100644 (file)
@@ -279,7 +279,7 @@ proc OR {a b} {
   sort_poslist [concat $a $b]
 }
 proc NOT {a b} {
-  if {[llength $b]} { return [list] }
+  if {[llength $b]>0} { return [list] }
   return $a
 }
 
index 48d914888270a05a72896e82c7c5a9f12c359738..30333de2212a088e70bbf2869094fd42d1dd8e49 100644 (file)
@@ -226,32 +226,13 @@ set data {
     {k s}                           {r f e j q p w}               
 }
 
-do_test 1.0 {
-  execsql {
-    BEGIN;
-    CREATE VIRTUAL TABLE tt USING fts5(a, b, c, d, e, f);
-  }
-  foreach {rowid a b c d e f} $data {
-    execsql {
-      INSERT INTO tt(rowid, a, b, c, d, e, f) 
-      VALUES($rowid, $a, $b, $c, $d, $e, $f)
-    }
-  }
-  execsql {
-    COMMIT;
-  }
+do_execsql_test 1.0 {
+  CREATE VIRTUAL TABLE tt USING fts5(a, b, c, d, e, f);
 } {}
 
-proc fts5_test_poslist {cmd} {
-  set res [list]
-  for {set i 0} {$i < [$cmd xInstCount]} {incr i} {
-    lappend res [string map {{ } .} [$cmd xInst $i]]
-  }
-  set res
-}
-sqlite3_fts5_create_function db fts5_test_poslist fts5_test_poslist
+fts5_aux_test_functions db
 
-proc matchdata {expr} {
+proc matchdata {expr {order ASC}} {
   set tclexpr [db one {
     SELECT fts5_expr_tcl(
       $expr, 'nearset $cols -pc ::pc', 'a','b','c','d','e','f'
@@ -259,49 +240,88 @@ proc matchdata {expr} {
   }]
   set res [list]
 
-  db eval {SELECT rowid, * FROM tt} {
+  db eval "SELECT rowid, * FROM tt ORDER BY rowid $order" {
     set cols [list $a $b $c $d $e $f]
     set ::pc 0
     set rowdata [eval $tclexpr]
-
-    if {$rowdata != ""} {
-      lappend res $rowid $rowdata
-    }
+    if {$rowdata != ""} { lappend res $rowid $rowdata }
   }
 
   set res
 }
 
+proc do_auto_test {tn expr} { 
+  foreach order {asc desc} {
+    set res [matchdata $expr $order]
+    set testname "3.$tn.[string range $order 0 0].rows=[expr [llength $res]/2]"
+
+    set ::autotest_expr $expr
+    do_execsql_test $testname [subst -novar {
+      SELECT rowid, fts5_test_poslist(tt) FROM tt 
+      WHERE tt MATCH $::autotest_expr ORDER BY rowid [set order]
+    }] $res
+  }
+
+
+}
+
 #-------------------------------------------------------------------------
 #
 
-do_execsql_test 2.0 {
-  SELECT rowid, fts5_test_poslist(tt) FROM tt WHERE tt MATCH 'a AND b';
-} [matchdata "a AND b"]
+for {set fold 0} {$fold < 3} {incr fold} {
+  switch $fold {
+    0 { set map {} }
+    1 { set map {
+      a a  b a  c b  d b  e c  f c  g d  h d  
+      i e  j e  k f  l f  m g  g g  o h  p h
+      q i  r i  s j  t j  u k  v k  w l  x l
+      y m  z m
+    }}
 
-do_test 2.1 {
-  llength [matchdata "a AND b"]
-} 62
+    2 { set map {
+      a a  b a  c a  d a  e a  f a  g a  h a  
+      i b  j b  k b  l b  m b  g b  o b  p b
+      q c  r c  s c  t c  u c  v c  w c  x c
+    }}
+  }
 
-foreach {tn expr} {
-  1 { [a] : x }
-  2 { [a b] : x }
-  3 { [a b f] : x }
-  4 { [f a b] : x }
-  5 { [f a b] : x y }
-  6 { [f a b] : x + y }
-  7 { [c a b] : x + c }
-  8 { [c d] : "l m" }
-  9 { [c e] : "l m" }
-} {
-  set res [matchdata $expr]
-  do_test 3.$tn.[llength $res] {
+  execsql {
+    BEGIN;
+    DELETE FROM tt;
+  }
+  foreach {rowid a b c d e f} [string map $map $data] {
     execsql {
-      SELECT rowid, fts5_test_poslist(tt) FROM tt WHERE tt MATCH $expr
+      INSERT INTO tt(rowid, a, b, c, d, e, f) 
+      VALUES($rowid, $a, $b, $c, $d, $e, $f)
     }
-  } $res
-}
+  }
+  execsql COMMIT
+
 
+  foreach {tn expr} {
+    3.1 { [a] : x }
+    3.2 { [a b] : x }
+    3.3 { [a b f] : x }
+    3.4 { [f a b] : x }
+    3.5 { [f a b] : x y }
+    3.6 { [f a b] : x + y }
+    3.7 { [c a b] : x + c }
+    3.8 { [c d] : "l m" }
+    3.9 { [c e] : "l m" }
+
+    4.1 { a NOT b }
+    4.2 { a NOT a:b }
+    4.3 { a OR (b AND c) }
+    4.4 { a OR (b AND [a b c]:c) }
+    4.5 { a OR "b c" }
+    4.6 { a OR b OR c }
+
+    5.1 { a OR (b AND "b c") }
+    5.2 { a OR (b AND "z c") }
+  } {
+    do_auto_test 3.$fold.$tn $expr
+  }
+}
 
 finish_test
 
index 2f6be39866053765851e05852d2f670d23d84f14..874c169da6ecd242e5dbde22cc9a749722959e90 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sthe\s"#include\ssqlite3Int.h"\sfrom\sfts5Int.h.
-D 2015-05-30T11:49:58.614
+C Change\sfts5\sexpression\sprocessing\sto\savoid\slinear\sscans\sof\slong\sdoclists\scaused\sby\sphrases\sthat\smatch\sspecific\scolumns\sonly.
+D 2015-06-01T09:15:20.958
 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 4c677f3b797acde90ba1b7730eca6a32e7def742
 F ext/fts5/fts5_aux.c d53f00f31ad615ca4f139dd8751f9041afa00971
 F ext/fts5/fts5_buffer.c 9ec57c75c81e81dca118568876b1caead0aadadf
 F ext/fts5/fts5_config.c 11f969ed711a0a8b611d47431d74c372ad78c713
-F ext/fts5/fts5_expr.c 6a683326d6ae4e58420792e84576af9c7a8a89e4
+F ext/fts5/fts5_expr.c e58c9dec148a92e9040abc613eb3c7506d741d4f
 F ext/fts5/fts5_hash.c c1cfdb2cae0fad00b06fae38a40eaf9261563ccc
 F ext/fts5/fts5_index.c 7cea402924cd3d8cd5943a7f9514c9153696571b
 F ext/fts5/fts5_storage.c 04e6717656b78eb230a1c730cac3b935eb94889b
@@ -122,7 +122,7 @@ F ext/fts5/fts5_varint.c 366452037bf9a000c351374b489badc1b3541796
 F ext/fts5/fts5_vocab.c 1f8543b2c1ae4427f127a911bc8e60873fcd7bf9
 F ext/fts5/fts5parse.y 4ee667932d561a150d96483cf563281b95a9e523
 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
-F ext/fts5/test/fts5_common.tcl 632ff0fd8bf3dd55c2ddaac2c16428548d5af7be
+F ext/fts5/test/fts5_common.tcl 339115b24a57244e792db465c5bad482e0e7db72
 F ext/fts5/test/fts5aa.test 5f73afe6a1394fdba9bc18302876ded81021bee6
 F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
 F ext/fts5/test/fts5ac.test 999fd5f44579f1eb565ed7cf3861c427537ff097
@@ -135,7 +135,7 @@ F ext/fts5/test/fts5ai.test f20e53bbf0c55bc596f1fd47f2740dae028b8f37
 F ext/fts5/test/fts5aj.test 05b569f5c16ea3098fb1984eec5cf50dbdaae5d8
 F ext/fts5/test/fts5ak.test 7b8c5df96df599293f920b7e5521ebc79f647592
 F ext/fts5/test/fts5al.test fc60ebeac9d8e366e71309d4c31fa72199d711d7
-F ext/fts5/test/fts5auto.test 62e62fa7d60c50d334c5f6cf6b1ed1d49fa3d8d8
+F ext/fts5/test/fts5auto.test 3810c1c4928be0161b87dfc479ecf1b873f37c6c
 F ext/fts5/test/fts5aux.test e5631607bbc05ac1c38cf7d691000509aca71ef3
 F ext/fts5/test/fts5auxdata.test c69b86092bf1a157172de5f9169731af3403179b
 F ext/fts5/test/fts5bigpl.test b1cfd00561350ab04994ba7dd9d48468e5e0ec3b
@@ -1333,7 +1333,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 ae6794ffa23ef6191bd8834422abf322d978c11b
-R bc0305687d74df992086e66a1770f40c
+P e008c3c8e29c843ec945ddad54b9688bbf2bdb44
+R 99cd144645ddb0146b8edfaf69348c90
 U dan
-Z 008bbbc1e4c3598d73e809e2e8e489be
+Z 9df575eada62ea84610594e2c9d9937b
index 3d9104933908cb49912d49b7a8b3b78b40f563a9..64f51bd23fda946ab76add5fbb50abff0c41dd2b 100644 (file)
@@ -1 +1 @@
-e008c3c8e29c843ec945ddad54b9688bbf2bdb44
\ No newline at end of file
+ec69e09a55b4daf1c40aeaaf9ee95091fe86f5c0
\ No newline at end of file