rusqlite / rusqlite Goto Github PK
View Code? Open in Web Editor NEWErgonomic bindings to SQLite for Rust
License: MIT License
Ergonomic bindings to SQLite for Rust
License: MIT License
I'm new to this code so this may actually be a question in the form of an issue, but I'm interested in using sqlite in-memory, and then backing up to disk, presumably using the backup API. Would you consider supporting this API, if not already supported? (API search for "backup" didn't show anything.)
This leads to a confusing couple of minutes when rust cannot import rusqlite::Connection
, because of the rename in jgallagher@4327a84
It might help to keep your docs in line with your latest version on crates.io instead of your master.
Currently, we always pass the SQLITE_TRANSIENT
flag when binding a text or blob parameter, instructing SQLite to make its own copy of the data. It would be nice to be able to avoid that copy if we can come up with a safe interface that allows it. (Initially discussed on #162.)
(I just started learning Rust. Please correct me if what I've written below seems off.)
I'd like a convenient way to safely access a blob column as a slice without allocating/copying to a Vec<u8>
. It would be more efficient in several situations, including:
protobuf::parse_from_bytes::<Proto>(...)
[u8; 20]::clone_from_slice(...)
uuid::Uuid::from_bytes(...)
I believe I can do this now with a FromSql
, but that's unpleasant in a couple ways:
uuid::Uuid
), I have to create a wrapper type (because of "orphan rules for trait implementations", see rustc --explain E0117
) then immediately unwrap it.mem::transmute
calls myself.I'd rather there be a safe interface provided in Row
. I think this is possible. However, the pointer isn't necessarily valid for as long as the Row
, as described in the sqlite3 docs:
Note that when type conversions occur, pointers returned by prior calls to sqlite3_column_blob(), sqlite3_column_text(), and/or sqlite3_column_text16() may be invalidated.
so I think it's best to provide an interface that allows accessing it through a map function. Something like the following:
pub fn with_blob<I: RowIndex, F, T>(&mut self, idx: I, f: F) -> Result<T>
where F: FnOnce(&[u8]) -> Result<T>
{
...
}
then callers could use it like so:
let uuid = r.with_blob(0, |b| {
match Uuid::from_bytes(b) {
Ok(uuid) => Ok(uuid),
Err(err) => rusqlite::Error::FromSqlConversionFailure(Box::new(err))
}
};
(or maybe it's better for with_blob
to do the wrapping of a supplied error with the rusqlite::Error::FromSqlConversionFailure(Box::new(...))
; I don't think it makes sense for the user-supplied lambda to return any of the other enum variants)
I put &mut self
in the signature to prevent accessing get_checked
on the same column while the lambda is running, causing the pointer to be prematurely invalidated. (IIUC, get_checked
by itself doesn't have this problem because there's only one thread involved (the raw pointer prevents RawStatement
from implementing Send
, which prevents Row
from implementing Send
) and the FromSql
variants get the pointer and copy it immediately, before there's any opportunity to run other code which might invalidate it.)
Unfortunately, query_map
and the like take a FnMut(&Row)
rather than a FnMut(&mut Row)
. I'm not sure what the best way to address that is. Can they simply change signatures without breaking existing calling code? Or would there have to be new functions created?
I'd be happy to submit a pull request if we can agree this feature is useful and what the function signature(s) should look like.
See #38 for discussion
See #138
Given the query_map()
and query_and_then()
methods, I suggest you take the big scary section about lifetimes and panicking out of the README. Refer to the new idioms from the warning in the rusqlite::Rows
docs too.
There's been a wee breakage causing lots of woe:
Compiling rusqlite v0.4.0
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/types.rs:110:60: 110:74 error: mismatched types:
expected `*const i8`,
found `*const u8`
(expected i8,
found u8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/types.rs:110 Ok(c_str) => ffi::sqlite3_bind_text(stmt, col, c_str.as_ptr(), length as c_int,
^~~~~~~~~~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/types.rs:110:60: 110:74 help: run `rustc --explain E0308` to see a detailed explanation
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/types.rs:204:42: 204:65 error: mismatched types:
expected `*const u8`,
found `*const i8`
(expected u8,
found i8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/types.rs:204 let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
^~~~~~~~~~~~~~~~~~~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/types.rs:204:42: 204:65 help: run `rustc --explain E0308` to see a detailed explanation
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:88:34: 88:40 error: mismatched types:
expected `*const u8`,
found `*const i8`
(expected u8,
found i8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:88 let c_slice = CStr::from_ptr(errmsg).to_bytes();
^~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:88:34: 88:40 help: run `rustc --explain E0308` to see a detailed explanation
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:486:42: 486:57 error: mismatched types:
expected `*const i8`,
found `*const u8`
(expected i8,
found u8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:486 let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), ptr::null());
^~~~~~~~~~~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:486:42: 486:57 help: run `rustc --explain E0308` to see a detailed explanation
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:543:50: 543:64 error: mismatched types:
expected `*const i8`,
found `*const u8`
(expected i8,
found u8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:543 let r = ffi::sqlite3_exec(self.db(), c_sql.as_ptr(), None, ptr::null_mut(), &mut errmsg);
^~~~~~~~~~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:543:50: 543:64 help: run `rustc --explain E0308` to see a detailed explanation
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:588:48: 588:62 error: mismatched types:
expected `*const i8`,
found `*const u8`
(expected i8,
found u8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:588 ffi::sqlite3_prepare_v2(self.db(), c_sql.as_ptr(), len_with_nul, &mut c_stmt,
^~~~~~~~~~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:588:48: 588:62 help: run `rustc --explain E0308` to see a detailed explanation
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:628:32: 628:70 error: mismatched types:
expected `*const u8`,
found `*const i8`
(expected u8,
found i8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:628 CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, i))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:628:32: 628:70 help: run `rustc --explain E0308` to see a detailed explanation
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:780:42: 780:69 error: mismatched types:
expected `*const u8`,
found `*const i8`
(expected u8,
found i8) [E0308]
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:780 let c_slice = CStr::from_ptr(ffi::sqlite3_sql(self.stmt)).to_bytes();
^~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/odroid/.cargo/registry/src/github.com-48ad6e4054423464/rusqlite-0.4.0/src/lib.rs:780:42: 780:69 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to 8 previous errors
This is what libgit2-sys does, and was also mentioned as a possible solution to difficulties on Windows in #46.
Currently, all the created savepoints have the same name sp
.
See the following test case:
gwenn@7c5f744#diff-d0e9b1d1df1c5795eac22a324e40477eR265
for an example that unexpectedly fails:
https://ci.appveyor.com/project/gwenn/rusqlite/build/1.0.64
It seems to me that savepoints must have distinct names.
Regards.
Hello,
It seems that Rust ensures that only one thread can use a Connection at the same time.
If it is true, the following optimisation can be applied when a connection is opened:
http://sqlite.org/threadsafe.html
Multi-thread. In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.
The SQLITE_OPEN_NOMUTEX flag causes the database connection to be in the multi-thread mode.
- let flags = SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE;
+ let flags = SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NO_MUTEX;
Regards.
rustc 1.10.0-nightly (9c6904ca1 2016-05-18)
---- Connection::transaction_0 stdout ----
<anon>:7:19: 7:23 error: cannot borrow immutable borrowed content `*conn` as mutable
<anon>:7 let tx = try!(conn.transaction());
^~~~
<anon>:7:19: 7:23 note: in this expansion of try! (defined in <std macros>)
error: aborting due to previous error(s)
thread 'Connection::transaction_0' panicked at 'Box<Any>', ../src/librustc/session/mod.rs:169
note: Run with `RUST_BACKTRACE=1` for a backtrace.
---- transaction::Transaction<'conn>::savepoint_0 stdout ----
<anon>:6:19: 6:23 error: cannot borrow immutable borrowed content `*conn` as mutable
<anon>:6 let tx = try!(conn.transaction());
^~~~
<anon>:6:19: 6:23 note: in this expansion of try! (defined in <std macros>)
<anon>:9:23: 9:25 error: cannot borrow immutable local variable `tx` as mutable
<anon>:9 let sp = try!(tx.savepoint());
^~
<anon>:9 let tx = try!(conn.transaction());
^~
<anon>:9:23: 9:25 note: in this expansion of try! (defined in <std macros>)
error: aborting due to previous error(s)
thread 'transaction::Transaction<'conn>::savepoint_0' panicked at 'Box<Any>', ../src/librustc/session/mod.rs:169
---- transaction::Transaction_0 stdout ----
<anon>:7:19: 7:23 error: cannot borrow immutable borrowed content `*conn` as mutable
<anon>:7 let tx = try!(conn.transaction());
^~~~
<anon>:7:19: 7:23 note: in this expansion of try! (defined in <std macros>)
error: aborting due to previous error(s)
thread 'transaction::Transaction_0' panicked at 'Box<Any>', ../src/librustc/session/mod.rs:169
failures:
Connection::transaction_0
transaction::Transaction<'conn>::savepoint_0
transaction::Transaction_0
test result: FAILED. 23 passed; 3 failed; 1 ignored; 0 measured
This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic
on IRC to discuss.
You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.
TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.
The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.
Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.
To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):
// Copyright 2016 rusqlite Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.
Be sure to add the relevant LICENSE-{MIT,APACHE}
files. You can copy these
from the Rust repo for a plain-text
version.
And don't forget to update the license
metadata in your Cargo.toml
to:
license = "MIT OR Apache-2.0"
I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!
To agree to relicensing, comment with :
I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.
Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.
The query_map
has a following signature:
fn query_map<'a, T, F>(&'a mut self, params: &[&ToSql], f: F) -> SqliteResult<MappedRows<'a, F>>
where T: 'static, F: FnMut(SqliteRow) -> T
From my understanding, the T: 'static
constraint is redundant. What is the reason for it to be there?
Since you can query on an immutable SqliteConnection
, won't this cause problems when the connection is shared amongst concurrent threads?
In https://github.com/jgallagher/rusqlite/blob/master/README.md
conn.execute("INSERT INTO person (name, time_created, data)
VALUES ($1, $2, $3)",
&[&me.name, &me.time_created, &me.data]).unwrap();
And https://github.com/jgallagher/rusqlite/blob/master/src/lib.rs#L34
//! conn.execute("INSERT INTO person (name, time_created, data)
//! VALUES ($1, $2, $3)",
//! &[&me.name, &me.time_created, &me.data]).unwrap();
http://sqlite.org/lang_expr.html#varparam
A dollar-sign followed by an identifier name also holds a spot for a named parameter with the name $AAAA.
Actually, it works because the order of parameter values match the order of bind parameters but it's not the correct syntax:
conn.execute("INSERT INTO person (name, time_created, data)
VALUES (?1, ?2, ?3)",
&[&me.name, &me.time_created, &me.data]).unwrap();
Currently, Statement::insert checks the id of the last inserted row and reports an error if that id has not changed after an insert. However, this fais when inserting in two tables alternatively. The first insert in table A can create rowid = 1, then a second insert in table B can also give back rowid = 1. Both operations are successful, but rusqlite will report an issue.
let prev_rowid = self.conn.last_insert_rowid(); // rowid from insert in table A
let changes = try!(self.execute(params));
let new_rowid = self.conn.last_insert_rowid(); // rowid from insert in table B
match changes {
1 if prev_rowid != new_rowid => Ok(new_rowid),
1 if prev_rowid == new_rowid => Err(Error::StatementFailedToInsertRow),
_ => Err(Error::StatementChangedRows(changes)),
}
See SQLITE_DBCONFIG_MAINDBNAME.
And https://github.com/jgallagher/rusqlite/blob/master/src/lib.rs#L184:
Main => str_to_cstring("main"),
Currently if you pass a slice with the wrong length into SqliteStatement::query
, it fails with an assert. It would be better to return a Result
, or at the very least use the assert!
macro with a second argument as an informative error message.
It seems like SqliteError
is meant only for errors from the sqlite bindings. If this is the case, it might be messy to add another Result
into the function interface. You could instead change the SqliteResult
type alias to take an enum as the error type param that could be either SqliteError
or some other Error
object, so both errors could be handled. Or just merge all the errors into SqliteError
.
cargo build result:
src/lib.rs:540:22: 540:27 error: use of undeclared type name `c_int` [E0412]
src/lib.rs:540 flags OpenFlags: c_int {
^~~~~
<bitflags macros>:17:24: 19:63 note: in this expansion of bitflags! (defined in <bitflags macros>)
<bitflags macros>:139:1: 141:63 note: in this expansion of bitflags! (defined in <bitflags macros>)
src/lib.rs:536:1: 551:2 note: in this expansion of bitflags! (defined in <bitflags macros>)
src/lib.rs:540:22: 540:27 help: run `rustc --explain E0412` to see a detailed explanation
src/lib.rs:540:22: 540:27 error: use of undeclared type name `c_int` [E0412]
cargo 0.10.0-nightly (fae9c53 2016-03-31)
rustc 1.7.0 (a5d1e7a59 2016-02-29)
It seems that there is no simple way to iterate on the columns of a Row
from a wildcard query (select * from foo
).
We can only call Row.get_checked
incrementally until an error is returned.
Or use Statement.column_names
to know the number of columns.
Maybe the column_count
should be public ?
The following error return isn't all that useful: https://github.com/jgallagher/rusqlite/blob/7586556db5b4ad4db94e5e6ab5232f8868b8f5c9/src/lib.rs#L299-L302
And capturing the error through string comparison message
isn't a good solution.
I think it may be useful to have error types that can be externally captured via rusqlite as a library.
This may require SqliteError
to be an enum or something.
I want to make some ffi calls after opening a connection but accessing db
fails because it is private.
I think there should be a function for that purpose but couldn't find.
query_row seems to segfault for me on the prepare line: https://github.com/jgallagher/rusqlite/blob/bf8c495b69859eea85a2e0b161b52dfe775a0641/src/lib.rs#L653. I'm walking through it with gdb and i'll have more info posted as I figure it out. I'm using the ~0.7 series of rusqlite
I believe the documentation is out of date. For example, SqliteConnection::open
takes a Path
, not a &str
.
The str_to_cstring
method is used to transform both path and SQL but the error message is meaningful only for path:
fn str_to_cstring(s: &str) -> SqliteResult<CString> {
CString::new(s).map_err(|_| SqliteError{
code: ffi::SQLITE_MISUSE,
message: "Could not convert path to C-combatible string".to_string()
})
}
After merging #161 or something like it, it'd be great to make ToSql
safe too. The easiest definition would be something like:
trait ToSql {
fn sqlite_value(&self) -> Result<Value>;
}
// for example...
impl<'a> ToSql for &'a str {
fn sqlite_value(&self) -> Result<Value> {
Ok(Value::Text(self.to_string()))
}
}
but it'd be nice to avoid forcing an extra copy (like in the hypothetical str
impl above) since SQLite is going to turn around and make its own copy too. I don't think this is possible:
trait ToSql {
fn sqlite_value<'a>(&'a self) -> Result<BorrowedValue<'a>>;
}
since there may be types which can't return a reference into themselves (e.g., if they have to serialize themselves into a string). I'm open to ideas here, both for the interface and the name of the method. A couple of possibilities:
Value
and BorrowedValue
:enum ToSqlOutput<'a> {
case Owned(Value)
case Borrowed(BorrowedValue<'a>)
}
trait ToSql {
fn sqlite_value<'a>(&'a self) -> Result<ToSqlOutput<'a>>;
}
trait ToSql {
fn sqlite_value<'a, F: FnOnce(Result<BorrowedValue<'a>>)>(&'a self, output: F);
}
@gwenn What do you think?
let row = s.query(&[]).unwrap().next().unwrap().unwrap();
// Rows has already been dropped, statement has been reset, no data can be retrieved...
row.get(0)
How much effort would it be to implement ToSql and FromSql traits for c_uint, u32 and u64?
It would be great to have an interface to sqlite3_update_hook
: https://www.sqlite.org/c3ref/update_hook.html
I also just realized Connection.handle()
is provided (never saw this before) so I can implement this myself in the meantime. However it would be great to have a baked-in way to listen to changes on the database.
Thanks!
Would it make sense to create a new connection the same database via clone? This could be useful to gain concurrent access. It is currently possible by opening the same file twice, but this does not work for in-memory databases.
It would be cool to have the query_row method for Statement and CachedStatement as well.
I've tried
Connection::open_in_memory_with_flags(SQLITE_OPEN_SHARED_CACHE).unwrap()
Connection::open_with_flags(":memory:?cache=shared", SQLITE_OPEN_URI).unwrap()
Both fail with APIMisuse
.
Firstly, please me tell me if I'm intruding on your project too much!
I was thinking the constructor for SqliteConnection
could be made more idiomatic by passing it a &Path
instead of a &str
. An added benefit would be that non-utf8 file paths could be opened as well.
A different constructor would have to be added for an in-memory connection.
What do you think?
A clippy status link can be added to the README:
@@ -1,7 +1,7 @@
# Rusqlite
[![Travis Build Status](https://api.travis-ci.org/jgallagher/rusqlite.svg?branch=master)](https://travis-ci.org/jgallagher/rusqlite)
-[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/jgallagher/rusqlite?branch=master&svg=true)](https://ci.appveyor.com/project/jgallagher/rusqlite)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/jgallagher/rusqlite?branch=master&svg=true)](https://ci.appveyor.com/project/jgallagher/rusqlite)[![Clippy Linting Result](https://clippy.bashy.io/github/jgallagher/rusqlite/master/badge.svg)](https://clippy.bashy.io/github/jgallagher/rusqlite/master/log)
Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). View the full
Statement
currently requires all parameters to be rebound each time the query is executed. We should be able to keep bindings around and only rebind individual parameters. (Initially discussed on #162.) Considerations:
BoundStatement
or something like that) that is constructed from a &mut Statement
? This derived type would re-expose execute
/query
/etc. but would not require parameters to be passed in.Null
for unknown parameters that would be rebound before the query was executed, but this might be better than leaving the door open for accidentally running a query with unbound parameters.rusqlite::Connection
isn't currently Sync + Send.
A minimal repro case could be with the lazy_static!
macro:
extern crate rusqlite;
use rusqlite::Connection;
lazy_static! {
static ref CONNECTION: Connection = Connection::open_in_memory().unwrap();
}
Compiler will identify InnerConnection
as not Syncable.
| ^ the trait `std::marker::Sync` is not implemented
for `std::cell::RefCell<rusqlite::InnerConnection>`
As far as I understand, RefCell isn't Syncable, as documented in the Rustonomicon.
Yet, tests/deny_single_threaded_sqlite_config.rs
checks sqlite3 has been compiled with multithread enabled, in the goal to share connections through threads.
Could we document the current thread status in the README and documentation?
There's no way to extract the values of each column in a row when you don't know what are the columns of the tables.
use case: generated query from an ORM.
select * from sqlite_master;
http://jgallagher.github.io/rusqlite/rusqlite/struct.SqliteRow.html
SqliteRow lacks the information of how many columns should i iterate and what are the column names of each.
Experimenting with possibilities brought up on #158, I realized we're leaving open the possibility of using sqlite3_column_type
incorrect. From SQLite's docs:
The value returned by sqlite3_column_type() is only meaningful if no type conversions have occurred as described below. After a type conversion, the value returned by sqlite3_column_type() is undefined. Future versions of SQLite may change the behavior of sqlite3_column_type() following a type conversion.
We call sqlite3_column_type
several places, including many column_has_valid_sqlite_type
implementations and the FromSql
impls for Option<T>
and Value
. If the user performs an operation that requires SQLite type conversion prior to these being called, we're hitting undefined behavior.
At first I thought maybe we could avoid calling sqlite3_column_type
altogether, and allow get
s that hit incorrectly-typed data to fall back onto SQLite's type conversions (which are well defined for all of SQLite's types). That could get rid of column_has_valid_sqlite_type
, but we still need a way to implement Option<T>
and Value
.
The only way I can think of to do this correctly is to call sqlite3_column_type
ahead of time for each column. This could be cached in the construction of the Rows
handle, but not up in Statement
(since a DDL execution between statement queries could result in changes).
@gwenn Any thoughts on this? Is my understanding of this issue correct, and if so, can you think of any other solution? I checked a couple of other SQLite wrappers; go-sqlite3 pulls out all the column values ahead of time during iteration (it calls sqlite3_column_type
but always as the first operation for a column), and sqlite-jdbc appears to have the same issue we currently do.
At first blush it seems redundant to have two results in use here, so I'm curious what errors it is actually guarding against.
On Linux eco system i had no problems. But on windows I feel a little bit helpless. Could you provide some short hints on how to build rusqlite on windows, please?
Install pkg_config for windows?
Which files I have to download from sqlite hompage?
Where to place?
...
Any hints?
Closing database connections fails when prepared statements are cached. Setting set_prepared_statement_cache_capacity
to 0
before closing seems to work as a workaround, but I haven't dug into the code to see if doing so in the close()
(and drop()
) implementation would be a good idea.
#[cfg(test)]
mod tests {
extern crate rusqlite;
use tests::rusqlite::Connection;
#[test]
fn it_works() {
let conn = Connection::open_in_memory().unwrap();
conn.prepare_cached("SELECT * FROM sqlite_master;").unwrap();
conn.close().expect("connection not closed");
}
}
Several types in the root module are named Sqlite*
. This is not good practice for names, and user code can simply bind these names to different ones in use
if they experience a naming collision.
There doesn't seem to be docs for extra features of rusqlite v0.6
. e.g. http://jgallagher.github.io/rusqlite/rusqlite/index.html?search=backup
I had to rely on source comments. Is this intended?
Things like let foo: i32 = row.get(0)
shouldn't be allowed if row.get(0) refers to a text field in the database. Currently this just returns 0 instead of panicing (or returning a Result
).
It would be cool to add a feature to do a static link to sqlite. As it's only one file, it should be fairly easy.
http://sqlite.org/c3ref/column_blob.html
The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
I'm getting this error below and for searching cannot see a way through it.
sqlite3 is installed and working fine.
I cannot see sqlite3.pc or similar and I'm not familiar with those .pc files then to know an obvious answer.
Curious that majkcramer commented in May on the other issue that he's been successful in Linux.. I tried building only this from git clone too but same error.
I'm using Cargo build; unsure what the rustc equivalent to Cargo.toml is to try rustc but I would expect the same error perhaps will follow from that too.
Fresh libc v0.1.8
Fresh winapi v0.2.1
Fresh pkg-config v0.3.5
Compiling libsqlite3-sys v0.2.0 (file:///home/davidpbrown/rust/firefox/rusqlite)
Running `/home/davidpbrown/rust/firefox/rusqlite/target/debug/build/libsqlite3-sys-863cdbd64abd8e99/build-script-build`
Fresh bitflags v0.1.1
Fresh winapi-build v0.1.1
Fresh advapi32-sys v0.1.2
Fresh rand v0.3.9
Fresh tempdir v0.3.4
Fresh kernel32-sys v0.1.3
Fresh time v0.1.32
failed to run custom build command for `libsqlite3-sys v0.2.0 (file:///home/davidpbrown/rust/firefox/rusqlite)`
Process didn't exit successfully: `/home/davidpbrown/rust/firefox/rusqlite/target/debug/build/libsqlite3-sys-863cdbd64abd8e99/build-script-build` (exit code: 101)
--- stderr
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: "`\"pkg-config\" \"--libs\" \"--cflags\" \"sqlite3\"` did not exit successfully: exit code: 1\n--- stderr\nPackage sqlite3 was not found in the pkg-config search path.\nPerhaps you should add the directory containing `sqlite3.pc\'\nto the PKG_CONFIG_PATH environment variable\nNo package \'sqlite3\' found\n"', ../src/libcore/result.rs:732
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.