mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Instead of disallowing writes to fts5 tables if there are fts5vocab cursors open on them (commit [c49a6ed7]), abort any fts5vocab queries if the on-disk structure of the fts5 table changes.
FossilOrigin-Name: 9dbdc9001e3258e71ca995fbcdebf66ab95890ded87fa7125c6cb4bd43010aaf
This commit is contained in:
@ -435,6 +435,9 @@ void sqlite3Fts5IndexCloseReader(Fts5Index*);
|
||||
*/
|
||||
const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*);
|
||||
int sqlite3Fts5IterNextScan(Fts5IndexIter*);
|
||||
void *sqlite3Fts5StructureRef(Fts5Index*);
|
||||
void sqlite3Fts5StructureRelease(void*);
|
||||
int sqlite3Fts5StructureTest(Fts5Index*, void*);
|
||||
|
||||
|
||||
/*
|
||||
@ -564,7 +567,6 @@ int sqlite3Fts5GetTokenizer(
|
||||
Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
|
||||
|
||||
int sqlite3Fts5FlushToDisk(Fts5Table*);
|
||||
void sqlite3Fts5VocabLock(Fts5Table*, int);
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5.c.
|
||||
|
@ -821,6 +821,22 @@ static void fts5StructureRef(Fts5Structure *pStruct){
|
||||
pStruct->nRef++;
|
||||
}
|
||||
|
||||
void *sqlite3Fts5StructureRef(Fts5Index *p){
|
||||
fts5StructureRef(p->pStruct);
|
||||
return (void*)p->pStruct;
|
||||
}
|
||||
void sqlite3Fts5StructureRelease(void *p){
|
||||
if( p ){
|
||||
fts5StructureRelease((Fts5Structure*)p);
|
||||
}
|
||||
}
|
||||
int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){
|
||||
if( p->pStruct!=(Fts5Structure*)pStruct ){
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Deserialize and return the structure record currently stored in serialized
|
||||
** form within buffer pData/nData.
|
||||
|
@ -117,7 +117,6 @@ struct Fts5FullTable {
|
||||
Fts5Storage *pStorage; /* Document store */
|
||||
Fts5Global *pGlobal; /* Global (connection wide) data */
|
||||
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
|
||||
int nVocabLock; /* Number of locks held by fts5vocab csrs */
|
||||
#ifdef SQLITE_DEBUG
|
||||
struct Fts5TransactionState ts;
|
||||
#endif
|
||||
@ -1635,9 +1634,7 @@ static int fts5UpdateMethod(
|
||||
assert( pTab->p.pConfig->pzErrmsg==0 );
|
||||
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
|
||||
/* Return an error if there are any fts5vocab cursors open. Put any active
|
||||
** fts5 cursors into REQUIRE_SEEK state. */
|
||||
if( pTab->nVocabLock ) return SQLITE_LOCKED;
|
||||
/* Put any active cursors into REQUIRE_SEEK state. */
|
||||
fts5TripCursors(pTab);
|
||||
|
||||
eType0 = sqlite3_value_type(apVal[0]);
|
||||
@ -2561,17 +2558,6 @@ int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
|
||||
return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Take (bUnlock==0) or release (bUnlock==1) a vocab lock on the table
|
||||
** passed as the only argument. It is not possible to modify the
|
||||
** structure of the table if there are one or more vocab locks.
|
||||
*/
|
||||
void sqlite3Fts5VocabLock(Fts5Table *pVtab, int bUnlock){
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
pTab->nVocabLock += (bUnlock ? -1 : +1);
|
||||
assert( pTab->nVocabLock>=0 );
|
||||
}
|
||||
|
||||
/*
|
||||
** The xSavepoint() method.
|
||||
**
|
||||
|
@ -60,6 +60,7 @@ struct Fts5VocabCursor {
|
||||
|
||||
int bEof; /* True if this cursor is at EOF */
|
||||
Fts5IndexIter *pIter; /* Term/rowid iterator object */
|
||||
void *pStruct; /* From sqlite3Fts5StructureRef() */
|
||||
|
||||
int nLeTerm; /* Size of zLeTerm in bytes */
|
||||
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
|
||||
@ -382,7 +383,6 @@ static int fts5VocabOpenMethod(
|
||||
pCsr->pStmt = pStmt;
|
||||
pCsr->aCnt = (i64*)&pCsr[1];
|
||||
pCsr->aDoc = &pCsr->aCnt[pFts5->pConfig->nCol];
|
||||
sqlite3Fts5VocabLock(pFts5, 0);
|
||||
}else{
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
@ -394,6 +394,8 @@ static int fts5VocabOpenMethod(
|
||||
static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
pCsr->rowid = 0;
|
||||
sqlite3Fts5IterClose(pCsr->pIter);
|
||||
sqlite3Fts5StructureRelease(pCsr->pStruct);
|
||||
pCsr->pStruct = 0;
|
||||
pCsr->pIter = 0;
|
||||
sqlite3_free(pCsr->zLeTerm);
|
||||
pCsr->nLeTerm = -1;
|
||||
@ -408,7 +410,6 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
||||
fts5VocabResetCursor(pCsr);
|
||||
sqlite3Fts5VocabLock(pCsr->pFts5, 1);
|
||||
sqlite3Fts5BufferFree(&pCsr->term);
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
sqlite3_free(pCsr);
|
||||
@ -472,9 +473,11 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
|
||||
static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
||||
Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
int nCol = pCsr->pFts5->pConfig->nCol;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3Fts5StructureTest(pCsr->pFts5->pIndex, pCsr->pStruct);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
pCsr->rowid++;
|
||||
|
||||
if( pTab->eType==FTS5_VOCAB_INSTANCE ){
|
||||
@ -648,6 +651,9 @@ static int fts5VocabFilterMethod(
|
||||
if( rc==SQLITE_OK ){
|
||||
Fts5Index *pIndex = pCsr->pFts5->pIndex;
|
||||
rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
|
||||
if( rc==SQLITE_OK ){
|
||||
pCsr->pStruct = sqlite3Fts5StructureRef(pIndex);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
|
||||
rc = fts5VocabInstanceNewTerm(pCsr);
|
||||
|
@ -15364,7 +15364,7 @@ do_execsql_test 79.1 {
|
||||
|
||||
do_catchsql_test 79.2 {
|
||||
INSERT INTO t1(t1) SELECT 'merge' FROM t2;
|
||||
} {1 {database table is locked}}
|
||||
} {1 {query aborted}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
|
@ -234,4 +234,27 @@ ifcapable fts3 {
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the fts5 table cannot be written while there are vocab
|
||||
# cursors open.
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
|
||||
INSERT INTO t1 VALUES('one'), ('two'), ('three'), ('four');
|
||||
}
|
||||
|
||||
do_test 5.1 {
|
||||
list [catch {
|
||||
db eval { SELECT * FROM v1 } {
|
||||
db eval {INSERT INTO t1 VALUES('five')}
|
||||
}
|
||||
} msg] $msg
|
||||
} {1 {query aborted}}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
SELECT * FROM t1
|
||||
} {one two three four five}
|
||||
finish_test
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user