mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Merge remote-tracking branch 'upstream/master' into progress_handler
This commit is contained in:
commit
b448d95510
@ -111,8 +111,9 @@ pub enum Error {
|
|||||||
InvalidParameterCount(usize, usize),
|
InvalidParameterCount(usize, usize),
|
||||||
|
|
||||||
/// Returned from various functions in the Blob IO positional API. For
|
/// Returned from various functions in the Blob IO positional API. For
|
||||||
/// example, [`Blob::raw_read_at_exact`](crate::blob::Blob::
|
/// example,
|
||||||
/// raw_read_at_exact) will return it if the blob has insufficient data.
|
/// [`Blob::raw_read_at_exact`](crate::blob::Blob::raw_read_at_exact) will
|
||||||
|
/// return it if the blob has insufficient data.
|
||||||
#[cfg(feature = "blob")]
|
#[cfg(feature = "blob")]
|
||||||
BlobSizeError,
|
BlobSizeError,
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,22 @@
|
|||||||
//! The number situation is a little complicated due to the fact that all
|
//! The number situation is a little complicated due to the fact that all
|
||||||
//! numbers in SQLite are stored as `INTEGER` (`i64`) or `REAL` (`f64`).
|
//! numbers in SQLite are stored as `INTEGER` (`i64`) or `REAL` (`f64`).
|
||||||
//!
|
//!
|
||||||
//! `ToSql` cannot fail and is therefore implemented for all number types that
|
//! `ToSql` and `FromSql` are implemented for all primitive number types.
|
||||||
//! can be losslessly converted to one of these types, i.e. `u8`, `u16`, `u32`,
|
//! `FromSql` has different behaviour depending on the SQL and Rust types, and
|
||||||
//! `i8`, `i16`, `i32`, `i64`, `isize`, `f32` and `f64`. It is *not* implemented
|
//! the value.
|
||||||
//! for `u64` or `usize`.
|
|
||||||
//!
|
|
||||||
//! `FromSql` can fail, and is implemented for all primitive number types,
|
|
||||||
//! however you may get a runtime error or rounding depending on the types
|
|
||||||
//! and values.
|
|
||||||
//!
|
//!
|
||||||
//! * `INTEGER` to integer: returns an `Error::IntegralValueOutOfRange` error if
|
//! * `INTEGER` to integer: returns an `Error::IntegralValueOutOfRange` error if
|
||||||
//! the value does not fit.
|
//! the value does not fit in the Rust type.
|
||||||
//! * `REAL` to integer: always returns an `Error::InvalidColumnType` error.
|
//! * `REAL` to integer: always returns an `Error::InvalidColumnType` error.
|
||||||
//! * `INTEGER` to float: casts using `as` operator. Never fails.
|
//! * `INTEGER` to float: casts using `as` operator. Never fails.
|
||||||
//! * `REAL` to float: casts using `as` operator. Never fails.
|
//! * `REAL` to float: casts using `as` operator. Never fails.
|
||||||
//!
|
//!
|
||||||
//! Additionally, if the `time` feature is enabled, implementations are
|
//! `ToSql` always succeeds except when storing a `u64` or `usize` value that
|
||||||
|
//! cannot fit in an `INTEGER` (`i64`). Also note that SQLite ignores column
|
||||||
|
//! types, so if you store an `i64` in a column with type `REAL` it will be
|
||||||
|
//! stored as an `INTEGER`, not a `REAL`.
|
||||||
|
//!
|
||||||
|
//! If the `time` feature is enabled, implementations are
|
||||||
//! provided for `time::OffsetDateTime` that use the RFC 3339 date/time format,
|
//! provided for `time::OffsetDateTime` that use the RFC 3339 date/time format,
|
||||||
//! `"%Y-%m-%dT%H:%M:%S.%fZ"`, to store time values as strings. These values
|
//! `"%Y-%m-%dT%H:%M:%S.%fZ"`, to store time values as strings. These values
|
||||||
//! can be parsed by SQLite's builtin
|
//! can be parsed by SQLite's builtin
|
||||||
@ -397,7 +397,7 @@ mod test {
|
|||||||
assert_eq!(res.unwrap(), $expected_value);
|
assert_eq!(res.unwrap(), $expected_value);
|
||||||
$db_etc.delete_statement.execute(NO_PARAMS).unwrap();
|
$db_etc.delete_statement.execute(NO_PARAMS).unwrap();
|
||||||
};
|
};
|
||||||
($db_etc:ident, $insert_value:expr, $get_type:ty,expect_error) => {
|
($db_etc:ident, $insert_value:expr, $get_type:ty,expect_from_sql_error) => {
|
||||||
$db_etc
|
$db_etc
|
||||||
.insert_statement
|
.insert_statement
|
||||||
.execute(params![$insert_value])
|
.execute(params![$insert_value])
|
||||||
@ -408,6 +408,12 @@ mod test {
|
|||||||
res.unwrap_err();
|
res.unwrap_err();
|
||||||
$db_etc.delete_statement.execute(NO_PARAMS).unwrap();
|
$db_etc.delete_statement.execute(NO_PARAMS).unwrap();
|
||||||
};
|
};
|
||||||
|
($db_etc:ident, $insert_value:expr, $get_type:ty,expect_to_sql_error) => {
|
||||||
|
$db_etc
|
||||||
|
.insert_statement
|
||||||
|
.execute(params![$insert_value])
|
||||||
|
.unwrap_err();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -445,22 +451,28 @@ mod test {
|
|||||||
test_conversion!(db_etc, i64::MIN, i64, expect i64::MIN);
|
test_conversion!(db_etc, i64::MIN, i64, expect i64::MIN);
|
||||||
test_conversion!(db_etc, i64::MAX, i64, expect i64::MAX);
|
test_conversion!(db_etc, i64::MAX, i64, expect i64::MAX);
|
||||||
test_conversion!(db_etc, i64::MAX, u64, expect i64::MAX as u64);
|
test_conversion!(db_etc, i64::MAX, u64, expect i64::MAX as u64);
|
||||||
|
test_conversion!(db_etc, 100usize, usize, expect 100usize);
|
||||||
|
test_conversion!(db_etc, 100u64, u64, expect 100u64);
|
||||||
|
test_conversion!(db_etc, i64::MAX as u64, u64, expect i64::MAX as u64);
|
||||||
|
|
||||||
// Out-of-range integral conversions.
|
// Out-of-range integral conversions.
|
||||||
test_conversion!(db_etc, 200u8, i8, expect_error);
|
test_conversion!(db_etc, 200u8, i8, expect_from_sql_error);
|
||||||
test_conversion!(db_etc, 400u16, i8, expect_error);
|
test_conversion!(db_etc, 400u16, i8, expect_from_sql_error);
|
||||||
test_conversion!(db_etc, 400u16, u8, expect_error);
|
test_conversion!(db_etc, 400u16, u8, expect_from_sql_error);
|
||||||
test_conversion!(db_etc, -1i8, u8, expect_error);
|
test_conversion!(db_etc, -1i8, u8, expect_from_sql_error);
|
||||||
test_conversion!(db_etc, i64::MIN, u64, expect_error);
|
test_conversion!(db_etc, i64::MIN, u64, expect_from_sql_error);
|
||||||
|
test_conversion!(db_etc, u64::MAX, i64, expect_to_sql_error);
|
||||||
|
test_conversion!(db_etc, u64::MAX, u64, expect_to_sql_error);
|
||||||
|
test_conversion!(db_etc, i64::MAX as u64 + 1, u64, expect_to_sql_error);
|
||||||
|
|
||||||
// Integer to float, always works.
|
// FromSql integer to float, always works.
|
||||||
test_conversion!(db_etc, i64::MIN, f32, expect i64::MIN as f32);
|
test_conversion!(db_etc, i64::MIN, f32, expect i64::MIN as f32);
|
||||||
test_conversion!(db_etc, i64::MAX, f32, expect i64::MAX as f32);
|
test_conversion!(db_etc, i64::MAX, f32, expect i64::MAX as f32);
|
||||||
test_conversion!(db_etc, i64::MIN, f64, expect i64::MIN as f64);
|
test_conversion!(db_etc, i64::MIN, f64, expect i64::MIN as f64);
|
||||||
test_conversion!(db_etc, i64::MAX, f64, expect i64::MAX as f64);
|
test_conversion!(db_etc, i64::MAX, f64, expect i64::MAX as f64);
|
||||||
|
|
||||||
// Float to int conversion, never works even if the actual value is an
|
// FromSql float to int conversion, never works even if the actual value
|
||||||
// integer.
|
// is an integer.
|
||||||
test_conversion!(db_etc, 0f64, i64, expect_error);
|
test_conversion!(db_etc, 0f64, i64, expect_from_sql_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use super::{Null, Value, ValueRef};
|
use super::{Null, Value, ValueRef};
|
||||||
#[cfg(feature = "array")]
|
#[cfg(feature = "array")]
|
||||||
use crate::vtab::array::Array;
|
use crate::vtab::array::Array;
|
||||||
use crate::Result;
|
use crate::{Error, Result};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
/// `ToSqlOutput` represents the possible output types for implementors of the
|
/// `ToSqlOutput` represents the possible output types for implementers of the
|
||||||
/// `ToSql` trait.
|
/// `ToSql` trait.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
@ -86,7 +87,8 @@ impl ToSql for ToSqlOutput<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for types that can be converted into SQLite values.
|
/// A trait for types that can be converted into SQLite values. Returns
|
||||||
|
/// `Error::ToSqlConversionFailure` if the conversion fails.
|
||||||
pub trait ToSql {
|
pub trait ToSql {
|
||||||
/// Converts Rust value to SQLite value
|
/// Converts Rust value to SQLite value
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>>;
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>>;
|
||||||
@ -157,6 +159,25 @@ to_sql_self!(i128);
|
|||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
to_sql_self!(uuid::Uuid);
|
to_sql_self!(uuid::Uuid);
|
||||||
|
|
||||||
|
macro_rules! to_sql_self_fallible(
|
||||||
|
($t:ty) => (
|
||||||
|
impl ToSql for $t {
|
||||||
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||||
|
Ok(ToSqlOutput::Owned(Value::Integer(
|
||||||
|
i64::try_from(*self).map_err(
|
||||||
|
// TODO: Include the values in the error message.
|
||||||
|
|err| Error::ToSqlConversionFailure(err.into())
|
||||||
|
)?
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Special implementations for usize and u64 because these conversions can fail.
|
||||||
|
to_sql_self_fallible!(u64);
|
||||||
|
to_sql_self_fallible!(usize);
|
||||||
|
|
||||||
impl<T: ?Sized> ToSql for &'_ T
|
impl<T: ?Sized> ToSql for &'_ T
|
||||||
where
|
where
|
||||||
T: ToSql,
|
T: ToSql,
|
||||||
|
Loading…
Reference in New Issue
Block a user