assert( pBuf->n<=pBuf->nSpace );
if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
}
- sqlite3Fts5HashClear(pHash);
fts5WriteFinish(p, &writer, &pgnoLast);
assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
fts5IndexCrisismerge(p, &pStruct);
fts5StructureWrite(p, pStruct);
fts5StructureRelease(pStruct);
- p->nContentlessDelete = 0;
}
/*
if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
fts5FlushOneHash(p);
- p->nPendingData = 0;
- p->nPendingRow = 0;
+ if( p->rc==SQLITE_OK ){
+ sqlite3Fts5HashClear(p->pHash);
+ p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->nContentlessDelete = 0;
+ }
}
}
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
}else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
#endif
+ }else if( 0==sqlite3_stricmp("flush", zCmd) ){
+ rc = sqlite3Fts5FlushToDisk(&pTab->p);
}else{
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
if( rc==SQLITE_OK ){
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
+ int rc;
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- return sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ pTab->bInSavepoint = 1;
+ rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ pTab->bInSavepoint = 0;
+ return rc;
}
int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
** 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;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
- return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ 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;
+ }
+ }
+
+ return rc;
}
/*
** This is a no-op.
*/
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((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
- return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
+ if( (iSavepoint+1)<pTab->iSavepoint ){
+ rc = sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint;
+ }
+ }
+ return rc;
}
/*
*/
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;
- return sqlite3Fts5StorageRollback(pTab->pStorage);
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ rc = sqlite3Fts5StorageRollback(pTab->pStorage);
+ }
+ return rc;
}
/*
i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
if( p->bTotalsValid ){
rc = fts5StorageSaveTotals(p);
- p->bTotalsValid = 0;
+ if( rc==SQLITE_OK ){
+ p->bTotalsValid = 0;
+ }
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexSync(p->pIndex);
--- /dev/null
+# 2010 June 15
+#
+# 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.
+#
+#***********************************************************************
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+source $testdir/malloc_common.tcl
+set testprefix fts5faultG
+
+# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+set ::testprefix fts5faultG
+
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a);
+ INSERT INTO t1 VALUES('test renaming the table');
+ INSERT INTO t1 VALUES(' after it has been written');
+ INSERT INTO t1 VALUES(' actually other stuff instead');
+}
+faultsim_save_and_close
+do_faultsim_test 1 -faults oom-t* -prep {
+ faultsim_restore_and_reopen
+ execsql {
+ BEGIN;
+ DELETE FROM t1 WHERE rowid=2;
+ }
+} -body {
+ execsql {
+ DELETE FROM t1;
+ }
+} -test {
+ catchsql { COMMIT }
+ faultsim_integrity_check
+ faultsim_test_result {0 {}}
+}
+
+
+finish_test
-C Fix\sPRAGMA\sintegrity_check\sso\sthat\sit\sdoes\snot\sraise\san\serror\sif\sthe\nschema\scontains\sa\sCREATE\sVIRTUAL\sTABLE\sthat\sdoes\snot\shave\sits\smodule\nloaded.
-D 2023-10-20T19:06:04.049
+C Fix\sa\sproblem\sallowing\sa\sCOMMIT\sfollowing\san\sOOM\sto\scause\sfts5\scorruption.
+D 2023-10-20T19:59:12.660
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/fts5/fts5_config.c 054359543566cbff1ba65a188330660a5457299513ac71c53b3a07d934c7b081
F ext/fts5/fts5_expr.c bd3b81ce669c4104e34ffe66570af1999a317b142c15fccb112de9fb0caa57a6
F ext/fts5/fts5_hash.c 65e7707bc8774706574346d18c20218facf87de3599b995963c3e6d6809f203d
-F ext/fts5/fts5_index.c a0f8e58e1c101d0b7959264f76b8c0c3c44914a999b29ec4264a6f55f1bccfe1
-F ext/fts5/fts5_main.c 95b479e4cc1ae5d22084caa9d85295ed759044d24a0c1679115aea4910792a1f
-F ext/fts5/fts5_storage.c 3c9b41fce41b6410f2e8f82eb035c6a29b2560483f773e6dc98cf3cb2e4ddbb5
+F ext/fts5/fts5_index.c 730c9c32ada18ce1eb7ff847b36507f4b005d88d47af7b47db521e695a8ea4c7
+F ext/fts5/fts5_main.c e345282be41c646702bbb91d488b78c35d9fa6e5a375d2809d9eb7dfbaed3314
+F ext/fts5/fts5_storage.c 5d10b9bdcce5b90656cad13c7d12ad4148677d4b9e3fca0481fca56d6601426d
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
F ext/fts5/test/fts5faultD.test e7ed7895abfe6bc98a5e853826f6b74956e7ba7f594f1860bbf9e504b9647996
F ext/fts5/test/fts5faultE.test 844586ce71dab4be85bb86880e87b624d089f851654cd22e4710c77eb8ce7075
F ext/fts5/test/fts5faultF.test 4abef99f86e99d9f0c6460dd68c586a766b6b9f1f660ada55bf2e8266bd1bbc1
+F ext/fts5/test/fts5faultG.test 7528654556b047ac515fc2790c03f71475141d5522a28edd3a6a630af269d9b1
F ext/fts5/test/fts5first.test 3fcf2365c00a15fc9704233674789a3b95131d12de18a9b996159f6909dc8079
F ext/fts5/test/fts5full.test e1701a112354e0ff9a1fdffb0c940c576530c33732ee20ac5e8361777070d717
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P b7a84eff5dcdf5b2ff81331097cdc64d0c5d16a4ae224320f39b64541ec72dc7
-R d49a86076e3848998904865202dcd417
-U drh
-Z 9b5fdaea1a9423bb5f088658371340a2
+P 5cb61c6788d7c0170b587e4667ee57d588c991a9901951762e33b97c6a135a82
+R 04eef64adc8baa80e96c39c8b85b43af
+U dan
+Z c4161b04175a3850db328dc9504c42b8
# Remove this line to create a well-formed Fossil manifest.
-5cb61c6788d7c0170b587e4667ee57d588c991a9901951762e33b97c6a135a82
\ No newline at end of file
+fba3129d1362dd3ee04d61cb3d3c48518cd98dde3febc85298f411776d60073e
\ No newline at end of file