• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::types::FromSqlError;
2 use crate::types::Type;
3 use crate::{errmsg_to_string, ffi, Result};
4 use std::error;
5 use std::fmt;
6 use std::os::raw::c_int;
7 use std::path::PathBuf;
8 use std::str;
9 
10 /// Enum listing possible errors from rusqlite.
11 #[derive(Debug)]
12 #[allow(clippy::enum_variant_names)]
13 #[non_exhaustive]
14 pub enum Error {
15     /// An error from an underlying SQLite call.
16     SqliteFailure(ffi::Error, Option<String>),
17 
18     /// Error reported when attempting to open a connection when SQLite was
19     /// configured to allow single-threaded use only.
20     SqliteSingleThreadedMode,
21 
22     /// Error when the value of a particular column is requested, but it cannot
23     /// be converted to the requested Rust type.
24     FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync + 'static>),
25 
26     /// Error when SQLite gives us an integral value outside the range of the
27     /// requested type (e.g., trying to get the value 1000 into a `u8`).
28     /// The associated `usize` is the column index,
29     /// and the associated `i64` is the value returned by SQLite.
30     IntegralValueOutOfRange(usize, i64),
31 
32     /// Error converting a string to UTF-8.
33     Utf8Error(str::Utf8Error),
34 
35     /// Error converting a string to a C-compatible string because it contained
36     /// an embedded nul.
37     NulError(std::ffi::NulError),
38 
39     /// Error when using SQL named parameters and passing a parameter name not
40     /// present in the SQL.
41     InvalidParameterName(String),
42 
43     /// Error converting a file path to a string.
44     InvalidPath(PathBuf),
45 
46     /// Error returned when an [`execute`](crate::Connection::execute) call
47     /// returns rows.
48     ExecuteReturnedResults,
49 
50     /// Error when a query that was expected to return at least one row (e.g.,
51     /// for [`query_row`](crate::Connection::query_row)) did not return any.
52     QueryReturnedNoRows,
53 
54     /// Error when the value of a particular column is requested, but the index
55     /// is out of range for the statement.
56     InvalidColumnIndex(usize),
57 
58     /// Error when the value of a named column is requested, but no column
59     /// matches the name for the statement.
60     InvalidColumnName(String),
61 
62     /// Error when the value of a particular column is requested, but the type
63     /// of the result in that column cannot be converted to the requested
64     /// Rust type.
65     InvalidColumnType(usize, String, Type),
66 
67     /// Error when a query that was expected to insert one row did not insert
68     /// any or insert many.
69     StatementChangedRows(usize),
70 
71     /// Error returned by
72     /// [`functions::Context::get`](crate::functions::Context::get) when the
73     /// function argument cannot be converted to the requested type.
74     #[cfg(feature = "functions")]
75     #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
76     InvalidFunctionParameterType(usize, Type),
77     /// Error returned by [`vtab::Values::get`](crate::vtab::Values::get) when
78     /// the filter argument cannot be converted to the requested type.
79     #[cfg(feature = "vtab")]
80     #[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
81     InvalidFilterParameterType(usize, Type),
82 
83     /// An error case available for implementors of custom user functions (e.g.,
84     /// [`create_scalar_function`](crate::Connection::create_scalar_function)).
85     #[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     /// Error available for the implementors of the
91     /// [`ToSql`](crate::types::ToSql) trait.
92     ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
93 
94     /// Error when the SQL is not a `SELECT`, is not read-only.
95     InvalidQuery,
96 
97     /// An error case available for implementors of custom modules (e.g.,
98     /// [`create_module`](crate::Connection::create_module)).
99     #[cfg(feature = "vtab")]
100     #[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
101     #[allow(dead_code)]
102     ModuleError(String),
103 
104     /// An unwinding panic occurs in a UDF (user-defined function).
105     UnwindingPanic,
106 
107     /// An error returned when
108     /// [`Context::get_aux`](crate::functions::Context::get_aux) attempts to
109     /// retrieve data of a different type than what had been stored using
110     /// [`Context::set_aux`](crate::functions::Context::set_aux).
111     #[cfg(feature = "functions")]
112     #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
113     GetAuxWrongType,
114 
115     /// Error when the SQL contains multiple statements.
116     MultipleStatement,
117     /// Error when the number of bound parameters does not match the number of
118     /// parameters in the query. The first `usize` is how many parameters were
119     /// given, the 2nd is how many were expected.
120     InvalidParameterCount(usize, usize),
121 
122     /// Returned from various functions in the Blob IO positional API. For
123     /// example,
124     /// [`Blob::raw_read_at_exact`](crate::blob::Blob::raw_read_at_exact) will
125     /// return it if the blob has insufficient data.
126     #[cfg(feature = "blob")]
127     #[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
128     BlobSizeError,
129     /// Error referencing a specific token in the input SQL
130     #[cfg(feature = "modern_sqlite")] // 3.38.0
131     #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
132     SqlInputError {
133         /// error code
134         error: ffi::Error,
135         /// error message
136         msg: String,
137         /// SQL input
138         sql: String,
139         /// byte offset of the start of invalid token
140         offset: c_int,
141     },
142     /// Loadable extension initialization error
143     #[cfg(feature = "loadable_extension")]
144     #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))]
145     InitError(ffi::InitError),
146     /// Error when the schema of a particular database is requested, but the index
147     /// is out of range.
148     #[cfg(feature = "modern_sqlite")] // 3.39.0
149     #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
150     InvalidDatabaseIndex(usize),
151 }
152 
153 impl PartialEq for Error {
eq(&self, other: &Error) -> bool154     fn eq(&self, other: &Error) -> bool {
155         match (self, other) {
156             (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
157             (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
158             (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
159                 i1 == i2 && n1 == n2
160             }
161             (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
162             (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
163             (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
164             (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
165             (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
166             (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
167             (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
168             (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
169             (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
170                 i1 == i2 && t1 == t2 && n1 == n2
171             }
172             (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
173             #[cfg(feature = "functions")]
174             (
175                 Error::InvalidFunctionParameterType(i1, t1),
176                 Error::InvalidFunctionParameterType(i2, t2),
177             ) => i1 == i2 && t1 == t2,
178             #[cfg(feature = "vtab")]
179             (
180                 Error::InvalidFilterParameterType(i1, t1),
181                 Error::InvalidFilterParameterType(i2, t2),
182             ) => i1 == i2 && t1 == t2,
183             (Error::InvalidQuery, Error::InvalidQuery) => true,
184             #[cfg(feature = "vtab")]
185             (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
186             (Error::UnwindingPanic, Error::UnwindingPanic) => true,
187             #[cfg(feature = "functions")]
188             (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
189             (Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
190                 i1 == i2 && n1 == n2
191             }
192             #[cfg(feature = "blob")]
193             (Error::BlobSizeError, Error::BlobSizeError) => true,
194             #[cfg(feature = "modern_sqlite")]
195             (
196                 Error::SqlInputError {
197                     error: e1,
198                     msg: m1,
199                     sql: s1,
200                     offset: o1,
201                 },
202                 Error::SqlInputError {
203                     error: e2,
204                     msg: m2,
205                     sql: s2,
206                     offset: o2,
207                 },
208             ) => e1 == e2 && m1 == m2 && s1 == s2 && o1 == o2,
209             #[cfg(feature = "loadable_extension")]
210             (Error::InitError(e1), Error::InitError(e2)) => e1 == e2,
211             #[cfg(feature = "modern_sqlite")]
212             (Error::InvalidDatabaseIndex(i1), Error::InvalidDatabaseIndex(i2)) => i1 == i2,
213             (..) => false,
214         }
215     }
216 }
217 
218 impl From<str::Utf8Error> for Error {
219     #[cold]
from(err: str::Utf8Error) -> Error220     fn from(err: str::Utf8Error) -> Error {
221         Error::Utf8Error(err)
222     }
223 }
224 
225 impl From<std::ffi::NulError> for Error {
226     #[cold]
from(err: std::ffi::NulError) -> Error227     fn from(err: std::ffi::NulError) -> Error {
228         Error::NulError(err)
229     }
230 }
231 
232 const UNKNOWN_COLUMN: usize = usize::MAX;
233 
234 /// The conversion isn't precise, but it's convenient to have it
235 /// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
236 impl From<FromSqlError> for Error {
237     #[cold]
from(err: FromSqlError) -> Error238     fn from(err: FromSqlError) -> Error {
239         // The error type requires index and type fields, but they aren't known in this
240         // context.
241         match err {
242             FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
243             FromSqlError::InvalidBlobSize { .. } => {
244                 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
245             }
246             FromSqlError::Other(source) => {
247                 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
248             }
249             _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
250         }
251     }
252 }
253 
254 #[cfg(feature = "loadable_extension")]
255 impl From<ffi::InitError> for Error {
256     #[cold]
from(err: ffi::InitError) -> Error257     fn from(err: ffi::InitError) -> Error {
258         Error::InitError(err)
259     }
260 }
261 
262 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result263     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264         match *self {
265             Error::SqliteFailure(ref err, None) => err.fmt(f),
266             Error::SqliteFailure(_, Some(ref s)) => write!(f, "{s}"),
267             Error::SqliteSingleThreadedMode => write!(
268                 f,
269                 "SQLite was compiled or configured for single-threaded use only"
270             ),
271             Error::FromSqlConversionFailure(i, ref t, ref err) => {
272                 if i != UNKNOWN_COLUMN {
273                     write!(f, "Conversion error from type {t} at index: {i}, {err}")
274                 } else {
275                     err.fmt(f)
276                 }
277             }
278             Error::IntegralValueOutOfRange(col, val) => {
279                 if col != UNKNOWN_COLUMN {
280                     write!(f, "Integer {val} out of range at index {col}")
281                 } else {
282                     write!(f, "Integer {val} out of range")
283                 }
284             }
285             Error::Utf8Error(ref err) => err.fmt(f),
286             Error::NulError(ref err) => err.fmt(f),
287             Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {name}"),
288             Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
289             Error::ExecuteReturnedResults => {
290                 write!(f, "Execute returned results - did you mean to call query?")
291             }
292             Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
293             Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"),
294             Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"),
295             Error::InvalidColumnType(i, ref name, ref t) => {
296                 write!(f, "Invalid column type {t} at index: {i}, name: {name}")
297             }
298             Error::InvalidParameterCount(i1, n1) => write!(
299                 f,
300                 "Wrong number of parameters passed to query. Got {i1}, needed {n1}"
301             ),
302             Error::StatementChangedRows(i) => write!(f, "Query changed {i} rows"),
303 
304             #[cfg(feature = "functions")]
305             Error::InvalidFunctionParameterType(i, ref t) => {
306                 write!(f, "Invalid function parameter type {t} at index {i}")
307             }
308             #[cfg(feature = "vtab")]
309             Error::InvalidFilterParameterType(i, ref t) => {
310                 write!(f, "Invalid filter parameter type {t} at index {i}")
311             }
312             #[cfg(feature = "functions")]
313             Error::UserFunctionError(ref err) => err.fmt(f),
314             Error::ToSqlConversionFailure(ref err) => err.fmt(f),
315             Error::InvalidQuery => write!(f, "Query is not read-only"),
316             #[cfg(feature = "vtab")]
317             Error::ModuleError(ref desc) => write!(f, "{desc}"),
318             Error::UnwindingPanic => write!(f, "unwinding panic"),
319             #[cfg(feature = "functions")]
320             Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
321             Error::MultipleStatement => write!(f, "Multiple statements provided"),
322             #[cfg(feature = "blob")]
323             Error::BlobSizeError => "Blob size is insufficient".fmt(f),
324             #[cfg(feature = "modern_sqlite")]
325             Error::SqlInputError {
326                 ref msg,
327                 offset,
328                 ref sql,
329                 ..
330             } => write!(f, "{msg} in {sql} at offset {offset}"),
331             #[cfg(feature = "loadable_extension")]
332             Error::InitError(ref err) => err.fmt(f),
333             #[cfg(feature = "modern_sqlite")]
334             Error::InvalidDatabaseIndex(i) => write!(f, "Invalid database index: {i}"),
335         }
336     }
337 }
338 
339 impl error::Error for Error {
source(&self) -> Option<&(dyn error::Error + 'static)>340     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
341         match *self {
342             Error::SqliteFailure(ref err, _) => Some(err),
343             Error::Utf8Error(ref err) => Some(err),
344             Error::NulError(ref err) => Some(err),
345 
346             Error::IntegralValueOutOfRange(..)
347             | Error::SqliteSingleThreadedMode
348             | Error::InvalidParameterName(_)
349             | Error::ExecuteReturnedResults
350             | Error::QueryReturnedNoRows
351             | Error::InvalidColumnIndex(_)
352             | Error::InvalidColumnName(_)
353             | Error::InvalidColumnType(..)
354             | Error::InvalidPath(_)
355             | Error::InvalidParameterCount(..)
356             | Error::StatementChangedRows(_)
357             | Error::InvalidQuery
358             | Error::MultipleStatement => None,
359 
360             #[cfg(feature = "functions")]
361             Error::InvalidFunctionParameterType(..) => None,
362             #[cfg(feature = "vtab")]
363             Error::InvalidFilterParameterType(..) => None,
364 
365             #[cfg(feature = "functions")]
366             Error::UserFunctionError(ref err) => Some(&**err),
367 
368             Error::FromSqlConversionFailure(_, _, ref err)
369             | Error::ToSqlConversionFailure(ref err) => Some(&**err),
370 
371             #[cfg(feature = "vtab")]
372             Error::ModuleError(_) => None,
373 
374             Error::UnwindingPanic => None,
375 
376             #[cfg(feature = "functions")]
377             Error::GetAuxWrongType => None,
378 
379             #[cfg(feature = "blob")]
380             Error::BlobSizeError => None,
381             #[cfg(feature = "modern_sqlite")]
382             Error::SqlInputError { ref error, .. } => Some(error),
383             #[cfg(feature = "loadable_extension")]
384             Error::InitError(ref err) => Some(err),
385             #[cfg(feature = "modern_sqlite")]
386             Error::InvalidDatabaseIndex(_) => None,
387         }
388     }
389 }
390 
391 impl Error {
392     /// Returns the underlying SQLite error if this is [`Error::SqliteFailure`].
393     #[inline]
394     #[must_use]
sqlite_error(&self) -> Option<&ffi::Error>395     pub fn sqlite_error(&self) -> Option<&ffi::Error> {
396         match self {
397             Self::SqliteFailure(error, _) => Some(error),
398             _ => None,
399         }
400     }
401 
402     /// Returns the underlying SQLite error code if this is
403     /// [`Error::SqliteFailure`].
404     #[inline]
405     #[must_use]
sqlite_error_code(&self) -> Option<ffi::ErrorCode>406     pub fn sqlite_error_code(&self) -> Option<ffi::ErrorCode> {
407         self.sqlite_error().map(|error| error.code)
408     }
409 }
410 
411 // These are public but not re-exported by lib.rs, so only visible within crate.
412 
413 #[cold]
error_from_sqlite_code(code: c_int, message: Option<String>) -> Error414 pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
415     Error::SqliteFailure(ffi::Error::new(code), message)
416 }
417 
418 #[cold]
error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error419 pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
420     let message = if db.is_null() {
421         None
422     } else {
423         Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
424     };
425     error_from_sqlite_code(code, message)
426 }
427 
428 #[cold]
429 #[cfg(not(feature = "modern_sqlite"))] // SQLite >= 3.38.0
error_with_offset(db: *mut ffi::sqlite3, code: c_int, _sql: &str) -> Error430 pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, _sql: &str) -> Error {
431     error_from_handle(db, code)
432 }
433 
434 #[cold]
435 #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error436 pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error {
437     if db.is_null() {
438         error_from_sqlite_code(code, None)
439     } else {
440         let error = ffi::Error::new(code);
441         let msg = errmsg_to_string(ffi::sqlite3_errmsg(db));
442         if ffi::ErrorCode::Unknown == error.code {
443             let offset = ffi::sqlite3_error_offset(db);
444             if offset >= 0 {
445                 return Error::SqlInputError {
446                     error,
447                     msg,
448                     sql: sql.to_owned(),
449                     offset,
450                 };
451             }
452         }
453         Error::SqliteFailure(error, Some(msg))
454     }
455 }
456 
check(code: c_int) -> Result<()>457 pub fn check(code: c_int) -> Result<()> {
458     if code != crate::ffi::SQLITE_OK {
459         Err(error_from_sqlite_code(code, None))
460     } else {
461         Ok(())
462     }
463 }
464 
465 /// Transform Rust error to SQLite error (message and code).
466 /// # Safety
467 /// This function is unsafe because it uses raw pointer
to_sqlite_error(e: &Error, err_msg: *mut *mut std::os::raw::c_char) -> c_int468 pub unsafe fn to_sqlite_error(e: &Error, err_msg: *mut *mut std::os::raw::c_char) -> c_int {
469     use crate::util::alloc;
470     match e {
471         Error::SqliteFailure(err, s) => {
472             if let Some(s) = s {
473                 *err_msg = alloc(s);
474             }
475             err.extended_code
476         }
477         err => {
478             *err_msg = alloc(&err.to_string());
479             ffi::SQLITE_ERROR
480         }
481     }
482 }
483