asqlite/
error.rs

1use std::{fmt, io};
2
3/// Library error.
4#[derive(Clone, Debug)]
5pub struct Error {
6    kind: ErrorKind,
7    message: String,
8}
9
10impl Error {
11    pub(crate) fn from_code(code: i32, message: Option<String>) -> Self {
12        Self {
13            kind: ErrorKind::from_code(code),
14            message: message.unwrap_or_else(|| ErrorKind::from_code(code).to_string()),
15        }
16    }
17
18    pub(crate) fn new(kind: ErrorKind, message: String) -> Self {
19        Self {
20            kind,
21            message,
22        }
23    }
24
25    pub(crate) fn background_task_failed() -> Self {
26        Self::new(ErrorKind::Generic, String::from("background task failed"))
27    }
28
29    /// Returns the kind of the error.
30    pub fn kind(&self) -> ErrorKind {
31        self.kind
32    }
33
34    /// Returns the message of the error.
35    pub fn message(&self) -> &str {
36        &self.message
37    }
38}
39
40impl fmt::Display for Error {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(f, "sqlite error: {} ({})", self.kind(), self.message())
43    }
44}
45
46impl std::error::Error for Error {}
47
48impl From<Error> for io::Error {
49    fn from(v: Error) -> io::Error {
50        io::Error::new(v.kind.into(), v)
51    }
52}
53
54impl From<ErrorKind> for Error {
55    fn from(kind: ErrorKind) -> Self {
56        Self {
57            kind,
58            message: kind.to_string(),
59        }
60    }
61}
62
63macro_rules! error_kind {
64    (
65        $(
66            $(#[doc = $doc:expr])*
67            #[message = $message:expr]
68            $(#[io = $error_kind:ident])?
69            $variant:ident $(= $code:ident)?,
70        )*
71    ) => {
72        /// Library error kind.
73        #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
74        #[non_exhaustive]
75        pub enum ErrorKind {
76            $(
77                $(#[doc = $doc])*
78                $variant,
79            )*
80        }
81
82        impl ErrorKind {
83            /// Converts the error kind from a SQLite error code.
84            pub const fn from_code(code: i32) -> Self {
85                match code & 0xFF {
86                    $(
87                        $(libsqlite3_sys::$code => Self::$variant,)?
88                    )*
89                    _ => Self::Generic,
90                }
91            }
92
93            /// Converts the error kind into a SQLite error code.
94            pub const fn code(self) -> Option<i32> {
95                match self {
96                    $(
97                        $(Self::$variant => Some(libsqlite3_sys::$code),)?
98                    )*
99                    _ => None,
100                }
101            }
102        }
103
104        impl fmt::Display for ErrorKind {
105            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106                match self {
107                    $(
108                        Self::$variant => f.write_str($message),
109                    )*
110                }
111            }
112        }
113
114        impl From<ErrorKind> for io::ErrorKind {
115            fn from(v: ErrorKind) -> io::ErrorKind {
116                match v {
117                    $(
118                        $(ErrorKind::$variant => io::ErrorKind::$error_kind,)?
119                    )*
120                    _ => io::ErrorKind::Other,
121                }
122            }
123        }
124    };
125}
126
127error_kind! {
128    /// Generic error.
129    #[message = "generic error"]
130    Generic = SQLITE_ERROR,
131
132    /// Internal library error.
133    #[message = "internal malfunction"]
134    InternalMalfunction = SQLITE_INTERNAL,
135
136    /// Unable to access the database.
137    #[message = "permission denied"]
138    #[io = PermissionDenied]
139    PermissionDenied = SQLITE_PERM,
140
141    /// The operation has been aborted.
142    #[message = "operation aborted"]
143    #[io = Interrupted]
144    OperationAborted = SQLITE_ABORT,
145
146    /// Database is being used concurrently by the same process.
147    #[message = "database busy"]
148    DatabaseBusy = SQLITE_BUSY,
149
150    /// Database is locked, usually because another process has opened it
151    /// with read-write access.
152    #[message = "database locked"]
153    DatabaseLocked = SQLITE_LOCKED,
154
155    /// Out of memory.
156    #[message = "out of memory"]
157    #[io = OutOfMemory]
158    OutOfMemory = SQLITE_NOMEM,
159
160    /// Tried to write to a database which is read only.
161    #[message = "database is read only"]
162    #[io = PermissionDenied]
163    ReadOnly = SQLITE_READONLY,
164
165    /// The operation has been interrupted.
166    #[message = "operation interrupted"]
167    #[io = Interrupted]
168    OperationInterrupted = SQLITE_INTERRUPT,
169
170    /// System I/O error.
171    #[message = "i/o error"]
172    SystemIoFailure = SQLITE_IOERR,
173
174    /// Database is corrupted.
175    #[message = "corrupted database"]
176    #[io = InvalidData]
177    DatabaseCorrupt = SQLITE_CORRUPT,
178
179    /// Database was not found.
180    #[message = "database not found"]
181    #[io = NotFound]
182    NotFound = SQLITE_NOTFOUND,
183
184    /// Disk is full.
185    #[message = "disk full"]
186    DiskFull = SQLITE_FULL,
187
188    /// Cannot open the database.
189    #[message = "cannot open database"]
190    CannotOpen = SQLITE_CANTOPEN,
191
192    /// Error in the file locking protocol.
193    #[message = "file locking protocol error"]
194    FileLockingProtocolFailed = SQLITE_PROTOCOL,
195
196    /// Schema has changed.
197    #[message = "schema has changed"]
198    #[io = InvalidData]
199    SchemaChanged = SQLITE_SCHEMA,
200
201    /// String or blob is too large.
202    #[message = "string or blob is too large"]
203    #[io = InvalidData]
204    TooLarge = SQLITE_TOOBIG,
205
206    /// Constraint violation.
207    #[message = "constraint violation"]
208    #[io = InvalidData]
209    ConstraintViolation = SQLITE_CONSTRAINT,
210
211    /// Datatype mismatch.
212    #[message = "datatype mismatch"]
213    #[io = InvalidData]
214    DatatypeMismatch = SQLITE_MISMATCH,
215
216    /// Library has been misused.
217    #[message = "library misuse"]
218    #[io = InvalidInput]
219    Misuse = SQLITE_MISUSE,
220
221    /// No support for large files.
222    #[message = "lfs not supported"]
223    #[io = Unsupported]
224    LfsUnsupported = SQLITE_NOLFS,
225
226    /// Statement is not authorized.
227    #[message = "unauthorized statement"]
228    #[io = PermissionDenied]
229    Unauthorized = SQLITE_AUTH,
230
231    /// Out of range.
232    #[message = "out of range"]
233    #[io = InvalidInput]
234    OutOfRange = SQLITE_RANGE,
235
236    /// Not a database.
237    #[message = "not a database"]
238    #[io = NotFound]
239    NotADatabase = SQLITE_NOTADB,
240
241    /// Invalid path.
242    #[message = "invalid database path"]
243    #[io = InvalidInput]
244    InvalidPath,
245
246    /// Database was closed already.
247    #[message = "connection was closed"]
248    #[io = BrokenPipe]
249    ConnectionClosed,
250
251    /// Too many statements.
252    #[message = "too many statements"]
253    #[io = InvalidInput]
254    TooManyStatements,
255}