This commit is contained in:
Gwenael Treguier 2015-12-13 11:05:11 +01:00
parent 6f0f121d61
commit 888dce0d8f

View File

@ -26,15 +26,37 @@ impl Connection {
/// ///
/// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string or if the /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string or if the
/// underlying SQLite BLOB open call fails. /// underlying SQLite BLOB open call fails.
pub fn blob_open<'a>(&'a self, db: &str, table: &str, column: &str, row: i64, read_only: bool) -> Result<Blob<'a>> { pub fn blob_open<'a>(&'a self,
db: &str,
table: &str,
column: &str,
row: i64,
read_only: bool)
-> Result<Blob<'a>> {
let mut c = self.db.borrow_mut(); let mut c = self.db.borrow_mut();
let mut blob = ptr::null_mut(); let mut blob = ptr::null_mut();
let db = try!(super::str_to_cstring(db)); let db = try!(super::str_to_cstring(db));
let table = try!(super::str_to_cstring(table)); let table = try!(super::str_to_cstring(table));
let column = try!(super::str_to_cstring(column)); let column = try!(super::str_to_cstring(column));
let rc = unsafe{ ffi::sqlite3_blob_open(c.db(), db.as_ptr(), table.as_ptr(), column.as_ptr(), row, if read_only { 0 } else { 1 }, &mut blob) }; let rc = unsafe {
ffi::sqlite3_blob_open(c.db(),
db.as_ptr(),
table.as_ptr(),
column.as_ptr(),
row,
if read_only {
0
} else {
1
},
&mut blob)
};
c.decode_result(rc).map(|_| { c.decode_result(rc).map(|_| {
Blob{ conn: self, blob: blob, pos: 0 } Blob {
conn: self,
blob: blob,
pos: 0,
}
}) })
} }
} }
@ -46,7 +68,7 @@ impl<'conn> Blob<'conn> {
/// ///
/// Will return `Err` if the underlying SQLite BLOB reopen call fails. /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
pub fn reopen(&mut self, row: i64) -> Result<()> { pub fn reopen(&mut self, row: i64) -> Result<()> {
let rc = unsafe{ ffi::sqlite3_blob_reopen(self.blob, row) }; let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
if rc != ffi::SQLITE_OK { if rc != ffi::SQLITE_OK {
return self.conn.decode_result(rc); return self.conn.decode_result(rc);
} }
@ -56,7 +78,7 @@ impl<'conn> Blob<'conn> {
/// Return the size in bytes of the BLOB /// Return the size in bytes of the BLOB
pub fn size(&self) -> i32 { pub fn size(&self) -> i32 {
unsafe{ ffi::sqlite3_blob_bytes(self.blob) } unsafe { ffi::sqlite3_blob_bytes(self.blob) }
} }
/// Read data from a BLOB incrementally /// Read data from a BLOB incrementally
@ -68,7 +90,7 @@ impl<'conn> Blob<'conn> {
if buf.len() > ::std::i32::MAX as usize { if buf.len() > ::std::i32::MAX as usize {
return Err(Error { return Err(Error {
code: ffi::SQLITE_TOOBIG, code: ffi::SQLITE_TOOBIG,
message: "buffer too long".to_string() message: "buffer too long".to_string(),
}); });
} }
let mut n = buf.len() as i32; let mut n = buf.len() as i32;
@ -79,7 +101,9 @@ impl<'conn> Blob<'conn> {
if n <= 0 { if n <= 0 {
return Ok(0); return Ok(0);
} }
let rc = unsafe { ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) }; let rc = unsafe {
ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
};
self.conn.decode_result(rc).map(|_| { self.conn.decode_result(rc).map(|_| {
self.pos += n; self.pos += n;
n n
@ -98,18 +122,23 @@ impl<'conn> Blob<'conn> {
if buf.len() > ::std::i32::MAX as usize { if buf.len() > ::std::i32::MAX as usize {
return Err(Error { return Err(Error {
code: ffi::SQLITE_TOOBIG, code: ffi::SQLITE_TOOBIG,
message: "buffer too long".to_string() message: "buffer too long".to_string(),
}); });
} }
let n = buf.len() as i32; let n = buf.len() as i32;
let size = self.size(); let size = self.size();
if self.pos + n > size { if self.pos + n > size {
return Err(Error{code: ffi::SQLITE_MISUSE, message: format!("pos = {} + n = {} > size = {}", self.pos, n, size)}); return Err(Error {
code: ffi::SQLITE_MISUSE,
message: format!("pos = {} + n = {} > size = {}", self.pos, n, size),
});
} }
if n <= 0 { if n <= 0 {
return Ok(0); return Ok(0);
} }
let rc = unsafe { ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) }; let rc = unsafe {
ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
};
self.conn.decode_result(rc).map(|_| { self.conn.decode_result(rc).map(|_| {
self.pos += n; self.pos += n;
n n
@ -118,10 +147,10 @@ impl<'conn> Blob<'conn> {
/// Seek to an offset, in bytes, in BLOB. /// Seek to an offset, in bytes, in BLOB.
pub fn seek(&mut self, pos: SeekFrom) { pub fn seek(&mut self, pos: SeekFrom) {
self.pos = match pos { self.pos = match pos {
SeekFrom::Start(offset) => offset, SeekFrom::Start(offset) => offset,
SeekFrom::Current(offset) => self.pos + offset, SeekFrom::Current(offset) => self.pos + offset,
SeekFrom::End(offset) => self.size() + offset SeekFrom::End(offset) => self.size() + offset,
}; };
} }
@ -152,7 +181,8 @@ impl<'conn> Drop for Blob<'conn> {
mod test { mod test {
use Connection; use Connection;
#[test] #[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_blob() { fn test_blob() {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory().unwrap();
let sql = "BEGIN; let sql = "BEGIN;
@ -165,7 +195,7 @@ mod test {
let mut blob = db.blob_open("main", "test", "content", rowid, false).unwrap(); let mut blob = db.blob_open("main", "test", "content", rowid, false).unwrap();
blob.write(b"Clob").unwrap(); blob.write(b"Clob").unwrap();
let err = blob.write(b"5678901"); let err = blob.write(b"5678901");
//writeln!(io::stderr(), "{:?}", err); // writeln!(io::stderr(), "{:?}", err);
assert!(err.is_err()); assert!(err.is_err());
assert!(blob.reopen(rowid).is_ok()); assert!(blob.reopen(rowid).is_ok());