1 use crate::types::FromSqlError;
2 use crate::types::Type;
3 use crate::{errmsg_to_string, ffi};
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` call returns rows.
47     ExecuteReturnedResults,
48 
49     /// Error when a query that was expected to return at least one row (e.g.,
50     /// for `query_row`) did not return any.
51     QueryReturnedNoRows,
52 
53     /// Error when the value of a particular column is requested, but the index
54     /// is out of range for the statement.
55     InvalidColumnIndex(usize),
56 
57     /// Error when the value of a named column is requested, but no column
58     /// matches the name for the statement.
59     InvalidColumnName(String),
60 
61     /// Error when the value of a particular column is requested, but the type
62     /// of the result in that column cannot be converted to the requested
63     /// Rust type.
64     InvalidColumnType(usize, String, Type),
65 
66     /// Error when a query that was expected to insert one row did not insert
67     /// any or insert many.
68     StatementChangedRows(usize),
69 
70     /// Error returned by `functions::Context::get` when the function argument
71     /// cannot be converted to the requested type.
72     #[cfg(feature = "functions")]
73     InvalidFunctionParameterType(usize, Type),
74     /// Error returned by `vtab::Values::get` when the filter argument cannot
75     /// be converted to the requested type.
76     #[cfg(feature = "vtab")]
77     InvalidFilterParameterType(usize, Type),
78 
79     /// An error case available for implementors of custom user functions (e.g.,
80     /// `create_scalar_function`).
81     #[cfg(feature = "functions")]
82     #[allow(dead_code)]
83     UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
84 
85     /// Error available for the implementors of the `ToSql` trait.
86     ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
87 
88     /// Error when the SQL is not a `SELECT`, is not read-only.
89     InvalidQuery,
90 
91     /// An error case available for implementors of custom modules (e.g.,
92     /// `create_module`).
93     #[cfg(feature = "vtab")]
94     #[allow(dead_code)]
95     ModuleError(String),
96 
97     /// An unwinding panic occurs in an UDF (user-defined function).
98     #[cfg(feature = "functions")]
99     UnwindingPanic,
100 
101     /// An error returned when `Context::get_aux` attempts to retrieve data
102     /// of a different type than what had been stored using `Context::set_aux`.
103     #[cfg(feature = "functions")]
104     GetAuxWrongType,
105 
106     /// Error when the SQL contains multiple statements.
107     MultipleStatement,
108     /// Error when the number of bound parameters does not match the number of
109     /// parameters in the query. The first `usize` is how many parameters were
110     /// given, the 2nd is how many were expected.
111     InvalidParameterCount(usize, usize),
112 
113     /// Returned from various functions in the Blob IO positional API. For
114     /// example, [`Blob::raw_read_at_exact`](crate::blob::Blob::raw_read_at_exact)
115     /// will return it if the blob has insufficient data.
116     #[cfg(feature = "blob")]
117     BlobSizeError,
118 }
119 
120 impl PartialEq for Error {
eq(&self, other: &Error) -> bool121     fn eq(&self, other: &Error) -> bool {
122         match (self, other) {
123             (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
124             (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
125             (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
126                 i1 == i2 && n1 == n2
127             }
128             (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
129             (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
130             (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
131             (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
132             (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
133             (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
134             (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
135             (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
136             (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
137                 i1 == i2 && t1 == t2 && n1 == n2
138             }
139             (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
140             #[cfg(feature = "functions")]
141             (
142                 Error::InvalidFunctionParameterType(i1, t1),
143                 Error::InvalidFunctionParameterType(i2, t2),
144             ) => i1 == i2 && t1 == t2,
145             #[cfg(feature = "vtab")]
146             (
147                 Error::InvalidFilterParameterType(i1, t1),
148                 Error::InvalidFilterParameterType(i2, t2),
149             ) => i1 == i2 && t1 == t2,
150             (Error::InvalidQuery, Error::InvalidQuery) => true,
151             #[cfg(feature = "vtab")]
152             (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
153             #[cfg(feature = "functions")]
154             (Error::UnwindingPanic, Error::UnwindingPanic) => true,
155             #[cfg(feature = "functions")]
156             (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
157             (Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
158                 i1 == i2 && n1 == n2
159             }
160             #[cfg(feature = "blob")]
161             (Error::BlobSizeError, Error::BlobSizeError) => true,
162             (..) => false,
163         }
164     }
165 }
166 
167 impl From<str::Utf8Error> for Error {
from(err: str::Utf8Error) -> Error168     fn from(err: str::Utf8Error) -> Error {
169         Error::Utf8Error(err)
170     }
171 }
172 
173 impl From<::std::ffi::NulError> for Error {
from(err: ::std::ffi::NulError) -> Error174     fn from(err: ::std::ffi::NulError) -> Error {
175         Error::NulError(err)
176     }
177 }
178 
179 const UNKNOWN_COLUMN: usize = std::usize::MAX;
180 
181 /// The conversion isn't precise, but it's convenient to have it
182 /// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
183 impl From<FromSqlError> for Error {
from(err: FromSqlError) -> Error184     fn from(err: FromSqlError) -> Error {
185         // The error type requires index and type fields, but they aren't known in this
186         // context.
187         match err {
188             FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
189             #[cfg(feature = "i128_blob")]
190             FromSqlError::InvalidI128Size(_) => {
191                 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
192             }
193             #[cfg(feature = "uuid")]
194             FromSqlError::InvalidUuidSize(_) => {
195                 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
196             }
197             FromSqlError::Other(source) => {
198                 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
199             }
200             _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
201         }
202     }
203 }
204 
205 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result206     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207         match *self {
208             Error::SqliteFailure(ref err, None) => err.fmt(f),
209             Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
210             Error::SqliteSingleThreadedMode => write!(
211                 f,
212                 "SQLite was compiled or configured for single-threaded use only"
213             ),
214             Error::FromSqlConversionFailure(i, ref t, ref err) => {
215                 if i != UNKNOWN_COLUMN {
216                     write!(
217                         f,
218                         "Conversion error from type {} at index: {}, {}",
219                         t, i, err
220                     )
221                 } else {
222                     err.fmt(f)
223                 }
224             }
225             Error::IntegralValueOutOfRange(col, val) => {
226                 if col != UNKNOWN_COLUMN {
227                     write!(f, "Integer {} out of range at index {}", val, col)
228                 } else {
229                     write!(f, "Integer {} out of range", val)
230                 }
231             }
232             Error::Utf8Error(ref err) => err.fmt(f),
233             Error::NulError(ref err) => err.fmt(f),
234             Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
235             Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
236             Error::ExecuteReturnedResults => {
237                 write!(f, "Execute returned results - did you mean to call query?")
238             }
239             Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
240             Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
241             Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
242             Error::InvalidColumnType(i, ref name, ref t) => write!(
243                 f,
244                 "Invalid column type {} at index: {}, name: {}",
245                 t, i, name
246             ),
247             Error::InvalidParameterCount(i1, n1) => write!(
248                 f,
249                 "Wrong number of parameters passed to query. Got {}, needed {}",
250                 i1, n1
251             ),
252             Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
253 
254             #[cfg(feature = "functions")]
255             Error::InvalidFunctionParameterType(i, ref t) => {
256                 write!(f, "Invalid function parameter type {} at index {}", t, i)
257             }
258             #[cfg(feature = "vtab")]
259             Error::InvalidFilterParameterType(i, ref t) => {
260                 write!(f, "Invalid filter parameter type {} at index {}", t, i)
261             }
262             #[cfg(feature = "functions")]
263             Error::UserFunctionError(ref err) => err.fmt(f),
264             Error::ToSqlConversionFailure(ref err) => err.fmt(f),
265             Error::InvalidQuery => write!(f, "Query is not read-only"),
266             #[cfg(feature = "vtab")]
267             Error::ModuleError(ref desc) => write!(f, "{}", desc),
268             #[cfg(feature = "functions")]
269             Error::UnwindingPanic => write!(f, "unwinding panic"),
270             #[cfg(feature = "functions")]
271             Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
272             Error::MultipleStatement => write!(f, "Multiple statements provided"),
273 
274             #[cfg(feature = "blob")]
275             Error::BlobSizeError => "Blob size is insufficient".fmt(f),
276         }
277     }
278 }
279 
280 impl error::Error for Error {
source(&self) -> Option<&(dyn error::Error + 'static)>281     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
282         match *self {
283             Error::SqliteFailure(ref err, _) => Some(err),
284             Error::Utf8Error(ref err) => Some(err),
285             Error::NulError(ref err) => Some(err),
286 
287             Error::IntegralValueOutOfRange(..)
288             | Error::SqliteSingleThreadedMode
289             | Error::InvalidParameterName(_)
290             | Error::ExecuteReturnedResults
291             | Error::QueryReturnedNoRows
292             | Error::InvalidColumnIndex(_)
293             | Error::InvalidColumnName(_)
294             | Error::InvalidColumnType(..)
295             | Error::InvalidPath(_)
296             | Error::InvalidParameterCount(..)
297             | Error::StatementChangedRows(_)
298             | Error::InvalidQuery
299             | Error::MultipleStatement => None,
300 
301             #[cfg(feature = "functions")]
302             Error::InvalidFunctionParameterType(..) => None,
303             #[cfg(feature = "vtab")]
304             Error::InvalidFilterParameterType(..) => None,
305 
306             #[cfg(feature = "functions")]
307             Error::UserFunctionError(ref err) => Some(&**err),
308 
309             Error::FromSqlConversionFailure(_, _, ref err)
310             | Error::ToSqlConversionFailure(ref err) => Some(&**err),
311 
312             #[cfg(feature = "vtab")]
313             Error::ModuleError(_) => None,
314 
315             #[cfg(feature = "functions")]
316             Error::UnwindingPanic => None,
317 
318             #[cfg(feature = "functions")]
319             Error::GetAuxWrongType => None,
320 
321             #[cfg(feature = "blob")]
322             Error::BlobSizeError => None,
323         }
324     }
325 }
326 
327 // These are public but not re-exported by lib.rs, so only visible within crate.
328 
error_from_sqlite_code(code: c_int, message: Option<String>) -> Error329 pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
330     Error::SqliteFailure(ffi::Error::new(code), message)
331 }
332 
error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error333 pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
334     let message = if db.is_null() {
335         None
336     } else {
337         Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
338     };
339     error_from_sqlite_code(code, message)
340 }
341 
342 macro_rules! check {
343     ($funcall:expr) => {{
344         let rc = $funcall;
345         if rc != crate::ffi::SQLITE_OK {
346             return Err(crate::error::error_from_sqlite_code(rc, None).into());
347         }
348     }};
349 }
350