From 4a7e83f0af8a1e7fab3faa7e348dcd62216409e5 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 1 Aug 2015 17:21:41 +0200 Subject: [PATCH 1/7] Feature sqlite3_{log,trace,profile}. --- Cargo.toml | 1 + libsqlite3-sys/src/lib.rs | 2 + src/lib.rs | 4 +- src/trace_extension.rs | 98 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/trace_extension.rs diff --git a/Cargo.toml b/Cargo.toml index 5d05ed5..772b4cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ name = "rusqlite" [features] load_extension = ["libsqlite3-sys/load_extension"] +trace_extension = [] [dependencies] time = "~0.1.0" diff --git a/libsqlite3-sys/src/lib.rs b/libsqlite3-sys/src/lib.rs index 5d37276..51f33c5 100644 --- a/libsqlite3-sys/src/lib.rs +++ b/libsqlite3-sys/src/lib.rs @@ -92,3 +92,5 @@ pub fn code_to_str(code: c_int) -> &'static str { _ => "Unknown error code", } } + +pub const SQLITE_CONFIG_LOG : c_int = 16; diff --git a/src/lib.rs b/src/lib.rs index f98780b..d96fdfd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ //! } //! } //! ``` +#![cfg_attr(test, feature(duration))] extern crate libc; extern crate libsqlite3_sys as ffi; #[macro_use] extern crate bitflags; @@ -79,6 +80,7 @@ pub use transaction::{SqliteTransactionBehavior, pub mod types; mod transaction; #[cfg(feature = "load_extension")] mod load_extension_guard; +#[cfg(feature = "trace_extension")] pub mod trace_extension; /// A typedef of the result returned by many methods. pub type SqliteResult = Result; @@ -664,7 +666,7 @@ impl<'conn> SqliteStatement<'conn> { } /// Executes the prepared statement and maps a function over the resulting - /// rows. + /// rows. /// /// Unlike the iterator produced by `query`, the returned iterator does not expose the possibility /// for accessing stale rows. diff --git a/src/trace_extension.rs b/src/trace_extension.rs new file mode 100644 index 0000000..cde1d75 --- /dev/null +++ b/src/trace_extension.rs @@ -0,0 +1,98 @@ +use libc::{c_char, c_int, c_void}; +use std::ffi::CString; +use std::ptr; + +use super::ffi; +use {SqliteError, SqliteResult, SqliteConnection}; + +pub type LogCallback = + Option; + +/// Set up the error logging callback +/// +/// cf [The Error And Warning Log](http://sqlite.org/errlog.html). +pub fn config_log(cb: LogCallback) -> SqliteResult<()> { + let rc = unsafe { + let p_arg: *mut c_void = ptr::null_mut(); + ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, cb, p_arg) + }; + if rc != ffi::SQLITE_OK { + return Err(SqliteError{ code: rc, message: "sqlite3_config(SQLITE_CONFIG_LOG, ...)".to_string() }); + } + Ok(()) +} + +/// Write a message into the error log established by `config_log`. +pub fn log(err_code: c_int, msg: &str) { + let msg = CString::new(msg).unwrap(); + unsafe { + ffi::sqlite3_log(err_code, msg.as_ptr()); + } +} + +pub type TraceCallback = + Option; +pub type ProfileCallback = + Option; +impl SqliteConnection { + /// Register or clear a callback function that can be used for tracing the execution of SQL statements. + /// Prepared statement placeholders are replaced/logged with their assigned values. + /// There can only be a single tracer defined for each database connection. + /// Setting a new tracer clears the old one. + pub fn trace(&mut self, x_trace: TraceCallback) { + let c = self.db.borrow_mut(); + unsafe { ffi::sqlite3_trace(c.db(), x_trace, ptr::null_mut()); } + } + /// Register or clear a callback function that can be used for profiling the execution of SQL statements. + /// There can only be a single profiler defined for each database connection. + /// Setting a new profiler clears the old one. + pub fn profile(&mut self, x_profile: ProfileCallback) { + let c = self.db.borrow_mut(); + unsafe { ffi::sqlite3_profile(c.db(), x_profile, ptr::null_mut()); } + } +} + +#[cfg(test)] +mod test { + use libc::{c_char, c_int, c_void}; + use std::ffi::CStr; + use std::io::Write; + use std::str; + + use ffi; + use SqliteConnection; + + extern "C" fn log_callback(_: *mut c_void, err: c_int, msg: *const c_char) { + unsafe { + let c_slice = CStr::from_ptr(msg).to_bytes(); + let _ = writeln!(::std::io::stderr(), "{}: {:?}", err, str::from_utf8(c_slice)); + } + } + + #[test] + fn test_log() { + if true { // To avoid freezing tests + return + } + unsafe { ffi::sqlite3_shutdown() }; + super::config_log(Some(log_callback)).unwrap(); + //super::log(ffi::SQLITE_NOTICE, "message from rusqlite"); + super::config_log(None).unwrap(); + } + + extern "C" fn profile_callback(_: *mut ::libc::c_void, sql: *const ::libc::c_char, nanoseconds: u64) { + use std::time::Duration; + unsafe { + let c_slice = ::std::ffi::CStr::from_ptr(sql).to_bytes(); + let d = Duration::from_millis(nanoseconds / 1_000_000); + let _ = writeln!(::std::io::stderr(), "PROFILE: {:?} ({})", ::std::str::from_utf8(c_slice), d); + } + } + + #[test] + fn test_profile() { + let mut db = SqliteConnection::open_in_memory().unwrap(); + db.profile(Some(profile_callback)); + db.execute_batch("PRAGMA application_id = 1").unwrap(); + } +} \ No newline at end of file From ef254fdca00d2fbf79830e0f1abb3e6dcef9f702 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 1 Aug 2015 18:58:04 +0200 Subject: [PATCH 2/7] Rename feature to 'trace' --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/{trace_extension.rs => trace.rs} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{trace_extension.rs => trace.rs} (100%) diff --git a/Cargo.toml b/Cargo.toml index 772b4cc..777d50c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ name = "rusqlite" [features] load_extension = ["libsqlite3-sys/load_extension"] -trace_extension = [] +trace = [] [dependencies] time = "~0.1.0" diff --git a/src/lib.rs b/src/lib.rs index d96fdfd..3c03fef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,7 +80,7 @@ pub use transaction::{SqliteTransactionBehavior, pub mod types; mod transaction; #[cfg(feature = "load_extension")] mod load_extension_guard; -#[cfg(feature = "trace_extension")] pub mod trace_extension; +#[cfg(feature = "trace")] pub mod trace; /// A typedef of the result returned by many methods. pub type SqliteResult = Result; diff --git a/src/trace_extension.rs b/src/trace.rs similarity index 100% rename from src/trace_extension.rs rename to src/trace.rs From 9c415f9c9e433101564767603e0be7aa341c7343 Mon Sep 17 00:00:00 2001 From: Gwenael Treguier Date: Sun, 2 Aug 2015 12:16:01 +0200 Subject: [PATCH 3/7] Remove usage of unstable library feature 'duration' --- src/lib.rs | 1 - src/trace.rs | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3c03fef..4dfd068 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,6 @@ //! } //! } //! ``` -#![cfg_attr(test, feature(duration))] extern crate libc; extern crate libsqlite3_sys as ffi; #[macro_use] extern crate bitflags; diff --git a/src/trace.rs b/src/trace.rs index cde1d75..de03742 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -80,19 +80,17 @@ mod test { super::config_log(None).unwrap(); } - extern "C" fn profile_callback(_: *mut ::libc::c_void, sql: *const ::libc::c_char, nanoseconds: u64) { - use std::time::Duration; + extern "C" fn trace_callback(_: *mut ::libc::c_void, sql: *const ::libc::c_char) { unsafe { let c_slice = ::std::ffi::CStr::from_ptr(sql).to_bytes(); - let d = Duration::from_millis(nanoseconds / 1_000_000); - let _ = writeln!(::std::io::stderr(), "PROFILE: {:?} ({})", ::std::str::from_utf8(c_slice), d); + let _ = writeln!(::std::io::stderr(), "TRACE: {:?}", ::std::str::from_utf8(c_slice)); } } #[test] - fn test_profile() { + fn test_trace() { let mut db = SqliteConnection::open_in_memory().unwrap(); - db.profile(Some(profile_callback)); + db.trace(Some(trace_callback)); db.execute_batch("PRAGMA application_id = 1").unwrap(); } } \ No newline at end of file From 59a4c5593a92c61058bff40ed64edd2a07f5423f Mon Sep 17 00:00:00 2001 From: Gwenael Treguier Date: Sat, 8 Aug 2015 09:57:07 +0200 Subject: [PATCH 4/7] Improve documentation. --- src/trace.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/trace.rs b/src/trace.rs index de03742..b3c9939 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -1,3 +1,4 @@ +//! Tracing and profiling functions. Error and warning log. use libc::{c_char, c_int, c_void}; use std::ffi::CString; use std::ptr; @@ -30,12 +31,16 @@ pub fn log(err_code: c_int, msg: &str) { } } +/// The trace callback function signature. pub type TraceCallback = Option; +/// The profile callback function signature. pub type ProfileCallback = Option; + impl SqliteConnection { /// Register or clear a callback function that can be used for tracing the execution of SQL statements. + /// /// Prepared statement placeholders are replaced/logged with their assigned values. /// There can only be a single tracer defined for each database connection. /// Setting a new tracer clears the old one. @@ -44,6 +49,7 @@ impl SqliteConnection { unsafe { ffi::sqlite3_trace(c.db(), x_trace, ptr::null_mut()); } } /// Register or clear a callback function that can be used for profiling the execution of SQL statements. + /// /// There can only be a single profiler defined for each database connection. /// Setting a new profiler clears the old one. pub fn profile(&mut self, x_profile: ProfileCallback) { From 50bfba1e1d5192aa78069bf88fdc57236f2afb38 Mon Sep 17 00:00:00 2001 From: Gwenael Treguier Date: Wed, 11 Nov 2015 14:29:40 +0100 Subject: [PATCH 5/7] Ignore test_log. --- src/trace.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/trace.rs b/src/trace.rs index b3c9939..29473a2 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -75,11 +75,8 @@ mod test { } } - #[test] + #[test] #[ignore] // To avoid freezing tests fn test_log() { - if true { // To avoid freezing tests - return - } unsafe { ffi::sqlite3_shutdown() }; super::config_log(Some(log_callback)).unwrap(); //super::log(ffi::SQLITE_NOTICE, "message from rusqlite"); @@ -99,4 +96,4 @@ mod test { db.trace(Some(trace_callback)); db.execute_batch("PRAGMA application_id = 1").unwrap(); } -} \ No newline at end of file +} From a2327fb048c96297ecad41243b4b4d04dfb7367b Mon Sep 17 00:00:00 2001 From: Gwenael Treguier Date: Wed, 11 Nov 2015 15:00:39 +0100 Subject: [PATCH 6/7] Revert "Remove usage of unstable library feature 'duration'" This reverts commit 9c415f9c9e433101564767603e0be7aa341c7343. --- src/lib.rs | 1 + src/trace.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c639831..c6f82ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ //! } //! } //! ``` +#![cfg_attr(test, feature(duration))] extern crate libc; extern crate libsqlite3_sys as ffi; #[macro_use] extern crate bitflags; diff --git a/src/trace.rs b/src/trace.rs index 29473a2..b024f13 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -83,17 +83,19 @@ mod test { super::config_log(None).unwrap(); } - extern "C" fn trace_callback(_: *mut ::libc::c_void, sql: *const ::libc::c_char) { + extern "C" fn profile_callback(_: *mut ::libc::c_void, sql: *const ::libc::c_char, nanoseconds: u64) { + use std::time::Duration; unsafe { let c_slice = ::std::ffi::CStr::from_ptr(sql).to_bytes(); - let _ = writeln!(::std::io::stderr(), "TRACE: {:?}", ::std::str::from_utf8(c_slice)); + let d = Duration::from_millis(nanoseconds / 1_000_000); + let _ = writeln!(::std::io::stderr(), "PROFILE: {:?} ({})", ::std::str::from_utf8(c_slice), d); } } #[test] - fn test_trace() { + fn test_profile() { let mut db = SqliteConnection::open_in_memory().unwrap(); - db.trace(Some(trace_callback)); + db.profile(Some(profile_callback)); db.execute_batch("PRAGMA application_id = 1").unwrap(); } } From 20c1213482ddd1bf5c19ebc4994b103f76d991f9 Mon Sep 17 00:00:00 2001 From: Gwenael Treguier Date: Wed, 11 Nov 2015 15:03:07 +0100 Subject: [PATCH 7/7] Remove feature duration. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c6f82ce..c639831 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,6 @@ //! } //! } //! ``` -#![cfg_attr(test, feature(duration))] extern crate libc; extern crate libsqlite3_sys as ffi; #[macro_use] extern crate bitflags;