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

This commit is contained in:
gwenn 2016-05-20 18:31:30 +02:00
commit 0740620ffe
16 changed files with 71 additions and 62 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "rusqlite" name = "rusqlite"
version = "0.6.0" version = "0.7.2"
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"
@ -37,7 +37,7 @@ regex = "~0.1.41"
[dependencies.libsqlite3-sys] [dependencies.libsqlite3-sys]
path = "libsqlite3-sys" path = "libsqlite3-sys"
version = "0.4.0" version = "0.5.0"
[dependencies.csv] [dependencies.csv]
version = "~0.14.3" version = "~0.14.3"

View File

@ -1,4 +1,4 @@
# Version UPCOMING (...) # Version 0.7.2 (2016-05-19)
* BREAKING CHANGE: `Rows` no longer implements `Iterator`. It still has a `next()` method, but * BREAKING CHANGE: `Rows` no longer implements `Iterator`. It still has a `next()` method, but
the lifetime of the returned `Row` is now tied to the lifetime of the vending `Rows` object. the lifetime of the returned `Row` is now tied to the lifetime of the vending `Rows` object.

View File

@ -72,6 +72,12 @@ features](http://doc.crates.io/manifest.html#the-features-section). They are:
allows hooks into SQLite's tracing and profiling APIs. allows hooks into SQLite's tracing and profiling APIs.
* [`blob`](http://jgallagher.github.io/rusqlite/rusqlite/blob/index.html) * [`blob`](http://jgallagher.github.io/rusqlite/rusqlite/blob/index.html)
gives `std::io::{Read, Write, Seek}` access to SQL BLOBs. gives `std::io::{Read, Write, Seek}` access to SQL BLOBs.
* `chrono` implements [`FromSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.FromSql.html)
and [`ToSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.ToSql.html) for various
types from the [`chrono` crate](https://crates.io/crates/chrono).
* `serde_json` implements [`FromSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.FromSql.html)
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).
## Author ## Author

1
clippy.toml Normal file
View File

@ -0,0 +1 @@
doc-valid-idents = ["SQLite", "lang_transaction"]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.4.0" version = "0.5.0"
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"

View File

@ -8,7 +8,7 @@ fi
cd $(git rev-parse --show-toplevel) cd $(git rev-parse --show-toplevel)
rm -rf target/doc/ rm -rf target/doc/
multirust run nightly cargo doc --no-deps --features "backup cache functions load_extension trace blob" rustup run nightly cargo doc --no-deps --features "backup blob chrono functions load_extension serde_json trace"
echo '<meta http-equiv=refresh content=0;url=rusqlite/index.html>' > target/doc/index.html echo '<meta http-equiv=refresh content=0;url=rusqlite/index.html>' > target/doc/index.html
ghp-import target/doc ghp-import target/doc
git push origin gh-pages:gh-pages git push origin gh-pages:gh-pages

View File

@ -235,7 +235,10 @@ impl<'conn> Drop for Blob<'conn> {
} }
/// BLOB of length N that is filled with zeroes. /// BLOB of length N that is filled with zeroes.
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using incremental BLOB I/O routines. ///
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using
/// incremental BLOB I/O routines.
///
/// A negative value for the zeroblob results in a zero-length BLOB. /// A negative value for the zeroblob results in a zero-length BLOB.
#[derive(Copy,Clone)] #[derive(Copy,Clone)]
pub struct ZeroBlob(pub i32); pub struct ZeroBlob(pub i32);

View File

@ -34,7 +34,7 @@ impl Connection {
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
/// underlying SQLite call fails. /// underlying SQLite call fails.
pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> { pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
self.cache.get(&self, sql) self.cache.get(self, sql)
} }
/// Set the maximum number of cached prepared statements this connection will hold. /// Set the maximum number of cached prepared statements this connection will hold.
@ -90,6 +90,8 @@ impl<'conn> CachedStatement<'conn> {
} }
} }
/// Discard the statement, preventing it from being returned to its `Connection`'s collection
/// of cached statements.
pub fn discard(mut self) { pub fn discard(mut self) {
self.stmt = None; self.stmt = None;
} }

View File

@ -170,8 +170,8 @@ impl error::Error for Error {
Error::InvalidColumnIndex(_) | Error::InvalidColumnIndex(_) |
Error::InvalidColumnName(_) | Error::InvalidColumnName(_) |
Error::InvalidColumnType(_, _) | Error::InvalidColumnType(_, _) |
Error::InvalidPath(_) => None, Error::InvalidPath(_) |
Error::StatementChangedRows(_) => None, Error::StatementChangedRows(_) |
Error::StatementFailedToInsertRow => None, Error::StatementFailedToInsertRow => None,
#[cfg(feature = "functions")] #[cfg(feature = "functions")]

View File

@ -111,7 +111,8 @@ impl<'a> ToResult for &'a str {
length as c_int, length as c_int,
ffi::SQLITE_TRANSIENT()) ffi::SQLITE_TRANSIENT())
} }
Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error // TODO sqlite3_result_error
Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE),
} }
} }
} }
@ -730,9 +731,10 @@ mod test {
assert_eq!(true, result.unwrap()); assert_eq!(true, result.unwrap());
let result: Result<i64> = db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1", let result: Result<i64> =
&[], db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1",
|r| r.get(0)); &[],
|r| r.get(0));
assert_eq!(2, result.unwrap()); assert_eq!(2, result.unwrap());
} }
@ -780,9 +782,10 @@ mod test {
assert_eq!(true, result.unwrap()); assert_eq!(true, result.unwrap());
let result: Result<i64> = db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1", let result: Result<i64> =
&[], db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1",
|r| r.get(0)); &[],
|r| r.get(0));
assert_eq!(2, result.unwrap()); assert_eq!(2, result.unwrap());
} }

View File

@ -80,7 +80,8 @@ use error::{error_from_sqlite_code, error_from_handle};
use raw_statement::RawStatement; use raw_statement::RawStatement;
use cache::StatementCache; use cache::StatementCache;
pub use transaction::{SqliteTransaction, Transaction, TransactionBehavior}; pub use transaction::{SqliteTransaction, SqliteTransactionBehavior, DropBehavior, Savepoint,
Transaction, TransactionBehavior};
pub use error::{SqliteError, Error}; pub use error::{SqliteError, Error};
pub use cache::CachedStatement; pub use cache::CachedStatement;
@ -320,7 +321,9 @@ impl Connection {
/// ```rust,no_run /// ```rust,no_run
/// # use rusqlite::{Result,Connection}; /// # use rusqlite::{Result,Connection};
/// fn preferred_locale(conn: &Connection) -> Result<String> { /// fn preferred_locale(conn: &Connection) -> Result<String> {
/// conn.query_row_and_then("SELECT value FROM preferences WHERE name='locale'", &[], |row| { /// conn.query_row_and_then("SELECT value FROM preferences WHERE name='locale'",
/// &[],
/// |row| {
/// row.get_checked(0) /// row.get_checked(0)
/// }) /// })
/// } /// }
@ -710,9 +713,12 @@ impl<'conn> Statement<'conn> {
} }
/// Returns the column index in the result set for a given column name. /// Returns the column index in the result set for a given column name.
/// If there is no AS clause then the name of the column is unspecified and may change from one release of SQLite to the next. ///
/// If there is no AS clause then the name of the column is unspecified and may change from one
/// release of SQLite to the next.
/// ///
/// # Failure /// # Failure
///
/// Will return an `Error::InvalidColumnName` when there is no column with the specified `name`. /// Will return an `Error::InvalidColumnName` when there is no column with the specified `name`.
pub fn column_index(&self, name: &str) -> Result<i32> { pub fn column_index(&self, name: &str) -> Result<i32> {
let bytes = name.as_bytes(); let bytes = name.as_bytes();
@ -966,9 +972,7 @@ pub struct Rows<'stmt> {
impl<'stmt> Rows<'stmt> { impl<'stmt> Rows<'stmt> {
fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> { fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
Rows { Rows { stmt: Some(stmt) }
stmt: Some(stmt),
}
} }
fn get_expected_row<'a>(&'a mut self) -> Result<Row<'a, 'stmt>> { fn get_expected_row<'a>(&'a mut self) -> Result<Row<'a, 'stmt>> {
@ -1372,19 +1376,6 @@ mod test {
} }
} }
#[test]
#[should_panic]
fn test_rows_dropped() {
let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();
db.execute_batch("INSERT INTO foo(x) VALUES(1)").unwrap();
let mut stmt = db.prepare("SELECT x FROM foo").unwrap();
let row = stmt.query(&[]).unwrap().next().unwrap().unwrap();
assert_eq!(1i32, row.get(0));
}
mod query_and_then_tests { mod query_and_then_tests {
extern crate libsqlite3_sys as ffi; extern crate libsqlite3_sys as ffi;
use super::*; use super::*;

View File

@ -279,9 +279,10 @@ mod test {
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 mut rows = stmt.query_map_named(&[(":name", &"one")], |row| {
let id: i32 = row.get(0); let id: i32 = row.get(0);
2 * id 2 * id
}).unwrap(); })
.unwrap();
let doubled_id: i32 = rows.next().unwrap().unwrap(); let doubled_id: i32 = rows.next().unwrap().unwrap();
assert_eq!(2, doubled_id); assert_eq!(2, doubled_id);
@ -298,15 +299,17 @@ mod test {
"#; "#;
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC").unwrap(); let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC")
.unwrap();
let mut rows = stmt.query_and_then_named(&[(":name", &"one")], |row| { let mut rows = stmt.query_and_then_named(&[(":name", &"one")], |row| {
let id: i32 = row.get(0); let id: i32 = row.get(0);
if id == 1 { if id == 1 {
Ok(id) Ok(id)
} else { } else {
Err(Error::SqliteSingleThreadedMode) Err(Error::SqliteSingleThreadedMode)
} }
}).unwrap(); })
.unwrap();
// first row should be Ok // first row should be Ok
let doubled_id: i32 = rows.next().unwrap().unwrap(); let doubled_id: i32 = rows.next().unwrap().unwrap();

View File

@ -59,7 +59,8 @@ pub fn log(err_code: c_int, msg: &str) {
} }
impl Connection { impl Connection {
/// Register or clear a callback function that can be used for tracing the execution of SQL statements. /// Register or clear a callback function that can be used for tracing the execution of SQL
/// statements.
/// ///
/// Prepared statement placeholders are replaced/logged with their assigned values. /// Prepared statement placeholders are replaced/logged with their assigned values.
/// There can only be a single tracer defined for each database connection. /// There can only be a single tracer defined for each database connection.
@ -83,7 +84,8 @@ impl Connection {
} }
} }
/// Register or clear a callback function that can be used for profiling the execution of SQL statements. /// Register or clear a callback function that can be used for profiling the execution of SQL
/// statements.
/// ///
/// There can only be a single profiler defined for each database connection. /// There can only be a single profiler defined for each database connection.
/// Setting a new profiler clears the old one. /// Setting a new profiler clears the old one.

View File

@ -209,7 +209,10 @@ impl<'conn> Drop for Transaction<'conn> {
} }
impl<'conn> Savepoint<'conn> { impl<'conn> Savepoint<'conn> {
fn with_depth_and_name<T: Into<String>>(conn: &Connection, depth: u32, name: T) -> Result<Savepoint> { fn with_depth_and_name<T: Into<String>>(conn: &Connection,
depth: u32,
name: T)
-> Result<Savepoint> {
let name = name.into(); let name = name.into();
conn.execute_batch(&format!("SAVEPOINT {}", name)).map(|_| { conn.execute_batch(&format!("SAVEPOINT {}", name)).map(|_| {
Savepoint { Savepoint {
@ -349,7 +352,9 @@ impl Connection {
/// # Failure /// # Failure
/// ///
/// Will return `Err` if the underlying SQLite call fails. /// Will return `Err` if the underlying SQLite call fails.
pub fn transaction_with_behavior(&mut self, behavior: TransactionBehavior) -> Result<Transaction> { pub fn transaction_with_behavior(&mut self,
behavior: TransactionBehavior)
-> Result<Transaction> {
Transaction::new(self, behavior) Transaction::new(self, behavior)
} }

View File

@ -228,7 +228,7 @@ impl From<csv::Error> for Error {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use Connection; use {Connection,Result};
use vtab::csvtab; use vtab::csvtab;
#[test] #[test]
@ -244,13 +244,8 @@ mod test {
assert_eq!(vec!["rowid", "colA", "colB", "colC"], headers); assert_eq!(vec!["rowid", "colA", "colB", "colC"], headers);
} }
let rows = s.query(&[]).unwrap(); let ids: Result<Vec<i32>> = s.query_map(&[], |row| row.get::<i32, i32>(0)).unwrap().collect();
let mut sum = 0; let sum = ids.unwrap().iter().fold(0, |acc, &id| acc + id);
for row in rows {
let row = row.unwrap();
let id: i64 = row.get(0);
sum = sum + id;
}
assert_eq!(sum, 15); assert_eq!(sum, 15);
} }
db.execute_batch("DROP TABLE vtab").unwrap(); db.execute_batch("DROP TABLE vtab").unwrap();

View File

@ -163,14 +163,12 @@ mod test {
p3.borrow_mut().append(&mut vec![-1, -5, -10]); p3.borrow_mut().append(&mut vec![-1, -5, -10]);
{ {
let rows = s.query(&[]).unwrap(); s.query_map(&[], |row| {
for row in rows {
let row = row.unwrap();
let i1: i64 = row.get(0); let i1: i64 = row.get(0);
assert!(i1 == 1 || i1 == 3); assert!(i1 == 1 || i1 == 3);
assert_eq!(11, row.get(1)); assert_eq!(11, row.get(1));
assert_eq!(-5, row.get(2)); assert_eq!(-5, row.get(2));
} }).unwrap();
} }
p1.borrow_mut().clear(); p1.borrow_mut().clear();