| https://sqlite.org/forum/forumpost/cb59d962fd |
| https://sqlite.org/src/vinfo/d8c6b246 |
| https://sqlite.org/src/info/67da596d82ec0ed3 (backport) |
| |
| --- a/ext/fts5/fts5_index.c |
| +++ b/ext/fts5/fts5_index.c |
| @@ -355,10 +355,11 @@ |
| int nContentlessDelete; /* Number of contentless delete ops */ |
| int nPendingRow; /* Number of INSERT in hash table */ |
| |
| /* Error state. */ |
| int rc; /* Current error code */ |
| + int flushRc; |
| |
| /* State used by the fts5DataXXX() functions. */ |
| sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ |
| sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ |
| sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ |
| @@ -4000,10 +4001,11 @@ |
| assert( p->pHash || p->nPendingData==0 ); |
| if( p->pHash ){ |
| sqlite3Fts5HashClear(p->pHash); |
| p->nPendingData = 0; |
| p->nPendingRow = 0; |
| + p->flushRc = SQLITE_OK; |
| } |
| p->nContentlessDelete = 0; |
| } |
| |
| /* |
| @@ -5582,18 +5584,24 @@ |
| /* |
| ** Flush any data stored in the in-memory hash tables to the database. |
| */ |
| static void fts5IndexFlush(Fts5Index *p){ |
| /* Unless it is empty, flush the hash table to disk */ |
| + if( p->flushRc ){ |
| + p->rc = p->flushRc; |
| + return; |
| + } |
| if( p->nPendingData || p->nContentlessDelete ){ |
| assert( p->pHash ); |
| fts5FlushOneHash(p); |
| if( p->rc==SQLITE_OK ){ |
| sqlite3Fts5HashClear(p->pHash); |
| p->nPendingData = 0; |
| p->nPendingRow = 0; |
| p->nContentlessDelete = 0; |
| + }else if( p->nPendingData || p->nContentlessDelete ){ |
| + p->flushRc = p->rc; |
| } |
| } |
| } |
| |
| static Fts5Structure *fts5IndexOptimizeStruct( |
| |
| --- a/ext/fts5/fts5_main.c |
| +++ b/ext/fts5/fts5_main.c |
| @@ -116,11 +116,11 @@ |
| Fts5Table p; /* Public class members from fts5Int.h */ |
| Fts5Storage *pStorage; /* Document store */ |
| Fts5Global *pGlobal; /* Global (connection wide) data */ |
| Fts5Cursor *pSortCsr; /* Sort data from this cursor */ |
| int iSavepoint; /* Successful xSavepoint()+1 */ |
| - int bInSavepoint; |
| + |
| #ifdef SQLITE_DEBUG |
| struct Fts5TransactionState ts; |
| #endif |
| }; |
| |
| @@ -2613,13 +2613,11 @@ |
| sqlite3_vtab *pVtab, /* Virtual table handle */ |
| const char *zName /* New name of table */ |
| ){ |
| int rc; |
| Fts5FullTable *pTab = (Fts5FullTable*)pVtab; |
| - pTab->bInSavepoint = 1; |
| rc = sqlite3Fts5StorageRename(pTab->pStorage, zName); |
| - pTab->bInSavepoint = 0; |
| return rc; |
| } |
| |
| int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ |
| fts5TripCursors((Fts5FullTable*)pTab); |
| @@ -2632,30 +2630,16 @@ |
| ** Flush the contents of the pending-terms table to disk. |
| */ |
| static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| Fts5FullTable *pTab = (Fts5FullTable*)pVtab; |
| int rc = SQLITE_OK; |
| - char *zSql = 0; |
| + |
| fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); |
| - |
| - if( pTab->bInSavepoint==0 ){ |
| - zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')", |
| - pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName |
| - ); |
| - if( zSql ){ |
| - pTab->bInSavepoint = 1; |
| - rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0); |
| - pTab->bInSavepoint = 0; |
| - sqlite3_free(zSql); |
| - }else{ |
| - rc = SQLITE_NOMEM; |
| - } |
| - if( rc==SQLITE_OK ){ |
| - pTab->iSavepoint = iSavepoint+1; |
| - } |
| - } |
| - |
| + rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); |
| + if( rc==SQLITE_OK ){ |
| + pTab->iSavepoint = iSavepoint+1; |
| + } |
| return rc; |
| } |
| |
| /* |
| ** The xRelease() method. |
| @@ -2912,11 +2896,11 @@ |
| /* |
| ** Run an integrity check on the FTS5 data structures. Return a string |
| ** if anything is found amiss. Return a NULL pointer if everything is |
| ** OK. |
| */ |
| -static int fts5Integrity( |
| +static int fts5IntegrityMethod( |
| sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */ |
| const char *zSchema, /* Name of schema in which this table lives */ |
| const char *zTabname, /* Name of the table itself */ |
| int isQuick, /* True if this is a quick-check */ |
| char **pzErr /* Write error message here */ |
| @@ -2970,11 +2954,11 @@ |
| /* xRename */ fts5RenameMethod, |
| /* xSavepoint */ fts5SavepointMethod, |
| /* xRelease */ fts5ReleaseMethod, |
| /* xRollbackTo */ fts5RollbackToMethod, |
| /* xShadowName */ fts5ShadowName, |
| - /* xIntegrity */ fts5Integrity |
| + /* xIntegrity */ fts5IntegrityMethod |
| }; |
| |
| int rc; |
| Fts5Global *pGlobal = 0; |
| |
| |
| --- a/ext/fts5/test/fts5misc.test |
| +++ b/ext/fts5/test/fts5misc.test |
| @@ -89,11 +89,10 @@ |
| CREATE VIRTUAL TABLE vt0 USING fts5(c0); |
| BEGIN TRANSACTION; |
| INSERT INTO vt0(c0) VALUES ('xyz'); |
| } |
| |
| -breakpoint |
| do_execsql_test 2.2.2 { |
| ALTER TABLE t0 RENAME TO t1; |
| } |
| do_execsql_test 2.2.3 { |
| INSERT INTO vt0(vt0) VALUES('integrity-check'); |
| @@ -498,8 +497,23 @@ |
| } {assertionfaultproblem} |
| do_execsql_test 17.5 { |
| SELECT c0 FROM t0 WHERE c0 GLOB '*faul*'; |
| } {assertionfaultproblem} |
| |
| +#------------------------------------------------------------------------- |
| +reset_db |
| +do_execsql_test 18.0 { |
| + BEGIN; |
| + CREATE VIRTUAL TABLE t1 USING fts5(text); |
| + ALTER TABLE t1 RENAME TO t2; |
| +} |
| + |
| +do_execsql_test 18.1 { |
| + DROP TABLE t2; |
| +} |
| + |
| +do_execsql_test 18.2 { |
| + COMMIT; |
| +} |
| |
| finish_test |
| |
| |