mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-09 11:14:20 +01:00
Merge 'core/translate: (refactor) use btreetablereference struct instead of tuple' from Jussi Saurio
`table` (a `Rc<BTreeTable>`) and `table_identifier` (a `String`) pretty much always go together in the current implementation, so makes sense to colocate them as a struct instead of passing around a tuple everywhere Closes #368
This commit is contained in:
@@ -18,7 +18,7 @@ use super::expr::{
|
||||
ConditionMetadata,
|
||||
};
|
||||
use super::optimizer::ExpressionResultCache;
|
||||
use super::plan::Plan;
|
||||
use super::plan::{BTreeTableReference, Plan};
|
||||
use super::plan::{Operator, ProjectionColumn};
|
||||
|
||||
/**
|
||||
@@ -32,19 +32,19 @@ pub trait Emitter {
|
||||
&mut self,
|
||||
pb: &mut ProgramBuilder,
|
||||
m: &mut Metadata,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
) -> Result<OpStepResult>;
|
||||
fn result_columns(
|
||||
&self,
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
metadata: &mut Metadata,
|
||||
cursor_override: Option<&SortCursorOverride>,
|
||||
) -> Result<usize>;
|
||||
fn result_row(
|
||||
&mut self,
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
metadata: &mut Metadata,
|
||||
cursor_override: Option<&SortCursorOverride>,
|
||||
) -> Result<()>;
|
||||
@@ -163,13 +163,12 @@ impl Emitter for Operator {
|
||||
&mut self,
|
||||
program: &mut ProgramBuilder,
|
||||
m: &mut Metadata,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
) -> Result<OpStepResult> {
|
||||
let current_operator_column_count = self.column_count(referenced_tables);
|
||||
match self {
|
||||
Operator::Scan {
|
||||
table,
|
||||
table_identifier,
|
||||
table_reference,
|
||||
id,
|
||||
step,
|
||||
predicates,
|
||||
@@ -182,10 +181,10 @@ impl Emitter for Operator {
|
||||
match *step {
|
||||
SCAN_OPEN_READ => {
|
||||
let cursor_id = program.alloc_cursor_id(
|
||||
Some(table_identifier.clone()),
|
||||
Some(Table::BTree(table.clone())),
|
||||
Some(table_reference.table_identifier.clone()),
|
||||
Some(Table::BTree(table_reference.table.clone())),
|
||||
);
|
||||
let root_page = table.root_page;
|
||||
let root_page = table_reference.table.root_page;
|
||||
let next_row_label = program.allocate_label();
|
||||
m.next_row_labels.insert(*id, next_row_label);
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
@@ -197,7 +196,8 @@ impl Emitter for Operator {
|
||||
Ok(OpStepResult::Continue)
|
||||
}
|
||||
SCAN_BODY => {
|
||||
let cursor_id = program.resolve_cursor_id(table_identifier, None);
|
||||
let cursor_id =
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, None);
|
||||
program.emit_insn(Insn::RewindAsync { cursor_id });
|
||||
let scan_loop_body_label = program.allocate_label();
|
||||
let halt_label = m.termination_label_stack.last().unwrap();
|
||||
@@ -237,7 +237,8 @@ impl Emitter for Operator {
|
||||
Ok(OpStepResult::ReadyToEmit)
|
||||
}
|
||||
SCAN_NEXT => {
|
||||
let cursor_id = program.resolve_cursor_id(table_identifier, None);
|
||||
let cursor_id =
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, None);
|
||||
program
|
||||
.resolve_label(*m.next_row_labels.get(id).unwrap(), program.offset());
|
||||
program.emit_insn(Insn::NextAsync { cursor_id });
|
||||
@@ -255,8 +256,7 @@ impl Emitter for Operator {
|
||||
}
|
||||
}
|
||||
Operator::Search {
|
||||
table,
|
||||
table_identifier,
|
||||
table_reference,
|
||||
search,
|
||||
predicates,
|
||||
step,
|
||||
@@ -270,8 +270,8 @@ impl Emitter for Operator {
|
||||
match *step {
|
||||
SEARCH_OPEN_READ => {
|
||||
let table_cursor_id = program.alloc_cursor_id(
|
||||
Some(table_identifier.clone()),
|
||||
Some(Table::BTree(table.clone())),
|
||||
Some(table_reference.table_identifier.clone()),
|
||||
Some(Table::BTree(table_reference.table.clone())),
|
||||
);
|
||||
|
||||
let next_row_label = program.allocate_label();
|
||||
@@ -285,7 +285,7 @@ impl Emitter for Operator {
|
||||
m.scan_loop_body_labels.push(scan_loop_body_label);
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
cursor_id: table_cursor_id,
|
||||
root_page: table.root_page,
|
||||
root_page: table_reference.table.root_page,
|
||||
});
|
||||
program.emit_insn(Insn::OpenReadAwait);
|
||||
|
||||
@@ -303,7 +303,8 @@ impl Emitter for Operator {
|
||||
Ok(OpStepResult::Continue)
|
||||
}
|
||||
SEARCH_BODY => {
|
||||
let table_cursor_id = program.resolve_cursor_id(table_identifier, None);
|
||||
let table_cursor_id =
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, None);
|
||||
|
||||
// Open the loop for the index search.
|
||||
// Primary key equality search is handled with a SeekRowid instruction which does not loop, since it is a single row lookup.
|
||||
@@ -521,7 +522,7 @@ impl Emitter for Operator {
|
||||
program.resolve_cursor_id(&index.name, None)
|
||||
}
|
||||
Search::PrimaryKeySearch { .. } => {
|
||||
program.resolve_cursor_id(table_identifier, None)
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, None)
|
||||
}
|
||||
Search::PrimaryKeyEq { .. } => unreachable!(),
|
||||
};
|
||||
@@ -642,11 +643,13 @@ impl Emitter for Operator {
|
||||
// If not, we set the right table cursor's "pseudo null bit" on, which means any Insn::Column will return NULL
|
||||
let right_cursor_id = match right.as_ref() {
|
||||
Operator::Scan {
|
||||
table_identifier, ..
|
||||
} => program.resolve_cursor_id(table_identifier, None),
|
||||
table_reference, ..
|
||||
} => program
|
||||
.resolve_cursor_id(&table_reference.table_identifier, None),
|
||||
Operator::Search {
|
||||
table_identifier, ..
|
||||
} => program.resolve_cursor_id(table_identifier, None),
|
||||
table_reference, ..
|
||||
} => program
|
||||
.resolve_cursor_id(&table_reference.table_identifier, None),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
program.emit_insn(Insn::NullRow {
|
||||
@@ -1394,41 +1397,37 @@ impl Emitter for Operator {
|
||||
fn result_columns(
|
||||
&self,
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
m: &mut Metadata,
|
||||
cursor_override: Option<&SortCursorOverride>,
|
||||
) -> Result<usize> {
|
||||
let col_count = self.column_count(referenced_tables);
|
||||
match self {
|
||||
Operator::Scan {
|
||||
table,
|
||||
table_identifier,
|
||||
..
|
||||
table_reference, ..
|
||||
} => {
|
||||
let start_reg = program.alloc_registers(col_count);
|
||||
let table = cursor_override
|
||||
.map(|c| c.pseudo_table.clone())
|
||||
.unwrap_or_else(|| Table::BTree(table.clone()));
|
||||
let cursor_id = cursor_override
|
||||
.map(|c| c.cursor_id)
|
||||
.unwrap_or_else(|| program.resolve_cursor_id(table_identifier, None));
|
||||
.unwrap_or_else(|| Table::BTree(table_reference.table.clone()));
|
||||
let cursor_id = cursor_override.map(|c| c.cursor_id).unwrap_or_else(|| {
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, None)
|
||||
});
|
||||
let start_column_offset = cursor_override.map(|c| c.sort_key_len).unwrap_or(0);
|
||||
translate_table_columns(program, cursor_id, &table, start_column_offset, start_reg);
|
||||
|
||||
Ok(start_reg)
|
||||
}
|
||||
Operator::Search {
|
||||
table,
|
||||
table_identifier,
|
||||
..
|
||||
table_reference, ..
|
||||
} => {
|
||||
let start_reg = program.alloc_registers(col_count);
|
||||
let table = cursor_override
|
||||
.map(|c| c.pseudo_table.clone())
|
||||
.unwrap_or_else(|| Table::BTree(table.clone()));
|
||||
let cursor_id = cursor_override
|
||||
.map(|c| c.cursor_id)
|
||||
.unwrap_or_else(|| program.resolve_cursor_id(table_identifier, None));
|
||||
.unwrap_or_else(|| Table::BTree(table_reference.table.clone()));
|
||||
let cursor_id = cursor_override.map(|c| c.cursor_id).unwrap_or_else(|| {
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, None)
|
||||
});
|
||||
let start_column_offset = cursor_override.map(|c| c.sort_key_len).unwrap_or(0);
|
||||
translate_table_columns(program, cursor_id, &table, start_column_offset, start_reg);
|
||||
|
||||
@@ -1544,13 +1543,16 @@ impl Emitter for Operator {
|
||||
cur_reg += 1;
|
||||
}
|
||||
ProjectionColumn::Star => {
|
||||
for (table, table_identifier) in referenced_tables.iter() {
|
||||
for table_reference in referenced_tables.iter() {
|
||||
let table = cursor_override
|
||||
.map(|c| c.pseudo_table.clone())
|
||||
.unwrap_or_else(|| Table::BTree(table.clone()));
|
||||
.unwrap_or_else(|| Table::BTree(table_reference.table.clone()));
|
||||
let cursor_id =
|
||||
cursor_override.map(|c| c.cursor_id).unwrap_or_else(|| {
|
||||
program.resolve_cursor_id(table_identifier, None)
|
||||
program.resolve_cursor_id(
|
||||
&table_reference.table_identifier,
|
||||
None,
|
||||
)
|
||||
});
|
||||
let start_column_offset =
|
||||
cursor_override.map(|c| c.sort_key_len).unwrap_or(0);
|
||||
@@ -1563,18 +1565,19 @@ impl Emitter for Operator {
|
||||
);
|
||||
}
|
||||
}
|
||||
ProjectionColumn::TableStar(_, table_identifier) => {
|
||||
let (table, table_identifier) = referenced_tables
|
||||
ProjectionColumn::TableStar(table_reference) => {
|
||||
let table_ref = referenced_tables
|
||||
.iter()
|
||||
.find(|(_, id)| id == table_identifier)
|
||||
.find(|t| t.table_identifier == table_reference.table_identifier)
|
||||
.unwrap();
|
||||
|
||||
let table = cursor_override
|
||||
.map(|c| c.pseudo_table.clone())
|
||||
.unwrap_or_else(|| Table::BTree(table.clone()));
|
||||
.unwrap_or_else(|| Table::BTree(table_ref.table.clone()));
|
||||
let cursor_id =
|
||||
cursor_override.map(|c| c.cursor_id).unwrap_or_else(|| {
|
||||
program.resolve_cursor_id(table_identifier, None)
|
||||
program
|
||||
.resolve_cursor_id(&table_reference.table_identifier, None)
|
||||
});
|
||||
let start_column_offset =
|
||||
cursor_override.map(|c| c.sort_key_len).unwrap_or(0);
|
||||
@@ -1597,7 +1600,7 @@ impl Emitter for Operator {
|
||||
fn result_row(
|
||||
&mut self,
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
m: &mut Metadata,
|
||||
cursor_override: Option<&SortCursorOverride>,
|
||||
) -> Result<()> {
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
vdbe::{builder::ProgramBuilder, BranchOffset, Insn},
|
||||
};
|
||||
|
||||
use super::plan::Aggregate;
|
||||
use super::plan::{Aggregate, BTreeTableReference};
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub struct ConditionMetadata {
|
||||
@@ -22,7 +22,7 @@ pub struct ConditionMetadata {
|
||||
|
||||
pub fn translate_condition_expr(
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
expr: &ast::Expr,
|
||||
cursor_hint: Option<usize>,
|
||||
condition_metadata: ConditionMetadata,
|
||||
@@ -555,7 +555,7 @@ pub fn translate_condition_expr(
|
||||
|
||||
pub fn get_cached_or_translate(
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: Option<&[(Rc<BTreeTable>, String)]>,
|
||||
referenced_tables: Option<&[BTreeTableReference]>,
|
||||
expr: &ast::Expr,
|
||||
cursor_hint: Option<usize>,
|
||||
cached_results: Option<&Vec<&CachedResult>>,
|
||||
@@ -582,7 +582,7 @@ pub fn get_cached_or_translate(
|
||||
|
||||
pub fn translate_expr(
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: Option<&[(Rc<BTreeTable>, String)]>,
|
||||
referenced_tables: Option<&[BTreeTableReference]>,
|
||||
expr: &ast::Expr,
|
||||
target_register: usize,
|
||||
cursor_hint: Option<usize>,
|
||||
@@ -1541,14 +1541,15 @@ pub fn resolve_ident_qualified(
|
||||
program: &ProgramBuilder,
|
||||
table_name: &str,
|
||||
ident: &str,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
cursor_hint: Option<usize>,
|
||||
) -> Result<(usize, Type, usize, bool)> {
|
||||
let ident = normalize_ident(ident);
|
||||
let table_name = normalize_ident(table_name);
|
||||
for (catalog_table, identifier) in referenced_tables.iter() {
|
||||
if *identifier == table_name {
|
||||
let res = catalog_table
|
||||
for table_reference in referenced_tables.iter() {
|
||||
if table_reference.table_identifier == table_name {
|
||||
let res = table_reference
|
||||
.table
|
||||
.columns
|
||||
.iter()
|
||||
.enumerate()
|
||||
@@ -1573,7 +1574,8 @@ pub fn resolve_ident_qualified(
|
||||
is_primary_key = res.1.primary_key;
|
||||
}
|
||||
}
|
||||
let cursor_id = program.resolve_cursor_id(identifier, cursor_hint);
|
||||
let cursor_id =
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, cursor_hint);
|
||||
return Ok((idx, col_type, cursor_id, is_primary_key));
|
||||
}
|
||||
}
|
||||
@@ -1588,18 +1590,25 @@ pub fn resolve_ident_qualified(
|
||||
pub fn resolve_ident_table(
|
||||
program: &ProgramBuilder,
|
||||
ident: &str,
|
||||
referenced_tables: Option<&[(Rc<BTreeTable>, String)]>,
|
||||
referenced_tables: Option<&[BTreeTableReference]>,
|
||||
cursor_hint: Option<usize>,
|
||||
) -> Result<(usize, Type, usize, bool)> {
|
||||
let ident = normalize_ident(ident);
|
||||
let mut found = Vec::new();
|
||||
for (catalog_table, identifier) in referenced_tables.unwrap() {
|
||||
let res = catalog_table
|
||||
for table_reference in referenced_tables.unwrap() {
|
||||
let res = table_reference
|
||||
.table
|
||||
.columns
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, col)| col.name == *ident)
|
||||
.map(|(idx, col)| (idx, col.ty, catalog_table.column_is_rowid_alias(col)));
|
||||
.map(|(idx, col)| {
|
||||
(
|
||||
idx,
|
||||
col.ty,
|
||||
table_reference.table.column_is_rowid_alias(col),
|
||||
)
|
||||
});
|
||||
let mut idx;
|
||||
let mut col_type;
|
||||
let mut is_rowid_alias;
|
||||
@@ -1616,10 +1625,11 @@ pub fn resolve_ident_table(
|
||||
}) {
|
||||
idx = res.0;
|
||||
col_type = res.1.ty;
|
||||
is_rowid_alias = catalog_table.column_is_rowid_alias(res.1);
|
||||
is_rowid_alias = table_reference.table.column_is_rowid_alias(res.1);
|
||||
}
|
||||
}
|
||||
let cursor_id = program.resolve_cursor_id(identifier, cursor_hint);
|
||||
let cursor_id =
|
||||
program.resolve_cursor_id(&table_reference.table_identifier, cursor_hint);
|
||||
found.push((idx, col_type, cursor_id, is_rowid_alias));
|
||||
}
|
||||
}
|
||||
@@ -1685,7 +1695,7 @@ pub fn translate_table_columns(
|
||||
|
||||
pub fn translate_aggregation(
|
||||
program: &mut ProgramBuilder,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
agg: &Aggregate,
|
||||
target_register: usize,
|
||||
cursor_hint: Option<usize>,
|
||||
|
||||
@@ -9,8 +9,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::plan::{
|
||||
get_table_ref_bitmask_for_ast_expr, get_table_ref_bitmask_for_operator, Direction, Operator,
|
||||
Plan, ProjectionColumn, Search,
|
||||
get_table_ref_bitmask_for_ast_expr, get_table_ref_bitmask_for_operator, BTreeTableReference,
|
||||
Direction, Operator, Plan, ProjectionColumn, Search,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -57,30 +57,17 @@ fn _operator_is_already_ordered_by(
|
||||
) -> Result<bool> {
|
||||
match operator {
|
||||
Operator::Scan {
|
||||
table,
|
||||
table_identifier,
|
||||
..
|
||||
} => {
|
||||
let tuple = (table.clone(), table_identifier.clone());
|
||||
Ok(key.is_primary_key_of(&tuple))
|
||||
}
|
||||
table_reference, ..
|
||||
} => Ok(key.is_primary_key_of(&table_reference)),
|
||||
Operator::Search {
|
||||
table,
|
||||
table_identifier,
|
||||
table_reference,
|
||||
search,
|
||||
..
|
||||
} => match search {
|
||||
Search::PrimaryKeyEq { .. } => {
|
||||
let tuple = (table.clone(), table_identifier.clone());
|
||||
Ok(key.is_primary_key_of(&tuple))
|
||||
}
|
||||
Search::PrimaryKeySearch { .. } => {
|
||||
let tuple = (table.clone(), table_identifier.clone());
|
||||
Ok(key.is_primary_key_of(&tuple))
|
||||
}
|
||||
Search::PrimaryKeyEq { .. } => Ok(key.is_primary_key_of(&table_reference)),
|
||||
Search::PrimaryKeySearch { .. } => Ok(key.is_primary_key_of(&table_reference)),
|
||||
Search::IndexSearch { index, .. } => {
|
||||
let tuple = (table.clone(), table_identifier.clone());
|
||||
let index_idx = key.check_index_scan(&tuple, available_indexes)?;
|
||||
let index_idx = key.check_index_scan(&table_reference, available_indexes)?;
|
||||
let index_is_the_same = index_idx
|
||||
.map(|i| Rc::ptr_eq(&available_indexes[i], index))
|
||||
.unwrap_or(false);
|
||||
@@ -102,7 +89,7 @@ fn _operator_is_already_ordered_by(
|
||||
|
||||
fn eliminate_unnecessary_orderby(
|
||||
operator: &mut Operator,
|
||||
referenced_tables: &Vec<(Rc<BTreeTable>, String)>,
|
||||
referenced_tables: &Vec<BTreeTableReference>,
|
||||
available_indexes: &Vec<Rc<Index>>,
|
||||
) -> Result<()> {
|
||||
match operator {
|
||||
@@ -134,15 +121,14 @@ fn eliminate_unnecessary_orderby(
|
||||
*/
|
||||
fn use_indexes(
|
||||
operator: &mut Operator,
|
||||
referenced_tables: &[(Rc<BTreeTable>, String)],
|
||||
referenced_tables: &[BTreeTableReference],
|
||||
available_indexes: &[Rc<Index>],
|
||||
) -> Result<()> {
|
||||
match operator {
|
||||
Operator::Search { .. } => Ok(()),
|
||||
Operator::Scan {
|
||||
table,
|
||||
table_reference,
|
||||
predicates: filter,
|
||||
table_identifier,
|
||||
id,
|
||||
..
|
||||
} => {
|
||||
@@ -153,11 +139,14 @@ fn use_indexes(
|
||||
let fs = filter.as_mut().unwrap();
|
||||
for i in 0..fs.len() {
|
||||
let f = fs[i].take_ownership();
|
||||
let table = referenced_tables
|
||||
let table_ref = referenced_tables
|
||||
.iter()
|
||||
.find(|(t, t_id)| Rc::ptr_eq(t, table) && t_id == table_identifier)
|
||||
.find(|t| {
|
||||
Rc::ptr_eq(&t.table, &table_reference.table)
|
||||
&& t.table_identifier == table_reference.table_identifier
|
||||
})
|
||||
.unwrap();
|
||||
match try_extract_index_search_expression(f, table, available_indexes)? {
|
||||
match try_extract_index_search_expression(f, table_ref, available_indexes)? {
|
||||
Either::Left(non_index_using_expr) => {
|
||||
fs[i] = non_index_using_expr;
|
||||
}
|
||||
@@ -165,8 +154,7 @@ fn use_indexes(
|
||||
fs.remove(i);
|
||||
*operator = Operator::Search {
|
||||
id: *id,
|
||||
table: table.0.clone(),
|
||||
table_identifier: table.1.clone(),
|
||||
table_reference: table_ref.clone(),
|
||||
predicates: Some(fs.clone()),
|
||||
search: index_search,
|
||||
step: 0,
|
||||
@@ -363,7 +351,7 @@ fn eliminate_constants(operator: &mut Operator) -> Result<ConstantConditionElimi
|
||||
*/
|
||||
fn push_predicates(
|
||||
operator: &mut Operator,
|
||||
referenced_tables: &Vec<(Rc<BTreeTable>, String)>,
|
||||
referenced_tables: &Vec<BTreeTableReference>,
|
||||
) -> Result<()> {
|
||||
match operator {
|
||||
Operator::Filter {
|
||||
@@ -465,17 +453,17 @@ fn push_predicates(
|
||||
fn push_predicate(
|
||||
operator: &mut Operator,
|
||||
predicate: ast::Expr,
|
||||
referenced_tables: &Vec<(Rc<BTreeTable>, String)>,
|
||||
referenced_tables: &Vec<BTreeTableReference>,
|
||||
) -> Result<Option<ast::Expr>> {
|
||||
match operator {
|
||||
Operator::Scan {
|
||||
predicates,
|
||||
table_identifier,
|
||||
table_reference,
|
||||
..
|
||||
} => {
|
||||
let table_index = referenced_tables
|
||||
.iter()
|
||||
.position(|(_, t_id)| t_id == table_identifier)
|
||||
.position(|t| t.table_identifier == table_reference.table_identifier)
|
||||
.unwrap();
|
||||
|
||||
let predicate_bitmask =
|
||||
@@ -751,7 +739,7 @@ fn find_indexes_of_all_result_columns_in_operator_that_match_expr_either_fully_o
|
||||
}
|
||||
}
|
||||
ProjectionColumn::Star => {}
|
||||
ProjectionColumn::TableStar(_, _) => {}
|
||||
ProjectionColumn::TableStar(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,21 +973,21 @@ pub trait Optimizable {
|
||||
.check_constant()?
|
||||
.map_or(false, |c| c == ConstantPredicate::AlwaysFalse))
|
||||
}
|
||||
fn is_primary_key_of(&self, table: &(Rc<BTreeTable>, String)) -> bool;
|
||||
fn is_primary_key_of(&self, table_reference: &BTreeTableReference) -> bool;
|
||||
fn check_index_scan(
|
||||
&mut self,
|
||||
table: &(Rc<BTreeTable>, String),
|
||||
table_reference: &BTreeTableReference,
|
||||
available_indexes: &[Rc<Index>],
|
||||
) -> Result<Option<usize>>;
|
||||
}
|
||||
|
||||
impl Optimizable for ast::Expr {
|
||||
fn is_primary_key_of(&self, table: &(Rc<BTreeTable>, String)) -> bool {
|
||||
fn is_primary_key_of(&self, table_reference: &BTreeTableReference) -> bool {
|
||||
match self {
|
||||
ast::Expr::Id(ident) => {
|
||||
let ident = normalize_ident(&ident.0);
|
||||
table
|
||||
.0
|
||||
table_reference
|
||||
.table
|
||||
.get_column(&ident)
|
||||
.map_or(false, |(_, c)| c.primary_key)
|
||||
}
|
||||
@@ -1007,9 +995,9 @@ impl Optimizable for ast::Expr {
|
||||
let tbl = normalize_ident(&tbl.0);
|
||||
let ident = normalize_ident(&ident.0);
|
||||
|
||||
tbl == table.1
|
||||
&& table
|
||||
.0
|
||||
tbl == table_reference.table_identifier
|
||||
&& table_reference
|
||||
.table
|
||||
.get_column(&ident)
|
||||
.map_or(false, |(_, c)| c.primary_key)
|
||||
}
|
||||
@@ -1018,7 +1006,7 @@ impl Optimizable for ast::Expr {
|
||||
}
|
||||
fn check_index_scan(
|
||||
&mut self,
|
||||
table: &(Rc<BTreeTable>, String),
|
||||
table_reference: &BTreeTableReference,
|
||||
available_indexes: &[Rc<Index>],
|
||||
) -> Result<Option<usize>> {
|
||||
match self {
|
||||
@@ -1028,7 +1016,8 @@ impl Optimizable for ast::Expr {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, i)| {
|
||||
i.table_name == table.1 && i.columns.iter().any(|c| c.name == ident)
|
||||
i.table_name == table_reference.table_identifier
|
||||
&& i.columns.iter().any(|c| c.name == ident)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if indexes.is_empty() {
|
||||
@@ -1042,7 +1031,7 @@ impl Optimizable for ast::Expr {
|
||||
ast::Expr::Qualified(_, ident) => {
|
||||
let ident = normalize_ident(&ident.0);
|
||||
let index = available_indexes.iter().enumerate().find(|(_, i)| {
|
||||
if i.table_name != table.0.name {
|
||||
if i.table_name != table_reference.table.name {
|
||||
return false;
|
||||
}
|
||||
i.columns.iter().any(|c| normalize_ident(&c.name) == ident)
|
||||
@@ -1053,11 +1042,11 @@ impl Optimizable for ast::Expr {
|
||||
Ok(Some(index.unwrap().0))
|
||||
}
|
||||
ast::Expr::Binary(lhs, op, rhs) => {
|
||||
let lhs_index = lhs.check_index_scan(table, available_indexes)?;
|
||||
let lhs_index = lhs.check_index_scan(table_reference, available_indexes)?;
|
||||
if lhs_index.is_some() {
|
||||
return Ok(lhs_index);
|
||||
}
|
||||
let rhs_index = rhs.check_index_scan(table, available_indexes)?;
|
||||
let rhs_index = rhs.check_index_scan(table_reference, available_indexes)?;
|
||||
if rhs_index.is_some() {
|
||||
// swap lhs and rhs
|
||||
let lhs_new = rhs.take_ownership();
|
||||
@@ -1196,12 +1185,12 @@ pub enum Either<T, U> {
|
||||
|
||||
pub fn try_extract_index_search_expression(
|
||||
expr: ast::Expr,
|
||||
table: &(Rc<BTreeTable>, String),
|
||||
table_reference: &BTreeTableReference,
|
||||
available_indexes: &[Rc<Index>],
|
||||
) -> Result<Either<ast::Expr, Search>> {
|
||||
match expr {
|
||||
ast::Expr::Binary(mut lhs, operator, mut rhs) => {
|
||||
if lhs.is_primary_key_of(table) {
|
||||
if lhs.is_primary_key_of(table_reference) {
|
||||
match operator {
|
||||
ast::Operator::Equals => {
|
||||
return Ok(Either::Right(Search::PrimaryKeyEq { cmp_expr: *rhs }));
|
||||
@@ -1219,7 +1208,7 @@ pub fn try_extract_index_search_expression(
|
||||
}
|
||||
}
|
||||
|
||||
if rhs.is_primary_key_of(table) {
|
||||
if rhs.is_primary_key_of(table_reference) {
|
||||
match operator {
|
||||
ast::Operator::Equals => {
|
||||
return Ok(Either::Right(Search::PrimaryKeyEq { cmp_expr: *lhs }));
|
||||
@@ -1237,7 +1226,7 @@ pub fn try_extract_index_search_expression(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(index_index) = lhs.check_index_scan(table, available_indexes)? {
|
||||
if let Some(index_index) = lhs.check_index_scan(table_reference, available_indexes)? {
|
||||
match operator {
|
||||
ast::Operator::Equals
|
||||
| ast::Operator::Greater
|
||||
@@ -1254,7 +1243,7 @@ pub fn try_extract_index_search_expression(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(index_index) = rhs.check_index_scan(table, available_indexes)? {
|
||||
if let Some(index_index) = rhs.check_index_scan(table_reference, available_indexes)? {
|
||||
match operator {
|
||||
ast::Operator::Equals
|
||||
| ast::Operator::Greater
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::{
|
||||
#[derive(Debug)]
|
||||
pub struct Plan {
|
||||
pub root_operator: Operator,
|
||||
pub referenced_tables: Vec<(Rc<BTreeTable>, String)>,
|
||||
pub referenced_tables: Vec<BTreeTableReference>,
|
||||
pub available_indexes: Vec<Rc<Index>>,
|
||||
}
|
||||
|
||||
@@ -111,8 +111,7 @@ pub enum Operator {
|
||||
// e.g. SELECT * FROM t1 WHERE t1.foo = 5
|
||||
Scan {
|
||||
id: usize,
|
||||
table: Rc<BTreeTable>,
|
||||
table_identifier: String,
|
||||
table_reference: BTreeTableReference,
|
||||
predicates: Option<Vec<ast::Expr>>,
|
||||
step: usize,
|
||||
},
|
||||
@@ -121,8 +120,7 @@ pub enum Operator {
|
||||
// (i.e. a primary key or a secondary index)
|
||||
Search {
|
||||
id: usize,
|
||||
table: Rc<BTreeTable>,
|
||||
table_identifier: String,
|
||||
table_reference: BTreeTableReference,
|
||||
search: Search,
|
||||
predicates: Option<Vec<ast::Expr>>,
|
||||
step: usize,
|
||||
@@ -133,6 +131,12 @@ pub enum Operator {
|
||||
Nothing,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BTreeTableReference {
|
||||
pub table: Rc<BTreeTable>,
|
||||
pub table_identifier: String,
|
||||
}
|
||||
|
||||
/// An enum that represents a search operation that can be used to search for a row in a table using an index
|
||||
/// (i.e. a primary key or a secondary index)
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -157,27 +161,27 @@ pub enum Search {
|
||||
pub enum ProjectionColumn {
|
||||
Column(ast::Expr),
|
||||
Star,
|
||||
TableStar(Rc<BTreeTable>, String),
|
||||
TableStar(BTreeTableReference),
|
||||
}
|
||||
|
||||
impl ProjectionColumn {
|
||||
pub fn column_count(&self, referenced_tables: &[(Rc<BTreeTable>, String)]) -> usize {
|
||||
pub fn column_count(&self, referenced_tables: &[BTreeTableReference]) -> usize {
|
||||
match self {
|
||||
ProjectionColumn::Column(_) => 1,
|
||||
ProjectionColumn::Star => {
|
||||
let mut count = 0;
|
||||
for (table, _) in referenced_tables {
|
||||
count += table.columns.len();
|
||||
for table_reference in referenced_tables {
|
||||
count += table_reference.table.columns.len();
|
||||
}
|
||||
count
|
||||
}
|
||||
ProjectionColumn::TableStar(table, _) => table.columns.len(),
|
||||
ProjectionColumn::TableStar(table_reference) => table_reference.table.columns.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
pub fn column_count(&self, referenced_tables: &[(Rc<BTreeTable>, String)]) -> usize {
|
||||
pub fn column_count(&self, referenced_tables: &[BTreeTableReference]) -> usize {
|
||||
match self {
|
||||
Operator::Aggregate {
|
||||
group_by,
|
||||
@@ -194,8 +198,12 @@ impl Operator {
|
||||
.iter()
|
||||
.map(|e| e.column_count(referenced_tables))
|
||||
.sum(),
|
||||
Operator::Scan { table, .. } => table.columns.len(),
|
||||
Operator::Search { table, .. } => table.columns.len(),
|
||||
Operator::Scan {
|
||||
table_reference, ..
|
||||
} => table_reference.table.columns.len(),
|
||||
Operator::Search {
|
||||
table_reference, ..
|
||||
} => table_reference.table.columns.len(),
|
||||
Operator::Nothing => 0,
|
||||
}
|
||||
}
|
||||
@@ -243,13 +251,27 @@ impl Operator {
|
||||
_ => "expr".to_string(),
|
||||
},
|
||||
ProjectionColumn::Star => "*".to_string(),
|
||||
ProjectionColumn::TableStar(_, tbl) => format!("{}.{}", tbl, "*"),
|
||||
ProjectionColumn::TableStar(table_reference) => {
|
||||
format!("{}.{}", table_reference.table_identifier, "*")
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
Operator::Scan { table, .. } => table.columns.iter().map(|c| c.name.clone()).collect(),
|
||||
Operator::Search { table, .. } => {
|
||||
table.columns.iter().map(|c| c.name.clone()).collect()
|
||||
}
|
||||
Operator::Scan {
|
||||
table_reference, ..
|
||||
} => table_reference
|
||||
.table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| c.name.clone())
|
||||
.collect(),
|
||||
Operator::Search {
|
||||
table_reference, ..
|
||||
} => table_reference
|
||||
.table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| c.name.clone())
|
||||
.collect(),
|
||||
Operator::Nothing => vec![],
|
||||
}
|
||||
}
|
||||
@@ -394,7 +416,9 @@ impl Display for Operator {
|
||||
.map(|expr| match expr {
|
||||
ProjectionColumn::Column(c) => c.to_string(),
|
||||
ProjectionColumn::Star => "*".to_string(),
|
||||
ProjectionColumn::TableStar(_, a) => format!("{}.{}", a, "*"),
|
||||
ProjectionColumn::TableStar(table_reference) => {
|
||||
format!("{}.{}", table_reference.table_identifier, "*")
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
@@ -402,16 +426,19 @@ impl Display for Operator {
|
||||
fmt_operator(source, f, level + 1, true)
|
||||
}
|
||||
Operator::Scan {
|
||||
table,
|
||||
table_reference,
|
||||
predicates: filter,
|
||||
table_identifier,
|
||||
..
|
||||
} => {
|
||||
let table_name = if table.name == *table_identifier {
|
||||
table.name.clone()
|
||||
} else {
|
||||
format!("{} AS {}", &table.name, &table_identifier)
|
||||
};
|
||||
let table_name =
|
||||
if table_reference.table.name == table_reference.table_identifier {
|
||||
table_reference.table_identifier.clone()
|
||||
} else {
|
||||
format!(
|
||||
"{} AS {}",
|
||||
&table_reference.table.name, &table_reference.table_identifier
|
||||
)
|
||||
};
|
||||
let filter_string = filter.as_ref().map(|f| {
|
||||
let filters_string = f
|
||||
.iter()
|
||||
@@ -427,7 +454,7 @@ impl Display for Operator {
|
||||
Ok(())
|
||||
}
|
||||
Operator::Search {
|
||||
table_identifier,
|
||||
table_reference,
|
||||
search,
|
||||
..
|
||||
} => {
|
||||
@@ -436,14 +463,14 @@ impl Display for Operator {
|
||||
writeln!(
|
||||
f,
|
||||
"{}SEARCH {} USING INTEGER PRIMARY KEY (rowid=?)",
|
||||
indent, table_identifier
|
||||
indent, table_reference.table_identifier
|
||||
)?;
|
||||
}
|
||||
Search::IndexSearch { index, .. } => {
|
||||
writeln!(
|
||||
f,
|
||||
"{}SEARCH {} USING INDEX {}",
|
||||
indent, table_identifier, index.name
|
||||
indent, table_reference.table_identifier, index.name
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -466,7 +493,7 @@ impl Display for Operator {
|
||||
then the return value will be (in bits): 110
|
||||
*/
|
||||
pub fn get_table_ref_bitmask_for_operator<'a>(
|
||||
tables: &'a Vec<(Rc<BTreeTable>, String)>,
|
||||
tables: &'a Vec<BTreeTableReference>,
|
||||
operator: &'a Operator,
|
||||
) -> Result<usize> {
|
||||
let mut table_refs_mask = 0;
|
||||
@@ -495,18 +522,22 @@ pub fn get_table_ref_bitmask_for_operator<'a>(
|
||||
Operator::Projection { source, .. } => {
|
||||
table_refs_mask |= get_table_ref_bitmask_for_operator(tables, source)?;
|
||||
}
|
||||
Operator::Scan { table, .. } => {
|
||||
Operator::Scan {
|
||||
table_reference, ..
|
||||
} => {
|
||||
table_refs_mask |= 1
|
||||
<< tables
|
||||
.iter()
|
||||
.position(|(t, _)| Rc::ptr_eq(t, table))
|
||||
.position(|t| Rc::ptr_eq(&t.table, &table_reference.table))
|
||||
.unwrap();
|
||||
}
|
||||
Operator::Search { table, .. } => {
|
||||
Operator::Search {
|
||||
table_reference, ..
|
||||
} => {
|
||||
table_refs_mask |= 1
|
||||
<< tables
|
||||
.iter()
|
||||
.position(|(t, _)| Rc::ptr_eq(t, table))
|
||||
.position(|t| Rc::ptr_eq(&t.table, &table_reference.table))
|
||||
.unwrap();
|
||||
}
|
||||
Operator::Nothing => {}
|
||||
@@ -523,7 +554,7 @@ pub fn get_table_ref_bitmask_for_operator<'a>(
|
||||
then the return value will be (in bits): 011
|
||||
*/
|
||||
pub fn get_table_ref_bitmask_for_ast_expr<'a>(
|
||||
tables: &'a Vec<(Rc<BTreeTable>, String)>,
|
||||
tables: &'a Vec<BTreeTableReference>,
|
||||
predicate: &'a ast::Expr,
|
||||
) -> Result<usize> {
|
||||
let mut table_refs_mask = 0;
|
||||
@@ -537,7 +568,7 @@ pub fn get_table_ref_bitmask_for_ast_expr<'a>(
|
||||
let matching_tables = tables
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, (table, _))| table.get_column(&ident).is_some());
|
||||
.filter(|(_, table_reference)| table_reference.table.get_column(&ident).is_some());
|
||||
|
||||
let mut matches = 0;
|
||||
let mut matching_tbl = None;
|
||||
@@ -561,17 +592,17 @@ pub fn get_table_ref_bitmask_for_ast_expr<'a>(
|
||||
let matching_table = tables
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, (_, t_id))| *t_id == tbl);
|
||||
.find(|(_, t)| t.table_identifier == tbl);
|
||||
|
||||
if matching_table.is_none() {
|
||||
crate::bail_parse_error!("introspect: table not found: {}", &tbl)
|
||||
}
|
||||
let matching_table = matching_table.unwrap();
|
||||
if matching_table.1 .0.get_column(&ident).is_none() {
|
||||
let (table_index, table_reference) = matching_table.unwrap();
|
||||
if table_reference.table.get_column(&ident).is_none() {
|
||||
crate::bail_parse_error!("column with qualified name {}.{} not found", &tbl, &ident)
|
||||
}
|
||||
|
||||
table_refs_mask |= 1 << matching_table.0;
|
||||
table_refs_mask |= 1 << table_index;
|
||||
}
|
||||
ast::Expr::Literal(_) => {}
|
||||
ast::Expr::Like { lhs, rhs, .. } => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::plan::{Aggregate, Direction, Operator, Plan, ProjectionColumn};
|
||||
use super::plan::{Aggregate, BTreeTableReference, Direction, Operator, Plan, ProjectionColumn};
|
||||
use crate::{
|
||||
function::Func,
|
||||
schema::{BTreeTable, Schema},
|
||||
@@ -113,16 +113,14 @@ pub fn prepare_select_plan<'a>(schema: &Schema, select: ast::Select) -> Result<P
|
||||
let name_normalized = normalize_ident(name.0.as_str());
|
||||
let referenced_table = referenced_tables
|
||||
.iter()
|
||||
.find(|(_t, t_id)| *t_id == name_normalized);
|
||||
.find(|t| t.table_identifier == name_normalized);
|
||||
|
||||
if referenced_table.is_none() {
|
||||
crate::bail_parse_error!("Table {} not found", name.0);
|
||||
}
|
||||
let (table, identifier) = referenced_table.unwrap();
|
||||
projection_expressions.push(ProjectionColumn::TableStar(
|
||||
table.clone(),
|
||||
identifier.clone(),
|
||||
));
|
||||
let table_reference = referenced_table.unwrap();
|
||||
projection_expressions
|
||||
.push(ProjectionColumn::TableStar(table_reference.clone()));
|
||||
}
|
||||
ast::ResultColumn::Expr(expr, _) => {
|
||||
projection_expressions.push(ProjectionColumn::Column(expr.clone()));
|
||||
@@ -299,7 +297,7 @@ fn parse_from(
|
||||
schema: &Schema,
|
||||
from: Option<FromClause>,
|
||||
operator_id_counter: &mut OperatorIdCounter,
|
||||
) -> Result<(Operator, Vec<(Rc<BTreeTable>, String)>)> {
|
||||
) -> Result<(Operator, Vec<BTreeTableReference>)> {
|
||||
if from.as_ref().and_then(|f| f.select.as_ref()).is_none() {
|
||||
return Ok((Operator::Nothing, vec![]));
|
||||
}
|
||||
@@ -318,15 +316,17 @@ fn parse_from(
|
||||
})
|
||||
.map(|a| a.0);
|
||||
|
||||
(table, alias.unwrap_or(qualified_name.name.0))
|
||||
BTreeTableReference {
|
||||
table: table.clone(),
|
||||
table_identifier: alias.unwrap_or(qualified_name.name.0),
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
let mut operator = Operator::Scan {
|
||||
table: first_table.0.clone(),
|
||||
table_reference: first_table.clone(),
|
||||
predicates: None,
|
||||
table_identifier: first_table.1.clone(),
|
||||
id: operator_id_counter.get_next_id(),
|
||||
step: 0,
|
||||
};
|
||||
@@ -353,7 +353,7 @@ fn parse_join(
|
||||
schema: &Schema,
|
||||
join: ast::JoinedSelectTable,
|
||||
operator_id_counter: &mut OperatorIdCounter,
|
||||
tables: &mut Vec<(Rc<BTreeTable>, String)>,
|
||||
tables: &mut Vec<BTreeTableReference>,
|
||||
) -> Result<(Operator, bool, Option<Vec<ast::Expr>>)> {
|
||||
let ast::JoinedSelectTable {
|
||||
operator,
|
||||
@@ -372,8 +372,10 @@ fn parse_join(
|
||||
ast::As::Elided(id) => id,
|
||||
})
|
||||
.map(|a| a.0);
|
||||
|
||||
(table, alias.unwrap_or(qualified_name.name.0))
|
||||
BTreeTableReference {
|
||||
table: table.clone(),
|
||||
table_identifier: alias.unwrap_or(qualified_name.name.0),
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
@@ -402,9 +404,8 @@ fn parse_join(
|
||||
|
||||
Ok((
|
||||
Operator::Scan {
|
||||
table: table.0.clone(),
|
||||
table_reference: table.clone(),
|
||||
predicates: None,
|
||||
table_identifier: table.1.clone(),
|
||||
id: operator_id_counter.get_next_id(),
|
||||
step: 0,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user