mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-10-31 13:58:55 +08:00 
			
		
		
		
	Add bindings to sqlite3_trace_v2
This commit is contained in:
		| @@ -260,10 +260,10 @@ pub const SQLITE_FUNCTION: i32 = 31; | |||||||
| pub const SQLITE_SAVEPOINT: i32 = 32; | pub const SQLITE_SAVEPOINT: i32 = 32; | ||||||
| pub const SQLITE_COPY: i32 = 0; | pub const SQLITE_COPY: i32 = 0; | ||||||
| pub const SQLITE_RECURSIVE: i32 = 33; | pub const SQLITE_RECURSIVE: i32 = 33; | ||||||
| pub const SQLITE_TRACE_STMT: i32 = 1; | pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; | ||||||
| pub const SQLITE_TRACE_PROFILE: i32 = 2; | pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; | ||||||
| pub const SQLITE_TRACE_ROW: i32 = 4; | pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; | ||||||
| pub const SQLITE_TRACE_CLOSE: i32 = 8; | pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; | ||||||
| pub const SQLITE_LIMIT_LENGTH: i32 = 0; | pub const SQLITE_LIMIT_LENGTH: i32 = 0; | ||||||
| pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | ||||||
| pub const SQLITE_LIMIT_COLUMN: i32 = 2; | pub const SQLITE_LIMIT_COLUMN: i32 = 2; | ||||||
|   | |||||||
| @@ -237,10 +237,10 @@ pub const SQLITE_FUNCTION: i32 = 31; | |||||||
| pub const SQLITE_SAVEPOINT: i32 = 32; | pub const SQLITE_SAVEPOINT: i32 = 32; | ||||||
| pub const SQLITE_COPY: i32 = 0; | pub const SQLITE_COPY: i32 = 0; | ||||||
| pub const SQLITE_RECURSIVE: i32 = 33; | pub const SQLITE_RECURSIVE: i32 = 33; | ||||||
| pub const SQLITE_TRACE_STMT: i32 = 1; | pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; | ||||||
| pub const SQLITE_TRACE_PROFILE: i32 = 2; | pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; | ||||||
| pub const SQLITE_TRACE_ROW: i32 = 4; | pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; | ||||||
| pub const SQLITE_TRACE_CLOSE: i32 = 8; | pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; | ||||||
| pub const SQLITE_LIMIT_LENGTH: i32 = 0; | pub const SQLITE_LIMIT_LENGTH: i32 = 0; | ||||||
| pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | ||||||
| pub const SQLITE_LIMIT_COLUMN: i32 = 2; | pub const SQLITE_LIMIT_COLUMN: i32 = 2; | ||||||
|   | |||||||
| @@ -507,6 +507,7 @@ mod bindings { | |||||||
|             if name == "SQLITE_SERIALIZE_NOCOPY" |             if name == "SQLITE_SERIALIZE_NOCOPY" | ||||||
|                 || name.starts_with("SQLITE_DESERIALIZE_") |                 || name.starts_with("SQLITE_DESERIALIZE_") | ||||||
|                 || name.starts_with("SQLITE_PREPARE_") |                 || name.starts_with("SQLITE_PREPARE_") | ||||||
|  |                 || name.starts_with("SQLITE_TRACE_") | ||||||
|             { |             { | ||||||
|                 Some(IntKind::UInt) |                 Some(IntKind::UInt) | ||||||
|             } else { |             } else { | ||||||
|   | |||||||
| @@ -319,10 +319,10 @@ pub const SQLITE_FUNCTION: i32 = 31; | |||||||
| pub const SQLITE_SAVEPOINT: i32 = 32; | pub const SQLITE_SAVEPOINT: i32 = 32; | ||||||
| pub const SQLITE_COPY: i32 = 0; | pub const SQLITE_COPY: i32 = 0; | ||||||
| pub const SQLITE_RECURSIVE: i32 = 33; | pub const SQLITE_RECURSIVE: i32 = 33; | ||||||
| pub const SQLITE_TRACE_STMT: i32 = 1; | pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; | ||||||
| pub const SQLITE_TRACE_PROFILE: i32 = 2; | pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; | ||||||
| pub const SQLITE_TRACE_ROW: i32 = 4; | pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; | ||||||
| pub const SQLITE_TRACE_CLOSE: i32 = 8; | pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; | ||||||
| pub const SQLITE_LIMIT_LENGTH: i32 = 0; | pub const SQLITE_LIMIT_LENGTH: i32 = 0; | ||||||
| pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | ||||||
| pub const SQLITE_LIMIT_COLUMN: i32 = 2; | pub const SQLITE_LIMIT_COLUMN: i32 = 2; | ||||||
|   | |||||||
| @@ -319,10 +319,10 @@ pub const SQLITE_FUNCTION: i32 = 31; | |||||||
| pub const SQLITE_SAVEPOINT: i32 = 32; | pub const SQLITE_SAVEPOINT: i32 = 32; | ||||||
| pub const SQLITE_COPY: i32 = 0; | pub const SQLITE_COPY: i32 = 0; | ||||||
| pub const SQLITE_RECURSIVE: i32 = 33; | pub const SQLITE_RECURSIVE: i32 = 33; | ||||||
| pub const SQLITE_TRACE_STMT: i32 = 1; | pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; | ||||||
| pub const SQLITE_TRACE_PROFILE: i32 = 2; | pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; | ||||||
| pub const SQLITE_TRACE_ROW: i32 = 4; | pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; | ||||||
| pub const SQLITE_TRACE_CLOSE: i32 = 8; | pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; | ||||||
| pub const SQLITE_LIMIT_LENGTH: i32 = 0; | pub const SQLITE_LIMIT_LENGTH: i32 = 0; | ||||||
| pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | ||||||
| pub const SQLITE_LIMIT_COLUMN: i32 = 2; | pub const SQLITE_LIMIT_COLUMN: i32 = 2; | ||||||
|   | |||||||
| @@ -296,10 +296,10 @@ pub const SQLITE_FUNCTION: i32 = 31; | |||||||
| pub const SQLITE_SAVEPOINT: i32 = 32; | pub const SQLITE_SAVEPOINT: i32 = 32; | ||||||
| pub const SQLITE_COPY: i32 = 0; | pub const SQLITE_COPY: i32 = 0; | ||||||
| pub const SQLITE_RECURSIVE: i32 = 33; | pub const SQLITE_RECURSIVE: i32 = 33; | ||||||
| pub const SQLITE_TRACE_STMT: i32 = 1; | pub const SQLITE_TRACE_STMT: ::std::os::raw::c_uint = 1; | ||||||
| pub const SQLITE_TRACE_PROFILE: i32 = 2; | pub const SQLITE_TRACE_PROFILE: ::std::os::raw::c_uint = 2; | ||||||
| pub const SQLITE_TRACE_ROW: i32 = 4; | pub const SQLITE_TRACE_ROW: ::std::os::raw::c_uint = 4; | ||||||
| pub const SQLITE_TRACE_CLOSE: i32 = 8; | pub const SQLITE_TRACE_CLOSE: ::std::os::raw::c_uint = 8; | ||||||
| pub const SQLITE_LIMIT_LENGTH: i32 = 0; | pub const SQLITE_LIMIT_LENGTH: i32 = 0; | ||||||
| pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | pub const SQLITE_LIMIT_SQL_LENGTH: i32 = 1; | ||||||
| pub const SQLITE_LIMIT_COLUMN: i32 = 2; | pub const SQLITE_LIMIT_COLUMN: i32 = 2; | ||||||
|   | |||||||
| @@ -452,7 +452,7 @@ pub enum CheckpointMode { | |||||||
|     FULL = ffi::SQLITE_CHECKPOINT_FULL, |     FULL = ffi::SQLITE_CHECKPOINT_FULL, | ||||||
|     /// Like FULL but wait for readers |     /// Like FULL but wait for readers | ||||||
|     RESTART = ffi::SQLITE_CHECKPOINT_RESTART, |     RESTART = ffi::SQLITE_CHECKPOINT_RESTART, | ||||||
|     /// Like RESTART but also truncate WA |     /// Like RESTART but also truncate WAL | ||||||
|     TRUNCATE = ffi::SQLITE_CHECKPOINT_TRUNCATE, |     TRUNCATE = ffi::SQLITE_CHECKPOINT_TRUNCATE, | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										86
									
								
								src/trace.rs
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								src/trace.rs
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| use std::ffi::{CStr, CString}; | use std::ffi::{CStr, CString}; | ||||||
| use std::mem; | 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::panic::catch_unwind; | ||||||
| use std::ptr; | use std::ptr; | ||||||
| use std::time::Duration; | 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 { | impl Connection { | ||||||
|     /// Register or clear a callback function that can be |     /// Register or clear a callback function that can be | ||||||
|     /// used for tracing the execution of SQL statements. |     /// used for tracing the execution of SQL statements. | ||||||
| @@ -68,6 +102,7 @@ impl Connection { | |||||||
|     /// Prepared statement placeholders are replaced/logged with their assigned |     /// Prepared statement placeholders are replaced/logged with their assigned | ||||||
|     /// values. There can only be a single tracer defined for each database |     /// values. There can only be a single tracer defined for each database | ||||||
|     /// connection. Setting a new tracer clears the old one. |     /// 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<fn(&str)>) { |     pub fn trace(&mut self, trace_fn: Option<fn(&str)>) { | ||||||
|         unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) { |         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); |             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 |     /// There can only be a single profiler defined for each database | ||||||
|     /// connection. Setting a new profiler clears the old one. |     /// 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<fn(&str, Duration)>) { |     pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) { | ||||||
|         unsafe extern "C" fn profile_callback( |         unsafe extern "C" fn profile_callback( | ||||||
|             p_arg: *mut c_void, |             p_arg: *mut c_void, | ||||||
| @@ -99,12 +135,8 @@ impl Connection { | |||||||
|         ) { |         ) { | ||||||
|             let profile_fn: fn(&str, Duration) = mem::transmute(p_arg); |             let profile_fn: fn(&str, Duration) = mem::transmute(p_arg); | ||||||
|             let s = CStr::from_ptr(z_sql).to_string_lossy(); |             let s = CStr::from_ptr(z_sql).to_string_lossy(); | ||||||
|             const NANOS_PER_SEC: u64 = 1_000_000_000; |  | ||||||
|  |  | ||||||
|             let duration = Duration::new( |             let duration = Duration::from_nanos(nanoseconds); | ||||||
|                 nanoseconds / NANOS_PER_SEC, |  | ||||||
|                 (nanoseconds % NANOS_PER_SEC) as u32, |  | ||||||
|             ); |  | ||||||
|             drop(catch_unwind(|| profile_fn(&s, duration))); |             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<fn(TraceEvent<'_>)>) { | ||||||
|  |         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)] | #[cfg(test)] | ||||||
| @@ -128,6 +198,7 @@ mod test { | |||||||
|     use crate::{Connection, Result}; |     use crate::{Connection, Result}; | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|  |     #[allow(deprecated)] | ||||||
|     fn test_trace() -> Result<()> { |     fn test_trace() -> Result<()> { | ||||||
|         static TRACED_STMTS: LazyLock<Mutex<Vec<String>>> = |         static TRACED_STMTS: LazyLock<Mutex<Vec<String>>> = | ||||||
|             LazyLock::new(|| Mutex::new(Vec::new())); |             LazyLock::new(|| Mutex::new(Vec::new())); | ||||||
| @@ -156,6 +227,7 @@ mod test { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|  |     #[allow(deprecated)] | ||||||
|     fn test_profile() -> Result<()> { |     fn test_profile() -> Result<()> { | ||||||
|         static PROFILED: LazyLock<Mutex<Vec<(String, Duration)>>> = |         static PROFILED: LazyLock<Mutex<Vec<(String, Duration)>>> = | ||||||
|             LazyLock::new(|| Mutex::new(Vec::new())); |             LazyLock::new(|| Mutex::new(Vec::new())); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user