mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Merge branch 'dynamic' of https://github.com/gwenn/rusqlite into gwenn-dynamic
This commit is contained in:
commit
f290c15d0d
24
src/lib.rs
24
src/lib.rs
@ -728,6 +728,11 @@ impl<'conn> Statement<'conn> {
|
||||
cols
|
||||
}
|
||||
|
||||
/// Return the number of columns in the result set returned by the prepared statement.
|
||||
pub fn column_count(&self) -> i32 {
|
||||
self.column_count
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
@ -1131,6 +1136,11 @@ impl<'stmt> Row<'stmt> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of columns in the current row.
|
||||
pub fn column_count(&self) -> i32 {
|
||||
self.stmt.column_count()
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait implemented by types that can index into columns of a row.
|
||||
@ -1267,9 +1277,11 @@ mod test {
|
||||
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap();
|
||||
|
||||
let stmt = db.prepare("SELECT * FROM foo").unwrap();
|
||||
assert_eq!(stmt.column_count(), 1);
|
||||
assert_eq!(stmt.column_names(), vec!["x"]);
|
||||
|
||||
let stmt = db.prepare("SELECT x AS a, x AS b FROM foo").unwrap();
|
||||
assert_eq!(stmt.column_count(), 2);
|
||||
assert_eq!(stmt.column_names(), vec!["a", "b"]);
|
||||
}
|
||||
|
||||
@ -1668,5 +1680,17 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
fn test_dynamic() {
|
||||
let db = checked_memory_handle();
|
||||
let sql = "BEGIN;
|
||||
CREATE TABLE foo(x INTEGER, y TEXT);
|
||||
INSERT INTO foo VALUES(4, \"hello\");
|
||||
END;";
|
||||
db.execute_batch(sql).unwrap();
|
||||
|
||||
db.query_row("SELECT * FROM foo", &[], |r| assert_eq!(2, r.column_count())).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
61
src/types.rs
61
src/types.rs
@ -96,7 +96,7 @@ macro_rules! raw_to_impl(
|
||||
)
|
||||
);
|
||||
|
||||
raw_to_impl!(c_int, sqlite3_bind_int);
|
||||
raw_to_impl!(c_int, sqlite3_bind_int); // i32
|
||||
raw_to_impl!(i64, sqlite3_bind_int64);
|
||||
raw_to_impl!(c_double, sqlite3_bind_double);
|
||||
|
||||
@ -208,9 +208,9 @@ macro_rules! raw_from_impl(
|
||||
)
|
||||
);
|
||||
|
||||
raw_from_impl!(c_int, sqlite3_column_int, ffi::SQLITE_INTEGER);
|
||||
raw_from_impl!(c_int, sqlite3_column_int, ffi::SQLITE_INTEGER); // i32
|
||||
raw_from_impl!(i64, sqlite3_column_int64, ffi::SQLITE_INTEGER);
|
||||
raw_from_impl!(c_double, sqlite3_column_double, ffi::SQLITE_FLOAT);
|
||||
raw_from_impl!(c_double, sqlite3_column_double, ffi::SQLITE_FLOAT); // f64
|
||||
|
||||
impl FromSql for bool {
|
||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<bool> {
|
||||
@ -293,6 +293,39 @@ impl<T: FromSql> FromSql for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Dynamic type value (http://sqlite.org/datatype3.html)
|
||||
/// Value's type is dictated by SQLite (not by the caller).
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum Value {
|
||||
/// The value is a `NULL` value.
|
||||
Null,
|
||||
/// The value is a signed integer.
|
||||
Integer(i64),
|
||||
/// The value is a floating point number.
|
||||
Real(f64),
|
||||
/// The value is a text string.
|
||||
Text(String),
|
||||
/// The value is a blob of data
|
||||
Blob(Vec<u8>),
|
||||
}
|
||||
|
||||
impl FromSql for Value {
|
||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<Value> {
|
||||
match sqlite3_column_type(stmt, col) {
|
||||
ffi::SQLITE_TEXT => FromSql::column_result(stmt, col).map(|t| Value::Text(t)),
|
||||
ffi::SQLITE_INTEGER => Ok(Value::Integer(ffi::sqlite3_column_int64(stmt, col))),
|
||||
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(|t| Value::Blob(t)),
|
||||
_ => Err(Error::InvalidColumnType),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn column_has_valid_sqlite_type(_: *mut sqlite3_stmt, _: c_int) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use Connection;
|
||||
@ -438,4 +471,26 @@ mod test {
|
||||
assert!(is_invalid_column_type(row.get_checked::<i32,Vec<u8>>(4).err().unwrap()));
|
||||
assert!(is_invalid_column_type(row.get_checked::<i32,time::Timespec>(4).err().unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dynamic_type() {
|
||||
use super::Value;
|
||||
let db = checked_memory_handle();
|
||||
|
||||
db.execute("INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)",
|
||||
&[])
|
||||
.unwrap();
|
||||
|
||||
let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo").unwrap();
|
||||
let mut rows = stmt.query(&[]).unwrap();
|
||||
|
||||
let row = rows.next().unwrap().unwrap();
|
||||
assert_eq!(Value::Blob(vec![1, 2]),
|
||||
row.get_checked::<i32,Value>(0).unwrap());
|
||||
assert_eq!(Value::Text(String::from("text")),
|
||||
row.get_checked::<i32,Value>(1).unwrap());
|
||||
assert_eq!(Value::Integer(1), row.get_checked::<i32,Value>(2).unwrap());
|
||||
assert_eq!(Value::Real(1.5), row.get_checked::<i32,Value>(3).unwrap());
|
||||
assert_eq!(Value::Null, row.get_checked::<i32,Value>(4).unwrap());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user