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