Skip to content

Commit b3a96c5

Browse files
committed
chore: decouple error stack from db
1 parent 899899e commit b3a96c5

File tree

6 files changed

+60
-65
lines changed

6 files changed

+60
-65
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ reqwest = { version = "0.12.9", features = ["json", "blocking", "gzip"] }
1717
num_cpus = "1.17.0"
1818
tokio-tungstenite = { version = "0.27.0", features = ["native-tls"] }
1919
futures-util = "0.3.31"
20+
lazy_static = "1.5.0"

src/auth.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ impl DbAuthStrategy for EnvVarStrategy {
6363
) -> Pin<Box<dyn Future<Output = Result<TursoConfig, Box<dyn std::error::Error>>> + Send + 'a>>
6464
{
6565
Box::pin(async move {
66-
let url = std::env::var("TURSO_DB_URL")?;
67-
let token = std::env::var("TURSO_DB_TOKEN")?;
66+
let url = std::env::var("TURSO_DB_URL")
67+
.map_err(|_| "TURSO_DB_URL environment variable not set")?;
68+
let token = std::env::var("TURSO_DB_TOKEN")
69+
.map_err(|_| "TURSO_DB_TOKEN environment variable not set")?;
6870

6971
Ok(TursoConfig {
7072
db_url: url,

src/lib.rs

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use sqlite::{
1515

1616
use crate::{
1717
auth::{DbAuthStrategy, EnvVarStrategy, GlobeStrategy},
18+
sqlite::get_latest_error,
1819
utils::{
1920
count_parameters, execute_async_task, get_tokio, is_aligned, sql_is_begin_transaction,
2021
sql_is_commit, sql_is_pragma, sql_is_rollback,
@@ -61,7 +62,10 @@ pub unsafe extern "C" fn sqlite3_open_v2(
6162

6263
let db_name = CStr::from_ptr(filename).to_str().unwrap();
6364
if db_name.contains(":memory") {
64-
return SQLITE_CANTOPEN;
65+
return push_error((
66+
"In-memory databases are not supported".to_string(),
67+
SQLITE_CANTOPEN,
68+
));
6569
}
6670

6771
// Check if running in Globe environment
@@ -77,13 +81,12 @@ pub unsafe extern "C" fn sqlite3_open_v2(
7781
};
7882
let connection =
7983
get_tokio().block_on(transport::DatabaseConnection::open(db_name, auth_strategy));
80-
if connection.is_err() {
81-
return SQLITE_CANTOPEN;
84+
if let Some(error) = connection.as_ref().err() {
85+
return push_error((error.to_string(), SQLITE_CANTOPEN));
8286
}
8387

8488
let mock_db = Box::into_raw(Box::new(SQLite3 {
8589
connection: connection.unwrap(),
86-
error_stack: Mutex::new(vec![]),
8790
transaction_baton: Mutex::new(None),
8891
last_insert_rowid: Mutex::new(None),
8992
transaction_has_began: Mutex::new(false),
@@ -115,21 +118,15 @@ pub unsafe extern "C" fn sqlite3_prepare_v3(
115118
pp_stmt: *mut *mut SQLite3PreparedStmt, // OUT: Prepared statement handle
116119
pz_tail: *mut *const c_char, // OUT: Unprocessed SQL string
117120
) -> c_int {
118-
if pp_stmt.is_null() {
121+
if !is_aligned(_db) {
119122
return SQLITE_ERROR;
120123
}
121124

122-
let db = &mut *_db;
123-
124125
if prep_flag != 0 {
125-
push_error(
126-
db,
127-
(
128-
"Persisted prepared statements not supported yet.".to_string(),
129-
SQLITE_MISUSE,
130-
),
131-
);
132-
return SQLITE_MISUSE;
126+
return push_error((
127+
"Persisted prepared statements not supported yet.".to_string(),
128+
SQLITE_MISUSE,
129+
));
133130
}
134131

135132
let bytes = slice::from_raw_parts(_sql as *const u8, byte_len);
@@ -284,11 +281,11 @@ pub unsafe extern "C" fn sqlite3_step(stmt_ptr: *mut SQLite3PreparedStmt) -> c_i
284281
let sql = stmt.sql.to_uppercase();
285282
let sql_result_code = {
286283
if sql_is_begin_transaction(&sql) {
287-
execute_async_task(stmt.db, sqlite::begin_tnx_on_db(stmt.db, &sql))
284+
execute_async_task(sqlite::begin_tnx_on_db(stmt.db, &sql))
288285
} else if sql_is_commit(&sql) {
289-
execute_async_task(stmt.db, sqlite::commit_tnx_on_db(stmt.db, &sql))
286+
execute_async_task(sqlite::commit_tnx_on_db(stmt.db, &sql))
290287
} else {
291-
execute_async_task(stmt.db, sqlite::execute_stmt(stmt))
288+
execute_async_task(sqlite::execute_stmt(stmt))
292289
}
293290
};
294291

@@ -299,7 +296,7 @@ pub unsafe extern "C" fn sqlite3_step(stmt_ptr: *mut SQLite3PreparedStmt) -> c_i
299296

300297
let sql_result_code = sqlite::iterate_rows(stmt);
301298
if let Err(error) = sql_result_code {
302-
push_error(stmt.db, (error.to_string(), SQLITE_ERROR));
299+
push_error((error.to_string(), SQLITE_ERROR));
303300
return SQLITE_ERROR;
304301
}
305302

@@ -377,37 +374,23 @@ pub unsafe extern "C" fn sqlite3_close_v2(db: *mut SQLite3) -> c_int {
377374
}
378375

379376
#[no_mangle]
380-
pub extern "C" fn sqlite3_extended_errcode(db: *mut SQLite3) -> c_int {
381-
if !is_aligned(db) {
382-
return SQLITE_CANTOPEN;
383-
}
384-
385-
let db = unsafe { &mut *db };
386-
387-
let error_stack = db.error_stack.lock().unwrap();
388-
if !error_stack.is_empty() {
389-
return error_stack[0].1;
377+
pub unsafe extern "C" fn sqlite3_extended_errcode(_: *mut SQLite3) -> c_int {
378+
let error_stack = get_latest_error();
379+
if let Some((_, code)) = error_stack {
380+
return code;
390381
}
391382

392383
SQLITE_OK
393384
}
394385

395386
#[no_mangle]
396-
pub extern "C" fn sqlite3_errmsg(db: *mut SQLite3) -> *const c_char {
397-
if !is_aligned(db) {
398-
return b"Invalid Database pointer\0".as_ptr() as *const c_char;
399-
}
400-
401-
let db = unsafe { &mut *db };
402-
403-
if let Some(error_entry) = sqlite::get_latest_error(db) {
404-
match CString::new(error_entry.0) {
405-
Ok(c_string) => c_string.into_raw(),
406-
Err(_) => std::ptr::null(),
387+
pub unsafe extern "C" fn sqlite3_errmsg(_: *mut SQLite3) -> *const c_char {
388+
if let Some(error_entry) = sqlite::get_latest_error() {
389+
if let Ok(c_string) = CString::new(error_entry.0) {
390+
return c_string.into_raw();
407391
}
408-
} else {
409-
b"No error\0".as_ptr() as *const c_char
410392
}
393+
std::ptr::null()
411394
}
412395

413396
#[no_mangle]
@@ -612,7 +595,7 @@ pub extern "C" fn sqlite3_errstr(errcode: c_int) -> *const c_char {
612595
pub unsafe extern "C" fn sqlite3_exec(
613596
db: *mut SQLite3,
614597
sql: *const c_char,
615-
callback: SQLite3ExecCallback, // Callback function
598+
callback: SQLite3ExecCallback,
616599
arg: *mut c_void,
617600
errmsg: *mut *mut c_char,
618601
) -> c_int {
@@ -627,14 +610,14 @@ pub unsafe extern "C" fn sqlite3_exec(
627610
if sql_is_pragma(&sql) {
628611
return SQLITE_OK;
629612
} else if sql_is_begin_transaction(&sql) {
630-
return execute_async_task(db, sqlite::begin_tnx_on_db(db, &sql));
613+
return execute_async_task(sqlite::begin_tnx_on_db(db, &sql));
631614
} else if sql_is_rollback(&sql) {
632615
return reset_txn_on_db(db);
633616
} else if sql_is_commit(&sql) {
634-
return execute_async_task(db, sqlite::commit_tnx_on_db(db, &sql));
617+
return execute_async_task(sqlite::commit_tnx_on_db(db, &sql));
635618
}
636619

637-
execute_async_task(db, sqlite::handle_execute(db, &sql))
620+
execute_async_task(sqlite::handle_execute(db, &sql))
638621
}
639622

640623
#[no_mangle]
@@ -668,15 +651,13 @@ pub extern "C" fn sqlite3_commit_hook(
668651
#[no_mangle]
669652
pub extern "C" fn sqlite3_rollback_hook(
670653
db: *mut SQLite3,
671-
x_callback: Option<unsafe extern "C" fn(*mut c_void) -> c_int>, // int (*xCallback)(void*)
672-
p_arg: *mut c_void, // void *pArg
654+
x_callback: Option<unsafe extern "C" fn(*mut c_void) -> c_int>,
655+
p_arg: *mut c_void,
673656
) -> c_int {
674657
if !is_aligned(db) {
675658
return SQLITE_CANTOPEN;
676659
}
677660

678-
let db = unsafe { &mut *db }; // Safely dereference the raw pointer
679-
680661
SQLITE_OK
681662
}
682663

src/sqlite.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use crate::{
1111
utils::{convert_params_to_json, get_execution_result},
1212
};
1313

14+
use lazy_static::lazy_static;
15+
1416
pub const SQLITE_OK: c_int = 0;
1517
pub const SQLITE_ERROR: c_int = 1;
1618
pub const SQLITE_MISUSE: c_int = 21;
@@ -76,11 +78,14 @@ impl fmt::Display for SqliteError {
7678
}
7779
}
7880

81+
lazy_static! {
82+
pub static ref ERROR_STACK: Mutex<Vec<(String, c_int)>> = Mutex::new(Vec::new());
83+
}
84+
7985
#[repr(C)]
8086
pub struct SQLite3 {
8187
pub connection: transport::DatabaseConnection, // Connection to the database
8288
pub last_insert_rowid: Mutex<Option<i64>>, // Last inserted row ID
83-
pub error_stack: Mutex<Vec<(String, c_int)>>, // Stack to store error messages
8489
pub transaction_baton: Mutex<Option<String>>, // Baton for transaction management
8590
pub transaction_has_began: Mutex<bool>, // Flag to check if a transaction has started
8691
pub update_hook: Mutex<Option<(SqliteHook, *mut c_void)>>, // Update hook callback
@@ -184,8 +189,15 @@ pub type SQLite3ExecCallback = Option<
184189
) -> c_int,
185190
>;
186191

187-
pub fn get_latest_error(db: &SQLite3) -> Option<(String, c_int)> {
188-
if let Ok(stack) = db.error_stack.lock() {
192+
pub unsafe fn push_error(error: (String, c_int)) -> c_int {
193+
let mut stack = ERROR_STACK.lock().unwrap();
194+
let code = error.1;
195+
stack.push(error);
196+
code
197+
}
198+
199+
pub unsafe fn get_latest_error() -> Option<(String, c_int)> {
200+
if let Ok(stack) = ERROR_STACK.lock() {
189201
stack.last().cloned()
190202
} else {
191203
None
@@ -205,14 +217,6 @@ pub fn reset_txn_on_db(db: *mut SQLite3) -> c_int {
205217
SQLITE_OK
206218
}
207219

208-
pub fn push_error(db: *mut SQLite3, error: (String, c_int)) {
209-
let db = unsafe { &mut *db };
210-
211-
if let Ok(mut stack) = db.error_stack.lock() {
212-
stack.push(error);
213-
}
214-
}
215-
216220
pub fn iterate_rows(stmt: &mut SQLite3PreparedStmt) -> Result<c_int, Box<dyn Error>> {
217221
let result_rows = stmt.result_rows.lock().unwrap();
218222
let mut current_row = stmt.current_row.lock().unwrap();

src/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub fn count_parameters(sql: &str) -> c_int {
3838
re.find_iter(&sql).count() as c_int
3939
}
4040

41-
pub fn execute_async_task<F, R>(db: *mut SQLite3, task: F) -> c_int
41+
pub fn execute_async_task<F, R>(task: F) -> c_int
4242
where
4343
F: std::future::Future<Output = Result<R, SqliteError>>,
4444
R: Into<c_int>,
@@ -48,7 +48,7 @@ where
4848
match runtime.block_on(task) {
4949
Ok(result) => result.into(),
5050
Err(err) => {
51-
push_error(db, (format!("{}", err), err.code));
51+
unsafe { push_error((format!("{}", err), err.code)) };
5252
SQLITE_ERROR
5353
}
5454
}

0 commit comments

Comments
 (0)