mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Merge remote-tracking branch 'remotes/jgallagher/master' into vtab
This commit is contained in:
commit
3aaab1e36f
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1 +1 @@
|
|||||||
libsqlite3-sys/sqlite3 linguist-vendored
|
libsqlite3-sys/sqlite3/* linguist-vendored
|
||||||
|
@ -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"
|
||||||
|
@ -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)
|
||||||
|
17
Cargo.toml
17
Cargo.toml
@ -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"
|
||||||
|
10
Changelog.md
10
Changelog.md
@ -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).
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 }
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
47
src/lib.rs
47
src/lib.rs
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
src/row.rs
30
src/row.rs
@ -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))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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()
|
||||||
|
@ -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")]
|
||||||
|
Loading…
Reference in New Issue
Block a user