mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-01 06:14:23 +01:00
Refactor vtable impl and remove Rc Refcell from module
This commit is contained in:
@@ -363,7 +363,7 @@ impl Connection {
|
||||
pub fn execute(self: &Rc<Connection>, sql: impl AsRef<str>) -> Result<()> {
|
||||
let sql = sql.as_ref();
|
||||
let db = &self.db;
|
||||
let syms: &SymbolTable = &db.syms.borrow();
|
||||
let syms: &SymbolTable = &db.syms.borrow_mut();
|
||||
let mut parser = Parser::new(sql.as_bytes());
|
||||
let cmd = parser.next()?;
|
||||
if let Some(cmd) = cmd {
|
||||
@@ -417,7 +417,7 @@ impl Connection {
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub fn load_extension<P: AsRef<std::ffi::OsStr>>(&self, path: P) -> Result<()> {
|
||||
Database::load_extension(self.db.as_ref(), path)
|
||||
Database::load_extension(&self.db, path)
|
||||
}
|
||||
|
||||
/// Close a connection and checkpoint.
|
||||
|
||||
@@ -68,20 +68,11 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_column_at(&self, index: usize) -> &Column {
|
||||
pub fn get_column_at(&self, index: usize) -> Option<&Column> {
|
||||
match self {
|
||||
Self::BTree(table) => table
|
||||
.columns
|
||||
.get(index)
|
||||
.expect("column index out of bounds"),
|
||||
Self::Pseudo(table) => table
|
||||
.columns
|
||||
.get(index)
|
||||
.expect("column index out of bounds"),
|
||||
Self::Virtual(table) => table
|
||||
.columns
|
||||
.get(index)
|
||||
.expect("column index out of bounds"),
|
||||
Self::BTree(table) => table.columns.get(index),
|
||||
Self::Pseudo(table) => table.columns.get(index),
|
||||
Self::Virtual(table) => table.columns.get(index),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +91,7 @@ impl Table {
|
||||
Self::Virtual(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn virtual_table(&self) -> Option<Rc<VirtualTable>> {
|
||||
match self {
|
||||
Self::Virtual(table) => Some(table.clone()),
|
||||
@@ -172,7 +164,7 @@ impl BTreeTable {
|
||||
sql.push_str(",\n");
|
||||
}
|
||||
sql.push_str(" ");
|
||||
sql.push_str(&column.name.as_ref().expect("column name is None"));
|
||||
sql.push_str(column.name.as_ref().expect("column name is None"));
|
||||
sql.push(' ');
|
||||
sql.push_str(&column.ty.to_string());
|
||||
}
|
||||
|
||||
@@ -1839,7 +1839,9 @@ pub fn translate_expr(
|
||||
dest: target_register,
|
||||
});
|
||||
}
|
||||
let column = table_reference.table.get_column_at(*column);
|
||||
let Some(column) = table_reference.table.get_column_at(*column) else {
|
||||
crate::bail_parse_error!("column index out of bounds");
|
||||
};
|
||||
maybe_apply_affinity(column.ty, target_register, program);
|
||||
Ok(target_register)
|
||||
}
|
||||
|
||||
@@ -307,7 +307,9 @@ impl Optimizable for ast::Expr {
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let column = table_reference.table.get_column_at(*column);
|
||||
let Some(column) = table_reference.table.get_column_at(*column) else {
|
||||
return Ok(None);
|
||||
};
|
||||
for index in available_indexes_for_table.iter() {
|
||||
if let Some(name) = column.name.as_ref() {
|
||||
if &index.columns.first().unwrap().name == name {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::{
|
||||
plan::{
|
||||
Aggregate, JoinInfo, Operation, Plan, ResultSetColumn, SelectQueryType, TableReference,
|
||||
|
||||
@@ -28,9 +28,9 @@ pub fn translate_select(
|
||||
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: count_plan_required_cursors(&select),
|
||||
approx_num_insns: estimate_num_instructions(&select),
|
||||
approx_num_labels: estimate_num_labels(&select),
|
||||
num_cursors: count_plan_required_cursors(select),
|
||||
approx_num_insns: estimate_num_instructions(select),
|
||||
approx_num_labels: estimate_num_labels(select),
|
||||
});
|
||||
emit_program(&mut program, select_plan, syms)?;
|
||||
Ok(program)
|
||||
|
||||
@@ -110,10 +110,15 @@ pub trait VTabModule: 'static {
|
||||
}
|
||||
|
||||
pub trait VTabCursor: Sized {
|
||||
type Error;
|
||||
fn rowid(&self) -> i64;
|
||||
fn column(&self, idx: u32) -> Value;
|
||||
fn eof(&self) -> bool;
|
||||
fn next(&mut self) -> ResultCode;
|
||||
fn set_error(&mut self, error: Self::Error);
|
||||
fn error(&self) -> Option<Self::Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
@@ -40,12 +40,14 @@ impl VTabModule for GenerateSeriesVTab {
|
||||
stop: 0,
|
||||
step: 0,
|
||||
current: 0,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn filter(cursor: &mut Self::VCursor, arg_count: i32, args: &[Value]) -> ResultCode {
|
||||
// args are the start, stop, and step
|
||||
if arg_count == 0 || arg_count > 3 {
|
||||
cursor.set_error("Expected between 1 and 3 arguments");
|
||||
return ResultCode::InvalidArgs;
|
||||
}
|
||||
let start = try_option!(args[0].to_integer(), ResultCode::InvalidArgs);
|
||||
@@ -84,6 +86,7 @@ struct GenerateSeriesCursor {
|
||||
stop: i64,
|
||||
step: i64,
|
||||
current: i64,
|
||||
error: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl GenerateSeriesCursor {
|
||||
@@ -101,6 +104,8 @@ impl GenerateSeriesCursor {
|
||||
}
|
||||
|
||||
impl VTabCursor for GenerateSeriesCursor {
|
||||
type Error = &'static str;
|
||||
|
||||
fn next(&mut self) -> ResultCode {
|
||||
GenerateSeriesCursor::next(self)
|
||||
}
|
||||
@@ -119,6 +124,14 @@ impl VTabCursor for GenerateSeriesCursor {
|
||||
}
|
||||
}
|
||||
|
||||
fn error(&self) -> Option<Self::Error> {
|
||||
self.error
|
||||
}
|
||||
|
||||
fn set_error(&mut self, err: &'static str) {
|
||||
self.error = Some(err);
|
||||
}
|
||||
|
||||
fn rowid(&self) -> i64 {
|
||||
((self.current - self.start) / self.step) + 1
|
||||
}
|
||||
|
||||
@@ -324,6 +324,89 @@ pub fn derive_agg_func(input: TokenStream) -> TokenStream {
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
/// Macro to derive a VTabModule for your extension. This macro will generate
|
||||
/// the necessary functions to register your module with core. You must implement
|
||||
/// the VTabModule trait for your struct, and the VTabCursor trait for your cursor.
|
||||
/// ```ignore
|
||||
///#[derive(Debug, VTabModuleDerive)]
|
||||
///struct CsvVTab;
|
||||
///impl VTabModule for CsvVTab {
|
||||
/// type VCursor = CsvCursor;
|
||||
/// const NAME: &'static str = "csv_data";
|
||||
///
|
||||
/// /// Declare the schema for your virtual table
|
||||
/// fn connect(api: &ExtensionApi) -> ResultCode {
|
||||
/// let sql = "CREATE TABLE csv_data(
|
||||
/// name TEXT,
|
||||
/// age TEXT,
|
||||
/// city TEXT
|
||||
/// )";
|
||||
/// api.declare_virtual_table(Self::NAME, sql)
|
||||
/// }
|
||||
/// /// Open the virtual table and return a cursor
|
||||
/// fn open() -> Self::VCursor {
|
||||
/// let csv_content = fs::read_to_string("data.csv").unwrap_or_default();
|
||||
/// let rows: Vec<Vec<String>> = csv_content
|
||||
/// .lines()
|
||||
/// .skip(1)
|
||||
/// .map(|line| {
|
||||
/// line.split(',')
|
||||
/// .map(|s| s.trim().to_string())
|
||||
/// .collect()
|
||||
/// })
|
||||
/// .collect();
|
||||
/// CsvCursor { rows, index: 0 }
|
||||
/// }
|
||||
/// /// Filter the virtual table based on arguments (omitted here for simplicity)
|
||||
/// fn filter(_cursor: &mut Self::VCursor, _arg_count: i32, _args: &[Value]) -> ResultCode {
|
||||
/// ResultCode::OK
|
||||
/// }
|
||||
/// /// Return the value for a given column index
|
||||
/// fn column(cursor: &Self::VCursor, idx: u32) -> Value {
|
||||
/// cursor.column(idx)
|
||||
/// }
|
||||
/// /// Move the cursor to the next row
|
||||
/// fn next(cursor: &mut Self::VCursor) -> ResultCode {
|
||||
/// if cursor.index < cursor.rows.len() - 1 {
|
||||
/// cursor.index += 1;
|
||||
/// ResultCode::OK
|
||||
/// } else {
|
||||
/// ResultCode::EOF
|
||||
/// }
|
||||
/// }
|
||||
/// fn eof(cursor: &Self::VCursor) -> bool {
|
||||
/// cursor.index >= cursor.rows.len()
|
||||
/// }
|
||||
/// #[derive(Debug)]
|
||||
/// struct CsvCursor {
|
||||
/// rows: Vec<Vec<String>>,
|
||||
/// index: usize,
|
||||
///
|
||||
/// impl CsvCursor {
|
||||
/// /// Returns the value for a given column index.
|
||||
/// fn column(&self, idx: u32) -> Value {
|
||||
/// let row = &self.rows[self.index];
|
||||
/// if (idx as usize) < row.len() {
|
||||
/// Value::from_text(&row[idx as usize])
|
||||
/// } else {
|
||||
/// Value::null()
|
||||
/// }
|
||||
/// }
|
||||
/// // Implement the VTabCursor trait for your virtual cursor
|
||||
/// impl VTabCursor for CsvCursor {
|
||||
/// fn next(&mut self) -> ResultCode {
|
||||
/// Self::next(self)
|
||||
/// }
|
||||
/// fn eof(&self) -> bool {
|
||||
/// self.index >= self.rows.len()
|
||||
/// }
|
||||
/// fn column(&self, idx: u32) -> Value {
|
||||
/// self.column(idx)
|
||||
/// }
|
||||
/// fn rowid(&self) -> i64 {
|
||||
/// self.index as i64
|
||||
/// }
|
||||
|
||||
#[proc_macro_derive(VTabModuleDerive)]
|
||||
pub fn derive_vtab_module(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
Reference in New Issue
Block a user