-
Igor Kuznetsov authoredIgor Kuznetsov authored
sql.rs 44.79 KiB
//! SQL frontend module.
//!
//! Parses an SQL statement to the abstract syntax tree (AST)
//! and builds the intermediate representation (IR).
use ahash::RandomState;
use pest::Parser;
use std::collections::{HashMap, HashSet};
use traversal::DftPost;
use crate::errors::QueryPlannerError;
use crate::executor::engine::{normalize_name_from_sql, CoordinatorMetadata};
use crate::frontend::sql::ast::{
AbstractSyntaxTree, ParseNode, ParseNodes, ParseTree, Rule, StackParseNode, Type,
};
use crate::frontend::sql::ir::Translation;
use crate::frontend::Ast;
use crate::ir::expression::Expression;
use crate::ir::operator::{Bool, Relational, Unary};
use crate::ir::value::Value;
use crate::ir::{Node, Plan};
impl Ast for AbstractSyntaxTree {
/// Build an empty AST.
fn empty() -> Self {
AbstractSyntaxTree {
nodes: ParseNodes::new(),
top: None,
map: HashMap::new(),
}
}
/// Constructor.
/// Builds a tree (nodes are in postorder reverse).
///
/// # Errors
/// - Failed to parse an SQL query.
fn new(query: &str) -> Result<Self, QueryPlannerError> {
let mut ast = AbstractSyntaxTree::empty();
let mut command_pair = match ParseTree::parse(Rule::Command, query) {
Ok(p) => p,
Err(e) => {
return Err(QueryPlannerError::CustomError(format!(
"Parsing error: {}",
e
)))
}
};
let top_pair = command_pair.next().ok_or_else(|| {
QueryPlannerError::CustomError("No query found in the parse tree.".to_string())
})?;
let top = StackParseNode::new(top_pair, None);
let mut stack: Vec<StackParseNode> = vec![top];
while !stack.is_empty() {
let stack_node: StackParseNode = match stack.pop() {
Some(n) => n,
None => break,
};
// Save node to AST
let node = ast.nodes.push_node(ParseNode::new(
stack_node.pair.as_rule(),
Some(String::from(stack_node.pair.as_str())),
)?);
// Update parent's node children list
ast.nodes.add_child(stack_node.parent, node)?;
// Clean parent values (only leafs should contain data)
if let Some(parent) = stack_node.parent {
ast.nodes.update_value(parent, None)?;
}
for parse_child in stack_node.pair.into_inner() {
stack.push(StackParseNode::new(parse_child, Some(node)));
}
}
ast.set_top(0)?;
ast.transform_select()?;
ast.add_aliases_to_projection()?;
ast.build_ref_to_relation_map()?;
Ok(ast)
}
fn is_empty(&self) -> bool {
self.nodes.arena.is_empty()
}
#[allow(dead_code)]
#[allow(clippy::too_many_lines)]
fn resolve_metadata<M>(&self, metadata: &M) -> Result<Plan, QueryPlannerError>
where
M: CoordinatorMetadata,
{
let mut plan = Plan::new();
let top = match self.top {
Some(t) => t,
None => return Err(QueryPlannerError::InvalidAst),
};
let dft_post = DftPost::new(&top, |node| self.nodes.ast_iter(node));
let mut map = Translation::with_capacity(self.nodes.next_id());
let mut rows: HashSet<usize> = HashSet::with_capacity(self.nodes.next_id());
let mut col_idx: usize = 0;
for (_, id) in dft_post {
let node = self.nodes.get_node(*id)?;
match &node.rule {
Type::Scan => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Could not find child id in scan node".to_string(),
)
})?;
let plan_child_id = map.get(*ast_child_id)?;
map.add(*id, plan_child_id);
if let Some(ast_scan_id) = node.children.get(1) {
let ast_scan = self.nodes.get_node(*ast_scan_id)?;
if let Type::ScanName = ast_scan.rule {
let ast_scan_name =
ast_scan.value.as_deref().map(normalize_name_from_sql);
// Update scan name in the plan.
let scan = plan.get_mut_relation_node(plan_child_id)?;
scan.set_scan_name(ast_scan_name)?;
} else {
return Err(QueryPlannerError::CustomError(
"Expected scan name AST node.".into(),
));
}
}
}
Type::Table => {
if let Some(node_val) = &node.value {
let table = node_val.as_str();
let t = metadata.get_table_segment(table)?;
plan.add_rel(t);
let scan_id = plan.add_scan(&normalize_name_from_sql(table), None)?;
map.add(*id, scan_id);
} else {
return Err(QueryPlannerError::CustomError(
"Table name is not found.".into(),
));
}
}
Type::SubQuery => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Child node id is not found among sub-query children.".into(),
)
})?;
let plan_child_id = map.get(*ast_child_id)?;
let alias_name: Option<String> = if let Some(ast_name_id) = node.children.get(1)
{
let ast_alias = self.nodes.get_node(*ast_name_id)?;
if let Type::SubQueryName = ast_alias.rule {
} else {
return Err(QueryPlannerError::CustomError(format!(
"Expected a sub-query name, got {:?}.",
ast_alias.rule
)));
}
ast_alias.value.as_deref().map(normalize_name_from_sql)
} else {
None
};
let plan_sq_id = plan.add_sub_query(plan_child_id, alias_name.as_deref())?;
map.add(*id, plan_sq_id);
}
Type::Reference => {
let ast_rel_list = self.get_referred_relational_nodes(*id)?;
let mut plan_rel_list = Vec::new();
for ast_id in ast_rel_list {
let plan_id = map.get(ast_id)?;
plan_rel_list.push(plan_id);
}
let get_column_name = |ast_id: usize| -> Result<String, QueryPlannerError> {
let ast_col_name = self.nodes.get_node(ast_id)?;
if let Type::ColumnName = ast_col_name.rule {
let name: Option<String> =
ast_col_name.value.as_deref().map(normalize_name_from_sql);
Ok(name.ok_or_else(|| {
QueryPlannerError::CustomError("Empty AST column name".into())
})?)
} else {
Err(QueryPlannerError::CustomError(
"Expected column name AST node.".into(),
))
}
};
let get_scan_name =
|col_name: &str,
plan_id: usize|
-> Result<Option<String>, QueryPlannerError> {
let child = plan.get_relation_node(plan_id)?;
let col_position = child
.output_alias_position_map(&plan.nodes)?
.get(col_name)
.copied();
match col_position {
Some(pos) => Ok(plan
.get_relation_node(plan_id)?
.scan_name(&plan, pos)?
.map(String::from)),
None => Ok(None),
}
};
// Reference to the join node.
if let (Some(plan_left_id), Some(plan_right_id)) =
(plan_rel_list.first(), plan_rel_list.get(1))
{
if let (Some(ast_scan_id), Some(ast_col_name_id)) =
(node.children.first(), node.children.get(1))
{
let ast_scan = self.nodes.get_node(*ast_scan_id)?;
if let Type::ScanName = ast_scan.rule {
// Get the column name and its positions in the output tuples.
let col_name = get_column_name(*ast_col_name_id)?;
let left_name = get_scan_name(&col_name, *plan_left_id)?;
let right_name = get_scan_name(&col_name, *plan_right_id)?;
// Check that the AST scan name matches to the children scan names in the plan join node.
let ast_scan_name: Option<String> =
ast_scan.value.as_deref().map(normalize_name_from_sql);
// Determine the referred side of the join (left or right).
if left_name == ast_scan_name {
let left_col_map = plan
.get_relation_node(*plan_left_id)?
.output_alias_position_map(&plan.nodes)?;
if left_col_map.get(&col_name.as_str()).is_some() {
let ref_id = plan.add_row_from_left_branch(
*plan_left_id,
*plan_right_id,
&[&col_name],
)?;
rows.insert(ref_id);
map.add(*id, ref_id);
} else {
return Err(QueryPlannerError::CustomError(format!(
"Column '{}' not found in for the join left child '{:?}'.",
col_name, left_name
)));
}
} else if right_name == ast_scan_name {
let right_col_map = plan
.get_relation_node(*plan_right_id)?
.output_alias_position_map(&plan.nodes)?;
if right_col_map.get(&col_name.as_str()).is_some() {
let ref_id = plan.add_row_from_right_branch(
*plan_left_id,
*plan_right_id,
&[&col_name],
)?;
rows.insert(ref_id);
map.add(*id, ref_id);
} else {
return Err(QueryPlannerError::CustomError(format!(
"Column '{}' not found in for the join right child '{:?}'.",
col_name, right_name
)));
}
} else {
return Err(QueryPlannerError::CustomError(
"Left and right plan nodes do not match the AST scan name."
.into(),
));
}
} else {
return Err(QueryPlannerError::CustomError(
"Expected AST node to be a scan name.".into(),
));
}
} else if let (Some(ast_col_name_id), None) =
(node.children.first(), node.children.get(1))
{
// Determine the referred side of the join (left or right).
let col_name = get_column_name(*ast_col_name_id)?;
let left_col_map = plan
.get_relation_node(*plan_left_id)?
.output_alias_position_map(&plan.nodes)?;
if left_col_map.get(&col_name.as_str()).is_some() {
let ref_id = plan.add_row_from_left_branch(
*plan_left_id,
*plan_right_id,
&[&col_name],
)?;
rows.insert(ref_id);
map.add(*id, ref_id);
}
let right_col_map = plan
.get_relation_node(*plan_right_id)?
.output_alias_position_map(&plan.nodes)?;
if right_col_map.get(&col_name.as_str()).is_some() {
let ref_id = plan.add_row_from_right_branch(
*plan_left_id,
*plan_right_id,
&[&col_name],
)?;
rows.insert(ref_id);
map.add(*id, ref_id);
}
return Err(QueryPlannerError::CustomError(format!(
"Column '{}' not found in for the join left or right children.",
col_name
)));
} else {
return Err(QueryPlannerError::CustomError(
"Expected children nodes contain a column name.".into(),
));
};
// Reference to a single child node.
} else if let (Some(plan_rel_id), None) =
(plan_rel_list.first(), plan_rel_list.get(1))
{
let col_name: String = if let (Some(ast_scan_id), Some(ast_col_id)) =
(node.children.first(), node.children.get(1))
{
// Get column name.
let col_name = get_column_name(*ast_col_id)?;
// Check that scan name in the reference matches to the one in scan node.
let ast_scan = self.nodes.get_node(*ast_scan_id)?;
if let Type::ScanName = ast_scan.rule {
let ast_scan_name = Some(normalize_name_from_sql(
ast_scan.value.as_ref().ok_or_else(|| {
QueryPlannerError::CustomError(
"Expected AST node to have a non-empty scan name."
.into(),
)
})?,
));
let plan_scan_name = get_scan_name(&col_name, *plan_rel_id)?;
if plan_scan_name != ast_scan_name {
return Err(QueryPlannerError::CustomError(
format!("Scan name for the column {:?} doesn't match: expected {:?}, found {:?}",
get_column_name(*ast_col_id), plan_scan_name, ast_scan_name
)));
}
} else {
return Err(QueryPlannerError::CustomError(
"Expected AST node to be a scan name.".into(),
));
};
col_name
} else if let (Some(ast_col_id), None) =
(node.children.first(), node.children.get(1))
{
// Get the column name.
get_column_name(*ast_col_id)?
} else {
return Err(QueryPlannerError::CustomError(
"No child node found in the AST reference.".into(),
));
};
let ref_list = plan.new_columns(
&[*plan_rel_id],
false,
&[0],
&[&col_name],
false,
true,
)?;
let ref_id = *ref_list.first().ok_or_else(|| {
QueryPlannerError::CustomError("Referred column is not found.".into())
})?;
map.add(*id, ref_id);
} else {
return Err(QueryPlannerError::CustomError(
"Expected one or two referred relational nodes, got less or more."
.into(),
));
}
}
Type::Integer
| Type::Decimal
| Type::Double
| Type::Unsigned
| Type::String
| Type::Null
| Type::True
| Type::False => {
let val = Value::from_node(node)?;
map.add(*id, plan.add_const(val));
}
Type::Parameter => {
map.add(*id, plan.add_param());
}
Type::Asterisk => {
// We can get an asterisk only in projection.
let ast_rel_list = self.get_referred_relational_nodes(*id)?;
let mut plan_rel_list = Vec::new();
for ast_id in ast_rel_list {
let plan_id = map.get(ast_id)?;
plan_rel_list.push(plan_id);
}
if plan_rel_list.len() > 1 {
return Err(QueryPlannerError::CustomError(
"Sub-queries in projections are not implemented yet.".into(),
));
}
let plan_rel_id = *plan_rel_list.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Referred relational node is not found.".into(),
)
})?;
let plan_asterisk_id = plan.add_row_for_output(plan_rel_id, &[], false)?;
map.add(*id, plan_asterisk_id);
}
Type::Alias => {
let ast_ref_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Reference node id is not found among alias children.".into(),
)
})?;
let plan_ref_id = map.get(*ast_ref_id)?;
let ast_name_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Alias name node id is not found among alias children.".into(),
)
})?;
let name = self
.nodes
.get_node(*ast_name_id)?
.value
.as_ref()
.ok_or_else(|| {
QueryPlannerError::CustomError("Alias name is not found.".into())
})?;
let plan_alias_id = plan
.nodes
.add_alias(&normalize_name_from_sql(name), plan_ref_id)?;
map.add(*id, plan_alias_id);
}
Type::Column => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError("Column has no children.".into())
})?;
let plan_child_id = map.get(*ast_child_id)?;
map.add(*id, plan_child_id);
}
Type::Row => {
let mut plan_col_list = Vec::new();
for ast_child_id in &node.children {
let plan_child_id = map.get(*ast_child_id)?;
// If the child is a row that was generated by our
// reference-to-row logic in AST code, we should unwrap it back.
let plan_id = if rows.get(&plan_child_id).is_some() {
let plan_inner_expr = plan.get_expression_node(plan_child_id)?;
*plan_inner_expr.get_row_list()?.first().ok_or_else(|| {
QueryPlannerError::CustomError("Row is empty.".into())
})?
} else {
plan_child_id
};
plan_col_list.push(plan_id);
}
let plan_row_id = plan.nodes.add_row(plan_col_list, None);
map.add(*id, plan_row_id);
}
Type::And
| Type::Or
| Type::Eq
| Type::In
| Type::Gt
| Type::GtEq
| Type::Lt
| Type::LtEq
| Type::NotEq
| Type::NotIn => {
let ast_left_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Left node id is not found among comparison children.".into(),
)
})?;
let plan_left_id = plan.as_row(map.get(*ast_left_id)?, &mut rows)?;
let ast_right_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Right node id is not found among comparison children.".into(),
)
})?;
let plan_right_id = plan.as_row(map.get(*ast_right_id)?, &mut rows)?;
let op = Bool::from_node_type(&node.rule)?;
let cond_id = plan.add_cond(plan_left_id, op, plan_right_id)?;
map.add(*id, cond_id);
}
Type::IsNull | Type::IsNotNull => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(format!("{:?} has no children.", &node.rule))
})?;
let plan_child_id = plan.as_row(map.get(*ast_child_id)?, &mut rows)?;
let op = Unary::from_node_type(&node.rule)?;
let unary_id = plan.add_unary(op, plan_child_id)?;
map.add(*id, unary_id);
}
Type::Between => {
// left BETWEEN center AND right
let ast_left_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Left node id is not found among between children.".into(),
)
})?;
let plan_left_id = plan.as_row(map.get(*ast_left_id)?, &mut rows)?;
let ast_center_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Center node id is not found among between children.".into(),
)
})?;
let plan_center_id = plan.as_row(map.get(*ast_center_id)?, &mut rows)?;
let ast_right_id = node.children.get(2).ok_or_else(|| {
QueryPlannerError::CustomError(
"Right node id is not found among between children.".into(),
)
})?;
let plan_right_id = plan.as_row(map.get(*ast_right_id)?, &mut rows)?;
let greater_eq_id = plan.add_cond(plan_left_id, Bool::GtEq, plan_center_id)?;
let less_eq_id = plan.add_cond(plan_left_id, Bool::LtEq, plan_right_id)?;
let and_id = plan.add_cond(greater_eq_id, Bool::And, less_eq_id)?;
map.add(*id, and_id);
}
Type::Condition => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError("Condition has no children.".into())
})?;
let plan_child_id = map.get(*ast_child_id)?;
map.add(*id, plan_child_id);
}
Type::InnerJoin => {
let ast_left_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Left node id is not found among join children.".into(),
)
})?;
let plan_left_id = map.get(*ast_left_id)?;
let ast_right_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Right node id is not found among join children.".into(),
)
})?;
let plan_right_id = map.get(*ast_right_id)?;
let ast_cond_id = node.children.get(2).ok_or_else(|| {
QueryPlannerError::CustomError(
"Condition node id is not found among join children.".into(),
)
})?;
let plan_cond_id = map.get(*ast_cond_id)?;
let plan_join_id = plan.add_join(plan_left_id, plan_right_id, plan_cond_id)?;
map.add(*id, plan_join_id);
}
Type::Selection => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Child node id is not found among selection children.".into(),
)
})?;
let plan_child_id = map.get(*ast_child_id)?;
let ast_filter_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Filter node id is not found among selection children.".into(),
)
})?;
let plan_filter_id = map.get(*ast_filter_id)?;
let plan_selection_id = plan.add_select(&[plan_child_id], plan_filter_id)?;
map.add(*id, plan_selection_id);
}
Type::Projection => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Child node id is not found among projection children.".into(),
)
})?;
let plan_child_id = map.get(*ast_child_id)?;
let mut columns: Vec<usize> = Vec::new();
for ast_column_id in node.children.iter().skip(1) {
let ast_column = self.nodes.get_node(*ast_column_id)?;
match ast_column.rule {
Type::Column => {
let ast_alias_id =
*ast_column.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Alias node id is not found among column children."
.into(),
)
})?;
let plan_alias_id = map.get(ast_alias_id)?;
columns.push(plan_alias_id);
}
Type::Asterisk => {
let plan_asterisk_id = map.get(*ast_column_id)?;
if let Node::Expression(Expression::Row { list, .. }) =
plan.get_node(plan_asterisk_id)?
{
for row_id in list {
columns.push(*row_id);
}
} else {
return Err(QueryPlannerError::CustomError(
"A plan node corresponding to asterisk is not a row."
.into(),
));
}
}
_ => {
return Err(QueryPlannerError::CustomError(format!(
"Expected a column in projection, got {:?}.",
ast_column.rule
)));
}
}
}
let projection_id = plan.add_proj_internal(plan_child_id, &columns)?;
map.add(*id, projection_id);
}
Type::Except => {
let ast_left_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Left node id is not found among except children.".into(),
)
})?;
let plan_left_id = map.get(*ast_left_id)?;
let ast_right_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Right node id is not found among except children.".into(),
)
})?;
let plan_right_id = map.get(*ast_right_id)?;
let plan_except_id = plan.add_except(plan_left_id, plan_right_id)?;
map.add(*id, plan_except_id);
}
Type::UnionAll => {
let ast_left_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Left node id is not found among union all children.".into(),
)
})?;
let plan_left_id = map.get(*ast_left_id)?;
let ast_right_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Right node id is not found among union all children.".into(),
)
})?;
let plan_right_id = map.get(*ast_right_id)?;
let plan_union_all_id = plan.add_union_all(plan_left_id, plan_right_id)?;
map.add(*id, plan_union_all_id);
}
Type::ValuesRow => {
let ast_child_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError("Values row has no children.".into())
})?;
let plan_child_id = map.get(*ast_child_id)?;
let values_row_id = plan.add_values_row(plan_child_id, &mut col_idx)?;
map.add(*id, values_row_id);
}
Type::Values => {
let mut plan_children_ids: Vec<usize> = Vec::with_capacity(node.children.len());
for ast_child_id in &node.children {
let plan_child_id = map.get(*ast_child_id)?;
plan_children_ids.push(plan_child_id);
}
let plan_values_id = plan.add_values(plan_children_ids)?;
map.add(*id, plan_values_id);
}
Type::Insert => {
let ast_table_id = node.children.first().ok_or_else(|| {
QueryPlannerError::CustomError(
"Table node id is not found among insert children.".into(),
)
})?;
let ast_table = self.nodes.get_node(*ast_table_id)?;
if let Type::Table = ast_table.rule {
} else {
return Err(QueryPlannerError::CustomError(format!(
"Expected a table in insert, got {:?}.",
ast_table
)));
}
let relation: &str = ast_table.value.as_ref().ok_or_else(|| {
QueryPlannerError::CustomError(
"Table name was not found in the AST.".into(),
)
})?;
let ast_child_id = node.children.get(1).ok_or_else(|| {
QueryPlannerError::CustomError(
"Second child is not found among insert children.".into(),
)
})?;
let ast_child = self.nodes.get_node(*ast_child_id)?;
let plan_insert_id = if let Type::TargetColumns = ast_child.rule {
// insert into t (a, b, c) ...
let mut col_names: Vec<&str> = Vec::with_capacity(ast_child.children.len());
for col_id in &ast_child.children {
let col = self.nodes.get_node(*col_id)?;
if let Type::ColumnName = col.rule {
col_names.push(col.value.as_ref().ok_or_else(||
QueryPlannerError::CustomError(
"Column name was not found among the AST target columns (insert).".into(),
))?);
} else {
return Err(QueryPlannerError::CustomError(format!(
"Expected a column name in insert, got {:?}.",
col
)));
}
}
let ast_rel_child_id = node.children.get(2).ok_or_else(|| {
QueryPlannerError::CustomError(
"Third child is not found among insert children.".into(),
)
})?;
let plan_rel_child_id = map.get(*ast_rel_child_id)?;
plan.add_insert(relation, plan_rel_child_id, &col_names)?
} else {
// insert into t ...
let plan_child_id = map.get(*ast_child_id)?;
plan.add_insert(relation, plan_child_id, &[])?
};
map.add(*id, plan_insert_id);
}
Type::AliasName
| Type::ColumnName
| Type::ScanName
| Type::Select
| Type::SubQueryName
| Type::TargetColumns => {}
rule => {
return Err(QueryPlannerError::CustomError(format!(
"Not implements type: {:?}",
rule
)));
}
}
}
// get root node id
let plan_top_id = map.get(
self.top
.ok_or_else(|| QueryPlannerError::CustomError("No top in AST.".into()))?,
)?;
plan.set_top(plan_top_id)?;
plan.replace_sq_with_references()?;
Ok(plan)
}
}
impl Plan {
/// Substitute parameters to the plan.
///
/// # Errors
/// - Invalid amount of parameters.
/// - Internal errors.
#[allow(clippy::too_many_lines)]
pub fn bind_params(&mut self, mut params: Vec<Value>) -> Result<(), QueryPlannerError> {
// Nothing to do here.
if params.is_empty() {
return Ok(());
}
let top_id = self.get_top()?;
let tree = DftPost::new(&top_id, |node| self.subtree_iter(node));
let nodes: Vec<usize> = tree.map(|(_, id)| *id).collect();
// Transform parameters to values. The result values are stored in the
// opposite to parameters order.
let mut value_ids: Vec<usize> = Vec::with_capacity(params.len());
while let Some(param) = params.pop() {
value_ids.push(self.add_const(param));
}
// We need to use rows instead of values in some cases (AST can solve
// this problem for non-parameterized queries, but for parameterized
// queries it is IR responsibility).
let mut row_ids: HashMap<usize, usize, RandomState> =
HashMap::with_hasher(RandomState::new());
// Gather all parameter nodes from the tree to a hash set.
let param_set = self.get_params();
// Closure to retrieve a corresponding value for a parameter node.
let get_value = |pos: usize| -> Result<usize, QueryPlannerError> {
let val_id = value_ids.get(pos).ok_or_else(|| {
QueryPlannerError::CustomError(format!(
"Parameter in position {} is not found.",
pos
))
})?;
Ok(*val_id)
};
// Populate rows.
let mut idx = value_ids.len();
for id in &nodes {
let node = self.get_node(*id)?;
match node {
Node::Relational(rel) => match rel {
Relational::Selection {
filter: ref param_id,
..
}
| Relational::InnerJoin {
condition: ref param_id,
..
}
| Relational::Projection {
output: ref param_id,
..
} => {
if param_set.contains(param_id) {
idx -= 1;
let val_id = get_value(idx)?;
row_ids.insert(idx, self.nodes.add_row(vec![val_id], None));
}
}
_ => {}
},
Node::Expression(expr) => match expr {
Expression::Alias {
child: ref param_id,
..
}
| Expression::Unary {
child: ref param_id,
..
} => {
if param_set.contains(param_id) {
idx -= 1;
}
}
Expression::Bool {
ref left,
ref right,
..
} => {
for param_id in &[*left, *right] {
if param_set.contains(param_id) {
idx -= 1;
let val_id = get_value(idx)?;
row_ids.insert(idx, self.nodes.add_row(vec![val_id], None));
}
}
}
Expression::Row { ref list, .. } => {
for param_id in list {
if param_set.contains(param_id) {
idx -= 1;
}
}
}
Expression::Constant { .. } | Expression::Reference { .. } => {}
},
Node::Parameter => {}
}
}
let get_row = |idx: usize| -> Result<usize, QueryPlannerError> {
let row_id = row_ids.get(&idx).ok_or_else(|| {
QueryPlannerError::CustomError(format!("Row in position {} is not found.", idx))
})?;
Ok(*row_id)
};
// Replace parameters in the plan.
idx = value_ids.len();
for id in &nodes {
let node = self.get_mut_node(*id)?;
match node {
Node::Relational(rel) => match rel {
Relational::Selection {
filter: ref mut param_id,
..
}
| Relational::InnerJoin {
condition: ref mut param_id,
..
}
| Relational::Projection {
output: ref mut param_id,
..
} => {
if param_set.contains(param_id) {
idx -= 1;
let row_id = get_row(idx)?;
*param_id = row_id;
}
}
_ => {}
},
Node::Expression(expr) => match expr {
Expression::Alias {
child: ref mut param_id,
..
}
| Expression::Unary {
child: ref mut param_id,
..
} => {
if param_set.contains(param_id) {
idx -= 1;
let val_id = get_value(idx)?;
*param_id = val_id;
}
}
Expression::Bool {
ref mut left,
ref mut right,
..
} => {
for param_id in &mut [left, right].iter_mut() {
if param_set.contains(param_id) {
idx -= 1;
let row_id = get_row(idx)?;
**param_id = row_id;
}
}
}
Expression::Row { ref mut list, .. } => {
for param_id in list {
if param_set.contains(param_id) {
idx -= 1;
let val_id = get_value(idx)?;
*param_id = val_id;
}
}
}
Expression::Constant { .. } | Expression::Reference { .. } => {}
},
Node::Parameter => {}
}
}
// Update values row output.
for id in nodes {
if let Ok(Relational::ValuesRow { .. }) = self.get_relation_node(id) {
self.update_values_row(id)?;
}
}
Ok(())
}
/// Wrap references and constants in the plan into rows.
fn as_row(
&mut self,
expr_id: usize,
rows: &mut HashSet<usize>,
) -> Result<usize, QueryPlannerError> {
if let Node::Expression(Expression::Reference { .. } | Expression::Constant { .. }) =
self.get_node(expr_id)?
{
let row_id = self.nodes.add_row(vec![expr_id], None);
rows.insert(row_id);
Ok(row_id)
} else {
Ok(expr_id)
}
}
}
pub mod ast;
pub mod ir;
pub mod tree;