Comments (7)
On second thought, it appears no mutability changes are needed in the existing API. They pass a Row
(not a &Row
) so there's no problem. This seems to build fine with the with_blob
signature above:
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_with_blob() {
let db = checked_memory_handle();
let sql = "BEGIN;
CREATE TABLE foo(x BLOB);
INSERT INTO foo VALUES(X'deadbeef');
END;";
db.execute_batch(sql).unwrap();
let mut run = false;
db.query_row_and_then("SELECT * FROM foo", &[], |mut r| {
r.with_blob(0, |b| {
assert_eq!(b, [0xde, 0xad, 0xbe, 0xef]);
assert!(!run);
run = true;
Ok(())
})
}).unwrap();
assert!(run);
}
I think for consistency with the other APIs, I probably should reverse what I have error-wise: the user-supplied function should supply something that can convert from rusqlite::Error
, not the reverse. I think something like this:
pub fn with_blob<I, F, T, E>(&mut self, idx: I, f: F) -> result::Result<T, E>
where I: RowIndex,
F: FnOnce(&[u8]) -> Result<T>,
E: convert::From<Error>
{
...
}
from rusqlite.
I agree this would be useful. I'm inclined to think there should be a way to get zero-copy string borrows too, though, and not just blobs. Before adding a with_blob
and with_str
(which I'm not necessarily opposed to), I'd like to step back and see if we can address the second point about FromSql
you brought up - having to do unsafe FFI things to implement it is very unpleasant. That's something I've been thinking about changing anyway, so I wonder if there are changes we can make to that interface that would make this possible without having to add methods to expose blobs/strs directly.
What if instead of the current FromSql
, it looked like this:
pub trait FromSql: Sized {
fn column_result(row: &Row, col: c_int) -> Result<Self>
}
rusqlite
would still implement FromSql
for basic built-in types (using the FFI interface internally), but users would be able to write their FromSql
implementations in terms of ours instead of the FFI. We could then add a parallel trait for borrowed types:
pub trait FromSqlBorrowed {
fn column_result_borrow<'a>(row: &'a mut Row, col: c_int) -> Result<&'a Self>
}
which we would implement for str
and [u8]
(but still allowing user-defined borrowed types, too). We'd have to sprout extra get
-like methods in Row
to get from these borrowed types, but those too would work for user-defined types.
I'm not thrilled with the &mut Row
. You're right that it's required given SQLite's type conversion handling, but we could potentially defer that to runtime by using a RefCell
. I'm not 100% sure it's possible and not sure at all sure it'd be worth it, but it would allow callers to pull out multiple borrowed things from different columns simultaneously. Need to play with that one a bit.
from rusqlite.
Hmm, passing a Row
directly for those traits probably isn't right. It muddies the waters about who should check the validity type of the SQLite columns. Probably need some intermediate wrapper that only exposes the equivalent to get_checked
? I'm a little uncertain what to do with those type checks, since SQLite is much more lax about types than Rust is.
from rusqlite.
I'd like a convenient way to safely access a blob column as a slice without allocating/copying to a Vec
You should have a look at the blob
feature (https://github.com/jgallagher/rusqlite/blob/master/src/blob.rs).
Blob/text data are copied directly into a Rust slice.
let db = Connection::open_in_memory().unwrap();
db.execute_batch("CREATE TABLE test (content BLOB)").unwrap();
// Insertion
db.execute_batch("INSERT INTO test VALUES ('MY VERY LONG TEXT HERE')").unwrap();
// Row id can also be retreived by a 'SELECT rowid, ... FROM test'
let rowid = db.last_insert_rowid();
// Read
let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
let size = blob.size() as usize;
// Replace this allocation by what you want/need.
let mut bytes = Vec::with_capacity(size);
bytes.resize(size, 0);
assert_eq!(size, blob.read(&mut bytes[..]).unwrap());
assert_eq!(b"MY VERY LONG TEXT HERE", &bytes[..]);
http://sqlite.org/c3ref/blob_read.html
from rusqlite.
I think the blob
feature would still require an unnecessary copy in the original case (constructing a Uuid
), since you can't construct a Uuid
from an io::Read
without first copying the bytes out into a vector or array AFAICT.
from rusqlite.
@scottlamb Now that #161 is merged, do you want to take a stab at adding a FromSqlRef
trait? I suppose it would only be implemented for str
and [u8]
.
I don't mind doing it, but if you'd like to, you're more than welcome. :)
from rusqlite.
Looking back on this, we don't need a FromSqlRef
. This still uses a wrapper type, but allows you to go straight from &[u8]
to Uuid
without collecting into a Vec<u8>
and with no unsafe code:
use rusqlite::Connection;
use rusqlite::types::{ValueRef, FromSql, FromSqlResult, FromSqlError};
use uuid::Uuid;
struct FromSqlUuid(Uuid);
impl FromSql for FromSqlUuid {
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
let bytes = value.as_blob()?;
let uuid = Uuid::from_bytes(bytes).map_err(|err| FromSqlError::Other(Box::new(err)))?;
Ok(FromSqlUuid(uuid))
}
}
fn main() {
let db = Connection::open_in_memory().unwrap();
let bytes = [4u8, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87];
let uuid = db.query_row("SELECT ?",
&[&(&bytes as &[u8])],
|row| row.get::<_, FromSqlUuid>(0).0)
.unwrap();
let expected_uuid = "0436430c-2b02-624c-2032-570501212b57";
assert_eq!(expected_uuid, uuid.hyphenated().to_string());
}
from rusqlite.
Related Issues (20)
- libsqlite3-sys fails to build on arm64: error[E0308]: mismatched types HOT 2
- release the latest version HOT 4
- FromSql vs TryFrom / ToSql vs TryInto HOT 1
- `sqlite3_compileoption_used` and Rust `const fn`
- called `Result::unwrap()` on an `Err` value: SqliteFailure(Error { code: Unknown, extended_code: 1 }, Some("json_object() requires an even number of arguments")) HOT 2
- Apps using `winsqlite3` feature no longer builds HOT 5
- Question: Is there any way to use SQLite 3.45 with rusqlite 0.30.0? HOT 2
- Trait for abstracting over `Connection`/`Transaction`? HOT 3
- SqlInputError { error: Error { code: Unknown, extended_code: 1 }, msg: "unrecognized token: \"{\"" HOT 1
- Release 0.31.0 with SQLite 3.45? HOT 2
- Type issue on select with digits only in a "string" colums. HOT 2
- wasm32-wasi target fails on Apple M3
- How to get "returning *" from insert HOT 2
- Stale Connection Handler on Multi-Threaded Situation HOT 1
- sqlite3_snapshot iteration HOT 2
- Creating `Value::Blob` without necessarily allocating heap HOT 5
- Using rusqlite::vtab::VTabConnection::handle() HOT 4
- Add bindings for `sqlite3_trace_v2` API HOT 4
- iOS Linker Warning: SQLite was build for newer version than being linked HOT 2
- the first query is failure due to below error HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rusqlite.