1
0
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:
dan
2023-10-21 18:12:07 +00:00
parent da4cfde031
commit ef6bf1bbe5
9 changed files with 66 additions and 46 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;