1use crate::types::FromSqlError;
2use crate::types::Type;
3use crate::{errmsg_to_string, ffi, Result};
4use std::error;
5use std::fmt;
6use std::os::raw::c_int;
7use std::path::PathBuf;
8use std::str;
9
10#[derive(Debug)]
12#[non_exhaustive]
13pub enum Error {
14 SqliteFailure(ffi::Error, Option<String>),
16
17 SqliteSingleThreadedMode,
20
21 FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync + 'static>),
24
25 IntegralValueOutOfRange(usize, i64),
30
31 Utf8Error(str::Utf8Error),
33
34 NulError(std::ffi::NulError),
37
38 InvalidParameterName(String),
41
42 InvalidPath(PathBuf),
44
45 ExecuteReturnedResults,
48
49 QueryReturnedNoRows,
52
53 InvalidColumnIndex(usize),
56
57 InvalidColumnName(String),
60
61 InvalidColumnType(usize, String, Type),
65
66 StatementChangedRows(usize),
69
70 #[cfg(feature = "functions")]
74 #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
75 InvalidFunctionParameterType(usize, Type),
76 #[cfg(feature = "vtab")]
79 #[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
80 InvalidFilterParameterType(usize, Type),
81
82 #[cfg(feature = "functions")]
85 #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
86 UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
87
88 ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
91
92 InvalidQuery,
94
95 #[cfg(feature = "vtab")]
98 #[cfg_attr(docsrs, doc(cfg(feature = "vtab")))]
99 ModuleError(String),
100
101 UnwindingPanic,
103
104 #[cfg(feature = "functions")]
109 #[cfg_attr(docsrs, doc(cfg(feature = "functions")))]
110 GetAuxWrongType,
111
112 MultipleStatement,
114 InvalidParameterCount(usize, usize),
118
119 #[cfg(feature = "blob")]
124 #[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
125 BlobSizeError,
126 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
129 SqlInputError {
130 error: ffi::Error,
132 msg: String,
134 sql: String,
136 offset: c_int,
138 },
139 #[cfg(feature = "loadable_extension")]
141 #[cfg_attr(docsrs, doc(cfg(feature = "loadable_extension")))]
142 InitError(ffi::InitError),
143 #[cfg(feature = "modern_sqlite")] #[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
147 InvalidDatabaseIndex(usize),
148}
149
150impl PartialEq for Error {
151 fn eq(&self, other: &Self) -> bool {
152 match (self, other) {
153 (Self::SqliteFailure(e1, s1), Self::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
154 (Self::SqliteSingleThreadedMode, Self::SqliteSingleThreadedMode) => true,
155 (Self::IntegralValueOutOfRange(i1, n1), Self::IntegralValueOutOfRange(i2, n2)) => {
156 i1 == i2 && n1 == n2
157 }
158 (Self::Utf8Error(e1), Self::Utf8Error(e2)) => e1 == e2,
159 (Self::NulError(e1), Self::NulError(e2)) => e1 == e2,
160 (Self::InvalidParameterName(n1), Self::InvalidParameterName(n2)) => n1 == n2,
161 (Self::InvalidPath(p1), Self::InvalidPath(p2)) => p1 == p2,
162 (Self::ExecuteReturnedResults, Self::ExecuteReturnedResults) => true,
163 (Self::QueryReturnedNoRows, Self::QueryReturnedNoRows) => true,
164 (Self::InvalidColumnIndex(i1), Self::InvalidColumnIndex(i2)) => i1 == i2,
165 (Self::InvalidColumnName(n1), Self::InvalidColumnName(n2)) => n1 == n2,
166 (Self::InvalidColumnType(i1, n1, t1), Self::InvalidColumnType(i2, n2, t2)) => {
167 i1 == i2 && t1 == t2 && n1 == n2
168 }
169 (Self::StatementChangedRows(n1), Self::StatementChangedRows(n2)) => n1 == n2,
170 #[cfg(feature = "functions")]
171 (
172 Self::InvalidFunctionParameterType(i1, t1),
173 Self::InvalidFunctionParameterType(i2, t2),
174 ) => i1 == i2 && t1 == t2,
175 #[cfg(feature = "vtab")]
176 (
177 Self::InvalidFilterParameterType(i1, t1),
178 Self::InvalidFilterParameterType(i2, t2),
179 ) => i1 == i2 && t1 == t2,
180 (Self::InvalidQuery, Self::InvalidQuery) => true,
181 #[cfg(feature = "vtab")]
182 (Self::ModuleError(s1), Self::ModuleError(s2)) => s1 == s2,
183 (Self::UnwindingPanic, Self::UnwindingPanic) => true,
184 #[cfg(feature = "functions")]
185 (Self::GetAuxWrongType, Self::GetAuxWrongType) => true,
186 (Self::InvalidParameterCount(i1, n1), Self::InvalidParameterCount(i2, n2)) => {
187 i1 == i2 && n1 == n2
188 }
189 #[cfg(feature = "blob")]
190 (Self::BlobSizeError, Self::BlobSizeError) => true,
191 #[cfg(feature = "modern_sqlite")]
192 (
193 Self::SqlInputError {
194 error: e1,
195 msg: m1,
196 sql: s1,
197 offset: o1,
198 },
199 Self::SqlInputError {
200 error: e2,
201 msg: m2,
202 sql: s2,
203 offset: o2,
204 },
205 ) => e1 == e2 && m1 == m2 && s1 == s2 && o1 == o2,
206 #[cfg(feature = "loadable_extension")]
207 (Self::InitError(e1), Self::InitError(e2)) => e1 == e2,
208 #[cfg(feature = "modern_sqlite")]
209 (Self::InvalidDatabaseIndex(i1), Self::InvalidDatabaseIndex(i2)) => i1 == i2,
210 (..) => false,
211 }
212 }
213}
214
215impl From<str::Utf8Error> for Error {
216 #[cold]
217 fn from(err: str::Utf8Error) -> Self {
218 Self::Utf8Error(err)
219 }
220}
221
222impl From<std::ffi::NulError> for Error {
223 #[cold]
224 fn from(err: std::ffi::NulError) -> Self {
225 Self::NulError(err)
226 }
227}
228
229const UNKNOWN_COLUMN: usize = usize::MAX;
230
231impl From<FromSqlError> for Error {
234 #[cold]
235 fn from(err: FromSqlError) -> Self {
236 match err {
239 FromSqlError::OutOfRange(val) => Self::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
240 FromSqlError::InvalidBlobSize { .. } => {
241 Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
242 }
243 FromSqlError::Other(source) => {
244 Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
245 }
246 _ => Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
247 }
248 }
249}
250
251#[cfg(feature = "loadable_extension")]
252impl From<ffi::InitError> for Error {
253 #[cold]
254 fn from(err: ffi::InitError) -> Self {
255 Self::InitError(err)
256 }
257}
258
259impl fmt::Display for Error {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 match *self {
262 Self::SqliteFailure(ref err, None) => err.fmt(f),
263 Self::SqliteFailure(_, Some(ref s)) => write!(f, "{s}"),
264 Self::SqliteSingleThreadedMode => write!(
265 f,
266 "SQLite was compiled or configured for single-threaded use only"
267 ),
268 Self::FromSqlConversionFailure(i, ref t, ref err) => {
269 if i != UNKNOWN_COLUMN {
270 write!(f, "Conversion error from type {t} at index: {i}, {err}")
271 } else {
272 err.fmt(f)
273 }
274 }
275 Self::IntegralValueOutOfRange(col, val) => {
276 if col != UNKNOWN_COLUMN {
277 write!(f, "Integer {val} out of range at index {col}")
278 } else {
279 write!(f, "Integer {val} out of range")
280 }
281 }
282 Self::Utf8Error(ref err) => err.fmt(f),
283 Self::NulError(ref err) => err.fmt(f),
284 Self::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {name}"),
285 Self::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
286 Self::ExecuteReturnedResults => {
287 write!(f, "Execute returned results - did you mean to call query?")
288 }
289 Self::QueryReturnedNoRows => write!(f, "Query returned no rows"),
290 Self::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"),
291 Self::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"),
292 Self::InvalidColumnType(i, ref name, ref t) => {
293 write!(f, "Invalid column type {t} at index: {i}, name: {name}")
294 }
295 Self::InvalidParameterCount(i1, n1) => write!(
296 f,
297 "Wrong number of parameters passed to query. Got {i1}, needed {n1}"
298 ),
299 Self::StatementChangedRows(i) => write!(f, "Query changed {i} rows"),
300
301 #[cfg(feature = "functions")]
302 Self::InvalidFunctionParameterType(i, ref t) => {
303 write!(f, "Invalid function parameter type {t} at index {i}")
304 }
305 #[cfg(feature = "vtab")]
306 Self::InvalidFilterParameterType(i, ref t) => {
307 write!(f, "Invalid filter parameter type {t} at index {i}")
308 }
309 #[cfg(feature = "functions")]
310 Self::UserFunctionError(ref err) => err.fmt(f),
311 Self::ToSqlConversionFailure(ref err) => err.fmt(f),
312 Self::InvalidQuery => write!(f, "Query is not read-only"),
313 #[cfg(feature = "vtab")]
314 Self::ModuleError(ref desc) => write!(f, "{desc}"),
315 Self::UnwindingPanic => write!(f, "unwinding panic"),
316 #[cfg(feature = "functions")]
317 Self::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
318 Self::MultipleStatement => write!(f, "Multiple statements provided"),
319 #[cfg(feature = "blob")]
320 Self::BlobSizeError => "Blob size is insufficient".fmt(f),
321 #[cfg(feature = "modern_sqlite")]
322 Self::SqlInputError {
323 ref msg,
324 offset,
325 ref sql,
326 ..
327 } => write!(f, "{msg} in {sql} at offset {offset}"),
328 #[cfg(feature = "loadable_extension")]
329 Self::InitError(ref err) => err.fmt(f),
330 #[cfg(feature = "modern_sqlite")]
331 Self::InvalidDatabaseIndex(i) => write!(f, "Invalid database index: {i}"),
332 }
333 }
334}
335
336impl error::Error for Error {
337 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
338 match *self {
339 Self::SqliteFailure(ref err, _) => Some(err),
340 Self::Utf8Error(ref err) => Some(err),
341 Self::NulError(ref err) => Some(err),
342
343 Self::IntegralValueOutOfRange(..)
344 | Self::SqliteSingleThreadedMode
345 | Self::InvalidParameterName(_)
346 | Self::ExecuteReturnedResults
347 | Self::QueryReturnedNoRows
348 | Self::InvalidColumnIndex(_)
349 | Self::InvalidColumnName(_)
350 | Self::InvalidColumnType(..)
351 | Self::InvalidPath(_)
352 | Self::InvalidParameterCount(..)
353 | Self::StatementChangedRows(_)
354 | Self::InvalidQuery
355 | Self::MultipleStatement => None,
356
357 #[cfg(feature = "functions")]
358 Self::InvalidFunctionParameterType(..) => None,
359 #[cfg(feature = "vtab")]
360 Self::InvalidFilterParameterType(..) => None,
361
362 #[cfg(feature = "functions")]
363 Self::UserFunctionError(ref err) => Some(&**err),
364
365 Self::FromSqlConversionFailure(_, _, ref err)
366 | Self::ToSqlConversionFailure(ref err) => Some(&**err),
367
368 #[cfg(feature = "vtab")]
369 Self::ModuleError(_) => None,
370
371 Self::UnwindingPanic => None,
372
373 #[cfg(feature = "functions")]
374 Self::GetAuxWrongType => None,
375
376 #[cfg(feature = "blob")]
377 Self::BlobSizeError => None,
378 #[cfg(feature = "modern_sqlite")]
379 Self::SqlInputError { ref error, .. } => Some(error),
380 #[cfg(feature = "loadable_extension")]
381 Self::InitError(ref err) => Some(err),
382 #[cfg(feature = "modern_sqlite")]
383 Self::InvalidDatabaseIndex(_) => None,
384 }
385 }
386}
387
388impl Error {
389 #[inline]
391 #[must_use]
392 pub fn sqlite_error(&self) -> Option<&ffi::Error> {
393 match self {
394 Self::SqliteFailure(error, _) => Some(error),
395 _ => None,
396 }
397 }
398
399 #[inline]
402 #[must_use]
403 pub fn sqlite_error_code(&self) -> Option<ffi::ErrorCode> {
404 self.sqlite_error().map(|error| error.code)
405 }
406}
407
408#[cold]
411pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
412 Error::SqliteFailure(ffi::Error::new(code), message)
413}
414
415macro_rules! err {
416 ($code:expr $(,)?) => {
417 $crate::error::error_from_sqlite_code($code, None)
418 };
419 ($code:expr, $msg:literal $(,)?) => {
420 $crate::error::error_from_sqlite_code($code, Some(format!($msg)))
421 };
422 ($code:expr, $err:expr $(,)?) => {
423 $crate::error::error_from_sqlite_code($code, Some(format!($err)))
424 };
425 ($code:expr, $fmt:expr, $($arg:tt)*) => {
426 $crate::error::error_from_sqlite_code($code, Some(format!($fmt, $($arg)*)))
427 };
428}
429
430#[cold]
431pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
432 error_from_sqlite_code(code, error_msg(db, code))
433}
434
435unsafe fn error_msg(db: *mut ffi::sqlite3, code: c_int) -> Option<String> {
436 if db.is_null() || ffi::sqlite3_errcode(db) != code {
437 let err_str = ffi::sqlite3_errstr(code);
438 if err_str.is_null() {
439 None
440 } else {
441 Some(errmsg_to_string(err_str))
442 }
443 } else {
444 Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
445 }
446}
447
448pub unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
449 if code == ffi::SQLITE_OK {
450 Ok(())
451 } else {
452 Err(error_from_handle(db, code))
453 }
454}
455
456#[cold]
457#[cfg(not(feature = "modern_sqlite"))] pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, _sql: &str) -> Error {
459 error_from_handle(db, code)
460}
461
462#[cold]
463#[cfg(feature = "modern_sqlite")] pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error {
465 if db.is_null() {
466 error_from_sqlite_code(code, None)
467 } else {
468 let error = ffi::Error::new(code);
469 let msg = error_msg(db, code);
470 if ffi::ErrorCode::Unknown == error.code {
471 let offset = ffi::sqlite3_error_offset(db);
472 if offset >= 0 {
473 return Error::SqlInputError {
474 error,
475 msg: msg.unwrap_or("error".to_owned()),
476 sql: sql.to_owned(),
477 offset,
478 };
479 }
480 }
481 Error::SqliteFailure(error, msg)
482 }
483}
484
485pub fn check(code: c_int) -> Result<()> {
486 if code != ffi::SQLITE_OK {
487 Err(error_from_sqlite_code(code, None))
488 } else {
489 Ok(())
490 }
491}
492
493pub unsafe fn to_sqlite_error(e: &Error, err_msg: *mut *mut std::os::raw::c_char) -> c_int {
497 use crate::util::alloc;
498 match e {
499 Error::SqliteFailure(err, s) => {
500 if let Some(s) = s {
501 *err_msg = alloc(s);
502 }
503 err.extended_code
504 }
505 err => {
506 *err_msg = alloc(&err.to_string());
507 ffi::SQLITE_ERROR
508 }
509 }
510}