From 139ec0035e0f2a1c9a0b81f42c8d95c125fc558b Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Fri, 21 Nov 2025 13:56:56 +0400 Subject: [PATCH 1/6] copy errors codes from SQLite --- sqlite3/src/lib.rs | 47 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 4eed01a39..7bfa802e9 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -14,19 +14,42 @@ macro_rules! stub { }; } -pub const SQLITE_OK: ffi::c_int = 0; -pub const SQLITE_ERROR: ffi::c_int = 1; -pub const SQLITE_ABORT: ffi::c_int = 4; -pub const SQLITE_BUSY: ffi::c_int = 5; -pub const SQLITE_NOMEM: ffi::c_int = 7; -pub const SQLITE_INTERRUPT: ffi::c_int = 9; -pub const SQLITE_NOTFOUND: ffi::c_int = 12; -pub const SQLITE_CANTOPEN: ffi::c_int = 14; -pub const SQLITE_MISUSE: ffi::c_int = 21; -pub const SQLITE_RANGE: ffi::c_int = 25; -pub const SQLITE_ROW: ffi::c_int = 100; -pub const SQLITE_DONE: ffi::c_int = 101; +/* generic error-codes */ +pub const SQLITE_OK: ffi::c_int = 0; /* Successful result */ +pub const SQLITE_ERROR: ffi::c_int = 1; /* Generic error */ +pub const SQLITE_INTERNAL: ffi::c_int = 2; /* Internal logic error in SQLite */ +pub const SQLITE_PERM: ffi::c_int = 3; /* Access permission denied */ +pub const SQLITE_ABORT: ffi::c_int = 4; /* Callback routine requested an abort */ +pub const SQLITE_BUSY: ffi::c_int = 5; /* The database file is locked */ +pub const SQLITE_LOCKED: ffi::c_int = 6; /* A table in the database is locked */ +pub const SQLITE_NOMEM: ffi::c_int = 7; /* A malloc() failed */ +pub const SQLITE_READONLY: ffi::c_int = 8; /* Attempt to write a readonly database */ +pub const SQLITE_INTERRUPT: ffi::c_int = 9; /* Operation terminated by sqlite3_interrupt()*/ +pub const SQLITE_IOERR: ffi::c_int = 10; /* Some kind of disk I/O error occurred */ +pub const SQLITE_CORRUPT: ffi::c_int = 11; /* The database disk image is malformed */ +pub const SQLITE_NOTFOUND: ffi::c_int = 12; /* Unknown opcode in sqlite3_file_control() */ +pub const SQLITE_FULL: ffi::c_int = 13; /* Insertion failed because database is full */ +pub const SQLITE_CANTOPEN: ffi::c_int = 14; /* Unable to open the database file */ +pub const SQLITE_PROTOCOL: ffi::c_int = 15; /* Database lock protocol error */ +pub const SQLITE_EMPTY: ffi::c_int = 16; /* Internal use only */ +pub const SQLITE_SCHEMA: ffi::c_int = 17; /* The database schema changed */ +pub const SQLITE_TOOBIG: ffi::c_int = 18; /* String or BLOB exceeds size limit */ +pub const SQLITE_CONSTRAINT: ffi::c_int = 19; /* Abort due to constraint violation */ +pub const SQLITE_MISMATCH: ffi::c_int = 20; /* Data type mismatch */ +pub const SQLITE_MISUSE: ffi::c_int = 21; /* Library used incorrectly */ +pub const SQLITE_NOLFS: ffi::c_int = 22; /* Uses OS features not supported on host */ +pub const SQLITE_AUTH: ffi::c_int = 23; /* Authorization denied */ +pub const SQLITE_FORMAT: ffi::c_int = 24; /* Not used */ +pub const SQLITE_RANGE: ffi::c_int = 25; /* 2nd parameter to sqlite3_bind out of range */ +pub const SQLITE_NOTADB: ffi::c_int = 26; /* File opened that is not a database file */ +pub const SQLITE_NOTICE: ffi::c_int = 27; /* Notifications from sqlite3_log() */ +pub const SQLITE_WARNING: ffi::c_int = 28; /* Warnings from sqlite3_log() */ +pub const SQLITE_ROW: ffi::c_int = 100; /* sqlite3_step() has another row ready */ +pub const SQLITE_DONE: ffi::c_int = 101; /* sqlite3_step() has finished executing */ + +/* extended error-codes */ pub const SQLITE_ABORT_ROLLBACK: ffi::c_int = SQLITE_ABORT | (2 << 8); + pub const SQLITE_STATE_OPEN: u8 = 0x76; pub const SQLITE_STATE_SICK: u8 = 0xba; pub const SQLITE_STATE_BUSY: u8 = 0x6d; From f5e8eaa6c14ec6fd05d12f7532f67482b698624a Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Fri, 21 Nov 2025 13:57:34 +0400 Subject: [PATCH 2/6] enable indices by default --- sqlite3/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 7bfa802e9..86b22100d 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -184,7 +184,7 @@ pub unsafe extern "C" fn sqlite3_open( Err(_) => return SQLITE_CANTOPEN, }, }; - match turso_core::Database::open_file(io.clone(), filename_str, false, false) { + match turso_core::Database::open_file(io.clone(), filename_str, false, true) { Ok(db) => { let conn = db.connect().unwrap(); let filename = match filename_str { From 228f2c1be905f67ee5f9e4be47d9fef6ef259485 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Fri, 21 Nov 2025 13:58:07 +0400 Subject: [PATCH 3/6] return proper error code in case of certain LimboErrors --- sqlite3/src/lib.rs | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 86b22100d..3ab363aac 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -311,9 +311,10 @@ pub unsafe extern "C" fn sqlite3_prepare_v2( }; let stmt = match db.conn.prepare(sql) { Ok(stmt) => stmt, - Err(_) => { - db.err_code = SQLITE_ERROR; - return SQLITE_ERROR; + Err(err) => { + let code = handle_limbo_err(err, std::ptr::null_mut()); + db.err_code = code; + return code; } }; let new_stmt = Box::leak(Box::new(sqlite3_stmt::new(raw_db, stmt))); @@ -367,8 +368,8 @@ pub unsafe extern "C" fn sqlite3_step(stmt: *mut sqlite3_stmt) -> ffi::c_int { let db = &mut *stmt.db; loop { let _db = db.inner.lock().unwrap(); - if let Ok(result) = stmt.stmt.step() { - match result { + match stmt.stmt.step() { + Ok(result) => match result { turso_core::StepResult::IO => { stmt.stmt.run_once().unwrap(); continue; @@ -383,9 +384,8 @@ pub unsafe extern "C" fn sqlite3_step(stmt: *mut sqlite3_stmt) -> ffi::c_int { return SQLITE_ROW; } turso_core::StepResult::Busy => return SQLITE_BUSY, - } - } else { - return SQLITE_ERROR; + }, + Err(err) => return handle_limbo_err(err, std::ptr::null_mut()), } } } @@ -435,11 +435,7 @@ pub unsafe extern "C" fn sqlite3_exec( match db_inner.conn.execute(trimmed) { Ok(_) => continue, Err(e) => { - if !err.is_null() { - let err_msg = format!("SQL error: {e:?}"); - *err = CString::new(err_msg).unwrap().into_raw(); - } - return SQLITE_ERROR; + return handle_limbo_err(e, err); } } } else if callback.is_none() { @@ -2119,3 +2115,20 @@ pub unsafe extern "C" fn sqlite3_table_column_metadata( rc } + +fn handle_limbo_err(err: LimboError, container: *mut *mut ffi::c_char) -> i32 { + if !container.is_null() { + let err_msg = format!("{}", err); + unsafe { *container = CString::new(err_msg).unwrap().into_raw() }; + } + match err { + LimboError::Corrupt(..) => SQLITE_CORRUPT, + LimboError::NotADB => SQLITE_NOTADB, + LimboError::Constraint(_) => SQLITE_CONSTRAINT, + LimboError::DatabaseFull(_) => SQLITE_FULL, + LimboError::TableLocked => SQLITE_LOCKED, + LimboError::ReadOnly => SQLITE_READONLY, + LimboError::Busy => SQLITE_BUSY, + _ => SQLITE_ERROR, + } +} From daaa91259b2269539e225dd4a3997ad0d184de6d Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Fri, 21 Nov 2025 13:58:20 +0400 Subject: [PATCH 4/6] remove debug logs --- sqlite3/src/lib.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 3ab363aac..0bedae199 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -983,7 +983,6 @@ pub unsafe extern "C" fn sqlite3_bind_double( idx: ffi::c_int, val: f64, ) -> ffi::c_int { - println!("Bind Double Rust"); if stmt.is_null() { return SQLITE_MISUSE; } @@ -1820,7 +1819,6 @@ pub unsafe extern "C" fn sqlite3_wal_checkpoint_v2( SQLITE_OK } Err(e) => { - println!("Checkpoint error: {e}"); if matches!(e, turso_core::LimboError::Busy) { SQLITE_BUSY } else { @@ -1967,10 +1965,7 @@ pub unsafe extern "C" fn libsql_wal_disable_checkpoint(db: *mut sqlite3) -> ffi: fn sqlite3_safety_check_sick_or_ok(db: &sqlite3Inner) -> bool { match db.e_open_state { SQLITE_STATE_SICK | SQLITE_STATE_OPEN | SQLITE_STATE_BUSY => true, - _ => { - eprintln!("Invalid database state: {}", db.e_open_state); - false - } + _ => false, } } From 78b9fa54a584bcce51874b5110fd8accfbd4b465 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Fri, 21 Nov 2025 14:04:04 +0400 Subject: [PATCH 5/6] fix clippy --- sqlite3/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 0bedae199..5e62275a5 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -1963,10 +1963,10 @@ pub unsafe extern "C" fn libsql_wal_disable_checkpoint(db: *mut sqlite3) -> ffi: } fn sqlite3_safety_check_sick_or_ok(db: &sqlite3Inner) -> bool { - match db.e_open_state { - SQLITE_STATE_SICK | SQLITE_STATE_OPEN | SQLITE_STATE_BUSY => true, - _ => false, - } + matches!( + db.e_open_state, + SQLITE_STATE_SICK | SQLITE_STATE_OPEN | SQLITE_STATE_BUSY + ) } // https://sqlite.org/c3ref/table_column_metadata.html @@ -2113,7 +2113,7 @@ pub unsafe extern "C" fn sqlite3_table_column_metadata( fn handle_limbo_err(err: LimboError, container: *mut *mut ffi::c_char) -> i32 { if !container.is_null() { - let err_msg = format!("{}", err); + let err_msg = format!("{err}"); unsafe { *container = CString::new(err_msg).unwrap().into_raw() }; } match err { From cb3ae4d7fd11980476fd87a97b0c3e9a3607ed10 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Fri, 21 Nov 2025 14:27:04 +0400 Subject: [PATCH 6/6] remove unnecessary constant - it is not exported as a symbol - so no need to have it --- sqlite3/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 5e62275a5..89ce1f8d0 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -62,7 +62,6 @@ pub const SQLITE_CHECKPOINT_TRUNCATE: ffi::c_int = 3; pub const SQLITE_INTEGER: ffi::c_int = 1; pub const SQLITE_FLOAT: ffi::c_int = 2; pub const SQLITE_TEXT: ffi::c_int = 3; -pub const SQLITE3_TEXT: ffi::c_int = 3; pub const SQLITE_BLOB: ffi::c_int = 4; pub const SQLITE_NULL: ffi::c_int = 5;