diff --git a/core/storage/pager.rs b/core/storage/pager.rs index e809673bb..8f57577d7 100644 --- a/core/storage/pager.rs +++ b/core/storage/pager.rs @@ -817,14 +817,14 @@ impl Pager { /// Rollback to the newest savepoint. This basically just means reading the subjournal from the start offset /// of the savepoint to the end of the subjournal and restoring the page images to the page cache. - pub fn rollback_to_newest_savepoint(&self) -> Result<()> { + pub fn rollback_to_newest_savepoint(&self) -> Result { let subjournal = self.subjournal.read(); let Some(subjournal) = subjournal.as_ref() else { - return Ok(()); + return Ok(false); }; let mut savepoints = self.savepoints.write(); let Some(savepoint) = savepoints.pop() else { - return Ok(()); + return Ok(false); }; let journal_start_offset = savepoint.start_offset.load(Ordering::SeqCst); @@ -901,7 +901,7 @@ impl Pager { self.page_cache.write().truncate(db_size as usize)?; - Ok(()) + Ok(true) } #[cfg(feature = "test_helper")] diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 493e607ac..37b9924de 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -525,7 +525,12 @@ impl ProgramState { match end_statement { EndStatement::ReleaseSavepoint => pager.release_savepoint(), EndStatement::RollbackSavepoint => { - pager.rollback_to_newest_savepoint()?; + let stmt_was_rolled_back = pager.rollback_to_newest_savepoint()?; + if !stmt_was_rolled_back { + // We sometimes call end_statement() on errors without explicitly knowing whether a stmt transaction + // caused the error or not. If it didn't, don't reset any FK violation counters. + return Ok(()); + } // Reset the deferred foreign key violations counter to the value it had at the start of the statement. // This is used to ensure that if an interactive transaction had deferred FK violations, they are not lost. connection.fk_deferred_violations.store(