mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-22 16:29:20 +08:00
Merge remote-tracking branch 'jgallagher/master' into unlock-notify
This commit is contained in:
commit
fee4bfcc86
@ -39,8 +39,8 @@ serde_json = { version = "1.0", optional = true }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
lazy_static = "0.2"
|
lazy_static = "1.0"
|
||||||
regex = "0.2"
|
regex = "1.0"
|
||||||
|
|
||||||
[dependencies.libsqlite3-sys]
|
[dependencies.libsqlite3-sys]
|
||||||
path = "libsqlite3-sys"
|
path = "libsqlite3-sys"
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- TARGET: 1.21.0-x86_64-pc-windows-gnu
|
- TARGET: 1.24.1-x86_64-pc-windows-gnu
|
||||||
MSYS2_BITS: 64
|
MSYS2_BITS: 64
|
||||||
- TARGET: 1.21.0-x86_64-pc-windows-msvc
|
- TARGET: 1.24.1-x86_64-pc-windows-msvc
|
||||||
VCPKG_DEFAULT_TRIPLET: x64-windows
|
VCPKG_DEFAULT_TRIPLET: x64-windows
|
||||||
VCPKGRS_DYNAMIC: 1
|
VCPKGRS_DYNAMIC: 1
|
||||||
- TARGET: nightly-x86_64-pc-windows-msvc
|
- TARGET: nightly-x86_64-pc-windows-msvc
|
||||||
|
@ -25,7 +25,7 @@ min_sqlite_version_3_7_16 = ["pkg-config", "vcpkg"]
|
|||||||
unlock_notify = []
|
unlock_notify = []
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = { version = "0.32", optional = true }
|
bindgen = { version = "0.36", optional = true }
|
||||||
pkg-config = { version = "0.3", optional = true }
|
pkg-config = { version = "0.3", optional = true }
|
||||||
cc = { version = "1.0", optional = true }
|
cc = { version = "1.0", optional = true }
|
||||||
|
|
||||||
|
28
src/cache.rs
28
src/cache.rs
@ -46,6 +46,7 @@ impl Connection {
|
|||||||
self.cache.set_capacity(capacity)
|
self.cache.set_capacity(capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove/finalize all prepared statements currently in the cache.
|
||||||
pub fn flush_prepared_statement_cache(&self) {
|
pub fn flush_prepared_statement_cache(&self) {
|
||||||
self.cache.flush()
|
self.cache.flush()
|
||||||
}
|
}
|
||||||
@ -124,7 +125,7 @@ impl StatementCache {
|
|||||||
sql: &str)
|
sql: &str)
|
||||||
-> Result<CachedStatement<'conn>> {
|
-> Result<CachedStatement<'conn>> {
|
||||||
let mut cache = self.0.borrow_mut();
|
let mut cache = self.0.borrow_mut();
|
||||||
let stmt = match cache.remove(sql) {
|
let stmt = match cache.remove(sql.trim()) {
|
||||||
Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
|
Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
|
||||||
None => conn.prepare(sql),
|
None => conn.prepare(sql),
|
||||||
};
|
};
|
||||||
@ -135,7 +136,7 @@ impl StatementCache {
|
|||||||
fn cache_stmt(&self, stmt: RawStatement) {
|
fn cache_stmt(&self, stmt: RawStatement) {
|
||||||
let mut cache = self.0.borrow_mut();
|
let mut cache = self.0.borrow_mut();
|
||||||
stmt.clear_bindings();
|
stmt.clear_bindings();
|
||||||
let sql = String::from_utf8_lossy(stmt.sql().to_bytes()).to_string();
|
let sql = String::from_utf8_lossy(stmt.sql().to_bytes()).trim().to_string();
|
||||||
cache.insert(sql, stmt);
|
cache.insert(sql, stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,4 +286,27 @@ mod test {
|
|||||||
|
|
||||||
conn.close().expect("connection not closed");
|
conn.close().expect("connection not closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cache_key() {
|
||||||
|
let db = Connection::open_in_memory().unwrap();
|
||||||
|
let cache = &db.cache;
|
||||||
|
assert_eq!(0, cache.len());
|
||||||
|
|
||||||
|
//let sql = " PRAGMA schema_version; -- comment";
|
||||||
|
let sql = "PRAGMA schema_version; ";
|
||||||
|
{
|
||||||
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
|
assert_eq!(0, cache.len());
|
||||||
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
|
}
|
||||||
|
assert_eq!(1, cache.len());
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
|
assert_eq!(0, cache.len());
|
||||||
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
|
}
|
||||||
|
assert_eq!(1, cache.len());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ impl Connection {
|
|||||||
/// Open a new connection to a SQLite database.
|
/// Open a new connection to a SQLite database.
|
||||||
///
|
///
|
||||||
/// `Connection::open(path)` is equivalent to `Connection::open_with_flags(path,
|
/// `Connection::open(path)` is equivalent to `Connection::open_with_flags(path,
|
||||||
/// SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE)`.
|
/// OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE)`.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
|
@ -45,7 +45,7 @@ impl<'conn> Statement<'conn> {
|
|||||||
let bytes = name.as_bytes();
|
let bytes = name.as_bytes();
|
||||||
let n = self.column_count();
|
let n = self.column_count();
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
if bytes == self.stmt.column_name(i).to_bytes() {
|
if bytes.eq_ignore_ascii_case(self.stmt.column_name(i).to_bytes()) {
|
||||||
return Ok(i);
|
return Ok(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -785,4 +785,30 @@ mod test {
|
|||||||
let y: Result<i64> = stmt.query_row(&[&1i32], |r| r.get(0));
|
let y: Result<i64> = stmt.query_row(&[&1i32], |r| r.get(0));
|
||||||
assert_eq!(3i64, y.unwrap());
|
assert_eq!(3i64, y.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_query_by_column_name() {
|
||||||
|
let db = Connection::open_in_memory().unwrap();
|
||||||
|
let sql = "BEGIN;
|
||||||
|
CREATE TABLE foo(x INTEGER, y INTEGER);
|
||||||
|
INSERT INTO foo VALUES(1, 3);
|
||||||
|
END;";
|
||||||
|
db.execute_batch(sql).unwrap();
|
||||||
|
let mut stmt = db.prepare("SELECT y FROM foo").unwrap();
|
||||||
|
let y: Result<i64> = stmt.query_row(&[], |r| r.get("y"));
|
||||||
|
assert_eq!(3i64, y.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_query_by_column_name_ignore_case() {
|
||||||
|
let db = Connection::open_in_memory().unwrap();
|
||||||
|
let sql = "BEGIN;
|
||||||
|
CREATE TABLE foo(x INTEGER, y INTEGER);
|
||||||
|
INSERT INTO foo VALUES(1, 3);
|
||||||
|
END;";
|
||||||
|
db.execute_batch(sql).unwrap();
|
||||||
|
let mut stmt = db.prepare("SELECT y as Y FROM foo").unwrap();
|
||||||
|
let y: Result<i64> = stmt.query_row(&[], |r| r.get("y"));
|
||||||
|
assert_eq!(3i64, y.unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,9 @@ pub enum DropBehavior {
|
|||||||
/// Do not commit or roll back changes - this will leave the transaction or savepoint
|
/// Do not commit or roll back changes - this will leave the transaction or savepoint
|
||||||
/// open, so should be used with care.
|
/// open, so should be used with care.
|
||||||
Ignore,
|
Ignore,
|
||||||
|
|
||||||
|
/// Panic. Used to enforce intentional behavior during development.
|
||||||
|
Panic,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Old name for `Transaction`. `SqliteTransaction` is deprecated.
|
/// Old name for `Transaction`. `SqliteTransaction` is deprecated.
|
||||||
@ -195,6 +198,7 @@ impl<'conn> Transaction<'conn> {
|
|||||||
DropBehavior::Commit => self.commit_(),
|
DropBehavior::Commit => self.commit_(),
|
||||||
DropBehavior::Rollback => self.rollback_(),
|
DropBehavior::Rollback => self.rollback_(),
|
||||||
DropBehavior::Ignore => Ok(()),
|
DropBehavior::Ignore => Ok(()),
|
||||||
|
DropBehavior::Panic => panic!("Transaction dropped unexpectedly."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,6 +310,7 @@ impl<'conn> Savepoint<'conn> {
|
|||||||
DropBehavior::Commit => self.commit_(),
|
DropBehavior::Commit => self.commit_(),
|
||||||
DropBehavior::Rollback => self.rollback(),
|
DropBehavior::Rollback => self.rollback(),
|
||||||
DropBehavior::Ignore => Ok(()),
|
DropBehavior::Ignore => Ok(()),
|
||||||
|
DropBehavior::Panic => panic!("Savepoint dropped unexpectedly."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,13 @@
|
|||||||
//! * Strings (`String` and `&str`)
|
//! * Strings (`String` and `&str`)
|
||||||
//! * Blobs (`Vec<u8>` and `&[u8]`)
|
//! * Blobs (`Vec<u8>` and `&[u8]`)
|
||||||
//!
|
//!
|
||||||
//! Additionally, because it is such a common data type, implementations are provided for
|
//! Additionally, because it is such a common data type, implementations are
|
||||||
//! `time::Timespec` that use a string for storage (using the same format string,
|
//! provided for `time::Timespec` that use the RFC 3339 date/time format,
|
||||||
//! `"%Y-%m-%d %H:%M:%S"`, as SQLite's builtin
|
//! `"%Y-%m-%dT%H:%M:%S.%fZ"`, to store time values as strings. These values
|
||||||
//! [datetime](https://www.sqlite.org/lang_datefunc.html) function. Note that this storage
|
//! can be parsed by SQLite's builtin
|
||||||
//! truncates timespecs to the nearest second. If you want different storage for timespecs, you can
|
//! [datetime](https://www.sqlite.org/lang_datefunc.html) functions. If you
|
||||||
//! use a newtype. For example, to store timespecs as `f64`s:
|
//! want different storage for timespecs, you can use a newtype. For example, to
|
||||||
|
//! store timespecs as `f64`s:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! extern crate rusqlite;
|
//! extern crate rusqlite;
|
||||||
|
@ -3,7 +3,8 @@ 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: &str = "%Y-%m-%d %H:%M:%S:%f %Z";
|
const SQLITE_DATETIME_FMT: &str = "%Y-%m-%dT%H:%M:%S.%fZ";
|
||||||
|
const SQLITE_DATETIME_FMT_LEGACY: &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> {
|
||||||
@ -19,10 +20,12 @@ impl FromSql for time::Timespec {
|
|||||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||||
value
|
value
|
||||||
.as_str()
|
.as_str()
|
||||||
.and_then(|s| match time::strptime(s, SQLITE_DATETIME_FMT) {
|
.and_then(|s| {
|
||||||
Ok(tm) => Ok(tm.to_timespec()),
|
time::strptime(s, SQLITE_DATETIME_FMT)
|
||||||
Err(err) => Err(FromSqlError::Other(Box::new(err))),
|
.or_else(|err| {
|
||||||
})
|
time::strptime(s, SQLITE_DATETIME_FMT_LEGACY)
|
||||||
|
.or(Err(FromSqlError::Other(Box::new(err))))})})
|
||||||
|
.map(|tm| tm.to_timespec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user