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