Git Product home page Git Product logo

rusqlite's Introduction

Rusqlite

Latest Version Documentation Build Status (GitHub) Build Status (AppVeyor) Code Coverage Dependency Status Discord Chat

Rusqlite is an ergonomic wrapper for using SQLite from Rust.

Historically, the API was based on the one from rust-postgres. However, the two have diverged in many ways, and no compatibility between the two is intended.

Usage

In your Cargo.toml:

[dependencies]
# `bundled` causes us to automatically compile and link in an up to date
# version of SQLite for you. This avoids many common build issues, and
# avoids depending on the version of SQLite on the users system (or your
# system), which may be old or missing. It's the right choice for most
# programs that control their own SQLite databases.
#
# That said, it's not ideal for all scenarios and in particular, generic
# libraries built around `rusqlite` should probably not enable it, which
# is why it is not a default feature -- it could become hard to disable.
rusqlite = { version = "0.31.0", features = ["bundled"] }

Simple example usage:

use rusqlite::{Connection, Result};

#[derive(Debug)]
struct Person {
    id: i32,
    name: String,
    data: Option<Vec<u8>>,
}

fn main() -> Result<()> {
    let conn = Connection::open_in_memory()?;

    conn.execute(
        "CREATE TABLE person (
            id    INTEGER PRIMARY KEY,
            name  TEXT NOT NULL,
            data  BLOB
        )",
        (), // empty list of parameters.
    )?;
    let me = Person {
        id: 0,
        name: "Steven".to_string(),
        data: None,
    };
    conn.execute(
        "INSERT INTO person (name, data) VALUES (?1, ?2)",
        (&me.name, &me.data),
    )?;

    let mut stmt = conn.prepare("SELECT id, name, data FROM person")?;
    let person_iter = stmt.query_map([], |row| {
        Ok(Person {
            id: row.get(0)?,
            name: row.get(1)?,
            data: row.get(2)?,
        })
    })?;

    for person in person_iter {
        println!("Found person {:?}", person.unwrap());
    }
    Ok(())
}

Supported SQLite Versions

The base rusqlite package supports SQLite version 3.14.0 or newer. If you need support for older versions, please file an issue. Some cargo features require a newer SQLite version; see details below.

Optional Features

Rusqlite provides several features that are behind Cargo features. They are:

  • load_extension allows loading dynamic library-based SQLite extensions.
  • loadable_extension to program loadable extension in Rust.
  • backup allows use of SQLite's online backup API.
  • functions allows you to load Rust closures into SQLite connections for use in queries.
  • window for window function support (fun(...) OVER ...). (Implies functions.)
  • trace allows hooks into SQLite's tracing and profiling APIs.
  • blob gives std::io::{Read, Write, Seek} access to SQL BLOBs.
  • limits allows you to set and retrieve SQLite's per connection limits.
  • chrono implements FromSql and ToSql for various types from the chrono crate.
  • serde_json implements FromSql and ToSql for the Value type from the serde_json crate.
  • time implements FromSql and ToSql for various types from the time crate.
  • url implements FromSql and ToSql for the Url type from the url crate.
  • bundled uses a bundled version of SQLite. This is a good option for cases where linking to SQLite is complicated, such as Windows.
  • sqlcipher looks for the SQLCipher library to link against instead of SQLite. This feature overrides bundled.
  • bundled-sqlcipher uses a bundled version of SQLCipher. This searches for and links against a system-installed crypto library to provide the crypto implementation.
  • bundled-sqlcipher-vendored-openssl allows using bundled-sqlcipher with a vendored version of OpenSSL (via the openssl-sys crate) as the crypto provider.
    • As the name implies this depends on the bundled-sqlcipher feature, and automatically turns it on.
    • If turned on, this uses the openssl-sys crate, with the vendored feature enabled in order to build and bundle the OpenSSL crypto library.
  • hooks for Commit, Rollback and Data Change notification callbacks.
  • preupdate_hook for preupdate notification callbacks. (Implies hooks.)
  • unlock_notify for Unlock notification.
  • vtab for virtual table support (allows you to write virtual table implementations in Rust). Currently, only read-only virtual tables are supported.
  • series exposes generate_series(...) Table-Valued Function. (Implies vtab.)
  • csvtab, CSV virtual table written in Rust. (Implies vtab.)
  • array, The rarray() Table-Valued Function. (Implies vtab.)
  • 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 crate using blobs.
  • session, Session module extension. Requires buildtime_bindgen feature. (Implies hooks.)
  • extra_check fail when a query passed to execute is readonly or has a column count > 0.
  • column_decltype provides columns() method for Statements and Rows; omit if linking to a version of SQLite/SQLCipher compiled with -DSQLITE_OMIT_DECLTYPE.
  • collation exposes sqlite3_create_collation_v2.
  • serialize exposes sqlite3_serialize (3.23.0).

Notes on building rusqlite and libsqlite3-sys

libsqlite3-sys is a separate crate from rusqlite that provides the Rust declarations for SQLite's C API. By default, libsqlite3-sys attempts to find a SQLite library that already exists on your system using pkg-config, or a Vcpkg installation for MSVC ABI builds.

You can adjust this behavior in a number of ways:

  • If you use the bundled, bundled-sqlcipher, or bundled-sqlcipher-vendored-openssl features, libsqlite3-sys will use the cc crate to compile SQLite or SQLCipher from source and link against that. This source is embedded in the libsqlite3-sys crate and is currently SQLite 3.45.1 (as of rusqlite 0.31.0 / libsqlite3-sys 0.28.0). This is probably the simplest solution to any build problems. You can enable this by adding the following in your Cargo.toml file:

    [dependencies.rusqlite]
    version = "0.31.0"
    features = ["bundled"]
  • When using any of the bundled features, the build script will honor SQLITE_MAX_VARIABLE_NUMBER and SQLITE_MAX_EXPR_DEPTH variables. It will also honor a LIBSQLITE3_FLAGS variable, which can have a format like "-USQLITE_ALPHA -DSQLITE_BETA SQLITE_GAMMA ...". That would disable the SQLITE_ALPHA flag, and set the SQLITE_BETA and SQLITE_GAMMA flags. (The initial -D can be omitted, as on the last one.)

  • When using bundled-sqlcipher (and not also using bundled-sqlcipher-vendored-openssl), libsqlite3-sys will need to link against crypto libraries on the system. If the build script can find a libcrypto from OpenSSL or LibreSSL (it will consult OPENSSL_LIB_DIR/OPENSSL_INCLUDE_DIR and OPENSSL_DIR environment variables), it will use that. If building on and for Macs, and none of those variables are set, it will use the system's SecurityFramework instead.

  • When linking against a SQLite (or SQLCipher) library already on the system (so not using any of the bundled features), you can set the SQLITE3_LIB_DIR (or SQLCIPHER_LIB_DIR) environment variable to point to a directory containing the library. You can also set the SQLITE3_INCLUDE_DIR (or SQLCIPHER_INCLUDE_DIR) variable to point to the directory containing sqlite3.h.

  • Installing the sqlite3 development packages will usually be all that is required, but the build helpers for pkg-config and vcpkg have some additional configuration options. The default when using vcpkg is to dynamically link, which must be enabled by setting VCPKGRS_DYNAMIC=1 environment variable before build. vcpkg install sqlite3:x64-windows will install the required library.

  • When linking against a SQLite (or SQLCipher) library already on the system, you can set the SQLITE3_STATIC (or SQLCIPHER_STATIC) environment variable to 1 to request that the library be statically instead of dynamically linked.

Binding generation

We use bindgen to generate the Rust declarations from SQLite's C header file. bindgen recommends running this as part of the build process of libraries that used this. We tried this briefly (rusqlite 0.10.0, specifically), but it had some annoyances:

  • The build time for libsqlite3-sys (and therefore rusqlite) increased dramatically.
  • Running bindgen requires a relatively-recent version of Clang, which many systems do not have installed by default.
  • Running bindgen also requires the SQLite header file to be present.

As of rusqlite 0.10.1, we avoid running bindgen at build-time by shipping pregenerated bindings for several versions of SQLite. When compiling rusqlite, we use your selected Cargo features to pick the bindings for the minimum SQLite version that supports your chosen features. If you are using libsqlite3-sys directly, you can use the same features to choose which pregenerated bindings are chosen:

  • min_sqlite_version_3_14_0 - SQLite 3.14.0 bindings (this is the default)

If you use any of the bundled features, you will get pregenerated bindings for the bundled version of SQLite/SQLCipher. If you need other specific pregenerated binding versions, please file an issue. If you want to run bindgen at buildtime to produce your own bindings, use the buildtime_bindgen Cargo feature.

If you enable the modern_sqlite feature, we'll use the bindings we would have included with the bundled build. You generally should have buildtime_bindgen enabled if you turn this on, as otherwise you'll need to keep the version of SQLite you link with in sync with what rusqlite would have bundled, (usually the most recent release of SQLite). Failing to do this will cause a runtime error.

Contributing

Rusqlite has many features, and many of them impact the build configuration in incompatible ways. This is unfortunate, and makes testing changes hard.

To help here: you generally should ensure that you run tests/lint for --features bundled, and --features "bundled-full session buildtime_bindgen".

If running bindgen is problematic for you, --features bundled-full enables bundled and all features which don't require binding generation, and can be used instead.

Checklist

  • Run cargo fmt to ensure your Rust code is correctly formatted.
  • Ensure cargo clippy --workspace --features bundled passes without warnings.
  • Ensure cargo clippy --workspace --features "bundled-full session buildtime_bindgen" passes without warnings.
  • Ensure cargo test --workspace --features bundled reports no failures.
  • Ensure cargo test --workspace --features "bundled-full session buildtime_bindgen" reports no failures.

Author

Rusqlite is the product of hard work by a number of people. A list is available here: https://github.com/rusqlite/rusqlite/graphs/contributors

Community

Feel free to join the Rusqlite Discord Server to discuss or get help with rusqlite or libsqlite3-sys.

License

Rusqlite and libsqlite3-sys are available under the MIT license. See the LICENSE file for more info.

Licenses of Bundled Software

Depending on the set of enabled cargo features, rusqlite and libsqlite3-sys will also bundle other libraries, which have their own licensing terms:

  • If --features=bundled-sqlcipher is enabled, the vendored source of SQLcipher will be compiled and statically linked in. SQLcipher is distributed under a BSD-style license, as described here.

  • If --features=bundled is enabled, the vendored source of SQLite will be compiled and linked in. SQLite is in the public domain, as described here.

Both of these are quite permissive, have no bearing on the license of the code in rusqlite or libsqlite3-sys themselves, and can be entirely ignored if you do not use the feature in question.

rusqlite's People

Contributors

aschey avatar blackholefox avatar chamakits avatar daanschutte avatar davidselassie avatar dependabot[bot] avatar derekdreery avatar dubiousjim avatar edelangh avatar gwenn avatar heavenboy8 avatar hydhknn avatar jgallagher avatar jrandall avatar kornelski avatar lgarczyn avatar marcusklaas avatar mcgoo avatar midaslamb avatar nhynes avatar nvzqz avatar nyurik avatar pfernie avatar phiresky avatar striezel avatar technic avatar thomcc avatar timmmm avatar trevyn avatar twistedfall avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rusqlite's Issues

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

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)

Update documentation

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

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?

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.

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

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.

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

Connection sharing

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

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

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?

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.

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)

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

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.

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.

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.

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

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

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.

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.

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?

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?

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

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?

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 ?

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

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

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

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.

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.