1use core::error;
2use core::ffi::c_int;
3use core::ffi::CStr;
4use core::fmt;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum ErrorCode {
10 InternalMalfunction,
12 PermissionDenied,
14 OperationAborted,
16 DatabaseBusy,
18 DatabaseLocked,
20 OutOfMemory,
22 ReadOnly,
24 OperationInterrupted,
26 SystemIoFailure,
28 DatabaseCorrupt,
30 NotFound,
32 DiskFull,
34 CannotOpen,
36 FileLockingProtocolFailed,
38 SchemaChanged,
40 TooBig,
42 ConstraintViolation,
44 TypeMismatch,
46 ApiMisuse,
48 NoLargeFileSupport,
50 AuthorizationForStatementDenied,
52 ParameterOutOfRange,
54 NotADatabase,
56 Unknown,
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61pub struct Error {
62 pub code: ErrorCode,
63 pub extended_code: c_int,
64}
65
66impl Error {
67 #[must_use]
68 pub fn new(result_code: c_int) -> Self {
69 let code = match result_code & 0xff {
70 super::SQLITE_INTERNAL => ErrorCode::InternalMalfunction,
71 super::SQLITE_PERM => ErrorCode::PermissionDenied,
72 super::SQLITE_ABORT => ErrorCode::OperationAborted,
73 super::SQLITE_BUSY => ErrorCode::DatabaseBusy,
74 super::SQLITE_LOCKED => ErrorCode::DatabaseLocked,
75 super::SQLITE_NOMEM => ErrorCode::OutOfMemory,
76 super::SQLITE_READONLY => ErrorCode::ReadOnly,
77 super::SQLITE_INTERRUPT => ErrorCode::OperationInterrupted,
78 super::SQLITE_IOERR => ErrorCode::SystemIoFailure,
79 super::SQLITE_CORRUPT => ErrorCode::DatabaseCorrupt,
80 super::SQLITE_NOTFOUND => ErrorCode::NotFound,
81 super::SQLITE_FULL => ErrorCode::DiskFull,
82 super::SQLITE_CANTOPEN => ErrorCode::CannotOpen,
83 super::SQLITE_PROTOCOL => ErrorCode::FileLockingProtocolFailed,
84 super::SQLITE_SCHEMA => ErrorCode::SchemaChanged,
85 super::SQLITE_TOOBIG => ErrorCode::TooBig,
86 super::SQLITE_CONSTRAINT => ErrorCode::ConstraintViolation,
87 super::SQLITE_MISMATCH => ErrorCode::TypeMismatch,
88 super::SQLITE_MISUSE => ErrorCode::ApiMisuse,
89 super::SQLITE_NOLFS => ErrorCode::NoLargeFileSupport,
90 super::SQLITE_AUTH => ErrorCode::AuthorizationForStatementDenied,
91 super::SQLITE_RANGE => ErrorCode::ParameterOutOfRange,
92 super::SQLITE_NOTADB => ErrorCode::NotADatabase,
93 _ => ErrorCode::Unknown,
94 };
95
96 Self {
97 code,
98 extended_code: result_code,
99 }
100 }
101}
102
103impl fmt::Display for Error {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 write!(
106 f,
107 "Error code {}: {}",
108 self.extended_code,
109 code_to_str(self.extended_code)
110 )
111 }
112}
113
114impl error::Error for Error {
115 fn description(&self) -> &str {
116 code_to_str(self.extended_code)
117 }
118}
119
120#[must_use]
121pub fn code_to_str(code: c_int) -> &'static str {
122 let err_str = unsafe { super::sqlite3_errstr(code) };
123 if err_str.is_null() {
124 "Unknown errod code"
125 } else {
126 unsafe { CStr::from_ptr(err_str) }.to_str().unwrap()
128 }
129}
130
131#[cfg(feature = "loadable_extension")]
133#[derive(Clone, Copy, Debug, PartialEq, Eq)]
134#[non_exhaustive]
135pub enum InitError {
136 VersionMismatch { compile_time: i32, runtime: i32 },
138 NullFunctionPointer,
140}
141#[cfg(feature = "loadable_extension")]
142impl fmt::Display for InitError {
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 match *self {
145 Self::VersionMismatch {
146 compile_time,
147 runtime,
148 } => {
149 write!(f, "SQLite version mismatch: {runtime} < {compile_time}")
150 }
151 Self::NullFunctionPointer => {
152 write!(f, "Some sqlite3_api_routines fields are null")
153 }
154 }
155 }
156}
157#[cfg(feature = "loadable_extension")]
158impl error::Error for InitError {}
159
160#[cfg(test)]
161mod test {
162 use crate::*;
163
164 #[test]
165 pub fn error_new() {
166 let assoc = vec![
167 (SQLITE_INTERNAL, ErrorCode::InternalMalfunction),
168 (SQLITE_PERM, ErrorCode::PermissionDenied),
169 (SQLITE_ABORT_ROLLBACK, ErrorCode::OperationAborted),
170 (SQLITE_BUSY_RECOVERY, ErrorCode::DatabaseBusy),
171 (SQLITE_LOCKED_SHAREDCACHE, ErrorCode::DatabaseLocked),
172 (SQLITE_NOMEM, ErrorCode::OutOfMemory),
173 (SQLITE_IOERR_READ, ErrorCode::SystemIoFailure),
174 (SQLITE_NOTFOUND, ErrorCode::NotFound),
175 (SQLITE_FULL, ErrorCode::DiskFull),
176 (SQLITE_PROTOCOL, ErrorCode::FileLockingProtocolFailed),
177 (SQLITE_SCHEMA, ErrorCode::SchemaChanged),
178 (SQLITE_TOOBIG, ErrorCode::TooBig),
179 (SQLITE_MISMATCH, ErrorCode::TypeMismatch),
180 (SQLITE_NOLFS, ErrorCode::NoLargeFileSupport),
181 (SQLITE_RANGE, ErrorCode::ParameterOutOfRange),
182 (SQLITE_NOTADB, ErrorCode::NotADatabase),
183 ];
184 for (sqlite_code, rust_code) in assoc {
185 let err = Error::new(sqlite_code);
186 assert_eq!(
187 err,
188 Error {
189 code: rust_code,
190 extended_code: sqlite_code
191 }
192 );
193 let s = format!("{err}");
194 assert!(!s.is_empty());
195 }
196 }
197}