diff --git a/src/error.rs b/src/error.rs index 797a216..ab89c22 100644 --- a/src/error.rs +++ b/src/error.rs @@ -443,3 +443,25 @@ pub fn check(code: c_int) -> Result<()> { Ok(()) } } + +/// Transform Rust error to SQLite error (message and code). +/// # Safety +/// This function is unsafe because it uses raw pointer +pub unsafe fn to_sqlite_error( + e: &Error, + err_msg: *mut *mut std::os::raw::c_char, +) -> std::os::raw::c_int { + use crate::util::alloc; + match e { + Error::SqliteFailure(err, s) => { + if let Some(s) = s { + *err_msg = alloc(s); + } + err.extended_code + } + err => { + *err_msg = alloc(&err.to_string()); + ffi::SQLITE_ERROR + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 11e1ad4..4d42287 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ use crate::types::ValueRef; pub use crate::cache::CachedStatement; pub use crate::column::Column; -pub use crate::error::Error; +pub use crate::error::{to_sqlite_error, Error}; pub use crate::ffi::ErrorCode; #[cfg(feature = "load_extension")] pub use crate::load_extension_guard::LoadExtensionGuard; diff --git a/src/util/mod.rs b/src/util/mod.rs index e81e3c0..a759cb9 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -6,4 +6,4 @@ pub(crate) use small_cstr::SmallCString; // Doesn't use any modern features or vtab stuff, but is only used by them. mod sqlite_string; -pub(crate) use sqlite_string::SqliteMallocString; +pub(crate) use sqlite_string::{alloc, SqliteMallocString}; diff --git a/src/util/sqlite_string.rs b/src/util/sqlite_string.rs index ae24c28..783d120 100644 --- a/src/util/sqlite_string.rs +++ b/src/util/sqlite_string.rs @@ -7,6 +7,12 @@ use std::marker::PhantomData; use std::os::raw::{c_char, c_int}; use std::ptr::NonNull; +// Space to hold this string must be obtained +// from an SQLite memory allocation function +pub(crate) fn alloc(s: &str) -> *mut c_char { + SqliteMallocString::from_str(s).into_raw() +} + /// A string we own that's allocated on the SQLite heap. Automatically calls /// `sqlite3_free` when dropped, unless `into_raw` (or `into_inner`) is called /// on it. If constructed from a rust string, `sqlite3_malloc` is used. diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index 4eaaee3..7e2f5f5 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -17,10 +17,11 @@ use std::ptr; use std::slice; use crate::context::set_result; -use crate::error::error_from_sqlite_code; +use crate::error::{error_from_sqlite_code, to_sqlite_error}; use crate::ffi; pub use crate::ffi::{sqlite3_vtab, sqlite3_vtab_cursor}; use crate::types::{FromSql, FromSqlError, ToSql, ValueRef}; +use crate::util::alloc; use crate::{str_to_cstring, Connection, Error, InnerConnection, Result}; // let conn: Connection = ...; @@ -964,8 +965,7 @@ where ffi::SQLITE_OK } else { let err = error_from_sqlite_code(rc, None); - *err_msg = alloc(&err.to_string()); - rc + to_sqlite_error(&err, err_msg) } } Err(err) => { @@ -973,16 +973,7 @@ where ffi::SQLITE_ERROR } }, - Err(Error::SqliteFailure(err, s)) => { - if let Some(s) = s { - *err_msg = alloc(&s); - } - err.extended_code - } - Err(err) => { - *err_msg = alloc(&err.to_string()); - ffi::SQLITE_ERROR - } + Err(err) => to_sqlite_error(&err, err_msg), } } @@ -1016,8 +1007,7 @@ where ffi::SQLITE_OK } else { let err = error_from_sqlite_code(rc, None); - *err_msg = alloc(&err.to_string()); - rc + to_sqlite_error(&err, err_msg) } } Err(err) => { @@ -1025,16 +1015,7 @@ where ffi::SQLITE_ERROR } }, - Err(Error::SqliteFailure(err, s)) => { - if let Some(s) = s { - *err_msg = alloc(&s); - } - err.extended_code - } - Err(err) => { - *err_msg = alloc(&err.to_string()); - ffi::SQLITE_ERROR - } + Err(err) => to_sqlite_error(&err, err_msg), } } @@ -1311,12 +1292,6 @@ unsafe fn result_error(ctx: *mut ffi::sqlite3_context, result: Result) -> } } -// Space to hold this string must be obtained -// from an SQLite memory allocation function -fn alloc(s: &str) -> *mut c_char { - crate::util::SqliteMallocString::from_str(s).into_raw() -} - #[cfg(feature = "array")] #[cfg_attr(docsrs, doc(cfg(feature = "array")))] pub mod array;