mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 09:09:19 +08:00
commit
85454c04ec
@ -40,6 +40,7 @@ script:
|
|||||||
- cargo test --features bundled
|
- cargo test --features bundled
|
||||||
- cargo test --features sqlcipher
|
- cargo test --features sqlcipher
|
||||||
- cargo test --features i128_blob
|
- cargo test --features i128_blob
|
||||||
|
- cargo test --features uuid
|
||||||
- cargo test --features "unlock_notify bundled"
|
- cargo test --features "unlock_notify bundled"
|
||||||
- cargo test --features "array bundled csvtab vtab"
|
- cargo test --features "array bundled csvtab vtab"
|
||||||
- cargo test --features "backup blob chrono csvtab functions hooks limits load_extension serde_json trace url vtab"
|
- cargo test --features "backup blob chrono csvtab functions hooks limits load_extension serde_json trace url vtab"
|
||||||
|
@ -62,11 +62,13 @@ byteorder = { version = "1.2", features = ["i128"], optional = true }
|
|||||||
fallible-iterator = "0.2"
|
fallible-iterator = "0.2"
|
||||||
fallible-streaming-iterator = "0.1"
|
fallible-streaming-iterator = "0.1"
|
||||||
memchr = "2.2.0"
|
memchr = "2.2.0"
|
||||||
|
uuid = { version = "0.7", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
regex = "1.0"
|
regex = "1.0"
|
||||||
|
uuid = { version = "0.7", features = ["v4"] }
|
||||||
|
|
||||||
[dependencies.libsqlite3-sys]
|
[dependencies.libsqlite3-sys]
|
||||||
path = "libsqlite3-sys"
|
path = "libsqlite3-sys"
|
||||||
|
@ -106,6 +106,7 @@ features](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-s
|
|||||||
* [`csvtab`](https://sqlite.org/csv.html), CSV virtual table written in Rust.
|
* [`csvtab`](https://sqlite.org/csv.html), CSV virtual table written in Rust.
|
||||||
* [`array`](https://sqlite.org/carray.html), The `rarray()` Table-Valued Function.
|
* [`array`](https://sqlite.org/carray.html), The `rarray()` Table-Valued Function.
|
||||||
* `i128_blob` allows storing values of type `i128` type in SQLite databases. Internally, the data is stored as a 16 byte big-endian blob, with the most significant bit flipped, which allows ordering and comparison between different blobs storing i128s to work as expected.
|
* `i128_blob` allows storing values of type `i128` type in SQLite databases. Internally, the data is stored as a 16 byte big-endian blob, with the most significant bit flipped, which allows ordering and comparison between different blobs storing i128s to work as expected.
|
||||||
|
* `uuid` allows storing and retrieving `Uuid` values from the [`uuid`](https://docs.rs/uuid/) using blobs.
|
||||||
* [`session`](https://sqlite.org/sessionintro.html), Session module extension.
|
* [`session`](https://sqlite.org/sessionintro.html), Session module extension.
|
||||||
|
|
||||||
## Notes on building rusqlite and libsqlite3-sys
|
## Notes on building rusqlite and libsqlite3-sys
|
||||||
|
@ -230,6 +230,8 @@ impl<'stmt> Row<'stmt> {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "i128_blob")]
|
#[cfg(feature = "i128_blob")]
|
||||||
FromSqlError::InvalidI128Size(_) => Error::InvalidColumnType(idx, value.data_type()),
|
FromSqlError::InvalidI128Size(_) => Error::InvalidColumnType(idx, value.data_type()),
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
FromSqlError::InvalidUuidSize(_) => Error::InvalidColumnType(idx, value.data_type()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ pub enum FromSqlError {
|
|||||||
#[cfg(feature = "i128_blob")]
|
#[cfg(feature = "i128_blob")]
|
||||||
InvalidI128Size(usize),
|
InvalidI128Size(usize),
|
||||||
|
|
||||||
|
/// Error returned when reading a `uuid` from a blob with a size
|
||||||
|
/// other than 16. Only available when the `uuid` feature is enabled.
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
InvalidUuidSize(usize),
|
||||||
|
|
||||||
/// An error case available for implementors of the `FromSql` trait.
|
/// An error case available for implementors of the `FromSql` trait.
|
||||||
Other(Box<dyn Error + Send + Sync>),
|
Other(Box<dyn Error + Send + Sync>),
|
||||||
}
|
}
|
||||||
@ -29,6 +34,8 @@ impl PartialEq for FromSqlError {
|
|||||||
(FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
|
(FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
|
||||||
#[cfg(feature = "i128_blob")]
|
#[cfg(feature = "i128_blob")]
|
||||||
(FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
|
(FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
(FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2,
|
||||||
(_, _) => false,
|
(_, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,6 +50,10 @@ impl fmt::Display for FromSqlError {
|
|||||||
FromSqlError::InvalidI128Size(s) => {
|
FromSqlError::InvalidI128Size(s) => {
|
||||||
write!(f, "Cannot read 128bit value out of {} byte blob", s)
|
write!(f, "Cannot read 128bit value out of {} byte blob", s)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
FromSqlError::InvalidUuidSize(s) => {
|
||||||
|
write!(f, "Cannot read UUID value out of {} byte blob", s)
|
||||||
|
}
|
||||||
FromSqlError::Other(ref err) => err.fmt(f),
|
FromSqlError::Other(ref err) => err.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,6 +66,8 @@ impl Error for FromSqlError {
|
|||||||
FromSqlError::OutOfRange(_) => "value out of range",
|
FromSqlError::OutOfRange(_) => "value out of range",
|
||||||
#[cfg(feature = "i128_blob")]
|
#[cfg(feature = "i128_blob")]
|
||||||
FromSqlError::InvalidI128Size(_) => "unexpected blob size for 128bit value",
|
FromSqlError::InvalidI128Size(_) => "unexpected blob size for 128bit value",
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
FromSqlError::InvalidUuidSize(_) => "unexpected blob size for UUID value",
|
||||||
FromSqlError::Other(ref err) => err.description(),
|
FromSqlError::Other(ref err) => err.description(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,9 +77,7 @@ impl Error for FromSqlError {
|
|||||||
fn cause(&self) -> Option<&dyn Error> {
|
fn cause(&self) -> Option<&dyn Error> {
|
||||||
match *self {
|
match *self {
|
||||||
FromSqlError::Other(ref err) => err.cause(),
|
FromSqlError::Other(ref err) => err.cause(),
|
||||||
FromSqlError::InvalidType | FromSqlError::OutOfRange(_) => None,
|
_ => None,
|
||||||
#[cfg(feature = "i128_blob")]
|
|
||||||
FromSqlError::InvalidI128Size(_) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,6 +187,19 @@ impl FromSql for i128 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
impl FromSql for uuid::Uuid {
|
||||||
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
|
value
|
||||||
|
.as_blob()
|
||||||
|
.and_then(|bytes| {
|
||||||
|
uuid::Builder::from_slice(bytes)
|
||||||
|
.map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
|
||||||
|
})
|
||||||
|
.map(|mut builder| builder.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: FromSql> FromSql for Option<T> {
|
impl<T: FromSql> FromSql for Option<T> {
|
||||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
match value {
|
match value {
|
||||||
|
@ -65,6 +65,9 @@ from_value!(Vec<u8>);
|
|||||||
#[cfg(feature = "i128_blob")]
|
#[cfg(feature = "i128_blob")]
|
||||||
from_value!(i128);
|
from_value!(i128);
|
||||||
|
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
from_value!(uuid::Uuid);
|
||||||
|
|
||||||
impl ToSql for ToSqlOutput<'_> {
|
impl ToSql for ToSqlOutput<'_> {
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||||
Ok(match *self {
|
Ok(match *self {
|
||||||
@ -128,6 +131,9 @@ to_sql_self!(f64);
|
|||||||
#[cfg(feature = "i128_blob")]
|
#[cfg(feature = "i128_blob")]
|
||||||
to_sql_self!(i128);
|
to_sql_self!(i128);
|
||||||
|
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
to_sql_self!(uuid::Uuid);
|
||||||
|
|
||||||
impl<T: ?Sized> ToSql for &'_ T
|
impl<T: ?Sized> ToSql for &'_ T
|
||||||
where
|
where
|
||||||
T: ToSql,
|
T: ToSql,
|
||||||
@ -255,4 +261,36 @@ mod test {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
#[test]
|
||||||
|
fn test_uuid() {
|
||||||
|
use crate::{params, Connection};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
let db = Connection::open_in_memory().unwrap();
|
||||||
|
db.execute_batch("CREATE TABLE foo (id BLOB CHECK(length(id) = 16), label TEXT);")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let id = Uuid::new_v4();
|
||||||
|
|
||||||
|
db.execute(
|
||||||
|
"INSERT INTO foo (id, label) VALUES (?, ?)",
|
||||||
|
params![id, "target"],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut stmt = db
|
||||||
|
.prepare("SELECT id, label FROM foo WHERE id = ?")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut rows = stmt.query(params![id]).unwrap();
|
||||||
|
let row = rows.next().unwrap().unwrap();
|
||||||
|
|
||||||
|
let found_id: Uuid = row.get_unwrap(0);
|
||||||
|
let found_label: String = row.get_unwrap(1);
|
||||||
|
|
||||||
|
assert_eq!(found_id, id);
|
||||||
|
assert_eq!(found_label, "target");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,13 @@ impl From<i128> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
impl From<uuid::Uuid> for Value {
|
||||||
|
fn from(id: uuid::Uuid) -> Value {
|
||||||
|
Value::Blob(id.as_bytes().to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! from_i64(
|
macro_rules! from_i64(
|
||||||
($t:ty) => (
|
($t:ty) => (
|
||||||
impl From<$t> for Value {
|
impl From<$t> for Value {
|
||||||
|
Loading…
Reference in New Issue
Block a user