mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-19 17:34:19 +01:00
Remove TableReferenceType enum to clean up planner
This commit is contained in:
@@ -136,6 +136,7 @@ impl Database {
|
||||
name: name.to_string(),
|
||||
implementation: vtab_module,
|
||||
columns,
|
||||
args: None,
|
||||
};
|
||||
self.syms.borrow_mut().vtabs.insert(name.to_string(), vtab);
|
||||
ResultCode::OK
|
||||
|
||||
@@ -514,6 +514,7 @@ pub type StepResult = vdbe::StepResult;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VirtualTable {
|
||||
name: String,
|
||||
args: Option<Vec<ast::Expr>>,
|
||||
pub implementation: Rc<VTabModuleImpl>,
|
||||
columns: Vec<Column>,
|
||||
}
|
||||
@@ -537,7 +538,7 @@ impl VirtualTable {
|
||||
OwnedValue::Null => Ok(ExtValue::null()),
|
||||
OwnedValue::Integer(i) => Ok(ExtValue::from_integer(*i)),
|
||||
OwnedValue::Float(f) => Ok(ExtValue::from_float(*f)),
|
||||
OwnedValue::Text(t) => Ok(ExtValue::from_text((*t.value).clone())),
|
||||
OwnedValue::Text(t) => Ok(ExtValue::from_text(t.as_str().to_string())),
|
||||
OwnedValue::Blob(b) => Ok(ExtValue::from_blob((**b).clone())),
|
||||
other => Err(LimboError::ExtensionError(format!(
|
||||
"Unsupported value type: {:?}",
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::vdbe::builder::{ProgramBuilder, ProgramBuilderOpts, QueryMode};
|
||||
use crate::{schema::Schema, Result, SymbolTable};
|
||||
use sqlite3_parser::ast::{Expr, Limit, QualifiedName};
|
||||
|
||||
use super::plan::{TableReference, TableReferenceType};
|
||||
use super::plan::TableReference;
|
||||
|
||||
pub fn translate_delete(
|
||||
query_mode: QueryMode,
|
||||
@@ -48,7 +48,6 @@ pub fn prepare_delete_plan(
|
||||
identifier: table.name.clone(),
|
||||
op: Operation::Scan { iter_dir: None },
|
||||
join_info: None,
|
||||
reference_type: TableReferenceType::BTreeTable,
|
||||
}];
|
||||
|
||||
let mut where_predicates = vec![];
|
||||
|
||||
@@ -3,7 +3,7 @@ use sqlite3_parser::ast::{self, UnaryOperator};
|
||||
#[cfg(feature = "json")]
|
||||
use crate::function::JsonFunc;
|
||||
use crate::function::{Func, FuncCtx, MathFuncArity, ScalarFunc, VectorFunc};
|
||||
use crate::schema::Type;
|
||||
use crate::schema::{Table, Type};
|
||||
use crate::util::normalize_ident;
|
||||
use crate::vdbe::{
|
||||
builder::ProgramBuilder,
|
||||
@@ -13,7 +13,7 @@ use crate::vdbe::{
|
||||
use crate::Result;
|
||||
|
||||
use super::emitter::Resolver;
|
||||
use super::plan::{Operation, TableReference, TableReferenceType};
|
||||
use super::plan::{Operation, TableReference};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ConditionMetadata {
|
||||
@@ -1823,9 +1823,8 @@ pub fn translate_expr(
|
||||
match table_reference.op {
|
||||
// If we are reading a column from a table, we find the cursor that corresponds to
|
||||
// the table and read the column from the cursor.
|
||||
Operation::Scan { .. } | Operation::Search(_) => {
|
||||
match &table_reference.reference_type {
|
||||
TableReferenceType::BTreeTable => {
|
||||
Operation::Scan { .. } | Operation::Search(_) => match &table_reference.table {
|
||||
Table::BTree(_) => {
|
||||
let cursor_id = program.resolve_cursor_id(&table_reference.identifier);
|
||||
if *is_rowid_alias {
|
||||
program.emit_insn(Insn::RowId {
|
||||
@@ -1845,7 +1844,7 @@ pub fn translate_expr(
|
||||
maybe_apply_affinity(column.ty, target_register, program);
|
||||
Ok(target_register)
|
||||
}
|
||||
TableReferenceType::VirtualTable { .. } => {
|
||||
Table::Virtual(_) => {
|
||||
let cursor_id = program.resolve_cursor_id(&table_reference.identifier);
|
||||
program.emit_insn(Insn::VColumn {
|
||||
cursor_id,
|
||||
@@ -1854,18 +1853,8 @@ pub fn translate_expr(
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
TableReferenceType::Subquery {
|
||||
result_columns_start_reg,
|
||||
} => {
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: result_columns_start_reg + *column,
|
||||
dst_reg: target_register,
|
||||
amount: 0,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
// If we are reading a column from a subquery, we instead copy the column from the
|
||||
// subquery's result registers.
|
||||
Operation::Subquery {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use sqlite3_parser::ast;
|
||||
|
||||
use crate::{
|
||||
schema::Table,
|
||||
translate::result_row::emit_select_result,
|
||||
vdbe::{
|
||||
builder::{CursorType, ProgramBuilder},
|
||||
@@ -17,7 +18,7 @@ use super::{
|
||||
order_by::{order_by_sorter_insert, sorter_insert},
|
||||
plan::{
|
||||
IterationDirection, Operation, Search, SelectPlan, SelectQueryType, TableReference,
|
||||
TableReferenceType, WhereTerm,
|
||||
WhereTerm,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -78,21 +79,18 @@ pub fn init_loop(
|
||||
}
|
||||
match &table.op {
|
||||
Operation::Scan { .. } => {
|
||||
let ref_type = &table.reference_type;
|
||||
let cursor_id = program.alloc_cursor_id(
|
||||
Some(table.identifier.clone()),
|
||||
match ref_type {
|
||||
TableReferenceType::BTreeTable => {
|
||||
CursorType::BTreeTable(table.btree().unwrap().clone())
|
||||
}
|
||||
TableReferenceType::VirtualTable { .. } => {
|
||||
match &table.table {
|
||||
Table::BTree(_) => CursorType::BTreeTable(table.btree().unwrap().clone()),
|
||||
Table::Virtual(_) => {
|
||||
CursorType::VirtualTable(table.virtual_table().unwrap().clone())
|
||||
}
|
||||
other => panic!("Invalid table reference type in Scan: {:?}", other),
|
||||
},
|
||||
);
|
||||
match (mode, ref_type) {
|
||||
(OperationMode::SELECT, TableReferenceType::BTreeTable) => {
|
||||
match (mode, &table.table) {
|
||||
(OperationMode::SELECT, Table::BTree(_)) => {
|
||||
let root_page = table.btree().unwrap().root_page;
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
cursor_id,
|
||||
@@ -100,7 +98,7 @@ pub fn init_loop(
|
||||
});
|
||||
program.emit_insn(Insn::OpenReadAwait {});
|
||||
}
|
||||
(OperationMode::DELETE, TableReferenceType::BTreeTable) => {
|
||||
(OperationMode::DELETE, Table::BTree(_)) => {
|
||||
let root_page = table.btree().unwrap().root_page;
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
cursor_id,
|
||||
@@ -108,7 +106,7 @@ pub fn init_loop(
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
}
|
||||
(OperationMode::SELECT, TableReferenceType::VirtualTable { .. }) => {
|
||||
(OperationMode::SELECT, Table::Virtual(_)) => {
|
||||
program.emit_insn(Insn::VOpenAsync { cursor_id });
|
||||
program.emit_insn(Insn::VOpenAwait {});
|
||||
}
|
||||
@@ -258,10 +256,9 @@ pub fn open_loop(
|
||||
}
|
||||
}
|
||||
Operation::Scan { iter_dir } => {
|
||||
let ref_type = &table.reference_type;
|
||||
let cursor_id = program.resolve_cursor_id(&table.identifier);
|
||||
|
||||
if !matches!(ref_type, TableReferenceType::VirtualTable { .. }) {
|
||||
if !matches!(&table.table, Table::Virtual(_)) {
|
||||
if iter_dir
|
||||
.as_ref()
|
||||
.is_some_and(|dir| *dir == IterationDirection::Backwards)
|
||||
@@ -271,8 +268,8 @@ pub fn open_loop(
|
||||
program.emit_insn(Insn::RewindAsync { cursor_id });
|
||||
}
|
||||
}
|
||||
match ref_type {
|
||||
TableReferenceType::BTreeTable => program.emit_insn(
|
||||
match &table.table {
|
||||
Table::BTree(_) => program.emit_insn(
|
||||
if iter_dir
|
||||
.as_ref()
|
||||
.is_some_and(|dir| *dir == IterationDirection::Backwards)
|
||||
@@ -288,13 +285,18 @@ pub fn open_loop(
|
||||
}
|
||||
},
|
||||
),
|
||||
TableReferenceType::VirtualTable { args, .. } => {
|
||||
Table::Virtual(ref table) => {
|
||||
let args = if let Some(args) = table.args.as_ref() {
|
||||
args
|
||||
} else {
|
||||
&vec![]
|
||||
};
|
||||
let start_reg = program.alloc_registers(args.len());
|
||||
let mut cur_reg = start_reg;
|
||||
for arg in args {
|
||||
let reg = cur_reg;
|
||||
cur_reg += 1;
|
||||
translate_expr(program, Some(tables), arg, reg, &t_ctx.resolver)?;
|
||||
translate_expr(program, Some(tables), &arg, reg, &t_ctx.resolver)?;
|
||||
}
|
||||
program.emit_insn(Insn::VFilter {
|
||||
cursor_id,
|
||||
@@ -722,11 +724,10 @@ pub fn close_loop(
|
||||
});
|
||||
}
|
||||
Operation::Scan { iter_dir, .. } => {
|
||||
let ref_type = &table.reference_type;
|
||||
program.resolve_label(loop_labels.next, program.offset());
|
||||
let cursor_id = program.resolve_cursor_id(&table.identifier);
|
||||
match ref_type {
|
||||
TableReferenceType::BTreeTable { .. } => {
|
||||
match &table.table {
|
||||
Table::BTree(_) => {
|
||||
if iter_dir
|
||||
.as_ref()
|
||||
.is_some_and(|dir| *dir == IterationDirection::Backwards)
|
||||
@@ -750,7 +751,7 @@ pub fn close_loop(
|
||||
});
|
||||
}
|
||||
}
|
||||
TableReferenceType::VirtualTable { .. } => {
|
||||
Table::Virtual(_) => {
|
||||
program.emit_insn(Insn::VNext {
|
||||
cursor_id,
|
||||
pc_if_next: loop_labels.loop_start,
|
||||
|
||||
@@ -198,7 +198,6 @@ pub struct TableReference {
|
||||
pub identifier: String,
|
||||
/// The join info for this table reference, if it is the right side of a join (which all except the first table reference have)
|
||||
pub join_info: Option<JoinInfo>,
|
||||
pub reference_type: TableReferenceType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -225,35 +224,17 @@ pub enum Operation {
|
||||
},
|
||||
}
|
||||
|
||||
/// The type of the table reference, either BTreeTable or Subquery
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum TableReferenceType {
|
||||
/// A BTreeTable is a table that is stored on disk in a B-tree index.
|
||||
BTreeTable,
|
||||
/// A subquery.
|
||||
Subquery {
|
||||
/// The index of the first register in the query plan that contains the result columns of the subquery.
|
||||
result_columns_start_reg: usize,
|
||||
},
|
||||
/// A virtual table.
|
||||
VirtualTable {
|
||||
/// Arguments to pass e.g. generate_series(1, 10, 2)
|
||||
args: Vec<ast::Expr>,
|
||||
},
|
||||
}
|
||||
|
||||
impl TableReference {
|
||||
/// Returns the btree table for this table reference, if it is a BTreeTable.
|
||||
pub fn btree(&self) -> Option<Rc<BTreeTable>> {
|
||||
match &self.reference_type {
|
||||
TableReferenceType::BTreeTable => self.table.btree(),
|
||||
TableReferenceType::Subquery { .. } => None,
|
||||
TableReferenceType::VirtualTable { .. } => None,
|
||||
match &self.table {
|
||||
Table::BTree(_) => self.table.btree(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn virtual_table(&self) -> Option<Rc<VirtualTable>> {
|
||||
match &self.reference_type {
|
||||
TableReferenceType::VirtualTable { .. } => self.table.virtual_table(),
|
||||
match &self.table {
|
||||
Table::Virtual(_) => self.table.virtual_table(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -280,9 +261,6 @@ impl TableReference {
|
||||
result_columns_start_reg: 0, // Will be set in the bytecode emission phase
|
||||
},
|
||||
table,
|
||||
reference_type: TableReferenceType::Subquery {
|
||||
result_columns_start_reg: 0, // Will be set in the bytecode emission phase
|
||||
},
|
||||
identifier: identifier.clone(),
|
||||
join_info,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{
|
||||
plan::{
|
||||
Aggregate, JoinInfo, Operation, Plan, ResultSetColumn, SelectQueryType, TableReference,
|
||||
TableReferenceType, WhereTerm,
|
||||
WhereTerm,
|
||||
},
|
||||
select::prepare_select_plan,
|
||||
SymbolTable,
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
schema::{Schema, Table},
|
||||
util::{exprs_are_equivalent, normalize_ident},
|
||||
vdbe::BranchOffset,
|
||||
Result,
|
||||
Result, VirtualTable,
|
||||
};
|
||||
use sqlite3_parser::ast::{self, Expr, FromClause, JoinType, Limit, UnaryOperator};
|
||||
|
||||
@@ -301,7 +301,6 @@ fn parse_from_clause_table(
|
||||
table: Table::BTree(table.clone()),
|
||||
identifier: alias.unwrap_or(normalized_qualified_name),
|
||||
join_info: None,
|
||||
reference_type: TableReferenceType::BTreeTable,
|
||||
})
|
||||
}
|
||||
ast::SelectTable::Select(subselect, maybe_alias) => {
|
||||
@@ -320,9 +319,9 @@ fn parse_from_clause_table(
|
||||
.unwrap_or(format!("subquery_{}", cur_table_index));
|
||||
Ok(TableReference::new_subquery(identifier, subplan, None))
|
||||
}
|
||||
ast::SelectTable::TableCall(qualified_name, mut maybe_args, maybe_alias) => {
|
||||
let normalized_name = normalize_ident(qualified_name.name.0.as_str());
|
||||
let Some(vtab) = syms.vtabs.get(&normalized_name) else {
|
||||
ast::SelectTable::TableCall(qualified_name, maybe_args, maybe_alias) => {
|
||||
let normalized_name = &normalize_ident(qualified_name.name.0.as_str());
|
||||
let Some(vtab) = syms.vtabs.get(normalized_name) else {
|
||||
crate::bail_parse_error!("Virtual table {} not found", normalized_name);
|
||||
};
|
||||
let alias = maybe_alias
|
||||
@@ -331,16 +330,22 @@ fn parse_from_clause_table(
|
||||
ast::As::As(id) => id.0.clone(),
|
||||
ast::As::Elided(id) => id.0.clone(),
|
||||
})
|
||||
.unwrap_or(normalized_name);
|
||||
.unwrap_or(normalized_name.to_string());
|
||||
|
||||
Ok(TableReference {
|
||||
op: Operation::Scan { iter_dir: None },
|
||||
join_info: None,
|
||||
table: Table::Virtual(vtab.clone().into()),
|
||||
table: Table::Virtual(
|
||||
VirtualTable {
|
||||
name: normalized_name.clone(),
|
||||
args: maybe_args,
|
||||
implementation: vtab.implementation.clone(),
|
||||
columns: vtab.columns.clone(),
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
.into(),
|
||||
identifier: alias.clone(),
|
||||
reference_type: TableReferenceType::VirtualTable {
|
||||
args: maybe_args.take().unwrap_or_default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
_ => todo!(),
|
||||
|
||||
@@ -307,7 +307,7 @@ def test_crypto(pipe):
|
||||
run_test(
|
||||
pipe,
|
||||
"SELECT crypto_blake('a');",
|
||||
lambda res: "Error" in res,
|
||||
lambda res: "Parse error" in res,
|
||||
"crypto_blake3 returns null when ext not loaded",
|
||||
)
|
||||
run_test(
|
||||
|
||||
Reference in New Issue
Block a user