mirror of
https://github.com/isar/rusqlite.git
synced 2025-05-16 22:17:49 +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
|
/// 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.
|
/// 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.
|
/// Error when a query that was expected to insert one row did not insert any or insert many.
|
||||||
StatementChangedRows(c_int),
|
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::GetFromStaleRow => write!(f, "Attempted to get a value from a stale row"),
|
||||||
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
|
Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
|
||||||
Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
|
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::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
|
||||||
Error::StatementFailedToInsertRow => write!(f, "Statement failed to insert new row"),
|
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::GetFromStaleRow => "attempted to get a value from a stale row",
|
||||||
Error::InvalidColumnIndex(_) => "invalid column index",
|
Error::InvalidColumnIndex(_) => "invalid column index",
|
||||||
Error::InvalidColumnName(_) => "invalid column name",
|
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::StatementChangedRows(_) => "query inserted zero or more than one row",
|
||||||
Error::StatementFailedToInsertRow => "statement failed to insert new row",
|
Error::StatementFailedToInsertRow => "statement failed to insert new row",
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ impl error::Error for Error {
|
|||||||
Error::GetFromStaleRow |
|
Error::GetFromStaleRow |
|
||||||
Error::InvalidColumnIndex(_) |
|
Error::InvalidColumnIndex(_) |
|
||||||
Error::InvalidColumnName(_) |
|
Error::InvalidColumnName(_) |
|
||||||
Error::InvalidColumnType |
|
Error::InvalidColumnType(_, _) |
|
||||||
Error::InvalidPath(_) => None,
|
Error::InvalidPath(_) => None,
|
||||||
Error::StatementChangedRows(_) => None,
|
Error::StatementChangedRows(_) => None,
|
||||||
Error::StatementFailedToInsertRow => None,
|
Error::StatementFailedToInsertRow => None,
|
||||||
|
26
src/lib.rs
26
src/lib.rs
@ -1131,10 +1131,9 @@ impl<'stmt> Row<'stmt> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let idx = try!(idx.idx(self.stmt));
|
let idx = try!(idx.idx(self.stmt));
|
||||||
|
|
||||||
if T::column_has_valid_sqlite_type(self.stmt.stmt, idx) {
|
match T::column_has_valid_sqlite_type(self.stmt.stmt, idx) {
|
||||||
FromSql::column_result(self.stmt.stmt, idx)
|
Ok(()) => FromSql::column_result(self.stmt.stmt, idx),
|
||||||
} else {
|
Err(e) => Err(e),
|
||||||
Err(Error::InvalidColumnType)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 {
|
mod query_and_then_tests {
|
||||||
extern crate libsqlite3_sys as ffi;
|
extern crate libsqlite3_sys as ffi;
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -1536,7 +1548,7 @@ mod test {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
match bad_type.unwrap_err() {
|
match bad_type.unwrap_err() {
|
||||||
Error::InvalidColumnType => (),
|
Error::InvalidColumnType(_, _) => (),
|
||||||
err => panic!("Unexpected error {}", err),
|
err => panic!("Unexpected error {}", err),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1596,7 +1608,7 @@ mod test {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
match bad_type.unwrap_err() {
|
match bad_type.unwrap_err() {
|
||||||
CustomError::Sqlite(Error::InvalidColumnType) => (),
|
CustomError::Sqlite(Error::InvalidColumnType(_, _)) => (),
|
||||||
err => panic!("Unexpected error {}", err),
|
err => panic!("Unexpected error {}", err),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1658,7 +1670,7 @@ mod test {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match bad_type.unwrap_err() {
|
match bad_type.unwrap_err() {
|
||||||
CustomError::Sqlite(Error::InvalidColumnType) => (),
|
CustomError::Sqlite(Error::InvalidColumnType(_, _)) => (),
|
||||||
err => panic!("Unexpected error {}", err),
|
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)
|
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)
|
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)
|
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)
|
String::column_has_valid_sqlite_type(stmt, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ impl FromSql for DateTime<Local> {
|
|||||||
Ok(utc_dt.with_timezone(&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)
|
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
|
/// 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
|
/// by `Row::get_checked` to confirm that the column contains a valid type before
|
||||||
/// attempting to retrieve the value.
|
/// attempting to retrieve the value.
|
||||||
unsafe fn column_has_valid_sqlite_type(_: *mut sqlite3_stmt, _: c_int) -> bool {
|
unsafe fn column_has_valid_sqlite_type(_: *mut sqlite3_stmt, _: c_int) -> Result<()> {
|
||||||
true
|
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))
|
Ok(ffi::$f(stmt, col))
|
||||||
}
|
}
|
||||||
|
|
||||||
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<()> {
|
||||||
sqlite3_column_type(stmt, col) == $c
|
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 {
|
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_INTEGER
|
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 {
|
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_TEXT
|
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())
|
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 {
|
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_BLOB
|
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 {
|
unsafe fn column_has_valid_sqlite_type(stmt: *mut sqlite3_stmt, col: c_int) -> Result<()> {
|
||||||
sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL ||
|
if sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
T::column_has_valid_sqlite_type(stmt, col)
|
T::column_has_valid_sqlite_type(stmt, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Dynamic type value (http://sqlite.org/datatype3.html)
|
/// Dynamic type value (http://sqlite.org/datatype3.html)
|
||||||
/// Value's type is dictated by SQLite (not by the caller).
|
/// 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_FLOAT => Ok(Value::Real(ffi::sqlite3_column_double(stmt, col))),
|
||||||
ffi::SQLITE_NULL => Ok(Value::Null),
|
ffi::SQLITE_NULL => Ok(Value::Null),
|
||||||
ffi::SQLITE_BLOB => FromSql::column_result(stmt, col).map(Value::Blob),
|
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 test_mismatched_types() {
|
||||||
fn is_invalid_column_type(err: Error) -> bool {
|
fn is_invalid_column_type(err: Error) -> bool {
|
||||||
match err {
|
match err {
|
||||||
Error::InvalidColumnType => true,
|
Error::InvalidColumnType(_, _) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ impl FromSql for Value {
|
|||||||
let blob = try!(Vec::<u8>::column_result(stmt, col));
|
let blob = try!(Vec::<u8>::column_result(stmt, col));
|
||||||
serde_json::from_slice(&blob)
|
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)))
|
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)
|
String::column_has_valid_sqlite_type(stmt, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,8 @@ mod test {
|
|||||||
WHERE v1.rowid < v2.rowid")
|
WHERE v1.rowid < v2.rowid")
|
||||||
.unwrap();
|
.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);
|
assert_eq!(row.get::<i32, i32>(0), 2);
|
||||||
}
|
}
|
||||||
db.execute_batch("DROP TABLE vtab").unwrap();
|
db.execute_batch("DROP TABLE vtab").unwrap();
|
||||||
|
@ -173,7 +173,6 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.reset_if_needed();
|
|
||||||
p1.borrow_mut().clear();
|
p1.borrow_mut().clear();
|
||||||
p2.borrow_mut().clear();
|
p2.borrow_mut().clear();
|
||||||
p3.borrow_mut().clear();
|
p3.borrow_mut().clear();
|
||||||
@ -182,18 +181,19 @@ mod test {
|
|||||||
p3.borrow_mut().append(&mut vec![-5, -10]);
|
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!(1, row.get(0));
|
||||||
assert_eq!(11, row.get(1));
|
assert_eq!(11, row.get(1));
|
||||||
assert_eq!(-5, row.get(2));
|
assert_eq!(-5, row.get(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
s.reset_if_needed();
|
|
||||||
p2.borrow_mut().clear();
|
p2.borrow_mut().clear();
|
||||||
p3.borrow_mut().clear();
|
p3.borrow_mut().clear();
|
||||||
p2.borrow_mut().append(&mut vec![3, 4, 5]);
|
p2.borrow_mut().append(&mut vec![3, 4, 5]);
|
||||||
p3.borrow_mut().append(&mut vec![0, -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, "ex1").unwrap();
|
||||||
int_array::drop_int_array(&db, "ex2").unwrap();
|
int_array::drop_int_array(&db, "ex2").unwrap();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user