From: dan Date: Tue, 28 Apr 2015 20:24:50 +0000 (+0000) Subject: Fix an fts5 bug in handling writes while there are active cursors. X-Git-Tag: version-3.8.11~114^2~54 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=90dd70226f402c4b539fe47426192584777405f8;p=thirdparty%2Fsqlite.git Fix an fts5 bug in handling writes while there are active cursors. FossilOrigin-Name: 07f70955392697556ca2951c9b6c3a5204cd5ec0 --- diff --git a/ext/fts5/fts5.c b/ext/fts5/fts5.c index 14ff73c718..928ad6d916 100644 --- a/ext/fts5/fts5.c +++ b/ext/fts5/fts5.c @@ -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 && iiiRowid) ){ + *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); } diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index af44bcf760..6463c64c3d 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -776,6 +776,10 @@ static int fts5ExprNearInitAll( pPhrase = pNear->apPhrase[i]; for(j=0; jnTerm; 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 index 0000000000..3b1f334221 --- /dev/null +++ b/ext/fts5/test/fts5restart.test @@ -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 + diff --git a/manifest b/manifest index db7571000e..370597381b 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index ed44a022b6..e0e7db8c5b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8e8136f2dc08082c2984462719d9cba0f212c92a \ No newline at end of file +07f70955392697556ca2951c9b6c3a5204cd5ec0 \ No newline at end of file