Merge remote-tracking branch 'jgallagher/master' into fallible-iterator

This commit is contained in:
gwenn
2019-03-10 11:12:14 +01:00
19 changed files with 727 additions and 264 deletions

View File

@@ -3,7 +3,7 @@
//!
//! ```rust
//! use rusqlite::types::ToSql;
//! use rusqlite::{params, Connection};
//! use rusqlite::{params, Connection, Result};
//! use time::Timespec;
//!
//! #[derive(Debug)]
@@ -14,8 +14,8 @@
//! data: Option<Vec<u8>>,
//! }
//!
//! fn main() {
//! let conn = Connection::open_in_memory().unwrap();
//! fn main() -> Result<()> {
//! let conn = Connection::open_in_memory()?;
//!
//! conn.execute(
//! "CREATE TABLE person (
@@ -25,8 +25,7 @@
//! data BLOB
//! )",
//! params![],
//! )
//! .unwrap();
//! )?;
//! let me = Person {
//! id: 0,
//! name: "Steven".to_string(),
@@ -37,24 +36,22 @@
//! "INSERT INTO person (name, time_created, data)
//! VALUES (?1, ?2, ?3)",
//! params![me.name, me.time_created, me.data],
//! )
//! .unwrap();
//! )?;
//!
//! let mut stmt = conn
//! .prepare("SELECT id, name, time_created, data FROM person")
//! .unwrap();
//! let person_iter = stmt
//! .query_map(params![], |row| Person {
//! id: row.get(0),
//! name: row.get(1),
//! time_created: row.get(2),
//! data: row.get(3),
//! let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person")?;
//! let person_iter = stmt.query_map(params![], |row| {
//! Ok(Person {
//! id: row.get(0)?,
//! name: row.get(1)?,
//! time_created: row.get(2)?,
//! data: row.get(3)?,
//! })
//! .unwrap();
//! })?;
//!
//! for person in person_iter {
//! println!("Found person {:?}", person.unwrap());
//! }
//! Ok(())
//! }
//! ```
#![allow(unknown_lints)]
@@ -121,6 +118,7 @@ mod inner_connection;
pub mod limits;
#[cfg(feature = "load_extension")]
mod load_extension_guard;
mod pragma;
mod raw_statement;
mod row;
#[cfg(feature = "session")]
@@ -242,6 +240,42 @@ fn str_to_cstring(s: &str) -> Result<CString> {
Ok(CString::new(s)?)
}
/// Returns `Ok((string ptr, len as c_int, SQLITE_STATIC | SQLITE_TRANSIENT))`
/// normally.
/// Returns errors if the string has embedded nuls or is too large for sqlite.
/// The `sqlite3_destructor_type` item is always `SQLITE_TRANSIENT` unless
/// the string was empty (in which case it's `SQLITE_STATIC`, and the ptr is
/// static).
fn str_for_sqlite(s: &str) -> Result<(*const c_char, c_int, ffi::sqlite3_destructor_type)> {
let len = len_as_c_int(s.len())?;
if memchr::memchr(0, s.as_bytes()).is_none() {
let (ptr, dtor_info) = if len != 0 {
(s.as_ptr() as *const c_char, ffi::SQLITE_TRANSIENT())
} else {
// Return a pointer guaranteed to live forever
("".as_ptr() as *const c_char, ffi::SQLITE_STATIC())
};
Ok((ptr, len, dtor_info))
} else {
// There's an embedded nul, so we fabricate a NulError.
let e = CString::new(s);
Err(Error::NulError(e.unwrap_err()))
}
}
// Helper to cast to c_int safely, returning the correct error type if the cast
// failed.
fn len_as_c_int(len: usize) -> Result<c_int> {
if len >= (c_int::max_value() as usize) {
Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_TOOBIG),
None,
))
} else {
Ok(len as c_int)
}
}
fn path_to_cstring(p: &Path) -> Result<CString> {
let s = p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned()))?;
str_to_cstring(s)
@@ -478,7 +512,7 @@ impl Connection {
where
P: IntoIterator,
P::Item: ToSql,
F: FnOnce(&Row<'_>) -> T,
F: FnOnce(&Row<'_>) -> Result<T>,
{
let mut stmt = self.prepare(sql)?;
stmt.query_row(params, f)
@@ -500,12 +534,12 @@ impl Connection {
/// or if the underlying SQLite call fails.
pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &dyn ToSql)], f: F) -> Result<T>
where
F: FnOnce(&Row<'_>) -> T,
F: FnOnce(&Row<'_>) -> Result<T>,
{
let mut stmt = self.prepare(sql)?;
let mut rows = stmt.query_named(params)?;
rows.get_expected_row().map(|r| f(&r))
rows.get_expected_row().and_then(|r| f(&r))
}
/// Convenience method to execute a query that is expected to return a
@@ -521,7 +555,7 @@ impl Connection {
/// conn.query_row_and_then(
/// "SELECT value FROM preferences WHERE name='locale'",
/// NO_PARAMS,
/// |row| row.get_checked(0),
/// |row| row.get(0),
/// )
/// }
/// ```
@@ -692,7 +726,7 @@ impl Connection {
/// Return the number of rows modified, inserted or deleted by the most
/// recently completed INSERT, UPDATE or DELETE statement on the database
/// connection.
pub fn changes(&self) -> usize {
fn changes(&self) -> usize {
self.db.borrow_mut().changes()
}
@@ -863,9 +897,9 @@ mod test {
let tx2 = db2.transaction().unwrap();
// SELECT first makes sqlite lock with a shared lock
tx1.query_row("SELECT x FROM foo LIMIT 1", NO_PARAMS, |_| ())
tx1.query_row("SELECT x FROM foo LIMIT 1", NO_PARAMS, |_| Ok(()))
.unwrap();
tx2.query_row("SELECT x FROM foo LIMIT 1", NO_PARAMS, |_| ())
tx2.query_row("SELECT x FROM foo LIMIT 1", NO_PARAMS, |_| Ok(()))
.unwrap();
tx1.execute("INSERT INTO foo VALUES(?1)", &[1]).unwrap();
@@ -1066,7 +1100,7 @@ mod test {
let mut v = Vec::<i32>::new();
while let Some(row) = rows.next().unwrap() {
v.push(row.get(0));
v.push(row.get(0).unwrap());
}
assert_eq!(v, [3i32, 2, 1]);
@@ -1077,7 +1111,7 @@ mod test {
let mut v = Vec::<i32>::new();
while let Some(row) = rows.next().unwrap() {
v.push(row.get(0));
v.push(row.get(0).unwrap());
}
assert_eq!(v, [2i32, 1]);
@@ -1130,7 +1164,7 @@ mod test {
err => panic!("Unexpected error {}", err),
}
let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", NO_PARAMS, |_| ());
let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", NO_PARAMS, |_| Ok(()));
assert!(bad_query_result.is_err());
}
@@ -1404,7 +1438,7 @@ mod test {
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let results: Result<Vec<String>> = query
.query_and_then(NO_PARAMS, |row| row.get_checked(1))
.query_and_then(NO_PARAMS, |row| row.get(1))
.unwrap()
.collect();
@@ -1425,7 +1459,7 @@ mod test {
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let bad_type: Result<Vec<f64>> = query
.query_and_then(NO_PARAMS, |row| row.get_checked(1))
.query_and_then(NO_PARAMS, |row| row.get(1))
.unwrap()
.collect();
@@ -1435,7 +1469,7 @@ mod test {
}
let bad_idx: Result<Vec<String>> = query
.query_and_then(NO_PARAMS, |row| row.get_checked(3))
.query_and_then(NO_PARAMS, |row| row.get(3))
.unwrap()
.collect();
@@ -1459,9 +1493,7 @@ mod test {
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let results: CustomResult<Vec<String>> = query
.query_and_then(NO_PARAMS, |row| {
row.get_checked(1).map_err(CustomError::Sqlite)
})
.query_and_then(NO_PARAMS, |row| row.get(1).map_err(CustomError::Sqlite))
.unwrap()
.collect();
@@ -1482,9 +1514,7 @@ mod test {
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap();
let bad_type: CustomResult<Vec<f64>> = query
.query_and_then(NO_PARAMS, |row| {
row.get_checked(1).map_err(CustomError::Sqlite)
})
.query_and_then(NO_PARAMS, |row| row.get(1).map_err(CustomError::Sqlite))
.unwrap()
.collect();
@@ -1494,9 +1524,7 @@ mod test {
}
let bad_idx: CustomResult<Vec<String>> = query
.query_and_then(NO_PARAMS, |row| {
row.get_checked(3).map_err(CustomError::Sqlite)
})
.query_and_then(NO_PARAMS, |row| row.get(3).map_err(CustomError::Sqlite))
.unwrap()
.collect();
@@ -1527,7 +1555,7 @@ mod test {
let query = "SELECT x, y FROM foo ORDER BY x DESC";
let results: CustomResult<String> = db.query_row_and_then(query, NO_PARAMS, |row| {
row.get_checked(1).map_err(CustomError::Sqlite)
row.get(1).map_err(CustomError::Sqlite)
});
assert_eq!(results.unwrap(), "hello");
@@ -1544,7 +1572,7 @@ mod test {
let query = "SELECT x, y FROM foo ORDER BY x DESC";
let bad_type: CustomResult<f64> = db.query_row_and_then(query, NO_PARAMS, |row| {
row.get_checked(1).map_err(CustomError::Sqlite)
row.get(1).map_err(CustomError::Sqlite)
});
match bad_type.unwrap_err() {
@@ -1553,7 +1581,7 @@ mod test {
}
let bad_idx: CustomResult<String> = db.query_row_and_then(query, NO_PARAMS, |row| {
row.get_checked(3).map_err(CustomError::Sqlite)
row.get(3).map_err(CustomError::Sqlite)
});
match bad_idx.unwrap_err() {
@@ -1580,7 +1608,8 @@ mod test {
db.execute_batch(sql).unwrap();
db.query_row("SELECT * FROM foo", params![], |r| {
assert_eq!(2, r.column_count())
assert_eq!(2, r.column_count());
Ok(())
})
.unwrap();
}