diff --git a/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0.rs b/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0.rs index bb6f871..6fbcd62 100644 --- a/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0.rs +++ b/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0.rs @@ -260,10 +260,10 @@ pub const SQLITE_FUNCTION: i32 = 31; pub const SQLITE_SAVEPOINT: i32 = 32; pub const SQLITE_COPY: i32 = 0; pub const SQLITE_RECURSIVE: i32 = 33; -pub const SQLITE_TRACE_STMT: i32 = 1; -pub const SQLITE_TRACE_PROFILE: i32 = 2; -pub const SQLITE_TRACE_ROW: i32 = 4; -pub const SQLITE_TRACE_CLOSE: i32 = 8; +pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; +pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; +pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; +pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; pub const SQLITE_LIMIT_LENGTH: i32 = 0; pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; pub const SQLITE_LIMIT_COLUMN: i32 = 2; diff --git a/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0_ext.rs b/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0_ext.rs index 573d196..352b9a3 100644 --- a/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0_ext.rs +++ b/libsqlite3-sys/bindgen-bindings/bindgen_3.14.0_ext.rs @@ -237,10 +237,10 @@ pub const SQLITE_FUNCTION: i32 = 31; pub const SQLITE_SAVEPOINT: i32 = 32; pub const SQLITE_COPY: i32 = 0; pub const SQLITE_RECURSIVE: i32 = 33; -pub const SQLITE_TRACE_STMT: i32 = 1; -pub const SQLITE_TRACE_PROFILE: i32 = 2; -pub const SQLITE_TRACE_ROW: i32 = 4; -pub const SQLITE_TRACE_CLOSE: i32 = 8; +pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; +pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; +pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; +pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; pub const SQLITE_LIMIT_LENGTH: i32 = 0; pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; pub const SQLITE_LIMIT_COLUMN: i32 = 2; diff --git a/libsqlite3-sys/build.rs b/libsqlite3-sys/build.rs index 6248e43..7a3d17b 100644 --- a/libsqlite3-sys/build.rs +++ b/libsqlite3-sys/build.rs @@ -507,6 +507,7 @@ mod bindings { if name == "SQLITE_SERIALIZE_NOCOPY" || name.starts_with("SQLITE_DESERIALIZE_") || name.starts_with("SQLITE_PREPARE_") + || name.starts_with("SQLITE_TRACE_") { Some(IntKind::UInt) } else { diff --git a/libsqlite3-sys/sqlcipher/bindgen_bundled_version.rs b/libsqlite3-sys/sqlcipher/bindgen_bundled_version.rs index 62bfdec..d8383c3 100644 --- a/libsqlite3-sys/sqlcipher/bindgen_bundled_version.rs +++ b/libsqlite3-sys/sqlcipher/bindgen_bundled_version.rs @@ -319,10 +319,10 @@ pub const SQLITE_FUNCTION: i32 = 31; pub const SQLITE_SAVEPOINT: i32 = 32; pub const SQLITE_COPY: i32 = 0; pub const SQLITE_RECURSIVE: i32 = 33; -pub const SQLITE_TRACE_STMT: i32 = 1; -pub const SQLITE_TRACE_PROFILE: i32 = 2; -pub const SQLITE_TRACE_ROW: i32 = 4; -pub const SQLITE_TRACE_CLOSE: i32 = 8; +pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; +pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; +pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; +pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; pub const SQLITE_LIMIT_LENGTH: i32 = 0; pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; pub const SQLITE_LIMIT_COLUMN: i32 = 2; diff --git a/libsqlite3-sys/sqlite3/bindgen_bundled_version.rs b/libsqlite3-sys/sqlite3/bindgen_bundled_version.rs index 35142f3..39c5b9a 100644 --- a/libsqlite3-sys/sqlite3/bindgen_bundled_version.rs +++ b/libsqlite3-sys/sqlite3/bindgen_bundled_version.rs @@ -319,10 +319,10 @@ pub const SQLITE_FUNCTION: i32 = 31; pub const SQLITE_SAVEPOINT: i32 = 32; pub const SQLITE_COPY: i32 = 0; pub const SQLITE_RECURSIVE: i32 = 33; -pub const SQLITE_TRACE_STMT: i32 = 1; -pub const SQLITE_TRACE_PROFILE: i32 = 2; -pub const SQLITE_TRACE_ROW: i32 = 4; -pub const SQLITE_TRACE_CLOSE: i32 = 8; +pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; +pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; +pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; +pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; pub const SQLITE_LIMIT_LENGTH: i32 = 0; pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; pub const SQLITE_LIMIT_COLUMN: i32 = 2; diff --git a/libsqlite3-sys/sqlite3/bindgen_bundled_version_ext.rs b/libsqlite3-sys/sqlite3/bindgen_bundled_version_ext.rs index b3d9faf..645eb4a 100644 --- a/libsqlite3-sys/sqlite3/bindgen_bundled_version_ext.rs +++ b/libsqlite3-sys/sqlite3/bindgen_bundled_version_ext.rs @@ -296,10 +296,10 @@ pub const SQLITE_FUNCTION: i32 = 31; pub const SQLITE_SAVEPOINT: i32 = 32; pub const SQLITE_COPY: i32 = 0; pub const SQLITE_RECURSIVE: i32 = 33; -pub const SQLITE_TRACE_STMT: i32 = 1; -pub const SQLITE_TRACE_PROFILE: i32 = 2; -pub const SQLITE_TRACE_ROW: i32 = 4; -pub const SQLITE_TRACE_CLOSE: i32 = 8; +pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; +pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; +pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; +pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; pub const SQLITE_LIMIT_LENGTH: i32 = 0; pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; pub const SQLITE_LIMIT_COLUMN: i32 = 2; diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs index 8e5f951..7cd8534 100644 --- a/src/hooks/mod.rs +++ b/src/hooks/mod.rs @@ -452,7 +452,7 @@ pub enum CheckpointMode { FULL = ffi::SQLITE_CHECKPOINT_FULL, /// Like FULL but wait for readers RESTART = ffi::SQLITE_CHECKPOINT_RESTART, - /// Like RESTART but also truncate WA + /// Like RESTART but also truncate WAL TRUNCATE = ffi::SQLITE_CHECKPOINT_TRUNCATE, } diff --git a/src/trace.rs b/src/trace.rs index c728dfa..2ec0ba9 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -2,7 +2,7 @@ use std::ffi::{CStr, CString}; use std::mem; -use std::os::raw::{c_char, c_int, c_void}; +use std::os::raw::{c_char, c_int, c_uint, c_void}; use std::panic::catch_unwind; use std::ptr; use std::time::Duration; @@ -61,6 +61,40 @@ pub fn log(err_code: c_int, msg: &str) { } } +bitflags::bitflags! { + /// Trace event codes + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] + #[non_exhaustive] + #[repr(C)] + pub struct TraceEventCodes: ::std::os::raw::c_uint { + /// Default + const NONE = 0; + /// when a prepared statement first begins running and possibly at other times during the execution + /// of the prepared statement, such as at the start of each trigger subprogram + const SQLITE_TRACE_STMT = ffi::SQLITE_TRACE_STMT; + /// when the statement finishes + const SQLITE_TRACE_PROFILE = ffi::SQLITE_TRACE_PROFILE; + /// whenever a prepared statement generates a single row of result + const SQLITE_TRACE_ROW = ffi::SQLITE_TRACE_ROW; + /// when a database connection closes + const SQLITE_TRACE_CLOSE = ffi::SQLITE_TRACE_CLOSE; + } +} + +/// Trace event +#[non_exhaustive] +pub enum TraceEvent<'s> { + /// when a prepared statement first begins running and possibly at other times during the execution + /// of the prepared statement, such as at the start of each trigger subprogram + Stmt(/*Statement,*/ &'s str), + /// when the statement finishes + Profile(/*Statement,*/ Duration), + /// whenever a prepared statement generates a single row of result + Row(/*Statement*/), + /// when a database connection closes + Close(/*Connection*/), +} + impl Connection { /// Register or clear a callback function that can be /// used for tracing the execution of SQL statements. @@ -68,6 +102,7 @@ impl Connection { /// 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. + #[deprecated(since = "0.33.0", note = "use trace_v2 instead")] pub fn trace(&mut self, trace_fn: Option) { unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) { let trace_fn: fn(&str) = mem::transmute(p_arg); @@ -91,6 +126,7 @@ impl Connection { /// /// There can only be a single profiler defined for each database /// connection. Setting a new profiler clears the old one. + #[deprecated(since = "0.33.0", note = "use trace_v2 instead")] pub fn profile(&mut self, profile_fn: Option) { unsafe extern "C" fn profile_callback( p_arg: *mut c_void, @@ -99,12 +135,8 @@ impl Connection { ) { let profile_fn: fn(&str, Duration) = mem::transmute(p_arg); let s = CStr::from_ptr(z_sql).to_string_lossy(); - const NANOS_PER_SEC: u64 = 1_000_000_000; - let duration = Duration::new( - nanoseconds / NANOS_PER_SEC, - (nanoseconds % NANOS_PER_SEC) as u32, - ); + let duration = Duration::from_nanos(nanoseconds); drop(catch_unwind(|| profile_fn(&s, duration))); } @@ -117,7 +149,45 @@ impl Connection { }; } - // TODO sqlite3_trace_v2 (https://sqlite.org/c3ref/trace_v2.html) // 3.14.0, #977 + /// Register or clear a trace callback function + pub fn trace_v2(&self, mask: TraceEventCodes, trace_fn: Option)>) { + unsafe extern "C" fn trace_callback( + evt: c_uint, + ctx: *mut c_void, + _p: *mut c_void, + x: *mut c_void, + ) -> c_int { + let trace_fn: fn(TraceEvent<'_>) = mem::transmute(ctx); + drop(catch_unwind(|| match evt { + ffi::SQLITE_TRACE_STMT => { + let str = CStr::from_ptr(x as *const c_char).to_string_lossy(); + trace_fn(TraceEvent::Stmt(&str)) + } + ffi::SQLITE_TRACE_PROFILE => { + let ns = *(x as *const i64); + trace_fn(TraceEvent::Profile(Duration::from_nanos( + u64::try_from(ns).unwrap_or_default(), + ))) + } + ffi::SQLITE_TRACE_ROW => trace_fn(TraceEvent::Row()), + ffi::SQLITE_TRACE_CLOSE => trace_fn(TraceEvent::Close()), + _ => {} + })); + // The integer return value from the callback is currently ignored, though this may change in future releases. + // Callback implementations should return zero to ensure future compatibility. + ffi::SQLITE_OK + } + let c = self.db.borrow_mut(); + if let Some(f) = trace_fn { + unsafe { + ffi::sqlite3_trace_v2(c.db(), mask.bits(), Some(trace_callback), f as *mut c_void); + } + } else { + unsafe { + ffi::sqlite3_trace_v2(c.db(), 0, None, ptr::null_mut()); + } + } + } } #[cfg(test)] @@ -128,6 +198,7 @@ mod test { use crate::{Connection, Result}; #[test] + #[allow(deprecated)] fn test_trace() -> Result<()> { static TRACED_STMTS: LazyLock>> = LazyLock::new(|| Mutex::new(Vec::new())); @@ -156,6 +227,7 @@ mod test { } #[test] + #[allow(deprecated)] fn test_profile() -> Result<()> { static PROFILED: LazyLock>> = LazyLock::new(|| Mutex::new(Vec::new()));