Last active
June 12, 2018 19:21
-
-
Save siscia/c6c8c6637f93e56a70a226e1ab643ab4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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