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:
jussisaurio
2024-10-13 12:05:19 +03:00
5 changed files with 206 additions and 172 deletions

View File

@@ -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<()> {

View File

@@ -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>,

View File

@@ -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

View File

@@ -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, .. } => {

View File

@@ -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,
},