]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix an fts5 bug in handling writes while there are active cursors.
authordan <dan@noemail.net>
Tue, 28 Apr 2015 20:24:50 +0000 (20:24 +0000)
committerdan <dan@noemail.net>
Tue, 28 Apr 2015 20:24:50 +0000 (20:24 +0000)
FossilOrigin-Name: 07f70955392697556ca2951c9b6c3a5204cd5ec0

ext/fts5/fts5.c
ext/fts5/fts5_expr.c
ext/fts5/test/fts5restart.test [new file with mode: 0644]
manifest
manifest.uuid

index 14ff73c7180ce4879fd5af72022635d4dd744190..928ad6d9167fa872aae6af27b75b4a2458e88784 100644 (file)
@@ -186,6 +186,7 @@ struct Fts5Cursor {
 #define FTS5CSR_REQUIRE_DOCSIZE   0x02
 #define FTS5CSR_EOF               0x04
 #define FTS5CSR_FREE_ZRANK        0x08
+#define FTS5CSR_REQUIRE_RESEEK    0x10
 
 /*
 ** Macros to Set(), Clear() and Test() cursor flags.
@@ -269,14 +270,12 @@ static int fts5IsContentless(Fts5Table *pTab){
 ** Delete a virtual table handle allocated by fts5InitVtab(). 
 */
 static void fts5FreeVtab(Fts5Table *pTab){
-  int rc = SQLITE_OK;
   if( pTab ){
     sqlite3Fts5IndexClose(pTab->pIndex);
     sqlite3Fts5StorageClose(pTab->pStorage);
     sqlite3Fts5ConfigFree(pTab->pConfig);
     sqlite3_free(pTab);
   }
-  return rc;
 }
 
 /*
@@ -608,6 +607,63 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
   return rc;
 }
 
+
+/*
+** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors 
+** open on table pTab.
+*/
+static void fts5TripCursors(Fts5Table *pTab){
+  Fts5Cursor *pCsr;
+  for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
+    if( FTS5_PLAN(pCsr->idxNum)==FTS5_PLAN_MATCH
+     && pCsr->base.pVtab==(sqlite3_vtab*)pTab 
+    ){
+      CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
+    }
+  }
+}
+
+/*
+** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
+** argument, close and reopen all Fts5IndexIter iterators that the cursor 
+** is using. Then attempt to move the cursor to a rowid equal to or laster
+** (in the cursors sort order - ASC or DESC) than the current rowid. 
+**
+** If the new rowid is not equal to the old, set output parameter *pbSkip
+** to 1 before returning. Otherwise, leave it unchanged.
+**
+** Return SQLITE_OK if successful or if no reseek was required, or an 
+** error code if an error occurred.
+*/
+static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
+  int rc = SQLITE_OK;
+  assert( *pbSkip==0 );
+  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
+    Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+    int bDesc = ((pCsr->idxNum & FTS5_ORDER_DESC) ? 1 : 0);
+    i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
+
+    rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, bDesc);
+    while( rc==SQLITE_OK && sqlite3Fts5ExprEof(pCsr->pExpr)==0 ){
+      i64 ii = sqlite3Fts5ExprRowid(pCsr->pExpr);
+      if( ii==iRowid ) break;
+      if( (bDesc && ii<iRowid) || (bDesc==0 && ii>iRowid) ){
+        *pbSkip = 1;
+        break;
+      }
+      rc = sqlite3Fts5ExprNext(pCsr->pExpr);
+    }
+
+    CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK);
+    fts5CsrNewrow(pCsr);
+    if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
+      CsrFlagSet(pCsr, FTS5CSR_EOF);
+    }
+  }
+  return rc;
+}
+
+
 /*
 ** Advance the cursor to the next row in the table that matches the 
 ** search criteria.
@@ -619,7 +675,10 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
 static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
   int ePlan = FTS5_PLAN(pCsr->idxNum);
-  int rc = SQLITE_OK;
+  int bSkip = 0;
+  int rc;
+
+  if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
 
   switch( ePlan ){
     case FTS5_PLAN_MATCH:
@@ -1156,6 +1215,7 @@ static int fts5UpdateMethod(
   assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
   assert( pVtab->zErrMsg==0 );
 
+  fts5TripCursors(pTab);
   if( rc==SQLITE_OK && eType0==SQLITE_INTEGER ){
     if( fts5IsContentless(pTab) ){
       pTab->base.zErrMsg = sqlite3_mprintf(
@@ -1196,6 +1256,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
   int rc;
   Fts5Table *pTab = (Fts5Table*)pVtab;
   fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
+  fts5TripCursors(pTab);
   rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
   return rc;
 }
@@ -1717,6 +1778,7 @@ static int fts5RenameMethod(
 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
   Fts5Table *pTab = (Fts5Table*)pVtab;
   fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
+  fts5TripCursors(pTab);
   return sqlite3Fts5StorageSync(pTab->pStorage, 0);
 }
 
@@ -1728,6 +1790,7 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
   Fts5Table *pTab = (Fts5Table*)pVtab;
   fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
+  fts5TripCursors(pTab);
   return sqlite3Fts5StorageSync(pTab->pStorage, 0);
 }
 
@@ -1739,6 +1802,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
   Fts5Table *pTab = (Fts5Table*)pVtab;
   fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
+  fts5TripCursors(pTab);
   return sqlite3Fts5StorageRollback(pTab->pStorage);
 }
 
index af44bcf760cfffabe5bbc1dbd09b7e44b9830fde..6463c64c3d5996e07b59790eda9bfc79117ad60a 100644 (file)
@@ -776,6 +776,10 @@ static int fts5ExprNearInitAll(
     pPhrase = pNear->apPhrase[i];
     for(j=0; j<pPhrase->nTerm; j++){
       pTerm = &pPhrase->aTerm[j];
+      if( pTerm->pIter ){
+        sqlite3Fts5IterClose(pTerm->pIter);
+        pTerm->pIter = 0;
+      }
       rc = sqlite3Fts5IndexQuery(
           pExpr->pIndex, pTerm->zTerm, strlen(pTerm->zTerm),
           (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
diff --git a/ext/fts5/test/fts5restart.test b/ext/fts5/test/fts5restart.test
new file mode 100644 (file)
index 0000000..3b1f334
--- /dev/null
@@ -0,0 +1,48 @@
+# 2015 April 28
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# This file focuses on testing the planner (xBestIndex function).
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5restart
+
+do_execsql_test 1.0 {
+  CREATE VIRTUAL TABLE f1 USING fts5(ff);
+}
+
+do_test 1.1 {
+  for {set i 1} {$i < 1000} {incr i} {
+    execsql { INSERT INTO f1 VALUES('a b c d e') }
+    lappend lRowid $i
+  }
+} {}
+
+do_execsql_test 1.2 {
+  SELECT rowid FROM f1 WHERE f1 MATCH 'c';
+} $lRowid
+
+breakpoint
+do_test 1.3 {
+  set res [list]
+  db eval { SELECT rowid FROM f1 WHERE f1 MATCH 'c' } {
+    if {$rowid == 100} {
+      execsql { INSERT INTO f1(f1) VALUES('optimize') }
+    }
+    lappend res $rowid
+  }
+  set res
+} $lRowid
+
+
+
+finish_test
+
index db7571000ed9aebaf120fc1be60044665b9eb3e5..370597381bc1ddccc595be7ba2e9d1c3b1e1aa5d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improve\scoverage\sof\sfts5\stests.
-D 2015-04-28T18:35:28.633
+C Fix\san\sfts5\sbug\sin\shandling\swrites\swhile\sthere\sare\sactive\scursors.
+D 2015-04-28T20:24:50.023
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 31b38b9da2e4b36f54a013bd71a5c3f6e45ca78f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -104,13 +104,13 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
 F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
 F ext/fts3/unicode/mkunicode.tcl 159c1194da0bc72f51b3c2eb71022568006dc5ad
 F ext/fts5/extract_api_docs.tcl 55a6d648d516f35d9a1e580ac00de27154e1904a
-F ext/fts5/fts5.c d9a99a595c0e341cb24918bc67c323d2444a3036
+F ext/fts5/fts5.c 45e82b584bb3fce22c82d8521bccaa2a6e9202fe
 F ext/fts5/fts5.h 24a2cc35b5e76eec57b37ba48c12d9d2cb522b3a
 F ext/fts5/fts5Int.h f573fe6c50471f1d66682fce282da801009c54e1
 F ext/fts5/fts5_aux.c fcea18b1a2a3f95a498b52aba2983557d7678a22
 F ext/fts5/fts5_buffer.c 8c8cfe7f09ca2767ab53ea883f9a0af0edb6bbae
 F ext/fts5/fts5_config.c f344ffa24d2add70fd5bde2b73c44846ad7a06bd
-F ext/fts5/fts5_expr.c 05da381ab26031243266069302c6eb4094b2c5dd
+F ext/fts5/fts5_expr.c e647a2626af5c80a6325532b23eea6d1eb252a78
 F ext/fts5/fts5_hash.c 29d8b0668727863cc1f1efa65efe4dd78635b016
 F ext/fts5/fts5_index.c de588982b0237b1605d6c37afd115b34c95c3da1
 F ext/fts5/fts5_storage.c ef60fc9dcc4e274f9589165e26833173c273ae18
@@ -152,6 +152,7 @@ F ext/fts5/test/fts5optimize.test 0028c90a7817d3e576d1148fc8dff17d89054e54
 F ext/fts5/test/fts5porter.test 50322599823cb8080a99f0ec0c39f7d0c12bcb5e
 F ext/fts5/test/fts5prefix.test 1287803c3df0e43f536196256fb9e0e6baccb4f1
 F ext/fts5/test/fts5rebuild.test ee6792715c6c528cc188e7869d67c3c655889ddb
+F ext/fts5/test/fts5restart.test 4934233dd2633665198d563c79f1015e3a2b9518
 F ext/fts5/test/fts5rowid.test a1b2a6d76648c734c1aab11ee1a619067e8d90e6
 F ext/fts5/test/fts5tokenizer.test 7a6ee24db908c09a0dc1eba634ffa17afcc05d86
 F ext/fts5/test/fts5unicode.test 79b3e34eb29ce4929628aa514a40cb467fdabe4d
@@ -1310,7 +1311,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 e38e2bb637844dae8ae5d5f3e23d8369e1b91e45
-R 36584b17863acf9c4ced66420a8dd86e
+P 8e8136f2dc08082c2984462719d9cba0f212c92a
+R 65017a9d42efb9cfacfe6e269e92cdbd
 U dan
-Z 4aeb27eb1cd105a6fffeab8d10b6e855
+Z 91e05f6f4d01e29ed38305d1f49be921
index ed44a022b67ab001f5f8c09d9fdc4d2b76973ffe..e0e7db8c5b8cbf13b4e2e34a62bd5ed67a41dd41 100644 (file)
@@ -1 +1 @@
-8e8136f2dc08082c2984462719d9cba0f212c92a
\ No newline at end of file
+07f70955392697556ca2951c9b6c3a5204cd5ec0
\ No newline at end of file