Implement column reading

This commit is contained in:
Ivan Ukhov 2015-05-29 13:08:02 -04:00
parent f7f9af43ed
commit ae0a12444b
4 changed files with 74 additions and 26 deletions

View File

@ -67,21 +67,12 @@ impl<'l> Drop for Database<'l> {
extern fn execute_callback(callback: *mut c_void, count: c_int, values: *mut *mut c_char,
columns: *mut *mut c_char) -> c_int {
macro_rules! c_str_to_string(
($string:expr) => (
match ::std::str::from_utf8(::std::ffi::CStr::from_ptr($string).to_bytes()) {
Ok(string) => String::from(string),
Err(_) => return 1,
}
);
);
unsafe {
let mut pairs = Vec::with_capacity(count as usize);
for i in 0..(count as isize) {
let column = c_str_to_string!(*columns.offset(i) as *const _);
let value = c_str_to_string!(*values.offset(i) as *const _);
let column = c_str_to_string!(*columns.offset(i));
let value = c_str_to_string!(*values.offset(i));
pairs.push((column, value));
}

View File

@ -98,6 +98,13 @@ macro_rules! str_to_c_str(
);
);
macro_rules! c_str_to_string(
($cstr:expr) => (
String::from_utf8_lossy(::std::ffi::CStr::from_ptr($cstr as *const _).to_bytes())
.into_owned()
);
);
mod database;
mod statement;

View File

@ -17,6 +17,12 @@ pub enum Binding<'l> {
Text(usize, &'l str),
}
/// A value stored in a column.
pub trait Value {
/// Read the value from a prepared statement at a specific position.
fn read(statement: &mut Statement, i: usize) -> Result<Self>;
}
impl<'l> Statement<'l> {
/// Assign values to the placeholders.
pub fn bind(&mut self, bindings: &[Binding]) -> Result<()> {
@ -38,6 +44,12 @@ impl<'l> Statement<'l> {
Ok(())
}
/// Return the value of a column.
#[inline]
pub fn column<T: Value>(&mut self, i: usize) -> Result<T> {
<T as Value>::read(self, i)
}
/// Take a step.
#[inline]
pub fn step(&mut self) -> ResultCode {
@ -59,6 +71,30 @@ impl<'l> Drop for Statement<'l> {
}
}
impl Value for f64 {
fn read(statement: &mut Statement, i: usize) -> Result<f64> {
Ok(unsafe { ::raw::sqlite3_column_double(statement.raw, i as c_int) as f64 })
}
}
impl Value for i64 {
fn read(statement: &mut Statement, i: usize) -> Result<i64> {
Ok(unsafe { ::raw::sqlite3_column_int64(statement.raw, i as c_int) as i64 })
}
}
impl Value for String {
fn read(statement: &mut Statement, i: usize) -> Result<String> {
unsafe {
let pointer = ::raw::sqlite3_column_text(statement.raw, i as c_int);
if pointer.is_null() {
raise!("cannot read a TEXT column");
}
Ok(c_str_to_string!(pointer))
}
}
}
#[inline]
pub fn from_raw<'l>(raw: *mut raw::sqlite3_stmt) -> Statement<'l> {
Statement { raw: raw, _phantom: PhantomData }

View File

@ -23,22 +23,36 @@ fn workflow() {
let sql = r#"CREATE TABLE `users` (id INTEGER, name VARCHAR(255), age REAL);"#;
ok!(database.execute(sql, None));
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
let mut statement = ok!(database.statement(sql));
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
assert!(statement.step() == ResultCode::Done);
{
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
let mut statement = ok!(database.statement(sql));
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
assert!(statement.step() == ResultCode::Done);
}
let mut done = false;
let sql = r#"SELECT * FROM `users`;"#;
ok!(database.execute(sql, Some(&mut |pairs: Vec<(String, String)>| -> bool {
assert!(pairs.len() == 3);
assert!(pairs[0] == pair!("id", "1"));
assert!(pairs[1] == pair!("name", "Alice"));
assert!(pairs[2] == pair!("age", "20.99"));
done = true;
true
})));
assert!(done);
{
let mut done = false;
let sql = r#"SELECT * FROM `users`;"#;
ok!(database.execute(sql, Some(&mut |pairs: Vec<(String, String)>| -> bool {
assert!(pairs.len() == 3);
assert!(pairs[0] == pair!("id", "1"));
assert!(pairs[1] == pair!("name", "Alice"));
assert!(pairs[2] == pair!("age", "20.99"));
done = true;
true
})));
assert!(done);
}
{
let sql = r#"SELECT * FROM `users`;"#;
let mut statement = ok!(database.statement(sql));
assert!(statement.step() == ResultCode::Row);
assert!(ok!(statement.column::<i64>(0)) == 1);
assert!(ok!(statement.column::<String>(1)) == String::from("Alice"));
assert!(ok!(statement.column::<f64>(2)) == 20.99);
assert!(statement.step() == ResultCode::Done);
}
}
fn setup() -> (PathBuf, Directory) {