1use crate::types::FromSqlError;
2use crate::types::Type;
3use crate::{errmsg_to_string, ffi, Result};
4use std::error;
5use std::ffi::{c_char, c_int, NulError};
6use std::fmt;
7use std::path::PathBuf;
8use std::str;
9
10macro_rules! cfg_select {
12 ({ $($tt:tt)* }) => {{
13 $crate::cfg_select! { $($tt)* }
14 }};
15 (_ => { $($output:tt)* }) => {
16 $($output)*
17 };
18 (
19 $cfg:meta => $output:tt
20 $($( $rest:tt )+)?
21 ) => {{
22 #[cfg($cfg)]
23 cfg_select! { _ => $output }
24 $(
25 #[cfg(not($cfg))]
26 cfg_select! { $($rest)+ }
27 )?
28 }}
29}
30
31#[derive(Debug)]
33#[non_exhaustive]
34pub enum Error {
35 SqliteFailure(ffi::Error, Option<String>),
37
38 SqliteSingleThreadedMode,
41
42 FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync + 'static>),
45
46 IntegralValueOutOfRange(usize, i64),
51
52 Utf8Error(usize, str::Utf8Error),
54
55 NulError(NulError),
58
59 InvalidParameterName(String),
62
63 InvalidPath(PathBuf),
65
66 ExecuteReturnedResults,
69
70 QueryReturnedNoRows,
73
74 QueryReturnedMoreThanOneRow,
77
78 InvalidColumnIndex(usize),
81
82 InvalidColumnName(String),
85
86 InvalidColumnType(usize, String, Type),
90
91 StatementChangedRows(usize),
94
95 #[cfg(feature = "functions")]
99 InvalidFunctionParameterType(usize, Type),
100 #[cfg(feature = "vtab")]
103 InvalidFilterParameterType(usize, Type),
104
105 #[cfg(feature = "functions")]
108 UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
109
110 ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
113
114 InvalidQuery,
116
117 #[cfg(feature = "vtab")]
120 ModuleError(String),
121
122 UnwindingPanic,
124
125 #[cfg(feature = "functions")]
130 GetAuxWrongType,
131
132 MultipleStatement,
134 InvalidParameterCount(usize, usize),
138
139 #[cfg(feature = "blob")]
144 BlobSizeError,
145 #[cfg(feature = "modern_sqlite")] SqlInputError {
148 error: ffi::Error,
150 msg: String,
152 sql: String,
154 offset: c_int,
156 },
157 #[cfg(feature = "loadable_extension")]
159 InitError(ffi::InitError),
160 #[cfg(feature = "modern_sqlite")] InvalidDatabaseIndex(usize),
164}
165
166impl PartialEq for Error {
167 fn eq(&self, other: &Self) -> bool {
168 match (self, other) {
169 (Self::SqliteFailure(e1, s1), Self::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
170 (Self::SqliteSingleThreadedMode, Self::SqliteSingleThreadedMode) => true,
171 (Self::IntegralValueOutOfRange(i1, n1), Self::IntegralValueOutOfRange(i2, n2)) => {
172 i1 == i2 && n1 == n2
173 }
174 (Self::Utf8Error(i1, e1), Self::Utf8Error(i2, e2)) => i1 == i2 && e1 == e2,
175 (Self::NulError(e1), Self::NulError(e2)) => e1 == e2,
176 (Self::InvalidParameterName(n1), Self::InvalidParameterName(n2)) => n1 == n2,
177 (Self::InvalidPath(p1), Self::InvalidPath(p2)) => p1 == p2,
178 (Self::ExecuteReturnedResults, Self::ExecuteReturnedResults) => true,
179 (Self::QueryReturnedNoRows, Self::QueryReturnedNoRows) => true,
180 (Self::QueryReturnedMoreThanOneRow, Self::QueryReturnedMoreThanOneRow) => true,
181 (Self::InvalidColumnIndex(i1), Self::InvalidColumnIndex(i2)) => i1 == i2,
182 (Self::InvalidColumnName(n1), Self::InvalidColumnName(n2)) => n1 == n2,
183 (Self::InvalidColumnType(i1, n1, t1), Self::InvalidColumnType(i2, n2, t2)) => {
184 i1 == i2 && t1 == t2 && n1 == n2
185 }
186 (Self::StatementChangedRows(n1), Self::StatementChangedRows(n2)) => n1 == n2,
187 #[cfg(feature = "functions")]
188 (
189 Self::InvalidFunctionParameterType(i1, t1),
190 Self::InvalidFunctionParameterType(i2, t2),
191 ) => i1 == i2 && t1 == t2,
192 #[cfg(feature = "vtab")]
193 (
194 Self::InvalidFilterParameterType(i1, t1),
195 Self::InvalidFilterParameterType(i2, t2),
196 ) => i1 == i2 && t1 == t2,
197 (Self::InvalidQuery, Self::InvalidQuery) => true,
198 #[cfg(feature = "vtab")]
199 (Self::ModuleError(s1), Self::ModuleError(s2)) => s1 == s2,
200 (Self::UnwindingPanic, Self::UnwindingPanic) => true,
201 #[cfg(feature = "functions")]
202 (Self::GetAuxWrongType, Self::GetAuxWrongType) => true,
203 (Self::InvalidParameterCount(i1, n1), Self::InvalidParameterCount(i2, n2)) => {
204 i1 == i2 && n1 == n2
205 }
206 #[cfg(feature = "blob")]
207 (Self::BlobSizeError, Self::BlobSizeError) => true,
208 #[cfg(feature = "modern_sqlite")]
209 (
210 Self::SqlInputError {
211 error: e1,
212 msg: m1,
213 sql: s1,
214 offset: o1,
215 },
216 Self::SqlInputError {
217 error: e2,
218 msg: m2,
219 sql: s2,
220 offset: o2,
221 },
222 ) => e1 == e2 && m1 == m2 && s1 == s2 && o1 == o2,
223 #[cfg(feature = "loadable_extension")]
224 (Self::InitError(e1), Self::InitError(e2)) => e1 == e2,
225 #[cfg(feature = "modern_sqlite")]
226 (Self::InvalidDatabaseIndex(i1), Self::InvalidDatabaseIndex(i2)) => i1 == i2,
227 (..) => false,
228 }
229 }
230}
231
232impl From<str::Utf8Error> for Error {
233 #[cold]
234 fn from(err: str::Utf8Error) -> Self {
235 Self::Utf8Error(UNKNOWN_COLUMN, err)
236 }
237}
238
239impl From<NulError> for Error {
240 #[cold]
241 fn from(err: NulError) -> Self {
242 Self::NulError(err)
243 }
244}
245
246const UNKNOWN_COLUMN: usize = usize::MAX;
247
248impl From<FromSqlError> for Error {
251 #[cold]
252 fn from(err: FromSqlError) -> Self {
253 match err {
256 FromSqlError::OutOfRange(val) => Self::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
257 FromSqlError::InvalidBlobSize { .. } => {
258 Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
259 }
260 FromSqlError::Other(source) => {
261 Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
262 }
263 _ => Self::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
264 }
265 }
266}
267
268#[cfg(feature = "loadable_extension")]
269impl From<ffi::InitError> for Error {
270 #[cold]
271 fn from(err: ffi::InitError) -> Self {
272 Self::InitError(err)
273 }
274}
275
276impl fmt::Display for Error {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 match *self {
279 Self::SqliteFailure(ref err, None) => err.fmt(f),
280 Self::SqliteFailure(_, Some(ref s)) => write!(f, "{s}"),
281 Self::SqliteSingleThreadedMode => write!(
282 f,
283 "SQLite was compiled or configured for single-threaded use only"
284 ),
285 Self::FromSqlConversionFailure(i, ref t, ref err) => {
286 if i != UNKNOWN_COLUMN {
287 write!(f, "Conversion error from type {t} at index: {i}, {err}")
288 } else {
289 err.fmt(f)
290 }
291 }
292 Self::IntegralValueOutOfRange(col, val) => {
293 if col != UNKNOWN_COLUMN {
294 write!(f, "Integer {val} out of range at index {col}")
295 } else {
296 write!(f, "Integer {val} out of range")
297 }
298 }
299 Self::Utf8Error(col, ref err) => {
300 if col != UNKNOWN_COLUMN {
301 write!(f, "{err} at index {col}")
302 } else {
303 err.fmt(f)
304 }
305 }
306 Self::NulError(ref err) => err.fmt(f),
307 Self::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {name}"),
308 Self::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
309 Self::ExecuteReturnedResults => {
310 write!(f, "Execute returned results - did you mean to call query?")
311 }
312 Self::QueryReturnedNoRows => write!(f, "Query returned no rows"),
313 Self::QueryReturnedMoreThanOneRow => write!(f, "Query returned more than one row"),
314 Self::InvalidColumnIndex(i) => write!(f, "Invalid column index: {i}"),
315 Self::InvalidColumnName(ref name) => write!(f, "Invalid column name: {name}"),
316 Self::InvalidColumnType(i, ref name, ref t) => {
317 write!(f, "Invalid column type {t} at index: {i}, name: {name}")
318 }
319 Self::InvalidParameterCount(i1, n1) => write!(
320 f,
321 "Wrong number of parameters passed to query. Got {i1}, needed {n1}"
322 ),
323 Self::StatementChangedRows(i) => write!(f, "Query changed {i} rows"),
324
325 #[cfg(feature = "functions")]
326 Self::InvalidFunctionParameterType(i, ref t) => {
327 write!(f, "Invalid function parameter type {t} at index {i}")
328 }
329 #[cfg(feature = "vtab")]
330 Self::InvalidFilterParameterType(i, ref t) => {
331 write!(f, "Invalid filter parameter type {t} at index {i}")
332 }
333 #[cfg(feature = "functions")]
334 Self::UserFunctionError(ref err) => err.fmt(f),
335 Self::ToSqlConversionFailure(ref err) => err.fmt(f),
336 Self::InvalidQuery => write!(f, "Query is not read-only"),
337 #[cfg(feature = "vtab")]
338 Self::ModuleError(ref desc) => write!(f, "{desc}"),
339 Self::UnwindingPanic => write!(f, "unwinding panic"),
340 #[cfg(feature = "functions")]
341 Self::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
342 Self::MultipleStatement => write!(f, "Multiple statements provided"),
343 #[cfg(feature = "blob")]
344 Self::BlobSizeError => "Blob size is insufficient".fmt(f),
345 #[cfg(feature = "modern_sqlite")]
346 Self::SqlInputError {
347 ref msg,
348 offset,
349 ref sql,
350 ..
351 } => write!(f, "{msg} in {sql} at offset {offset}"),
352 #[cfg(feature = "loadable_extension")]
353 Self::InitError(ref err) => err.fmt(f),
354 #[cfg(feature = "modern_sqlite")]
355 Self::InvalidDatabaseIndex(i) => write!(f, "Invalid database index: {i}"),
356 }
357 }
358}
359
360impl error::Error for Error {
361 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
362 match *self {
363 Self::SqliteFailure(ref err, _) => Some(err),
364 Self::Utf8Error(_, ref err) => Some(err),
365 Self::NulError(ref err) => Some(err),
366
367 Self::IntegralValueOutOfRange(..)
368 | Self::SqliteSingleThreadedMode
369 | Self::InvalidParameterName(_)
370 | Self::ExecuteReturnedResults
371 | Self::QueryReturnedNoRows
372 | Self::QueryReturnedMoreThanOneRow
373 | Self::InvalidColumnIndex(_)
374 | Self::InvalidColumnName(_)
375 | Self::InvalidColumnType(..)
376 | Self::InvalidPath(_)
377 | Self::InvalidParameterCount(..)
378 | Self::StatementChangedRows(_)
379 | Self::InvalidQuery
380 | Self::MultipleStatement => None,
381
382 #[cfg(feature = "functions")]
383 Self::InvalidFunctionParameterType(..) => None,
384 #[cfg(feature = "vtab")]
385 Self::InvalidFilterParameterType(..) => None,
386
387 #[cfg(feature = "functions")]
388 Self::UserFunctionError(ref err) => Some(&**err),
389
390 Self::FromSqlConversionFailure(_, _, ref err)
391 | Self::ToSqlConversionFailure(ref err) => Some(&**err),
392
393 #[cfg(feature = "vtab")]
394 Self::ModuleError(_) => None,
395
396 Self::UnwindingPanic => None,
397
398 #[cfg(feature = "functions")]
399 Self::GetAuxWrongType => None,
400
401 #[cfg(feature = "blob")]
402 Self::BlobSizeError => None,
403 #[cfg(feature = "modern_sqlite")]
404 Self::SqlInputError { ref error, .. } => Some(error),
405 #[cfg(feature = "loadable_extension")]
406 Self::InitError(ref err) => Some(err),
407 #[cfg(feature = "modern_sqlite")]
408 Self::InvalidDatabaseIndex(_) => None,
409 }
410 }
411}
412
413impl Error {
414 #[inline]
416 #[must_use]
417 pub fn sqlite_error(&self) -> Option<&ffi::Error> {
418 match self {
419 Self::SqliteFailure(error, _) => Some(error),
420 _ => None,
421 }
422 }
423
424 #[inline]
427 #[must_use]
428 pub fn sqlite_error_code(&self) -> Option<ffi::ErrorCode> {
429 self.sqlite_error().map(|error| error.code)
430 }
431
432 #[inline]
435 #[must_use]
436 pub fn sqlite_extended_error_code(&self) -> Option<c_int> {
437 self.sqlite_error().map(|error| error.extended_code)
438 }
439}
440
441#[cold]
444pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
445 Error::SqliteFailure(ffi::Error::new(code), message)
446}
447
448macro_rules! err {
449 ($code:expr $(,)?) => {
450 $crate::error::error_from_sqlite_code($code, None)
451 };
452 ($code:expr, $msg:literal $(,)?) => {
453 $crate::error::error_from_sqlite_code($code, Some(format!($msg)))
454 };
455 ($code:expr, $err:expr $(,)?) => {
456 $crate::error::error_from_sqlite_code($code, Some(format!($err)))
457 };
458 ($code:expr, $fmt:expr, $($arg:tt)*) => {
459 $crate::error::error_from_sqlite_code($code, Some(format!($fmt, $($arg)*)))
460 };
461}
462
463#[cold]
464pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
465 error_from_sqlite_code(code, error_msg(db, code))
466}
467
468unsafe fn error_msg(db: *mut ffi::sqlite3, code: c_int) -> Option<String> {
469 if db.is_null() || ffi::sqlite3_errcode(db) != code {
470 let err_str = ffi::sqlite3_errstr(code);
471 if err_str.is_null() {
472 None
473 } else {
474 Some(errmsg_to_string(err_str))
475 }
476 } else {
477 Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
478 }
479}
480
481pub unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
482 if code == ffi::SQLITE_OK {
483 Ok(())
484 } else {
485 Err(error_from_handle(db, code))
486 }
487}
488
489#[cold]
490#[allow(unused_variables)]
491pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error {
492 cfg_select! {
493 feature = "modern_sqlite" => { if db.is_null() {
495 error_from_sqlite_code(code, None)
496 } else {
497 let error = ffi::Error::new(code);
498 let msg = error_msg(db, code);
499 if ffi::ErrorCode::Unknown == error.code {
500 let offset = ffi::sqlite3_error_offset(db);
501 if offset >= 0 {
502 return Error::SqlInputError {
503 error,
504 msg: msg.unwrap_or("error".to_owned()),
505 sql: sql.to_owned(),
506 offset,
507 };
508 }
509 }
510 Error::SqliteFailure(error, msg)
511 }
512 }
513 _ => {
514 error_from_handle(db, code)
515 }
516 }
517}
518
519pub fn check(code: c_int) -> Result<()> {
520 if code != ffi::SQLITE_OK {
521 Err(error_from_sqlite_code(code, None))
522 } else {
523 Ok(())
524 }
525}
526
527pub unsafe fn to_sqlite_error(e: &Error, err_msg: *mut *mut c_char) -> c_int {
531 use crate::util::alloc;
532 match e {
533 Error::SqliteFailure(err, s) => {
534 if let Some(s) = s {
535 *err_msg = alloc(s);
536 }
537 err.extended_code
538 }
539 err => {
540 *err_msg = alloc(&err.to_string());
541 ffi::SQLITE_ERROR
542 }
543 }
544}
545
546#[cfg(feature = "modern_sqlite")] pub unsafe fn set_errmsg(
551 db: *mut ffi::sqlite3,
552 code: c_int,
553 msg: Option<&std::ffi::CStr>,
554) -> Result<()> {
555 unsafe {
556 decode_result_raw(
557 db,
558 ffi::sqlite3_set_errmsg(
559 db,
560 code,
561 msg.map_or(std::ptr::null(), std::ffi::CStr::as_ptr),
562 ),
563 )
564 }
565}