From ba257b99bcf4e3b24247320f38f547cf5e8082c2 Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Sat, 1 Aug 2015 17:19:21 -0400 Subject: [PATCH] Add the possibility to read binary data --- src/statement.rs | 37 ++++++++++++++++++++++++++++++++++--- tests/lib.rs | 37 ++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/statement.rs b/src/statement.rs index dca27b1..67ef1fd 100644 --- a/src/statement.rs +++ b/src/statement.rs @@ -136,23 +136,36 @@ impl<'l> Parameter for &'l str { } } +impl<'l> Parameter for &'l [u8] { + #[inline] + fn bind(&self, statement: &mut Statement, i: usize) -> Result<()> { + debug_assert!(i > 0, "the indexing starts from 1"); + unsafe { + ok!(statement.raw.1, ffi::sqlite3_bind_blob(statement.raw.0, i as c_int, + self.as_ptr() as *const _, + self.len() as c_int, None)); + } + Ok(()) + } +} + impl Value for f64 { #[inline] - fn read(statement: &Statement, i: usize) -> Result { + fn read(statement: &Statement, i: usize) -> Result { Ok(unsafe { ffi::sqlite3_column_double(statement.raw.0, i as c_int) as f64 }) } } impl Value for i64 { #[inline] - fn read(statement: &Statement, i: usize) -> Result { + fn read(statement: &Statement, i: usize) -> Result { Ok(unsafe { ffi::sqlite3_column_int64(statement.raw.0, i as c_int) as i64 }) } } impl Value for String { #[inline] - fn read(statement: &Statement, i: usize) -> Result { + fn read(statement: &Statement, i: usize) -> Result { unsafe { let pointer = ffi::sqlite3_column_text(statement.raw.0, i as c_int); if pointer.is_null() { @@ -163,6 +176,24 @@ impl Value for String { } } +impl Value for Vec { + #[inline] + fn read(statement: &Statement, i: usize) -> Result { + use std::ptr::copy_nonoverlapping as copy; + unsafe { + let pointer = ffi::sqlite3_column_blob(statement.raw.0, i as c_int); + if pointer.is_null() { + return Ok(vec![]); + } + let count = ffi::sqlite3_column_bytes(statement.raw.0, i as c_int) as usize; + let mut buffer = Vec::with_capacity(count); + buffer.set_len(count); + copy(pointer as *const u8, buffer.as_mut_ptr(), count); + Ok(buffer) + } + } +} + #[inline] pub fn new<'l, T: AsRef>(raw1: *mut ffi::sqlite3, query: T) -> Result> { let mut raw0 = 0 as *mut _; diff --git a/tests/lib.rs b/tests/lib.rs index df5e4f1..99c9fe4 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -9,7 +9,7 @@ macro_rules! ok( ); #[test] -fn connection_execute() { +fn connection_error() { let connection = setup(":memory:"); match connection.execute(":)") { Err(error) => assert_eq!(error.message, Some(String::from(r#"unrecognized token: ":""#))), @@ -28,10 +28,11 @@ fn connection_process() { let mut done = false; let query = "SELECT * FROM users"; ok!(connection.process(query, |pairs| { - assert_eq!(pairs.len(), 3); + assert_eq!(pairs.len(), 4); assert_eq!(pairs[0], pair!("id", "1")); assert_eq!(pairs[1], pair!("name", "Alice")); assert_eq!(pairs[2], pair!("age", "42.69")); + assert_eq!(pairs[3], pair!("photo", "\x42\x69")); done = true; true })); @@ -52,11 +53,12 @@ fn connection_set_busy_handler() { thread::spawn(move || { let mut connection = ok!(sqlite::open(&path)); ok!(connection.set_busy_handler(|_| true)); - let query = "INSERT INTO `users` (id, name, age) VALUES (?, ?, ?)"; + let query = "INSERT INTO `users` (id, name, age, photo) VALUES (?, ?, ?, ?)"; let mut statement = ok!(connection.prepare(query)); ok!(statement.bind(1, 2i64)); ok!(statement.bind(2, "Bob")); - ok!(statement.bind(3, 20.99)); + ok!(statement.bind(3, 69.42)); + ok!(statement.bind(4, &[0x69u8, 0x42u8][..])); assert_eq!(ok!(statement.step()), State::Done); true }) @@ -73,11 +75,11 @@ fn statement_columns() { let query = "SELECT * FROM users"; let mut statement = ok!(connection.prepare(query)); - assert_eq!(statement.columns(), 3); + assert_eq!(statement.columns(), 4); assert_eq!(ok!(statement.step()), State::Row); - assert_eq!(statement.columns(), 3); + assert_eq!(statement.columns(), 4); } #[test] @@ -89,28 +91,31 @@ fn statement_kind() { assert_eq!(statement.kind(0), Type::Null); assert_eq!(statement.kind(1), Type::Null); assert_eq!(statement.kind(2), Type::Null); + assert_eq!(statement.kind(3), Type::Null); assert_eq!(ok!(statement.step()), State::Row); assert_eq!(statement.kind(0), Type::Integer); assert_eq!(statement.kind(1), Type::String); assert_eq!(statement.kind(2), Type::Float); + assert_eq!(statement.kind(3), Type::Blob); } #[test] -fn statement_insert() { +fn statement_bind() { let connection = setup(":memory:"); - let query = "INSERT INTO users (id, name, age) VALUES (?, ?, ?)"; + let query = "INSERT INTO users (id, name, age, photo) VALUES (?, ?, ?, ?)"; let mut statement = ok!(connection.prepare(query)); ok!(statement.bind(1, 2i64)); ok!(statement.bind(2, "Bob")); - ok!(statement.bind(3, 20.99)); + ok!(statement.bind(3, 69.42)); + ok!(statement.bind(4, &[0x69u8, 0x42u8][..])); assert_eq!(ok!(statement.step()), State::Done); } #[test] -fn statement_select() { +fn statement_read() { let connection = setup(":memory:"); let query = "SELECT * FROM users"; let mut statement = ok!(connection.prepare(query)); @@ -119,17 +124,15 @@ fn statement_select() { assert_eq!(ok!(statement.read::(0)), 1); assert_eq!(ok!(statement.read::(1)), String::from("Alice")); assert_eq!(ok!(statement.read::(2)), 42.69); + assert_eq!(ok!(statement.read::>(3)), vec![0x42, 0x69]); assert_eq!(ok!(statement.step()), State::Done); } fn setup>(path: T) -> Connection { let connection = ok!(sqlite::open(path)); - - let query = "CREATE TABLE users (id INTEGER, name VARCHAR(255), age REAL)"; - ok!(connection.execute(query)); - - let query = "INSERT INTO users (id, name, age) VALUES (1, 'Alice', 42.69)"; - ok!(connection.execute(query)); - + ok!(connection.execute(" + CREATE TABLE users (id INTEGER, name VARCHAR(255), age REAL, photo BLOB); + INSERT INTO users (id, name, age, photo) VALUES (1, 'Alice', 42.69, X'4269'); + ")); connection }