diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index 6606c8dd0..eb56d429d 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -296,9 +296,11 @@ impl Connection { impl Drop for Connection { fn drop(&mut self) { - self.conn - .close() - .expect("Failed to drop (close) connection"); + if Arc::strong_count(&self.conn) == 1 { + self.conn + .close() + .expect("Failed to drop (close) connection"); + } } } diff --git a/core/lib.rs b/core/lib.rs index 7f63d1b3c..6e2fb82a7 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -280,6 +280,7 @@ impl Database { readonly: Cell::new(false), wal_checkpoint_disabled: Cell::new(false), capture_data_changes: RefCell::new(CaptureDataChangesMode::Off), + closed: Cell::new(false), }); if let Err(e) = conn.register_builtins() { return Err(LimboError::ExtensionError(e)); @@ -333,6 +334,7 @@ impl Database { readonly: Cell::new(false), wal_checkpoint_disabled: Cell::new(false), capture_data_changes: RefCell::new(CaptureDataChangesMode::Off), + closed: Cell::new(false), }); if let Err(e) = conn.register_builtins() { @@ -487,6 +489,7 @@ pub struct Connection { readonly: Cell, wal_checkpoint_disabled: Cell, capture_data_changes: RefCell, + closed: Cell, } impl Connection { @@ -739,6 +742,8 @@ impl Connection { /// Close a connection and checkpoint. pub fn close(&self) -> Result<()> { + turso_assert!(!self.closed.get(), "Connection already closed"); + self.closed.set(true); self.pager .checkpoint_shutdown(self.wal_checkpoint_disabled.get()) } diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 3750fcfec..8e3c4427d 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -380,6 +380,14 @@ impl Program { pager: Rc, ) -> Result { loop { + if *self.connection.closed.borrow() { + // Connection is closed for whatever reason, rollback the transaction. + let state = self.connection.transaction_state.get(); + if let TransactionState::Write { schema_did_change } = state { + pager.rollback(schema_did_change, &self.connection)? + } + return Err(LimboError::InternalError("Connection closed".to_string())); + } if state.is_interrupted() { return Ok(StepResult::Interrupt); }