22
33use crate :: local:: rows:: BatchedRows ;
44use crate :: params:: Params ;
5- use crate :: { connection:: BatchRows , errors} ;
5+ use crate :: {
6+ connection:: { BatchRows , Op } ,
7+ errors,
8+ } ;
69
710use super :: { Database , Error , Result , Rows , RowsFuture , Statement , Transaction } ;
811
@@ -11,6 +14,10 @@ use crate::TransactionBehavior;
1114use libsql_sys:: ffi;
1215use std:: { ffi:: c_int, fmt, path:: Path , sync:: Arc } ;
1316
17+ struct Container {
18+ cb : Box < dyn Fn ( Op , & str , & str , i64 ) + Send + Sync > ,
19+ }
20+
1421/// A connection to a libSQL database.
1522#[ derive( Clone ) ]
1623pub struct Connection {
@@ -384,6 +391,24 @@ impl Connection {
384391 } )
385392 }
386393
394+ /// Installs update hook
395+ pub fn add_update_hook ( & self , cb : Box < dyn Fn ( Op , & str , & str , i64 ) + Send + Sync > ) {
396+ let c = Box :: new ( Container { cb } ) ;
397+ let ptr: * mut Container = std:: ptr:: from_mut ( Box :: leak ( c) ) ;
398+
399+ let old_data = unsafe {
400+ ffi:: sqlite3_update_hook (
401+ self . raw ,
402+ Some ( update_hook_cb) ,
403+ ptr as * mut :: std:: os:: raw:: c_void ,
404+ )
405+ } ;
406+
407+ if !old_data. is_null ( ) {
408+ let _ = unsafe { Box :: from_raw ( old_data as * mut Container ) } ;
409+ }
410+ }
411+
387412 pub fn enable_load_extension ( & self , onoff : bool ) -> Result < ( ) > {
388413 // SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION configration verb accepts 2 additional parameters: an on/off flag and a pointer to an c_int where new state of the parameter will be written (or NULL if reporting back the setting is not needed)
389414 // See: https://sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigenableloadextension
@@ -489,3 +514,25 @@ impl fmt::Debug for Connection {
489514 f. debug_struct ( "Connection" ) . finish ( )
490515 }
491516}
517+
518+ #[ no_mangle]
519+ extern "C" fn update_hook_cb (
520+ data : * mut :: std:: os:: raw:: c_void ,
521+ op : :: std:: os:: raw:: c_int ,
522+ db_name : * const :: std:: os:: raw:: c_char ,
523+ table_name : * const :: std:: os:: raw:: c_char ,
524+ row_id : i64 ,
525+ ) {
526+ let db = unsafe { std:: ffi:: CStr :: from_ptr ( db_name) . to_string_lossy ( ) } ;
527+ let table = unsafe { std:: ffi:: CStr :: from_ptr ( table_name) . to_string_lossy ( ) } ;
528+
529+ let c = unsafe { & mut * ( data as * mut Container ) } ;
530+ let o = match op {
531+ 9 => Op :: Delete ,
532+ 18 => Op :: Insert ,
533+ 23 => Op :: Update ,
534+ _ => unreachable ! ( "Unknown operation {op}" ) ,
535+ } ;
536+
537+ ( * c. cb ) ( o, & db, & table, row_id) ;
538+ }
0 commit comments