Merge remote-tracking branch 'jgallagher/master' into vtab

This commit is contained in:
gwenn 2016-05-16 22:30:58 +02:00
commit 29373e7d0d
9 changed files with 79 additions and 84 deletions

View File

@ -23,7 +23,7 @@ csvtab = ["csv"]
[dependencies] [dependencies]
time = "~0.1.0" time = "~0.1.0"
bitflags = "~0.1" bitflags = "0.7"
libc = "~0.2" libc = "~0.2"
clippy = {version = "~0.0.58", optional = true} clippy = {version = "~0.0.58", optional = true}
chrono = { version = "~0.2", optional = true } chrono = { version = "~0.2", optional = true }

View File

@ -1,5 +1,5 @@
environment: environment:
TARGET: 1.6.0-x86_64-pc-windows-gnu TARGET: 1.8.0-x86_64-pc-windows-gnu
MSYS2_BITS: 64 MSYS2_BITS: 64
install: install:
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe"

View File

@ -159,9 +159,8 @@ impl<'conn> io::Read for Blob<'conn> {
if n <= 0 { if n <= 0 {
return Ok(0); return Ok(0);
} }
let rc = unsafe { let rc =
ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) unsafe { ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos) };
};
self.conn self.conn
.decode_result(rc) .decode_result(rc)
.map(|_| { .map(|_| {

View File

@ -23,12 +23,14 @@ impl<'conn> Statement<'conn> {
/// Return `true` if a query in the SQL statement it executes returns one or more rows /// Return `true` if a query in the SQL statement it executes returns one or more rows
/// and `false` if the SQL returns an empty set. /// and `false` if the SQL returns an empty set.
pub fn exists(&mut self, params: &[&ToSql]) -> Result<bool> { pub fn exists(&mut self, params: &[&ToSql]) -> Result<bool> {
self.reset_if_needed();
let mut rows = try!(self.query(params)); let mut rows = try!(self.query(params));
let exists = {
match rows.next() { match rows.next() {
Some(_) => Ok(true), Some(_) => true,
None => Ok(false), None => false,
} }
};
Ok(exists)
} }
} }

View File

@ -538,7 +538,7 @@ bitflags! {
#[doc = "Flags for opening SQLite database connections."] #[doc = "Flags for opening SQLite database connections."]
#[doc = "See [sqlite3_open_v2](http://www.sqlite.org/c3ref/open.html) for details."] #[doc = "See [sqlite3_open_v2](http://www.sqlite.org/c3ref/open.html) for details."]
#[repr(C)] #[repr(C)]
flags OpenFlags: c_int { pub flags OpenFlags: ::libc::c_int {
const SQLITE_OPEN_READ_ONLY = 0x00000001, const SQLITE_OPEN_READ_ONLY = 0x00000001,
const SQLITE_OPEN_READ_WRITE = 0x00000002, const SQLITE_OPEN_READ_WRITE = 0x00000002,
const SQLITE_OPEN_CREATE = 0x00000004, const SQLITE_OPEN_CREATE = 0x00000004,
@ -709,7 +709,6 @@ pub type SqliteStatement<'conn> = Statement<'conn>;
pub struct Statement<'conn> { pub struct Statement<'conn> {
conn: &'conn Connection, conn: &'conn Connection,
stmt: *mut ffi::sqlite3_stmt, stmt: *mut ffi::sqlite3_stmt,
needs_reset: bool,
column_count: c_int, column_count: c_int,
} }
@ -718,7 +717,6 @@ impl<'conn> Statement<'conn> {
Statement { Statement {
conn: conn, conn: conn,
stmt: stmt, stmt: stmt,
needs_reset: false,
column_count: unsafe { ffi::sqlite3_column_count(stmt) }, column_count: unsafe { ffi::sqlite3_column_count(stmt) },
} }
} }
@ -827,13 +825,10 @@ impl<'conn> Statement<'conn> {
/// ///
/// Will return `Err` if binding parameters fails. /// Will return `Err` if binding parameters fails.
pub fn query<'a>(&'a mut self, params: &[&ToSql]) -> Result<Rows<'a>> { pub fn query<'a>(&'a mut self, params: &[&ToSql]) -> Result<Rows<'a>> {
self.reset_if_needed();
unsafe { unsafe {
try!(self.bind_parameters(params)); try!(self.bind_parameters(params));
} }
self.needs_reset = true;
Ok(Rows::new(self)) Ok(Rows::new(self))
} }
@ -907,15 +902,6 @@ impl<'conn> Statement<'conn> {
Ok(()) Ok(())
} }
fn reset_if_needed(&mut self) {
if self.needs_reset {
unsafe {
ffi::sqlite3_reset(self.stmt);
};
self.needs_reset = false;
}
}
fn finalize_(&mut self) -> Result<()> { fn finalize_(&mut self) -> Result<()> {
let r = unsafe { ffi::sqlite3_finalize(self.stmt) }; let r = unsafe { ffi::sqlite3_finalize(self.stmt) };
self.stmt = ptr::null_mut(); self.stmt = ptr::null_mut();
@ -1017,17 +1003,15 @@ pub type SqliteRows<'stmt> = Rows<'stmt>;
/// `min`/`max` (which could return a stale row unless the last row happened to be the min or max, /// `min`/`max` (which could return a stale row unless the last row happened to be the min or max,
/// respectively). /// respectively).
pub struct Rows<'stmt> { pub struct Rows<'stmt> {
stmt: &'stmt Statement<'stmt>, stmt: Option<&'stmt Statement<'stmt>>,
current_row: Rc<Cell<c_int>>, current_row: Rc<Cell<c_int>>,
failed: bool,
} }
impl<'stmt> Rows<'stmt> { impl<'stmt> Rows<'stmt> {
fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> { fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
Rows { Rows {
stmt: stmt, stmt: Some(stmt),
current_row: Rc::new(Cell::new(0)), current_row: Rc::new(Cell::new(0)),
failed: false,
} }
} }
@ -1037,31 +1021,47 @@ impl<'stmt> Rows<'stmt> {
None => Err(Error::QueryReturnedNoRows), None => Err(Error::QueryReturnedNoRows),
} }
} }
fn reset(&mut self) {
if let Some(stmt) = self.stmt.take() {
unsafe {
ffi::sqlite3_reset(stmt.stmt);
}
}
}
} }
impl<'stmt> Iterator for Rows<'stmt> { impl<'stmt> Iterator for Rows<'stmt> {
type Item = Result<Row<'stmt>>; type Item = Result<Row<'stmt>>;
fn next(&mut self) -> Option<Result<Row<'stmt>>> { fn next(&mut self) -> Option<Result<Row<'stmt>>> {
if self.failed { self.stmt.and_then(|stmt| {
return None; match unsafe { ffi::sqlite3_step(stmt.stmt) } {
}
match unsafe { ffi::sqlite3_step(self.stmt.stmt) } {
ffi::SQLITE_ROW => { ffi::SQLITE_ROW => {
let current_row = self.current_row.get() + 1; let current_row = self.current_row.get() + 1;
self.current_row.set(current_row); self.current_row.set(current_row);
Some(Ok(Row { Some(Ok(Row {
stmt: self.stmt, stmt: stmt,
current_row: self.current_row.clone(), current_row: self.current_row.clone(),
row_idx: current_row, row_idx: current_row,
})) }))
} }
ffi::SQLITE_DONE => None, ffi::SQLITE_DONE => {
self.reset();
None
}
code => { code => {
self.failed = true; self.reset();
Some(Err(self.stmt.conn.decode_result(code).unwrap_err())) Some(Err(stmt.conn.decode_result(code).unwrap_err()))
} }
} }
})
}
}
impl<'stmt> Drop for Rows<'stmt> {
fn drop(&mut self) {
self.reset();
} }
} }

View File

@ -113,10 +113,7 @@ impl<'conn> Statement<'conn> {
/// ///
/// Will return `Err` if binding parameters fails. /// Will return `Err` if binding parameters fails.
pub fn query_named<'a>(&'a mut self, params: &[(&str, &ToSql)]) -> Result<Rows<'a>> { pub fn query_named<'a>(&'a mut self, params: &[(&str, &ToSql)]) -> Result<Rows<'a>> {
self.reset_if_needed();
try!(self.bind_parameters_named(params)); try!(self.bind_parameters_named(params));
self.needs_reset = true;
Ok(Rows::new(self)) Ok(Rows::new(self))
} }
@ -190,9 +187,8 @@ mod test {
let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)").unwrap(); let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)").unwrap();
stmt.execute_named(&[(":x", &"one")]).unwrap(); stmt.execute_named(&[(":x", &"one")]).unwrap();
let result: Option<String> = db.query_row("SELECT y FROM test WHERE x = 'one'", let result: Option<String> =
&[], db.query_row("SELECT y FROM test WHERE x = 'one'", &[], |row| row.get(0))
|row| row.get(0))
.unwrap(); .unwrap();
assert!(result.is_none()); assert!(result.is_none());
} }
@ -207,9 +203,8 @@ mod test {
stmt.execute_named(&[(":x", &"one")]).unwrap(); stmt.execute_named(&[(":x", &"one")]).unwrap();
stmt.execute_named(&[(":y", &"two")]).unwrap(); stmt.execute_named(&[(":y", &"two")]).unwrap();
let result: String = db.query_row("SELECT x FROM test WHERE y = 'two'", let result: String =
&[], db.query_row("SELECT x FROM test WHERE y = 'two'", &[], |row| row.get(0))
|row| row.get(0))
.unwrap(); .unwrap();
assert_eq!(result, "one"); assert_eq!(result, "one");
} }

View File

@ -4,7 +4,6 @@ use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::str;
use std::time::Duration; use std::time::Duration;
use super::ffi; use super::ffi;