1use crate::types::FromSqlError;
2use crate::types::Type;
3use crate::{errmsg_to_string, ffi, Result};
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,
49
50 QueryReturnedNoRows,
53
54 InvalidColumnIndex(usize),
57
58 InvalidColumnName(String),
61
62 InvalidColumnType(usize, String, Type),
66
67 StatementChangedRows(usize),
70
71 #[cfg(feature = "functions")]
75 #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
76 InvalidFunctionParameterType(usize, Type),
77 #[cfg(feature = "vtab")]
80 #[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
81 InvalidFilterParameterType(usize, Type),
82
83 #[cfg(feature = "functions")]
86 #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
87 #[allow(dead_code)]
88 UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
89
90 ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
93
94 InvalidQuery,
96
97 #[cfg(feature = "vtab")]
100 #[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
101 #[allow(dead_code)]
102 ModuleError(String),
103
104 #[cfg(feature = "functions")]
106 #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
107 UnwindingPanic,
108
109 #[cfg(feature = "functions")]
114 #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
115 GetAuxWrongType,
116
117 MultipleStatement,
119 InvalidParameterCount(usize, usize),
123
124 #[cfg(feature = "blob")]
129 #[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
130 BlobSizeError,
131 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
134 SqlInputError {
135 error: ffi::Error,
137 msg: String,
139 sql: String,
141 offset: c_int,
143 },
144}
145
146impl PartialEq for Error {
147 fn eq(&self, other: &Error) -> bool {
148 match (self, other) {
149 (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
150 (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
151 (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
152 i1 == i2 && n1 == n2
153 }
154 (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
155 (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
156 (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
157 (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
158 (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
159 (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
160 (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
161 (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
162 (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
163 i1 == i2 && t1 == t2 && n1 == n2
164 }
165 (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
166 #[cfg(feature = "functions")]
167 (
168 Error::InvalidFunctionParameterType(i1, t1),
169 Error::InvalidFunctionParameterType(i2, t2),
170 ) => i1 == i2 && t1 == t2,
171 #[cfg(feature = "vtab")]
172 (
173 Error::InvalidFilterParameterType(i1, t1),
174 Error::InvalidFilterParameterType(i2, t2),
175 ) => i1 == i2 && t1 == t2,
176 (Error::InvalidQuery, Error::InvalidQuery) => true,
177 #[cfg(feature = "vtab")]
178 (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
179 #[cfg(feature = "functions")]
180 (Error::UnwindingPanic, Error::UnwindingPanic) => true,
181 #[cfg(feature = "functions")]
182 (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
183 (Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
184 i1 == i2 && n1 == n2
185 }
186 #[cfg(feature = "blob")]
187 (Error::BlobSizeError, Error::BlobSizeError) => true,
188 #[cfg(feature = "modern_sqlite")]
189 (
190 Error::SqlInputError {
191 error: e1,
192 msg: m1,
193 sql: s1,
194 offset: o1,
195 },
196 Error::SqlInputError {
197 error: e2,
198 msg: m2,
199 sql: s2,
200 offset: o2,
201 },
202 ) => e1 == e2 && m1 == m2 && s1 == s2 && o1 == o2,
203 (..) => false,
204 }
205 }
206}
207
208impl From<str::Utf8Error> for Error {
209 #[cold]
210 fn from(err: str::Utf8Error) -> Error {
211 Error::Utf8Error(err)
212 }
213}
214
215impl From<std::ffi::NulError> for Error {
216 #[cold]
217 fn from(err: std::ffi::NulError) -> Error {
218 Error::NulError(err)
219 }
220}
221
222const UNKNOWN_COLUMN: usize = usize::MAX;
223
224impl From<FromSqlError> for Error {
227 #[cold]
228 fn from(err: FromSqlError) -> Error {
229 match err {
232 FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
233 FromSqlError::InvalidBlobSize { .. } => {
234 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
235 }
236 FromSqlError::Other(source) => {
237 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
238 }
239 _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
240 }
241 }
242}
243
244impl fmt::Display for Error {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 match *self {
247 Error::SqliteFailure(ref err, None) => err.fmt(f),
248 Error::SqliteFailure(_, Some(ref s)) => write!(f, "{s}"),
249 Error::SqliteSingleThreadedMode => write!(
250 f,
251 "SQLite was compiled or configured for single-threaded use only"
252 ),
253 Error::FromSqlConversionFailure(i, ref t, ref err) => {
254 if i != UNKNOWN_COLUMN {
255 write!(
256 f,
257 "Conversion error from type {} at index: {}, {}",
258 t, i, err
259 )
260 } else {
261 err.fmt(f)
262 }
263 }
264 Error::IntegralValueOutOfRange(col, val) => {
265 if col != UNKNOWN_COLUMN {
266 write!(f, "Integer {val} out of range at index {col}")
267 } else {
268 write!(f, "Integer {val} out of range")
269 }
270 }
271 Error::Utf8Error(ref err) => err.fmt(f),
272 Error::NulError(ref err) => err.fmt(f),
273 Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {name}"),
274 Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
275 Error::ExecuteReturnedResults => {
276 write!(f, "Execute returned results - did you mean to call query?")
277 }
278 Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
279 Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"),
280 Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"),
281 Error::InvalidColumnType(i, ref name, ref t) => write!(
282 f,
283 "Invalid column type {} at index: {}, name: {}",
284 t, i, name
285 ),
286 Error::InvalidParameterCount(i1, n1) => write!(
287 f,
288 "Wrong number of parameters passed to query. Got {}, needed {}",
289 i1, n1
290 ),
291 Error::StatementChangedRows(i) => write!(f, "Query changed {i} rows"),
292
293 #[cfg(feature = "functions")]
294 Error::InvalidFunctionParameterType(i, ref t) => {
295 write!(f, "Invalid function parameter type {t} at index {i}")
296 }
297 #[cfg(feature = "vtab")]
298 Error::InvalidFilterParameterType(i, ref t) => {
299 write!(f, "Invalid filter parameter type {t} at index {i}")
300 }
301 #[cfg(feature = "functions")]
302 Error::UserFunctionError(ref err) => err.fmt(f),
303 Error::ToSqlConversionFailure(ref err) => err.fmt(f),
304 Error::InvalidQuery => write!(f, "Query is not read-only"),
305 #[cfg(feature = "vtab")]
306 Error::ModuleError(ref desc) => write!(f, "{desc}"),
307 #[cfg(feature = "functions")]
308 Error::UnwindingPanic => write!(f, "unwinding panic"),
309 #[cfg(feature = "functions")]
310 Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
311 Error::MultipleStatement => write!(f, "Multiple statements provided"),
312 #[cfg(feature = "blob")]
313 Error::BlobSizeError => "Blob size is insufficient".fmt(f),
314 #[cfg(feature = "modern_sqlite")]
315 Error::SqlInputError {
316 ref msg,
317 offset,
318 ref sql,
319 ..
320 } => write!(f, "{msg} in {sql} at offset {offset}"),
321 }
322 }
323}
324
325impl error::Error for Error {
326 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
327 match *self {
328 Error::SqliteFailure(ref err, _) => Some(err),
329 Error::Utf8Error(ref err) => Some(err),
330 Error::NulError(ref err) => Some(err),
331
332 Error::IntegralValueOutOfRange(..)
333 | Error::SqliteSingleThreadedMode
334 | Error::InvalidParameterName(_)
335 | Error::ExecuteReturnedResults
336 | Error::QueryReturnedNoRows
337 | Error::InvalidColumnIndex(_)
338 | Error::InvalidColumnName(_)
339 | Error::InvalidColumnType(..)
340 | Error::InvalidPath(_)
341 | Error::InvalidParameterCount(..)
342 | Error::StatementChangedRows(_)
343 | Error::InvalidQuery
344 | Error::MultipleStatement => None,
345
346 #[cfg(feature = "functions")]
347 Error::InvalidFunctionParameterType(..) => None,
348 #[cfg(feature = "vtab")]
349 Error::InvalidFilterParameterType(..) => None,
350
351 #[cfg(feature = "functions")]
352 Error::UserFunctionError(ref err) => Some(&**err),
353
354 Error::FromSqlConversionFailure(_, _, ref err)
355 | Error::ToSqlConversionFailure(ref err) => Some(&**err),
356
357 #[cfg(feature = "vtab")]
358 Error::ModuleError(_) => None,
359
360 #[cfg(feature = "functions")]
361 Error::UnwindingPanic => None,
362
363 #[cfg(feature = "functions")]
364 Error::GetAuxWrongType => None,
365
366 #[cfg(feature = "blob")]
367 Error::BlobSizeError => None,
368 #[cfg(feature = "modern_sqlite")]
369 Error::SqlInputError { ref error, .. } => Some(error),
370 }
371 }
372}
373
374impl Error {
375 #[inline]
377 pub fn sqlite_error(&self) -> Option<&ffi::Error> {
378 match self {
379 Self::SqliteFailure(error, _) => Some(error),
380 _ => None,
381 }
382 }
383
384 #[inline]
387 pub fn sqlite_error_code(&self) -> Option<ffi::ErrorCode> {
388 self.sqlite_error().map(|error| error.code)
389 }
390}
391
392#[cold]
395pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
396 Error::SqliteFailure(ffi::Error::new(code), message)
398}
399
400#[cold]
401pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
402 let message = if db.is_null() {
403 None
404 } else {
405 Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
406 };
407 error_from_sqlite_code(code, message)
408}
409
410#[cold]
411#[cfg(not(feature = "modern_sqlite"))] pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, _sql: &str) -> Error {
413 error_from_handle(db, code)
414}
415
416#[cold]
417#[cfg(feature = "modern_sqlite")] pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error {
419 if db.is_null() {
420 error_from_sqlite_code(code, None)
421 } else {
422 let error = ffi::Error::new(code);
423 let msg = errmsg_to_string(ffi::sqlite3_errmsg(db));
424 if ffi::ErrorCode::Unknown == error.code {
425 let offset = ffi::sqlite3_error_offset(db);
426 if offset >= 0 {
427 return Error::SqlInputError {
428 error,
429 msg,
430 sql: sql.to_owned(),
431 offset,
432 };
433 }
434 }
435 Error::SqliteFailure(error, Some(msg))
436 }
437}
438
439pub fn check(code: c_int) -> Result<()> {
440 if code != crate::ffi::SQLITE_OK {
441 Err(error_from_sqlite_code(code, None))
442 } else {
443 Ok(())
444 }
445}