Git Product home page Git Product logo

rusqlite's Issues

Add support for online backup API

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.)

Allow binding of text/blobs without SQLITE_TRANSIENT?

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.)

rusqlite::Row::with_blob

(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:

  • Protocol buffer messages: protobuf::parse_from_bytes::<Proto>(...)
  • SHA-1s: [u8; 20]::clone_from_slice(...)
  • UUIDs: uuid::Uuid::from_bytes(...)

I believe I can do this now with a FromSql, but that's unpleasant in a couple ways:

  • When I don't own the type I want to use (e.g. uuid::Uuid), I have to create a wrapper type (because of "orphan rules for trait implementations", see rustc --explain E0117) then immediately unwrap it.
  • I have to do the unsafe FFI and 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.

Crate broken by Rust 1.6 on arm

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

Thread safe Connection and Optimisation

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.

Tests fail with nightly

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

Relicense under dual MIT/Apache-2.0

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.

Why?

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.

How?

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!

Contributor checkoff

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.

Why the T in query_map, and query_and_then is constrained with 'static?

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?

Connection sharing

Since you can query on an immutable SqliteConnection, won't this cause problems when the connection is shared amongst concurrent threads?

Wrong syntax for bind parameters

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();

statement.insert() does not work when using two prepared statements

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)),
        }

Check if the right number of parameters is passed into `query`

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.

Build error. use of undeclared type name `c_int`

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)

Need to know the number of columns

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 ?

Update documentation

I believe the documentation is out of date. For example, SqliteConnection::open takes a Path, not a &str.

Inappropriate `str_to_cstring` error message

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()
    })
}

Redesign ToSql to be implementable without `unsafe`

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:

  • Define an enum allowing implementors to choose between Value and BorrowedValue:
enum ToSqlOutput<'a> {
    case Owned(Value)
    case Borrowed(BorrowedValue<'a>)
}

trait ToSql {
    fn sqlite_value<'a>(&'a self) -> Result<ToSqlOutput<'a>>;
}
  • Pass in a closure that implementors must call. We'd check and panic at runtime if they don't call it?
trait ToSql {
    fn sqlite_value<'a, F: FnOnce(Result<BorrowedValue<'a>>)>(&'a self, output: F);
}

@gwenn What do you think?

Rows cannot implement Drop

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)

Implement clone for SqliteConnection?

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.

How to open a shared, in-memory database?

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.

Non-idiomatic constructor

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?

Clippy status link

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

Allow reuse of bound parameters

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:

  • Do we add a derived type (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.
  • Do we require all parameters to be bound initially? It would be slightly annoying to have to bind 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.
  • This may interact poorly with #164.

Share Connection into several threads

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?

Fix handling of SQLite column types

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 gets 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.

how to build rusqlite on windows?

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?

Database not closed when statements are cached

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");
    }
}

Make FromSql strongly typed

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).

Static link

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.

Error building Linux Mint - cannot find sqlite3

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.