mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 09:09:19 +08:00
Partial CSV virtual table implementation.
This commit is contained in:
parent
2dc4230223
commit
933000b57a
@ -19,6 +19,7 @@ blob = []
|
|||||||
functions = []
|
functions = []
|
||||||
trace = []
|
trace = []
|
||||||
vtab = []
|
vtab = []
|
||||||
|
csvtab = ["csv"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
time = "~0.1.0"
|
time = "~0.1.0"
|
||||||
@ -34,6 +35,10 @@ regex = "~0.1.41"
|
|||||||
path = "libsqlite3-sys"
|
path = "libsqlite3-sys"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
||||||
|
[dependencies.csv]
|
||||||
|
version = "~0.14.3"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "config_log"
|
name = "config_log"
|
||||||
harness = false
|
harness = false
|
||||||
|
12
src/error.rs
12
src/error.rs
@ -66,6 +66,12 @@ pub enum Error {
|
|||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
UserFunctionError(Box<error::Error + Send + Sync>),
|
UserFunctionError(Box<error::Error + Send + Sync>),
|
||||||
|
|
||||||
|
/// An error case available for implementors of custom modules (e.g.,
|
||||||
|
/// `create_module`).
|
||||||
|
#[cfg(feature = "vtab")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
ModuleError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<str::Utf8Error> for Error {
|
impl From<str::Utf8Error> for Error {
|
||||||
@ -107,6 +113,8 @@ impl fmt::Display for Error {
|
|||||||
&Error::InvalidFunctionParameterType => write!(f, "Invalid function parameter type"),
|
&Error::InvalidFunctionParameterType => write!(f, "Invalid function parameter type"),
|
||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
&Error::UserFunctionError(ref err) => err.fmt(f),
|
&Error::UserFunctionError(ref err) => err.fmt(f),
|
||||||
|
#[cfg(feature = "vtab")]
|
||||||
|
&Error::ModuleError(ref desc) => write!(f, "{}", desc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,6 +145,8 @@ impl error::Error for Error {
|
|||||||
&Error::InvalidFunctionParameterType => "invalid function parameter type",
|
&Error::InvalidFunctionParameterType => "invalid function parameter type",
|
||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
&Error::UserFunctionError(ref err) => err.description(),
|
&Error::UserFunctionError(ref err) => err.description(),
|
||||||
|
#[cfg(feature = "vtab")]
|
||||||
|
&Error::ModuleError(ref desc) => desc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +170,8 @@ impl error::Error for Error {
|
|||||||
&Error::InvalidFunctionParameterType => None,
|
&Error::InvalidFunctionParameterType => None,
|
||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
&Error::UserFunctionError(ref err) => Some(&**err),
|
&Error::UserFunctionError(ref err) => Some(&**err),
|
||||||
|
#[cfg(feature = "vtab")]
|
||||||
|
&Error::ModuleError(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
src/vtab/csvtab.rs
Normal file
114
src/vtab/csvtab.rs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
//! CSV Virtual Table
|
||||||
|
extern crate csv;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::mem;
|
||||||
|
use libc;
|
||||||
|
|
||||||
|
use {Connection, Error, Result};
|
||||||
|
use ffi;
|
||||||
|
use vtab::declare_vtab;
|
||||||
|
|
||||||
|
use self::csv::Reader;
|
||||||
|
|
||||||
|
pub fn load_module(conn: &Connection) -> Result<()> {
|
||||||
|
let aux: Option<()> = None;
|
||||||
|
conn.create_module("csv", &CSV_MODULE, aux)
|
||||||
|
}
|
||||||
|
|
||||||
|
init_module!(CSV_MODULE, CSVTab, CSVTabCursor,
|
||||||
|
csv_create, csv_best_index, csv_destroy,
|
||||||
|
csv_open, csv_close,
|
||||||
|
csv_filter, csv_next, csv_eof,
|
||||||
|
csv_column, csv_rowid);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct CSVTab {
|
||||||
|
/// Base class
|
||||||
|
base: ffi::sqlite3_vtab,
|
||||||
|
reader: csv::Reader<File>,
|
||||||
|
offset_first_row: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSVTab {
|
||||||
|
fn create(db: *mut ffi::sqlite3,
|
||||||
|
aux: *mut libc::c_void,
|
||||||
|
_argc: libc::c_int,
|
||||||
|
_argv: *const *const libc::c_char)
|
||||||
|
-> Result<CSVTab> {
|
||||||
|
let reader = try!(csv::Reader::from_file("FIXME"));
|
||||||
|
let vtab = CSVTab {
|
||||||
|
base: Default::default(),
|
||||||
|
reader: reader,
|
||||||
|
offset_first_row: 0,
|
||||||
|
};
|
||||||
|
unimplemented!();
|
||||||
|
try!(declare_vtab(db, "CREATE TABLE x FIXME"));
|
||||||
|
Ok(vtab)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn best_index(&self, _info: *mut ffi::sqlite3_index_info) {}
|
||||||
|
|
||||||
|
fn open(&self) -> Result<CSVTabCursor> {
|
||||||
|
Ok(CSVTabCursor::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct CSVTabCursor {
|
||||||
|
/// Base class
|
||||||
|
base: ffi::sqlite3_vtab_cursor,
|
||||||
|
/// Current cursor position
|
||||||
|
row_number: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSVTabCursor {
|
||||||
|
fn new() -> CSVTabCursor {
|
||||||
|
CSVTabCursor {
|
||||||
|
base: Default::default(),
|
||||||
|
row_number: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vtab(&self) -> &mut CSVTab {
|
||||||
|
unsafe { &mut *(self.base.pVtab as *mut CSVTab) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter(&mut self) -> Result<()> {
|
||||||
|
{
|
||||||
|
let vtab = self.vtab();
|
||||||
|
vtab.reader.seek(vtab.offset_first_row); // FIXME Result ignore
|
||||||
|
}
|
||||||
|
self.row_number = 0;
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
fn next(&mut self) -> Result<()> {
|
||||||
|
let vtab = self.vtab();
|
||||||
|
if vtab.reader.done() {
|
||||||
|
return Err(Error::SqliteFailure(ffi::Error::new(ffi::SQLITE_ERROR), None));
|
||||||
|
}
|
||||||
|
unimplemented!();
|
||||||
|
// self.row_number = self.row_number + 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn eof(&self) -> bool {
|
||||||
|
let vtab = self.vtab();
|
||||||
|
unsafe { (*vtab).reader.done() }
|
||||||
|
}
|
||||||
|
fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> Result<()> {
|
||||||
|
let vtab = self.vtab();
|
||||||
|
unimplemented!();
|
||||||
|
// TODO.set_result(ctx);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn rowid(&self) -> Result<i64> {
|
||||||
|
Ok(self.row_number as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<csv::Error> for Error {
|
||||||
|
fn from(err: csv::Error) -> Error {
|
||||||
|
use std::error::Error as StdError;
|
||||||
|
Error::ModuleError(String::from(err.description()))
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
//! Int array virtual table.
|
//! Int array virtual table.
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@ -8,12 +7,11 @@ use libc;
|
|||||||
|
|
||||||
use {Connection, Error, Result};
|
use {Connection, Error, Result};
|
||||||
use ffi;
|
use ffi;
|
||||||
use functions::ToResult;
|
use vtab::declare_vtab;
|
||||||
use vtab::{declare_vtab, mprintf};
|
|
||||||
|
|
||||||
pub fn create_int_array(conn: &Connection, name: &str) -> Result<Rc<RefCell<Vec<i64>>>> {
|
pub fn create_int_array(conn: &Connection, name: &str) -> Result<Rc<RefCell<Vec<i64>>>> {
|
||||||
let array = Rc::new(RefCell::new(Vec::new()));
|
let array = Rc::new(RefCell::new(Vec::new()));
|
||||||
try!(conn.create_module(name, &INT_ARRAY_MODULE, array.clone()));
|
try!(conn.create_module(name, &INT_ARRAY_MODULE, Some(array.clone())));
|
||||||
try!(conn.execute_batch(&format!("CREATE VIRTUAL TABLE temp.{0} USING {0}",
|
try!(conn.execute_batch(&format!("CREATE VIRTUAL TABLE temp.{0} USING {0}",
|
||||||
escape_quote(name.to_string()))));
|
escape_quote(name.to_string()))));
|
||||||
Ok(array)
|
Ok(array)
|
||||||
@ -60,11 +58,10 @@ impl IntArrayVTab {
|
|||||||
Ok(vtab)
|
Ok(vtab)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_index(&self, _info: *mut ffi::sqlite3_index_info) {
|
fn best_index(&self, _info: *mut ffi::sqlite3_index_info) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn open(&self) -> IntArrayVTabCursor {
|
fn open(&self) -> Result<IntArrayVTabCursor> {
|
||||||
IntArrayVTabCursor::new()
|
Ok(IntArrayVTabCursor::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,35 +81,36 @@ impl IntArrayVTabCursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vtab(&self) -> *mut IntArrayVTab {
|
fn vtab(&self) -> &mut IntArrayVTab {
|
||||||
self.base.pVtab as *mut IntArrayVTab
|
unsafe { &mut *(self.base.pVtab as *mut IntArrayVTab) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter(&mut self) -> libc::c_int {
|
fn filter(&mut self) -> Result<()> {
|
||||||
self.i = 0;
|
self.i = 0;
|
||||||
ffi::SQLITE_OK
|
Ok(())
|
||||||
}
|
}
|
||||||
fn next(&mut self) -> libc::c_int {
|
fn next(&mut self) -> Result<()> {
|
||||||
self.i = self.i + 1;
|
self.i = self.i + 1;
|
||||||
ffi::SQLITE_OK
|
Ok(())
|
||||||
}
|
}
|
||||||
fn eof(&self) -> bool {
|
fn eof(&self) -> bool {
|
||||||
let vtab = self.vtab();
|
let vtab = self.vtab();
|
||||||
unsafe {
|
unsafe {
|
||||||
let array = (*(*vtab).array).borrow();
|
let array = (*vtab.array).borrow();
|
||||||
self.i >= array.len()
|
self.i >= array.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> libc::c_int {
|
fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> Result<()> {
|
||||||
|
use functions::ToResult;
|
||||||
let vtab = self.vtab();
|
let vtab = self.vtab();
|
||||||
unsafe {
|
unsafe {
|
||||||
let array = (*(*vtab).array).borrow();
|
let array = (*vtab.array).borrow();
|
||||||
array[self.i].set_result(ctx);
|
array[self.i].set_result(ctx);
|
||||||
}
|
}
|
||||||
ffi::SQLITE_OK
|
Ok(())
|
||||||
}
|
}
|
||||||
fn rowid(&self) -> i64 {
|
fn rowid(&self) -> Result<i64> {
|
||||||
self.i as i64
|
Ok(self.i as i64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
112
src/vtab/mod.rs
112
src/vtab/mod.rs
@ -1,8 +1,8 @@
|
|||||||
//! Create virtual tables.
|
//! Create virtual tables.
|
||||||
//! (See http://sqlite.org/vtab.html)
|
//! (See http://sqlite.org/vtab.html)
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::ptr;
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
use {Connection, Error, Result, InnerConnection, str_to_cstring};
|
use {Connection, Error, Result, InnerConnection, str_to_cstring};
|
||||||
@ -29,7 +29,7 @@ use ffi;
|
|||||||
//
|
//
|
||||||
// let stmt = conn.prepare("SELECT ... FROM foo WHERE ...");
|
// let stmt = conn.prepare("SELECT ... FROM foo WHERE ...");
|
||||||
// \-> vtab.xbestindex
|
// \-> vtab.xbestindex
|
||||||
// stmt.quey().next();
|
// stmt.query().next();
|
||||||
// \-> vtab.xopen
|
// \-> vtab.xopen
|
||||||
// |-> let cursor: Cursor = ...; // on the heap
|
// |-> let cursor: Cursor = ...; // on the heap
|
||||||
// |-> cursor.xfilter or xnext
|
// |-> cursor.xfilter or xnext
|
||||||
@ -42,7 +42,7 @@ impl Connection {
|
|||||||
pub fn create_module<A>(&self,
|
pub fn create_module<A>(&self,
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
module: *const ffi::sqlite3_module,
|
module: *const ffi::sqlite3_module,
|
||||||
aux: A)
|
aux: Option<A>)
|
||||||
-> Result<()> {
|
-> Result<()> {
|
||||||
self.db
|
self.db
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
@ -54,16 +54,27 @@ impl InnerConnection {
|
|||||||
fn create_module<A>(&mut self,
|
fn create_module<A>(&mut self,
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
module: *const ffi::sqlite3_module,
|
module: *const ffi::sqlite3_module,
|
||||||
aux: A)
|
aux: Option<A>)
|
||||||
-> Result<()> {
|
-> Result<()> {
|
||||||
let boxed_aux: *mut A = Box::into_raw(Box::new(aux));
|
|
||||||
let c_name = try!(str_to_cstring(module_name));
|
let c_name = try!(str_to_cstring(module_name));
|
||||||
let r = unsafe {
|
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(),
|
ffi::sqlite3_create_module_v2(self.db(),
|
||||||
c_name.as_ptr(),
|
c_name.as_ptr(),
|
||||||
module,
|
module,
|
||||||
mem::transmute(boxed_aux),
|
mem::transmute(boxed_aux),
|
||||||
Some(mem::transmute(free_boxed_value::<A>)))
|
Some(mem::transmute(free_boxed_value::<A>)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => unsafe {
|
||||||
|
ffi::sqlite3_create_module_v2(self.db(),
|
||||||
|
c_name.as_ptr(),
|
||||||
|
module,
|
||||||
|
ptr::null_mut(),
|
||||||
|
None)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
self.decode_result(r)
|
self.decode_result(r)
|
||||||
}
|
}
|
||||||
@ -125,28 +136,26 @@ unsafe extern "C" fn $create(db: *mut ffi::sqlite3,
|
|||||||
pp_vtab: *mut *mut ffi::sqlite3_vtab,
|
pp_vtab: *mut *mut ffi::sqlite3_vtab,
|
||||||
err_msg: *mut *mut libc::c_char)
|
err_msg: *mut *mut libc::c_char)
|
||||||
-> libc::c_int {
|
-> libc::c_int {
|
||||||
|
use std::error::Error as StdError;
|
||||||
|
use vtab::mprintf;
|
||||||
match $vtab::create(db, aux, argc, argv) {
|
match $vtab::create(db, aux, argc, argv) {
|
||||||
Ok(vtab) => {
|
Ok(vtab) => {
|
||||||
let boxed_vtab: *mut $vtab = Box::into_raw(Box::new(vtab));
|
let boxed_vtab: *mut $vtab = Box::into_raw(Box::new(vtab));
|
||||||
*pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
|
*pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
|
||||||
ffi::SQLITE_OK
|
ffi::SQLITE_OK
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(Error::SqliteFailure(err, s)) => {
|
||||||
match err {
|
|
||||||
Error::SqliteFailure(err, s) => {
|
|
||||||
if let Some(s) = s {
|
if let Some(s) = s {
|
||||||
*err_msg = mprintf(&s);
|
*err_msg = mprintf(&s);
|
||||||
}
|
}
|
||||||
err.extended_code
|
err.extended_code
|
||||||
}
|
},
|
||||||
_ => {
|
Err(err) => {
|
||||||
*err_msg = mprintf(err.description());
|
*err_msg = mprintf(err.description());
|
||||||
ffi::SQLITE_ERROR
|
ffi::SQLITE_ERROR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
unsafe extern "C" fn $best_index(vtab: *mut ffi::sqlite3_vtab,
|
unsafe extern "C" fn $best_index(vtab: *mut ffi::sqlite3_vtab,
|
||||||
info: *mut ffi::sqlite3_index_info)
|
info: *mut ffi::sqlite3_index_info)
|
||||||
-> libc::c_int {
|
-> libc::c_int {
|
||||||
@ -163,15 +172,28 @@ unsafe extern "C" fn $destroy(vtab: *mut ffi::sqlite3_vtab) -> libc::c_int {
|
|||||||
unsafe extern "C" fn $open(vtab: *mut ffi::sqlite3_vtab,
|
unsafe extern "C" fn $open(vtab: *mut ffi::sqlite3_vtab,
|
||||||
pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor)
|
pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor)
|
||||||
-> libc::c_int {
|
-> libc::c_int {
|
||||||
let vtab = vtab as *mut $vtab;
|
use vtab::set_err_msg;
|
||||||
let cursor = (*vtab).open();
|
let vt = vtab as *mut $vtab;
|
||||||
|
match (*vt).open() {
|
||||||
|
Ok(cursor) => {
|
||||||
let boxed_cursor: *mut $cursor = Box::into_raw(Box::new(cursor));
|
let boxed_cursor: *mut $cursor = Box::into_raw(Box::new(cursor));
|
||||||
*pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor;
|
*pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor;
|
||||||
ffi::SQLITE_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(_) => {
|
||||||
|
ffi::SQLITE_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unsafe extern "C" fn $close(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
unsafe extern "C" fn $close(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
||||||
let cursor = cursor as *mut $cursor;
|
let cr = cursor as *mut $cursor;
|
||||||
let _: Box<$cursor> = Box::from_raw(mem::transmute(cursor));
|
let _: Box<$cursor> = Box::from_raw(mem::transmute(cr));
|
||||||
ffi::SQLITE_OK
|
ffi::SQLITE_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,35 +203,70 @@ unsafe extern "C" fn $filter(cursor: *mut ffi::sqlite3_vtab_cursor,
|
|||||||
_argc: libc::c_int,
|
_argc: libc::c_int,
|
||||||
_argv: *mut *mut ffi::sqlite3_value)
|
_argv: *mut *mut ffi::sqlite3_value)
|
||||||
-> libc::c_int {
|
-> libc::c_int {
|
||||||
let cursor = cursor as *mut $cursor;
|
use vtab::cursor_error;
|
||||||
(*cursor).filter()
|
let cr = cursor as *mut $cursor;
|
||||||
|
cursor_error(cursor, (*cr).filter())
|
||||||
}
|
}
|
||||||
unsafe extern "C" fn $next(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
unsafe extern "C" fn $next(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
||||||
let cursor = cursor as *mut $cursor;
|
use vtab::cursor_error;
|
||||||
(*cursor).next()
|
let cr = cursor as *mut $cursor;
|
||||||
|
cursor_error(cursor, (*cr).next())
|
||||||
}
|
}
|
||||||
unsafe extern "C" fn $eof(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
unsafe extern "C" fn $eof(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
||||||
let cursor = cursor as *mut $cursor;
|
let cr = cursor as *mut $cursor;
|
||||||
(*cursor).eof() as libc::c_int
|
(*cr).eof() as libc::c_int
|
||||||
}
|
}
|
||||||
unsafe extern "C" fn $column(cursor: *mut ffi::sqlite3_vtab_cursor,
|
unsafe extern "C" fn $column(cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||||
ctx: *mut ffi::sqlite3_context,
|
ctx: *mut ffi::sqlite3_context,
|
||||||
i: libc::c_int)
|
i: libc::c_int)
|
||||||
-> libc::c_int {
|
-> libc::c_int {
|
||||||
let cursor = cursor as *mut $cursor;
|
use vtab::cursor_error;
|
||||||
(*cursor).column(ctx, i)
|
let cr = cursor as *mut $cursor;
|
||||||
|
cursor_error(cursor, (*cr).column(ctx, i))
|
||||||
}
|
}
|
||||||
unsafe extern "C" fn $rowid(cursor: *mut ffi::sqlite3_vtab_cursor,
|
unsafe extern "C" fn $rowid(cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||||
p_rowid: *mut ffi::sqlite3_int64)
|
p_rowid: *mut ffi::sqlite3_int64)
|
||||||
-> libc::c_int {
|
-> libc::c_int {
|
||||||
let cursor = cursor as *mut $cursor;
|
use vtab::cursor_error;
|
||||||
*p_rowid = (*cursor).rowid();
|
let cr = cursor as *mut $cursor;
|
||||||
|
match (*cr).rowid() {
|
||||||
|
Ok(rowid) => {
|
||||||
|
*p_rowid = rowid;
|
||||||
ffi::SQLITE_OK
|
ffi::SQLITE_OK
|
||||||
|
},
|
||||||
|
err => cursor_error(cursor, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||||
|
result: Result<T>)
|
||||||
|
-> libc::c_int {
|
||||||
|
match result {
|
||||||
|
Ok(_) => ffi::SQLITE_OK,
|
||||||
|
Err(Error::SqliteFailure(err, s)) => {
|
||||||
|
if let Some(err_msg) = s {
|
||||||
|
set_err_msg((*cursor).pVtab, &err_msg);
|
||||||
|
}
|
||||||
|
err.extended_code
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// TODO errMsg
|
||||||
|
ffi::SQLITE_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
|
||||||
|
if !(*vtab).zErrMsg.is_null() {
|
||||||
|
ffi::sqlite3_free((*vtab).zErrMsg as *mut libc::c_void);
|
||||||
|
}
|
||||||
|
(*vtab).zErrMsg = mprintf(err_msg);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn result_error(ctx: *mut ffi::sqlite3_context, err: Error) -> libc::c_int {
|
unsafe fn result_error(ctx: *mut ffi::sqlite3_context, err: Error) -> libc::c_int {
|
||||||
|
use std::error::Error as StdError;
|
||||||
match err {
|
match err {
|
||||||
Error::SqliteFailure(err, s) => {
|
Error::SqliteFailure(err, s) => {
|
||||||
ffi::sqlite3_result_error_code(ctx, err.extended_code);
|
ffi::sqlite3_result_error_code(ctx, err.extended_code);
|
||||||
@ -236,3 +293,4 @@ pub fn mprintf(err_msg: &str) -> *mut ::libc::c_char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod int_array;
|
pub mod int_array;
|
||||||
|
#[cfg(feature = "csvtab")]pub mod csvtab;
|
||||||
|
Loading…
Reference in New Issue
Block a user