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 an UDF (user-defined function).
105     #[cfg(feature = "functions")]
106     #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
107     UnwindingPanic,
108 
109     /// An error returned when
110     /// [`Context::get_aux`](crate::functions::Context::get_aux) attempts to
111     /// retrieve data of a different type than what had been stored using
112     /// [`Context::set_aux`](crate::functions::Context::set_aux).
113     #[cfg(feature = "functions")]
114     #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
115     GetAuxWrongType,
116 
117     /// Error when the SQL contains multiple statements.
118     MultipleStatement,
119     /// Error when the number of bound parameters does not match the number of
120     /// parameters in the query. The first `usize` is how many parameters were
121     /// given, the 2nd is how many were expected.
122     InvalidParameterCount(usize, usize),
123 
124     /// Returned from various functions in the Blob IO positional API. For
125     /// example,
126     /// [`Blob::raw_read_at_exact`](crate::blob::Blob::raw_read_at_exact) will
127     /// return it if the blob has insufficient data.
128     #[cfg(feature = "blob")]
129     #[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
130     BlobSizeError,
131     /// Error referencing a specific token in the input SQL
132     #[cfg(feature = "modern_sqlite")] // 3.38.0
133     #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
134     SqlInputError {
135         /// error code
136         error: ffi::Error,
137         /// error message
138         msg: String,
139         /// SQL input
140         sql: String,
141         /// byte offset of the start of invalid token
142         offset: c_int,
143     },
144 }
145 
146 impl PartialEq for Error {
eq(&self, other: &Error) -> bool147     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 
208 impl From<str::Utf8Error> for Error {
209     #[cold]
from(err: str::Utf8Error) -> Error210     fn from(err: str::Utf8Error) -> Error {
211         Error::Utf8Error(err)
212     }
213 }
214 
215 impl From<std::ffi::NulError> for Error {
216     #[cold]
from(err: std::ffi::NulError) -> Error217     fn from(err: std::ffi::NulError) -> Error {
218         Error::NulError(err)
219     }
220 }
221 
222 const UNKNOWN_COLUMN: usize = usize::MAX;
223 
224 /// The conversion isn't precise, but it's convenient to have it
225 /// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
226 impl From<FromSqlError> for Error {
227     #[cold]
from(err: FromSqlError) -> Error228     fn from(err: FromSqlError) -> Error {
229         // The error type requires index and type fields, but they aren't known in this
230         // context.
231         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 
244 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result245     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 
325 impl error::Error for Error {
source(&self) -> Option<&(dyn error::Error + 'static)>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 
374 impl Error {
375     /// Returns the underlying SQLite error if this is [`Error::SqliteFailure`].
376     #[inline]
sqlite_error(&self) -> Option<&ffi::Error>377     pub fn sqlite_error(&self) -> Option<&ffi::Error> {
378         match self {
379             Self::SqliteFailure(error, _) => Some(error),
380             _ => None,
381         }
382     }
383 
384     /// Returns the underlying SQLite error code if this is
385     /// [`Error::SqliteFailure`].
386     #[inline]
sqlite_error_code(&self) -> Option<ffi::ErrorCode>387     pub fn sqlite_error_code(&self) -> Option<ffi::ErrorCode> {
388         self.sqlite_error().map(|error| error.code)
389     }
390 }
391 
392 // These are public but not re-exported by lib.rs, so only visible within crate.
393 
394 #[cold]
error_from_sqlite_code(code: c_int, message: Option<String>) -> Error395 pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
396     // TODO sqlite3_error_offset // 3.38.0, #1130
397     Error::SqliteFailure(ffi::Error::new(code), message)
398 }
399 
400 #[cold]
error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error401 pub 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"))] // SQLite >= 3.38.0
error_with_offset(db: *mut ffi::sqlite3, code: c_int, _sql: &str) -> Error412 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")] // SQLite >= 3.38.0
error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error418 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 
check(code: c_int) -> Result<()>439 pub 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 }
446