mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
commit
85454c04ec
@ -40,6 +40,7 @@ script:
|
||||
- cargo test --features bundled
|
||||
- cargo test --features sqlcipher
|
||||
- cargo test --features i128_blob
|
||||
- cargo test --features uuid
|
||||
- cargo test --features "unlock_notify bundled"
|
||||
- cargo test --features "array bundled csvtab 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-streaming-iterator = "0.1"
|
||||
memchr = "2.2.0"
|
||||
uuid = { version = "0.7", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
lazy_static = "1.0"
|
||||
regex = "1.0"
|
||||
uuid = { version = "0.7", features = ["v4"] }
|
||||
|
||||
[dependencies.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.
|
||||
* [`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.
|
||||
* `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.
|
||||
|
||||
## Notes on building rusqlite and libsqlite3-sys
|
||||
|
@ -230,6 +230,8 @@ impl<'stmt> Row<'stmt> {
|
||||
}
|
||||
#[cfg(feature = "i128_blob")]
|
||||
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")]
|
||||
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.
|
||||
Other(Box<dyn Error + Send + Sync>),
|
||||
}
|
||||
@ -29,6 +34,8 @@ impl PartialEq for FromSqlError {
|
||||
(FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
|
||||
#[cfg(feature = "i128_blob")]
|
||||
(FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
|
||||
#[cfg(feature = "uuid")]
|
||||
(FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2,
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
@ -43,6 +50,10 @@ impl fmt::Display for FromSqlError {
|
||||
FromSqlError::InvalidI128Size(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),
|
||||
}
|
||||
}
|
||||
@ -55,6 +66,8 @@ impl Error for FromSqlError {
|
||||
FromSqlError::OutOfRange(_) => "value out of range",
|
||||
#[cfg(feature = "i128_blob")]
|
||||
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(),
|
||||
}
|
||||
}
|
||||
@ -64,9 +77,7 @@ impl Error for FromSqlError {
|
||||
fn cause(&self) -> Option<&dyn Error> {
|
||||
match *self {
|
||||
FromSqlError::Other(ref err) => err.cause(),
|
||||
FromSqlError::InvalidType | FromSqlError::OutOfRange(_) => None,
|
||||
#[cfg(feature = "i128_blob")]
|
||||
FromSqlError::InvalidI128Size(_) => None,
|
||||
_ => 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> {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
match value {
|
||||
|
@ -65,6 +65,9 @@ from_value!(Vec<u8>);
|
||||
#[cfg(feature = "i128_blob")]
|
||||
from_value!(i128);
|
||||
|
||||
#[cfg(feature = "uuid")]
|
||||
from_value!(uuid::Uuid);
|
||||
|
||||
impl ToSql for ToSqlOutput<'_> {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||
Ok(match *self {
|
||||
@ -128,6 +131,9 @@ to_sql_self!(f64);
|
||||
#[cfg(feature = "i128_blob")]
|
||||
to_sql_self!(i128);
|
||||
|
||||
#[cfg(feature = "uuid")]
|
||||
to_sql_self!(uuid::Uuid);
|
||||
|
||||
impl<T: ?Sized> ToSql for &'_ T
|
||||
where
|
||||
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(
|
||||
($t:ty) => (
|
||||
impl From<$t> for Value {
|
||||
|
Loading…
Reference in New Issue
Block a user