mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 09:09:19 +08:00
First, try to implement a simple virtual table.
This commit is contained in:
parent
5b62e2dd5f
commit
2d6705b03e
@ -155,6 +155,26 @@ impl ToResult for Null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error indicating that a memory allocation failed.
|
||||||
|
#[derive(Copy,Clone)]
|
||||||
|
pub struct NoMem;
|
||||||
|
|
||||||
|
impl ToResult for NoMem {
|
||||||
|
unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
|
||||||
|
ffi::sqlite3_result_error_nomem(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error indicating that a string or BLOB is too long to represent.
|
||||||
|
#[derive(Copy,Clone)]
|
||||||
|
pub struct TooBig;
|
||||||
|
|
||||||
|
impl ToResult for TooBig {
|
||||||
|
unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
|
||||||
|
ffi::sqlite3_result_error_toobig(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A trait for types that can be created from a SQLite function parameter value.
|
/// A trait for types that can be created from a SQLite function parameter value.
|
||||||
pub trait FromValue: Sized {
|
pub trait FromValue: Sized {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Self>;
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Self>;
|
||||||
|
475
src/vtab.rs
475
src/vtab.rs
@ -1,71 +1,54 @@
|
|||||||
//! Create virtual tables.
|
//! Create virtual tables.
|
||||||
//! (See http://sqlite.org/vtab.html)
|
//! (See http://sqlite.org/vtab.html)
|
||||||
|
use std::default::Default;
|
||||||
|
use std::error::Error as StdError;
|
||||||
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use libc;
|
||||||
use libc::c_void;
|
|
||||||
|
|
||||||
use {Connection, Result, InnerConnection, str_to_cstring};
|
use {Connection, Error, Result, InnerConnection, str_to_cstring};
|
||||||
use functions::ToResult;
|
use error::error_from_sqlite_code;
|
||||||
use ffi;
|
use ffi;
|
||||||
|
use functions::{ToResult, NoMem, TooBig};
|
||||||
|
|
||||||
/// Virtual table module.
|
// let conn: Connection = ...;
|
||||||
/// (See http://sqlite.org/c3ref/module.html)
|
// let mod: Module = ...; // VTab builder
|
||||||
// (partial/minimal implementation)
|
// conn.create_module("module", mod);
|
||||||
pub trait Module: Drop {
|
//
|
||||||
type V: VTab;
|
// conn.execute("CREATE VIRTUAL TABLE foo USING module(...)");
|
||||||
|
// \-> Module::xcreate
|
||||||
/// http://sqlite.org/vtab.html#xconnect
|
// |-> let vtab: VTab = ...; // on the heap
|
||||||
fn connect(conn: &Connection, args: &[&str]) -> Result<Self::V>; // xcreate() == xconnect()
|
// \-> conn.declare_vtab("CREATE TABLE foo (...)");
|
||||||
// drop() = destroy (http://sqlite.org/c3ref/create_module.html)
|
// conn = Connection::open(...);
|
||||||
}
|
// \-> Module::xconnect
|
||||||
|
// |-> let vtab: VTab = ...; // on the heap
|
||||||
/// VTab describes a particular instance of a virtual table.
|
// \-> conn.declare_vtab("CREATE TABLE foo (...)");
|
||||||
/// (See http://sqlite.org/c3ref/vtab.html)
|
//
|
||||||
// (partial/minimal implementation)
|
// conn.close();
|
||||||
pub trait VTab: Drop {
|
// \-> vtab.xdisconnect
|
||||||
type C: Cursor;
|
// conn.execute("DROP TABLE foo");
|
||||||
|
// \-> vtab.xDestroy
|
||||||
/// http://sqlite.org/vtab.html#xopen
|
//
|
||||||
fn open(&self) -> Result<Self::C>;
|
// let stmt = conn.prepare("SELECT ... FROM foo WHERE ...");
|
||||||
/// http://sqlite.org/vtab.html#xbestindex
|
// \-> vtab.xbestindex
|
||||||
fn best_index(&self) -> Result<()> {
|
// stmt.quey().next();
|
||||||
// TODO sqlite3_index_info*
|
// \-> vtab.xopen
|
||||||
Ok(())
|
// |-> let cursor: Cursor = ...; // on the heap
|
||||||
}
|
// |-> cursor.xfilter or xnext
|
||||||
// drop() = xdisconnect == xDestroy (http://sqlite.org/vtab.html#xdisconnect)
|
// |-> cursor.xeof
|
||||||
}
|
// \-> if not eof { cursor.column or xrowid } else { cursor.xclose }
|
||||||
|
//
|
||||||
/// Cursor that points into the virtual table and is used to loop through the virtual table.
|
|
||||||
/// (See http://sqlite.org/c3ref/vtab_cursor.html)
|
|
||||||
pub trait Cursor: Drop {
|
|
||||||
/// http://sqlite.org/vtab.html#xfilter
|
|
||||||
fn filter(&self) -> Result<()>; // TODO int idxNum, const char *idxStr, int argc, sqlite3_value **argv
|
|
||||||
/// http://sqlite.org/vtab.html#xnext
|
|
||||||
fn next(&self) -> Result<()>;
|
|
||||||
/// http://sqlite.org/vtab.html#xeof
|
|
||||||
fn eof(&self) -> bool;
|
|
||||||
/// http://sqlite.org/vtab.html#xcolumn
|
|
||||||
fn column<T: ToResult + Sized>(&self, col: i32) -> Result<T>;
|
|
||||||
/// http://sqlite.org/vtab.html#xrowid
|
|
||||||
fn rowid(&self) -> i64; // TODO vs Result<i64>
|
|
||||||
// drop() == http://sqlite.org/vtab.html#xclose
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
/// Register a virtual table implementation.
|
/// Register a virtual table implementation.
|
||||||
pub fn create_module<M>(&self, module_name: &str, module: M) -> Result<()>
|
pub fn create_module<A>(&self,
|
||||||
where M: Module
|
module_name: &str,
|
||||||
{
|
module: *const ffi::sqlite3_module,
|
||||||
|
aux: A)
|
||||||
|
-> Result<()> {
|
||||||
self.db
|
self.db
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.create_module(module_name, module)
|
.create_module(module_name, module, aux)
|
||||||
}
|
|
||||||
|
|
||||||
/// Declare the schema of a virtual table.
|
|
||||||
pub fn declare_vtab(&self, sql: &str) -> Result<()> {
|
|
||||||
self.db
|
|
||||||
.borrow_mut()
|
|
||||||
.declare_vtab(sql)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,18 +59,18 @@ unsafe extern "C" fn free_boxed_value<T>(p: *mut libc::c_void) {
|
|||||||
|
|
||||||
static RUST_MODULE: ffi::sqlite3_module = ffi::sqlite3_module {
|
static RUST_MODULE: ffi::sqlite3_module = ffi::sqlite3_module {
|
||||||
iVersion: 1,
|
iVersion: 1,
|
||||||
xCreate: Some(xCreate),
|
xCreate: Some(x_create),
|
||||||
xConnect: Some(xCreate), /* A virtual table is eponymous if its xCreate method is the exact same function as the xConnect method */
|
xConnect: Some(x_create), /* A virtual table is eponymous if its xCreate method is the exact same function as the xConnect method */
|
||||||
xBestIndex: Some(xBestIndex),
|
xBestIndex: Some(x_best_index),
|
||||||
xDisconnect: Some(xDestroy),
|
xDisconnect: Some(x_destroy),
|
||||||
xDestroy: Some(xDestroy),
|
xDestroy: Some(x_destroy),
|
||||||
xOpen: Some(xOpen),
|
xOpen: Some(x_open),
|
||||||
xClose: Some(xClose),
|
xClose: Some(x_close),
|
||||||
xFilter: Some(xFilter),
|
xFilter: Some(x_filter),
|
||||||
xNext: Some(xNext),
|
xNext: Some(x_next),
|
||||||
xEof: Some(xEof),
|
xEof: Some(x_eof),
|
||||||
xColumn: Some(xColumn),
|
xColumn: Some(x_column),
|
||||||
xRowid: Some(xRowid),
|
xRowid: Some(x_rowid),
|
||||||
xUpdate: None, // TODO
|
xUpdate: None, // TODO
|
||||||
xBegin: None,
|
xBegin: None,
|
||||||
xSync: None,
|
xSync: None,
|
||||||
@ -100,175 +83,217 @@ static RUST_MODULE: ffi::sqlite3_module = ffi::sqlite3_module {
|
|||||||
xRollbackTo: None,
|
xRollbackTo: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe extern "C" fn xCreate(arg1: *mut ffi::sqlite3,
|
unsafe extern "C" fn x_create(db: *mut ffi::sqlite3,
|
||||||
pAux: *mut libc::c_void,
|
aux: *mut libc::c_void,
|
||||||
argc: libc::c_int,
|
argc: libc::c_int,
|
||||||
argv: *const *const libc::c_char,
|
argv: *const *const libc::c_char,
|
||||||
ppVTab: *mut *mut ffi::sqlite3_vtab,
|
pp_vtab: *mut *mut ffi::sqlite3_vtab,
|
||||||
arg2: *mut *mut libc::c_char)
|
err_msg: *mut *mut libc::c_char)
|
||||||
-> libc::c_int {
|
-> libc::c_int {
|
||||||
unimplemented!()
|
match VTab::new(db, aux, argc, argv) {
|
||||||
}
|
Ok(vtab) => {
|
||||||
unsafe extern "C" fn xBestIndex(pVTab: *mut ffi::sqlite3_vtab,
|
let boxed_vtab: *mut VTab = Box::into_raw(Box::new(vtab));
|
||||||
info: *mut ffi::sqlite3_index_info)
|
*pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab;
|
||||||
-> libc::c_int {
|
ffi::SQLITE_OK
|
||||||
unimplemented!()
|
}
|
||||||
}
|
Err(err) => {
|
||||||
unsafe extern "C" fn xDestroy(pVTab: *mut ffi::sqlite3_vtab) -> libc::c_int {
|
match err {
|
||||||
unimplemented!()
|
Error::SqliteFailure(err, s) => {
|
||||||
}
|
if let Some(s) = s {
|
||||||
unsafe extern "C" fn xOpen(pVTab: *mut ffi::sqlite3_vtab,
|
*err_msg = mprintf(&s);
|
||||||
ppCursor: *mut *mut ffi::sqlite3_vtab_cursor)
|
}
|
||||||
-> libc::c_int {
|
err.extended_code
|
||||||
unimplemented!()
|
}
|
||||||
}
|
_ => {
|
||||||
|
*err_msg = mprintf(err.description());
|
||||||
unsafe extern "C" fn xClose(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
ffi::SQLITE_ERROR
|
||||||
unimplemented!()
|
}
|
||||||
}
|
}
|
||||||
unsafe extern "C" fn xFilter(cursor: *mut ffi::sqlite3_vtab_cursor,
|
}
|
||||||
idxNum: libc::c_int,
|
|
||||||
idxStr: *const libc::c_char,
|
|
||||||
argc: libc::c_int,
|
|
||||||
argv: *mut *mut ffi::sqlite3_value)
|
|
||||||
-> libc::c_int {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
unsafe extern "C" fn xNext(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
unsafe extern "C" fn xEof(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
unsafe extern "C" fn xColumn(cursor: *mut ffi::sqlite3_vtab_cursor,
|
|
||||||
ctx: *mut ffi::sqlite3_context,
|
|
||||||
i: libc::c_int)
|
|
||||||
-> libc::c_int {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
unsafe extern "C" fn xRowid(cursor: *mut ffi::sqlite3_vtab_cursor,
|
|
||||||
pRowid: *mut ffi::sqlite3_int64)
|
|
||||||
-> libc::c_int {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn set_err_msg(cursor: *mut ffi::sqlite3_vtab_cursor,
|
|
||||||
err_msg: *mut libc::c_char)
|
|
||||||
-> libc::c_int {
|
|
||||||
let pVtab = (*cursor).pVtab;
|
|
||||||
if !(*pVtab).zErrMsg.is_null() {
|
|
||||||
ffi::sqlite3_free((*pVtab).zErrMsg as *mut libc::c_void)
|
|
||||||
}
|
}
|
||||||
(*pVtab).zErrMsg = err_msg;
|
}
|
||||||
return ffi::SQLITE_ERROR;
|
|
||||||
|
unsafe extern "C" fn x_destroy(vtab: *mut ffi::sqlite3_vtab) -> libc::c_int {
|
||||||
|
let vtab = vtab as *mut VTab;
|
||||||
|
let _: Box<VTab> = Box::from_raw(mem::transmute(vtab));
|
||||||
|
ffi::SQLITE_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct VTab {
|
||||||
|
/// Base class
|
||||||
|
base: ffi::sqlite3_vtab,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VTab {
|
||||||
|
fn new(db: *mut ffi::sqlite3,
|
||||||
|
aux: *mut libc::c_void,
|
||||||
|
argc: libc::c_int,
|
||||||
|
argv: *const *const libc::c_char)
|
||||||
|
-> Result<VTab> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
fn open(&self) -> VTabCursor {
|
||||||
|
VTabCursor::new()
|
||||||
|
}
|
||||||
|
unsafe fn declare_vtab(db: *mut ffi::sqlite3, sql: &str) -> Result<()> {
|
||||||
|
let c_sql = try!(CString::new(sql));
|
||||||
|
let rc = ffi::sqlite3_declare_vtab(db, c_sql.as_ptr());
|
||||||
|
if rc == ffi::SQLITE_OK {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(error_from_sqlite_code(rc, None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_err_msg(&mut self, err_msg: &str) -> libc::c_int {
|
||||||
|
if !self.base.zErrMsg.is_null() {
|
||||||
|
ffi::sqlite3_free(self.base.zErrMsg as *mut libc::c_void)
|
||||||
|
}
|
||||||
|
self.base.zErrMsg = mprintf(err_msg);
|
||||||
|
return ffi::SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn x_best_index(_vtab: *mut ffi::sqlite3_vtab,
|
||||||
|
_info: *mut ffi::sqlite3_index_info)
|
||||||
|
-> libc::c_int {
|
||||||
|
ffi::SQLITE_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn x_open(vtab: *mut ffi::sqlite3_vtab,
|
||||||
|
pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor)
|
||||||
|
-> libc::c_int {
|
||||||
|
let vtab = vtab as *mut VTab;
|
||||||
|
let cursor = (*vtab).open();
|
||||||
|
let boxed_cursor: *mut VTabCursor = Box::into_raw(Box::new(cursor));
|
||||||
|
*pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor;
|
||||||
|
ffi::SQLITE_OK
|
||||||
|
}
|
||||||
|
unsafe extern "C" fn x_close(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
||||||
|
let cursor = cursor as *mut VTabCursor;
|
||||||
|
let _: Box<VTabCursor> = Box::from_raw(mem::transmute(cursor));
|
||||||
|
ffi::SQLITE_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct VTabCursor {
|
||||||
|
/// Base class
|
||||||
|
base: ffi::sqlite3_vtab_cursor,
|
||||||
|
/// Current cursor position
|
||||||
|
i: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VTabCursor {
|
||||||
|
fn new() -> VTabCursor {
|
||||||
|
VTabCursor {
|
||||||
|
base: Default::default(),
|
||||||
|
i: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn vtab(&self) -> *mut VTab {
|
||||||
|
self.base.pVtab as *mut VTab
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter(&mut self) -> libc::c_int {
|
||||||
|
self.i = 0;
|
||||||
|
ffi::SQLITE_OK
|
||||||
|
}
|
||||||
|
fn next(&mut self) -> libc::c_int {
|
||||||
|
self.i = self.i + 1;
|
||||||
|
ffi::SQLITE_OK
|
||||||
|
}
|
||||||
|
fn eof(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
fn column(&self, ctx: *mut ffi::sqlite3_context, i: libc::c_int) -> libc::c_int {
|
||||||
|
// FIXME Result<()>
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
fn rowid(&self) -> i64 {
|
||||||
|
self.i as i64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn x_filter(cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||||
|
_idx_num: libc::c_int,
|
||||||
|
_idx_str: *const libc::c_char,
|
||||||
|
_argc: libc::c_int,
|
||||||
|
_argv: *mut *mut ffi::sqlite3_value)
|
||||||
|
-> libc::c_int {
|
||||||
|
let cursor = cursor as *mut VTabCursor;
|
||||||
|
(*cursor).filter()
|
||||||
|
}
|
||||||
|
unsafe extern "C" fn x_next(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
||||||
|
let cursor = cursor as *mut VTabCursor;
|
||||||
|
(*cursor).next()
|
||||||
|
}
|
||||||
|
unsafe extern "C" fn x_eof(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int {
|
||||||
|
let cursor = cursor as *mut VTabCursor;
|
||||||
|
(*cursor).eof() as libc::c_int
|
||||||
|
}
|
||||||
|
unsafe extern "C" fn x_column(cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||||
|
ctx: *mut ffi::sqlite3_context,
|
||||||
|
i: libc::c_int)
|
||||||
|
-> libc::c_int {
|
||||||
|
let cursor = cursor as *mut VTabCursor;
|
||||||
|
(*cursor).column(ctx, i)
|
||||||
|
}
|
||||||
|
unsafe extern "C" fn x_rowid(cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||||
|
p_rowid: *mut ffi::sqlite3_int64)
|
||||||
|
-> libc::c_int {
|
||||||
|
let cursor = cursor as *mut VTabCursor;
|
||||||
|
*p_rowid = (*cursor).rowid();
|
||||||
|
ffi::SQLITE_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn result_error(ctx: *mut ffi::sqlite3_context, err: Error) -> libc::c_int {
|
||||||
|
match err {
|
||||||
|
Error::SqliteFailure(err, s) => {
|
||||||
|
ffi::sqlite3_result_error_code(ctx, err.extended_code);
|
||||||
|
if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
|
||||||
|
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
|
||||||
|
}
|
||||||
|
err.extended_code
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_CORRUPT_VTAB);
|
||||||
|
if let Ok(cstr) = str_to_cstring(err.description()) {
|
||||||
|
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
|
||||||
|
}
|
||||||
|
ffi::SQLITE_CORRUPT_VTAB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Space to hold this error message string must be obtained from an SQLite memory allocation function.
|
||||||
|
unsafe fn mprintf(err_msg: &str) -> *mut ::libc::c_char {
|
||||||
|
let c_format = CString::new("%s").unwrap();
|
||||||
|
let c_err = CString::new(err_msg).unwrap();
|
||||||
|
ffi::sqlite3_mprintf(c_format.as_ptr(), c_err.as_ptr())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerConnection {
|
impl InnerConnection {
|
||||||
fn create_module<M>(&mut self, module_name: &str, module: M) -> Result<()>
|
fn create_module<A>(&mut self,
|
||||||
where M: Module
|
module_name: &str,
|
||||||
{
|
module: *const ffi::sqlite3_module,
|
||||||
let boxed_mod: *mut M = Box::into_raw(Box::new(module));
|
aux: A)
|
||||||
|
-> Result<()> {
|
||||||
|
// FIXME Both rust_module and aux need to be boxed
|
||||||
|
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 = unsafe {
|
||||||
ffi::sqlite3_create_module_v2(self.db(),
|
ffi::sqlite3_create_module_v2(self.db(),
|
||||||
c_name.as_ptr(),
|
c_name.as_ptr(),
|
||||||
ptr::null_mut(), // FIXME *const sqlite3_module
|
module,
|
||||||
mem::transmute(boxed_mod),
|
mem::transmute(boxed_aux),
|
||||||
Some(mem::transmute(free_boxed_value::<M>)))
|
Some(mem::transmute(free_boxed_value::<A>)))
|
||||||
};
|
};
|
||||||
self.decode_result(r)
|
self.decode_result(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_vtab(&mut self, sql: &str) -> Result<()> {
|
|
||||||
let c_sql = try!(str_to_cstring(sql));
|
|
||||||
let r = unsafe { ffi::sqlite3_declare_vtab(self.db(), c_sql.as_ptr()) };
|
|
||||||
self.decode_result(r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A intarray table
|
|
||||||
// #[repr(C)]
|
|
||||||
// struct IntArrayVTab {
|
|
||||||
// Base class
|
|
||||||
// base: ffi::sqlite3_vtab,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl VTab for IntArrayVTab {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Drop for IntArrayVTab {
|
|
||||||
// fn drop(&mut self) {
|
|
||||||
// FIXME
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// A intarray cursor
|
|
||||||
// #[repr(C)]
|
|
||||||
// struct IntArrayCursor {
|
|
||||||
// Base class
|
|
||||||
// base: ffi::sqlite3_vtab_cursor,
|
|
||||||
// i: usize
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Cursor for IntArrayCursor {
|
|
||||||
// type V = IntArrayVTab;
|
|
||||||
//
|
|
||||||
// fn filter(&mut self) -> Result<()> {
|
|
||||||
// self.i = 0;
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// fn next(&mut self) -> Result<()> {
|
|
||||||
// self.i = self.i + 1;
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// fn eof(&self) -> bool {
|
|
||||||
// false // FIXME
|
|
||||||
// }
|
|
||||||
// fn column(&self, ctx: *mut ffi::sqlite3_context, _: i32) -> Result<()> {
|
|
||||||
// let v: i64 = 0; // FIXME
|
|
||||||
// unsafe {
|
|
||||||
// v.set_result(ctx);
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// fn rowid(&self) -> i64 {
|
|
||||||
// self.i as i64
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Drop for IntArrayCursor {
|
|
||||||
// fn drop(&mut self) {
|
|
||||||
// FIXME
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[repr(C)]
|
|
||||||
// #[derive(Copy)]
|
|
||||||
// pub struct Struct_sqlite3_vtab {
|
|
||||||
// pub pModule: *const sqlite3_module,
|
|
||||||
// pub nRef: libc::c_int,
|
|
||||||
// pub zErrMsg: *mut libc::c_char,
|
|
||||||
// }
|
|
||||||
// #[repr(C)]
|
|
||||||
// #[derive(Copy)]
|
|
||||||
// pub struct Struct_sqlite3_vtab_cursor {
|
|
||||||
// pub pVtab: *mut sqlite3_vtab,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
// file:///usr/local/share/doc/rust/html/book/ffi.html#targeting-callbacks-to-rust-objects
|
|
||||||
//
|
|
||||||
// #[repr(C)]
|
|
||||||
// struct RustObject {
|
|
||||||
// a: i32,
|
|
||||||
// other members
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// file:///usr/local/share/doc/rust/html/book/associated-types.html#implementing-associated-types
|
|
||||||
// file:///usr/local/share/doc/rust/html/book/closures.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user