@@ -8,13 +8,13 @@ use std::ffi::{c_char, c_int, c_void, CStr, CString};
88use std:: ptr;
99use std:: slice;
1010use std:: sync:: atomic:: { AtomicU64 , Ordering } ;
11- use std:: sync:: { Arc , OnceLock } ;
11+ use std:: sync:: { Arc , Mutex , OnceLock } ;
1212
1313use libsqlite3_sys:: * ;
1414use tokio:: runtime:: Handle ;
1515
1616use crate :: kv;
17- use crate :: sqlite_kv:: { KvGetResult , SqliteKv } ;
17+ use crate :: sqlite_kv:: { KvGetResult , SqliteKv , SqliteKvError } ;
1818
1919// MARK: Panic Guard
2020
@@ -158,12 +158,32 @@ struct VfsContext {
158158 actor_id : String ,
159159 main_file_name : String ,
160160 read_cache_enabled : bool ,
161+ last_error : Mutex < Option < String > > ,
161162 rt_handle : Handle ,
162163 io_methods : Box < sqlite3_io_methods > ,
163164 vfs_metrics : Arc < VfsMetrics > ,
164165}
165166
166167impl VfsContext {
168+ fn clear_last_error ( & self ) {
169+ if let Ok ( mut last_error) = self . last_error . lock ( ) {
170+ * last_error = None ;
171+ }
172+ }
173+
174+ fn set_last_error ( & self , message : String ) {
175+ if let Ok ( mut last_error) = self . last_error . lock ( ) {
176+ * last_error = Some ( message) ;
177+ }
178+ }
179+
180+ fn report_kv_error ( & self , err : SqliteKvError ) -> String {
181+ let message = err. to_string ( ) ;
182+ self . set_last_error ( message. clone ( ) ) ;
183+ self . kv . on_error ( & self . actor_id , & err) ;
184+ message
185+ }
186+
167187 fn resolve_file_tag ( & self , path : & str ) -> Option < u8 > {
168188 if path == self . main_file_name {
169189 return Some ( kv:: FILE_TAG_MAIN ) ;
@@ -187,7 +207,10 @@ impl VfsContext {
187207 let result = self
188208 . rt_handle
189209 . block_on ( self . kv . batch_get ( & self . actor_id , keys) )
190- . map_err ( |e| e. to_string ( ) ) ;
210+ . map_err ( |err| self . report_kv_error ( err) ) ;
211+ if result. is_ok ( ) {
212+ self . clear_last_error ( ) ;
213+ }
191214 let elapsed = start. elapsed ( ) ;
192215 tracing:: debug!(
193216 op = %format_args!( "get({key_count}keys)" ) ,
@@ -203,7 +226,10 @@ impl VfsContext {
203226 let result = self
204227 . rt_handle
205228 . block_on ( self . kv . batch_put ( & self . actor_id , keys, values) )
206- . map_err ( |e| e. to_string ( ) ) ;
229+ . map_err ( |err| self . report_kv_error ( err) ) ;
230+ if result. is_ok ( ) {
231+ self . clear_last_error ( ) ;
232+ }
207233 let elapsed = start. elapsed ( ) ;
208234 tracing:: debug!(
209235 op = %format_args!( "put({key_count}keys)" ) ,
@@ -219,7 +245,10 @@ impl VfsContext {
219245 let result = self
220246 . rt_handle
221247 . block_on ( self . kv . batch_delete ( & self . actor_id , keys) )
222- . map_err ( |e| e. to_string ( ) ) ;
248+ . map_err ( |err| self . report_kv_error ( err) ) ;
249+ if result. is_ok ( ) {
250+ self . clear_last_error ( ) ;
251+ }
223252 let elapsed = start. elapsed ( ) ;
224253 tracing:: debug!(
225254 op = %format_args!( "del({key_count}keys)" ) ,
@@ -234,7 +263,10 @@ impl VfsContext {
234263 let result = self
235264 . rt_handle
236265 . block_on ( self . kv . delete_range ( & self . actor_id , start, end) )
237- . map_err ( |e| e. to_string ( ) ) ;
266+ . map_err ( |err| self . report_kv_error ( err) ) ;
267+ if result. is_ok ( ) {
268+ self . clear_last_error ( ) ;
269+ }
238270 let elapsed = start_time. elapsed ( ) ;
239271 tracing:: debug!(
240272 op = "delRange" ,
@@ -1164,11 +1196,29 @@ unsafe extern "C" fn kv_vfs_current_time(_p_vfs: *mut sqlite3_vfs, p_time_out: *
11641196}
11651197
11661198unsafe extern "C" fn kv_vfs_get_last_error (
1167- _p_vfs : * mut sqlite3_vfs ,
1168- _n_byte : c_int ,
1169- _z_err_msg : * mut c_char ,
1199+ p_vfs : * mut sqlite3_vfs ,
1200+ n_byte : c_int ,
1201+ z_err_msg : * mut c_char ,
11701202) -> c_int {
1171- vfs_catch_unwind ! ( SQLITE_IOERR , SQLITE_OK )
1203+ vfs_catch_unwind ! ( SQLITE_IOERR , {
1204+ if n_byte <= 0 || z_err_msg. is_null( ) {
1205+ return 0 ;
1206+ }
1207+
1208+ let ctx = get_vfs_ctx( p_vfs) ;
1209+ let last_error = ctx. last_error. lock( ) . ok( ) . and_then( |guard| guard. clone( ) ) ;
1210+ let Some ( message) = last_error else {
1211+ * z_err_msg = 0 ;
1212+ return 0 ;
1213+ } ;
1214+
1215+ let bytes = message. as_bytes( ) ;
1216+ let max_len = ( n_byte as usize ) . saturating_sub( 1 ) ;
1217+ let copy_len = bytes. len( ) . min( max_len) ;
1218+ ptr:: copy_nonoverlapping( bytes. as_ptr( ) , z_err_msg. cast:: <u8 >( ) , copy_len) ;
1219+ * z_err_msg. add( copy_len) = 0 ;
1220+ 0
1221+ } )
11721222}
11731223
11741224// MARK: KvVfs
@@ -1183,6 +1233,16 @@ unsafe impl Send for KvVfs {}
11831233unsafe impl Sync for KvVfs { }
11841234
11851235impl KvVfs {
1236+ fn take_last_kv_error ( & self ) -> Option < String > {
1237+ unsafe {
1238+ ( * self . ctx_ptr )
1239+ . last_error
1240+ . lock ( )
1241+ . ok ( )
1242+ . and_then ( |mut last_error| last_error. take ( ) )
1243+ }
1244+ }
1245+
11861246 pub fn register (
11871247 name : & str ,
11881248 kv : Arc < dyn SqliteKv > ,
@@ -1210,6 +1270,7 @@ impl KvVfs {
12101270 actor_id : actor_id. clone ( ) ,
12111271 main_file_name : actor_id,
12121272 read_cache_enabled : read_cache_enabled ( ) ,
1273+ last_error : Mutex :: new ( None ) ,
12131274 rt_handle,
12141275 io_methods : Box :: new ( io_methods) ,
12151276 vfs_metrics,
@@ -1279,6 +1340,10 @@ impl NativeDatabase {
12791340 pub fn as_ptr ( & self ) -> * mut sqlite3 {
12801341 self . db
12811342 }
1343+
1344+ pub fn take_last_kv_error ( & self ) -> Option < String > {
1345+ self . _vfs . take_last_kv_error ( )
1346+ }
12821347}
12831348
12841349impl Drop for NativeDatabase {
@@ -1291,6 +1356,18 @@ impl Drop for NativeDatabase {
12911356 }
12921357}
12931358
1359+ fn sqlite_error_message ( db : * mut sqlite3 ) -> String {
1360+ unsafe {
1361+ if db. is_null ( ) {
1362+ "unknown sqlite error" . to_string ( )
1363+ } else {
1364+ CStr :: from_ptr ( sqlite3_errmsg ( db) )
1365+ . to_string_lossy ( )
1366+ . into_owned ( )
1367+ }
1368+ }
1369+ }
1370+
12941371pub fn open_database ( vfs : KvVfs , file_name : & str ) -> Result < NativeDatabase , String > {
12951372 let c_name = CString :: new ( file_name) . map_err ( |err| err. to_string ( ) ) ?;
12961373 let mut db: * mut sqlite3 = ptr:: null_mut ( ) ;
@@ -1304,12 +1381,13 @@ pub fn open_database(vfs: KvVfs, file_name: &str) -> Result<NativeDatabase, Stri
13041381 )
13051382 } ;
13061383 if rc != SQLITE_OK {
1384+ let message = sqlite_error_message ( db) ;
13071385 if !db. is_null ( ) {
13081386 unsafe {
13091387 sqlite3_close ( db) ;
13101388 }
13111389 }
1312- return Err ( format ! ( "sqlite3_open_v2 failed with code {rc}" ) ) ;
1390+ return Err ( format ! ( "sqlite3_open_v2 failed with code {rc}: {message} " ) ) ;
13131391 }
13141392
13151393 for pragma in & [
@@ -1324,10 +1402,11 @@ pub fn open_database(vfs: KvVfs, file_name: &str) -> Result<NativeDatabase, Stri
13241402 let rc =
13251403 unsafe { sqlite3_exec ( db, c_sql. as_ptr ( ) , None , ptr:: null_mut ( ) , ptr:: null_mut ( ) ) } ;
13261404 if rc != SQLITE_OK {
1405+ let message = sqlite_error_message ( db) ;
13271406 unsafe {
13281407 sqlite3_close ( db) ;
13291408 }
1330- return Err ( format ! ( "{pragma} failed with code {rc}" ) ) ;
1409+ return Err ( format ! ( "{pragma} failed with code {rc}: {message} " ) ) ;
13311410 }
13321411 }
13331412
0 commit comments