diff options
Diffstat (limited to 'src/inner_connection.rs')
-rw-r--r-- | src/inner_connection.rs | 78 |
1 files changed, 69 insertions, 9 deletions
diff --git a/src/inner_connection.rs b/src/inner_connection.rs index 0ea630e..e5bc3f1 100644 --- a/src/inner_connection.rs +++ b/src/inner_connection.rs @@ -10,7 +10,7 @@ use std::sync::{Arc, Mutex}; use super::ffi; use super::str_for_sqlite; use super::{Connection, InterruptHandle, OpenFlags, Result}; -use crate::error::{error_from_handle, error_from_sqlite_code, Error}; +use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error}; use crate::raw_statement::RawStatement; use crate::statement::Statement; use crate::version::version_number; @@ -25,11 +25,11 @@ pub struct InnerConnection { // interrupt would only acquire the lock after the query's completion. interrupt_lock: Arc<Mutex<*mut ffi::sqlite3>>, #[cfg(feature = "hooks")] - pub free_commit_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>, + pub free_commit_hook: Option<unsafe fn(*mut std::os::raw::c_void)>, #[cfg(feature = "hooks")] - pub free_rollback_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>, + pub free_rollback_hook: Option<unsafe fn(*mut std::os::raw::c_void)>, #[cfg(feature = "hooks")] - pub free_update_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>, + pub free_update_hook: Option<unsafe fn(*mut std::os::raw::c_void)>, #[cfg(feature = "hooks")] pub progress_handler: Option<Box<dyn FnMut() -> bool + Send>>, #[cfg(feature = "hooks")] @@ -208,7 +208,7 @@ impl InnerConnection { Ok(()) } else { let message = super::errmsg_to_string(errmsg); - ffi::sqlite3_free(errmsg.cast::<::std::os::raw::c_void>()); + ffi::sqlite3_free(errmsg.cast::<std::os::raw::c_void>()); Err(error_from_sqlite_code(r, Some(message))) } } @@ -222,6 +222,7 @@ impl InnerConnection { let mut c_stmt = ptr::null_mut(); let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?; let mut c_tail = ptr::null(); + // TODO sqlite3_prepare_v3 (https://sqlite.org/c3ref/c_prepare_normalize.html) // 3.20.0, #728 #[cfg(not(feature = "unlock_notify"))] let r = unsafe { ffi::sqlite3_prepare_v2( @@ -255,7 +256,9 @@ impl InnerConnection { rc }; // If there is an error, *ppStmt is set to NULL. - self.decode_result(r)?; + if r != ffi::SQLITE_OK { + return Err(unsafe { error_with_offset(self.db, r, sql) }); + } // If the input text contains no SQL (if the input is an empty string or a // comment) then *ppStmt is set to NULL. let c_stmt: *mut ffi::sqlite3_stmt = c_stmt; @@ -276,8 +279,15 @@ impl InnerConnection { } #[inline] - pub fn changes(&self) -> usize { - unsafe { ffi::sqlite3_changes(self.db()) as usize } + pub fn changes(&self) -> u64 { + #[cfg(not(feature = "modern_sqlite"))] + unsafe { + ffi::sqlite3_changes(self.db()) as u64 + } + #[cfg(feature = "modern_sqlite")] // 3.37.0 + unsafe { + ffi::sqlite3_changes64(self.db()) as u64 + } } #[inline] @@ -308,6 +318,56 @@ impl InnerConnection { #[cfg(not(feature = "hooks"))] #[inline] fn remove_hooks(&mut self) {} + + #[cfg(feature = "modern_sqlite")] // 3.7.11 + pub fn db_readonly(&self, db_name: super::DatabaseName<'_>) -> Result<bool> { + let name = db_name.as_cstring()?; + let r = unsafe { ffi::sqlite3_db_readonly(self.db, name.as_ptr()) }; + match r { + 0 => Ok(false), + 1 => Ok(true), + -1 => Err(Error::SqliteFailure( + ffi::Error::new(ffi::SQLITE_MISUSE), + Some(format!("{:?} is not the name of a database", db_name)), + )), + _ => Err(error_from_sqlite_code( + r, + Some("Unexpected result".to_owned()), + )), + } + } + + #[cfg(feature = "modern_sqlite")] // 3.37.0 + pub fn txn_state( + &self, + db_name: Option<super::DatabaseName<'_>>, + ) -> Result<super::transaction::TransactionState> { + let r = if let Some(ref name) = db_name { + let name = name.as_cstring()?; + unsafe { ffi::sqlite3_txn_state(self.db, name.as_ptr()) } + } else { + unsafe { ffi::sqlite3_txn_state(self.db, ptr::null()) } + }; + match r { + 0 => Ok(super::transaction::TransactionState::None), + 1 => Ok(super::transaction::TransactionState::Read), + 2 => Ok(super::transaction::TransactionState::Write), + -1 => Err(Error::SqliteFailure( + ffi::Error::new(ffi::SQLITE_MISUSE), + Some(format!("{:?} is not the name of a valid schema", db_name)), + )), + _ => Err(error_from_sqlite_code( + r, + Some("Unexpected result".to_owned()), + )), + } + } + + #[inline] + #[cfg(feature = "release_memory")] + pub fn release_memory(&self) -> Result<()> { + self.decode_result(unsafe { ffi::sqlite3_db_release_memory(self.db) }) + } } impl Drop for InnerConnection { @@ -340,7 +400,7 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> { #[cfg(not(any(target_arch = "wasm32")))] fn ensure_safe_sqlite_threading_mode() -> Result<()> { - // Ensure SQLite was compiled in thredsafe mode. + // Ensure SQLite was compiled in threadsafe mode. if unsafe { ffi::sqlite3_threadsafe() == 0 } { return Err(Error::SqliteSingleThreadedMode); } |