mirror of
https://github.com/isar/rusqlite.git
synced 2025-02-01 16:00:50 +08:00
Fix tests and improve InvalidColumnType error message.
This commit is contained in:
parent
29373e7d0d
commit
42d95f042f
@ -54,7 +54,7 @@ pub enum Error {
|
||||
|
||||
/// Error when the value of a particular column is requested, but the type of the result in
|
||||
/// that column cannot be converted to the requested Rust type.
|
||||
InvalidColumnType,
|
||||
InvalidColumnType(c_int, c_int),
|
||||
|
||||
/// Error when a query that was expected to insert one row did not insert any or insert many.
|
||||
StatementChangedRows(c_int),
|
||||
@ -114,7 +114,7 @@ impl fmt::Display for Error {
|
||||
Error::GetFromStaleRow => write!(f, "Attempted to get a value from a stale row"),
|
||||
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
|
||||
Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
|
||||
Error::InvalidColumnType => write!(f, "Invalid column type"),
|
||||
Error::InvalidColumnType(i, t) => write!(f, "Invalid column type {} at index: {}", t, i),
|
||||
Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
|
||||
Error::StatementFailedToInsertRow => write!(f, "Statement failed to insert new row"),
|
||||
|
||||
@ -148,7 +148,7 @@ impl error::Error for Error {
|
||||
Error::GetFromStaleRow => "attempted to get a value from a stale row",
|
||||
Error::InvalidColumnIndex(_) => "invalid column index",
|
||||
Error::InvalidColumnName(_) => "invalid column name",
|
||||
Error::InvalidColumnType => "invalid column type",
|
||||
Error::InvalidColumnType(_, _) => "invalid column type",
|
||||
Error::StatementChangedRows(_) => "query inserted zero or more than one row",
|
||||
Error::StatementFailedToInsertRow => "statement failed to insert new row",
|
||||
|
||||
@ -176,7 +176,7 @@ impl error::Error for Error {
|
||||
Error::GetFromStaleRow |
|
||||
Error::InvalidColumnIndex(_) |
|
||||
Error::InvalidColumnName(_) |
|
||||
Error::InvalidColumnType |
|
||||
Error::InvalidColumnType(_, _) |
|
||||
Error::InvalidPath(_) => None,
|
||||
Error::StatementChangedRows(_) => None,
|
||||
Error::StatementFailedToInsertRow => None,
|
||||
|
26
src/lib.rs
26
src/lib.rs
@ -1131,10 +1131,9 @@ impl<'stmt> Row<'stmt> {
|
||||
unsafe {
|
||||
let idx = try!(idx.idx(self.stmt));
|
||||
|
||||
if T::column_has_valid_sqlite_type(self.stmt.stmt, idx) {
|
||||
FromSql::column_result(self.stmt.stmt, idx)
|
||||
} else {
|
||||
Err(Error::InvalidColumnType)
|
||||
match T::column_has_valid_sqlite_type(self.stmt.stmt, idx) {
|
||||
Ok(()) => FromSql::column_result(self.stmt.stmt, idx),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1456,6 +1455,19 @@ 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 {
|
||||
extern crate libsqlite3_sys as ffi;
|
||||
use super::*;
|
||||
@ -1536,7 +1548,7 @@ mod test {
|
||||
.collect();
|
||||
|
||||
match bad_type.unwrap_err() {
|
||||
Error::InvalidColumnType => (),
|
||||
Error::InvalidColumnType(_, _) => (),
|
||||
err => panic!("Unexpected error {}", err),
|
||||
}
|
||||
|
||||
@ -1596,7 +1608,7 @@ mod test {
|
||||
.collect();
|
||||
|
||||
match bad_type.unwrap_err() {
|
||||
CustomError::Sqlite(Error::InvalidColumnType) => (),
|
||||
CustomError::Sqlite(Error::InvalidColumnType(_, _)) => (),
|
||||
err => panic!("Unexpected error {}", err),
|
||||
}
|
||||
|
||||
@ -1658,7 +1670,7 @@ mod test {
|
||||
});
|
||||
|
||||
match bad_type.unwrap_err() {
|
||||
CustomError::Sqlite(Error::InvalidColumnType) => (),
|
||||
CustomError::Sqlite(Error::InvalidColumnType(_, _)) => (),
|
||||
err => panic!("Unexpected error {}", err),
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ impl FromSql for NaiveDate {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
String::column_has_valid_sqlite_type(stmt, col)
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ impl FromSql for NaiveTime {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
String::column_has_valid_sqlite_type(stmt, col)
|
||||
}
|
||||
}
|
||||
@ -86,7 +86,7 @@ impl FromSql for NaiveDateTime {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
String::column_has_valid_sqlite_type(stmt, col)
|
||||
}
|
||||
}
|
||||
@ -118,7 +118,7 @@ impl FromSql for DateTime<UTC> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
String::column_has_valid_sqlite_type(stmt, col)
|
||||
}
|
||||
}
|
||||
@ -130,7 +130,7 @@ impl FromSql for DateTime<Local> {
|
||||
Ok(utc_dt.with_timezone(&Local))
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
DateTime::<UTC>::column_has_valid_sqlite_type(stmt, col)
|
||||
}
|
||||
}
|
||||
|
@ -83,8 +83,17 @@ pub trait FromSql: Sized {
|
||||
/// the type reported by SQLite matches a type suitable for Self. This method is used
|
||||
/// by `Row::get_checked` to confirm that the column contains a valid type before
|
||||
/// attempting to retrieve the value.
|
||||
unsafe fn column_has_valid_sqlite_type(_: *mut sqlite3_stmt, _: c_int) -> bool {
|
||||
true
|
||||
unsafe fn column_has_valid_sqlite_type(_: *mut sqlite3_stmt, _: c_int) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_expected_typed(stmt: *mut sqlite3_stmt, col: c_int, expected_type: c_int) -> Result<()> {
|
||||
let actual_type = sqlite3_column_type(stmt, col);
|
||||
if actual_type == expected_type {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidColumnType(col, actual_type))
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,8 +206,8 @@ macro_rules! raw_from_impl(
|
||||
Ok(ffi::$f(stmt, col))
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
sqlite3_column_type(stmt, col) == $c
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
column_has_expected_typed(stmt, col, $c)
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -216,8 +225,8 @@ impl FromSql for bool {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_INTEGER
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
column_has_expected_typed(stmt, col, ffi::SQLITE_INTEGER)
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,8 +242,8 @@ impl FromSql for String {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_TEXT
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
column_has_expected_typed(stmt, col, ffi::SQLITE_TEXT)
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,8 +262,8 @@ impl FromSql for Vec<u8> {
|
||||
Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_BLOB
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
column_has_expected_typed(stmt, col, ffi::SQLITE_BLOB)
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,11 +276,14 @@ impl<T: FromSql> FromSql for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL ||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
if sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL {
|
||||
Ok(())
|
||||
} else {
|
||||
T::column_has_valid_sqlite_type(stmt, col)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dynamic type value (http://sqlite.org/datatype3.html)
|
||||
/// Value's type is dictated by SQLite (not by the caller).
|
||||
@ -297,7 +309,7 @@ impl FromSql for Value {
|
||||
ffi::SQLITE_FLOAT => Ok(Value::Real(ffi::sqlite3_column_double(stmt, col))),
|
||||
ffi::SQLITE_NULL => Ok(Value::Null),
|
||||
ffi::SQLITE_BLOB => FromSql::column_result(stmt, col).map(Value::Blob),
|
||||
_ => Err(Error::InvalidColumnType),
|
||||
ct => Err(Error::InvalidColumnType(col, ct)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -371,7 +383,7 @@ mod test {
|
||||
fn test_mismatched_types() {
|
||||
fn is_invalid_column_type(err: Error) -> bool {
|
||||
match err {
|
||||
Error::InvalidColumnType => true,
|
||||
Error::InvalidColumnType(_, _) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ impl FromSql for Value {
|
||||
let blob = try!(Vec::<u8>::column_result(stmt, col));
|
||||
serde_json::from_slice(&blob)
|
||||
}
|
||||
_ => return Err(Error::InvalidColumnType),
|
||||
ct => return Err(Error::InvalidColumnType(col, ct)),
|
||||
};
|
||||
value_result.map_err(|err| Error::FromSqlConversionFailure(Box::new(err)))
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ impl FromSql for time::Timespec {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> bool {
|
||||
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||
String::column_has_valid_sqlite_type(stmt, col)
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +267,8 @@ mod test {
|
||||
WHERE v1.rowid < v2.rowid")
|
||||
.unwrap();
|
||||
|
||||
let row = s.query(&[]).unwrap().next().unwrap().unwrap();
|
||||
let mut rows = s.query(&[]).unwrap();
|
||||
let row = rows.next().unwrap().unwrap();
|
||||
assert_eq!(row.get::<i32, i32>(0), 2);
|
||||
}
|
||||
db.execute_batch("DROP TABLE vtab").unwrap();
|
||||
|
@ -173,7 +173,6 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
s.reset_if_needed();
|
||||
p1.borrow_mut().clear();
|
||||
p2.borrow_mut().clear();
|
||||
p3.borrow_mut().clear();
|
||||
@ -182,18 +181,19 @@ mod test {
|
||||
p3.borrow_mut().append(&mut vec![-5, -10]);
|
||||
|
||||
{
|
||||
let row = s.query(&[]).unwrap().next().unwrap().unwrap();
|
||||
let mut rows = s.query(&[]).unwrap();
|
||||
let row = rows.next().unwrap().unwrap();
|
||||
assert_eq!(1, row.get(0));
|
||||
assert_eq!(11, row.get(1));
|
||||
assert_eq!(-5, row.get(2));
|
||||
}
|
||||
|
||||
s.reset_if_needed();
|
||||
p2.borrow_mut().clear();
|
||||
p3.borrow_mut().clear();
|
||||
p2.borrow_mut().append(&mut vec![3, 4, 5]);
|
||||
p3.borrow_mut().append(&mut vec![0, -5]);
|
||||
assert!(s.query(&[]).unwrap().next().is_none());
|
||||
let mut rows = s.query(&[]).unwrap();
|
||||
assert!(rows.next().is_none());
|
||||
|
||||
int_array::drop_int_array(&db, "ex1").unwrap();
|
||||
int_array::drop_int_array(&db, "ex2").unwrap();
|
||||
|
Loading…
x
Reference in New Issue
Block a user