mod definition_lookup;
use definition_lookup::{DefinitionLookup, DefinitionLookupError};
use crate::constants::Nullable;
use crate::engine::objects::{JoinType, SqlTuple};
use super::io::VisibleRowManager;
use super::objects::types::{BaseSqlTypes, BaseSqlTypesError, SqlTypeDefinition};
use super::objects::{
Attribute, CommandType, ParseExpression, ParseTree, QueryTree, RangeRelation,
RangeRelationTable, RawInsertCommand, RawSelectCommand, Table,
};
use super::transactions::TransactionId;
use std::collections::HashMap;
use std::sync::Arc;
use thiserror::Error;
#[derive(Clone)]
pub struct Analyzer {
dl: DefinitionLookup,
}
impl Analyzer {
pub fn new(vis_row_man: VisibleRowManager) -> Analyzer {
Analyzer {
dl: DefinitionLookup::new(vis_row_man),
}
}
pub async fn analyze(
&self,
tran_id: TransactionId,
parse_tree: ParseTree,
) -> Result<QueryTree, AnalyzerError> {
match parse_tree {
ParseTree::Insert(i) => self.insert_processing(tran_id, i).await,
ParseTree::Select(i) => self.select_processing(tran_id, i).await,
_ => Err(AnalyzerError::NotImplemented()),
}
}
async fn insert_processing(
&self,
tran_id: TransactionId,
raw_insert: RawInsertCommand,
) -> Result<QueryTree, AnalyzerError> {
let definition = self
.dl
.get_definition(tran_id, raw_insert.table_name)
.await?;
let (output_type, val_cols) = Analyzer::validate_columns(
definition.clone(),
raw_insert.provided_columns,
raw_insert.provided_values,
)?;
let anon_tbl = RangeRelation::AnonymousTable(Arc::new(vec![val_cols]));
let target_tbl = RangeRelation::Table(RangeRelationTable {
alias: None,
table: definition,
});
Ok(QueryTree {
command_type: CommandType::Insert,
targets: Arc::new(output_type),
range_tables: vec![target_tbl.clone(), anon_tbl.clone()],
joins: vec![(JoinType::Inner, target_tbl, anon_tbl)],
})
}
async fn select_processing(
&self,
tran_id: TransactionId,
raw_select: RawSelectCommand,
) -> Result<QueryTree, AnalyzerError> {
let definition = self.dl.get_definition(tran_id, raw_select.table).await?;
let mut targets = vec![];
'outer: for rcol in raw_select.columns {
for c in definition.attributes.as_slice() {
if rcol == c.name {
targets.push((c.name.clone(), c.sql_type.clone()));
continue 'outer;
}
}
return Err(AnalyzerError::UnknownColumn(rcol));
}
Ok(QueryTree {
command_type: CommandType::Select,
targets: Arc::new(SqlTypeDefinition(targets)),
range_tables: vec![RangeRelation::Table(RangeRelationTable {
table: definition,
alias: None,
})],
joins: vec![],
})
}
fn validate_columns(
table: Arc<Table>,
provided_columns: Option<Vec<String>>,
provided_values: Vec<ParseExpression>,
) -> Result<(SqlTypeDefinition, SqlTuple), AnalyzerError> {
let columns = match provided_columns {
Some(pc) => {
let mut provided_pair: HashMap<String, ParseExpression> =
pc.into_iter().zip(provided_values).collect();
let mut result = vec![];
for a in table.attributes.clone() {
match provided_pair.get(&a.name) {
Some(ppv) => {
result.push((a.clone(), Some(ppv.clone())));
provided_pair.remove(&a.name);
}
None => match a.nullable {
Nullable::NotNull => return Err(AnalyzerError::MissingColumn(a)),
Nullable::Null => result.push((a, None)),
},
}
}
if !provided_pair.is_empty() {
return Err(AnalyzerError::UnknownColumns(
provided_pair.keys().cloned().collect(),
));
}
result
}
None => {
table
.attributes
.clone()
.into_iter()
.zip(provided_values)
.map(|(a, s)| (a, Some(s)))
.collect()
}
};
Analyzer::convert_into_types(columns)
}
fn convert_into_types(
provided: Vec<(Attribute, Option<ParseExpression>)>,
) -> Result<(SqlTypeDefinition, SqlTuple), AnalyzerError> {
let mut tbl_cols = vec![];
let mut val_cols = vec![];
for (a, s) in provided {
match s {
Some(s2) => match s2 {
ParseExpression::String(s3) => {
tbl_cols.push((a.name, a.sql_type.clone()));
val_cols.push(Some(BaseSqlTypes::parse(a.sql_type, &s3)?));
}
ParseExpression::Null() => {
tbl_cols.push((a.name, a.sql_type));
val_cols.push(None);
}
},
None => {
tbl_cols.push((a.name, a.sql_type));
val_cols.push(None);
}
}
}
Ok((SqlTypeDefinition(tbl_cols), SqlTuple(val_cols)))
}
}
#[derive(Debug, Error)]
pub enum AnalyzerError {
#[error(transparent)]
DefinitionLookupError(#[from] DefinitionLookupError),
#[error(transparent)]
BaseSqlTypesError(#[from] BaseSqlTypesError),
#[error("Provided columns {0:?} does not match the underlying table columns {1:?}")]
ColumnVsColumnMismatch(Vec<String>, Vec<String>),
#[error("Provided value count {0} does not match the underlying table column count {1}")]
ValueVsColumnMismatch(usize, usize),
#[error("Missing required column {0}")]
MissingColumn(Attribute),
#[error("Unknown column received {0}")]
UnknownColumn(String),
#[error("Unknown columns received {0:?}")]
UnknownColumns(Vec<String>),
#[error("Not implemented")]
NotImplemented(),
}