diff --git a/src/vtab/csvtab.rs b/src/vtab/csvtab.rs index a191a28..1e5d137 100644 --- a/src/vtab/csvtab.rs +++ b/src/vtab/csvtab.rs @@ -7,10 +7,13 @@ use std::path::Path; use std::result; use std::str; -use {Connection, Error, Result}; use ffi; use types::Null; -use vtab::{declare_vtab, dequote, escape_double_quote, parse_boolean, Context, IndexInfo, Values, VTab, VTabCursor}; +use vtab::{ + declare_vtab, dequote, escape_double_quote, parse_boolean, Context, IndexInfo, VTab, + VTabCursor, Values, +}; +use {Connection, Error, Result}; /// Register the "csv" module. /// ```sql @@ -28,21 +31,23 @@ pub fn load_module(conn: &Connection) -> Result<()> { conn.create_module("csv", &CSV_MODULE, aux) } -init_module!(CSV_MODULE, - CSVTab, - CSVTabCursor, - csv_create, - csv_connect, - csv_best_index, - csv_disconnect, - csv_disconnect, - csv_open, - csv_close, - csv_filter, - csv_next, - csv_eof, - csv_column, - csv_rowid); +init_module!( + CSV_MODULE, + CSVTab, + CSVTabCursor, + csv_create, + csv_connect, + csv_best_index, + csv_disconnect, + csv_disconnect, + csv_open, + csv_close, + csv_filter, + csv_next, + csv_eof, + csv_column, + csv_rowid +); /// An instance of the CSV virtual table #[repr(C)] @@ -61,7 +66,8 @@ struct CSVTab { impl CSVTab { fn reader(&self) -> result::Result, csv::Error> { csv::Reader::from_file(&self.filename).map(|reader| { - reader.has_headers(self.has_headers) + reader + .has_headers(self.has_headers) .delimiter(self.delimiter) .quote(self.quote) }) @@ -114,39 +120,55 @@ impl VTab for CSVTab { match param { "filename" => { if !Path::new(value).exists() { - return Err(Error::ModuleError(format!("file '{}' does not exist", value))); + return Err(Error::ModuleError(format!( + "file '{}' does not exist", + value + ))); } vtab.filename = value.to_owned(); - }, + } "schema" => { schema = Some(value.to_owned()); - }, + } "columns" => { if let Ok(n) = value.parse::() { if n_col.is_some() { - return Err(Error::ModuleError("more than one 'columns' parameter".to_owned())); + return Err(Error::ModuleError( + "more than one 'columns' parameter".to_owned(), + )); } else if n == 0 { - return Err(Error::ModuleError("must have at least one column".to_owned())); + return Err(Error::ModuleError( + "must have at least one column".to_owned(), + )); } n_col = Some(n); } else { - return Err(Error::ModuleError(format!("unrecognized argument to 'columns': {}", value))); + return Err(Error::ModuleError(format!( + "unrecognized argument to 'columns': {}", + value + ))); } - }, + } "header" => { if let Some(b) = parse_boolean(value) { vtab.has_headers = b; } else { - return Err(Error::ModuleError(format!("unrecognized argument to 'header': {}", value))); + return Err(Error::ModuleError(format!( + "unrecognized argument to 'header': {}", + value + ))); } - }, + } "delimiter" => { if let Some(b) = CSVTab::parse_byte(value) { vtab.delimiter = b; } else { - return Err(Error::ModuleError(format!("unrecognized argument to 'delimiter': {}", value))); + return Err(Error::ModuleError(format!( + "unrecognized argument to 'delimiter': {}", + value + ))); } - }, + } "quote" => { if let Some(b) = CSVTab::parse_byte(value) { if b == b'0' { @@ -155,12 +177,18 @@ impl VTab for CSVTab { vtab.quote = b; } } else { - return Err(Error::ModuleError(format!("unrecognized argument to 'quote': {}", value))); + return Err(Error::ModuleError(format!( + "unrecognized argument to 'quote': {}", + value + ))); } - }, + } _ => { - return Err(Error::ModuleError(format!("unrecognized parameter '{}'", param))); - }, + return Err(Error::ModuleError(format!( + "unrecognized parameter '{}'", + param + ))); + } } } @@ -176,14 +204,17 @@ impl VTab for CSVTab { vtab.offset_first_row = reader.byte_offset(); // headers ignored if cols is not empty if n_col.is_none() && schema.is_none() { - cols = headers.into_iter().map(|header| escape_double_quote(&header).into_owned()).collect(); + cols = headers + .into_iter() + .map(|header| escape_double_quote(&header).into_owned()) + .collect(); } } else { let mut count = 0; while let Some(col) = reader.next_bytes().into_iter_result() { try!(col); cols.push(format!("c{}", count)); - count+=1; + count += 1; } } } @@ -252,16 +283,12 @@ impl VTabCursor for CSVTabCursor { type Table = CSVTab; fn vtab(&self) -> &CSVTab { - unsafe { & *(self.base.pVtab as *const CSVTab) } + unsafe { &*(self.base.pVtab as *const CSVTab) } } // Only a full table scan is supported. So `filter` simply rewinds to // the beginning. - fn filter(&mut self, - _idx_num: c_int, - _idx_str: Option<&str>, - _args: &Values) - -> Result<()> { + fn filter(&mut self, _idx_num: c_int, _idx_str: Option<&str>, _args: &Values) -> Result<()> { { let offset_first_row = self.vtab().offset_first_row; try!(self.reader.seek(offset_first_row)); @@ -290,7 +317,10 @@ impl VTabCursor for CSVTabCursor { } fn column(&self, ctx: &mut Context, col: c_int) -> Result<()> { if col < 0 || col as usize >= self.cols.len() { - return Err(Error::ModuleError(format!("column index out of bounds: {}", col))); + return Err(Error::ModuleError(format!( + "column index out of bounds: {}", + col + ))); } if self.cols.is_empty() { ctx.set_result(&Null); @@ -314,14 +344,15 @@ impl From for Error { #[cfg(test)] mod test { - use {Connection, Result}; use vtab::csvtab; + use {Connection, Result}; #[test] fn test_csv_module() { let db = Connection::open_in_memory().unwrap(); csvtab::load_module(&db).unwrap(); - db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)").unwrap(); + db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)") + .unwrap(); { let mut s = db.prepare("SELECT rowid, * FROM vtab").unwrap(); @@ -330,8 +361,9 @@ mod test { assert_eq!(vec!["rowid", "colA", "colB", "colC"], headers); } - let ids: Result> = - s.query_map(&[], |row| row.get::(0)).unwrap().collect(); + let ids: Result> = s.query_map(&[], |row| row.get::(0)) + .unwrap() + .collect(); let sum = ids.unwrap().iter().fold(0, |acc, &id| acc + id); assert_eq!(sum, 15); } @@ -342,13 +374,14 @@ mod test { fn test_csv_cursor() { let db = Connection::open_in_memory().unwrap(); csvtab::load_module(&db).unwrap(); - db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)").unwrap(); + db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)") + .unwrap(); { - let mut s = - db.prepare("SELECT v1.rowid, v1.* FROM vtab v1 NATURAL JOIN vtab v2 WHERE \ - v1.rowid < v2.rowid") - .unwrap(); + let mut s = db.prepare( + "SELECT v1.rowid, v1.* FROM vtab v1 NATURAL JOIN vtab v2 WHERE \ + v1.rowid < v2.rowid", + ).unwrap(); let mut rows = s.query(&[]).unwrap(); let row = rows.next().unwrap().unwrap(); diff --git a/src/vtab/int_array.rs b/src/vtab/int_array.rs index 22f2795..21eb54b 100644 --- a/src/vtab/int_array.rs +++ b/src/vtab/int_array.rs @@ -5,9 +5,9 @@ use std::default::Default; use std::os::raw::{c_char, c_int, c_void}; use std::rc::Rc; -use {Connection, Error, Result}; use ffi; -use vtab::{declare_vtab, escape_double_quote, Context, IndexInfo, Values, VTab, VTabCursor}; +use vtab::{declare_vtab, escape_double_quote, Context, IndexInfo, VTab, VTabCursor, Values}; +use {Connection, Error, Result}; /// Create a specific instance of an intarray object. /// The new intarray object is returned. @@ -17,8 +17,10 @@ use vtab::{declare_vtab, escape_double_quote, Context, IndexInfo, Values, VTab, pub fn create_int_array(conn: &Connection, name: &str) -> Result>>> { let array = Rc::new(RefCell::new(Vec::new())); try!(conn.create_module(name, &INT_ARRAY_MODULE, Some(array.clone()))); - try!(conn.execute_batch(&format!("CREATE VIRTUAL TABLE temp.\"{0}\" USING \"{0}\"", - escape_double_quote(name)))); + try!(conn.execute_batch(&format!( + "CREATE VIRTUAL TABLE temp.\"{0}\" USING \"{0}\"", + escape_double_quote(name) + ))); Ok(array) } @@ -28,29 +30,33 @@ pub fn create_int_array(conn: &Connection, name: &str) -> Result Result<()> { - conn.execute_batch(&format!("DROP TABLE temp.\"{0}\"", escape_double_quote(name))) + conn.execute_batch(&format!( + "DROP TABLE temp.\"{0}\"", + escape_double_quote(name) + )) // http://www.mail-archive.com/sqlite-users%40mailinglists.sqlite.org/msg08423.html // "Once a virtual table module has been created, it cannot be modified or destroyed, except by closing the database connection." // let aux: Option<()> = None; // conn.create_module(name, ptr::null() as *const ffi::sqlite3_module, aux) - } -eponymous_module!(INT_ARRAY_MODULE, - IntArrayVTab, - IntArrayVTabCursor, - Some(int_array_connect), - int_array_connect, - int_array_best_index, - int_array_disconnect, - Some(int_array_disconnect), - int_array_open, - int_array_close, - int_array_filter, - int_array_next, - int_array_eof, - int_array_column, - int_array_rowid); +eponymous_module!( + INT_ARRAY_MODULE, + IntArrayVTab, + IntArrayVTabCursor, + Some(int_array_connect), + int_array_connect, + int_array_best_index, + int_array_disconnect, + Some(int_array_disconnect), + int_array_open, + int_array_close, + int_array_filter, + int_array_next, + int_array_eof, + int_array_column, + int_array_rowid +); #[repr(C)] struct IntArrayVTab { @@ -62,16 +68,20 @@ struct IntArrayVTab { impl VTab for IntArrayVTab { type Cursor = IntArrayVTabCursor; - unsafe fn connect(db: *mut ffi::sqlite3, - aux: *mut c_void, - _args: &[&[u8]]) - -> Result { + unsafe fn connect( + db: *mut ffi::sqlite3, + aux: *mut c_void, + _args: &[&[u8]], + ) -> Result { let array = aux as *const Rc>>; let vtab = IntArrayVTab { base: Default::default(), array, }; - try!(declare_vtab(db, "CREATE TABLE x(value INTEGER PRIMARY KEY)")); + try!(declare_vtab( + db, + "CREATE TABLE x(value INTEGER PRIMARY KEY)" + )); Ok(vtab) } @@ -106,13 +116,9 @@ impl VTabCursor for IntArrayVTabCursor { type Table = IntArrayVTab; fn vtab(&self) -> &IntArrayVTab { - unsafe { & *(self.base.pVtab as *const IntArrayVTab) } + unsafe { &*(self.base.pVtab as *const IntArrayVTab) } } - fn filter(&mut self, - _idx_num: c_int, - _idx_str: Option<&str>, - _args: &Values) - -> Result<()> { + fn filter(&mut self, _idx_num: c_int, _idx_str: Option<&str>, _args: &Values) -> Result<()> { self.i = 0; Ok(()) } @@ -142,8 +148,8 @@ impl VTabCursor for IntArrayVTabCursor { #[cfg(test)] mod test { - use Connection; use vtab::int_array; + use Connection; #[test] #[cfg_attr(rustfmt, rustfmt_skip)] diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index 9ba5f40..7a8575d 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -6,11 +6,11 @@ use std::os::raw::{c_char, c_int, c_void}; use std::ptr; use std::slice; -use {Connection, Error, Result, InnerConnection, str_to_cstring}; use error::error_from_sqlite_code; use ffi; -use functions::{set_result, report_error}; +use functions::{report_error, set_result}; use types::{FromSql, FromSqlError, ToSql, ValueRef}; +use {str_to_cstring, Connection, Error, InnerConnection, Result}; // let conn: Connection = ...; // let mod: Module = ...; // VTab builder @@ -77,7 +77,9 @@ impl IndexInfo { pub fn constraints(&self) -> IndexConstraintIter { let constraints = unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) }; - IndexConstraintIter { iter: constraints.iter() } + IndexConstraintIter { + iter: constraints.iter(), + } } /// Number of terms in the ORDER BY clause @@ -241,7 +243,9 @@ impl<'a> Values<'a> { } pub fn iter(&self) -> ValueIter { - ValueIter { iter: self.args.iter() } + ValueIter { + iter: self.args.iter(), + } } } @@ -262,7 +266,9 @@ impl<'a> Iterator for ValueIter<'a> { type Item = ValueRef<'a>; fn next(&mut self) -> Option> { - self.iter.next().map(|&raw| { unsafe { ValueRef::from_value(raw) } }) + self.iter + .next() + .map(|&raw| unsafe { ValueRef::from_value(raw) }) } fn size_hint(&self) -> (usize, Option) { @@ -272,41 +278,45 @@ impl<'a> Iterator for ValueIter<'a> { impl Connection { /// Register a virtual table implementation. - pub fn create_module(&self, - module_name: &str, - module: *const ffi::sqlite3_module, - aux: Option) - -> Result<()> { - self.db - .borrow_mut() - .create_module(module_name, module, aux) + pub fn create_module( + &self, + module_name: &str, + module: *const ffi::sqlite3_module, + aux: Option, + ) -> Result<()> { + self.db.borrow_mut().create_module(module_name, module, aux) } } impl InnerConnection { - fn create_module(&mut self, - module_name: &str, - module: *const ffi::sqlite3_module, - aux: Option) - -> Result<()> { + fn create_module( + &mut self, + module_name: &str, + module: *const ffi::sqlite3_module, + aux: Option, + ) -> Result<()> { let c_name = try!(str_to_cstring(module_name)); let r = match aux { Some(aux) => { let boxed_aux: *mut A = Box::into_raw(Box::new(aux)); unsafe { - ffi::sqlite3_create_module_v2(self.db(), - c_name.as_ptr(), - module, - boxed_aux as *mut c_void, - Some(free_boxed_value::)) + ffi::sqlite3_create_module_v2( + self.db(), + c_name.as_ptr(), + module, + boxed_aux as *mut c_void, + Some(free_boxed_value::), + ) } } None => unsafe { - ffi::sqlite3_create_module_v2(self.db(), - c_name.as_ptr(), - module, - ptr::null_mut(), - None) + ffi::sqlite3_create_module_v2( + self.db(), + c_name.as_ptr(), + module, + ptr::null_mut(), + None, + ) }, }; self.decode_result(r) @@ -339,11 +349,9 @@ pub fn dequote(s: &str) -> &str { return s; } match s.bytes().next() { - Some(b) if b == b'"' || b == b'\'' => { - match s.bytes().rev().next() { - Some(e) if e == b => &s[1..s.len()-1], - _ => s, - } + Some(b) if b == b'"' || b == b'\'' => match s.bytes().rev().next() { + Some(e) if e == b => &s[1..s.len() - 1], + _ => s, }, _ => s, } @@ -354,9 +362,13 @@ pub fn dequote(s: &str) -> &str { /// 0 no false off /// ``` pub fn parse_boolean(s: &str) -> Option { - if s.eq_ignore_ascii_case("yes") || s.eq_ignore_ascii_case("on") || s.eq_ignore_ascii_case("true") || s.eq("1") { + if s.eq_ignore_ascii_case("yes") || s.eq_ignore_ascii_case("on") + || s.eq_ignore_ascii_case("true") || s.eq("1") + { Some(true) - } else if s.eq_ignore_ascii_case("no") || s.eq_ignore_ascii_case("off") || s.eq_ignore_ascii_case("false") || s.eq("0") { + } else if s.eq_ignore_ascii_case("no") || s.eq_ignore_ascii_case("off") + || s.eq_ignore_ascii_case("false") || s.eq("0") + { Some(false) } else { None @@ -370,262 +382,309 @@ unsafe extern "C" fn free_boxed_value(p: *mut c_void) { #[macro_export] macro_rules! init_module { - ($module_name: ident, $vtab: ident, $cursor: ty, - $create: ident, $connect: ident, $best_index: ident, - $disconnect: ident, $destroy: ident, - $open: ident, $close: ident, - $filter: ident, $next: ident, $eof: ident, - $column: ident, $rowid: ident) => { + ( + $module_name:ident, + $vtab:ident, + $cursor:ty, + $create:ident, + $connect:ident, + $best_index:ident, + $disconnect:ident, + $destroy:ident, + $open:ident, + $close:ident, + $filter:ident, + $next:ident, + $eof:ident, + $column:ident, + $rowid:ident + ) => { + static $module_name: ffi::sqlite3_module = ffi::sqlite3_module { + iVersion: 1, + xCreate: Some($create), + xConnect: Some($connect), + xBestIndex: Some($best_index), + xDisconnect: Some($disconnect), + xDestroy: Some($destroy), + xOpen: Some($open), + xClose: Some($close), + xFilter: Some($filter), + xNext: Some($next), + xEof: Some($eof), + xColumn: Some($column), + xRowid: Some($rowid), + xUpdate: None, // TODO + xBegin: None, + xSync: None, + xCommit: None, + xRollback: None, + xFindFunction: None, + xRename: None, + xSavepoint: None, + xRelease: None, + xRollbackTo: None, + }; -static $module_name: ffi::sqlite3_module = ffi::sqlite3_module { - iVersion: 1, - xCreate: Some($create), - xConnect: Some($connect), - xBestIndex: Some($best_index), - xDisconnect: Some($disconnect), - xDestroy: Some($destroy), - xOpen: Some($open), - xClose: Some($close), - xFilter: Some($filter), - xNext: Some($next), - xEof: Some($eof), - xColumn: Some($column), - xRowid: Some($rowid), - xUpdate: None, // TODO - xBegin: None, - xSync: None, - xCommit: None, - xRollback: None, - xFindFunction: None, - xRename: None, - xSavepoint: None, - xRelease: None, - xRollbackTo: None, -}; - -// The xConnect and xCreate methods do the same thing, but they must be -// different so that the virtual table is not an eponymous virtual table. -create_or_connect!($vtab, $create, create); -common_decl!($vtab, $cursor, - $connect, $best_index, - $disconnect, $destroy, - $open, $close, - $filter, $next, $eof, - $column, $rowid -); - } + // The xConnect and xCreate methods do the same thing, but they must be + // different so that the virtual table is not an eponymous virtual table. + create_or_connect!($vtab, $create, create); + common_decl!( + $vtab, + $cursor, + $connect, + $best_index, + $disconnect, + $destroy, + $open, + $close, + $filter, + $next, + $eof, + $column, + $rowid + ); + }; } // init_module macro end #[macro_export] macro_rules! eponymous_module { - ($module_name: ident, $vtab: ident, $cursor: ty, - $create: expr, $connect: ident, $best_index: ident, - $disconnect: ident, $destroy: expr, - $open: ident, $close: ident, - $filter: ident, $next: ident, $eof: ident, - $column: ident, $rowid: ident) => { + ( + $module_name:ident, + $vtab:ident, + $cursor:ty, + $create:expr, + $connect:ident, + $best_index:ident, + $disconnect:ident, + $destroy:expr, + $open:ident, + $close:ident, + $filter:ident, + $next:ident, + $eof:ident, + $column:ident, + $rowid:ident + ) => { + static $module_name: ffi::sqlite3_module = ffi::sqlite3_module { + iVersion: 1, + xCreate: $create, /* For eponymous-only virtual tables, the xCreate method is NULL */ + xConnect: Some($connect), /* A virtual table is eponymous if its xCreate method is + the exact same function as the xConnect method */ + xBestIndex: Some($best_index), + xDisconnect: Some($disconnect), + xDestroy: $destroy, + xOpen: Some($open), + xClose: Some($close), + xFilter: Some($filter), + xNext: Some($next), + xEof: Some($eof), + xColumn: Some($column), + xRowid: Some($rowid), + xUpdate: None, // TODO + xBegin: None, + xSync: None, + xCommit: None, + xRollback: None, + xFindFunction: None, + xRename: None, + xSavepoint: None, + xRelease: None, + xRollbackTo: None, + }; -static $module_name: ffi::sqlite3_module = ffi::sqlite3_module { - iVersion: 1, - xCreate: $create, /* For eponymous-only virtual tables, the xCreate method is NULL */ - xConnect: Some($connect), /* A virtual table is eponymous if its xCreate method is - the exact same function as the xConnect method */ - xBestIndex: Some($best_index), - xDisconnect: Some($disconnect), - xDestroy: $destroy, - xOpen: Some($open), - xClose: Some($close), - xFilter: Some($filter), - xNext: Some($next), - xEof: Some($eof), - xColumn: Some($column), - xRowid: Some($rowid), - xUpdate: None, // TODO - xBegin: None, - xSync: None, - xCommit: None, - xRollback: None, - xFindFunction: None, - xRename: None, - xSavepoint: None, - xRelease: None, - xRollbackTo: None, -}; - -common_decl!($vtab, $cursor, - $connect, $best_index, - $disconnect, $destroy, - $open, $close, - $filter, $next, $eof, - $column, $rowid -); - } + common_decl!( + $vtab, + $cursor, + $connect, + $best_index, + $disconnect, + $destroy, + $open, + $close, + $filter, + $next, + $eof, + $column, + $rowid + ); + }; } // eponymous_module macro end macro_rules! create_or_connect { - ($vtab: ident, $create_or_connect: ident, $vtab_func: ident) => { -unsafe extern "C" fn $create_or_connect(db: *mut ffi::sqlite3, - aux: *mut c_void, - argc: c_int, - argv: *const *const c_char, - pp_vtab: *mut *mut ffi::sqlite3_vtab, - err_msg: *mut *mut c_char) - -> c_int { - use std::error::Error as StdError; - use std::ffi::CStr; - use std::slice; - use vtab::mprintf; - let args = slice::from_raw_parts(argv, argc as usize); - let vec = args.iter().map(|&cs| { - CStr::from_ptr(cs).to_bytes() - }).collect::>(); - match $vtab::$vtab_func(db, aux, &vec[..]) { - Ok(vtab) => { - let boxed_vtab: *mut $vtab = Box::into_raw(Box::new(vtab)); - *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab; - ffi::SQLITE_OK - }, - Err(Error::SqliteFailure(err, s)) => { - if let Some(s) = s { - *err_msg = mprintf(&s); + ($vtab:ident, $create_or_connect:ident, $vtab_func:ident) => { + unsafe extern "C" fn $create_or_connect( + db: *mut ffi::sqlite3, + aux: *mut c_void, + argc: c_int, + argv: *const *const c_char, + pp_vtab: *mut *mut ffi::sqlite3_vtab, + err_msg: *mut *mut c_char, + ) -> c_int { + use std::error::Error as StdError; + use std::ffi::CStr; + use std::slice; + use vtab::mprintf; + let args = slice::from_raw_parts(argv, argc as usize); + let vec = args.iter() + .map(|&cs| CStr::from_ptr(cs).to_bytes()) + .collect::>(); + match $vtab::$vtab_func(db, aux, &vec[..]) { + Ok(vtab) => { + let boxed_vtab: *mut $vtab = Box::into_raw(Box::new(vtab)); + *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab; + ffi::SQLITE_OK + } + Err(Error::SqliteFailure(err, s)) => { + if let Some(s) = s { + *err_msg = mprintf(&s); + } + err.extended_code + } + Err(err) => { + *err_msg = mprintf(err.description()); + ffi::SQLITE_ERROR + } } - err.extended_code - }, - Err(err) => { - *err_msg = mprintf(err.description()); - ffi::SQLITE_ERROR } - } -} - } + }; } // create_or_connect macro end macro_rules! common_decl { - ($vtab: ident, $cursor: ty, - $connect: ident, $best_index: ident, - $disconnect: ident, $destroy: expr, - $open: ident, $close: ident, - $filter: ident, $next: ident, $eof: ident, - $column: ident, $rowid: ident) => { -create_or_connect!($vtab, $connect, connect); -unsafe extern "C" fn $best_index(vtab: *mut ffi::sqlite3_vtab, - info: *mut ffi::sqlite3_index_info) - -> c_int { - use std::error::Error as StdError; - use vtab::set_err_msg; - let vt = vtab as *mut $vtab; - let mut idx_info = IndexInfo(info); - match (*vt).best_index(&mut idx_info) { - Ok(_) => ffi::SQLITE_OK, - Err(Error::SqliteFailure(err, s)) => { - if let Some(err_msg) = s { - set_err_msg(vtab, &err_msg); + ( + $vtab:ident, + $cursor:ty, + $connect:ident, + $best_index:ident, + $disconnect:ident, + $destroy:expr, + $open:ident, + $close:ident, + $filter:ident, + $next:ident, + $eof:ident, + $column:ident, + $rowid:ident + ) => { + create_or_connect!($vtab, $connect, connect); + unsafe extern "C" fn $best_index( + vtab: *mut ffi::sqlite3_vtab, + info: *mut ffi::sqlite3_index_info, + ) -> c_int { + use std::error::Error as StdError; + use vtab::set_err_msg; + let vt = vtab as *mut $vtab; + let mut idx_info = IndexInfo(info); + match (*vt).best_index(&mut idx_info) { + Ok(_) => ffi::SQLITE_OK, + Err(Error::SqliteFailure(err, s)) => { + if let Some(err_msg) = s { + set_err_msg(vtab, &err_msg); + } + err.extended_code + } + Err(err) => { + set_err_msg(vtab, err.description()); + ffi::SQLITE_ERROR + } } - err.extended_code - }, - Err(err) => { - set_err_msg(vtab, err.description()); - ffi::SQLITE_ERROR } - - } - -} -unsafe extern "C" fn $disconnect(vtab: *mut ffi::sqlite3_vtab) -> c_int { - let vtab = vtab as *mut $vtab; - let _: Box<$vtab> = Box::from_raw(vtab); - ffi::SQLITE_OK -} - -unsafe extern "C" fn $open(vtab: *mut ffi::sqlite3_vtab, - pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor) - -> c_int { - use std::error::Error as StdError; - use vtab::set_err_msg; - let vt = vtab as *mut $vtab; - match (*vt).open() { - Ok(cursor) => { - let boxed_cursor: *mut $cursor = Box::into_raw(Box::new(cursor)); - *pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor; + unsafe extern "C" fn $disconnect(vtab: *mut ffi::sqlite3_vtab) -> c_int { + let vtab = vtab as *mut $vtab; + let _: Box<$vtab> = Box::from_raw(vtab); ffi::SQLITE_OK - }, - Err(Error::SqliteFailure(err, s)) => { - if let Some(err_msg) = s { - set_err_msg(vtab, &err_msg); - } - err.extended_code - }, - Err(err) => { - set_err_msg(vtab, err.description()); - ffi::SQLITE_ERROR } - } -} -unsafe extern "C" fn $close(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int { - let cr = cursor as *mut $cursor; - let _: Box<$cursor> = Box::from_raw(cr); - ffi::SQLITE_OK -} -unsafe extern "C" fn $filter(cursor: *mut ffi::sqlite3_vtab_cursor, - idx_num: c_int, - idx_str: *const c_char, - argc: c_int, - argv: *mut *mut ffi::sqlite3_value) - -> c_int { - use std::ffi::CStr; - use std::slice; - use std::str; - use vtab::{cursor_error, Values}; - let idx_name = if idx_str.is_null() { - None - } else { - let c_slice = CStr::from_ptr(idx_str).to_bytes(); - Some(str::from_utf8_unchecked(c_slice)) + unsafe extern "C" fn $open( + vtab: *mut ffi::sqlite3_vtab, + pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor, + ) -> c_int { + use std::error::Error as StdError; + use vtab::set_err_msg; + let vt = vtab as *mut $vtab; + match (*vt).open() { + Ok(cursor) => { + let boxed_cursor: *mut $cursor = Box::into_raw(Box::new(cursor)); + *pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor; + ffi::SQLITE_OK + } + Err(Error::SqliteFailure(err, s)) => { + if let Some(err_msg) = s { + set_err_msg(vtab, &err_msg); + } + err.extended_code + } + Err(err) => { + set_err_msg(vtab, err.description()); + ffi::SQLITE_ERROR + } + } + } + unsafe extern "C" fn $close(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int { + let cr = cursor as *mut $cursor; + let _: Box<$cursor> = Box::from_raw(cr); + ffi::SQLITE_OK + } + + unsafe extern "C" fn $filter( + cursor: *mut ffi::sqlite3_vtab_cursor, + idx_num: c_int, + idx_str: *const c_char, + argc: c_int, + argv: *mut *mut ffi::sqlite3_value, + ) -> c_int { + use std::ffi::CStr; + use std::slice; + use std::str; + use vtab::{cursor_error, Values}; + let idx_name = if idx_str.is_null() { + None + } else { + let c_slice = CStr::from_ptr(idx_str).to_bytes(); + Some(str::from_utf8_unchecked(c_slice)) + }; + let args = slice::from_raw_parts_mut(argv, argc as usize); + let values = Values { args: args }; + let cr = cursor as *mut $cursor; + cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values)) + } + unsafe extern "C" fn $next(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int { + use vtab::cursor_error; + let cr = cursor as *mut $cursor; + cursor_error(cursor, (*cr).next()) + } + unsafe extern "C" fn $eof(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int { + let cr = cursor as *mut $cursor; + (*cr).eof() as c_int + } + unsafe extern "C" fn $column( + cursor: *mut ffi::sqlite3_vtab_cursor, + ctx: *mut ffi::sqlite3_context, + i: c_int, + ) -> c_int { + use vtab::{result_error, Context}; + let cr = cursor as *mut $cursor; + let mut ctxt = Context(ctx); + result_error(ctx, (*cr).column(&mut ctxt, i)) + } + unsafe extern "C" fn $rowid( + cursor: *mut ffi::sqlite3_vtab_cursor, + p_rowid: *mut ffi::sqlite3_int64, + ) -> c_int { + use vtab::cursor_error; + let cr = cursor as *mut $cursor; + match (*cr).rowid() { + Ok(rowid) => { + *p_rowid = rowid; + ffi::SQLITE_OK + } + err => cursor_error(cursor, err), + } + } }; - let args = slice::from_raw_parts_mut(argv, argc as usize); - let values = Values { args: args }; - let cr = cursor as *mut $cursor; - cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values)) -} -unsafe extern "C" fn $next(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int { - use vtab::cursor_error; - let cr = cursor as *mut $cursor; - cursor_error(cursor, (*cr).next()) -} -unsafe extern "C" fn $eof(cursor: *mut ffi::sqlite3_vtab_cursor) -> c_int { - let cr = cursor as *mut $cursor; - (*cr).eof() as c_int -} -unsafe extern "C" fn $column(cursor: *mut ffi::sqlite3_vtab_cursor, - ctx: *mut ffi::sqlite3_context, - i: c_int) - -> c_int { - use vtab::{result_error, Context}; - let cr = cursor as *mut $cursor; - let mut ctxt = Context(ctx); - result_error(ctx, (*cr).column(&mut ctxt, i)) -} -unsafe extern "C" fn $rowid(cursor: *mut ffi::sqlite3_vtab_cursor, - p_rowid: *mut ffi::sqlite3_int64) - -> c_int { - use vtab::cursor_error; - let cr = cursor as *mut $cursor; - match (*cr).rowid() { - Ok(rowid) => { - *p_rowid = rowid; - ffi::SQLITE_OK - }, - err => cursor_error(cursor, err) - } -} - } } // common_decl macro end /// Virtual table cursors can set an error message by assigning a string to `zErrMsg`. -pub unsafe fn cursor_error(cursor: *mut ffi::sqlite3_vtab_cursor, - result: Result) - -> c_int { +pub unsafe fn cursor_error(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result) -> c_int { use std::error::Error as StdError; match result { Ok(_) => ffi::SQLITE_OK, @@ -691,9 +750,9 @@ pub fn mprintf(err_msg: &str) -> *mut c_char { unsafe { ffi::sqlite3_mprintf(c_format.as_ptr(), c_err.as_ptr()) } } -pub mod int_array; #[cfg(feature = "csvtab")] pub mod csvtab; +pub mod int_array; #[cfg(feature = "bundled")] pub mod series; @@ -723,4 +782,4 @@ mod test { assert_eq!(Some(false), super::parse_boolean("off")); assert_eq!(Some(false), super::parse_boolean("false")); } -} \ No newline at end of file +} diff --git a/src/vtab/series.rs b/src/vtab/series.rs index fe54164..1feb8dd 100644 --- a/src/vtab/series.rs +++ b/src/vtab/series.rs @@ -3,9 +3,9 @@ use std::default::Default; use std::os::raw::{c_char, c_int, c_void}; -use {Connection, Error, Result}; use ffi; -use vtab::{self, declare_vtab, Context, IndexInfo, Values, VTab, VTabCursor}; +use vtab::{self, declare_vtab, Context, IndexInfo, VTab, VTabCursor, Values}; +use {Connection, Error, Result}; /// Register the "generate_series" module. pub fn load_module(conn: &Connection) -> Result<()> { @@ -13,21 +13,23 @@ pub fn load_module(conn: &Connection) -> Result<()> { conn.create_module("generate_series", &SERIES_MODULE, aux) } -eponymous_module!(SERIES_MODULE, - SeriesTab, - SeriesTabCursor, - None, - series_connect, - series_best_index, - series_disconnect, - None, - series_open, - series_close, - series_filter, - series_next, - series_eof, - series_column, - series_rowid); +eponymous_module!( + SERIES_MODULE, + SeriesTab, + SeriesTabCursor, + None, + series_connect, + series_best_index, + series_disconnect, + None, + series_open, + series_close, + series_filter, + series_next, + series_eof, + series_column, + series_rowid +); // Column numbers // const SERIES_COLUMN_VALUE : c_int = 0; @@ -51,7 +53,6 @@ bitflags! { } } - /// An instance of the Series virtual table #[repr(C)] struct SeriesTab { @@ -59,17 +60,21 @@ struct SeriesTab { base: ffi::sqlite3_vtab, } - impl VTab for SeriesTab { type Cursor = SeriesTabCursor; - unsafe fn connect(db: *mut ffi::sqlite3, - _aux: *mut c_void, - _args: &[&[u8]]) - -> Result { - let vtab = SeriesTab { base: Default::default() }; - try!(declare_vtab(db, - "CREATE TABLE x(value,start hidden,stop hidden,step hidden)")); + unsafe fn connect( + db: *mut ffi::sqlite3, + _aux: *mut c_void, + _args: &[&[u8]], + ) -> Result { + let vtab = SeriesTab { + base: Default::default(), + }; + try!(declare_vtab( + db, + "CREATE TABLE x(value,start hidden,stop hidden,step hidden)" + )); Ok(vtab) } @@ -127,7 +132,13 @@ impl VTab for SeriesTab { } if idx_num.contains(QueryPlanFlags::BOTH) { // Both start= and stop= boundaries are available. - info.set_estimated_cost((2 - if idx_num.contains(QueryPlanFlags::STEP) { 1 } else { 0 }) as f64); + info.set_estimated_cost( + (2 - if idx_num.contains(QueryPlanFlags::STEP) { + 1 + } else { + 0 + }) as f64, + ); info.set_estimated_rows(1000); if info.num_of_order_by() == 1 { if info.is_order_by_desc(0) { @@ -177,13 +188,9 @@ impl VTabCursor for SeriesTabCursor { type Table = SeriesTab; fn vtab(&self) -> &SeriesTab { - unsafe { & *(self.base.pVtab as *const SeriesTab) } + unsafe { &*(self.base.pVtab as *const SeriesTab) } } - fn filter(&mut self, - idx_num: c_int, - _idx_str: Option<&str>, - args: &Values) - -> Result<()> { + fn filter(&mut self, idx_num: c_int, _idx_str: Option<&str>, args: &Values) -> Result<()> { let idx_num = QueryPlanFlags::from_bits_truncate(idx_num); let mut i = 0; if idx_num.contains(QueryPlanFlags::START) { @@ -251,9 +258,9 @@ impl VTabCursor for SeriesTabCursor { #[cfg(test)] mod test { - use Connection; - use vtab::series; use ffi; + use vtab::series; + use Connection; #[test] fn test_series_module() { @@ -267,9 +274,7 @@ mod test { let mut s = db.prepare("SELECT * FROM generate_series(0,20,5)").unwrap(); - - let series = s.query_map(&[], |row| row.get::(0)) - .unwrap(); + let series = s.query_map(&[], |row| row.get::(0)).unwrap(); let mut expected = 0; for value in series {