Merge remote-tracking branch 'remotes/jgallagher/master' into vtab

This commit is contained in:
gwenn 2018-01-20 12:29:07 +01:00
commit 3aaab1e36f
20 changed files with 194 additions and 93 deletions

2
.gitattributes vendored
View File

@ -1 +1 @@
libsqlite3-sys/sqlite3 linguist-vendored libsqlite3-sys/sqlite3/* linguist-vendored

View File

@ -13,12 +13,10 @@ matrix:
addons: addons:
apt: apt:
sources:
- llvm-toolchain-precise-3.9
- ubuntu-toolchain-r-test
packages: # recommanded versions for rust-bindgen packages: # recommanded versions for rust-bindgen
- llvm-3.9-dev - llvm-3.9-dev
- libclang-3.9-dev - libclang-3.9-dev
- libsqlcipher-dev
env: # specify the clang path for rust-bindgen env: # specify the clang path for rust-bindgen
- LIBCLANG_PATH=/usr/lib/llvm-3.9/lib - LIBCLANG_PATH=/usr/lib/llvm-3.9/lib
@ -26,6 +24,7 @@ env: # specify the clang path for rust-bindgen
script: script:
- cargo build - cargo build
- cargo build --features bundled - cargo build --features bundled
- cargo build --features sqlcipher
- cargo test - cargo test
- cargo test --features backup - cargo test --features backup
- cargo test --features blob - cargo test --features blob
@ -36,6 +35,7 @@ script:
- cargo test --features chrono - cargo test --features chrono
- cargo test --features serde_json - cargo test --features serde_json
- cargo test --features bundled - cargo test --features bundled
- cargo test --features sqlcipher
- cargo test --features "csvtab functions vtab" - cargo test --features "csvtab functions vtab"
- cargo test --features "backup blob chrono csvtab functions limits load_extension serde_json trace vtab" - cargo test --features "backup blob chrono csvtab functions limits load_extension serde_json trace vtab"
- cargo test --features "backup blob chrono csvtab functions limits load_extension serde_json trace vtab buildtime_bindgen" - cargo test --features "backup blob chrono csvtab functions limits load_extension serde_json trace vtab buildtime_bindgen"

View File

@ -22,3 +22,13 @@ rusqlite contributors
* [Steven Fackler](https://github.com/sfackler) * [Steven Fackler](https://github.com/sfackler)
* [Davide Aversa](https://github.com/THeK3nger) * [Davide Aversa](https://github.com/THeK3nger)
* [mcgoo](https://github.com/mcgoo) * [mcgoo](https://github.com/mcgoo)
* [Kelvin Ly](https://github.com/cactorium)
* [king6cong](https://github.com/king6cong)
* [Andy Russell](https://github.com/euclio)
* [Tristan Lostroh](https://github.com/tl8roy)
* [Ossi Herrala](https://github.com/oherrala)
* [Vojtech Cima](https://github.com/vojtechcima)
* [Louis Garczynski](https://github.com/lgarczyn)
* [twistedfall](https://github.com/twistedfall)
* [Nick Fitzgerald](https://github.com/fitzgen)
* [Lorenzo Villani](https://github.com/lvillani)

View File

@ -1,10 +1,10 @@
[package] [package]
name = "rusqlite" name = "rusqlite"
version = "0.12.0" version = "0.13.0"
authors = ["John Gallagher <jgallagher@bignerdranch.com>"] authors = ["John Gallagher <jgallagher@bignerdranch.com>"]
description = "Ergonomic wrapper for SQLite" description = "Ergonomic wrapper for SQLite"
repository = "https://github.com/jgallagher/rusqlite" repository = "https://github.com/jgallagher/rusqlite"
documentation = "http://jgallagher.github.io/rusqlite/rusqlite/index.html" documentation = "http://docs.rs/rusqlite/"
readme = "README.md" readme = "README.md"
keywords = ["sqlite", "database", "ffi"] keywords = ["sqlite", "database", "ffi"]
license = "MIT" license = "MIT"
@ -26,14 +26,15 @@ trace = ["libsqlite3-sys/min_sqlite_version_3_6_23"]
bundled = ["libsqlite3-sys/bundled"] bundled = ["libsqlite3-sys/bundled"]
buildtime_bindgen = ["libsqlite3-sys/buildtime_bindgen"] buildtime_bindgen = ["libsqlite3-sys/buildtime_bindgen"]
limits = [] limits = []
sqlcipher = ["libsqlite3-sys/sqlcipher"]
vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7"] vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7"]
csvtab = ["csv"] csvtab = ["csv"]
[dependencies] [dependencies]
time = "0.1.0" time = "0.1.0"
bitflags = "0.9" bitflags = "1.0"
lru-cache = "0.1" lru-cache = "0.1"
chrono = { version = "0.3", optional = true } chrono = { version = "0.4", optional = true }
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
[dev-dependencies] [dev-dependencies]
@ -43,7 +44,7 @@ regex = "0.2"
[dependencies.libsqlite3-sys] [dependencies.libsqlite3-sys]
path = "libsqlite3-sys" path = "libsqlite3-sys"
version = "0.8" version = "0.9"
[dependencies.csv] [dependencies.csv]
version = "0.14" version = "0.14"
@ -55,3 +56,9 @@ harness = false
[[test]] [[test]]
name = "deny_single_threaded_sqlite_config" name = "deny_single_threaded_sqlite_config"
[package.metadata.docs.rs]
features = [ "backup", "blob", "chrono", "functions", "limits", "load_extension", "serde_json", "trace" ]
all-features = false
no-default-features = true
default-target = "x86_64-unknown-linux-gnu"

View File

@ -1,3 +1,13 @@
# Version 0.13.0 (2017-11-13)
* Added ToSqlConversionFailure case to Error enum.
* Now depends on chrono 0.4, bitflats 1.0, and (optionally) cc 1.0 / bindgen 0.31.
* The ToSql/FromSql implementations for time::Timespec now include
and expect fractional seconds and timezone in the serialized string.
* The RowIndex type used in Row::get is now publicly exported.
* New `sqlcipher` feature allows linking against SQLCipher instead of SQLite.
* Doc link in README now point to docs.rs.
# Version 0.12.0 (2017-05-29) # Version 0.12.0 (2017-05-29)
* Defines HAVE\_USLEEP when building with a bundled SQLite (#263). * Defines HAVE\_USLEEP when building with a bundled SQLite (#263).

View File

@ -5,7 +5,7 @@
Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose 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 an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). View the full
[API documentation](http://jgallagher.github.io/rusqlite/rusqlite/index.html). [API documentation](http://docs.rs/rusqlite/).
```rust ```rust
extern crate rusqlite; extern crate rusqlite;
@ -90,6 +90,7 @@ features](http://doc.crates.io/manifest.html#the-features-section). They are:
and [`ToSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.ToSql.html) for the and [`ToSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.ToSql.html) for the
`Value` type from the [`serde_json` crate](https://crates.io/crates/serde_json). `Value` type from the [`serde_json` crate](https://crates.io/crates/serde_json).
* `bundled` uses a bundled version of sqlite3. This is a good option for cases where linking to sqlite3 is complicated, such as Windows. * `bundled` uses a bundled version of sqlite3. This is a good option for cases where linking to sqlite3 is complicated, such as Windows.
* `sqlcipher` looks for the SQLCipher library to link against instead of SQLite. This feature is mutually exclusive with `bundled`.
## Notes on building rusqlite and libsqlite3-sys ## Notes on building rusqlite and libsqlite3-sys

View File

@ -1,9 +1,10 @@
environment: environment:
matrix: matrix:
- TARGET: 1.15.0-x86_64-pc-windows-gnu - TARGET: 1.21.0-x86_64-pc-windows-gnu
MSYS2_BITS: 64 MSYS2_BITS: 64
- TARGET: 1.15.0-x86_64-pc-windows-msvc - TARGET: 1.21.0-x86_64-pc-windows-msvc
VCPKG_DEFAULT_TRIPLET: x64-windows VCPKG_DEFAULT_TRIPLET: x64-windows
VCPKGRS_DYNAMIC: 1
- TARGET: nightly-x86_64-pc-windows-msvc - TARGET: nightly-x86_64-pc-windows-msvc
VCPKG_DEFAULT_TRIPLET: x64-windows-static VCPKG_DEFAULT_TRIPLET: x64-windows-static
RUSTFLAGS: -Ctarget-feature=+crt-static RUSTFLAGS: -Ctarget-feature=+crt-static

View File

@ -1,19 +1,20 @@
[package] [package]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.8.1" version = "0.9.1"
authors = ["John Gallagher <jgallagher@bignerdranch.com>"] authors = ["John Gallagher <jgallagher@bignerdranch.com>"]
repository = "https://github.com/jgallagher/rusqlite" repository = "https://github.com/jgallagher/rusqlite"
description = "Native bindings to the libsqlite3 library" description = "Native bindings to the libsqlite3 library"
license = "MIT" license = "MIT"
links = "sqlite3" links = "sqlite3"
build = "build.rs" build = "build.rs"
keywords = ["sqlite", "database", "ffi"] keywords = ["sqlite", "sqlcipher", "ffi"]
categories = ["database", "external-ffi-bindings"] categories = ["external-ffi-bindings"]
[features] [features]
default = ["min_sqlite_version_3_6_8"] default = ["min_sqlite_version_3_6_8"]
bundled = ["gcc"] bundled = ["cc"]
buildtime_bindgen = ["bindgen", "pkg-config", "vcpkg"] buildtime_bindgen = ["bindgen", "pkg-config", "vcpkg"]
sqlcipher = []
min_sqlite_version_3_6_8 = ["pkg-config", "vcpkg"] min_sqlite_version_3_6_8 = ["pkg-config", "vcpkg"]
min_sqlite_version_3_6_11 = ["pkg-config", "vcpkg"] min_sqlite_version_3_6_11 = ["pkg-config", "vcpkg"]
min_sqlite_version_3_6_23 = ["pkg-config", "vcpkg"] min_sqlite_version_3_6_23 = ["pkg-config", "vcpkg"]
@ -23,9 +24,9 @@ min_sqlite_version_3_7_7 = ["pkg-config", "vcpkg"]
min_sqlite_version_3_7_16 = ["pkg-config", "vcpkg"] min_sqlite_version_3_7_16 = ["pkg-config", "vcpkg"]
[build-dependencies] [build-dependencies]
bindgen = { version = "0.23", optional = true } bindgen = { version = "0.31", optional = true }
pkg-config = { version = "0.3", optional = true } pkg-config = { version = "0.3", optional = true }
gcc = { version = "0.3", optional = true } cc = { version = "1.0", optional = true }
[target.'cfg(target_env = "msvc")'.build-dependencies] [target.'cfg(target_env = "msvc")'.build-dependencies]
vcpkg = { version = "0.2", optional = true } vcpkg = { version = "0.2", optional = true }

View File

@ -4,17 +4,21 @@ fn main() {
#[cfg(feature = "bundled")] #[cfg(feature = "bundled")]
mod build { mod build {
extern crate gcc; extern crate cc;
use std::{env, fs}; use std::{env, fs};
use std::path::Path; use std::path::Path;
pub fn main() { pub fn main() {
if cfg!(feature = "sqlcipher") {
panic!("Builds with bundled SQLCipher are not supported");
}
let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap();
let out_path = Path::new(&out_dir).join("bindgen.rs"); let out_path = Path::new(&out_dir).join("bindgen.rs");
fs::copy("sqlite3/bindgen_bundled_version.rs", out_path) fs::copy("sqlite3/bindgen_bundled_version.rs", out_path)
.expect("Could not copy bindings to output directory"); .expect("Could not copy bindings to output directory");
gcc::Config::new() cc::Build::new()
.file("sqlite3/sqlite3.c") .file("sqlite3/sqlite3.c")
.flag("-DSQLITE_CORE") .flag("-DSQLITE_CORE")
.flag("-DSQLITE_DEFAULT_FOREIGN_KEYS=1") .flag("-DSQLITE_DEFAULT_FOREIGN_KEYS=1")
@ -58,8 +62,9 @@ mod build {
fn from(header: HeaderLocation) -> String { fn from(header: HeaderLocation) -> String {
match header { match header {
HeaderLocation::FromEnvironment => { HeaderLocation::FromEnvironment => {
let mut header = env::var("SQLITE3_INCLUDE_DIR") let prefix = env_prefix();
.expect("SQLITE3_INCLUDE_DIR must be set if SQLITE3_LIB_DIR is set"); let mut header = env::var(format!("{}_INCLUDE_DIR", prefix))
.expect(&format!("{}_INCLUDE_DIR must be set if {}_LIB_DIR is set", prefix, prefix));
header.push_str("/sqlite3.h"); header.push_str("/sqlite3.h");
header header
} }
@ -76,9 +81,11 @@ mod build {
// Prints the necessary cargo link commands and returns the path to the header. // Prints the necessary cargo link commands and returns the path to the header.
fn find_sqlite() -> HeaderLocation { fn find_sqlite() -> HeaderLocation {
let link_lib = link_lib();
// Allow users to specify where to find SQLite. // Allow users to specify where to find SQLite.
if let Ok(dir) = env::var("SQLITE3_LIB_DIR") { if let Ok(dir) = env::var(format!("{}_LIB_DIR", env_prefix())) {
println!("cargo:rustc-link-lib=sqlite3"); println!("cargo:rustc-link-lib={}", link_lib);
println!("cargo:rustc-link-search={}", dir); println!("cargo:rustc-link-search={}", dir);
return HeaderLocation::FromEnvironment; return HeaderLocation::FromEnvironment;
} }
@ -88,7 +95,7 @@ mod build {
} }
// See if pkg-config can do everything for us. // See if pkg-config can do everything for us.
match pkg_config::Config::new().print_system_libs(false).probe("sqlite3") { match pkg_config::Config::new().print_system_libs(false).probe(link_lib) {
Ok(mut lib) => { Ok(mut lib) => {
if let Some(mut header) = lib.include_paths.pop() { if let Some(mut header) = lib.include_paths.pop() {
header.push("sqlite3.h"); header.push("sqlite3.h");
@ -102,7 +109,7 @@ mod build {
// request and hope that the library exists on the system paths. We used to // request and hope that the library exists on the system paths. We used to
// output /usr/lib explicitly, but that can introduce other linking problems; see // output /usr/lib explicitly, but that can introduce other linking problems; see
// https://github.com/jgallagher/rusqlite/issues/207. // https://github.com/jgallagher/rusqlite/issues/207.
println!("cargo:rustc-link-lib=sqlite3"); println!("cargo:rustc-link-lib={}", link_lib);
HeaderLocation::Wrapper HeaderLocation::Wrapper
} }
} }
@ -111,7 +118,7 @@ mod build {
#[cfg(all(feature = "vcpkg", target_env = "msvc"))] #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
fn try_vcpkg() -> Option<HeaderLocation> { fn try_vcpkg() -> Option<HeaderLocation> {
// See if vcpkg can find it. // See if vcpkg can find it.
if let Ok(mut lib) = vcpkg::Config::new().probe("sqlite3") { if let Ok(mut lib) = vcpkg::Config::new().probe(link_lib()) {
if let Some(mut header) = lib.include_paths.pop() { if let Some(mut header) = lib.include_paths.pop() {
header.push("sqlite3.h"); header.push("sqlite3.h");
return Some(HeaderLocation::FromPath(header.to_string_lossy().into())); return Some(HeaderLocation::FromPath(header.to_string_lossy().into()));
@ -125,6 +132,22 @@ mod build {
None None
} }
fn env_prefix() -> &'static str {
if cfg!(feature = "sqlcipher") {
"SQLCIPHER"
} else {
"SQLITE3"
}
}
fn link_lib() -> &'static str {
if cfg!(feature = "sqlcipher") {
"sqlcipher"
} else {
"sqlite3"
}
}
#[cfg(not(feature = "buildtime_bindgen"))] #[cfg(not(feature = "buildtime_bindgen"))]
mod bindings { mod bindings {
use super::HeaderLocation; use super::HeaderLocation;
@ -205,7 +228,7 @@ mod build {
// was added in SQLite 3.8.3, but oring it in in prior versions of SQLite is harmless. We // was added in SQLite 3.8.3, but oring it in in prior versions of SQLite is harmless. We
// don't want to not build just because this flag is missing (e.g., if we're linking against // don't want to not build just because this flag is missing (e.g., if we're linking against
// SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's output. // SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's output.
if !output.contains("pub const SQLITE_DETERMINISTIC:") { if !output.contains("pub const SQLITE_DETERMINISTIC") {
output.push_str("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n"); output.push_str("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n");
} }

View File

@ -75,6 +75,9 @@ pub enum Error {
#[allow(dead_code)] #[allow(dead_code)]
UserFunctionError(Box<error::Error + Send + Sync>), UserFunctionError(Box<error::Error + Send + Sync>),
/// Error available for the implementors of the `ToSql` trait.
ToSqlConversionFailure(Box<error::Error + Send + Sync>),
/// An error case available for implementors of custom modules (e.g., /// An error case available for implementors of custom modules (e.g.,
/// `create_module`). /// `create_module`).
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
@ -134,6 +137,7 @@ impl fmt::Display for Error {
} }
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::UserFunctionError(ref err) => err.fmt(f), Error::UserFunctionError(ref err) => err.fmt(f),
Error::ToSqlConversionFailure(ref err) => err.fmt(f),
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
Error::ModuleError(ref desc) => write!(f, "{}", desc), Error::ModuleError(ref desc) => write!(f, "{}", desc),
} }
@ -163,6 +167,7 @@ impl error::Error for Error {
Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type", Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::UserFunctionError(ref err) => err.description(), Error::UserFunctionError(ref err) => err.description(),
Error::ToSqlConversionFailure(ref err) => err.description(),
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
Error::ModuleError(ref desc) => desc, Error::ModuleError(ref desc) => desc,
} }
@ -171,7 +176,6 @@ impl error::Error for Error {
fn cause(&self) -> Option<&error::Error> { fn cause(&self) -> Option<&error::Error> {
match *self { match *self {
Error::SqliteFailure(ref err, _) => Some(err), Error::SqliteFailure(ref err, _) => Some(err),
Error::FromSqlConversionFailure(_, _, ref err) => Some(&**err),
Error::Utf8Error(ref err) => Some(err), Error::Utf8Error(ref err) => Some(err),
Error::NulError(ref err) => Some(err), Error::NulError(ref err) => Some(err),
@ -191,6 +195,9 @@ impl error::Error for Error {
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
Error::UserFunctionError(ref err) => Some(&**err), Error::UserFunctionError(ref err) => Some(&**err),
Error::FromSqlConversionFailure(_, _, ref err) |
Error::ToSqlConversionFailure(ref err) => Some(&**err),
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
Error::ModuleError(_) => None, Error::ModuleError(_) => None,
} }

View File

@ -82,7 +82,7 @@ use cache::StatementCache;
pub use statement::Statement; pub use statement::Statement;
use statement::StatementCrateImpl; use statement::StatementCrateImpl;
pub use row::{Row, Rows, MappedRows, AndThenRows}; pub use row::{Row, Rows, MappedRows, AndThenRows, RowIndex};
use row::RowsCrateImpl; use row::RowsCrateImpl;
#[allow(deprecated)] #[allow(deprecated)]
@ -144,7 +144,7 @@ fn str_to_cstring(s: &str) -> Result<CString> {
} }
fn path_to_cstring(p: &Path) -> Result<CString> { fn path_to_cstring(p: &Path) -> Result<CString> {
let s = try!(p.to_str().ok_or(Error::InvalidPath(p.to_owned()))); let s = try!(p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned())));
str_to_cstring(s) str_to_cstring(s)
} }
@ -187,6 +187,12 @@ pub struct Connection {
unsafe impl Send for Connection {} unsafe impl Send for Connection {}
impl Drop for Connection {
fn drop(&mut self) {
self.flush_prepared_statement_cache();
}
}
impl Connection { impl Connection {
/// Open a new connection to a SQLite database. /// Open a new connection to a SQLite database.
/// ///
@ -590,18 +596,19 @@ bitflags! {
const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY; const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE; const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE; const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
const SQLITE_OPEN_URI = 0x00000040; const SQLITE_OPEN_URI = 0x0000_0040;
const SQLITE_OPEN_MEMORY = 0x00000080; const SQLITE_OPEN_MEMORY = 0x0000_0080;
const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX; const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX; const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
const SQLITE_OPEN_SHARED_CACHE = 0x00020000; const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
const SQLITE_OPEN_PRIVATE_CACHE = 0x00040000; const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
} }
} }
impl Default for OpenFlags { impl Default for OpenFlags {
fn default() -> OpenFlags { fn default() -> OpenFlags {
SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NO_MUTEX | SQLITE_OPEN_URI OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE |
OpenFlags::SQLITE_OPEN_NO_MUTEX | OpenFlags::SQLITE_OPEN_URI
} }
} }
@ -640,7 +647,7 @@ fn ensure_valid_sqlite_version() {
let version_number = version_number(); let version_number = version_number();
// Check our hard floor. // Check our hard floor.
if version_number < 3006008 { if version_number < 3_006_008 {
panic!("rusqlite requires SQLite 3.6.8 or newer"); panic!("rusqlite requires SQLite 3.6.8 or newer");
} }
@ -693,7 +700,7 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> {
// will fail if someone else has already initialized SQLite even if they initialized it // will fail if someone else has already initialized SQLite even if they initialized it
// safely. That's not ideal either, which is why we expose bypass_sqlite_initialization // safely. That's not ideal either, which is why we expose bypass_sqlite_initialization
// above. // above.
if version_number() >= 3007000 { if version_number() >= 3_007_000 {
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8; const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
let is_singlethreaded = unsafe { let is_singlethreaded = unsafe {
let mutex_ptr = ffi::sqlite3_mutex_alloc(0); let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
@ -739,9 +746,9 @@ impl InnerConnection {
// Replicate the check for sane open flags from SQLite, because the check in SQLite itself // Replicate the check for sane open flags from SQLite, because the check in SQLite itself
// wasn't added until version 3.7.3. // wasn't added until version 3.7.3.
debug_assert!(1 << SQLITE_OPEN_READ_ONLY.bits == 0x02); debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_ONLY.bits, 0x02);
debug_assert!(1 << SQLITE_OPEN_READ_WRITE.bits == 0x04); debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits, 0x04);
debug_assert!(1 << (SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE).bits == 0x40); debug_assert_eq!(1 << (OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE).bits, 0x40);
if (1 << (flags.bits & 0x7)) & 0x46 == 0 { if (1 << (flags.bits & 0x7)) & 0x46 == 0 {
return Err(Error::SqliteFailure(ffi::Error::new(ffi::SQLITE_MISUSE), None)); return Err(Error::SqliteFailure(ffi::Error::new(ffi::SQLITE_MISUSE), None));
} }
@ -869,7 +876,15 @@ impl InnerConnection {
impl Drop for InnerConnection { impl Drop for InnerConnection {
#[allow(unused_must_use)] #[allow(unused_must_use)]
fn drop(&mut self) { fn drop(&mut self) {
self.close(); use std::thread::panicking;
if let Err(e) = self.close() {
if panicking() {
eprintln!("Error while closing SQLite connection: {:?}", e);
} else {
panic!("Error while closing SQLite connection: {:?}", e);
}
}
} }
} }
@ -920,7 +935,7 @@ mod test {
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(42); INSERT INTO foo VALUES(42);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
} }
let path_string = path.to_str().unwrap(); let path_string = path.to_str().unwrap();
@ -978,8 +993,8 @@ mod test {
#[test] #[test]
fn test_open_with_flags() { fn test_open_with_flags() {
for bad_flags in &[OpenFlags::empty(), for bad_flags in &[OpenFlags::empty(),
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_READ_WRITE, OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_CREATE] { OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE] {
assert!(Connection::open_in_memory_with_flags(*bad_flags).is_err()); assert!(Connection::open_in_memory_with_flags(*bad_flags).is_err());
} }
} }

View File

@ -30,21 +30,21 @@ impl<'stmt> Rows<'stmt> {
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> { pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
self.stmt self.stmt
.and_then(|stmt| match stmt.step() { .and_then(|stmt| match stmt.step() {
Ok(true) => { Ok(true) => {
Some(Ok(Row { Some(Ok(Row {
stmt: stmt, stmt: stmt,
phantom: PhantomData, phantom: PhantomData,
})) }))
} }
Ok(false) => { Ok(false) => {
self.reset(); self.reset();
None None
} }
Err(err) => { Err(err) => {
self.reset(); self.reset();
Some(Err(err)) Some(Err(err))
} }
}) })
} }
} }

View File

@ -368,7 +368,7 @@ impl<'conn> Statement<'conn> {
} }
fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> { fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> {
assert!(params.len() as c_int == self.stmt.bind_parameter_count(), assert_eq!(params.len() as c_int, self.stmt.bind_parameter_count(),
"incorrect number of parameters to query(): expected {}, got {}", "incorrect number of parameters to query(): expected {}, got {}",
self.stmt.bind_parameter_count(), self.stmt.bind_parameter_count(),
params.len()); params.len());

View File

@ -3,7 +3,7 @@ extern crate chrono;
use std::borrow::Cow; use std::borrow::Cow;
use self::chrono::{NaiveDate, NaiveTime, NaiveDateTime, DateTime, TimeZone, UTC, Local}; use self::chrono::{NaiveDate, NaiveTime, NaiveDateTime, DateTime, TimeZone, Utc, Local};
use Result; use Result;
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
@ -87,12 +87,12 @@ impl FromSql for NaiveDateTime {
/// Date and time with time zone => UTC RFC3339 timestamp ("YYYY-MM-DDTHH:MM:SS.SSS+00:00"). /// Date and time with time zone => UTC RFC3339 timestamp ("YYYY-MM-DDTHH:MM:SS.SSS+00:00").
impl<Tz: TimeZone> ToSql for DateTime<Tz> { impl<Tz: TimeZone> ToSql for DateTime<Tz> {
fn to_sql(&self) -> Result<ToSqlOutput> { fn to_sql(&self) -> Result<ToSqlOutput> {
Ok(ToSqlOutput::from(self.with_timezone(&UTC).to_rfc3339())) Ok(ToSqlOutput::from(self.with_timezone(&Utc).to_rfc3339()))
} }
} }
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<UTC>. /// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into `DateTime<Utc>`.
impl FromSql for DateTime<UTC> { impl FromSql for DateTime<Utc> {
fn column_result(value: ValueRef) -> FromSqlResult<Self> { fn column_result(value: ValueRef) -> FromSqlResult<Self> {
{ {
// Try to parse value as rfc3339 first. // Try to parse value as rfc3339 first.
@ -111,19 +111,19 @@ impl FromSql for DateTime<UTC> {
}; };
if let Ok(dt) = DateTime::parse_from_rfc3339(&s) { if let Ok(dt) = DateTime::parse_from_rfc3339(&s) {
return Ok(dt.with_timezone(&UTC)); return Ok(dt.with_timezone(&Utc));
} }
} }
// Couldn't parse as rfc3339 - fall back to NaiveDateTime. // Couldn't parse as rfc3339 - fall back to NaiveDateTime.
NaiveDateTime::column_result(value).map(|dt| UTC.from_utc_datetime(&dt)) NaiveDateTime::column_result(value).map(|dt| Utc.from_utc_datetime(&dt))
} }
} }
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<Local>. /// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into `DateTime<Local>`.
impl FromSql for DateTime<Local> { impl FromSql for DateTime<Local> {
fn column_result(value: ValueRef) -> FromSqlResult<Self> { fn column_result(value: ValueRef) -> FromSqlResult<Self> {
let utc_dt = try!(DateTime::<UTC>::column_result(value)); let utc_dt = try!(DateTime::<Utc>::column_result(value));
Ok(utc_dt.with_timezone(&Local)) Ok(utc_dt.with_timezone(&Local))
} }
} }
@ -131,7 +131,7 @@ impl FromSql for DateTime<Local> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use Connection; use Connection;
use super::chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, UTC, use super::chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc,
Duration}; Duration};
fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Connection {
@ -201,7 +201,7 @@ mod test {
let date = NaiveDate::from_ymd(2016, 2, 23); let date = NaiveDate::from_ymd(2016, 2, 23);
let time = NaiveTime::from_hms_milli(23, 56, 4, 789); let time = NaiveTime::from_hms_milli(23, 56, 4, 789);
let dt = NaiveDateTime::new(date, time); let dt = NaiveDateTime::new(date, time);
let utc = UTC.from_utc_datetime(&dt); let utc = Utc.from_utc_datetime(&dt);
db.execute("INSERT INTO foo (t) VALUES (?)", &[&utc]) db.execute("INSERT INTO foo (t) VALUES (?)", &[&utc])
.unwrap(); .unwrap();
@ -210,19 +210,19 @@ mod test {
.unwrap(); .unwrap();
assert_eq!("2016-02-23T23:56:04.789+00:00", s); assert_eq!("2016-02-23T23:56:04.789+00:00", s);
let v1: DateTime<UTC> = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) let v1: DateTime<Utc> = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
.unwrap(); .unwrap();
assert_eq!(utc, v1); assert_eq!(utc, v1);
let v2: DateTime<UTC> = db.query_row("SELECT '2016-02-23 23:56:04.789'", &[], |r| r.get(0)) let v2: DateTime<Utc> = db.query_row("SELECT '2016-02-23 23:56:04.789'", &[], |r| r.get(0))
.unwrap(); .unwrap();
assert_eq!(utc, v2); assert_eq!(utc, v2);
let v3: DateTime<UTC> = db.query_row("SELECT '2016-02-23 23:56:04'", &[], |r| r.get(0)) let v3: DateTime<Utc> = db.query_row("SELECT '2016-02-23 23:56:04'", &[], |r| r.get(0))
.unwrap(); .unwrap();
assert_eq!(utc - Duration::milliseconds(789), v3); assert_eq!(utc - Duration::milliseconds(789), v3);
let v4: DateTime<UTC> = let v4: DateTime<Utc> =
db.query_row("SELECT '2016-02-23 23:56:04.789+00:00'", &[], |r| r.get(0)) db.query_row("SELECT '2016-02-23 23:56:04.789+00:00'", &[], |r| r.get(0))
.unwrap(); .unwrap();
assert_eq!(utc, v4); assert_eq!(utc, v4);

View File

@ -61,12 +61,24 @@ pub trait FromSql: Sized {
fn column_result(value: ValueRef) -> FromSqlResult<Self>; fn column_result(value: ValueRef) -> FromSqlResult<Self>;
} }
impl FromSql for isize {
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
i64::column_result(value).and_then(|i| {
if i < isize::min_value() as i64 || i > isize::max_value() as i64 {
Err(FromSqlError::OutOfRange(i))
} else {
Ok(i as isize)
}
})
}
}
macro_rules! from_sql_integral( macro_rules! from_sql_integral(
($t:ident) => ( ($t:ident) => (
impl FromSql for $t { impl FromSql for $t {
fn column_result(value: ValueRef) -> FromSqlResult<Self> { fn column_result(value: ValueRef) -> FromSqlResult<Self> {
i64::column_result(value).and_then(|i| { i64::column_result(value).and_then(|i| {
if i < $t::min_value() as i64 || i > $t::max_value() as i64 { if i < i64::from($t::min_value()) || i > i64::from($t::max_value()) {
Err(FromSqlError::OutOfRange(i)) Err(FromSqlError::OutOfRange(i))
} else { } else {
Ok(i as $t) Ok(i as $t)
@ -80,7 +92,6 @@ macro_rules! from_sql_integral(
from_sql_integral!(i8); from_sql_integral!(i8);
from_sql_integral!(i16); from_sql_integral!(i16);
from_sql_integral!(i32); from_sql_integral!(i32);
from_sql_integral!(isize);
from_sql_integral!(u8); from_sql_integral!(u8);
from_sql_integral!(u16); from_sql_integral!(u16);
from_sql_integral!(u32); from_sql_integral!(u32);

View File

@ -3,7 +3,7 @@ extern crate time;
use Result; use Result;
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S"; const SQLITE_DATETIME_FMT: &str = "%Y-%m-%d %H:%M:%S:%f %Z";
impl ToSql for time::Timespec { impl ToSql for time::Timespec {
fn to_sql(&self) -> Result<ToSqlOutput> { fn to_sql(&self) -> Result<ToSqlOutput> {
@ -42,15 +42,27 @@ mod test {
fn test_timespec() { fn test_timespec() {
let db = checked_memory_handle(); let db = checked_memory_handle();
let ts = time::Timespec { let mut ts_vec = vec![];
sec: 10_000,
nsec: 0, ts_vec.push(time::Timespec::new(10_000, 0));//January 1, 1970 2:46:40 AM
}; ts_vec.push(time::Timespec::new(10_000, 1000));//January 1, 1970 2:46:40 AM (and one microsecond)
db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]) ts_vec.push(time::Timespec::new(1500391124, 1_000_000));//July 18, 2017
.unwrap(); ts_vec.push(time::Timespec::new(2000000000, 2_000_000));//May 18, 2033
ts_vec.push(time::Timespec::new(3000000000, 999_999_999));//January 24, 2065
ts_vec.push(time::Timespec::new(10000000000, 0));//November 20, 2286
for ts in ts_vec {
db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts])
.unwrap();
let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
.unwrap();
db.execute("DELETE FROM foo", &[]).unwrap();
assert_eq!(from, ts);
}
let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
.unwrap();
assert_eq!(from, ts);
} }
} }

View File

@ -84,7 +84,7 @@ impl<'a, T: ?Sized> ToSql for &'a T
where &'a T: Into<ToSqlOutput<'a>> where &'a T: Into<ToSqlOutput<'a>>
{ {
fn to_sql(&self) -> Result<ToSqlOutput> { fn to_sql(&self) -> Result<ToSqlOutput> {
Ok(ToSqlOutput::from((*self).into())) Ok((*self).into())
} }
} }

View File

@ -30,11 +30,15 @@ impl From<bool> for Value {
} }
} }
impl From<isize> for Value {
fn from(i: isize) -> Value { Value::Integer(i as i64) }
}
macro_rules! from_i64( macro_rules! from_i64(
($t:ty) => ( ($t:ty) => (
impl From<$t> for Value { impl From<$t> for Value {
fn from(i: $t) -> Value { fn from(i: $t) -> Value {
Value::Integer(i as i64) Value::Integer(i64::from(i))
} }
} }
) )
@ -43,7 +47,6 @@ macro_rules! from_i64(
from_i64!(i8); from_i64!(i8);
from_i64!(i16); from_i64!(i16);
from_i64!(i32); from_i64!(i32);
from_i64!(isize);
from_i64!(u8); from_i64!(u8);
from_i64!(u16); from_i64!(u16);
from_i64!(u32); from_i64!(u32);

View File

@ -3,14 +3,14 @@ use std::ffi::CStr;
/// Returns the SQLite version as an integer; e.g., `3016002` for version 3.16.2. /// Returns the SQLite version as an integer; e.g., `3016002` for version 3.16.2.
/// ///
/// See [sqlite3_libversion_number()](https://www.sqlite.org/c3ref/libversion.html). /// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html).
pub fn version_number() -> i32 { pub fn version_number() -> i32 {
unsafe { ffi::sqlite3_libversion_number() } unsafe { ffi::sqlite3_libversion_number() }
} }
/// Returns the SQLite version as a string; e.g., `"3.16.2"` for version 3.16.2. /// Returns the SQLite version as a string; e.g., `"3.16.2"` for version 3.16.2.
/// ///
/// See [sqlite3_libversion()](https://www.sqlite.org/c3ref/libversion.html). /// See [`sqlite3_libversion()`](https://www.sqlite.org/c3ref/libversion.html).
pub fn version() -> &'static str { pub fn version() -> &'static str {
let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) }; let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) };
cstr.to_str() cstr.to_str()

View File

@ -1,4 +1,4 @@
//! This file contains unit tests for rusqlite::trace::config_log. This function affects //! This file contains unit tests for `rusqlite::trace::config_log`. This function affects
//! SQLite process-wide and so is not safe to run as a normal #[test] in the library. //! SQLite process-wide and so is not safe to run as a normal #[test] in the library.
#[cfg(feature = "trace")] #[cfg(feature = "trace")]