1use crate::types::FromSqlError;
2use crate::types::Type;
3use crate::{errmsg_to_string, ffi};
4use std::error;
5use std::fmt;
6use std::os::raw::c_int;
7use std::path::PathBuf;
8use std::str;
9
10#[derive(Debug)]
12#[allow(clippy::enum_variant_names)]
13#[non_exhaustive]
14pub enum Error {
15 SqliteFailure(ffi::Error, Option<String>),
17
18 SqliteSingleThreadedMode,
21
22 FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync + 'static>),
25
26 IntegralValueOutOfRange(usize, i64),
31
32 Utf8Error(str::Utf8Error),
34
35 NulError(::std::ffi::NulError),
38
39 InvalidParameterName(String),
42
43 InvalidPath(PathBuf),
45
46 ExecuteReturnedResults,
48
49 QueryReturnedNoRows,
52
53 InvalidColumnIndex(usize),
56
57 InvalidColumnName(String),
60
61 InvalidColumnType(usize, String, Type),
65
66 StatementChangedRows(usize),
69
70 #[cfg(feature = "functions")]
73 InvalidFunctionParameterType(usize, Type),
74 #[cfg(feature = "vtab")]
77 InvalidFilterParameterType(usize, Type),
78
79 #[cfg(feature = "functions")]
82 #[allow(dead_code)]
83 UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
84
85 ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
87
88 InvalidQuery,
90
91 #[cfg(feature = "vtab")]
94 #[allow(dead_code)]
95 ModuleError(String),
96
97 #[cfg(feature = "functions")]
99 UnwindingPanic,
100
101 #[cfg(feature = "functions")]
104 GetAuxWrongType,
105
106 MultipleStatement,
108 InvalidParameterCount(usize, usize),
112
113 #[cfg(feature = "blob")]
118 BlobSizeError,
119}
120
121impl PartialEq for Error {
122 fn eq(&self, other: &Error) -> bool {
123 match (self, other) {
124 (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
125 (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
126 (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
127 i1 == i2 && n1 == n2
128 }
129 (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
130 (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
131 (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
132 (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
133 (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
134 (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
135 (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
136 (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
137 (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
138 i1 == i2 && t1 == t2 && n1 == n2
139 }
140 (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
141 #[cfg(feature = "functions")]
142 (
143 Error::InvalidFunctionParameterType(i1, t1),
144 Error::InvalidFunctionParameterType(i2, t2),
145 ) => i1 == i2 && t1 == t2,
146 #[cfg(feature = "vtab")]
147 (
148 Error::InvalidFilterParameterType(i1, t1),
149 Error::InvalidFilterParameterType(i2, t2),
150 ) => i1 == i2 && t1 == t2,
151 (Error::InvalidQuery, Error::InvalidQuery) => true,
152 #[cfg(feature = "vtab")]
153 (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
154 #[cfg(feature = "functions")]
155 (Error::UnwindingPanic, Error::UnwindingPanic) => true,
156 #[cfg(feature = "functions")]
157 (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
158 (Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
159 i1 == i2 && n1 == n2
160 }
161 #[cfg(feature = "blob")]
162 (Error::BlobSizeError, Error::BlobSizeError) => true,
163 (..) => false,
164 }
165 }
166}
167
168impl From<str::Utf8Error> for Error {
169 #[cold]
170 fn from(err: str::Utf8Error) -> Error {
171 Error::Utf8Error(err)
172 }
173}
174
175impl From<::std::ffi::NulError> for Error {
176 #[cold]
177 fn from(err: ::std::ffi::NulError) -> Error {
178 Error::NulError(err)
179 }
180}
181
182const UNKNOWN_COLUMN: usize = std::usize::MAX;
183
184impl From<FromSqlError> for Error {
187 #[cold]
188 fn from(err: FromSqlError) -> Error {
189 match err {
192 FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
193 #[cfg(feature = "i128_blob")]
194 FromSqlError::InvalidI128Size(_) => {
195 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
196 }
197 #[cfg(feature = "uuid")]
198 FromSqlError::InvalidUuidSize(_) => {
199 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
200 }
201 FromSqlError::Other(source) => {
202 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
203 }
204 _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
205 }
206 }
207}
208
209impl fmt::Display for Error {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 match *self {
212 Error::SqliteFailure(ref err, None) => err.fmt(f),
213 Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
214 Error::SqliteSingleThreadedMode => write!(
215 f,
216 "SQLite was compiled or configured for single-threaded use only"
217 ),
218 Error::FromSqlConversionFailure(i, ref t, ref err) => {
219 if i != UNKNOWN_COLUMN {
220 write!(
221 f,
222 "Conversion error from type {} at index: {}, {}",
223 t, i, err
224 )
225 } else {
226 err.fmt(f)
227 }
228 }
229 Error::IntegralValueOutOfRange(col, val) => {
230 if col != UNKNOWN_COLUMN {
231 write!(f, "Integer {} out of range at index {}", val, col)
232 } else {
233 write!(f, "Integer {} out of range", val)
234 }
235 }
236 Error::Utf8Error(ref err) => err.fmt(f),
237 Error::NulError(ref err) => err.fmt(f),
238 Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
239 Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
240 Error::ExecuteReturnedResults => {
241 write!(f, "Execute returned results - did you mean to call query?")
242 }
243 Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
244 Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
245 Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
246 Error::InvalidColumnType(i, ref name, ref t) => write!(
247 f,
248 "Invalid column type {} at index: {}, name: {}",
249 t, i, name
250 ),
251 Error::InvalidParameterCount(i1, n1) => write!(
252 f,
253 "Wrong number of parameters passed to query. Got {}, needed {}",
254 i1, n1
255 ),
256 Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
257
258 #[cfg(feature = "functions")]
259 Error::InvalidFunctionParameterType(i, ref t) => {
260 write!(f, "Invalid function parameter type {} at index {}", t, i)
261 }
262 #[cfg(feature = "vtab")]
263 Error::InvalidFilterParameterType(i, ref t) => {
264 write!(f, "Invalid filter parameter type {} at index {}", t, i)
265 }
266 #[cfg(feature = "functions")]
267 Error::UserFunctionError(ref err) => err.fmt(f),
268 Error::ToSqlConversionFailure(ref err) => err.fmt(f),
269 Error::InvalidQuery => write!(f, "Query is not read-only"),
270 #[cfg(feature = "vtab")]
271 Error::ModuleError(ref desc) => write!(f, "{}", desc),
272 #[cfg(feature = "functions")]
273 Error::UnwindingPanic => write!(f, "unwinding panic"),
274 #[cfg(feature = "functions")]
275 Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
276 Error::MultipleStatement => write!(f, "Multiple statements provided"),
277
278 #[cfg(feature = "blob")]
279 Error::BlobSizeError => "Blob size is insufficient".fmt(f),
280 }
281 }
282}
283
284impl error::Error for Error {
285 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
286 match *self {
287 Error::SqliteFailure(ref err, _) => Some(err),
288 Error::Utf8Error(ref err) => Some(err),
289 Error::NulError(ref err) => Some(err),
290
291 Error::IntegralValueOutOfRange(..)
292 | Error::SqliteSingleThreadedMode
293 | Error::InvalidParameterName(_)
294 | Error::ExecuteReturnedResults
295 | Error::QueryReturnedNoRows
296 | Error::InvalidColumnIndex(_)
297 | Error::InvalidColumnName(_)
298 | Error::InvalidColumnType(..)
299 | Error::InvalidPath(_)
300 | Error::InvalidParameterCount(..)
301 | Error::StatementChangedRows(_)
302 | Error::InvalidQuery
303 | Error::MultipleStatement => None,
304
305 #[cfg(feature = "functions")]
306 Error::InvalidFunctionParameterType(..) => None,
307 #[cfg(feature = "vtab")]
308 Error::InvalidFilterParameterType(..) => None,
309
310 #[cfg(feature = "functions")]
311 Error::UserFunctionError(ref err) => Some(&**err),
312
313 Error::FromSqlConversionFailure(_, _, ref err)
314 | Error::ToSqlConversionFailure(ref err) => Some(&**err),
315
316 #[cfg(feature = "vtab")]
317 Error::ModuleError(_) => None,
318
319 #[cfg(feature = "functions")]
320 Error::UnwindingPanic => None,
321
322 #[cfg(feature = "functions")]
323 Error::GetAuxWrongType => None,
324
325 #[cfg(feature = "blob")]
326 Error::BlobSizeError => None,
327 }
328 }
329}
330
331#[cold]
334pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
335 Error::SqliteFailure(ffi::Error::new(code), message)
336}
337
338#[cold]
339pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
340 let message = if db.is_null() {
341 None
342 } else {
343 Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
344 };
345 error_from_sqlite_code(code, message)
346}
347
348#[macro_export]
361macro_rules! check {
362 ($funcall:expr) => {{
363 let rc = $funcall;
364 if rc != crate::ffi::SQLITE_OK {
365 return Err(crate::error::error_from_sqlite_code(rc, None).into());
366 }
367 }};
368}
369
370#[cfg(any(
374 feature = "vtab",
375 feature = "loadable_extension",
376 feature = "loadable_extension_embedded"
377))]
378pub unsafe fn to_sqlite_error(
379 e: &Error,
380 err_msg: *mut *mut std::os::raw::c_char,
381) -> std::os::raw::c_int {
382 use crate::util::alloc;
383 match e {
384 Error::SqliteFailure(err, s) => {
385 if let Some(s) = s {
386 *err_msg = alloc(&s);
387 }
388 err.extended_code
389 }
390 err => {
391 *err_msg = alloc(&err.to_string());
392 ffi::SQLITE_ERROR
393 }
394 }
395}