use super::{ffi, mutex::SQLiteMutexGuard, sqlite3_require_version, Connection};
use std::ffi::CStr;
pub const SQLITE_LOCKED: Error = Error::Sqlite(ffi::SQLITE_LOCKED, None);
pub const SQLITE_NOMEM: Error = Error::Sqlite(ffi::SQLITE_NOMEM, None);
pub const SQLITE_READONLY: Error = Error::Sqlite(ffi::SQLITE_READONLY, None);
pub const SQLITE_NOTFOUND: Error = Error::Sqlite(ffi::SQLITE_NOTFOUND, None);
pub const SQLITE_EMPTY: Error = Error::Sqlite(ffi::SQLITE_EMPTY, None);
pub const SQLITE_CONSTRAINT: Error = Error::Sqlite(ffi::SQLITE_CONSTRAINT, None);
pub const SQLITE_MISMATCH: Error = Error::Sqlite(ffi::SQLITE_MISMATCH, None);
pub const SQLITE_MISUSE: Error = Error::Sqlite(ffi::SQLITE_MISUSE, None);
pub const SQLITE_RANGE: Error = Error::Sqlite(ffi::SQLITE_RANGE, None);
#[derive(Clone, Eq, PartialEq)]
pub enum Error {
Sqlite(i32, Option<String>),
Utf8Error(std::str::Utf8Error),
NulError(std::ffi::NulError),
VersionNotSatisfied(std::os::raw::c_int),
Module(String),
NoChange,
}
impl Error {
pub fn from_sqlite(rc: i32) -> Result<()> {
match rc {
ffi::SQLITE_OK | ffi::SQLITE_ROW | ffi::SQLITE_DONE => Ok(()),
_ => Err(Error::Sqlite(rc, None)),
}
}
pub fn from_sqlite_desc(rc: i32, guard: SQLiteMutexGuard<'_, Connection>) -> Result<()> {
unsafe { Self::from_sqlite_desc_unchecked(rc, guard.as_mut_ptr()) }
}
pub unsafe fn from_sqlite_desc_unchecked(rc: i32, conn: *mut ffi::sqlite3) -> Result<()> {
match rc {
ffi::SQLITE_OK | ffi::SQLITE_ROW | ffi::SQLITE_DONE => Ok(()),
rc => {
let msg = CStr::from_ptr(ffi::sqlite3_errmsg(conn));
let msg = msg.to_str()?.to_owned();
Err(Error::Sqlite(rc, Some(msg)))
}
}
}
}
impl From<String> for Error {
fn from(msg: String) -> Self {
Self::Module(msg)
}
}
impl From<&str> for Error {
fn from(msg: &str) -> Self {
Self::Module(msg.to_string())
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Sqlite(_, Some(desc)) => write!(f, "{desc}"),
Error::Sqlite(i, None) => {
let errstr: Result<&str> = sqlite3_require_version!(3_007_015, unsafe {
std::ffi::CStr::from_ptr(ffi::sqlite3_errstr(*i))
.to_str()
.map_err(Error::Utf8Error)
});
match errstr {
Ok(s) => write!(f, "{s}"),
_ => write!(f, "SQLite error {i}"),
}
}
Error::Utf8Error(e) => e.fmt(f),
Error::NulError(e) => e.fmt(f),
Error::Module(s) => write!(f, "{s}"),
Error::VersionNotSatisfied(v) => write!(
f,
"requires SQLite version {}.{}.{} or above",
v / 1_000_000,
(v / 1000) % 1000,
v % 1000
),
Error::NoChange => write!(f, "invalid Error::NoChange"),
}
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Sqlite(i, Some(desc)) => f.debug_tuple("Sqlite").field(&i).field(&desc).finish(),
Error::Sqlite(i, None) => {
let errstr: Result<&str> = sqlite3_require_version!(3_007_015, unsafe {
std::ffi::CStr::from_ptr(ffi::sqlite3_errstr(*i))
.to_str()
.map_err(Error::Utf8Error)
});
match errstr {
Ok(s) => f.debug_tuple("Sqlite").field(&i).field(&s).finish(),
_ => f.debug_tuple("Sqlite").field(&i).finish(),
}
}
Error::Utf8Error(e) => f.debug_tuple("Utf8Error").field(&e).finish(),
Error::NulError(e) => f.debug_tuple("NulError").field(&e).finish(),
Error::Module(s) => f.debug_tuple("Module").field(&s).finish(),
Error::VersionNotSatisfied(v) => {
f.debug_tuple("VersionNotSatisfied").field(&v).finish()
}
Error::NoChange => f.debug_tuple("NoChange").finish(),
}
}
}
impl std::error::Error for Error {}
impl From<std::str::Utf8Error> for Error {
fn from(err: std::str::Utf8Error) -> Self {
Self::Utf8Error(err)
}
}
impl From<std::ffi::NulError> for Error {
fn from(err: std::ffi::NulError) -> Self {
Self::NulError(err)
}
}
pub type Result<T> = std::result::Result<T, Error>;