mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
Fix a problem allowing a COMMIT following an OOM to cause fts3/4 corruption.
FossilOrigin-Name: 7f41d7006db4225cf9b3d197d3a76842778669ac079e76361214a8023c9976e6
This commit is contained in:
@ -3890,6 +3890,8 @@ static int fts3RenameMethod(
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
}
|
||||
|
||||
p->bIgnoreSavepoint = 1;
|
||||
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3DbExec(&rc, db,
|
||||
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
|
||||
@ -3917,6 +3919,8 @@ static int fts3RenameMethod(
|
||||
"ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
|
||||
p->zDb, p->zName, zName
|
||||
);
|
||||
|
||||
p->bIgnoreSavepoint = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3927,12 +3931,28 @@ static int fts3RenameMethod(
|
||||
*/
|
||||
static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
int rc = SQLITE_OK;
|
||||
UNUSED_PARAMETER(iSavepoint);
|
||||
assert( ((Fts3Table *)pVtab)->inTransaction );
|
||||
assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint );
|
||||
TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
|
||||
if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
|
||||
rc = fts3SyncMethod(pVtab);
|
||||
Fts3Table *pTab = (Fts3Table*)pVtab;
|
||||
assert( pTab->inTransaction );
|
||||
assert( pTab->mxSavepoint<=iSavepoint );
|
||||
TESTONLY( pTab->mxSavepoint = iSavepoint );
|
||||
|
||||
if( pTab->bIgnoreSavepoint==0 ){
|
||||
if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){
|
||||
char *zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
|
||||
pTab->zDb, pTab->zName, pTab->zName
|
||||
);
|
||||
if( zSql ){
|
||||
pTab->bIgnoreSavepoint = 1;
|
||||
rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0);
|
||||
pTab->bIgnoreSavepoint = 0;
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab->iSavepoint = iSavepoint+1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -3943,12 +3963,11 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
** This is a no-op.
|
||||
*/
|
||||
static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
|
||||
UNUSED_PARAMETER(iSavepoint);
|
||||
UNUSED_PARAMETER(pVtab);
|
||||
assert( p->inTransaction );
|
||||
assert( p->mxSavepoint >= iSavepoint );
|
||||
TESTONLY( p->mxSavepoint = iSavepoint-1 );
|
||||
Fts3Table *pTab = (Fts3Table*)pVtab;
|
||||
assert( pTab->inTransaction );
|
||||
assert( pTab->mxSavepoint >= iSavepoint );
|
||||
TESTONLY( pTab->mxSavepoint = iSavepoint-1 );
|
||||
pTab->iSavepoint = iSavepoint;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -3958,11 +3977,13 @@ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
** Discard the contents of the pending terms table.
|
||||
*/
|
||||
static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts3Table *p = (Fts3Table*)pVtab;
|
||||
Fts3Table *pTab = (Fts3Table*)pVtab;
|
||||
UNUSED_PARAMETER(iSavepoint);
|
||||
assert( p->inTransaction );
|
||||
TESTONLY( p->mxSavepoint = iSavepoint );
|
||||
sqlite3Fts3PendingTermsClear(p);
|
||||
assert( pTab->inTransaction );
|
||||
TESTONLY( pTab->mxSavepoint = iSavepoint );
|
||||
if( (iSavepoint+1)<=pTab->iSavepoint ){
|
||||
sqlite3Fts3PendingTermsClear(pTab);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -265,6 +265,7 @@ struct Fts3Table {
|
||||
int nPgsz; /* Page size for host database */
|
||||
char *zSegmentsTbl; /* Name of %_segments table */
|
||||
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
|
||||
int iSavepoint;
|
||||
|
||||
/*
|
||||
** The following array of hash tables is used to buffer pending index
|
||||
|
@ -3325,7 +3325,6 @@ int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
|
||||
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
|
||||
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
||||
}
|
||||
sqlite3Fts3PendingTermsClear(p);
|
||||
|
||||
/* Determine the auto-incr-merge setting if unknown. If enabled,
|
||||
** estimate the number of leaf blocks of content to be written
|
||||
@ -3347,6 +3346,10 @@ int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
|
||||
rc = sqlite3_reset(pStmt);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3Fts3PendingTermsClear(p);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -5437,8 +5440,11 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
rc = fts3DoIncrmerge(p, &zVal[6]);
|
||||
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
|
||||
rc = fts3DoAutoincrmerge(p, &zVal[10]);
|
||||
}else if( nVal==5 && 0==sqlite3_strnicmp(zVal, "flush", 5) ){
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
}
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
}else{
|
||||
else{
|
||||
int v;
|
||||
if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
|
||||
v = atoi(&zVal[9]);
|
||||
@ -5456,8 +5462,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2635,7 +2635,6 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
char *zSql = 0;
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
|
||||
|
||||
if( pTab->bInSavepoint==0 ){
|
||||
@ -2666,7 +2665,6 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
|
||||
if( (iSavepoint+1)<pTab->iSavepoint ){
|
||||
rc = sqlite3Fts5FlushToDisk(&pTab->p);
|
||||
@ -2685,7 +2683,6 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
pTab->p.pConfig->pgsz = 0;
|
||||
|
@ -30,7 +30,7 @@ do_execsql_test 1.0 {
|
||||
INSERT INTO t1 VALUES(' actually other stuff instead');
|
||||
}
|
||||
faultsim_save_and_close
|
||||
do_faultsim_test 1 -faults oom-t* -prep {
|
||||
do_faultsim_test 1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
BEGIN;
|
||||
|
@ -71,7 +71,7 @@ ifcapable fts3 {
|
||||
|
||||
do_catchsql_test 3.2 {
|
||||
DROP TABLE vt1;
|
||||
} {1 {SQL logic error}}
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
SAVEPOINT x;
|
||||
|
Reference in New Issue
Block a user