Skip to content

Commit

Permalink
feat(Sqlite): add LockedSqliteHandle::last_error (launchbadge#3707)
Browse files Browse the repository at this point in the history
  • Loading branch information
joeydewaal authored Jan 28, 2025
1 parent 6ca52fe commit 546ec96
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 3 deletions.
Binary file added ci.db
Binary file not shown.
6 changes: 5 additions & 1 deletion sqlx-sqlite/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::connection::establish::EstablishParams;
use crate::connection::worker::ConnectionWorker;
use crate::options::OptimizeOnClose;
use crate::statement::VirtualStatement;
use crate::{Sqlite, SqliteConnectOptions};
use crate::{Sqlite, SqliteConnectOptions, SqliteError};

pub(crate) mod collation;
pub(crate) mod describe;
Expand Down Expand Up @@ -542,6 +542,10 @@ impl LockedSqliteHandle<'_> {
pub fn remove_rollback_hook(&mut self) {
self.guard.remove_rollback_hook();
}

pub fn last_error(&mut self) -> Option<SqliteError> {
SqliteError::try_new(self.guard.handle.as_ptr())
}
}

impl Drop for ConnectionState {
Expand Down
12 changes: 10 additions & 2 deletions sqlx-sqlite/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@ pub struct SqliteError {

impl SqliteError {
pub(crate) fn new(handle: *mut sqlite3) -> Self {
Self::try_new(handle).expect("There should be an error")
}

pub(crate) fn try_new(handle: *mut sqlite3) -> Option<Self> {
// returns the extended result code even when extended result codes are disabled
let code: c_int = unsafe { sqlite3_extended_errcode(handle) };

if code == 0 {
return None;
}

// return English-language text that describes the error
let message = unsafe {
let msg = sqlite3_errmsg(handle);
Expand All @@ -34,10 +42,10 @@ impl SqliteError {
from_utf8_unchecked(CStr::from_ptr(msg).to_bytes())
};

Self {
Some(Self {
code,
message: message.to_owned(),
}
})
}

/// For errors during extension load, the error message is supplied via a separate pointer
Expand Down
21 changes: 21 additions & 0 deletions tests/sqlite/sqlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1172,3 +1172,24 @@ async fn test_multiple_set_preupdate_hook_calls_drop_old_handler() -> anyhow::Re
assert_eq!(1, Arc::strong_count(&ref_counted_object));
Ok(())
}

#[sqlx_macros::test]
async fn test_get_last_error() -> anyhow::Result<()> {
let mut conn = new::<Sqlite>().await?;

let _ = sqlx::query("select 1").fetch_one(&mut conn).await?;

{
let mut handle = conn.lock_handle().await?;
assert!(handle.last_error().is_none());
}

let _ = sqlx::query("invalid statement").fetch_one(&mut conn).await;

{
let mut handle = conn.lock_handle().await?;
assert!(handle.last_error().is_some());
}

Ok(())
}

0 comments on commit 546ec96

Please sign in to comment.