From 6d795caaedc233266a62966ef045ed7981248e21 Mon Sep 17 00:00:00 2001 From: Joshua Schneider Date: Wed, 4 Feb 2015 21:08:44 +0100 Subject: [PATCH 1/9] Implement standard Error trait for SqliteError --- src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb1a4f6..903793c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ extern crate libc; use std::mem; use std::ptr; use std::fmt; +use std::error; use std::rc::{Rc}; use std::cell::{RefCell, Cell}; use std::ffi::{CString}; @@ -100,8 +101,14 @@ pub struct SqliteError { } impl fmt::Display for SqliteError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "SqliteError( code: {}, message: {} )", self.code, self.message) + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} (SQLite error {})", self.message, self.code) + } +} + +impl error::Error for SqliteError { + fn description(&self) -> &str { + ffi::code_to_str(self.code) } } From 937eedbe6179bea851db0b6243334a059f615666 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Fri, 13 Feb 2015 15:44:24 -0500 Subject: [PATCH 2/9] Fix for latest rustc changes --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index cb1a4f6..ecfd540 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -311,7 +311,8 @@ impl SqliteConnection { /// This is functionally equivalent to the `Drop` implementation for `SqliteConnection` except /// that it returns any error encountered to the caller. pub fn close(self) -> SqliteResult<()> { - self.db.borrow_mut().close() + let mut db = self.db.borrow_mut(); + db.close() } fn decode_result(&self, code: c_int) -> SqliteResult<()> { From 7a430c0fde58be3598f4118f82325be491362750 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Fri, 13 Feb 2015 15:48:11 -0500 Subject: [PATCH 3/9] Use existing message instead of `ffi::code_to_str` in Error trait --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 24ad3cf..2efedb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ impl fmt::Display for SqliteError { impl error::Error for SqliteError { fn description(&self) -> &str { - ffi::code_to_str(self.code) + self.message.as_slice() } } From 31ea62a176dbf2b796de378c30c676dcaf66a80a Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Fri, 13 Feb 2015 15:49:16 -0500 Subject: [PATCH 4/9] Bump version to 0.0.9 --- Cargo.toml | 2 +- Changelog.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d62c270..0d322ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusqlite" -version = "0.0.8" +version = "0.0.9" authors = ["John Gallagher "] description = "Ergonomic wrapper for SQLite" homepage = "https://github.com/jgallagher/rusqlite" diff --git a/Changelog.md b/Changelog.md index 395d447..3ee1ed3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,8 @@ +# Version 0.0.9 (2015-02-13) + +* Updates to track latest rustc changes. +* Implement standard `Error` trait for `SqliteError`. + # Version 0.0.8 (2015-02-04) * Updates to track latest rustc changes. From 03f368c4f439ec7f7b960013833adab74b9d811b Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Mon, 23 Feb 2015 15:22:34 -0500 Subject: [PATCH 5/9] Build raw sqlite interface as libsqlite3-sys Use pkg-config to find it. --- Cargo.toml | 3 +++ build.rs | 5 +++++ libsqlite3-sys/.gitignore | 3 +++ libsqlite3-sys/Cargo.toml | 11 +++++++++++ libsqlite3-sys/build.rs | 5 +++++ {src/ffi => libsqlite3-sys/src}/bindgen.rs | 3 +-- src/ffi/mod.rs => libsqlite3-sys/src/lib.rs | 6 ++++++ src/lib.rs | 5 ++--- 8 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 build.rs create mode 100644 libsqlite3-sys/.gitignore create mode 100644 libsqlite3-sys/Cargo.toml create mode 100644 libsqlite3-sys/build.rs rename {src/ffi => libsqlite3-sys/src}/bindgen.rs (99%) rename src/ffi/mod.rs => libsqlite3-sys/src/lib.rs (98%) diff --git a/Cargo.toml b/Cargo.toml index 0d322ba..11cc6a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,6 @@ name = "rusqlite" [dependencies] time = "~0.1.0" bitflags = "~0.1" + +[dependencies.libsqlite3-sys] +path = "libsqlite3-sys" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..5001b67 --- /dev/null +++ b/build.rs @@ -0,0 +1,5 @@ +extern crate "pkg-config" as pkg_config; + +fn main() { + pkg_config::find_library("sqlite3").unwrap(); +} diff --git a/libsqlite3-sys/.gitignore b/libsqlite3-sys/.gitignore new file mode 100644 index 0000000..5f0a3e1 --- /dev/null +++ b/libsqlite3-sys/.gitignore @@ -0,0 +1,3 @@ +/target/ +/doc/ +Cargo.lock diff --git a/libsqlite3-sys/Cargo.toml b/libsqlite3-sys/Cargo.toml new file mode 100644 index 0000000..149c3f6 --- /dev/null +++ b/libsqlite3-sys/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "libsqlite3-sys" +version = "0.0.9" +authors = ["John Gallagher "] +description = "Native bindings to the libsqlite3 library" +license = "MIT" +links = "sqlite3" +build = "build.rs" + +[build-dependencies] +pkg-config = "~0.2" diff --git a/libsqlite3-sys/build.rs b/libsqlite3-sys/build.rs new file mode 100644 index 0000000..5001b67 --- /dev/null +++ b/libsqlite3-sys/build.rs @@ -0,0 +1,5 @@ +extern crate "pkg-config" as pkg_config; + +fn main() { + pkg_config::find_library("sqlite3").unwrap(); +} diff --git a/src/ffi/bindgen.rs b/libsqlite3-sys/src/bindgen.rs similarity index 99% rename from src/ffi/bindgen.rs rename to libsqlite3-sys/src/bindgen.rs index e6d3871..b79b0f8 100644 --- a/src/ffi/bindgen.rs +++ b/libsqlite3-sys/src/bindgen.rs @@ -1,4 +1,4 @@ -#![allow(raw_pointer_derive)] +#![allow(raw_pointer_derive, non_snake_case, non_camel_case_types)] /* Running `target/bindgen /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/sqlite3.h -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/6.0/include` */ /* automatically generated by rust-bindgen */ @@ -521,7 +521,6 @@ pub struct Struct_sqlite3_rtree_geometry { pub xDelUser: ::std::option::Option, } -#[link(name = "sqlite3")] extern "C" { pub static mut sqlite3_version: *const ::libc::c_char; pub static mut sqlite3_temp_directory: *mut ::libc::c_char; diff --git a/src/ffi/mod.rs b/libsqlite3-sys/src/lib.rs similarity index 98% rename from src/ffi/mod.rs rename to libsqlite3-sys/src/lib.rs index 62213a9..8f4712d 100644 --- a/src/ffi/mod.rs +++ b/libsqlite3-sys/src/lib.rs @@ -1,4 +1,10 @@ +#![feature(libc)] +#![allow(non_snake_case)] + +extern crate libc; + pub use self::bindgen::*; + use std::mem; use libc::{c_int, c_void}; diff --git a/src/lib.rs b/src/lib.rs index 2efedb7..a911809 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,6 +52,7 @@ #![cfg_attr(test, feature(test))] extern crate libc; +extern crate "libsqlite3-sys" as ffi; #[macro_use] extern crate rustc_bitflags; use std::mem; @@ -76,9 +77,6 @@ pub use transaction::{SqliteTransactionBehavior, pub mod types; mod transaction; -/// Automatically generated FFI bindings (via [bindgen](https://github.com/crabtw/rust-bindgen)). -#[allow(dead_code,non_snake_case,non_camel_case_types)] pub mod ffi; - /// A typedef of the result returned by many methods. pub type SqliteResult = Result; @@ -705,6 +703,7 @@ impl<'stmt> SqliteRow<'stmt> { #[cfg(test)] mod test { + extern crate "libsqlite3-sys" as ffi; use super::*; fn checked_memory_handle() -> SqliteConnection { From 1097842a85eef51c9fb893ca84ef6ad87ccb1c31 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Mon, 23 Feb 2015 19:32:53 -0500 Subject: [PATCH 6/9] Put sqlite3 extension functions behind a feature --- libsqlite3-sys/Cargo.toml | 3 +++ libsqlite3-sys/src/bindgen.rs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libsqlite3-sys/Cargo.toml b/libsqlite3-sys/Cargo.toml index 149c3f6..d0fbf75 100644 --- a/libsqlite3-sys/Cargo.toml +++ b/libsqlite3-sys/Cargo.toml @@ -7,5 +7,8 @@ license = "MIT" links = "sqlite3" build = "build.rs" +[features] +load_extension = [] + [build-dependencies] pkg-config = "~0.2" diff --git a/libsqlite3-sys/src/bindgen.rs b/libsqlite3-sys/src/bindgen.rs index b79b0f8..c9807b8 100644 --- a/libsqlite3-sys/src/bindgen.rs +++ b/libsqlite3-sys/src/bindgen.rs @@ -1,6 +1,5 @@ #![allow(raw_pointer_derive, non_snake_case, non_camel_case_types)] /* Running `target/bindgen /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/sqlite3.h -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/6.0/include` */ -/* automatically generated by rust-bindgen */ #[derive(Copy)] pub enum Struct_sqlite3 { } @@ -1588,11 +1587,13 @@ extern "C" { pPrimaryKey: *mut ::libc::c_int, pAutoinc: *mut ::libc::c_int) -> ::libc::c_int; + #[cfg(feature = "load_extension")] pub fn sqlite3_load_extension(db: *mut sqlite3, zFile: *const ::libc::c_char, zProc: *const ::libc::c_char, pzErrMsg: *mut *mut ::libc::c_char) -> ::libc::c_int; + #[cfg(feature = "load_extension")] pub fn sqlite3_enable_load_extension(db: *mut sqlite3, onoff: ::libc::c_int) -> ::libc::c_int; From 348f94e1092352c565c0cc07b9b676b6fb5cc78e Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Mon, 23 Feb 2015 19:52:48 -0500 Subject: [PATCH 7/9] Add public API for loading extensions --- Cargo.toml | 3 ++ src/lib.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11cc6a0..0d43f1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ license = "MIT" [lib] name = "rusqlite" +[features] +load_extension = ["libsqlite3-sys/load_extension"] + [dependencies] time = "~0.1.0" bitflags = "~0.1" diff --git a/src/lib.rs b/src/lib.rs index a911809..30a2c46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ //! } //! } //! ``` -#![feature(unsafe_destructor, core, std_misc, libc, rustc_private, collections, hash)] +#![feature(unsafe_destructor, core, std_misc, path, libc, rustc_private, collections, hash)] #![cfg_attr(test, feature(test))] extern crate libc; @@ -58,11 +58,11 @@ extern crate "libsqlite3-sys" as ffi; use std::mem; use std::ptr; use std::fmt; +use std::path::{Path}; use std::error; use std::rc::{Rc}; use std::cell::{RefCell, Cell}; -use std::ffi::{CString}; -use std::ffi as std_ffi; +use std::ffi::{CStr, CString}; use std::str; use libc::{c_int, c_void, c_char}; @@ -81,7 +81,7 @@ mod transaction; pub type SqliteResult = Result; unsafe fn errmsg_to_string(errmsg: *const c_char) -> String { - let c_slice = std_ffi::c_str_to_bytes(&errmsg); + let c_slice = CStr::from_ptr(errmsg).to_bytes(); let utf8_str = str::from_utf8(c_slice); utf8_str.unwrap_or("Invalid string encoding").to_string() } @@ -121,6 +121,21 @@ impl SqliteError { } } +fn str_to_cstring(s: &str) -> SqliteResult { + CString::new(s).map_err(|_| SqliteError{ + code: ffi::SQLITE_MISUSE, + message: "Could not convert path to C-combatible string".to_string() + }) +} + +fn path_to_cstring(p: &Path) -> SqliteResult { + let s = try!(p.to_str().ok_or(SqliteError{ + code: ffi::SQLITE_MISUSE, + message: "Could not convert path to UTF-8 string".to_string() + })); + str_to_cstring(s) +} + /// A connection to a SQLite database. /// /// ## Warning @@ -320,6 +335,43 @@ impl SqliteConnection { db.close() } + /// Enable loading of SQLite extensions. + /// + /// ## Example + /// + /// ```rust,no_run + /// # use rusqlite::{SqliteConnection, SqliteResult}; + /// # use std::path::{Path}; + /// fn load_my_extension(conn: &SqliteConnection) -> SqliteResult<()> { + /// try!(conn.load_extension_enable()); + /// try!(conn.load_extension(Path::new("my_sqlite_extension"), None)); + /// conn.load_extension_disable() + /// } + /// ``` + #[cfg(feature = "load_extension")] + pub fn load_extension_enable(&self) -> SqliteResult<()> { + self.db.borrow_mut().enable_load_extension(1) + } + + /// Disable loading of SQLite extensions. + /// + /// See `load_extension_enable` for an example. + #[cfg(feature = "load_extension")] + pub fn load_extension_disable(&self) -> SqliteResult<()> { + self.db.borrow_mut().enable_load_extension(0) + } + + /// Load the SQLite extension at `dylib_path`. `dylib_path` is passed through to + /// `sqlite3_load_extension`, which may attempt OS-specific modifications if the file + /// cannot be loaded directly. + /// + /// If `entry_point` is `None`, SQLite will attempt to find the entry point. If it is not + /// `None`, the entry point will be passed through to `sqlite3_load_extension`. + #[cfg(feature = "load_extension")] + pub fn load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> SqliteResult<()> { + self.db.borrow_mut().load_extension(dylib_path, entry_point) + } + fn decode_result(&self, code: c_int) -> SqliteResult<()> { self.db.borrow_mut().decode_result(code) } @@ -392,6 +444,16 @@ impl InnerSqliteConnection { } } + unsafe fn decode_result_with_errmsg(&self, code: c_int, errmsg: *mut c_char) -> SqliteResult<()> { + if code == ffi::SQLITE_OK { + Ok(()) + } else { + let message = errmsg_to_string(&*errmsg); + ffi::sqlite3_free(errmsg as *mut c_void); + Err(SqliteError{ code: code, message: message }) + } + } + fn close(&mut self) -> SqliteResult<()> { let r = unsafe { ffi::sqlite3_close(self.db) }; self.db = ptr::null_mut(); @@ -403,13 +465,28 @@ impl InnerSqliteConnection { unsafe { let mut errmsg: *mut c_char = mem::uninitialized(); let r = ffi::sqlite3_exec(self.db, c_sql.as_ptr(), None, ptr::null_mut(), &mut errmsg); - if r == ffi::SQLITE_OK { - Ok(()) + self.decode_result_with_errmsg(r, errmsg) + } + } + + #[cfg(feature = "load_extension")] + fn enable_load_extension(&mut self, onoff: c_int) -> SqliteResult<()> { + let r = unsafe { ffi::sqlite3_enable_load_extension(self.db, onoff) }; + self.decode_result(r) + } + + #[cfg(feature = "load_extension")] + fn load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> SqliteResult<()> { + let dylib_str = try!(path_to_cstring(dylib_path)); + unsafe { + let mut errmsg: *mut c_char = mem::uninitialized(); + let r = if let Some(entry_point) = entry_point { + let c_entry = try!(str_to_cstring(entry_point)); + ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), c_entry.as_ptr(), &mut errmsg) } else { - let message = errmsg_to_string(&*errmsg); - ffi::sqlite3_free(errmsg as *mut c_void); - Err(SqliteError{ code: r, message: message }) - } + ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), ptr::null(), &mut errmsg) + }; + self.decode_result_with_errmsg(r, errmsg) } } From 31d629070eb9263af3bcba1f6385cd4abc70736c Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Mon, 23 Feb 2015 20:16:49 -0500 Subject: [PATCH 8/9] Add scoped guard for enabling extension loading --- src/lib.rs | 17 ++++++++++++++++- src/load_extension_guard.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/load_extension_guard.rs diff --git a/src/lib.rs b/src/lib.rs index 30a2c46..8286d7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,8 +74,11 @@ pub use transaction::{SqliteTransactionBehavior, SqliteTransactionImmediate, SqliteTransactionExclusive}; +#[cfg(feature = "load_extension")] pub use load_extension_guard::{SqliteLoadExtensionGuard}; + pub mod types; mod transaction; +#[cfg(feature = "load_extension")] mod load_extension_guard; /// A typedef of the result returned by many methods. pub type SqliteResult = Result; @@ -335,7 +338,8 @@ impl SqliteConnection { db.close() } - /// Enable loading of SQLite extensions. + /// Enable loading of SQLite extensions. Strongly consider using `SqliteLoadExtensionGuard` + /// instead of this function. /// /// ## Example /// @@ -367,6 +371,17 @@ impl SqliteConnection { /// /// If `entry_point` is `None`, SQLite will attempt to find the entry point. If it is not /// `None`, the entry point will be passed through to `sqlite3_load_extension`. + /// + /// ## Example + /// + /// ```rust,no_run + /// # use rusqlite::{SqliteConnection, SqliteResult, SqliteLoadExtensionGuard}; + /// # use std::path::{Path}; + /// fn load_my_extension(conn: &SqliteConnection) -> SqliteResult<()> { + /// let _guard = try!(SqliteLoadExtensionGuard::new(conn)); + /// + /// conn.load_extension(Path::new("my_sqlite_extension"), None) + /// } #[cfg(feature = "load_extension")] pub fn load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> SqliteResult<()> { self.db.borrow_mut().load_extension(dylib_path, entry_point) diff --git a/src/load_extension_guard.rs b/src/load_extension_guard.rs new file mode 100644 index 0000000..82a7c89 --- /dev/null +++ b/src/load_extension_guard.rs @@ -0,0 +1,34 @@ +use {SqliteResult, SqliteConnection}; + +/// RAII guard temporarily enabling SQLite extensions to be loaded. +/// +/// ## Example +/// +/// ```rust,no_run +/// # use rusqlite::{SqliteConnection, SqliteResult, SqliteLoadExtensionGuard}; +/// # use std::path::{Path}; +/// fn load_my_extension(conn: &SqliteConnection) -> SqliteResult<()> { +/// let _guard = try!(SqliteLoadExtensionGuard::new(conn)); +/// +/// conn.load_extension(Path::new("my_sqlite_extension"), None) +/// } +/// ``` +pub struct SqliteLoadExtensionGuard<'conn> { + conn: &'conn SqliteConnection, +} + +impl<'conn> SqliteLoadExtensionGuard<'conn> { + /// Attempt to enable loading extensions. Loading extensions will be disabled when this + /// guard goes out of scope. Cannot be meaningfully nested. + pub fn new(conn: &SqliteConnection) -> SqliteResult { + conn.load_extension_enable().map(|_| SqliteLoadExtensionGuard{ conn: conn }) + } +} + +#[unsafe_destructor] +#[allow(unused_must_use)] +impl<'conn> Drop for SqliteLoadExtensionGuard<'conn> { + fn drop(&mut self) { + self.conn.load_extension_disable(); + } +} From ee89f8db59bb2d40675ad7a23f8a9c0b691b55a0 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Mon, 23 Feb 2015 20:20:35 -0500 Subject: [PATCH 9/9] Fix warnings from latest rustc --- libsqlite3-sys/src/lib.rs | 2 +- src/lib.rs | 8 ++++---- src/types.rs | 15 ++++++++------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libsqlite3-sys/src/lib.rs b/libsqlite3-sys/src/lib.rs index 8f4712d..a3411c5 100644 --- a/libsqlite3-sys/src/lib.rs +++ b/libsqlite3-sys/src/lib.rs @@ -48,7 +48,7 @@ pub const SQLITE_NULL : c_int = 5; pub type SqliteDestructor = extern "C" fn(*mut c_void); pub fn SQLITE_TRANSIENT() -> SqliteDestructor { - unsafe { mem::transmute(-1is) } + unsafe { mem::transmute(-1isize) } } pub fn code_to_str(code: c_int) -> &'static str { diff --git a/src/lib.rs b/src/lib.rs index 8286d7a..2579580 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ //! } //! } //! ``` -#![feature(unsafe_destructor, core, std_misc, path, libc, rustc_private, collections, hash)] +#![feature(unsafe_destructor, core, std_misc, path, libc, rustc_private, collections)] #![cfg_attr(test, feature(test))] extern crate libc; @@ -425,7 +425,7 @@ bitflags! { impl InnerSqliteConnection { fn open_with_flags(path: &str, flags: SqliteOpenFlags) -> SqliteResult { - let c_path = CString::from_slice(path.as_bytes()); + let c_path = try!(str_to_cstring(path)); unsafe { let mut db: *mut ffi::sqlite3 = mem::uninitialized(); let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), ptr::null()); @@ -476,7 +476,7 @@ impl InnerSqliteConnection { } fn execute_batch(&mut self, sql: &str) -> SqliteResult<()> { - let c_sql = CString::from_slice(sql.as_bytes()); + let c_sql = try!(str_to_cstring(sql)); unsafe { let mut errmsg: *mut c_char = mem::uninitialized(); let r = ffi::sqlite3_exec(self.db, c_sql.as_ptr(), None, ptr::null_mut(), &mut errmsg); @@ -515,7 +515,7 @@ impl InnerSqliteConnection { conn: &'a SqliteConnection, sql: &str) -> SqliteResult> { let mut c_stmt: *mut ffi::sqlite3_stmt = unsafe { mem::uninitialized() }; - let c_sql = CString::from_slice(sql.as_bytes()); + let c_sql = try!(str_to_cstring(sql)); let r = unsafe { let len_with_nul = (sql.len() + 1) as c_int; ffi::sqlite3_prepare_v2(self.db, c_sql.as_ptr(), len_with_nul, &mut c_stmt, diff --git a/src/types.rs b/src/types.rs index b63c03a..a15f4a5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -55,12 +55,11 @@ extern crate time; use libc::{c_int, c_double, c_char}; -use std::ffi as std_ffi; -use std::ffi::{CString}; +use std::ffi::{CStr}; use std::mem; use std::str; use super::ffi; -use super::{SqliteResult, SqliteError}; +use super::{SqliteResult, SqliteError, str_to_cstring}; const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S"; @@ -90,8 +89,11 @@ raw_to_impl!(c_double, sqlite3_bind_double); impl<'a> ToSql for &'a str { unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int { - let c_str = CString::from_slice(self.as_bytes()); - ffi::sqlite3_bind_text(stmt, col, c_str.as_ptr(), -1, Some(ffi::SQLITE_TRANSIENT())) + if let Ok(c_str) = str_to_cstring(self) { + ffi::sqlite3_bind_text(stmt, col, c_str.as_ptr(), -1, Some(ffi::SQLITE_TRANSIENT())) + } else { + ffi::SQLITE_MISUSE + } } } @@ -177,8 +179,7 @@ impl FromSql for String { if c_text.is_null() { Ok("".to_string()) } else { - let c_text = c_text as *const c_char; - let c_slice = std_ffi::c_str_to_bytes(&c_text); + let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes(); let utf8_str = str::from_utf8(c_slice); utf8_str .map(|s| { s.to_string() })