diff options
Diffstat (limited to 'src/raw_statement.rs')
-rw-r--r-- | src/raw_statement.rs | 78 |
1 files changed, 63 insertions, 15 deletions
diff --git a/src/raw_statement.rs b/src/raw_statement.rs index c02dcd9..8e624dc 100644 --- a/src/raw_statement.rs +++ b/src/raw_statement.rs @@ -1,6 +1,6 @@ use super::ffi; -use super::unlock_notify; use super::StatementStatus; +use crate::util::ParamIndexCache; #[cfg(feature = "modern_sqlite")] use crate::util::SqliteMallocString; use std::ffi::CStr; @@ -14,7 +14,7 @@ pub struct RawStatement { ptr: *mut ffi::sqlite3_stmt, tail: usize, // Cached indices of named parameters, computed on the fly. - cache: crate::util::ParamIndexCache, + cache: ParamIndexCache, // Cached SQL (trimmed) that we use as the key when we're in the statement // cache. This is None for statements which didn't come from the statement // cache. @@ -29,40 +29,48 @@ pub struct RawStatement { } impl RawStatement { + #[inline] pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt, tail: usize) -> RawStatement { RawStatement { ptr: stmt, tail, - cache: Default::default(), + cache: ParamIndexCache::default(), statement_cache_key: None, } } + #[inline] pub fn is_null(&self) -> bool { self.ptr.is_null() } + #[inline] pub(crate) fn set_statement_cache_key(&mut self, p: impl Into<Arc<str>>) { self.statement_cache_key = Some(p.into()); } + #[inline] pub(crate) fn statement_cache_key(&self) -> Option<Arc<str>> { self.statement_cache_key.clone() } + #[inline] pub unsafe fn ptr(&self) -> *mut ffi::sqlite3_stmt { self.ptr } + #[inline] pub fn column_count(&self) -> usize { // Note: Can't cache this as it changes if the schema is altered. unsafe { ffi::sqlite3_column_count(self.ptr) as usize } } + #[inline] pub fn column_type(&self, idx: usize) -> c_int { unsafe { ffi::sqlite3_column_type(self.ptr, idx as c_int) } } + #[inline] #[cfg(feature = "column_decltype")] pub fn column_decltype(&self, idx: usize) -> Option<&CStr> { unsafe { @@ -75,6 +83,7 @@ impl RawStatement { } } + #[inline] pub fn column_name(&self, idx: usize) -> Option<&CStr> { let idx = idx as c_int; if idx < 0 || idx >= self.column_count() as c_int { @@ -92,35 +101,52 @@ impl RawStatement { } } + #[inline] + #[cfg(not(feature = "unlock_notify"))] pub fn step(&self) -> c_int { - if cfg!(feature = "unlock_notify") { - let db = unsafe { ffi::sqlite3_db_handle(self.ptr) }; - let mut rc; - loop { - rc = unsafe { ffi::sqlite3_step(self.ptr) }; - if unsafe { !unlock_notify::is_locked(db, rc) } { - break; + unsafe { ffi::sqlite3_step(self.ptr) } + } + + #[cfg(feature = "unlock_notify")] + pub fn step(&self) -> c_int { + use crate::unlock_notify; + let mut db = core::ptr::null_mut::<ffi::sqlite3>(); + loop { + unsafe { + let mut rc = ffi::sqlite3_step(self.ptr); + // Bail out early for success and errors unrelated to locking. We + // still need check `is_locked` after this, but checking now lets us + // avoid one or two (admittedly cheap) calls into SQLite that we + // don't need to make. + if (rc & 0xff) != ffi::SQLITE_LOCKED { + break rc; + } + if db.is_null() { + db = ffi::sqlite3_db_handle(self.ptr); } - rc = unsafe { unlock_notify::wait_for_unlock_notify(db) }; + if !unlock_notify::is_locked(db, rc) { + break rc; + } + rc = unlock_notify::wait_for_unlock_notify(db); if rc != ffi::SQLITE_OK { - break; + break rc; } self.reset(); } - rc - } else { - unsafe { ffi::sqlite3_step(self.ptr) } } } + #[inline] pub fn reset(&self) -> c_int { unsafe { ffi::sqlite3_reset(self.ptr) } } + #[inline] pub fn bind_parameter_count(&self) -> usize { unsafe { ffi::sqlite3_bind_parameter_count(self.ptr) as usize } } + #[inline] pub fn bind_parameter_index(&self, name: &str) -> Option<usize> { self.cache.get_or_insert_with(name, |param_cstr| { let r = unsafe { ffi::sqlite3_bind_parameter_index(self.ptr, param_cstr.as_ptr()) }; @@ -131,10 +157,24 @@ impl RawStatement { }) } + #[inline] + pub fn bind_parameter_name(&self, index: i32) -> Option<&CStr> { + unsafe { + let name = ffi::sqlite3_bind_parameter_name(self.ptr, index); + if name.is_null() { + None + } else { + Some(CStr::from_ptr(name)) + } + } + } + + #[inline] pub fn clear_bindings(&self) -> c_int { unsafe { ffi::sqlite3_clear_bindings(self.ptr) } } + #[inline] pub fn sql(&self) -> Option<&CStr> { if self.ptr.is_null() { None @@ -143,36 +183,44 @@ impl RawStatement { } } + #[inline] pub fn finalize(mut self) -> c_int { self.finalize_() } + #[inline] fn finalize_(&mut self) -> c_int { let r = unsafe { ffi::sqlite3_finalize(self.ptr) }; self.ptr = ptr::null_mut(); r } + // does not work for PRAGMA + #[inline] #[cfg(all(feature = "extra_check", feature = "modern_sqlite"))] // 3.7.4 pub fn readonly(&self) -> bool { unsafe { ffi::sqlite3_stmt_readonly(self.ptr) != 0 } } + #[inline] #[cfg(feature = "modern_sqlite")] // 3.14.0 pub(crate) fn expanded_sql(&self) -> Option<SqliteMallocString> { unsafe { SqliteMallocString::from_raw(ffi::sqlite3_expanded_sql(self.ptr)) } } + #[inline] pub fn get_status(&self, status: StatementStatus, reset: bool) -> i32 { assert!(!self.ptr.is_null()); unsafe { ffi::sqlite3_stmt_status(self.ptr, status as i32, reset as i32) } } + #[inline] #[cfg(feature = "extra_check")] pub fn has_tail(&self) -> bool { self.tail != 0 } + #[inline] pub fn tail(&self) -> usize { self.tail } |