diff --git a/src/functions.rs b/src/functions.rs index 47bfe3e..bf32399 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -177,7 +177,7 @@ impl ToResult for TooBig { } impl<'a> ValueRef<'a> { - unsafe fn from_value(value: *mut sqlite3_value) -> ValueRef<'a> { + pub unsafe fn from_value(value: *mut sqlite3_value) -> ValueRef<'a> { use std::slice::from_raw_parts; match ffi::sqlite3_value_type(value) { diff --git a/src/vtab/csvtab.rs b/src/vtab/csvtab.rs index be7e1a3..e49048f 100644 --- a/src/vtab/csvtab.rs +++ b/src/vtab/csvtab.rs @@ -9,7 +9,7 @@ use libc; use {Connection, Error, Result}; use ffi; use types::Null; -use vtab::{declare_vtab, escape_double_quote, Context, IndexInfo, VTab, VTabCursor}; +use vtab::{declare_vtab, escape_double_quote, Context, IndexInfo, Values, VTab, VTabCursor}; /// Register the "csv" module. pub fn load_module(conn: &Connection) -> Result<()> { @@ -171,7 +171,7 @@ impl VTabCursor for CSVTabCursor { fn filter(&mut self, _idx_num: libc::c_int, _idx_str: Option<&str>, - _args: &mut [*mut ffi::sqlite3_value]) + _args: &Values) -> Result<()> { { let offset_first_row = self.vtab().offset_first_row; diff --git a/src/vtab/int_array.rs b/src/vtab/int_array.rs index 2bdb8e3..a298324 100644 --- a/src/vtab/int_array.rs +++ b/src/vtab/int_array.rs @@ -7,7 +7,7 @@ use libc; use {Connection, Error, Result}; use ffi; -use vtab::{declare_vtab, escape_double_quote, Context, IndexInfo, VTab, VTabCursor}; +use vtab::{declare_vtab, escape_double_quote, Context, IndexInfo, Values, VTab, VTabCursor}; /// Create a specific instance of an intarray object. /// The new intarray object is returned. @@ -103,7 +103,7 @@ impl VTabCursor for IntArrayVTabCursor { fn filter(&mut self, _idx_num: libc::c_int, _idx_str: Option<&str>, - _args: &mut [*mut ffi::sqlite3_value]) + _args: &Values) -> Result<()> { self.i = 0; Ok(()) diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index 46e684e..1662ac4 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -10,6 +10,7 @@ use {Connection, Error, Result, InnerConnection, str_to_cstring}; use error::error_from_sqlite_code; use ffi; use functions::ToResult; +use types::FromSql; // let conn: Connection = ...; // let mod: Module = ...; // VTab builder @@ -61,11 +62,7 @@ pub trait VTabCursor>: Sized { /// Accessor to the associated virtual table. fn vtab(&self) -> &mut V; /// Begin a search of a virtual table. - fn filter(&mut self, - idx_num: libc::c_int, - idx_str: Option<&str>, - args: &mut [*mut ffi::sqlite3_value]) - -> Result<()>; + fn filter(&mut self, idx_num: libc::c_int, idx_str: Option<&str>, args: &Values) -> Result<()>; /// Advance cursor to the next row of a result set initiated by `filter`. fn next(&mut self) -> Result<()>; /// Must return `false` if the cursor currently points to a valid row of data, or `true` otherwise. @@ -88,6 +85,30 @@ impl Context { } } +pub struct Values<'a> { + args: &'a [*mut ffi::sqlite3_value], +} + +impl<'a> Values<'a> { + pub fn len(&self) -> usize { + self.args.len() + } + + pub fn is_empty(&self) -> bool { + self.args.is_empty() + } + + pub fn get(&self, idx: usize) -> Result { + use types::ValueRef; + let arg = self.args[idx]; + let value = unsafe { ValueRef::from_value(arg) }; + FromSql::column_result(value).map_err(|err| match err { + Error::InvalidColumnType => Error::InvalidFunctionParameterType, + _ => err, + }) + } +} + impl Connection { /// Register a virtual table implementation. pub fn create_module(&self, @@ -277,16 +298,17 @@ unsafe extern "C" fn $filter(cursor: *mut ffi::sqlite3_vtab_cursor, use std::ffi::CStr; use std::slice; use std::str; - use vtab::cursor_error; + 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 mut args = slice::from_raw_parts_mut(argv, argc as usize); + 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, &mut args)) + cursor_error(cursor, (*cr).filter(idx_num, idx_name, &values)) } unsafe extern "C" fn $next(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int { use vtab::cursor_error;