diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a9c1e9e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +libsqlite3-sys/sqlite3 linguist-vendored diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 81870c9..078ec47 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -18,3 +18,7 @@ rusqlite contributors * [Omar Ferrer](https://github.com/chamakits) * [Lee Jenkins](https://github.com/reddraggone9) * [miedzinski](https://github.com/miedzinski) +* [aidanhs](https://github.com/aidanhs) +* [Steven Fackler](https://github.com/sfackler) +* [Davide Aversa](https://github.com/THeK3nger) +* [mcgoo](https://github.com/mcgoo) diff --git a/Cargo.toml b/Cargo.toml index ebc2bac..b92b45a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusqlite" -version = "0.11.0" +version = "0.12.0" authors = ["John Gallagher "] description = "Ergonomic wrapper for SQLite" repository = "https://github.com/jgallagher/rusqlite" @@ -30,11 +30,11 @@ vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7"] csvtab = ["csv"] [dependencies] -time = "0.1" -bitflags = "0.7" +time = "0.1.0" +bitflags = "0.9" lru-cache = "0.1" chrono = { version = "0.3", optional = true } -serde_json = { version = "0.9", optional = true } +serde_json = { version = "1.0", optional = true } [dev-dependencies] tempdir = "0.3" diff --git a/Changelog.md b/Changelog.md index cca0d8f..712d67e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,10 @@ +# Version 0.12.0 (2017-05-29) + +* Defines HAVE\_USLEEP when building with a bundled SQLite (#263). +* Updates dependencies to their latest versions, particularly serde to 1.0. +* Adds support for vcpkg on Windows. +* Adds `ToSql` impls for `str` and `[u8]`. + # Version 0.11.0 (2017-04-06) * Avoid publicly exporting SQLite constants multiple times from libsqlite3-sys. diff --git a/README.md b/README.md index a4d155f..67bb467 100644 --- a/README.md +++ b/README.md @@ -94,17 +94,27 @@ features](http://doc.crates.io/manifest.html#the-features-section). They are: ## 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 use -pkg-config to find a SQLite library that already exists on your system. You can -adjust this behavior in a couple of ways: +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](https://github.com/Microsoft/vcpkg) installation for MSVC ABI builds. + +You can adjust this behavior in a number of ways: * If you use the `bundled` feature, `libsqlite3-sys` will use the [gcc](https://crates.io/crates/gcc) crate to compile SQLite from source and link against that. This source is embedded in the `libsqlite3-sys` crate and is currently SQLite 3.17.0 (as of `rusqlite` 0.10.1 / `libsqlite3-sys` - 0.7.1). This is probably the simplest solution to any build problems. + 0.7.1). 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.11.0" + features = ["bundled"] + ``` * You can set the `SQLITE3_LIB_DIR` to point to directory containing the SQLite library. +* Installing the sqlite3 development packages will usually be all that is required, but + the build helpers for [pkg-config](https://github.com/alexcrichton/pkg-config-rs) + and [vcpkg](https://github.com/mcgoo/vcpkg-rs) have some additional configuration + options. The default when using vcpkg is to dynamically link. `vcpkg install sqlite3:x64-windows` will install the required library. ### Binding generation diff --git a/appveyor.yml b/appveyor.yml index 3a9c09c..8b2bffa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,12 @@ environment: - TARGET: 1.15.0-x86_64-pc-windows-gnu - MSYS2_BITS: 64 + matrix: + - TARGET: 1.15.0-x86_64-pc-windows-gnu + MSYS2_BITS: 64 + - TARGET: 1.15.0-x86_64-pc-windows-msvc + VCPKG_DEFAULT_TRIPLET: x64-windows + - TARGET: nightly-x86_64-pc-windows-msvc + VCPKG_DEFAULT_TRIPLET: x64-windows-static + RUSTFLAGS: -Ctarget-feature=+crt-static install: - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" - rust-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" @@ -9,11 +15,18 @@ install: - rustc -V - cargo -V - ps: Start-FileDownload 'https://sqlite.org/2017/sqlite-dll-win64-x64-3170000.zip' # download SQLite dll (useful only when the `bundled` feature is not set) - - cmd: 7z e sqlite-dll-win64-x64-3170000.zip -y > nul + - if not defined VCPKG_DEFAULT_TRIPLET 7z e sqlite-dll-win64-x64-3170000.zip -y > nul - ps: Start-FileDownload 'https://sqlite.org/2017/sqlite-amalgamation-3170000.zip' # download SQLite headers (useful only when the `bundled` feature is not set) - - cmd: 7z e sqlite-amalgamation-3170000.zip -y > nul - - SET SQLITE3_LIB_DIR=%APPVEYOR_BUILD_FOLDER% # specify where the SQLite dll has been downloaded (useful only when the `bundled` feature is not set) - - SET SQLITE3_INCLUDE_DIR=%APPVEYOR_BUILD_FOLDER% # specify where the SQLite headers have been downloaded (useful only when the `bundled` feature is not set) + - if not defined VCPKG_DEFAULT_TRIPLET 7z e sqlite-amalgamation-3170000.zip -y > nul + - if not defined VCPKG_DEFAULT_TRIPLET SET SQLITE3_LIB_DIR=%APPVEYOR_BUILD_FOLDER% # specify where the SQLite dll has been downloaded (useful only when the `bundled` feature is not set) + - if not defined VCPKG_DEFAULT_TRIPLET SET SQLITE3_INCLUDE_DIR=%APPVEYOR_BUILD_FOLDER% # specify where the SQLite headers have been downloaded (useful only when the `bundled` feature is not set) + # install vcpkg and the sqlite3 package + - if defined VCPKG_DEFAULT_TRIPLET git clone https://github.com/Microsoft/vcpkg c:\projects\vcpkg + - if defined VCPKG_DEFAULT_TRIPLET c:\projects\vcpkg\bootstrap-vcpkg.bat + - if defined VCPKG_DEFAULT_TRIPLET set VCPKG_ROOT=c:\projects\vcpkg + - if defined VCPKG_DEFAULT_TRIPLET %VCPKG_ROOT%\vcpkg.exe install sqlite3 + - if defined VCPKG_DEFAULT_TRIPLET appveyor DownloadFile http://releases.llvm.org/4.0.0/LLVM-4.0.0-win64.exe + - if defined VCPKG_DEFAULT_TRIPLET LLVM-4.0.0-win64.exe /S build: false diff --git a/libsqlite3-sys/Cargo.toml b/libsqlite3-sys/Cargo.toml index e56b66e..0ef7b05 100644 --- a/libsqlite3-sys/Cargo.toml +++ b/libsqlite3-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libsqlite3-sys" -version = "0.8.0" +version = "0.8.1" authors = ["John Gallagher "] repository = "https://github.com/jgallagher/rusqlite" description = "Native bindings to the libsqlite3 library" @@ -13,16 +13,19 @@ categories = ["database", "external-ffi-bindings"] [features] default = ["min_sqlite_version_3_6_8"] bundled = ["gcc"] -buildtime_bindgen = ["bindgen", "pkg-config"] -min_sqlite_version_3_6_8 = ["pkg-config"] -min_sqlite_version_3_6_11 = ["pkg-config"] -min_sqlite_version_3_6_23 = ["pkg-config"] -min_sqlite_version_3_7_3 = ["pkg-config"] -min_sqlite_version_3_7_4 = ["pkg-config"] -min_sqlite_version_3_7_7 = ["pkg-config"] -min_sqlite_version_3_7_16 = ["pkg-config"] +buildtime_bindgen = ["bindgen", "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_23 = ["pkg-config", "vcpkg"] +min_sqlite_version_3_7_3 = ["pkg-config", "vcpkg"] +min_sqlite_version_3_7_4 = ["pkg-config", "vcpkg"] +min_sqlite_version_3_7_7 = ["pkg-config", "vcpkg"] +min_sqlite_version_3_7_16 = ["pkg-config", "vcpkg"] [build-dependencies] -bindgen = { version = "0.21", optional = true } +bindgen = { version = "0.23", optional = true } pkg-config = { version = "0.3", optional = true } gcc = { version = "0.3", optional = true } + +[target.'cfg(target_env = "msvc")'.build-dependencies] +vcpkg = { version = "0.2", optional = true } diff --git a/libsqlite3-sys/build.rs b/libsqlite3-sys/build.rs index 4d622a0..b85d8c9 100644 --- a/libsqlite3-sys/build.rs +++ b/libsqlite3-sys/build.rs @@ -34,6 +34,7 @@ mod build { .flag("-DSQLITE_SOUNDEX") .flag("-DSQLITE_THREADSAFE=1") .flag("-DSQLITE_USE_URI") + .flag("-DHAVE_USLEEP=1") .compile("libsqlite3.a"); } } @@ -42,6 +43,9 @@ mod build { mod build { extern crate pkg_config; + #[cfg(all(feature = "vcpkg", target_env = "msvc"))] + extern crate vcpkg; + use std::env; pub enum HeaderLocation { @@ -79,6 +83,10 @@ mod build { return HeaderLocation::FromEnvironment; } + if let Some(header) = try_vcpkg() { + return header; + } + // See if pkg-config can do everything for us. match pkg_config::Config::new().print_system_libs(false).probe("sqlite3") { Ok(mut lib) => { @@ -100,6 +108,23 @@ mod build { } } + #[cfg(all(feature = "vcpkg", target_env = "msvc"))] + fn try_vcpkg() -> Option { + // See if vcpkg can find it. + if let Ok(mut lib) = vcpkg::Config::new().probe("sqlite3") { + if let Some(mut header) = lib.include_paths.pop() { + header.push("sqlite3.h"); + return Some(HeaderLocation::FromPath(header.to_string_lossy().into())); + } + } + None + } + + #[cfg(not(all(feature = "vcpkg", target_env = "msvc")))] + fn try_vcpkg() -> Option { + None + } + #[cfg(not(feature = "buildtime_bindgen"))] mod bindings { use super::HeaderLocation; @@ -142,7 +167,7 @@ mod build { mod bindings { extern crate bindgen; - use self::bindgen::chooser::{TypeChooser, IntKind}; + use self::bindgen::callbacks::{ParseCallbacks, IntKind}; use super::HeaderLocation; use std::env; @@ -153,7 +178,7 @@ mod build { #[derive(Debug)] struct SqliteTypeChooser; - impl TypeChooser for SqliteTypeChooser { + impl ParseCallbacks for SqliteTypeChooser { fn int_macro(&self, _name: &str, value: i64) -> Option { if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 { Some(IntKind::I32) @@ -169,7 +194,7 @@ mod build { let mut output = Vec::new(); bindgen::builder() .header(header.clone()) - .type_chooser(Box::new(SqliteTypeChooser)) + .parse_callbacks(Box::new(SqliteTypeChooser)) .generate() .expect(&format!("could not run bindgen on header {}", header)) .write(Box::new(&mut output)) diff --git a/libsqlite3-sys/src/error.rs b/libsqlite3-sys/src/error.rs index 9394e5f..61c80f9 100644 --- a/libsqlite3-sys/src/error.rs +++ b/libsqlite3-sys/src/error.rs @@ -64,29 +64,29 @@ pub struct Error { impl Error { pub fn new(result_code: c_int) -> Error { let code = match result_code & 0xff { - SQLITE_INTERNAL => ErrorCode::InternalMalfunction, - SQLITE_PERM => ErrorCode::PermissionDenied, - SQLITE_ABORT => ErrorCode::OperationAborted, - SQLITE_BUSY => ErrorCode::DatabaseBusy, - SQLITE_LOCKED => ErrorCode::DatabaseLocked, - SQLITE_NOMEM => ErrorCode::OutOfMemory, - SQLITE_READONLY => ErrorCode::ReadOnly, - SQLITE_INTERRUPT => ErrorCode::OperationInterrupted, - SQLITE_IOERR => ErrorCode::SystemIOFailure, - SQLITE_CORRUPT => ErrorCode::DatabaseCorrupt, - SQLITE_NOTFOUND => ErrorCode::NotFound, - SQLITE_FULL => ErrorCode::DiskFull, - SQLITE_CANTOPEN => ErrorCode::CannotOpen, - SQLITE_PROTOCOL => ErrorCode::FileLockingProtocolFailed, - SQLITE_SCHEMA => ErrorCode::SchemaChanged, - SQLITE_TOOBIG => ErrorCode::TooBig, - SQLITE_CONSTRAINT=> ErrorCode::ConstraintViolation, - SQLITE_MISMATCH => ErrorCode::TypeMismatch, - SQLITE_MISUSE => ErrorCode::APIMisuse, - SQLITE_NOLFS => ErrorCode::NoLargeFileSupport, - SQLITE_AUTH => ErrorCode::AuthorizationForStatementDenied, - SQLITE_RANGE => ErrorCode::ParameterOutOfRange, - SQLITE_NOTADB => ErrorCode::NotADatabase, + super::SQLITE_INTERNAL => ErrorCode::InternalMalfunction, + super::SQLITE_PERM => ErrorCode::PermissionDenied, + super::SQLITE_ABORT => ErrorCode::OperationAborted, + super::SQLITE_BUSY => ErrorCode::DatabaseBusy, + super::SQLITE_LOCKED => ErrorCode::DatabaseLocked, + super::SQLITE_NOMEM => ErrorCode::OutOfMemory, + super::SQLITE_READONLY => ErrorCode::ReadOnly, + super::SQLITE_INTERRUPT => ErrorCode::OperationInterrupted, + super::SQLITE_IOERR => ErrorCode::SystemIOFailure, + super::SQLITE_CORRUPT => ErrorCode::DatabaseCorrupt, + super::SQLITE_NOTFOUND => ErrorCode::NotFound, + super::SQLITE_FULL => ErrorCode::DiskFull, + super::SQLITE_CANTOPEN => ErrorCode::CannotOpen, + super::SQLITE_PROTOCOL => ErrorCode::FileLockingProtocolFailed, + super::SQLITE_SCHEMA => ErrorCode::SchemaChanged, + super::SQLITE_TOOBIG => ErrorCode::TooBig, + super::SQLITE_CONSTRAINT=> ErrorCode::ConstraintViolation, + super::SQLITE_MISMATCH => ErrorCode::TypeMismatch, + super::SQLITE_MISUSE => ErrorCode::APIMisuse, + super::SQLITE_NOLFS => ErrorCode::NoLargeFileSupport, + super::SQLITE_AUTH => ErrorCode::AuthorizationForStatementDenied, + super::SQLITE_RANGE => ErrorCode::ParameterOutOfRange, + super::SQLITE_NOTADB => ErrorCode::NotADatabase, _ => ErrorCode::Unknown, }; @@ -114,146 +114,100 @@ impl error::Error for Error { // in the current version of SQLite. We repeat them here so we don't have to worry about which // version of SQLite added which constants, and we only use them to implement code_to_str below. -const SQLITE_OK : c_int = 0; -const SQLITE_ERROR : c_int = 1; -const SQLITE_INTERNAL : c_int = 2; -const SQLITE_PERM : c_int = 3; -const SQLITE_ABORT : c_int = 4; -const SQLITE_BUSY : c_int = 5; -const SQLITE_LOCKED : c_int = 6; -const SQLITE_NOMEM : c_int = 7; -const SQLITE_READONLY : c_int = 8; -const SQLITE_INTERRUPT : c_int = 9; -const SQLITE_IOERR : c_int = 10; -const SQLITE_CORRUPT : c_int = 11; -const SQLITE_NOTFOUND : c_int = 12; -const SQLITE_FULL : c_int = 13; -const SQLITE_CANTOPEN : c_int = 14; -const SQLITE_PROTOCOL : c_int = 15; -const SQLITE_EMPTY : c_int = 16; -const SQLITE_SCHEMA : c_int = 17; -const SQLITE_TOOBIG : c_int = 18; -const SQLITE_CONSTRAINT: c_int = 19; -const SQLITE_MISMATCH : c_int = 20; -const SQLITE_MISUSE : c_int = 21; -const SQLITE_NOLFS : c_int = 22; -const SQLITE_AUTH : c_int = 23; -const SQLITE_FORMAT : c_int = 24; -const SQLITE_RANGE : c_int = 25; -const SQLITE_NOTADB : c_int = 26; const SQLITE_NOTICE : c_int = 27; const SQLITE_WARNING : c_int = 28; -const SQLITE_ROW : c_int = 100; -const SQLITE_DONE : c_int = 101; // Extended result codes. -const SQLITE_IOERR_READ : c_int = (SQLITE_IOERR | (1<<8)); -const SQLITE_IOERR_SHORT_READ : c_int = (SQLITE_IOERR | (2<<8)); -const SQLITE_IOERR_WRITE : c_int = (SQLITE_IOERR | (3<<8)); -const SQLITE_IOERR_FSYNC : c_int = (SQLITE_IOERR | (4<<8)); -const SQLITE_IOERR_DIR_FSYNC : c_int = (SQLITE_IOERR | (5<<8)); -const SQLITE_IOERR_TRUNCATE : c_int = (SQLITE_IOERR | (6<<8)); -const SQLITE_IOERR_FSTAT : c_int = (SQLITE_IOERR | (7<<8)); -const SQLITE_IOERR_UNLOCK : c_int = (SQLITE_IOERR | (8<<8)); -const SQLITE_IOERR_RDLOCK : c_int = (SQLITE_IOERR | (9<<8)); -const SQLITE_IOERR_DELETE : c_int = (SQLITE_IOERR | (10<<8)); -const SQLITE_IOERR_BLOCKED : c_int = (SQLITE_IOERR | (11<<8)); -const SQLITE_IOERR_NOMEM : c_int = (SQLITE_IOERR | (12<<8)); -const SQLITE_IOERR_ACCESS : c_int = (SQLITE_IOERR | (13<<8)); -const SQLITE_IOERR_CHECKRESERVEDLOCK : c_int = (SQLITE_IOERR | (14<<8)); -const SQLITE_IOERR_LOCK : c_int = (SQLITE_IOERR | (15<<8)); -const SQLITE_IOERR_CLOSE : c_int = (SQLITE_IOERR | (16<<8)); -const SQLITE_IOERR_DIR_CLOSE : c_int = (SQLITE_IOERR | (17<<8)); -const SQLITE_IOERR_SHMOPEN : c_int = (SQLITE_IOERR | (18<<8)); -const SQLITE_IOERR_SHMSIZE : c_int = (SQLITE_IOERR | (19<<8)); -const SQLITE_IOERR_SHMLOCK : c_int = (SQLITE_IOERR | (20<<8)); -const SQLITE_IOERR_SHMMAP : c_int = (SQLITE_IOERR | (21<<8)); -const SQLITE_IOERR_SEEK : c_int = (SQLITE_IOERR | (22<<8)); -const SQLITE_IOERR_DELETE_NOENT : c_int = (SQLITE_IOERR | (23<<8)); -const SQLITE_IOERR_MMAP : c_int = (SQLITE_IOERR | (24<<8)); -const SQLITE_IOERR_GETTEMPPATH : c_int = (SQLITE_IOERR | (25<<8)); -const SQLITE_IOERR_CONVPATH : c_int = (SQLITE_IOERR | (26<<8)); -const SQLITE_IOERR_VNODE : c_int = (SQLITE_IOERR | (27<<8)); -const SQLITE_LOCKED_SHAREDCACHE : c_int = (SQLITE_LOCKED | (1<<8)); -const SQLITE_BUSY_RECOVERY : c_int = (SQLITE_BUSY | (1<<8)); -const SQLITE_BUSY_SNAPSHOT : c_int = (SQLITE_BUSY | (2<<8)); -const SQLITE_CANTOPEN_NOTEMPDIR : c_int = (SQLITE_CANTOPEN | (1<<8)); -const SQLITE_CANTOPEN_ISDIR : c_int = (SQLITE_CANTOPEN | (2<<8)); -const SQLITE_CANTOPEN_FULLPATH : c_int = (SQLITE_CANTOPEN | (3<<8)); -const SQLITE_CANTOPEN_CONVPATH : c_int = (SQLITE_CANTOPEN | (4<<8)); -const SQLITE_CORRUPT_VTAB : c_int = (SQLITE_CORRUPT | (1<<8)); -const SQLITE_READONLY_RECOVERY : c_int = (SQLITE_READONLY | (1<<8)); -const SQLITE_READONLY_CANTLOCK : c_int = (SQLITE_READONLY | (2<<8)); -const SQLITE_READONLY_ROLLBACK : c_int = (SQLITE_READONLY | (3<<8)); -const SQLITE_READONLY_DBMOVED : c_int = (SQLITE_READONLY | (4<<8)); -const SQLITE_ABORT_ROLLBACK : c_int = (SQLITE_ABORT | (2<<8)); -const SQLITE_CONSTRAINT_CHECK : c_int = (SQLITE_CONSTRAINT | (1<<8)); -const SQLITE_CONSTRAINT_COMMITHOOK : c_int = (SQLITE_CONSTRAINT | (2<<8)); -const SQLITE_CONSTRAINT_FOREIGNKEY : c_int = (SQLITE_CONSTRAINT | (3<<8)); -const SQLITE_CONSTRAINT_FUNCTION : c_int = (SQLITE_CONSTRAINT | (4<<8)); -const SQLITE_CONSTRAINT_NOTNULL : c_int = (SQLITE_CONSTRAINT | (5<<8)); -const SQLITE_CONSTRAINT_PRIMARYKEY : c_int = (SQLITE_CONSTRAINT | (6<<8)); -const SQLITE_CONSTRAINT_TRIGGER : c_int = (SQLITE_CONSTRAINT | (7<<8)); -const SQLITE_CONSTRAINT_UNIQUE : c_int = (SQLITE_CONSTRAINT | (8<<8)); -const SQLITE_CONSTRAINT_VTAB : c_int = (SQLITE_CONSTRAINT | (9<<8)); -const SQLITE_CONSTRAINT_ROWID : c_int = (SQLITE_CONSTRAINT |(10<<8)); +const SQLITE_IOERR_SHMOPEN : c_int = (super::SQLITE_IOERR | (18<<8)); +const SQLITE_IOERR_SHMSIZE : c_int = (super::SQLITE_IOERR | (19<<8)); +const SQLITE_IOERR_SHMLOCK : c_int = (super::SQLITE_IOERR | (20<<8)); +const SQLITE_IOERR_SHMMAP : c_int = (super::SQLITE_IOERR | (21<<8)); +const SQLITE_IOERR_SEEK : c_int = (super::SQLITE_IOERR | (22<<8)); +const SQLITE_IOERR_DELETE_NOENT : c_int = (super::SQLITE_IOERR | (23<<8)); +const SQLITE_IOERR_MMAP : c_int = (super::SQLITE_IOERR | (24<<8)); +const SQLITE_IOERR_GETTEMPPATH : c_int = (super::SQLITE_IOERR | (25<<8)); +const SQLITE_IOERR_CONVPATH : c_int = (super::SQLITE_IOERR | (26<<8)); +const SQLITE_IOERR_VNODE : c_int = (super::SQLITE_IOERR | (27<<8)); +const SQLITE_LOCKED_SHAREDCACHE : c_int = (super::SQLITE_LOCKED | (1<<8)); +const SQLITE_BUSY_RECOVERY : c_int = (super::SQLITE_BUSY | (1<<8)); +const SQLITE_BUSY_SNAPSHOT : c_int = (super::SQLITE_BUSY | (2<<8)); +const SQLITE_CANTOPEN_NOTEMPDIR : c_int = (super::SQLITE_CANTOPEN | (1<<8)); +const SQLITE_CANTOPEN_ISDIR : c_int = (super::SQLITE_CANTOPEN | (2<<8)); +const SQLITE_CANTOPEN_FULLPATH : c_int = (super::SQLITE_CANTOPEN | (3<<8)); +const SQLITE_CANTOPEN_CONVPATH : c_int = (super::SQLITE_CANTOPEN | (4<<8)); +const SQLITE_CORRUPT_VTAB : c_int = (super::SQLITE_CORRUPT | (1<<8)); +const SQLITE_READONLY_RECOVERY : c_int = (super::SQLITE_READONLY | (1<<8)); +const SQLITE_READONLY_CANTLOCK : c_int = (super::SQLITE_READONLY | (2<<8)); +const SQLITE_READONLY_ROLLBACK : c_int = (super::SQLITE_READONLY | (3<<8)); +const SQLITE_READONLY_DBMOVED : c_int = (super::SQLITE_READONLY | (4<<8)); +const SQLITE_ABORT_ROLLBACK : c_int = (super::SQLITE_ABORT | (2<<8)); +const SQLITE_CONSTRAINT_CHECK : c_int = (super::SQLITE_CONSTRAINT | (1<<8)); +const SQLITE_CONSTRAINT_COMMITHOOK : c_int = (super::SQLITE_CONSTRAINT | (2<<8)); +const SQLITE_CONSTRAINT_FOREIGNKEY : c_int = (super::SQLITE_CONSTRAINT | (3<<8)); +const SQLITE_CONSTRAINT_FUNCTION : c_int = (super::SQLITE_CONSTRAINT | (4<<8)); +const SQLITE_CONSTRAINT_NOTNULL : c_int = (super::SQLITE_CONSTRAINT | (5<<8)); +const SQLITE_CONSTRAINT_PRIMARYKEY : c_int = (super::SQLITE_CONSTRAINT | (6<<8)); +const SQLITE_CONSTRAINT_TRIGGER : c_int = (super::SQLITE_CONSTRAINT | (7<<8)); +const SQLITE_CONSTRAINT_UNIQUE : c_int = (super::SQLITE_CONSTRAINT | (8<<8)); +const SQLITE_CONSTRAINT_VTAB : c_int = (super::SQLITE_CONSTRAINT | (9<<8)); +const SQLITE_CONSTRAINT_ROWID : c_int = (super::SQLITE_CONSTRAINT |(10<<8)); const SQLITE_NOTICE_RECOVER_WAL : c_int = (SQLITE_NOTICE | (1<<8)); const SQLITE_NOTICE_RECOVER_ROLLBACK : c_int = (SQLITE_NOTICE | (2<<8)); const SQLITE_WARNING_AUTOINDEX : c_int = (SQLITE_WARNING | (1<<8)); -const SQLITE_AUTH_USER : c_int = (SQLITE_AUTH | (1<<8)); +const SQLITE_AUTH_USER : c_int = (super::SQLITE_AUTH | (1<<8)); pub fn code_to_str(code: c_int) -> &'static str { match code { - SQLITE_OK => "Successful result", - SQLITE_ERROR => "SQL error or missing database", - SQLITE_INTERNAL => "Internal logic error in SQLite", - SQLITE_PERM => "Access permission denied", - SQLITE_ABORT => "Callback routine requested an abort", - SQLITE_BUSY => "The database file is locked", - SQLITE_LOCKED => "A table in the database is locked", - SQLITE_NOMEM => "A malloc() failed", - SQLITE_READONLY => "Attempt to write a readonly database", - SQLITE_INTERRUPT => "Operation terminated by sqlite3_interrupt()", - SQLITE_IOERR => "Some kind of disk I/O error occurred", - SQLITE_CORRUPT => "The database disk image is malformed", - SQLITE_NOTFOUND => "Unknown opcode in sqlite3_file_control()", - SQLITE_FULL => "Insertion failed because database is full", - SQLITE_CANTOPEN => "Unable to open the database file", - SQLITE_PROTOCOL => "Database lock protocol error", - SQLITE_EMPTY => "Database is empty", - SQLITE_SCHEMA => "The database schema changed", - SQLITE_TOOBIG => "String or BLOB exceeds size limit", - SQLITE_CONSTRAINT=> "Abort due to constraint violation", - SQLITE_MISMATCH => "Data type mismatch", - SQLITE_MISUSE => "Library used incorrectly", - SQLITE_NOLFS => "Uses OS features not supported on host", - SQLITE_AUTH => "Authorization denied", - SQLITE_FORMAT => "Auxiliary database format error", - SQLITE_RANGE => "2nd parameter to sqlite3_bind out of range", - SQLITE_NOTADB => "File opened that is not a database file", + super::SQLITE_OK => "Successful result", + super::SQLITE_ERROR => "SQL error or missing database", + super::SQLITE_INTERNAL => "Internal logic error in SQLite", + super::SQLITE_PERM => "Access permission denied", + super::SQLITE_ABORT => "Callback routine requested an abort", + super::SQLITE_BUSY => "The database file is locked", + super::SQLITE_LOCKED => "A table in the database is locked", + super::SQLITE_NOMEM => "A malloc() failed", + super::SQLITE_READONLY => "Attempt to write a readonly database", + super::SQLITE_INTERRUPT => "Operation terminated by sqlite3_interrupt()", + super::SQLITE_IOERR => "Some kind of disk I/O error occurred", + super::SQLITE_CORRUPT => "The database disk image is malformed", + super::SQLITE_NOTFOUND => "Unknown opcode in sqlite3_file_control()", + super::SQLITE_FULL => "Insertion failed because database is full", + super::SQLITE_CANTOPEN => "Unable to open the database file", + super::SQLITE_PROTOCOL => "Database lock protocol error", + super::SQLITE_EMPTY => "Database is empty", + super::SQLITE_SCHEMA => "The database schema changed", + super::SQLITE_TOOBIG => "String or BLOB exceeds size limit", + super::SQLITE_CONSTRAINT=> "Abort due to constraint violation", + super::SQLITE_MISMATCH => "Data type mismatch", + super::SQLITE_MISUSE => "Library used incorrectly", + super::SQLITE_NOLFS => "Uses OS features not supported on host", + super::SQLITE_AUTH => "Authorization denied", + super::SQLITE_FORMAT => "Auxiliary database format error", + super::SQLITE_RANGE => "2nd parameter to sqlite3_bind out of range", + super::SQLITE_NOTADB => "File opened that is not a database file", SQLITE_NOTICE => "Notifications from sqlite3_log()", SQLITE_WARNING => "Warnings from sqlite3_log()", - SQLITE_ROW => "sqlite3_step() has another row ready", - SQLITE_DONE => "sqlite3_step() has finished executing", + super::SQLITE_ROW => "sqlite3_step() has another row ready", + super::SQLITE_DONE => "sqlite3_step() has finished executing", - SQLITE_IOERR_READ => "Error reading from disk", - SQLITE_IOERR_SHORT_READ => "Unable to obtain number of requested bytes (file truncated?)", - SQLITE_IOERR_WRITE => "Error writing to disk", - SQLITE_IOERR_FSYNC => "Error flushing data to persistent storage (fsync)", - SQLITE_IOERR_DIR_FSYNC => "Error calling fsync on a directory", - SQLITE_IOERR_TRUNCATE => "Error attempting to truncate file", - SQLITE_IOERR_FSTAT => "Error invoking fstat to get file metadata", - SQLITE_IOERR_UNLOCK => "I/O error within xUnlock of a VFS object", - SQLITE_IOERR_RDLOCK => "I/O error within xLock of a VFS object (trying to obtain a read lock)", - SQLITE_IOERR_DELETE => "I/O error within xDelete of a VFS object", - SQLITE_IOERR_BLOCKED => "SQLITE_IOERR_BLOCKED", // no longer used - SQLITE_IOERR_NOMEM => "Out of memory in I/O layer", - SQLITE_IOERR_ACCESS => "I/O error within xAccess of a VFS object", - SQLITE_IOERR_CHECKRESERVEDLOCK => "I/O error within then xCheckReservedLock method", - SQLITE_IOERR_LOCK => "I/O error in the advisory file locking layer", - SQLITE_IOERR_CLOSE => "I/O error within the xClose method", - SQLITE_IOERR_DIR_CLOSE => "SQLITE_IOERR_DIR_CLOSE", // no longer used + super::SQLITE_IOERR_READ => "Error reading from disk", + super::SQLITE_IOERR_SHORT_READ => "Unable to obtain number of requested bytes (file truncated?)", + super::SQLITE_IOERR_WRITE => "Error writing to disk", + super::SQLITE_IOERR_FSYNC => "Error flushing data to persistent storage (fsync)", + super::SQLITE_IOERR_DIR_FSYNC => "Error calling fsync on a directory", + super::SQLITE_IOERR_TRUNCATE => "Error attempting to truncate file", + super::SQLITE_IOERR_FSTAT => "Error invoking fstat to get file metadata", + super::SQLITE_IOERR_UNLOCK => "I/O error within xUnlock of a VFS object", + super::SQLITE_IOERR_RDLOCK => "I/O error within xLock of a VFS object (trying to obtain a read lock)", + super::SQLITE_IOERR_DELETE => "I/O error within xDelete of a VFS object", + super::SQLITE_IOERR_BLOCKED => "SQLITE_IOERR_BLOCKED", // no longer used + super::SQLITE_IOERR_NOMEM => "Out of memory in I/O layer", + super::SQLITE_IOERR_ACCESS => "I/O error within xAccess of a VFS object", + super::SQLITE_IOERR_CHECKRESERVEDLOCK => "I/O error within then xCheckReservedLock method", + super::SQLITE_IOERR_LOCK => "I/O error in the advisory file locking layer", + super::SQLITE_IOERR_CLOSE => "I/O error within the xClose method", + super::SQLITE_IOERR_DIR_CLOSE => "SQLITE_IOERR_DIR_CLOSE", // no longer used SQLITE_IOERR_SHMOPEN => "I/O error within the xShmMap method (trying to open a new shared-memory segment)", SQLITE_IOERR_SHMSIZE => "I/O error within the xShmMap method (trying to resize an existing shared-memory segment)", SQLITE_IOERR_SHMLOCK => "SQLITE_IOERR_SHMLOCK", // no longer used diff --git a/libsqlite3-sys/src/lib.rs b/libsqlite3-sys/src/lib.rs index afd453d..e0d9b62 100644 --- a/libsqlite3-sys/src/lib.rs +++ b/libsqlite3-sys/src/lib.rs @@ -19,26 +19,26 @@ pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type { #[repr(C)] pub enum Limit { /// The maximum size of any string or BLOB or table row, in bytes. - SQLITE_LIMIT_LENGTH = 0, + SQLITE_LIMIT_LENGTH = SQLITE_LIMIT_LENGTH as isize, /// The maximum length of an SQL statement, in bytes. - SQLITE_LIMIT_SQL_LENGTH = 1, + SQLITE_LIMIT_SQL_LENGTH = SQLITE_LIMIT_SQL_LENGTH as isize, /// The maximum number of columns in a table definition or in the result set of a SELECT /// or the maximum number of columns in an index or in an ORDER BY or GROUP BY clause. - SQLITE_LIMIT_COLUMN = 2, + SQLITE_LIMIT_COLUMN = SQLITE_LIMIT_COLUMN as isize, /// The maximum depth of the parse tree on any expression. - SQLITE_LIMIT_EXPR_DEPTH = 3, + SQLITE_LIMIT_EXPR_DEPTH = SQLITE_LIMIT_EXPR_DEPTH as isize, /// The maximum number of terms in a compound SELECT statement. - SQLITE_LIMIT_COMPOUND_SELECT = 4, + SQLITE_LIMIT_COMPOUND_SELECT = SQLITE_LIMIT_COMPOUND_SELECT as isize, /// The maximum number of instructions in a virtual machine program used to implement an SQL statement. - SQLITE_LIMIT_VDBE_OP = 5, + SQLITE_LIMIT_VDBE_OP = SQLITE_LIMIT_VDBE_OP as isize, /// The maximum number of arguments on a function. - SQLITE_LIMIT_FUNCTION_ARG = 6, + SQLITE_LIMIT_FUNCTION_ARG = SQLITE_LIMIT_FUNCTION_ARG as isize, /// The maximum number of attached databases. - SQLITE_LIMIT_ATTACHED = 7, + SQLITE_LIMIT_ATTACHED = SQLITE_LIMIT_ATTACHED as isize, /// The maximum length of the pattern argument to the LIKE or GLOB operators. - SQLITE_LIMIT_LIKE_PATTERN_LENGTH = 8, + SQLITE_LIMIT_LIKE_PATTERN_LENGTH = SQLITE_LIMIT_LIKE_PATTERN_LENGTH as isize, /// The maximum index number of any parameter in an SQL statement. - SQLITE_LIMIT_VARIABLE_NUMBER = 9, + SQLITE_LIMIT_VARIABLE_NUMBER = SQLITE_LIMIT_VARIABLE_NUMBER as isize, /// The maximum depth of recursion for triggers. SQLITE_LIMIT_TRIGGER_DEPTH = 10, /// The maximum number of auxiliary worker threads that a single prepared statement may start. diff --git a/src/backup.rs b/src/backup.rs index afa796c..73ed119 100644 --- a/src/backup.rs +++ b/src/backup.rs @@ -206,10 +206,10 @@ impl<'a, 'b> Backup<'a, 'b> { }; Ok(Backup { - phantom_from: PhantomData, - phantom_to: PhantomData, - b: b, - }) + phantom_from: PhantomData, + phantom_to: PhantomData, + b: b, + }) } /// Gets the progress of the backup as of the last call to `step`. diff --git a/src/blob.rs b/src/blob.rs index 4361366..636a3c3 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -92,13 +92,14 @@ impl Connection { if read_only { 0 } else { 1 }, &mut blob) }; - c.decode_result(rc).map(|_| { - Blob { - conn: self, - blob: blob, - pos: 0, - } - }) + c.decode_result(rc) + .map(|_| { + Blob { + conn: self, + blob: blob, + pos: 0, + } + }) } } @@ -159,9 +160,9 @@ impl<'conn> io::Read for Blob<'conn> { self.conn .decode_result(rc) .map(|_| { - self.pos += n; - n as usize - }) + self.pos += n; + n as usize + }) .map_err(|err| io::Error::new(io::ErrorKind::Other, err)) } } @@ -189,9 +190,9 @@ impl<'conn> io::Write for Blob<'conn> { self.conn .decode_result(rc) .map(|_| { - self.pos += n; - n as usize - }) + self.pos += n; + n as usize + }) .map_err(|err| io::Error::new(io::ErrorKind::Other, err)) } @@ -266,7 +267,8 @@ mod test { fn test_blob() { let (db, rowid) = db_with_test_blob().unwrap(); - let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap(); + let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false) + .unwrap(); assert_eq!(4, blob.write(b"Clob").unwrap()); assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10 assert_eq!(0, blob.write(b"5678").unwrap()); // still cannot write past 10 @@ -274,7 +276,8 @@ mod test { blob.reopen(rowid).unwrap(); blob.close().unwrap(); - blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap(); + blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true) + .unwrap(); let mut bytes = [0u8; 5]; assert_eq!(5, blob.read(&mut bytes[..]).unwrap()); assert_eq!(&bytes, b"Clob5"); @@ -314,7 +317,8 @@ mod test { fn test_blob_in_bufreader() { let (db, rowid) = db_with_test_blob().unwrap(); - let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap(); + let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false) + .unwrap(); assert_eq!(8, blob.write(b"one\ntwo\n").unwrap()); blob.reopen(rowid).unwrap(); @@ -338,7 +342,8 @@ mod test { let (db, rowid) = db_with_test_blob().unwrap(); { - let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap(); + let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false) + .unwrap(); let mut writer = BufWriter::new(blob); // trying to write too much and then flush should fail @@ -357,7 +362,8 @@ mod test { } { - let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap(); + let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false) + .unwrap(); let mut writer = BufWriter::new(blob); // trying to write_all too much should fail diff --git a/src/cache.rs b/src/cache.rs index d0cf289..bfafbac 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -280,7 +280,8 @@ mod test { #[test] fn test_connection_close() { let conn = Connection::open_in_memory().unwrap(); - conn.prepare_cached("SELECT * FROM sqlite_master;").unwrap(); + conn.prepare_cached("SELECT * FROM sqlite_master;") + .unwrap(); conn.close().expect("connection not closed"); } diff --git a/src/error.rs b/src/error.rs index 5f9de06..6602e3a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -145,18 +145,14 @@ impl error::Error for Error { match *self { Error::SqliteFailure(ref err, None) => err.description(), Error::SqliteFailure(_, Some(ref s)) => s, - Error::SqliteSingleThreadedMode => { - "SQLite was compiled or configured for single-threaded use only" - } + Error::SqliteSingleThreadedMode => "SQLite was compiled or configured for single-threaded use only", Error::FromSqlConversionFailure(_, _, ref err) => err.description(), Error::IntegralValueOutOfRange(_, _) => "integral value out of range of requested type", Error::Utf8Error(ref err) => err.description(), Error::InvalidParameterName(_) => "invalid parameter name", Error::NulError(ref err) => err.description(), Error::InvalidPath(_) => "invalid path", - Error::ExecuteReturnedResults => { - "execute returned results - did you mean to call query?" - } + Error::ExecuteReturnedResults => "execute returned results - did you mean to call query?", Error::QueryReturnedNoRows => "query returned no rows", Error::InvalidColumnIndex(_) => "invalid column index", Error::InvalidColumnName(_) => "invalid column name", diff --git a/src/functions.rs b/src/functions.rs index 8829091..0167cc4 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -119,9 +119,13 @@ pub unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) { // if we're on the bundled version (since it's at least 3.17.0) and the normal constraint // error code if not. #[cfg(feature = "bundled")] - fn constraint_error_code() -> i32 { ffi::SQLITE_CONSTRAINT_FUNCTION } + fn constraint_error_code() -> i32 { + ffi::SQLITE_CONSTRAINT_FUNCTION + } #[cfg(not(feature = "bundled"))] - fn constraint_error_code() -> i32 { ffi::SQLITE_CONSTRAINT } + fn constraint_error_code() -> i32 { + ffi::SQLITE_CONSTRAINT + } match *err { Error::SqliteFailure(ref err, ref s) => { @@ -154,19 +158,24 @@ impl<'a> ValueRef<'a> { let s = CStr::from_ptr(text as *const c_char); // sqlite3_value_text returns UTF8 data, so our unwrap here should be fine. - let s = s.to_str().expect("sqlite3_value_text returned invalid UTF-8"); + let s = s.to_str() + .expect("sqlite3_value_text returned invalid UTF-8"); ValueRef::Text(s) } ffi::SQLITE_BLOB => { - let blob = ffi::sqlite3_value_blob(value); - assert!(!blob.is_null(), - "unexpected SQLITE_BLOB value type with NULL data"); + let (blob, len) = (ffi::sqlite3_value_blob(value), ffi::sqlite3_value_bytes(value)); - let len = ffi::sqlite3_value_bytes(value); assert!(len >= 0, "unexpected negative return from sqlite3_value_bytes"); - - ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize)) + if len > 0 { + assert!(!blob.is_null(), + "unexpected SQLITE_BLOB value type with NULL data"); + ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize)) + } else { + // The return value from sqlite3_value_blob() for a zero-length BLOB + // is a NULL pointer. + ValueRef::Blob(&[]) + } } _ => unreachable!("sqlite3_value_type returned invalid value"), } @@ -204,14 +213,17 @@ impl<'a> Context<'a> { let arg = self.args[idx]; let value = unsafe { ValueRef::from_value(arg) }; FromSql::column_result(value).map_err(|err| match err { - FromSqlError::InvalidType => { + FromSqlError::InvalidType => { Error::InvalidFunctionParameterType(idx, value.data_type()) } - FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx as c_int, i), - FromSqlError::Other(err) => { + FromSqlError::OutOfRange(i) => { + Error::IntegralValueOutOfRange(idx as c_int, + i) + } + FromSqlError::Other(err) => { Error::FromSqlConversionFailure(idx, value.data_type(), err) } - }) + }) } /// Sets the auxilliary data associated with a particular parameter. See @@ -304,7 +316,9 @@ impl Connection { where F: FnMut(&Context) -> Result, T: ToSql { - self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func) + self.db + .borrow_mut() + .create_scalar_function(fn_name, n_arg, deterministic, x_func) } /// Attach a user-defined aggregate function to this database connection. @@ -720,17 +734,16 @@ mod test { #[test] fn test_sum() { let db = Connection::open_in_memory().unwrap(); - db.create_aggregate_function("my_sum", 1, true, Sum).unwrap(); + db.create_aggregate_function("my_sum", 1, true, Sum) + .unwrap(); // sum should return NULL when given no columns (contrast with count below) let no_result = "SELECT my_sum(i) FROM (SELECT 2 AS i WHERE 1 <> 1)"; - let result: Option = db.query_row(no_result, &[], |r| r.get(0)) - .unwrap(); + let result: Option = db.query_row(no_result, &[], |r| r.get(0)).unwrap(); assert!(result.is_none()); let single_sum = "SELECT my_sum(i) FROM (SELECT 2 AS i UNION ALL SELECT 2)"; - let result: i64 = db.query_row(single_sum, &[], |r| r.get(0)) - .unwrap(); + let result: i64 = db.query_row(single_sum, &[], |r| r.get(0)).unwrap(); assert_eq!(4, result); let dual_sum = "SELECT my_sum(i), my_sum(j) FROM (SELECT 2 AS i, 1 AS j UNION ALL SELECT \ @@ -743,7 +756,8 @@ mod test { #[test] fn test_count() { let db = Connection::open_in_memory().unwrap(); - db.create_aggregate_function("my_count", -1, true, Count).unwrap(); + db.create_aggregate_function("my_count", -1, true, Count) + .unwrap(); // count should return 0 when given no columns (contrast with sum above) let no_result = "SELECT my_count(i) FROM (SELECT 2 AS i WHERE 1 <> 1)"; @@ -751,8 +765,7 @@ mod test { assert_eq!(result, 0); let single_sum = "SELECT my_count(i) FROM (SELECT 2 AS i UNION ALL SELECT 2)"; - let result: i64 = db.query_row(single_sum, &[], |r| r.get(0)) - .unwrap(); + let result: i64 = db.query_row(single_sum, &[], |r| r.get(0)).unwrap(); assert_eq!(2, result); } } diff --git a/src/lib.rs b/src/lib.rs index 7f8e8c8..632e0be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -224,12 +224,12 @@ impl Connection { pub fn open_with_flags>(path: P, flags: OpenFlags) -> Result { let c_path = try!(path_to_cstring(path.as_ref())); InnerConnection::open_with_flags(&c_path, flags).map(|db| { - Connection { + Connection { db: RefCell::new(db), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), path: Some(path.as_ref().to_path_buf()), } - }) + }) } /// Open a new connection to an in-memory SQLite database. @@ -243,12 +243,12 @@ impl Connection { pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result { let c_memory = try!(str_to_cstring(":memory:")); InnerConnection::open_with_flags(&c_memory, flags).map(|db| { - Connection { + Connection { db: RefCell::new(db), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), path: None, } - }) + }) } /// Convenience method to run multiple SQL statements (that cannot take any parameters). @@ -297,7 +297,8 @@ impl Connection { /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the /// underlying SQLite call fails. pub fn execute(&self, sql: &str, params: &[&ToSql]) -> Result { - self.prepare(sql).and_then(|mut stmt| stmt.execute(params)) + self.prepare(sql) + .and_then(|mut stmt| stmt.execute(params)) } /// Convenience method to prepare and execute a single SQL statement with named parameter(s). @@ -319,7 +320,8 @@ impl Connection { /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the /// underlying SQLite call fails. pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> Result { - self.prepare(sql).and_then(|mut stmt| stmt.execute_named(params)) + self.prepare(sql) + .and_then(|mut stmt| stmt.execute_named(params)) } /// Get the SQLite rowid of the most recent successful INSERT. @@ -408,7 +410,9 @@ impl Connection { let mut stmt = try!(self.prepare(sql)); let mut rows = try!(stmt.query(params)); - rows.get_expected_row().map_err(E::from).and_then(|r| f(&r)) + rows.get_expected_row() + .map_err(E::from) + .and_then(|r| f(&r)) } /// Convenience method to execute a query that is expected to return a single row. @@ -536,7 +540,9 @@ impl Connection { dylib_path: P, entry_point: Option<&str>) -> Result<()> { - self.db.borrow_mut().load_extension(dylib_path.as_ref(), entry_point) + self.db + .borrow_mut() + .load_extension(dylib_path.as_ref(), entry_point) } /// Get access to the underlying SQLite database connection handle. @@ -580,16 +586,16 @@ bitflags! { #[doc = "Flags for opening SQLite database connections."] #[doc = "See [sqlite3_open_v2](http://www.sqlite.org/c3ref/open.html) for details."] #[repr(C)] - pub flags OpenFlags: ::std::os::raw::c_int { - const SQLITE_OPEN_READ_ONLY = 0x00000001, - const SQLITE_OPEN_READ_WRITE = 0x00000002, - const SQLITE_OPEN_CREATE = 0x00000004, - const SQLITE_OPEN_URI = 0x00000040, - const SQLITE_OPEN_MEMORY = 0x00000080, - const SQLITE_OPEN_NO_MUTEX = 0x00008000, - const SQLITE_OPEN_FULL_MUTEX = 0x00010000, - const SQLITE_OPEN_SHARED_CACHE = 0x00020000, - const SQLITE_OPEN_PRIVATE_CACHE = 0x00040000, + pub struct OpenFlags: ::std::os::raw::c_int { + const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY; + const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE; + const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE; + const SQLITE_OPEN_URI = 0x00000040; + const SQLITE_OPEN_MEMORY = 0x00000080; + const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX; + const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX; + const SQLITE_OPEN_SHARED_CACHE = 0x00020000; + const SQLITE_OPEN_PRIVATE_CACHE = 0x00040000; } } @@ -851,7 +857,8 @@ impl InnerConnection { &mut c_stmt, ptr::null_mut()) }; - self.decode_result(r).map(|_| Statement::new(conn, RawStatement::new(c_stmt))) + self.decode_result(r) + .map(|_| Statement::new(conn, RawStatement::new(c_stmt))) } fn changes(&mut self) -> c_int { @@ -1001,12 +1008,15 @@ mod test { db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap(); assert_eq!(1, - db.execute("INSERT INTO foo(x) VALUES (?)", &[&1i32]).unwrap()); + db.execute("INSERT INTO foo(x) VALUES (?)", &[&1i32]) + .unwrap()); assert_eq!(1, - db.execute("INSERT INTO foo(x) VALUES (?)", &[&2i32]).unwrap()); + db.execute("INSERT INTO foo(x) VALUES (?)", &[&2i32]) + .unwrap()); assert_eq!(3i32, - db.query_row::("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap()); + db.query_row::("SELECT SUM(x) FROM foo", &[], |r| r.get(0)) + .unwrap()); } #[test] @@ -1063,7 +1073,8 @@ mod test { assert_eq!(insert_stmt.execute(&[&2i32]).unwrap(), 1); assert_eq!(insert_stmt.execute(&[&3i32]).unwrap(), 1); - let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC").unwrap(); + let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC") + .unwrap(); { let mut rows = query.query(&[&4i32]).unwrap(); let mut v = Vec::::new(); @@ -1148,8 +1159,10 @@ mod test { #[test] fn test_last_insert_rowid() { let db = checked_memory_handle(); - db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)").unwrap(); - db.execute_batch("INSERT INTO foo DEFAULT VALUES").unwrap(); + db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)") + .unwrap(); + db.execute_batch("INSERT INTO foo DEFAULT VALUES") + .unwrap(); assert_eq!(db.last_insert_rowid(), 1); diff --git a/src/load_extension_guard.rs b/src/load_extension_guard.rs index 92db69b..7f62a60 100644 --- a/src/load_extension_guard.rs +++ b/src/load_extension_guard.rs @@ -25,7 +25,8 @@ impl<'conn> LoadExtensionGuard<'conn> { /// Attempt to enable loading extensions. Loading extensions will be disabled when this /// guard goes out of scope. Cannot be meaningfully nested. pub fn new(conn: &Connection) -> Result { - conn.load_extension_enable().map(|_| LoadExtensionGuard { conn: conn }) + conn.load_extension_enable() + .map(|_| LoadExtensionGuard { conn: conn }) } } diff --git a/src/row.rs b/src/row.rs index 1c98639..a93474a 100644 --- a/src/row.rs +++ b/src/row.rs @@ -28,22 +28,23 @@ impl<'stmt> Rows<'stmt> { /// "streaming iterator". For a more natural interface, consider using `query_map` /// or `query_and_then` instead, which return types that implement `Iterator`. pub fn next<'a>(&'a mut self) -> Option>> { - self.stmt.and_then(|stmt| match stmt.step() { - Ok(true) => { - Some(Ok(Row { - stmt: stmt, - phantom: PhantomData, - })) - } - Ok(false) => { + self.stmt + .and_then(|stmt| match stmt.step() { + Ok(true) => { + Some(Ok(Row { + stmt: stmt, + phantom: PhantomData, + })) + } + Ok(false) => { self.reset(); None } - Err(err) => { + Err(err) => { self.reset(); Some(Err(err)) } - }) + }) } } @@ -89,10 +90,7 @@ impl<'stmt, T, F> MappedRowsCrateImpl<'stmt, T, F> for MappedRows<'stmt, F> where F: FnMut(&Row) -> T { fn new(rows: Rows<'stmt>, f: F) -> MappedRows<'stmt, F> { - MappedRows { - rows: rows, - map: f, - } + MappedRows { rows: rows, map: f } } } @@ -103,7 +101,9 @@ impl<'conn, T, F> Iterator for MappedRows<'conn, F> fn next(&mut self) -> Option> { let map = &mut self.map; - self.rows.next().map(|row_result| row_result.map(|row| (map)(&row))) + self.rows + .next() + .map(|row_result| row_result.map(|row| (map)(&row))) } } @@ -124,10 +124,7 @@ impl<'stmt, T, E, F> AndThenRowsCrateImpl<'stmt, T, E, F> for AndThenRows<'stmt, where F: FnMut(&Row) -> result::Result { fn new(rows: Rows<'stmt>, f: F) -> AndThenRows<'stmt, F> { - AndThenRows { - rows: rows, - map: f, - } + AndThenRows { rows: rows, map: f } } } @@ -139,10 +136,9 @@ impl<'stmt, T, E, F> Iterator for AndThenRows<'stmt, F> fn next(&mut self) -> Option { let map = &mut self.map; - self.rows.next().map(|row_result| { - row_result.map_err(E::from) - .and_then(|row| (map)(&row)) - }) + self.rows + .next() + .map(|row_result| row_result.map_err(E::from).and_then(|row| (map)(&row))) } } @@ -182,12 +178,17 @@ impl<'a, 'stmt> Row<'a, 'stmt> { let idx = try!(idx.idx(self.stmt)); let value = self.stmt.value_ref(idx); FromSql::column_result(value).map_err(|err| match err { - FromSqlError::InvalidType => Error::InvalidColumnType(idx, value.data_type()), - FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i), - FromSqlError::Other(err) => { + FromSqlError::InvalidType => { + Error::InvalidColumnType(idx, + value.data_type()) + } + FromSqlError::OutOfRange(i) => { + Error::IntegralValueOutOfRange(idx, i) + } + FromSqlError::Other(err) => { Error::FromSqlConversionFailure(idx as usize, value.data_type(), err) } - }) + }) } /// Return the number of columns in the current row. diff --git a/src/statement.rs b/src/statement.rs index 09db33d..8885ec1 100644 --- a/src/statement.rs +++ b/src/statement.rs @@ -402,14 +402,19 @@ impl<'conn> Statement<'conn> { #[cfg(feature = "blob")] ToSqlOutput::ZeroBlob(len) => { return self.conn - .decode_result(unsafe { ffi::sqlite3_bind_zeroblob(ptr, col, len) }); + .decode_result(unsafe { ffi::sqlite3_bind_zeroblob(ptr, col, len) }); } }; - self.conn.decode_result(match value { - ValueRef::Null => unsafe { ffi::sqlite3_bind_null(ptr, col) }, - ValueRef::Integer(i) => unsafe { ffi::sqlite3_bind_int64(ptr, col, i) }, - ValueRef::Real(r) => unsafe { ffi::sqlite3_bind_double(ptr, col, r) }, - ValueRef::Text(s) => unsafe { + self.conn + .decode_result(match value { + ValueRef::Null => unsafe { ffi::sqlite3_bind_null(ptr, col) }, + ValueRef::Integer(i) => unsafe { + ffi::sqlite3_bind_int64(ptr, col, i) + }, + ValueRef::Real(r) => unsafe { + ffi::sqlite3_bind_double(ptr, col, r) + }, + ValueRef::Text(s) => unsafe { let length = s.len(); if length > ::std::i32::MAX as usize { ffi::SQLITE_TOOBIG @@ -423,7 +428,7 @@ impl<'conn> Statement<'conn> { ffi::sqlite3_bind_text(ptr, col, c_str.as_ptr(), length as c_int, destructor) } }, - ValueRef::Blob(b) => unsafe { + ValueRef::Blob(b) => unsafe { let length = b.len(); if length > ::std::i32::MAX as usize { ffi::SQLITE_TOOBIG @@ -437,7 +442,7 @@ impl<'conn> Statement<'conn> { ffi::SQLITE_TRANSIENT()) } }, - }) + }) } fn execute_with_bound_parameters(&mut self) -> Result { @@ -524,7 +529,8 @@ impl<'conn> StatementCrateImpl<'conn> for Statement<'conn> { }; // sqlite3_column_text returns UTF8 data, so our unwrap here should be fine. - let s = s.to_str().expect("sqlite3_column_text returned invalid UTF-8"); + let s = s.to_str() + .expect("sqlite3_column_text returned invalid UTF-8"); ValueRef::Text(s) } ffi::SQLITE_BLOB => { @@ -570,15 +576,17 @@ mod test { let db = Connection::open_in_memory().unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap(); - assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]).unwrap(), + assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]) + .unwrap(), 1); - assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)]).unwrap(), + assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)]) + .unwrap(), 1); assert_eq!(3i32, db.query_row_named::("SELECT SUM(x) FROM foo WHERE x > :x", - &[(":x", &0i32)], - |r| r.get(0)) + &[(":x", &0i32)], + |r| r.get(0)) .unwrap()); } @@ -589,13 +597,14 @@ mod test { INTEGER)"; db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("INSERT INTO test (name) VALUES (:name)").unwrap(); + let mut stmt = db.prepare("INSERT INTO test (name) VALUES (:name)") + .unwrap(); stmt.execute_named(&[(":name", &"one")]).unwrap(); assert_eq!(1i32, db.query_row_named::("SELECT COUNT(*) FROM test WHERE name = :name", - &[(":name", &"one")], - |r| r.get(0)) + &[(":name", &"one")], + |r| r.get(0)) .unwrap()); } @@ -608,7 +617,8 @@ mod test { "#; db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("SELECT id FROM test where name = :name").unwrap(); + let mut stmt = db.prepare("SELECT id FROM test where name = :name") + .unwrap(); let mut rows = stmt.query_named(&[(":name", &"one")]).unwrap(); let id: i32 = rows.next().unwrap().unwrap().get(0); @@ -624,7 +634,8 @@ mod test { "#; db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("SELECT id FROM test where name = :name").unwrap(); + let mut stmt = db.prepare("SELECT id FROM test where name = :name") + .unwrap(); let mut rows = stmt.query_map_named(&[(":name", &"one")], |row| { let id: i32 = row.get(0); 2 * id @@ -676,7 +687,8 @@ mod test { let sql = "CREATE TABLE test (x TEXT, y TEXT)"; db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)").unwrap(); + let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)") + .unwrap(); stmt.execute_named(&[(":x", &"one")]).unwrap(); let result: Option = @@ -691,7 +703,8 @@ mod test { let sql = "CREATE TABLE test (x TEXT, y TEXT)"; db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)").unwrap(); + let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)") + .unwrap(); stmt.execute_named(&[(":x", &"one")]).unwrap(); stmt.execute_named(&[(":y", &"two")]).unwrap(); @@ -704,15 +717,18 @@ mod test { #[test] fn test_insert() { let db = Connection::open_in_memory().unwrap(); - db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)").unwrap(); - let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?)").unwrap(); + db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)") + .unwrap(); + let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?)") + .unwrap(); assert_eq!(stmt.insert(&[&1i32]).unwrap(), 1); assert_eq!(stmt.insert(&[&2i32]).unwrap(), 2); match stmt.insert(&[&1i32]).unwrap_err() { Error::StatementChangedRows(0) => (), err => panic!("Unexpected error {}", err), } - let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4").unwrap(); + let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4") + .unwrap(); match multi.insert(&[]).unwrap_err() { Error::StatementChangedRows(2) => (), err => panic!("Unexpected error {}", err), @@ -729,9 +745,15 @@ mod test { ") .unwrap(); - assert_eq!(db.prepare("INSERT INTO foo VALUES (10)").unwrap().insert(&[]).unwrap(), + assert_eq!(db.prepare("INSERT INTO foo VALUES (10)") + .unwrap() + .insert(&[]) + .unwrap(), 1); - assert_eq!(db.prepare("INSERT INTO bar VALUES (10)").unwrap().insert(&[]).unwrap(), + assert_eq!(db.prepare("INSERT INTO bar VALUES (10)") + .unwrap() + .insert(&[]) + .unwrap(), 1); } diff --git a/src/transaction.rs b/src/transaction.rs index 6fa3fe2..41414f7 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -100,13 +100,14 @@ impl<'conn> Transaction<'conn> { TransactionBehavior::Immediate => "BEGIN IMMEDIATE", TransactionBehavior::Exclusive => "BEGIN EXCLUSIVE", }; - conn.execute_batch(query).map(move |_| { - Transaction { - conn: conn, - drop_behavior: DropBehavior::Rollback, - committed: false, - } - }) + conn.execute_batch(query) + .map(move |_| { + Transaction { + conn: conn, + drop_behavior: DropBehavior::Rollback, + committed: false, + } + }) } /// Starts a new [savepoint](http://www.sqlite.org/lang_savepoint.html), allowing nested @@ -216,15 +217,16 @@ impl<'conn> Savepoint<'conn> { name: T) -> Result { let name = name.into(); - conn.execute_batch(&format!("SAVEPOINT {}", name)).map(|_| { - Savepoint { - conn: conn, - name: name, - depth: depth, - drop_behavior: DropBehavior::Rollback, - committed: false, - } - }) + conn.execute_batch(&format!("SAVEPOINT {}", name)) + .map(|_| { + Savepoint { + conn: conn, + name: name, + depth: depth, + drop_behavior: DropBehavior::Rollback, + committed: false, + } + }) } fn with_depth(conn: &Connection, depth: u32) -> Result { @@ -269,7 +271,8 @@ impl<'conn> Savepoint<'conn> { fn commit_(&mut self) -> Result<()> { self.committed = true; - self.conn.execute_batch(&format!("RELEASE {}", self.name)) + self.conn + .execute_batch(&format!("RELEASE {}", self.name)) } /// A convenience method which rolls back a savepoint. @@ -279,7 +282,8 @@ impl<'conn> Savepoint<'conn> { /// Unlike `Transaction`s, savepoints remain active after they have been rolled back, /// and can be rolled back again or committed. pub fn rollback(&mut self) -> Result<()> { - self.conn.execute_batch(&format!("ROLLBACK TO {}", self.name)) + self.conn + .execute_batch(&format!("ROLLBACK TO {}", self.name)) } /// Consumes the savepoint, committing or rolling back according to the current setting @@ -549,7 +553,8 @@ mod test { } fn assert_current_sum(x: i32, conn: &Connection) { - let i = conn.query_row::("SELECT SUM(x) FROM foo", &[], |r| r.get(0)).unwrap(); + let i = conn.query_row::("SELECT SUM(x) FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(x, i); } } diff --git a/src/types/chrono.rs b/src/types/chrono.rs index 29993a1..ee0511e 100644 --- a/src/types/chrono.rs +++ b/src/types/chrono.rs @@ -19,10 +19,12 @@ impl ToSql for NaiveDate { /// "YYYY-MM-DD" => ISO 8601 calendar date without timezone. impl FromSql for NaiveDate { fn column_result(value: ValueRef) -> FromSqlResult { - value.as_str().and_then(|s| match NaiveDate::parse_from_str(s, "%Y-%m-%d") { - Ok(dt) => Ok(dt), - Err(err) => Err(FromSqlError::Other(Box::new(err))), - }) + value + .as_str() + .and_then(|s| match NaiveDate::parse_from_str(s, "%Y-%m-%d") { + Ok(dt) => Ok(dt), + Err(err) => Err(FromSqlError::Other(Box::new(err))), + }) } } @@ -37,17 +39,19 @@ impl ToSql for NaiveTime { /// "HH:MM"/"HH:MM:SS"/"HH:MM:SS.SSS" => ISO 8601 time without timezone. impl FromSql for NaiveTime { fn column_result(value: ValueRef) -> FromSqlResult { - value.as_str().and_then(|s| { - let fmt = match s.len() { - 5 => "%H:%M", - 8 => "%H:%M:%S", - _ => "%H:%M:%S%.f", - }; - match NaiveTime::parse_from_str(s, fmt) { - Ok(dt) => Ok(dt), - Err(err) => Err(FromSqlError::Other(Box::new(err))), - } - }) + value + .as_str() + .and_then(|s| { + let fmt = match s.len() { + 5 => "%H:%M", + 8 => "%H:%M:%S", + _ => "%H:%M:%S%.f", + }; + match NaiveTime::parse_from_str(s, fmt) { + Ok(dt) => Ok(dt), + Err(err) => Err(FromSqlError::Other(Box::new(err))), + } + }) } } @@ -63,18 +67,20 @@ impl ToSql for NaiveDateTime { /// without timezone. ("YYYY-MM-DDTHH:MM:SS"/"YYYY-MM-DDTHH:MM:SS.SSS" also supported) impl FromSql for NaiveDateTime { fn column_result(value: ValueRef) -> FromSqlResult { - value.as_str().and_then(|s| { - let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' { - "%Y-%m-%dT%H:%M:%S%.f" - } else { - "%Y-%m-%d %H:%M:%S%.f" - }; + value + .as_str() + .and_then(|s| { + let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' { + "%Y-%m-%dT%H:%M:%S%.f" + } else { + "%Y-%m-%d %H:%M:%S%.f" + }; - match NaiveDateTime::parse_from_str(s, fmt) { - Ok(dt) => Ok(dt), - Err(err) => Err(FromSqlError::Other(Box::new(err))), - } - }) + match NaiveDateTime::parse_from_str(s, fmt) { + Ok(dt) => Ok(dt), + Err(err) => Err(FromSqlError::Other(Box::new(err))), + } + }) } } @@ -130,7 +136,8 @@ mod test { fn checked_memory_handle() -> Connection { let db = Connection::open_in_memory().unwrap(); - db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT, b BLOB)").unwrap(); + db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT, b BLOB)") + .unwrap(); db } @@ -138,11 +145,14 @@ mod test { fn test_naive_date() { let db = checked_memory_handle(); let date = NaiveDate::from_ymd(2016, 2, 23); - db.execute("INSERT INTO foo (t) VALUES (?)", &[&date]).unwrap(); + db.execute("INSERT INTO foo (t) VALUES (?)", &[&date]) + .unwrap(); - let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!("2016-02-23", s); - let t: NaiveDate = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let t: NaiveDate = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(date, t); } @@ -150,11 +160,14 @@ mod test { fn test_naive_time() { let db = checked_memory_handle(); let time = NaiveTime::from_hms(23, 56, 4); - db.execute("INSERT INTO foo (t) VALUES (?)", &[&time]).unwrap(); + db.execute("INSERT INTO foo (t) VALUES (?)", &[&time]) + .unwrap(); - let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!("23:56:04", s); - let v: NaiveTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let v: NaiveTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(time, v); } @@ -165,15 +178,20 @@ mod test { let time = NaiveTime::from_hms(23, 56, 4); let dt = NaiveDateTime::new(date, time); - db.execute("INSERT INTO foo (t) VALUES (?)", &[&dt]).unwrap(); + db.execute("INSERT INTO foo (t) VALUES (?)", &[&dt]) + .unwrap(); - let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!("2016-02-23T23:56:04", s); - let v: NaiveDateTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let v: NaiveDateTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(dt, v); - db.execute("UPDATE foo set b = datetime(t)", &[]).unwrap(); // "YYYY-MM-DD HH:MM:SS" - let hms: NaiveDateTime = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap(); + db.execute("UPDATE foo set b = datetime(t)", &[]) + .unwrap(); // "YYYY-MM-DD HH:MM:SS" + let hms: NaiveDateTime = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(dt, hms); } @@ -185,12 +203,15 @@ mod test { let dt = NaiveDateTime::new(date, time); let utc = UTC.from_utc_datetime(&dt); - db.execute("INSERT INTO foo (t) VALUES (?)", &[&utc]).unwrap(); + db.execute("INSERT INTO foo (t) VALUES (?)", &[&utc]) + .unwrap(); - let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!("2016-02-23T23:56:04.789+00:00", s); - let v1: DateTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let v1: DateTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(utc, v1); let v2: DateTime = db.query_row("SELECT '2016-02-23 23:56:04.789'", &[], |r| r.get(0)) @@ -202,7 +223,8 @@ mod test { assert_eq!(utc - Duration::milliseconds(789), v3); let v4: DateTime = - db.query_row("SELECT '2016-02-23 23:56:04.789+00:00'", &[], |r| r.get(0)).unwrap(); + db.query_row("SELECT '2016-02-23 23:56:04.789+00:00'", &[], |r| r.get(0)) + .unwrap(); assert_eq!(utc, v4); } @@ -214,13 +236,16 @@ mod test { let dt = NaiveDateTime::new(date, time); let local = Local.from_local_datetime(&dt).single().unwrap(); - db.execute("INSERT INTO foo (t) VALUES (?)", &[&local]).unwrap(); + db.execute("INSERT INTO foo (t) VALUES (?)", &[&local]) + .unwrap(); // Stored string should be in UTC - let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let s: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert!(s.ends_with("+00:00")); - let v: DateTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let v: DateTime = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(local, v); } } diff --git a/src/types/from_sql.rs b/src/types/from_sql.rs index ab79750..2f9bb19 100644 --- a/src/types/from_sql.rs +++ b/src/types/from_sql.rs @@ -104,9 +104,9 @@ impl FromSql for f64 { impl FromSql for bool { fn column_result(value: ValueRef) -> FromSqlResult { i64::column_result(value).map(|i| match i { - 0 => false, - _ => true, - }) + 0 => false, + _ => true, + }) } } @@ -164,7 +164,9 @@ mod test { } for n in in_range { assert_eq!(*n, - db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0)).unwrap().into()); + db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0)) + .unwrap() + .into()); } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 630db02..c998d89 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -119,7 +119,8 @@ mod test { fn checked_memory_handle() -> Connection { let db = Connection::open_in_memory().unwrap(); - db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT, i INTEGER, f FLOAT, n)").unwrap(); + db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT, i INTEGER, f FLOAT, n)") + .unwrap(); db } @@ -128,9 +129,11 @@ mod test { let db = checked_memory_handle(); let v1234 = vec![1u8, 2, 3, 4]; - db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234]).unwrap(); + db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234]) + .unwrap(); - let v: Vec = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap(); + let v: Vec = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(v, v1234); } @@ -139,9 +142,11 @@ mod test { let db = checked_memory_handle(); let empty = vec![]; - db.execute("INSERT INTO foo(b) VALUES (?)", &[&empty]).unwrap(); + db.execute("INSERT INTO foo(b) VALUES (?)", &[&empty]) + .unwrap(); - let v: Vec = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap(); + let v: Vec = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(v, empty); } @@ -150,9 +155,11 @@ mod test { let db = checked_memory_handle(); let s = "hello, world!"; - db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap(); + db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]) + .unwrap(); - let from: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let from: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(from, s); } @@ -161,9 +168,11 @@ mod test { let db = checked_memory_handle(); let s = "hello, world!"; - db.execute("INSERT INTO foo(t) VALUES (?)", &[&s.to_owned()]).unwrap(); + db.execute("INSERT INTO foo(t) VALUES (?)", &[&s.to_owned()]) + .unwrap(); - let from: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let from: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(from, s); } @@ -171,10 +180,12 @@ mod test { fn test_value() { let db = checked_memory_handle(); - db.execute("INSERT INTO foo(i) VALUES (?)", &[&Value::Integer(10)]).unwrap(); + db.execute("INSERT INTO foo(i) VALUES (?)", &[&Value::Integer(10)]) + .unwrap(); assert_eq!(10i64, - db.query_row::("SELECT i FROM foo", &[], |r| r.get(0)).unwrap()); + db.query_row::("SELECT i FROM foo", &[], |r| r.get(0)) + .unwrap()); } #[test] @@ -184,10 +195,13 @@ mod test { let s = Some("hello, world!"); let b = Some(vec![1u8, 2, 3, 4]); - db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap(); - db.execute("INSERT INTO foo(b) VALUES (?)", &[&b]).unwrap(); + db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]) + .unwrap(); + db.execute("INSERT INTO foo(b) VALUES (?)", &[&b]) + .unwrap(); - let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC").unwrap(); + let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC") + .unwrap(); let mut rows = stmt.query(&[]).unwrap(); { @@ -232,9 +246,15 @@ mod test { assert_eq!("text", row.get_checked::(1).unwrap()); assert_eq!(1, row.get_checked::(2).unwrap()); assert!((1.5 - row.get_checked::(3).unwrap()).abs() < EPSILON); - assert!(row.get_checked::>(4).unwrap().is_none()); - assert!(row.get_checked::>(4).unwrap().is_none()); - assert!(row.get_checked::>(4).unwrap().is_none()); + assert!(row.get_checked::>(4) + .unwrap() + .is_none()); + assert!(row.get_checked::>(4) + .unwrap() + .is_none()); + assert!(row.get_checked::>(4) + .unwrap() + .is_none()); // check some invalid types diff --git a/src/types/serde_json.rs b/src/types/serde_json.rs index 5f236dc..13a570a 100644 --- a/src/types/serde_json.rs +++ b/src/types/serde_json.rs @@ -32,7 +32,8 @@ mod test { fn checked_memory_handle() -> Connection { let db = Connection::open_in_memory().unwrap(); - db.execute_batch("CREATE TABLE foo (t TEXT, b BLOB)").unwrap(); + db.execute_batch("CREATE TABLE foo (t TEXT, b BLOB)") + .unwrap(); db } @@ -46,9 +47,11 @@ mod test { &[&data, &json.as_bytes()]) .unwrap(); - let t: serde_json::Value = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap(); + let t: serde_json::Value = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(data, t); - let b: serde_json::Value = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap(); + let b: serde_json::Value = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(data, b); } } diff --git a/src/types/time.rs b/src/types/time.rs index 28baad4..7f74b65 100644 --- a/src/types/time.rs +++ b/src/types/time.rs @@ -7,17 +7,22 @@ const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S"; impl ToSql for time::Timespec { fn to_sql(&self) -> Result { - let time_string = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap().to_string(); + let time_string = time::at_utc(*self) + .strftime(SQLITE_DATETIME_FMT) + .unwrap() + .to_string(); Ok(ToSqlOutput::from(time_string)) } } impl FromSql for time::Timespec { fn column_result(value: ValueRef) -> FromSqlResult { - value.as_str().and_then(|s| match time::strptime(s, SQLITE_DATETIME_FMT) { - Ok(tm) => Ok(tm.to_timespec()), - Err(err) => Err(FromSqlError::Other(Box::new(err))), - }) + value + .as_str() + .and_then(|s| match time::strptime(s, SQLITE_DATETIME_FMT) { + Ok(tm) => Ok(tm.to_timespec()), + Err(err) => Err(FromSqlError::Other(Box::new(err))), + }) } } @@ -28,7 +33,8 @@ mod test { fn checked_memory_handle() -> Connection { let db = Connection::open_in_memory().unwrap(); - db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT)").unwrap(); + db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT)") + .unwrap(); db } @@ -40,9 +46,11 @@ mod test { sec: 10_000, nsec: 0, }; - db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]).unwrap(); + 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(); + let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)) + .unwrap(); assert_eq!(from, ts); } } diff --git a/src/types/to_sql.rs b/src/types/to_sql.rs index 3d4df7f..21236a1 100644 --- a/src/types/to_sql.rs +++ b/src/types/to_sql.rs @@ -32,12 +32,12 @@ impl<'a, T: Into> From for ToSqlOutput<'a> { impl<'a> ToSql for ToSqlOutput<'a> { fn to_sql(&self) -> Result { Ok(match *self { - ToSqlOutput::Borrowed(v) => ToSqlOutput::Borrowed(v), - ToSqlOutput::Owned(ref v) => ToSqlOutput::Borrowed(ValueRef::from(v)), + ToSqlOutput::Borrowed(v) => ToSqlOutput::Borrowed(v), + ToSqlOutput::Owned(ref v) => ToSqlOutput::Borrowed(ValueRef::from(v)), - #[cfg(feature = "blob")] + #[cfg(feature = "blob")] ToSqlOutput::ZeroBlob(i) => ToSqlOutput::ZeroBlob(i), - }) + }) } } @@ -94,12 +94,24 @@ impl ToSql for String { } } +impl ToSql for str { + fn to_sql(&self) -> Result { + Ok(ToSqlOutput::from(self)) + } +} + impl ToSql for Vec { fn to_sql(&self) -> Result { Ok(ToSqlOutput::from(self.as_slice())) } } +impl ToSql for [u8] { + fn to_sql(&self) -> Result { + Ok(ToSqlOutput::from(self)) + } +} + impl ToSql for Value { fn to_sql(&self) -> Result { Ok(ToSqlOutput::from(self)) diff --git a/src/version.rs b/src/version.rs index e7d8522..19d0f55 100644 --- a/src/version.rs +++ b/src/version.rs @@ -13,5 +13,6 @@ pub fn version_number() -> i32 { /// See [sqlite3_libversion()](https://www.sqlite.org/c3ref/libversion.html). pub fn version() -> &'static str { let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) }; - cstr.to_str().expect("SQLite version string is not valid UTF8 ?!") + cstr.to_str() + .expect("SQLite version string is not valid UTF8 ?!") } diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index 3370c87..d4fdaf4 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -56,13 +56,13 @@ pub trait VTab>: Sized { bitflags! { #[doc = "Index constraint operator."] #[repr(C)] - pub flags IndexConstraintOp: ::std::os::raw::c_uchar { - const SQLITE_INDEX_CONSTRAINT_EQ = 2, - const SQLITE_INDEX_CONSTRAINT_GT = 4, - const SQLITE_INDEX_CONSTRAINT_LE = 8, - const SQLITE_INDEX_CONSTRAINT_LT = 16, - const SQLITE_INDEX_CONSTRAINT_GE = 32, - const SQLITE_INDEX_CONSTRAINT_MATCH = 64, + pub struct IndexConstraintOp: ::std::os::raw::c_uchar { + const SQLITE_INDEX_CONSTRAINT_EQ = 2; + const SQLITE_INDEX_CONSTRAINT_GT = 4; + const SQLITE_INDEX_CONSTRAINT_LE = 8; + const SQLITE_INDEX_CONSTRAINT_LT = 16; + const SQLITE_INDEX_CONSTRAINT_GE = 32; + const SQLITE_INDEX_CONSTRAINT_MATCH = 64; } } @@ -96,7 +96,7 @@ impl IndexInfo { /// if `argv_index` > 0, constraint is part of argv to xFilter pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage { - let mut constraint_usages = unsafe { + let constraint_usages = unsafe { slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize) }; IndexConstraintUsage(&mut constraint_usages[constraint_idx]) diff --git a/src/vtab/series.rs b/src/vtab/series.rs index 6e7a375..850fd40 100644 --- a/src/vtab/series.rs +++ b/src/vtab/series.rs @@ -37,17 +37,17 @@ const SERIES_COLUMN_STEP: c_int = 3; bitflags! { #[repr(C)] - flags QueryPlanFlags: ::std::os::raw::c_int { + struct QueryPlanFlags: ::std::os::raw::c_int { // start = $value -- constraint exists - const START = 1, + const START = 1; // stop = $value -- constraint exists - const STOP = 2, + const STOP = 2; // step = $value -- constraint exists - const STEP = 4, + const STEP = 4; // output in descending order - const DESC = 8, + const DESC = 8; // Both start and stop - const BOTH = START.bits | STOP.bits, + const BOTH = START.bits | STOP.bits; } }