mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-24 18:01:37 +08:00
Ensure Virtual tables can be declared outside rusqlite
crate
Not sure it is the way to go.
This commit is contained in:
parent
ce39b9a3c0
commit
823f3c96aa
@ -58,6 +58,9 @@ harness = false
|
||||
[[test]]
|
||||
name = "deny_single_threaded_sqlite_config"
|
||||
|
||||
[[test]]
|
||||
name = "vtab"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = [ "backup", "blob", "chrono", "functions", "limits", "load_extension", "serde_json", "trace" ]
|
||||
all-features = false
|
||||
|
@ -216,12 +216,12 @@ impl error::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
// These are public but not re-exported by lib.rs, so only visible within crate.
|
||||
|
||||
pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
|
||||
Error::SqliteFailure(ffi::Error::new(code), message)
|
||||
}
|
||||
|
||||
// These are public but not re-exported by lib.rs, so only visible within crate.
|
||||
|
||||
pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
|
||||
let message = if db.is_null() {
|
||||
None
|
||||
|
@ -75,7 +75,7 @@ use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||
use std::os::raw::{c_int, c_char};
|
||||
|
||||
use types::{ToSql, ValueRef};
|
||||
use error::{error_from_sqlite_code, error_from_handle};
|
||||
use error::error_from_handle;
|
||||
use raw_statement::RawStatement;
|
||||
use cache::StatementCache;
|
||||
|
||||
@ -91,7 +91,7 @@ pub use transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior}
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub use error::SqliteError;
|
||||
pub use error::Error;
|
||||
pub use error::{Error, error_from_sqlite_code};
|
||||
pub use ffi::ErrorCode;
|
||||
|
||||
pub use cache::CachedStatement;
|
||||
|
@ -45,7 +45,7 @@ use {str_to_cstring, Connection, Error, InnerConnection, Result};
|
||||
// ffi::sqlite3_vtab => VTab
|
||||
// ffi::sqlite3_vtab_cursor => VTabCursor
|
||||
|
||||
pub struct VTabConnection(*mut ffi::sqlite3);
|
||||
pub struct VTabConnection(pub *mut ffi::sqlite3);
|
||||
|
||||
impl VTabConnection {
|
||||
/// Get access to the underlying SQLite database connection handle.
|
||||
@ -110,7 +110,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IndexInfo(*mut ffi::sqlite3_index_info);
|
||||
pub struct IndexInfo(pub *mut ffi::sqlite3_index_info);
|
||||
|
||||
impl IndexInfo {
|
||||
pub fn constraints(&self) -> IndexConstraintIter {
|
||||
@ -265,7 +265,7 @@ pub trait VTabCursor: Sized {
|
||||
fn rowid(&self) -> Result<i64>;
|
||||
}
|
||||
|
||||
pub struct Context(*mut ffi::sqlite3_context);
|
||||
pub struct Context(pub *mut ffi::sqlite3_context);
|
||||
|
||||
impl Context {
|
||||
pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
|
||||
@ -276,7 +276,7 @@ impl Context {
|
||||
}
|
||||
|
||||
pub struct Values<'a> {
|
||||
args: &'a [*mut ffi::sqlite3_value],
|
||||
pub args: &'a [*mut ffi::sqlite3_value],
|
||||
}
|
||||
|
||||
impl<'a> Values<'a> {
|
||||
@ -585,6 +585,7 @@ macro_rules! eponymous_module {
|
||||
};
|
||||
} // eponymous_module macro end
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! create_or_connect {
|
||||
($module:ident, $vtab:ident, $aux:ty, $create_or_connect:ident, $module_func:ident) => {
|
||||
unsafe extern "C" fn $create_or_connect(
|
||||
@ -598,7 +599,7 @@ macro_rules! create_or_connect {
|
||||
use std::error::Error as StdError;
|
||||
use std::ffi::CStr;
|
||||
use std::slice;
|
||||
use vtab::mprintf;
|
||||
use $crate::vtab::mprintf;
|
||||
|
||||
let mut conn = VTabConnection(db);
|
||||
let aux = aux as *mut $aux;
|
||||
@ -643,6 +644,7 @@ macro_rules! create_or_connect {
|
||||
};
|
||||
} // create_or_connect macro end
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! common_decl {
|
||||
(
|
||||
$module:ident,
|
||||
@ -667,7 +669,7 @@ macro_rules! common_decl {
|
||||
info: *mut ffi::sqlite3_index_info,
|
||||
) -> c_int {
|
||||
use std::error::Error as StdError;
|
||||
use vtab::set_err_msg;
|
||||
use $crate::vtab::set_err_msg;
|
||||
let vt = vtab as *mut $vtab;
|
||||
let mut idx_info = IndexInfo(info);
|
||||
match (*vt).best_index(&mut idx_info) {
|
||||
@ -695,7 +697,7 @@ macro_rules! common_decl {
|
||||
pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor,
|
||||
) -> c_int {
|
||||
use std::error::Error as StdError;
|
||||
use vtab::set_err_msg;
|
||||
use $crate::vtab::set_err_msg;
|
||||
let vt = vtab as *mut $vtab;
|
||||
match (*vt).open() {
|
||||
Ok(cursor) => {
|
||||
@ -731,7 +733,7 @@ macro_rules! common_decl {
|
||||
use std::ffi::CStr;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
use vtab::{cursor_error, Values};
|
||||
use $crate::vtab::{cursor_error, Values};
|
||||
let idx_name = if idx_str.is_null() {
|
||||
None
|
||||
} else {
|
||||
@ -744,7 +746,7 @@ macro_rules! common_decl {
|
||||
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;
|
||||
use $crate::vtab::cursor_error;
|
||||
let cr = cursor as *mut $cursor;
|
||||
cursor_error(cursor, (*cr).next())
|
||||
}
|
||||
@ -757,7 +759,7 @@ macro_rules! common_decl {
|
||||
ctx: *mut ffi::sqlite3_context,
|
||||
i: c_int,
|
||||
) -> c_int {
|
||||
use vtab::{result_error, Context};
|
||||
use $crate::vtab::{result_error, Context};
|
||||
let cr = cursor as *mut $cursor;
|
||||
let mut ctxt = Context(ctx);
|
||||
result_error(ctx, (*cr).column(&mut ctxt, i))
|
||||
@ -766,7 +768,7 @@ macro_rules! common_decl {
|
||||
cursor: *mut ffi::sqlite3_vtab_cursor,
|
||||
p_rowid: *mut ffi::sqlite3_int64,
|
||||
) -> c_int {
|
||||
use vtab::cursor_error;
|
||||
use $crate::vtab::cursor_error;
|
||||
let cr = cursor as *mut $cursor;
|
||||
match (*cr).rowid() {
|
||||
Ok(rowid) => {
|
||||
@ -798,7 +800,7 @@ pub unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Res
|
||||
}
|
||||
|
||||
/// Virtual tables methods can set an error message by assigning a string to `zErrMsg`.
|
||||
unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
|
||||
pub 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 c_void);
|
||||
}
|
||||
@ -807,7 +809,7 @@ unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
|
||||
|
||||
/// To raise an error, the `column` method should use this method to set the error message
|
||||
/// and return the error code.
|
||||
unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
|
||||
pub unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
|
||||
use std::error::Error as StdError;
|
||||
match result {
|
||||
Ok(_) => ffi::SQLITE_OK,
|
||||
|
127
tests/vtab.rs
Normal file
127
tests/vtab.rs
Normal file
@ -0,0 +1,127 @@
|
||||
//! Ensure Virtual tables can be declared outside `rusqlite` crate.
|
||||
|
||||
#[cfg(feature = "vtab")]
|
||||
#[macro_use]
|
||||
extern crate rusqlite;
|
||||
extern crate libsqlite3_sys as ffi;
|
||||
|
||||
#[cfg(feature = "vtab")]
|
||||
#[test]
|
||||
fn test_dummy_module() {
|
||||
use ffi;
|
||||
use rusqlite::vtab::{Context, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
|
||||
use rusqlite::{error_from_sqlite_code, Connection, Error, Result};
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
|
||||
eponymous_module!(
|
||||
DUMMY_MODULE,
|
||||
DummyModule,
|
||||
DummyTab,
|
||||
(),
|
||||
DummyTabCursor,
|
||||
None,
|
||||
dummy_connect,
|
||||
dummy_best_index,
|
||||
dummy_disconnect,
|
||||
None,
|
||||
dummy_open,
|
||||
dummy_close,
|
||||
dummy_filter,
|
||||
dummy_next,
|
||||
dummy_eof,
|
||||
dummy_column,
|
||||
dummy_rowid
|
||||
);
|
||||
|
||||
#[repr(C)]
|
||||
struct DummyModule(&'static ffi::sqlite3_module);
|
||||
|
||||
impl Module for DummyModule {
|
||||
type Aux = ();
|
||||
type Table = DummyTab;
|
||||
|
||||
fn as_ptr(&self) -> *const ffi::sqlite3_module {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
_aux: Option<&()>,
|
||||
_args: &[&[u8]],
|
||||
) -> Result<(String, DummyTab)> {
|
||||
let vtab = DummyTab {
|
||||
base: ffi::sqlite3_vtab::default(),
|
||||
};
|
||||
Ok(("CREATE TABLE x(value)".to_owned(), vtab))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct DummyTab {
|
||||
/// Base class. Must be first
|
||||
base: ffi::sqlite3_vtab,
|
||||
}
|
||||
|
||||
impl VTab for DummyTab {
|
||||
type Cursor = DummyTabCursor;
|
||||
|
||||
fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
|
||||
info.set_estimated_cost(1.);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn open(&self) -> Result<DummyTabCursor> {
|
||||
Ok(DummyTabCursor::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[repr(C)]
|
||||
struct DummyTabCursor {
|
||||
/// Base class. Must be first
|
||||
base: ffi::sqlite3_vtab_cursor,
|
||||
/// The rowid
|
||||
row_id: i64,
|
||||
}
|
||||
|
||||
impl VTabCursor for DummyTabCursor {
|
||||
type Table = DummyTab;
|
||||
|
||||
fn vtab(&self) -> &DummyTab {
|
||||
unsafe { &*(self.base.pVtab as *const DummyTab) }
|
||||
}
|
||||
fn filter(
|
||||
&mut self,
|
||||
_idx_num: c_int,
|
||||
_idx_str: Option<&str>,
|
||||
_args: &Values,
|
||||
) -> Result<()> {
|
||||
self.row_id = 1;
|
||||
Ok(())
|
||||
}
|
||||
fn next(&mut self) -> Result<()> {
|
||||
self.row_id += 1;
|
||||
Ok(())
|
||||
}
|
||||
fn eof(&self) -> bool {
|
||||
self.row_id > 1
|
||||
}
|
||||
fn column(&self, ctx: &mut Context, _: c_int) -> Result<()> {
|
||||
ctx.set_result(&self.row_id)
|
||||
}
|
||||
fn rowid(&self) -> Result<i64> {
|
||||
Ok(self.row_id)
|
||||
}
|
||||
}
|
||||
|
||||
let db = Connection::open_in_memory().unwrap();
|
||||
|
||||
let module = DummyModule(&DUMMY_MODULE);
|
||||
|
||||
db.create_module("dummy", module, None).unwrap();
|
||||
|
||||
let mut s = db.prepare("SELECT * FROM dummy()").unwrap();
|
||||
|
||||
let dummy = s.query_row(&[], |row| row.get::<_, i32>(0)).unwrap();
|
||||
assert_eq!(1, dummy);
|
||||
}
|
Loading…
Reference in New Issue
Block a user