rusqlite/src/error.rs

350 lines
14 KiB
Rust
Raw Normal View History

use crate::types::FromSqlError;
2018-10-31 03:13:41 +08:00
use crate::types::Type;
use crate::{errmsg_to_string, ffi};
use std::error;
use std::fmt;
2018-08-11 18:48:21 +08:00
use std::os::raw::c_int;
use std::path::PathBuf;
use std::str;
2015-12-17 12:46:39 +08:00
/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
2018-12-07 02:00:55 +08:00
#[allow(clippy::enum_variant_names)]
#[non_exhaustive]
pub enum Error {
2015-12-17 12:46:39 +08:00
/// An error from an underlying SQLite call.
SqliteFailure(ffi::Error, Option<String>),
2015-12-17 12:46:39 +08:00
2018-08-17 00:29:46 +08:00
/// Error reported when attempting to open a connection when SQLite was
/// configured to allow single-threaded use only.
SqliteSingleThreadedMode,
2018-08-17 00:29:46 +08:00
/// Error when the value of a particular column is requested, but it cannot
/// be converted to the requested Rust type.
FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync + 'static>),
2015-12-17 12:46:39 +08:00
2018-08-17 00:29:46 +08:00
/// Error when SQLite gives us an integral value outside the range of the
/// requested type (e.g., trying to get the value 1000 into a `u8`).
/// The associated `usize` is the column index,
/// and the associated `i64` is the value returned by SQLite.
IntegralValueOutOfRange(usize, i64),
2015-12-17 12:46:39 +08:00
/// Error converting a string to UTF-8.
Utf8Error(str::Utf8Error),
2015-12-17 12:46:39 +08:00
2018-08-17 00:29:46 +08:00
/// Error converting a string to a C-compatible string because it contained
/// an embedded nul.
NulError(::std::ffi::NulError),
2015-12-17 12:46:39 +08:00
2018-08-17 00:29:46 +08:00
/// Error when using SQL named parameters and passing a parameter name not
/// present in the SQL.
InvalidParameterName(String),
2015-12-17 12:46:39 +08:00
/// Error converting a file path to a string.
InvalidPath(PathBuf),
2015-12-17 12:46:39 +08:00
2016-01-08 00:36:01 +08:00
/// Error returned when an `execute` call returns rows.
ExecuteReturnedResults,
2015-12-17 12:46:39 +08:00
2018-08-17 00:29:46 +08:00
/// Error when a query that was expected to return at least one row (e.g.,
/// for `query_row`) did not return any.
QueryReturnedNoRows,
2015-12-17 12:46:39 +08:00
2018-08-17 00:29:46 +08:00
/// Error when the value of a particular column is requested, but the index
/// is out of range for the statement.
InvalidColumnIndex(usize),
2015-12-17 12:46:39 +08:00
2018-08-17 00:29:46 +08:00
/// Error when the value of a named column is requested, but no column
/// matches the name for the statement.
InvalidColumnName(String),
2018-08-17 00:29:46 +08:00
/// Error when the value of a particular column is requested, but the type
/// of the result in that column cannot be converted to the requested
/// Rust type.
InvalidColumnType(usize, String, Type),
2018-08-17 00:29:46 +08:00
/// Error when a query that was expected to insert one row did not insert
/// any or insert many.
StatementChangedRows(usize),
2018-08-17 00:29:46 +08:00
/// Error returned by `functions::Context::get` when the function argument
/// cannot be converted to the requested type.
#[cfg(feature = "functions")]
InvalidFunctionParameterType(usize, Type),
2018-08-17 00:29:46 +08:00
/// Error returned by `vtab::Values::get` when the filter argument cannot
/// be converted to the requested type.
#[cfg(feature = "vtab")]
InvalidFilterParameterType(usize, Type),
2015-12-17 12:46:39 +08:00
/// An error case available for implementors of custom user functions (e.g.,
/// `create_scalar_function`).
#[cfg(feature = "functions")]
#[allow(dead_code)]
UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),
/// Error available for the implementors of the `ToSql` trait.
ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),
/// Error when the SQL is not a `SELECT`, is not read-only.
InvalidQuery,
/// An error case available for implementors of custom modules (e.g.,
/// `create_module`).
#[cfg(feature = "vtab")]
#[allow(dead_code)]
ModuleError(String),
2020-05-17 17:21:10 +08:00
/// An unwinding panic occurs in an UDF (user-defined function).
#[cfg(feature = "functions")]
UnwindingPanic,
/// An error returned when `Context::get_aux` attempts to retrieve data
/// of a different type than what had been stored using `Context::set_aux`.
#[cfg(feature = "functions")]
GetAuxWrongType,
/// Error when the SQL contains multiple statements.
MultipleStatement,
/// Error when the number of bound parameters does not match the number of
/// parameters in the query. The first `usize` is how many parameters were
/// given, the 2nd is how many were expected.
InvalidParameterCount(usize, usize),
/// Returned from various functions in the Blob IO positional API. For
/// example, [`Blob::raw_read_at_exact`](crate::blob::Blob::raw_read_at_exact)
/// will return it if the blob has insufficient data.
#[cfg(feature = "blob")]
BlobSizeError,
}
impl PartialEq for Error {
fn eq(&self, other: &Error) -> bool {
match (self, other) {
(Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
(Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
(Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
i1 == i2 && n1 == n2
}
(Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
(Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
(Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
(Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
(Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
(Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
(Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
(Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
(Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
i1 == i2 && t1 == t2 && n1 == n2
}
(Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
#[cfg(feature = "functions")]
(
Error::InvalidFunctionParameterType(i1, t1),
Error::InvalidFunctionParameterType(i2, t2),
) => i1 == i2 && t1 == t2,
#[cfg(feature = "vtab")]
(
Error::InvalidFilterParameterType(i1, t1),
Error::InvalidFilterParameterType(i2, t2),
) => i1 == i2 && t1 == t2,
(Error::InvalidQuery, Error::InvalidQuery) => true,
#[cfg(feature = "vtab")]
(Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
#[cfg(feature = "functions")]
(Error::UnwindingPanic, Error::UnwindingPanic) => true,
#[cfg(feature = "functions")]
(Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
(Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
i1 == i2 && n1 == n2
}
#[cfg(feature = "blob")]
(Error::BlobSizeError, Error::BlobSizeError) => true,
2019-11-03 18:19:07 +08:00
(..) => false,
}
}
}
impl From<str::Utf8Error> for Error {
fn from(err: str::Utf8Error) -> Error {
Error::Utf8Error(err)
}
}
impl From<::std::ffi::NulError> for Error {
fn from(err: ::std::ffi::NulError) -> Error {
Error::NulError(err)
}
}
const UNKNOWN_COLUMN: usize = std::usize::MAX;
/// The conversion isn't precise, but it's convenient to have it
/// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
impl From<FromSqlError> for Error {
fn from(err: FromSqlError) -> Error {
2019-08-10 02:03:46 +08:00
// The error type requires index and type fields, but they aren't known in this
// context.
match err {
FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
#[cfg(feature = "i128_blob")]
2019-08-10 02:06:31 +08:00
FromSqlError::InvalidI128Size(_) => {
Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
}
#[cfg(feature = "uuid")]
2019-08-10 02:06:31 +08:00
FromSqlError::InvalidUuidSize(_) => {
Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
}
FromSqlError::Other(source) => {
Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
}
_ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
}
}
}
impl fmt::Display for Error {
2018-12-08 04:57:04 +08:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2016-02-14 23:11:59 +08:00
match *self {
Error::SqliteFailure(ref err, None) => err.fmt(f),
Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
2018-08-11 18:48:21 +08:00
Error::SqliteSingleThreadedMode => write!(
f,
"SQLite was compiled or configured for single-threaded use only"
),
2019-08-10 02:03:46 +08:00
Error::FromSqlConversionFailure(i, ref t, ref err) => {
if i != UNKNOWN_COLUMN {
write!(
f,
"Conversion error from type {} at index: {}, {}",
t, i, err
)
} else {
err.fmt(f)
}
}
Error::IntegralValueOutOfRange(col, val) => {
2019-08-10 02:03:46 +08:00
if col != UNKNOWN_COLUMN {
write!(f, "Integer {} out of range at index {}", val, col)
} else {
write!(f, "Integer {} out of range", val)
}
}
2016-02-14 23:11:59 +08:00
Error::Utf8Error(ref err) => err.fmt(f),
Error::NulError(ref err) => err.fmt(f),
Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
Error::ExecuteReturnedResults => {
2016-02-03 02:12:00 +08:00
write!(f, "Execute returned results - did you mean to call query?")
}
2016-02-14 23:11:59 +08:00
Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
2019-07-11 03:10:12 +08:00
Error::InvalidColumnType(i, ref name, ref t) => write!(
f,
"Invalid column type {} at index: {}, name: {}",
t, i, name
),
Error::InvalidParameterCount(i1, n1) => write!(
f,
"Wrong number of parameters passed to query. Got {}, needed {}",
i1, n1
),
Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
#[cfg(feature = "functions")]
Error::InvalidFunctionParameterType(i, ref t) => {
write!(f, "Invalid function parameter type {} at index {}", t, i)
}
#[cfg(feature = "vtab")]
Error::InvalidFilterParameterType(i, ref t) => {
write!(f, "Invalid filter parameter type {} at index {}", t, i)
}
#[cfg(feature = "functions")]
2016-02-14 23:11:59 +08:00
Error::UserFunctionError(ref err) => err.fmt(f),
Error::ToSqlConversionFailure(ref err) => err.fmt(f),
Error::InvalidQuery => write!(f, "Query is not read-only"),
#[cfg(feature = "vtab")]
Error::ModuleError(ref desc) => write!(f, "{}", desc),
#[cfg(feature = "functions")]
Error::UnwindingPanic => write!(f, "unwinding panic"),
#[cfg(feature = "functions")]
Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
Error::MultipleStatement => write!(f, "Multiple statements provided"),
#[cfg(feature = "blob")]
Error::BlobSizeError => "Blob size is insufficient".fmt(f),
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2016-02-14 23:11:59 +08:00
match *self {
Error::SqliteFailure(ref err, _) => Some(err),
Error::Utf8Error(ref err) => Some(err),
Error::NulError(ref err) => Some(err),
2019-11-03 18:19:07 +08:00
Error::IntegralValueOutOfRange(..)
2018-08-11 18:48:21 +08:00
| Error::SqliteSingleThreadedMode
| Error::InvalidParameterName(_)
| Error::ExecuteReturnedResults
| Error::QueryReturnedNoRows
| Error::InvalidColumnIndex(_)
| Error::InvalidColumnName(_)
2019-11-03 18:19:07 +08:00
| Error::InvalidColumnType(..)
2018-08-11 18:48:21 +08:00
| Error::InvalidPath(_)
| Error::InvalidParameterCount(..)
2018-08-11 18:48:21 +08:00
| Error::StatementChangedRows(_)
| Error::InvalidQuery
| Error::MultipleStatement => None,
#[cfg(feature = "functions")]
2019-11-03 18:19:07 +08:00
Error::InvalidFunctionParameterType(..) => None,
#[cfg(feature = "vtab")]
2019-11-03 18:19:07 +08:00
Error::InvalidFilterParameterType(..) => None,
2016-03-30 02:18:56 +08:00
#[cfg(feature = "functions")]
2016-02-14 23:11:59 +08:00
Error::UserFunctionError(ref err) => Some(&**err),
2017-11-18 02:37:23 +08:00
2018-08-11 18:48:21 +08:00
Error::FromSqlConversionFailure(_, _, ref err)
| Error::ToSqlConversionFailure(ref err) => Some(&**err),
#[cfg(feature = "vtab")]
Error::ModuleError(_) => None,
#[cfg(feature = "functions")]
Error::UnwindingPanic => None,
#[cfg(feature = "functions")]
Error::GetAuxWrongType => None,
#[cfg(feature = "blob")]
Error::BlobSizeError => None,
}
}
}
2018-07-15 00:47:52 +08:00
// These are public but not re-exported by lib.rs, so only visible within crate.
pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
Error::SqliteFailure(ffi::Error::new(code), message)
}
pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
let message = if db.is_null() {
None
} else {
Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
};
error_from_sqlite_code(code, message)
}
macro_rules! check {
($funcall:expr) => {{
let rc = $funcall;
if rc != crate::ffi::SQLITE_OK {
2019-07-11 03:10:12 +08:00
return Err(crate::error::error_from_sqlite_code(rc, None).into());
}
}};
}