Skip to content

Instantly share code, notes, and snippets.

@siscia
Last active June 12, 2018 19:21
Show Gist options
  • Select an option

  • Save siscia/c6c8c6637f93e56a70a226e1ab643ab4 to your computer and use it in GitHub Desktop.

Select an option

Save siscia/c6c8c6637f93e56a70a226e1ab643ab4 to your computer and use it in GitHub Desktop.
Hi All,
I am facing a quite interesting problem.
I am trying to implement a new virtual table, everything seems alright, I receive SQLITE_OK code on the registration but as soon as I try to use the vtab that I just created I only get an error: "no such module: $NAME_VTAB"
It seems to me that I followed the documentation quite closely, moreover, I am not doing weird cast or particular alchemy with the code, with the exception that it is rust code and not plain C.
What I do is quite simple, I just call `sqlite3_create_module_v2` passing all the parameter.
Then I try to create a new virtual table doing something like: `CREATE VIRTUAL TABLE lalala USING REDISQL_TABLES_BRUTE_HASH();` where `REDISQL_TABLES_BRUTE_HASH` is the same name that I pass to `sqlite3_create_module_v2` and it just doesn't work.
I really don't understand what I am doing wrong.
Is there any step I am missing?
For reference the code is here: https://gist.github.com/siscia/c6c8c6637f93e56a70a226e1ab643ab4
use redis_type::Context;
use redisql_error::RediSQLError;
use sqlite::ffi;
use sqlite::ffi::{sqlite3_create_module_v2, sqlite3_vtab};
use sqlite::{SQLite3Error, SQLiteConnection};
use std::cell::RefCell;
use std::ffi::{CStr, CString};
use std::os::raw;
use std::ptr;
use std::str::Utf8Error;
use std::sync::{Arc, Mutex};
static brute_hash_module: ffi::sqlite3_module = ffi::sqlite3_module {
iVersion: 1,
xBegin: None,
xBestIndex: Some(best_index_brute_hash),
xClose: Some(close_brute_hash),
xColumn: Some(column_brute_hash),
xCommit: None,
xConnect: Some(create_brute_hash),
xCreate: Some(create_brute_hash),
xDestroy: Some(disconnect_brute_hash),
xDisconnect: Some(disconnect_brute_hash),
xEof: Some(eof_brute_hash),
xFilter: Some(filter_brute_hash),
xFindFunction: None,
xNext: Some(next_brute_hash),
xOpen: Some(open_brute_hash),
xRelease: None,
xRename: Some(rename_brute_hash),
xRollback: None,
xRollbackTo: None,
xRowid: Some(rowid_brute_hash),
xSavepoint: None,
xSync: None,
xUpdate: None,
};
static brute_hash_name: &[u8] = b"REDISQL_TABLE_BRUTE_HASH\0";
#[repr(C)]
struct VirtualTable {
base: sqlite3_vtab,
ctx: Arc<RefCell<Option<Context>>>,
}
impl VirtualTable {
pub fn new(ctx: Arc<RefCell<Option<Context>>>) -> VirtualTable {
VirtualTable {
base: sqlite3_vtab {
nRef: 0,
pModule: ptr::null(),
zErrMsg: ptr::null_mut(),
},
ctx: ctx,
}
}
}
#[repr(C)]
struct VirtualTableCursor {
vtab: *mut sqlite3_vtab,
redis_cursor: Option<i64>,
}
pub fn register_modules<Conn>(
conn: Arc<Mutex<Conn>>,
) -> Result<Arc<Mutex<Option<Context>>>, SQLite3Error>
where
Conn: SQLiteConnection + Sized,
{
debug!("Registering modules");
let conn = conn.lock().unwrap();
match register_module_vtabs(conn.get_db()) {
Ok(context) => Ok(context),
_ => Err(conn.get_last_error()),
}
}
fn register_module_vtabs(
conn: *mut ffi::sqlite3,
) -> Result<Arc<Mutex<Option<Context>>>, ()> {
debug!("Registering REDISQL_TABLES_BRUTE_HASH");
let name = CString::new("REDISQL_TABLE_BRUTE_HASH").unwrap();
let name_ptr = name.as_ptr();
let client_data = Box::new(Arc::new(Mutex::new(None)));
let to_return = client_data.clone();
let destructor = None;
match unsafe {
sqlite3_create_module_v2(
conn,
brute_hash_name.as_ptr() as *const i8,
&brute_hash_module,
Box::into_raw(client_data) as *mut raw::c_void,
destructor,
)
} {
ffi::SQLITE_OK => Ok(*to_return),
_ => {
println!("Error in creating the vtab");
Err(())
}
}
}
unsafe fn get_str_at_index(
argv: *const *const raw::c_char,
index: isize,
) -> Result<&'static str, &'static str> {
match CStr::from_ptr(*argv.offset(index)).to_str() {
Ok(s) => Ok(s),
Err(_) => Err("Not UTF8 input string"),
}
}
fn create_table_name(
argc: isize,
argv: *const *const raw::c_char,
) -> Result<String, &'static str> {
let table_name = unsafe { get_str_at_index(argv, 2)? };
let mut table = format!("CREATE TABLE {} (ID STRING", table_name);
for i in 3..argc {
let column_name = unsafe { get_str_at_index(argv, i)? };
table.push_str(&format!(", {}", column_name));
}
table.push_str(");");
Ok(table)
}
fn set_error(to_set: *mut *mut raw::c_char, error: &str) {
let error = CString::new(error).unwrap();
unsafe {
*to_set =
ffi::sqlite3_mprintf(error.as_ptr() as *const raw::c_char)
};
}
// need to be sure that the context exist here and put it into pp_vtab
#[no_mangle]
pub extern "C" fn create_brute_hash(
conn: *mut ffi::sqlite3,
aux: *mut raw::c_void,
argc: raw::c_int,
argv: *const *const raw::c_char,
pp_vtab: *mut *mut ffi::sqlite3_vtab,
pz_err: *mut *mut raw::c_char,
) -> raw::c_int {
debug!("Creating BRUTE_HASH");
let table_name = match create_table_name(argc as isize, argv) {
Ok(name) => CString::new(name).unwrap(),
Err(err) => {
set_error(pz_err, err);
return ffi::SQLITE_ERROR;
}
};
if unsafe { ffi::sqlite3_declare_vtab(conn, table_name.as_ptr()) }
!= ffi::SQLITE_OK
{
set_error(pz_err, "Impossible to create the vtab");
return ffi::SQLITE_ERROR;
}
ffi::SQLITE_OK
}
extern "C" fn best_index_brute_hash(
p_vtab: *mut ffi::sqlite3_vtab,
index_info: *mut ffi::sqlite3_index_info,
) -> raw::c_int {
unsafe {
(*index_info).orderByConsumed = 0;
(*index_info).estimatedCost = 100_000.0;
}
ffi::SQLITE_OK
}
// need the context here, one way or another
extern "C" fn filter_brute_hash(
p_vtab_cursor: *mut ffi::sqlite3_vtab_cursor,
idx_num: raw::c_int,
idx_str: *const raw::c_char,
argc: raw::c_int,
argv: *mut *mut ffi::sqlite3_value,
) -> i32 {
ffi::SQLITE_OK
}
extern "C" fn next_brute_hash(
p_vtab_cursor: *mut ffi::sqlite3_vtab_cursor,
) -> i32 {
ffi::SQLITE_OK
}
extern "C" fn column_brute_hash(
p_vtab_cursor: *mut ffi::sqlite3_vtab_cursor,
sqlite_context: *mut ffi::sqlite3_context,
N: i32,
) -> i32 {
ffi::SQLITE_OK
}
extern "C" fn disconnect_brute_hash(
p_vtab: *mut ffi::sqlite3_vtab,
) -> i32 {
ffi::SQLITE_OK
}
extern "C" fn open_brute_hash(
p_vtab: *mut ffi::sqlite3_vtab,
p_vtab_cursor: *mut *mut ffi::sqlite3_vtab_cursor,
) -> i32 {
ffi::SQLITE_OK
}
extern "C" fn close_brute_hash(
p_vtab_cursor: *mut ffi::sqlite3_vtab_cursor,
) -> i32 {
ffi::SQLITE_OK
}
extern "C" fn eof_brute_hash(
p_vtab_cursor: *mut ffi::sqlite3_vtab_cursor,
) -> i32 {
true as i32
}
extern "C" fn rowid_brute_hash(
p_vtab_cursor: *mut ffi::sqlite3_vtab_cursor,
rowId: *mut i64,
) -> i32 {
ffi::SQLITE_OK
}
extern "C" fn rename_brute_hash(
p_vtab: *mut ffi::sqlite3_vtab,
new: *const raw::c_char,
) -> i32 {
ffi::SQLITE_OK
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment