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 }
132
133 impl PartialEq for Error {
eq(&self, other: &Error) -> bool134 fn eq(&self, other: &Error) -> bool {
135 match (self, other) {
136 (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
137 (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
138 (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
139 i1 == i2 && n1 == n2
140 }
141 (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
142 (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
143 (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
144 (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
145 (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
146 (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
147 (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
148 (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
149 (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
150 i1 == i2 && t1 == t2 && n1 == n2
151 }
152 (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
153 #[cfg(feature = "functions")]
154 (
155 Error::InvalidFunctionParameterType(i1, t1),
156 Error::InvalidFunctionParameterType(i2, t2),
157 ) => i1 == i2 && t1 == t2,
158 #[cfg(feature = "vtab")]
159 (
160 Error::InvalidFilterParameterType(i1, t1),
161 Error::InvalidFilterParameterType(i2, t2),
162 ) => i1 == i2 && t1 == t2,
163 (Error::InvalidQuery, Error::InvalidQuery) => true,
164 #[cfg(feature = "vtab")]
165 (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
166 #[cfg(feature = "functions")]
167 (Error::UnwindingPanic, Error::UnwindingPanic) => true,
168 #[cfg(feature = "functions")]
169 (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
170 (Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
171 i1 == i2 && n1 == n2
172 }
173 #[cfg(feature = "blob")]
174 (Error::BlobSizeError, Error::BlobSizeError) => true,
175 (..) => false,
176 }
177 }
178 }
179
180 impl From<str::Utf8Error> for Error {
181 #[cold]
from(err: str::Utf8Error) -> Error182 fn from(err: str::Utf8Error) -> Error {
183 Error::Utf8Error(err)
184 }
185 }
186
187 impl From<::std::ffi::NulError> for Error {
188 #[cold]
from(err: ::std::ffi::NulError) -> Error189 fn from(err: ::std::ffi::NulError) -> Error {
190 Error::NulError(err)
191 }
192 }
193
194 const UNKNOWN_COLUMN: usize = std::usize::MAX;
195
196 /// The conversion isn't precise, but it's convenient to have it
197 /// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
198 impl From<FromSqlError> for Error {
199 #[cold]
from(err: FromSqlError) -> Error200 fn from(err: FromSqlError) -> Error {
201 // The error type requires index and type fields, but they aren't known in this
202 // context.
203 match err {
204 FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
205 #[cfg(feature = "i128_blob")]
206 FromSqlError::InvalidI128Size(_) => {
207 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
208 }
209 #[cfg(feature = "uuid")]
210 FromSqlError::InvalidUuidSize(_) => {
211 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
212 }
213 FromSqlError::Other(source) => {
214 Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
215 }
216 _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
217 }
218 }
219 }
220
221 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 match *self {
224 Error::SqliteFailure(ref err, None) => err.fmt(f),
225 Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
226 Error::SqliteSingleThreadedMode => write!(
227 f,
228 "SQLite was compiled or configured for single-threaded use only"
229 ),
230 Error::FromSqlConversionFailure(i, ref t, ref err) => {
231 if i != UNKNOWN_COLUMN {
232 write!(
233 f,
234 "Conversion error from type {} at index: {}, {}",
235 t, i, err
236 )
237 } else {
238 err.fmt(f)
239 }
240 }
241 Error::IntegralValueOutOfRange(col, val) => {
242 if col != UNKNOWN_COLUMN {
243 write!(f, "Integer {} out of range at index {}", val, col)
244 } else {
245 write!(f, "Integer {} out of range", val)
246 }
247 }
248 Error::Utf8Error(ref err) => err.fmt(f),
249 Error::NulError(ref err) => err.fmt(f),
250 Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
251 Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
252 Error::ExecuteReturnedResults => {
253 write!(f, "Execute returned results - did you mean to call query?")
254 }
255 Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
256 Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
257 Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
258 Error::InvalidColumnType(i, ref name, ref t) => write!(
259 f,
260 "Invalid column type {} at index: {}, name: {}",
261 t, i, name
262 ),
263 Error::InvalidParameterCount(i1, n1) => write!(
264 f,
265 "Wrong number of parameters passed to query. Got {}, needed {}",
266 i1, n1
267 ),
268 Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
269
270 #[cfg(feature = "functions")]
271 Error::InvalidFunctionParameterType(i, ref t) => {
272 write!(f, "Invalid function parameter type {} at index {}", t, i)
273 }
274 #[cfg(feature = "vtab")]
275 Error::InvalidFilterParameterType(i, ref t) => {
276 write!(f, "Invalid filter parameter type {} at index {}", t, i)
277 }
278 #[cfg(feature = "functions")]
279 Error::UserFunctionError(ref err) => err.fmt(f),
280 Error::ToSqlConversionFailure(ref err) => err.fmt(f),
281 Error::InvalidQuery => write!(f, "Query is not read-only"),
282 #[cfg(feature = "vtab")]
283 Error::ModuleError(ref desc) => write!(f, "{}", desc),
284 #[cfg(feature = "functions")]
285 Error::UnwindingPanic => write!(f, "unwinding panic"),
286 #[cfg(feature = "functions")]
287 Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
288 Error::MultipleStatement => write!(f, "Multiple statements provided"),
289
290 #[cfg(feature = "blob")]
291 Error::BlobSizeError => "Blob size is insufficient".fmt(f),
292 }
293 }
294 }
295
296 impl error::Error for Error {
source(&self) -> Option<&(dyn error::Error + 'static)>297 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
298 match *self {
299 Error::SqliteFailure(ref err, _) => Some(err),
300 Error::Utf8Error(ref err) => Some(err),
301 Error::NulError(ref err) => Some(err),
302
303 Error::IntegralValueOutOfRange(..)
304 | Error::SqliteSingleThreadedMode
305 | Error::InvalidParameterName(_)
306 | Error::ExecuteReturnedResults
307 | Error::QueryReturnedNoRows
308 | Error::InvalidColumnIndex(_)
309 | Error::InvalidColumnName(_)
310 | Error::InvalidColumnType(..)
311 | Error::InvalidPath(_)
312 | Error::InvalidParameterCount(..)
313 | Error::StatementChangedRows(_)
314 | Error::InvalidQuery
315 | Error::MultipleStatement => None,
316
317 #[cfg(feature = "functions")]
318 Error::InvalidFunctionParameterType(..) => None,
319 #[cfg(feature = "vtab")]
320 Error::InvalidFilterParameterType(..) => None,
321
322 #[cfg(feature = "functions")]
323 Error::UserFunctionError(ref err) => Some(&**err),
324
325 Error::FromSqlConversionFailure(_, _, ref err)
326 | Error::ToSqlConversionFailure(ref err) => Some(&**err),
327
328 #[cfg(feature = "vtab")]
329 Error::ModuleError(_) => None,
330
331 #[cfg(feature = "functions")]
332 Error::UnwindingPanic => None,
333
334 #[cfg(feature = "functions")]
335 Error::GetAuxWrongType => None,
336
337 #[cfg(feature = "blob")]
338 Error::BlobSizeError => None,
339 }
340 }
341 }
342
343 // These are public but not re-exported by lib.rs, so only visible within crate.
344
345 #[cold]
error_from_sqlite_code(code: c_int, message: Option<String>) -> Error346 pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
347 Error::SqliteFailure(ffi::Error::new(code), message)
348 }
349
350 #[cold]
error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error351 pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
352 let message = if db.is_null() {
353 None
354 } else {
355 Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
356 };
357 error_from_sqlite_code(code, message)
358 }
359
check(code: c_int) -> Result<()>360 pub fn check(code: c_int) -> Result<()> {
361 if code != crate::ffi::SQLITE_OK {
362 Err(crate::error::error_from_sqlite_code(code, None))
363 } else {
364 Ok(())
365 }
366 }
367