mirror of
https://github.com/isar/rusqlite.git
synced 2025-08-20 21:09:31 +08:00
Merge branch 'master' into gwenn-stmt-cache
This commit is contained in:
18
src/blob.rs
18
src/blob.rs
@@ -17,6 +17,7 @@
|
||||
//! extern crate rusqlite;
|
||||
//!
|
||||
//! use rusqlite::{Connection, DatabaseName};
|
||||
//! use rusqlite::blob::ZeroBlob;
|
||||
//! use std::io::{Read, Write, Seek, SeekFrom};
|
||||
//!
|
||||
//! fn main() {
|
||||
@@ -38,7 +39,7 @@
|
||||
//! let bytes_read = blob.read(&mut buf[..]).unwrap();
|
||||
//! assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
|
||||
//!
|
||||
//! db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(64))", &[]).unwrap();
|
||||
//! db.execute("INSERT INTO test (content) VALUES (?)", &[&ZeroBlob(64)]).unwrap();
|
||||
//!
|
||||
//! // given a new row ID, we can reopen the blob on that row
|
||||
//! let rowid = db.last_insert_rowid();
|
||||
@@ -51,8 +52,10 @@ use std::io;
|
||||
use std::cmp::min;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use libc::c_int;
|
||||
|
||||
use super::ffi;
|
||||
use super::types::ToSql;
|
||||
use {Result, Connection, DatabaseName};
|
||||
|
||||
/// Handle to an open BLOB.
|
||||
@@ -232,6 +235,19 @@ impl<'conn> Drop for Blob<'conn> {
|
||||
}
|
||||
}
|
||||
|
||||
/// BLOB of length N that is filled with zeroes.
|
||||
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using incremental BLOB I/O routines.
|
||||
/// A negative value for the zeroblob results in a zero-length BLOB.
|
||||
#[derive(Copy,Clone)]
|
||||
pub struct ZeroBlob(pub i32);
|
||||
|
||||
impl ToSql for ZeroBlob {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
|
||||
let ZeroBlob(length) = *self;
|
||||
ffi::sqlite3_bind_zeroblob(stmt, col, length)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::io::{BufReader, BufRead, BufWriter, Read, Write, Seek, SeekFrom};
|
||||
|
@@ -489,9 +489,10 @@ impl InnerConnection {
|
||||
where D: Aggregate<A, T>,
|
||||
T: ToResult
|
||||
{
|
||||
unsafe fn aggregate_context<A>(ctx: *mut sqlite3_context) -> Option<*mut *mut A> {
|
||||
let pac = ffi::sqlite3_aggregate_context(ctx, ::std::mem::size_of::<*mut A>() as c_int)
|
||||
as *mut *mut A;
|
||||
unsafe fn aggregate_context<A>(ctx: *mut sqlite3_context,
|
||||
bytes: usize)
|
||||
-> Option<*mut *mut A> {
|
||||
let pac = ffi::sqlite3_aggregate_context(ctx, bytes as c_int) as *mut *mut A;
|
||||
if pac.is_null() {
|
||||
return None;
|
||||
}
|
||||
@@ -525,7 +526,7 @@ impl InnerConnection {
|
||||
assert!(!boxed_aggr.is_null(),
|
||||
"Internal error - null aggregate pointer");
|
||||
|
||||
let pac = match aggregate_context(ctx) {
|
||||
let pac = match aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
|
||||
Some(pac) => pac,
|
||||
None => {
|
||||
ffi::sqlite3_result_error_nomem(ctx);
|
||||
@@ -556,19 +557,18 @@ impl InnerConnection {
|
||||
assert!(!boxed_aggr.is_null(),
|
||||
"Internal error - null aggregate pointer");
|
||||
|
||||
let pac = match aggregate_context(ctx) {
|
||||
Some(pac) => pac,
|
||||
None => {
|
||||
ffi::sqlite3_result_error_nomem(ctx);
|
||||
return;
|
||||
// Within the xFinal callback, it is customary to set N=0 in calls to
|
||||
// sqlite3_aggregate_context(C,N) so that no pointless memory allocations occur.
|
||||
let a: Option<A> = match aggregate_context(ctx, 0) {
|
||||
Some(pac) => {
|
||||
if (*pac).is_null() {
|
||||
None
|
||||
} else {
|
||||
let a = Box::from_raw(*pac);
|
||||
Some(*a)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let a: Option<A> = if (*pac).is_null() {
|
||||
None
|
||||
} else {
|
||||
let a = Box::from_raw(*pac);
|
||||
Some(*a)
|
||||
None => None,
|
||||
};
|
||||
|
||||
match (*boxed_aggr).finalize(a) {
|
||||
|
23
src/lib.rs
23
src/lib.rs
@@ -495,6 +495,18 @@ impl Connection {
|
||||
self.db.borrow_mut().load_extension(dylib_path.as_ref(), entry_point)
|
||||
}
|
||||
|
||||
/// Get access to the underlying SQLite database connection handle.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// You should not need to use this function. If you do need to, please [open an issue
|
||||
/// on the rusqlite repository](https://github.com/jgallagher/rusqlite/issues) and describe
|
||||
/// your use case. This function is unsafe because it gives you raw access to the SQLite
|
||||
/// connection, and what you do with it could impact the safety of this `Connection`.
|
||||
pub unsafe fn handle(&self) -> *mut ffi::Struct_sqlite3 {
|
||||
self.db.borrow().db()
|
||||
}
|
||||
|
||||
fn decode_result(&self, code: c_int) -> Result<()> {
|
||||
self.db.borrow_mut().decode_result(code)
|
||||
}
|
||||
@@ -999,6 +1011,9 @@ pub type SqliteRows<'stmt> = Rows<'stmt>;
|
||||
///
|
||||
/// ## Warning
|
||||
///
|
||||
/// Strongly consider using `query_map` or `query_and_then` instead of `query`; the former do not
|
||||
/// suffer from the following problem.
|
||||
///
|
||||
/// Due to the way SQLite returns result rows of a query, it is not safe to attempt to get values
|
||||
/// from a row after it has become stale (i.e., `next()` has been called again on the `Rows`
|
||||
/// iterator). For example:
|
||||
@@ -1010,7 +1025,7 @@ pub type SqliteRows<'stmt> = Rows<'stmt>;
|
||||
/// let mut rows = try!(stmt.query(&[]));
|
||||
///
|
||||
/// let row0 = try!(rows.next().unwrap());
|
||||
/// // row 0 is value now...
|
||||
/// // row 0 is valid for now...
|
||||
///
|
||||
/// let row1 = try!(rows.next().unwrap());
|
||||
/// // row 0 is now STALE, and row 1 is valid
|
||||
@@ -1024,12 +1039,6 @@ pub type SqliteRows<'stmt> = Rows<'stmt>;
|
||||
/// (which would result in a collection of rows, only the last of which can safely be used) and
|
||||
/// `min`/`max` (which could return a stale row unless the last row happened to be the min or max,
|
||||
/// respectively).
|
||||
///
|
||||
/// This problem could be solved by changing the signature of `next` to tie the lifetime of the
|
||||
/// returned row to the lifetime of (a mutable reference to) the result rows handle, but this would
|
||||
/// no longer implement `Iterator`, and therefore you would lose access to the majority of
|
||||
/// functions which are useful (such as support for `for ... in ...` looping, `map`, `filter`,
|
||||
/// etc.).
|
||||
pub struct Rows<'stmt> {
|
||||
stmt: &'stmt Statement<'stmt>,
|
||||
current_row: Rc<Cell<c_int>>,
|
||||
|
Reference in New Issue
Block a user