Last active
April 1, 2024 12:57
-
-
Save dvas0004/84a8f4048dc60eb948a1a17d0ecb1d05 to your computer and use it in GitHub Desktop.
Revisions
-
dvas0004 revised this gist
Apr 1, 2024 . No changes.There are no files selected for viewing
-
dvas0004 created this gist
Apr 1, 2024 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,94 @@ use std::{ffi::c_int, marker::PhantomData}; use rusqlite::ffi; use rusqlite::{ffi::{sqlite3_vtab, sqlite3_vtab_cursor}, vtab::{Context, IndexInfo, VTab, VTabConnection, VTabCursor, Values}, Connection}; use std::os::raw::c_char; use rusqlite::{to_sqlite_error, Result}; #[repr(C)] struct Test { /// Base class. Must be first base: sqlite3_vtab, } #[derive(Default)] #[repr(C)] struct TestCursor<'vtab> { /// Base class. Must be first base: sqlite3_vtab_cursor, /// The rowid row_id: i64, phantom: PhantomData<&'vtab Test>, data: Vec<String>, // this is where we load and store our "external" data - see `open` } // Write implementation of VTab trait. // Step 1(a) from https://docs.rs/rusqlite/latest/rusqlite/vtab/index.html unsafe impl<'vtab> VTab<'vtab> for Test { type Aux = (); type Cursor = TestCursor<'vtab>; fn connect( _: &mut VTabConnection, _aux: Option<&()>, _args: &[&[u8]], ) -> Result<(String, Test), rusqlite::Error> { let vtab = Test { base: sqlite3_vtab::default() }; // our vtab schema is defined here Ok(("CREATE TABLE test(id INT, name TEXT)".to_owned(), vtab)) } fn best_index(&self, info: &mut IndexInfo) -> Result<(), rusqlite::Error> { info.set_estimated_cost(1.); Ok(()) } // this is where we do external calls (e.g. APIs, files) // to populate our external data fn open(&'vtab mut self) -> Result<TestCursor<'vtab>, rusqlite::Error> { let mut test_cursor = TestCursor::default(); test_cursor.data = vec!["a".to_owned(), "b".to_owned(), "c".to_owned()]; Ok(test_cursor) } } // Write implementation of VTabCursor trait. // Step 1(b) from https://docs.rs/rusqlite/latest/rusqlite/vtab/index.html unsafe impl VTabCursor for TestCursor<'_> { fn filter( &mut self, _idx_num: c_int, _idx_str: Option<&str>, _args: &Values<'_>, ) -> Result<(), rusqlite::Error> { Ok(()) } // next - how do we get the next record? fn next(&mut self) -> Result<(), rusqlite::Error> { self.row_id += 1; Ok(()) } // EOF - when should we stop calling `next`? fn eof(&self) -> bool { self.row_id >= self.data.len().try_into().unwrap() } // descibe the mappings between columns (expressed as numbers) and our data // stored in the cursor fn column(&self, ctx: &mut Context, col_number: c_int) -> Result<(), rusqlite::Error> { match col_number { 0 => ctx.set_result(&self.row_id), 1 => ctx.set_result(&self.data[self.row_id as usize]), _ => Err(rusqlite::Error::InvalidColumnName("n/a".to_owned())), } } fn rowid(&self) -> Result<i64, rusqlite::Error> { Ok(self.row_id) } }