From 56722e55afc2cf03213a6cda02fda3b4f40369be Mon Sep 17 00:00:00 2001 From: Andrey Strochuk <a.strochuk@picodata.io> Date: Sun, 19 May 2024 12:14:00 +0300 Subject: [PATCH] feat: add one subarena --- sbroad-cartridge/src/cartridge/router.rs | 7 +- sbroad-cartridge/src/cartridge/storage.rs | 2 +- sbroad-core/src/backend/sql/ir.rs | 14 +- sbroad-core/src/backend/sql/space.rs | 3 +- sbroad-core/src/backend/sql/tree.rs | 119 ++++---- sbroad-core/src/executor.rs | 13 +- sbroad-core/src/executor/bucket.rs | 16 +- sbroad-core/src/executor/engine.rs | 6 +- sbroad-core/src/executor/engine/helpers.rs | 35 ++- .../src/executor/engine/helpers/storage.rs | 2 +- .../src/executor/engine/helpers/vshard.rs | 27 +- sbroad-core/src/executor/engine/mock.rs | 17 +- sbroad-core/src/executor/ir.rs | 78 ++--- sbroad-core/src/executor/protocol.rs | 5 +- sbroad-core/src/executor/result.rs | 5 +- sbroad-core/src/executor/tests.rs | 4 +- sbroad-core/src/executor/tests/exec_plan.rs | 83 +++--- sbroad-core/src/executor/vtable.rs | 9 +- sbroad-core/src/frontend/sql.rs | 58 ++-- sbroad-core/src/frontend/sql/ir.rs | 85 +++--- sbroad-core/src/frontend/sql/ir/tests.rs | 62 ++-- .../src/frontend/sql/ir/tests/global.rs | 39 ++- .../src/frontend/sql/ir/tests/single.rs | 10 +- sbroad-core/src/ir.rs | 256 +++++++++------- sbroad-core/src/ir/acl.rs | 8 +- sbroad-core/src/ir/aggregates.rs | 16 +- sbroad-core/src/ir/api/children.rs | 40 +-- sbroad-core/src/ir/api/constant.rs | 18 +- sbroad-core/src/ir/api/parameter.rs | 62 ++-- sbroad-core/src/ir/block.rs | 8 +- sbroad-core/src/ir/ddl.rs | 8 +- sbroad-core/src/ir/distribution.rs | 48 +-- sbroad-core/src/ir/distribution/tests.rs | 257 +--------------- sbroad-core/src/ir/explain.rs | 39 +-- sbroad-core/src/ir/expression.rs | 234 ++++++++------- sbroad-core/src/ir/expression/cast.rs | 4 +- sbroad-core/src/ir/expression/concat.rs | 4 +- sbroad-core/src/ir/expression/types.rs | 4 +- sbroad-core/src/ir/function.rs | 10 +- sbroad-core/src/ir/helpers.rs | 17 +- sbroad-core/src/ir/helpers/tests.rs | 117 ++++---- sbroad-core/src/ir/operator.rs | 266 +++++++++-------- sbroad-core/src/ir/operator/tests.rs | 184 ++---------- sbroad-core/src/ir/parameters.rs | 10 +- sbroad-core/src/ir/relation/tests.rs | 102 ------- sbroad-core/src/ir/tests.rs | 38 +-- sbroad-core/src/ir/transformation.rs | 46 +-- sbroad-core/src/ir/transformation/bool_in.rs | 8 +- sbroad-core/src/ir/transformation/dnf.rs | 26 +- .../ir/transformation/equality_propagation.rs | 26 +- .../equality_propagation/tests.rs | 6 +- .../src/ir/transformation/merge_tuples.rs | 49 +-- .../src/ir/transformation/not_push_down.rs | 23 +- .../src/ir/transformation/redistribution.rs | 215 +++++++------- .../ir/transformation/redistribution/dml.rs | 29 +- .../transformation/redistribution/eq_cols.rs | 38 +-- .../transformation/redistribution/groupby.rs | 223 +++++++------- .../redistribution/left_join.rs | 7 +- .../ir/transformation/redistribution/tests.rs | 281 +----------------- .../redistribution/tests/not_in.rs | 14 +- .../redistribution/tests/segment.rs | 95 +----- .../src/ir/transformation/split_columns.rs | 8 +- .../ir/transformation/split_columns/tests.rs | 4 +- sbroad-core/src/ir/tree.rs | 16 +- sbroad-core/src/ir/tree/and.rs | 14 +- sbroad-core/src/ir/tree/expression.rs | 22 +- sbroad-core/src/ir/tree/relation.rs | 19 +- sbroad-core/src/ir/tree/subtree.rs | 30 +- sbroad-core/src/ir/tree/tests.rs | 82 ++--- sbroad-core/src/ir/tree/traversal.rs | 101 ++++--- sbroad-core/src/ir/undo.rs | 10 +- 71 files changed, 1598 insertions(+), 2243 deletions(-) diff --git a/sbroad-cartridge/src/cartridge/router.rs b/sbroad-cartridge/src/cartridge/router.rs index 89d7d4aaf..a5de1d2f6 100644 --- a/sbroad-cartridge/src/cartridge/router.rs +++ b/sbroad-cartridge/src/cartridge/router.rs @@ -3,6 +3,7 @@ use sbroad::cbo::{ColumnStats, TableColumnPair, TableStats}; use sbroad::executor::engine::helpers::vshard::{get_random_bucket, impl_exec_ir_on_buckets}; use sbroad::executor::engine::{DispatchReturnFormat, Metadata, QueryCache, Vshard}; +use sbroad::ir::expression::NodeId; use sbroad::utils::MutexLike; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use tarantool::fiber::Mutex; @@ -247,7 +248,7 @@ impl Router for RouterRuntime { fn dispatch( &self, plan: &mut ExecutionPlan, - top_id: usize, + top_id: NodeId, buckets: &Buckets, return_format: DispatchReturnFormat, ) -> Result<Box<dyn Any>, SbroadError> { @@ -263,10 +264,10 @@ impl Router for RouterRuntime { fn materialize_motion( &self, plan: &mut ExecutionPlan, - motion_node_id: usize, + motion_node_id: &NodeId, buckets: &Buckets, ) -> Result<VirtualTable, SbroadError> { - materialize_motion(self, plan, motion_node_id, buckets) + materialize_motion(self, plan, *motion_node_id, buckets) } fn extract_sharding_key_from_map<'rec>( diff --git a/sbroad-cartridge/src/cartridge/storage.rs b/sbroad-cartridge/src/cartridge/storage.rs index 076ff6540..50c55146a 100644 --- a/sbroad-cartridge/src/cartridge/storage.rs +++ b/sbroad-cartridge/src/cartridge/storage.rs @@ -16,7 +16,7 @@ use sbroad::executor::ir::{ExecutionPlan, QueryType}; use sbroad::executor::lru::{Cache, LRUCache, DEFAULT_CAPACITY}; use sbroad::executor::protocol::{RequiredData, SchemaInfo}; use sbroad::ir::value::Value; -use sbroad::ir::NodeId; +use sbroad::ir::expression::NodeId; use sbroad::utils::MutexLike; use sbroad::{debug, error, warn}; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; diff --git a/sbroad-core/src/backend/sql/ir.rs b/sbroad-core/src/backend/sql/ir.rs index 330fb4451..b033e3f71 100644 --- a/sbroad-core/src/backend/sql/ir.rs +++ b/sbroad-core/src/backend/sql/ir.rs @@ -2,7 +2,7 @@ use crate::debug; use crate::executor::protocol::VTablesMeta; use crate::ir::relation::Column; use crate::ir::transformation::redistribution::MotionPolicy; -use crate::ir::tree::traversal::PostOrderWithFilter; +use crate::ir::tree::traversal::{LevelNode, PostOrderWithFilter}; use opentelemetry::Context; use serde::{Deserialize, Serialize}; use smol_str::format_smolstr; @@ -14,7 +14,7 @@ use tarantool::tuple::{FunctionArgs, Tuple}; use crate::errors::{Action, Entity, SbroadError}; use crate::executor::engine::helpers::table_name; use crate::executor::ir::ExecutionPlan; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::{OrderByType, Relational}; use crate::ir::value::{LuaValue, Value}; use crate::ir::Node; @@ -161,8 +161,8 @@ impl ExecutionPlan { /// - IR plan is invalid pub fn to_params(&self) -> Result<Vec<Value>, SbroadError> { let plan = self.get_ir_plan(); - let capacity = plan.next_id(); - let filter = |id: usize| -> bool { matches!(plan.get_node(id), Ok(Node::Parameter(_))) }; + let capacity = plan.nodes.len(); + let filter = |id: NodeId| -> bool { matches!(plan.get_node(id), Ok(Node::Parameter(_))) }; let mut tree = PostOrderWithFilter::with_capacity( |node| plan.flashback_subtree_iter(node), capacity, @@ -172,7 +172,7 @@ impl ExecutionPlan { tree.populate_nodes(top_id); let nodes = tree.take_nodes(); let mut params: Vec<Value> = Vec::with_capacity(nodes.len()); - for (_, param_id) in nodes { + for LevelNode(_, param_id) in nodes { let Expression::Constant { value } = plan.get_expression_node(param_id)? else { return Err(SbroadError::Invalid( Entity::Plan, @@ -428,7 +428,7 @@ impl ExecutionPlan { })?; } Expression::Reference { position, .. } => { - let rel_id: usize = + let rel_id = *ir_plan.get_relational_from_reference_node(*id)?; let rel_node = ir_plan.get_relation_node(rel_id)?; @@ -553,7 +553,7 @@ impl ExecutionPlan { /// /// # Errors /// - If the subtree top is not a relational node. - pub fn subtree_modifies_data(&self, top_id: usize) -> Result<bool, SbroadError> { + pub fn subtree_modifies_data(&self, top_id: NodeId) -> Result<bool, SbroadError> { // Tarantool doesn't support `INSERT`, `UPDATE` and `DELETE` statements // with `RETURNING` clause. That is why it is enough to check if the top // node is a data modification statement or not. diff --git a/sbroad-core/src/backend/sql/space.rs b/sbroad-core/src/backend/sql/space.rs index 6342206ce..4807b384b 100644 --- a/sbroad-core/src/backend/sql/space.rs +++ b/sbroad-core/src/backend/sql/space.rs @@ -1,4 +1,5 @@ use crate::executor::ir::ExecutionPlan; +use crate::ir::expression::NodeId; use crate::ir::relation::SpaceEngine; use crate::{errors::SbroadError, executor::protocol::VTablesMeta}; @@ -133,7 +134,7 @@ pub const ADMIN_ID: u32 = 1; pub fn create_table( exec_plan: &ExecutionPlan, plan_id: &str, - motion_id: usize, + motion_id: NodeId, engine: &SpaceEngine, #[allow(unused_variables)] vtables_meta: Option<&VTablesMeta>, ) -> Result<TableGuard, SbroadError> { diff --git a/sbroad-core/src/backend/sql/tree.rs b/sbroad-core/src/backend/sql/tree.rs index 524448408..51954121c 100644 --- a/sbroad-core/src/backend/sql/tree.rs +++ b/sbroad-core/src/backend/sql/tree.rs @@ -4,10 +4,10 @@ use std::mem::take; use crate::errors::{Entity, SbroadError}; use crate::executor::ir::ExecutionPlan; -use crate::ir::expression::{Expression, FunctionFeature, TrimKind}; +use crate::ir::expression::{Expression, FunctionFeature, NodeId, TrimKind}; use crate::ir::operator::{Bool, OrderByElement, OrderByEntity, OrderByType, Relational, Unary}; use crate::ir::transformation::redistribution::{MotionOpcode, MotionPolicy}; -use crate::ir::tree::traversal::PostOrder; +use crate::ir::tree::traversal::{LevelNode, PostOrder}; use crate::ir::tree::Snapshot; use crate::ir::{Node, Plan}; use crate::otm::child_span; @@ -72,12 +72,12 @@ pub enum SyntaxData { /// "=, >, <, and, or, ..." Operator(SmolStr), /// plan node id - PlanId(usize), + PlanId(NodeId), /// parameter (a wrapper over a plan constants) - Parameter(usize), + Parameter(NodeId), /// virtual table (the key is a motion node id /// pointing to the execution plan's virtual table) - VTable(usize), + VTable(NodeId), } /// A syntax tree node. @@ -300,7 +300,7 @@ impl SyntaxNode { } } - fn new_pointer(id: usize, left: Option<usize>, right: Vec<usize>) -> Self { + fn new_pointer(id: NodeId, left: Option<usize>, right: Vec<usize>) -> Self { SyntaxNode { data: SyntaxData::PlanId(id), left, @@ -308,7 +308,7 @@ impl SyntaxNode { } } - fn new_parameter(id: usize) -> Self { + fn new_parameter(id: NodeId) -> Self { SyntaxNode { data: SyntaxData::Parameter(id), left: None, @@ -326,7 +326,7 @@ impl SyntaxNode { } } - fn new_vtable(motion_id: usize) -> Self { + fn new_vtable(motion_id: NodeId) -> Self { SyntaxNode { data: SyntaxData::VTable(motion_id), left: None, @@ -550,7 +550,7 @@ impl<'p> SyntaxPlan<'p> { /// # Panics /// - syntax node wraps non-plan node; /// - plan node is not the one we expect; - fn check_plan_node(&self, sn_id: usize, plan_id: usize) { + fn check_plan_node(&self, sn_id: usize, plan_id: NodeId) { let sn = self.nodes.get_sn(sn_id); let SyntaxNode { data: SyntaxData::PlanId(id) | SyntaxData::Parameter(id), @@ -580,7 +580,7 @@ impl<'p> SyntaxPlan<'p> { } _ => {} } - panic!("Expected plan node {plan_id} but got {id}"); + panic!("Expected plan node {plan_id:?} but got {id:?}"); } } @@ -591,7 +591,7 @@ impl<'p> SyntaxPlan<'p> { /// Pop syntax node identifier from the stack with a check, that the popped syntax /// node wraps an expected plan node. - fn pop_from_stack(&mut self, plan_id: usize) -> usize { + fn pop_from_stack(&mut self, plan_id: NodeId) -> usize { let sn_id = self.nodes.stack.pop().expect("stack must be non-empty"); self.check_plan_node(sn_id, plan_id); sn_id @@ -609,7 +609,7 @@ impl<'p> SyntaxPlan<'p> { /// - Failed to find a node in the plan. #[allow(clippy::too_many_lines)] #[allow(unused_variables)] - pub fn add_plan_node(&mut self, id: usize) { + pub fn add_plan_node(&mut self, id: NodeId) { let ir_plan = self.plan.get_ir_plan(); let node = ir_plan .get_node(id) @@ -668,7 +668,7 @@ impl<'p> SyntaxPlan<'p> { } } - fn prologue_rel(&self, id: usize) -> (&Plan, &Relational) { + fn prologue_rel(&self, id: NodeId) -> (&Plan, &Relational) { let plan = self.plan.get_ir_plan(); let rel = plan .get_relation_node(id) @@ -676,7 +676,7 @@ impl<'p> SyntaxPlan<'p> { (plan, rel) } - fn prologue_expr(&self, id: usize) -> (&Plan, &Expression) { + fn prologue_expr(&self, id: NodeId) -> (&Plan, &Expression) { let plan = self.plan.get_ir_plan(); let expr = plan .get_expression_node(id) @@ -686,7 +686,7 @@ impl<'p> SyntaxPlan<'p> { // Relational nodes. - fn add_cte(&mut self, id: usize) { + fn add_cte(&mut self, id: NodeId) { let (_, cte) = self.prologue_rel(id); let Relational::ScanCte { alias, child, .. } = cte else { panic!("expected CTE node"); @@ -704,7 +704,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_filter(&mut self, id: usize) { + fn add_filter(&mut self, id: NodeId) { let (plan, rel) = self.prologue_rel(id); let (Relational::Selection { children, filter, .. @@ -726,7 +726,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_group_by(&mut self, id: usize) { + fn add_group_by(&mut self, id: NodeId) { let (_, gb) = self.prologue_rel(id); let Relational::GroupBy { children, gr_cols, .. @@ -736,16 +736,17 @@ impl<'p> SyntaxPlan<'p> { }; let child_plan_id = *children.first().expect("GROUP BY child"); // The columns on the stack are in reverse order. - let mut sn_gr_cols = gr_cols.iter().rev().copied().collect::<Vec<_>>(); + let plan_gr_cols = gr_cols.iter().rev().copied().collect::<Vec<_>>(); + let mut syntax_gr_cols = Vec::with_capacity(plan_gr_cols.len()); // Reuse the same vector to avoid extra allocations // (replace plan node ids with syntax node ids). - for col_id in &mut sn_gr_cols { - *col_id = self.pop_from_stack(*col_id); + for col_id in &plan_gr_cols { + syntax_gr_cols.push(self.pop_from_stack(*col_id)); } let child_sn_id = self.pop_from_stack(child_plan_id); - let mut sn_children = Vec::with_capacity(sn_gr_cols.len() * 2 - 1); + let mut sn_children = Vec::with_capacity(syntax_gr_cols.len() * 2 - 1); // The columns are in reverse order, so we need to reverse them back. - if let Some((first, others)) = sn_gr_cols.split_first() { + if let Some((first, others)) = syntax_gr_cols.split_first() { for id in others.iter().rev() { sn_children.push(*id); sn_children.push(self.nodes.push_sn_non_plan(SyntaxNode::new_comma())); @@ -756,7 +757,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_join(&mut self, id: usize) { + fn add_join(&mut self, id: NodeId) { let (plan, join) = self.prologue_rel(id); let Relational::Join { children, @@ -791,7 +792,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_motion(&mut self, id: usize) { + fn add_motion(&mut self, id: NodeId) { let (plan, motion) = self.prologue_rel(id); let Relational::Motion { policy, @@ -896,7 +897,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_order_by(&mut self, id: usize) { + fn add_order_by(&mut self, id: NodeId) { let (_, order_by) = self.prologue_rel(id); let Relational::OrderBy { order_by_elements, @@ -952,7 +953,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_proj(&mut self, id: usize) { + fn add_proj(&mut self, id: NodeId) { let (_, proj) = self.prologue_rel(id); let Relational::Projection { children, output, .. @@ -985,7 +986,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_scan_relation(&mut self, id: usize) { + fn add_scan_relation(&mut self, id: NodeId) { let (_, scan) = self.prologue_rel(id); let Relational::ScanRelation { alias, .. } = scan else { panic!("Expected SCAN node"); @@ -1001,7 +1002,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_set(&mut self, id: usize) { + fn add_set(&mut self, id: NodeId) { let (_, set) = self.prologue_rel(id); let (Relational::Except { left, right, .. } | Relational::Union { left, right, .. } @@ -1017,7 +1018,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_sq(&mut self, id: usize) { + fn add_sq(&mut self, id: NodeId) { let (_, sq) = self.prologue_rel(id); let Relational::ScanSubQuery { children, alias, .. @@ -1042,7 +1043,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_values_row(&mut self, id: usize) { + fn add_values_row(&mut self, id: NodeId) { let (_, row) = self.prologue_rel(id); let Relational::ValuesRow { data, .. } = row else { panic!("Expected VALUES ROW node"); @@ -1052,7 +1053,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_values(&mut self, id: usize) { + fn add_values(&mut self, id: NodeId) { let (_, values) = self.prologue_rel(id); let Relational::Values { children, output, .. @@ -1062,24 +1063,25 @@ impl<'p> SyntaxPlan<'p> { }; let output_plan_id = *output; // The syntax nodes on the stack are in the reverse order. - let mut sn_children = children.iter().rev().copied().collect::<Vec<_>>(); - // Reuse the same vector to avoid extra allocations (replace plan node ids with syntax node ids). - for child_id in &mut sn_children { - *child_id = self.pop_from_stack(*child_id); + let plan_children = children.iter().rev().copied().collect::<Vec<_>>(); + let mut syntax_children = Vec::with_capacity(plan_children.len()); + + for child_id in &plan_children { + syntax_children.push(self.pop_from_stack(*child_id)); } // Consume the output from the stack. let _ = self.pop_from_stack(output_plan_id); - let mut nodes = Vec::with_capacity(sn_children.len() * 2 - 1); + let mut nodes = Vec::with_capacity(syntax_children.len() * 2 - 1); // Reverse the order of the children back. let arena = &mut self.nodes; - for child_id in sn_children.iter().skip(1).rev() { + for child_id in syntax_children.iter().skip(1).rev() { nodes.push(*child_id); nodes.push(arena.push_sn_non_plan(SyntaxNode::new_comma())); } nodes.push( - *sn_children + *syntax_children .first() .expect("values must have at least one child"), ); @@ -1087,7 +1089,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_limit(&mut self, id: usize) { + fn add_limit(&mut self, id: NodeId) { let (_, limit) = self.prologue_rel(id); let Relational::Limit { limit, child, .. } = limit else { panic!("expected LIMIT node"); @@ -1105,7 +1107,7 @@ impl<'p> SyntaxPlan<'p> { // Expression nodes. - fn add_alias(&mut self, id: usize) { + fn add_alias(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); let Expression::Alias { child, name } = expr else { panic!("Expected ALIAS node"); @@ -1132,7 +1134,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_binary_op(&mut self, id: usize) { + fn add_binary_op(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); let (left_plan_id, right_plan_id, op_sn_id) = match expr { Expression::Bool { @@ -1162,7 +1164,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_case(&mut self, id: usize) { + fn add_case(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); let Expression::Case { search_expr, @@ -1173,7 +1175,7 @@ impl<'p> SyntaxPlan<'p> { panic!("Expected CASE node"); }; let search_expr = *search_expr; - let when_blocks: Vec<(usize, usize)> = when_blocks.clone(); + let when_blocks: Vec<(NodeId, NodeId)> = when_blocks.clone(); let else_expr = *else_expr; let mut right_vec = Vec::with_capacity(1 + when_blocks.len() * 4 + 1); @@ -1200,7 +1202,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_cast(&mut self, id: usize) { + fn add_cast(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); let Expression::Cast { child, to } = expr else { panic!("Expected CAST node"); @@ -1220,7 +1222,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_concat(&mut self, id: usize) { + fn add_concat(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); let Expression::Concat { left, right } = expr else { panic!("Expected CONCAT node"); @@ -1236,7 +1238,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_expr_in_parentheses(&mut self, id: usize) { + fn add_expr_in_parentheses(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); let Expression::ExprInParentheses { child } = expr else { panic!("Expected expression in parentheses node"); @@ -1252,7 +1254,7 @@ impl<'p> SyntaxPlan<'p> { arena.push_sn_plan(sn); } - fn add_row(&mut self, id: usize) { + fn add_row(&mut self, id: NodeId) { let plan = self.plan.get_ir_plan(); let expr = plan .get_expression_node(id) @@ -1376,7 +1378,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_stable_func(&mut self, id: usize) { + fn add_stable_func(&mut self, id: NodeId) { let plan = self.plan.get_ir_plan(); let expr = plan .get_expression_node(id) @@ -1409,7 +1411,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_trim(&mut self, id: usize) { + fn add_trim(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); let Expression::Trim { kind, @@ -1457,7 +1459,7 @@ impl<'p> SyntaxPlan<'p> { self.nodes.push_sn_plan(sn); } - fn add_unary_op(&mut self, id: usize) { + fn add_unary_op(&mut self, id: NodeId) { let (plan, expr) = self.prologue_expr(id); let Expression::Unary { child, op } = expr else { panic!("Expected unary expression node"); @@ -1558,7 +1560,7 @@ impl<'p> SyntaxPlan<'p> { ); dfs.populate_nodes(top); let nodes = dfs.take_nodes(); - for (_, pos) in nodes { + for LevelNode(_, pos) in nodes { let node = self.nodes.get_sn(pos); if pos == top { let select = Select::new(self, None, None, pos)?; @@ -1603,7 +1605,7 @@ impl<'p> SyntaxPlan<'p> { pub(crate) fn empty(plan: &'p ExecutionPlan) -> Self { SyntaxPlan { - nodes: SyntaxNodes::with_capacity(plan.get_ir_plan().next_id() * 2), + nodes: SyntaxNodes::with_capacity(plan.get_ir_plan().nodes.len() * 2), top: None, plan, snapshot: Snapshot::Latest, @@ -1619,7 +1621,7 @@ impl<'p> SyntaxPlan<'p> { #[otm_child_span("syntax.new")] pub fn new( plan: &'p ExecutionPlan, - top: usize, + top: NodeId, snapshot: Snapshot, ) -> Result<Self, SbroadError> { let mut sp = SyntaxPlan::empty(plan); @@ -1627,12 +1629,13 @@ impl<'p> SyntaxPlan<'p> { let ir_plan = plan.get_ir_plan(); // Wrap plan's nodes and preserve their ids. - let capacity = ir_plan.next_id(); + let capacity = ir_plan.nodes.len(); match snapshot { Snapshot::Latest => { let mut dft_post = PostOrder::with_capacity(|node| ir_plan.subtree_iter(node, false), capacity); - for (_, id) in dft_post.iter(top) { + for level_node in dft_post.iter(top) { + let id = level_node.1; // it works only for post-order traversal sp.add_plan_node(id); let sn_id = sp.nodes.next_id() - 1; @@ -1644,7 +1647,8 @@ impl<'p> SyntaxPlan<'p> { Snapshot::Oldest => { let mut dft_post = PostOrder::with_capacity(|node| ir_plan.flashback_subtree_iter(node), capacity); - for (_, id) in dft_post.iter(top) { + for level_node in dft_post.iter(top) { + let id = level_node.1; // it works only for post-order traversal sp.add_plan_node(id); let sn_id = sp.nodes.next_id() - 1; @@ -1787,6 +1791,3 @@ impl TryFrom<SyntaxPlan<'_>> for OrderedSyntaxNodes { Ok(Self { arena, positions }) } } - -#[cfg(test)] -mod tests; diff --git a/sbroad-core/src/executor.rs b/sbroad-core/src/executor.rs index d88f66beb..b708f8af1 100644 --- a/sbroad-core/src/executor.rs +++ b/sbroad-core/src/executor.rs @@ -33,6 +33,7 @@ use crate::executor::engine::{helpers::materialize_values, Router, TableVersionM use crate::executor::ir::ExecutionPlan; use crate::executor::lru::Cache; use crate::frontend::Ast; +use crate::ir::expression::NodeId; use crate::ir::operator::Relational; use crate::ir::transformation::redistribution::MotionPolicy; use crate::ir::value::Value; @@ -82,7 +83,7 @@ where coordinator: &'a C, /// Bucket map of view { plan output_id (Expression::Row) -> `Buckets` }. /// It's supposed to denote relational nodes' output buckets destination. - bucket_map: HashMap<usize, Buckets>, + bucket_map: HashMap<NodeId, Buckets>, } impl<'a, C> Query<'a, C> @@ -93,7 +94,7 @@ where is_explain: bool, exec_plan: ExecutionPlan, coordinator: &'a C, - bucket_map: HashMap<usize, Buckets>, + bucket_map: HashMap<NodeId, Buckets>, ) -> Self { Self { is_explain, @@ -201,7 +202,7 @@ where materialize_values(&mut self.exec_plan, *motion_id)? { self.exec_plan.set_motion_vtable( - *motion_id, + motion_id, virtual_table, &vshard, )?; @@ -227,11 +228,11 @@ where let buckets = self.bucket_discovery(top_id)?; let virtual_table = self.coordinator.materialize_motion( &mut self.exec_plan, - *motion_id, + motion_id, &buckets, )?; self.exec_plan - .set_motion_vtable(*motion_id, virtual_table, &vshard)?; + .set_motion_vtable(motion_id, virtual_table, &vshard)?; } } @@ -273,7 +274,7 @@ where return Err(err("no vtables in plan with motion top")); }; let Some(mut vtable) = vtables.remove(&top_id) else { - return Err(err(&format!("no motion on top_id: {top_id}"))); + return Err(err(&format!("no motion on top_id: {top_id:?}"))); }; let Some(v) = Rc::get_mut(&mut vtable) else { return Err(err("there are other refs to vtable")); diff --git a/sbroad-core/src/executor/bucket.rs b/sbroad-core/src/executor/bucket.rs index 072ea8f8f..ebaae19bb 100644 --- a/sbroad-core/src/executor/bucket.rs +++ b/sbroad-core/src/executor/bucket.rs @@ -7,11 +7,11 @@ use crate::errors::{Action, Entity, SbroadError}; use crate::executor::engine::{Router, Vshard}; use crate::executor::Query; use crate::ir::distribution::Distribution; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::helpers::RepeatableState; use crate::ir::operator::{Bool, JoinKind, Relational}; use crate::ir::transformation::redistribution::MotionPolicy; -use crate::ir::tree::traversal::{PostOrderWithFilter, REL_CAPACITY}; +use crate::ir::tree::traversal::{LevelNode, PostOrderWithFilter, REL_CAPACITY}; use crate::ir::value::Value; use crate::ir::Node; use crate::otm::child_span; @@ -88,7 +88,7 @@ where /// In general it returns `Buckets::All`, but in some cases (e.g. `Eq` and `In` operators) it /// will return `Buckets::Filtered` (if such a result is met in SELECT or JOIN filter, it means /// that we can execute the query only on some of the replicasets). - fn get_buckets_from_expr(&self, expr_id: usize) -> Result<Option<Buckets>, SbroadError> { + fn get_buckets_from_expr(&self, expr_id: NodeId) -> Result<Option<Buckets>, SbroadError> { // The only possible case there will be several `Buckets` in the vec is when we have `Eq`. // See the logic of its handling below. let mut buckets: Vec<Buckets> = vec![]; @@ -206,8 +206,8 @@ where /// In case there is just one expression (not `ANDed`) `chains` will remain empty. fn get_expression_tree_buckets( &self, - expr_id: usize, - rel_children: &[usize], + expr_id: NodeId, + rel_children: &[NodeId], ) -> Result<Buckets, SbroadError> { let ir_plan = self.exec_plan.get_ir_plan(); let chains = ir_plan.get_dnf_chains(expr_id)?; @@ -273,7 +273,7 @@ where /// - Relational nodes contain invalid children. #[allow(clippy::too_many_lines)] #[otm_child_span("query.bucket.discovery")] - pub fn bucket_discovery(&mut self, top_id: usize) -> Result<Buckets, SbroadError> { + pub fn bucket_discovery(&mut self, top_id: NodeId) -> Result<Buckets, SbroadError> { // if top's output has Distribution::Single then the whole subtree must executed only on // a single node, no need to traverse the subtree let top_output_id = self.exec_plan.get_ir_plan().get_relational_output(top_id)?; @@ -291,7 +291,7 @@ where } let ir_plan = self.exec_plan.get_ir_plan(); - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { if let Ok(Node::Relational(_)) = ir_plan.get_node(node_id) { return true; } @@ -305,7 +305,7 @@ where Box::new(filter), ); - for (_, node_id) in tree.iter(top_id) { + for LevelNode(_, node_id) in tree.iter(top_id) { if self.bucket_map.contains_key(&node_id) { continue; } diff --git a/sbroad-core/src/executor/engine.rs b/sbroad-core/src/executor/engine.rs index 556bde45a..509a93a58 100644 --- a/sbroad-core/src/executor/engine.rs +++ b/sbroad-core/src/executor/engine.rs @@ -7,6 +7,7 @@ use tarantool::tuple::Tuple; use crate::cbo::histogram::Scalar; use crate::cbo::{ColumnStats, TableColumnPair, TableStats}; +use crate::ir::expression::NodeId; use crate::utils::MutexLike; use std::any::Any; @@ -23,7 +24,6 @@ use crate::ir::function::Function; use crate::ir::relation::Table; use crate::ir::relation::Type; use crate::ir::value::Value; -use crate::ir::NodeId; use super::result::ProducerResult; @@ -277,7 +277,7 @@ pub trait Router: QueryCache { fn dispatch( &self, plan: &mut ExecutionPlan, - top_id: usize, + top_id: NodeId, buckets: &Buckets, return_format: DispatchReturnFormat, ) -> Result<Box<dyn Any>, SbroadError>; @@ -289,7 +289,7 @@ pub trait Router: QueryCache { fn materialize_motion( &self, plan: &mut ExecutionPlan, - motion_node_id: usize, + motion_node_id: &NodeId, buckets: &Buckets, ) -> Result<VirtualTable, SbroadError>; diff --git a/sbroad-core/src/executor/engine/helpers.rs b/sbroad-core/src/executor/engine/helpers.rs index f29ba3c0a..77a7cc8a9 100644 --- a/sbroad-core/src/executor/engine/helpers.rs +++ b/sbroad-core/src/executor/engine/helpers.rs @@ -1,6 +1,6 @@ use ahash::AHashMap; -use crate::{error, utils::MutexLike}; +use crate::{error, ir::expression::NodeId, utils::MutexLike}; use itertools::enumerate; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use std::{ @@ -24,7 +24,6 @@ use crate::executor::engine::{QueryCache, StorageCache}; use crate::executor::protocol::{EncodedTables, SchemaInfo}; use crate::ir::operator::ConflictStrategy; use crate::ir::value::{EncodedValue, LuaValue, MsgPackValue}; -use crate::ir::NodeId; use crate::otm::child_span; use crate::utils::ByteCounter; use crate::{ @@ -436,7 +435,7 @@ pub type TupleBuilderPattern = Vec<TupleBuilderCommand>; pub fn init_local_update_tuple_builder( plan: &Plan, vtable: &VirtualTable, - update_id: usize, + update_id: NodeId, ) -> Result<TupleBuilderPattern, SbroadError> { if let Relational::Update { relation, @@ -520,7 +519,7 @@ pub fn init_local_update_tuple_builder( } Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("expected Update on id ({update_id})")), + Some(format_smolstr!("expected Update on id ({update_id:?})")), )) } @@ -530,7 +529,7 @@ pub fn init_local_update_tuple_builder( /// - plan top is not Delete pub fn init_delete_tuple_builder( plan: &Plan, - delete_id: usize, + delete_id: NodeId, ) -> Result<TupleBuilderPattern, SbroadError> { let table = plan.dml_node_table(delete_id)?; let mut commands = Vec::with_capacity(table.primary_key.positions.len()); @@ -547,7 +546,7 @@ pub fn init_delete_tuple_builder( pub fn init_insert_tuple_builder( plan: &Plan, vtable: &VirtualTable, - insert_id: usize, + insert_id: NodeId, ) -> Result<TupleBuilderPattern, SbroadError> { let columns = plan.insert_columns(insert_id)?; // Revert map of { pos_in_child_node -> pos_in_relation } @@ -663,7 +662,7 @@ pub fn build_insert_args<'t>( fn init_sharded_update_tuple_builder( plan: &Plan, vtable: &VirtualTable, - update_id: usize, + update_id: NodeId, ) -> Result<TupleBuilderPattern, SbroadError> { let Relational::Update { update_columns_map, .. @@ -672,7 +671,7 @@ fn init_sharded_update_tuple_builder( return Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "update tuple builder: expected update node on id: {update_id}" + "update tuple builder: expected update node on id: {update_id:?}" )), )); }; @@ -825,7 +824,7 @@ fn has_zero_limit_clause(plan: &ExecutionPlan) -> Result<bool, SbroadError> { pub fn dispatch_impl( coordinator: &impl Router, plan: &mut ExecutionPlan, - top_id: usize, + top_id: NodeId, buckets: &Buckets, return_format: DispatchReturnFormat, ) -> Result<Box<dyn Any>, SbroadError> { @@ -881,7 +880,7 @@ pub fn dispatch_by_buckets( if !vtable.get_bucket_index().is_empty() { return Err(SbroadError::Invalid( Entity::Motion, - Some(format_smolstr!("motion ({motion_id}) in subtree with distribution Single, but policy is not Full!")), + Some(format_smolstr!("motion ({motion_id:?}) in subtree with distribution Single, but policy is not Full!")), )); } } @@ -897,7 +896,7 @@ pub fn dispatch_by_buckets( #[allow(clippy::too_many_lines)] pub(crate) fn materialize_values( plan: &mut ExecutionPlan, - motion_node_id: usize, + motion_node_id: NodeId, ) -> Result<Option<VirtualTable>, SbroadError> { // Check that the motion node has a local segment policy. let motion_node = plan.get_ir_plan().get_relation_node(motion_node_id)?; @@ -1004,7 +1003,7 @@ pub(crate) fn materialize_values( return Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "value node child ({child_id}) is not a values row node!" + "value node child ({child_id:?}) is not a values row node!" )), )); } @@ -1031,7 +1030,7 @@ pub(crate) fn materialize_values( return Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "output column ({column_id}) is not an alias node!" + "output column ({column_id:?}) is not an alias node!" )), )); } @@ -1051,7 +1050,7 @@ pub(crate) fn materialize_values( pub fn materialize_motion( runtime: &impl Router, plan: &mut ExecutionPlan, - motion_node_id: usize, + motion_node_id: NodeId, buckets: &Buckets, ) -> Result<VirtualTable, SbroadError> { let top_id = plan.get_motion_subtree_root(motion_node_id)?; @@ -1548,7 +1547,7 @@ fn materialize_vtable_locally<R: Vshard + QueryCache>( runtime: &R, optional: &mut OptionalData, required: &mut RequiredData, - child_id: usize, + child_id: NodeId, ) -> Result<(), SbroadError> where R::Cache: StorageCache, @@ -1565,7 +1564,7 @@ where SbroadError::FailedTo( Action::Deserialize, Some(Entity::Tuple), - format_smolstr!("motion node {child_id}. {e:?}"), + format_smolstr!("motion node {child_id:?}. {e:?}"), ) })?; let mut reader = bytes.as_ref().as_slice(); @@ -1573,7 +1572,7 @@ where SbroadError::FailedTo( Action::Decode, Some(Entity::Tuple), - format_smolstr!("motion node {child_id}. {e}"), + format_smolstr!("motion node {child_id:?}. {e}"), ) })?; let vtable = data @@ -1584,7 +1583,7 @@ where .as_virtual_table(column_names, true)?; optional .exec_plan - .set_motion_vtable(child_id, vtable, runtime)?; + .set_motion_vtable(&child_id, vtable, runtime)?; Ok(()) } diff --git a/sbroad-core/src/executor/engine/helpers/storage.rs b/sbroad-core/src/executor/engine/helpers/storage.rs index a0556cb8f..c1756ffb9 100644 --- a/sbroad-core/src/executor/engine/helpers/storage.rs +++ b/sbroad-core/src/executor/engine/helpers/storage.rs @@ -17,7 +17,7 @@ use crate::executor::engine::helpers::proxy::sql_cache_proxy; use crate::executor::engine::helpers::table_name; use crate::executor::lru::DEFAULT_CAPACITY; use crate::ir::value::{EncodedValue, Value}; -use crate::ir::NodeId; +use crate::ir::expression::NodeId; use crate::otm::child_span; use crate::utils::ByteCounter; diff --git a/sbroad-core/src/executor/engine/helpers/vshard.rs b/sbroad-core/src/executor/engine/helpers/vshard.rs index 6dfedda56..87302d9d5 100644 --- a/sbroad-core/src/executor/engine/helpers/vshard.rs +++ b/sbroad-core/src/executor/engine/helpers/vshard.rs @@ -19,14 +19,15 @@ use crate::{ result::ProducerResult, }, ir::{ + expression::NodeId, helpers::RepeatableState, operator::Relational, transformation::redistribution::{MotionOpcode, MotionPolicy}, tree::{ relation::RelationalIterator, - traversal::{PostOrderWithFilter, REL_CAPACITY}, + traversal::{LevelNode, PostOrderWithFilter, REL_CAPACITY}, }, - Node, NodeId, Plan, + Node, Plan, }, otm::child_span, }; @@ -748,7 +749,7 @@ struct SerializeAsEmptyInfo { impl Plan { // return true if given node is Motion containing seriliaze as empty // opcode. If `check_enabled` is true checks that the opcode is enabled. - fn is_serialize_as_empty_motion(&self, node_id: usize, check_enabled: bool) -> bool { + fn is_serialize_as_empty_motion(&self, node_id: NodeId, check_enabled: bool) -> bool { if let Ok(Node::Relational(Relational::Motion { program, .. })) = self.get_node(node_id) { if let Some(op) = program .0 @@ -761,8 +762,8 @@ impl Plan { false } - fn collect_top_ids(&self) -> Result<Vec<usize>, SbroadError> { - let mut stop_nodes: HashSet<usize> = HashSet::new(); + fn collect_top_ids(&self) -> Result<Vec<NodeId>, SbroadError> { + let mut stop_nodes: HashSet<NodeId> = HashSet::new(); let iter_children = |node_id| -> RelationalIterator<'_> { if self.is_serialize_as_empty_motion(node_id, true) { stop_nodes.insert(node_id); @@ -773,17 +774,17 @@ impl Plan { } self.nodes.rel_iter(node_id) }; - let filter = |node_id: usize| -> bool { self.is_serialize_as_empty_motion(node_id, true) }; + let filter = |node_id: NodeId| -> bool { self.is_serialize_as_empty_motion(node_id, true) }; let mut dfs = PostOrderWithFilter::with_capacity(iter_children, 4, Box::new(filter)); - Ok(dfs.iter(self.get_top()?).map(|(_, id)| id).collect()) + Ok(dfs.iter(self.get_top()?).map(|id| id.1).collect()) } fn serialize_as_empty_info(&self) -> Result<Option<SerializeAsEmptyInfo>, SbroadError> { let top_ids = self.collect_top_ids()?; let mut motions_ref_count: AHashMap<NodeId, usize> = AHashMap::new(); - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), Ok(Node::Relational(Relational::Motion { .. })) @@ -791,7 +792,7 @@ impl Plan { }; let mut dfs = PostOrderWithFilter::with_capacity(|x| self.nodes.rel_iter(x), 0, Box::new(filter)); - for (_, motion_id) in dfs.iter(self.get_top()?) { + for LevelNode(_, motion_id) in dfs.iter(self.get_top()?) { motions_ref_count .entry(motion_id) .and_modify(|cnt| *cnt += 1) @@ -805,7 +806,7 @@ impl Plan { // all motion nodes that are inside the subtrees // defined by `top_ids` let all_motion_nodes = { - let is_motion = |node_id: usize| -> bool { + let is_motion = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), Ok(Node::Relational(Relational::Motion { .. })) @@ -818,7 +819,7 @@ impl Plan { REL_CAPACITY, Box::new(is_motion), ); - all_motions.extend(dfs.iter(*top_id).map(|(_, id)| id)); + all_motions.extend(dfs.iter(*top_id).map(|id| id.1)); } all_motions }; @@ -890,7 +891,7 @@ fn apply_serialize_as_empty_opcode( for motion_id in &unused_motions { let Some(use_count) = info.motions_ref_count.get_mut(motion_id) else { return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!( - "no ref count for motion={motion_id}" + "no ref count for motion={motion_id:?}" ))); }; if *use_count > 1 { @@ -925,7 +926,7 @@ fn disable_serialize_as_empty_opcode( } else { return Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("expected motion node on id {motion_id}")), + Some(format_smolstr!("expected motion node on id {motion_id:?}")), )); }; for op in &mut program.0 { diff --git a/sbroad-core/src/executor/engine/mock.rs b/sbroad-core/src/executor/engine/mock.rs index 7a4336aac..900d90740 100644 --- a/sbroad-core/src/executor/engine/mock.rs +++ b/sbroad-core/src/executor/engine/mock.rs @@ -30,6 +30,7 @@ use crate::executor::result::ProducerResult; use crate::executor::vtable::VirtualTable; use crate::executor::Cache; use crate::frontend::sql::ast::AbstractSyntaxTree; +use crate::ir::expression::NodeId; use crate::ir::function::Function; use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type}; use crate::ir::tree::Snapshot; @@ -826,7 +827,7 @@ pub struct RouterRuntimeMock { // It's based on the RefCells instead of tarantool mutexes, // so it could be used in unit tests - they won't compile otherwise due to missing tarantool symbols. metadata: RefCell<RouterConfigurationMock>, - virtual_tables: RefCell<HashMap<usize, VirtualTable>>, + virtual_tables: RefCell<HashMap<NodeId, VirtualTable>>, ir_cache: Rc<RefCell<LRUCache<SmolStr, Plan>>>, table_statistics_cache: RefCell<HashMap<SmolStr, Rc<TableStats>>>, initial_column_statistics_cache: RefCell<HashMap<TableColumnPair, Rc<Box<dyn Any>>>>, @@ -1299,7 +1300,7 @@ impl RouterRuntimeMock { } #[allow(dead_code)] - pub fn add_virtual_table(&self, id: usize, table: VirtualTable) { + pub fn add_virtual_table(&self, id: NodeId, table: VirtualTable) { self.virtual_tables.borrow_mut().insert(id, table); } } @@ -1316,15 +1317,15 @@ impl Router for RouterRuntimeMock { fn materialize_motion( &self, _plan: &mut ExecutionPlan, - motion_node_id: usize, + motion_node_id: &NodeId, _buckets: &Buckets, ) -> Result<VirtualTable, SbroadError> { - if let Some(virtual_table) = self.virtual_tables.borrow().get(&motion_node_id) { + if let Some(virtual_table) = self.virtual_tables.borrow().get(motion_node_id) { Ok(virtual_table.clone()) } else { Err(SbroadError::NotFound( Entity::VirtualTable, - format_smolstr!("for motion node {motion_node_id}"), + format_smolstr!("for motion node {motion_node_id:?}"), )) } } @@ -1332,7 +1333,7 @@ impl Router for RouterRuntimeMock { fn dispatch( &self, plan: &mut ExecutionPlan, - top_id: usize, + top_id: NodeId, buckets: &Buckets, _return_format: DispatchReturnFormat, ) -> Result<Box<dyn Any>, SbroadError> { @@ -1488,7 +1489,7 @@ pub struct ReplicasetDispatchInfo { pub rs_id: usize, pub pattern: String, pub params: Vec<Value>, - pub vtables_map: HashMap<usize, Rc<VirtualTable>>, + pub vtables_map: HashMap<NodeId, Rc<VirtualTable>>, } impl ReplicasetDispatchInfo { @@ -1502,7 +1503,7 @@ impl ReplicasetDispatchInfo { let (pattern_with_params, _) = exec_plan .to_sql(&syntax_data_nodes, TEMPLATE, None) .unwrap(); - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); if let Some(vtables_map) = exec_plan.get_vtables() { vtables.clone_from(vtables_map); } diff --git a/sbroad-core/src/executor/ir.rs b/sbroad-core/src/executor/ir.rs index 1b6888d7b..5a4fb3743 100644 --- a/sbroad-core/src/executor/ir.rs +++ b/sbroad-core/src/executor/ir.rs @@ -8,12 +8,12 @@ use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use crate::errors::{Action, Entity, SbroadError}; use crate::executor::engine::Vshard; use crate::executor::vtable::{VirtualTable, VirtualTableMap}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::{OrderByElement, OrderByEntity, Relational}; use crate::ir::relation::SpaceEngine; use crate::ir::transformation::redistribution::{MotionOpcode, MotionPolicy}; -use crate::ir::tree::traversal::PostOrder; -use crate::ir::{ExecuteOptions, Node, Plan}; +use crate::ir::tree::traversal::{LevelNode, PostOrder}; +use crate::ir::{ArenaType, ExecuteOptions, Node, Plan}; use crate::otm::child_span; use sbroad_proc::otm_child_span; @@ -63,7 +63,7 @@ impl From<Plan> for ExecutionPlan { /// Translates the original plan's node id to the new sub-plan one. struct SubtreeMap { - inner: AHashMap<usize, usize>, + inner: AHashMap<NodeId, NodeId>, } impl SubtreeMap { @@ -73,18 +73,18 @@ impl SubtreeMap { } } - fn get_id(&self, expr_id: usize) -> usize { + fn get_id(&self, expr_id: NodeId) -> NodeId { *self .inner .get(&expr_id) - .unwrap_or_else(|| panic!("Could not find expr with id {expr_id} in subtree map")) + .unwrap_or_else(|| panic!("Could not find expr with id {expr_id:?} in subtree map")) } - fn contains_key(&self, expr_id: usize) -> bool { + fn contains_key(&self, expr_id: NodeId) -> bool { self.inner.contains_key(&expr_id) } - fn insert(&mut self, old_id: usize, new_id: usize) { + fn insert(&mut self, old_id: NodeId, new_id: NodeId) { self.inner.insert(old_id, new_id); } } @@ -111,15 +111,15 @@ impl ExecutionPlan { } #[must_use] - pub fn get_vtables(&self) -> Option<&HashMap<usize, Rc<VirtualTable>>> { + pub fn get_vtables(&self) -> Option<&HashMap<NodeId, Rc<VirtualTable>>> { self.vtables.as_ref().map(VirtualTableMap::map) } - pub fn get_mut_vtables(&mut self) -> Option<&mut HashMap<usize, Rc<VirtualTable>>> { + pub fn get_mut_vtables(&mut self) -> Option<&mut HashMap<NodeId, Rc<VirtualTable>>> { self.vtables.as_mut().map(VirtualTableMap::mut_map) } - pub fn set_vtables(&mut self, vtables: HashMap<usize, Rc<VirtualTable>>) { + pub fn set_vtables(&mut self, vtables: HashMap<NodeId, Rc<VirtualTable>>) { self.vtables = Some(VirtualTableMap::new(vtables)); } @@ -127,7 +127,7 @@ impl ExecutionPlan { /// /// # Errors /// - Failed to find a virtual table for the motion node. - pub fn get_motion_vtable(&self, motion_id: usize) -> Result<Rc<VirtualTable>, SbroadError> { + pub fn get_motion_vtable(&self, motion_id: NodeId) -> Result<Rc<VirtualTable>, SbroadError> { if let Some(vtable) = self.get_vtables() { if let Some(result) = vtable.get(&motion_id) { return Ok(Rc::clone(result)); @@ -138,7 +138,7 @@ impl ExecutionPlan { Err(SbroadError::NotFound( Entity::VirtualTable, format_smolstr!( - "for Motion node ({motion_id}): {motion_node:?}. Plan: {:?}", + "for Motion node ({motion_id:?}): {motion_node:?}. Plan: {:?}", self ), )) @@ -151,13 +151,13 @@ impl ExecutionPlan { #[otm_child_span("query.motion.add")] pub fn set_motion_vtable( &mut self, - motion_id: usize, + motion_id: &NodeId, vtable: VirtualTable, runtime: &impl Vshard, ) -> Result<(), SbroadError> { let mut vtable = vtable; let program_len = if let Relational::Motion { program, .. } = - self.get_ir_plan().get_relation_node(motion_id)? + self.get_ir_plan().get_relation_node(*motion_id)? { program.0.len() } else { @@ -168,7 +168,7 @@ impl ExecutionPlan { }; for op_idx in 0..program_len { let plan = self.get_ir_plan(); - let opcode = plan.get_motion_opcode(motion_id, op_idx)?; + let opcode = plan.get_motion_opcode(*motion_id, op_idx)?; match opcode { MotionOpcode::RemoveDuplicates => { vtable.remove_duplicates(); @@ -177,7 +177,7 @@ impl ExecutionPlan { // Resharding must be done before applying projection // to the virtual table. Otherwise projection can // remove sharding columns. - match plan.get_motion_policy(motion_id)? { + match plan.get_motion_policy(*motion_id)? { MotionPolicy::Segment(shard_key) | MotionPolicy::LocalSegment(shard_key) => { vtable.reshard(shard_key, runtime)?; @@ -213,7 +213,7 @@ impl ExecutionPlan { }; let Some(from_vtable) = vtables.map().get(&motion_id) else { return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!( - "expected virtual table for motion {motion_id}" + "expected virtual table for motion {motion_id:?}" ))); }; vtable.add_missing_rows(from_vtable)?; @@ -228,7 +228,7 @@ impl ExecutionPlan { } if let Some(vtables) = self.get_mut_vtables() { - vtables.insert(motion_id, Rc::new(vtable)); + vtables.insert(*motion_id, Rc::new(vtable)); } Ok(()) @@ -272,7 +272,7 @@ impl ExecutionPlan { /// # Errors /// - node is not `Relation` type /// - node is not `Motion` type - pub fn get_motion_policy(&self, node_id: usize) -> Result<MotionPolicy, SbroadError> { + pub fn get_motion_policy(&self, node_id: NodeId) -> Result<MotionPolicy, SbroadError> { if let Relational::Motion { policy, .. } = &self.plan.get_relation_node(node_id)? { return Ok(policy.clone()); } @@ -287,7 +287,7 @@ impl ExecutionPlan { /// /// # Errors /// - node is not valid - pub fn get_motion_alias(&self, node_id: usize) -> Result<Option<SmolStr>, SbroadError> { + pub fn get_motion_alias(&self, node_id: NodeId) -> Result<Option<SmolStr>, SbroadError> { let child_id = &self.get_motion_child(node_id)?; let child_rel = self.get_ir_plan().get_relation_node(*child_id)?; match child_rel { @@ -301,7 +301,7 @@ impl ExecutionPlan { /// /// # Errors /// - node is not valid - pub fn get_motion_subtree_root(&self, node_id: usize) -> Result<usize, SbroadError> { + pub fn get_motion_subtree_root(&self, node_id: NodeId) -> Result<NodeId, SbroadError> { let top_id = &self.get_motion_child(node_id)?; let rel = self.get_ir_plan().get_relation_node(*top_id)?; match rel { @@ -337,12 +337,12 @@ impl ExecutionPlan { /// # Errors /// - node is not `Relation` type /// - node does not contain children - pub(crate) fn get_motion_child(&self, node_id: usize) -> Result<usize, SbroadError> { + pub(crate) fn get_motion_child(&self, node_id: NodeId) -> Result<NodeId, SbroadError> { let node = self.get_ir_plan().get_relation_node(node_id)?; if !node.is_motion() { return Err(SbroadError::Invalid( Entity::Relational, - Some(format_smolstr!("current node ({node_id}) is not motion")), + Some(format_smolstr!("current node ({node_id:?}) is not motion")), )); } @@ -350,7 +350,7 @@ impl ExecutionPlan { assert!( children.len() == 1, - "Motion node ({node_id}:{node:?}) must have a single child only (actual {})", + "Motion node ({node_id:?}:{node:?}) must have a single child only (actual {})", children.len() ); @@ -366,7 +366,7 @@ impl ExecutionPlan { /// /// # Errors /// - not a motion node - pub fn unlink_motion_subtree(&mut self, motion_id: usize) -> Result<(), SbroadError> { + pub fn unlink_motion_subtree(&mut self, motion_id: NodeId) -> Result<(), SbroadError> { let motion = self.get_mut_ir_plan().get_mut_relation_node(motion_id)?; if let Relational::Motion { ref mut children, .. @@ -376,7 +376,7 @@ impl ExecutionPlan { } else { return Err(SbroadError::Invalid( Entity::Relational, - Some(format_smolstr!("node ({motion_id}) is not motion")), + Some(format_smolstr!("node ({motion_id:?}) is not motion")), )); } Ok(()) @@ -391,11 +391,11 @@ impl ExecutionPlan { /// # Panics /// - Plan is in invalid state #[allow(clippy::too_many_lines)] - pub fn take_subtree(&mut self, top_id: usize) -> Result<Self, SbroadError> { + pub fn take_subtree(&mut self, top_id: NodeId) -> Result<Self, SbroadError> { // Get the subtree nodes indexes. let plan = self.get_ir_plan(); let mut subtree = - PostOrder::with_capacity(|node| plan.exec_plan_subtree_iter(node), plan.next_id()); + PostOrder::with_capacity(|node| plan.exec_plan_subtree_iter(node), plan.nodes.len()); subtree.populate_nodes(top_id); let nodes = subtree.take_nodes(); @@ -404,7 +404,7 @@ impl ExecutionPlan { // as a set to avoid their removal. let cte_scans = nodes .iter() - .map(|(_, id)| *id) + .map(|LevelNode(_, id)| *id) .filter(|id| { matches!( plan.get_node(*id), @@ -424,9 +424,11 @@ impl ExecutionPlan { unreachable!("Expected CTE scan node."); }; let child_id = *child; - if all_cte_nodes_capacity < child_id { - all_cte_nodes_capacity = child_id; + let offset = usize::try_from(child_id.offset).unwrap(); + if all_cte_nodes_capacity < offset { + all_cte_nodes_capacity = offset; } + cte_amount += 1; } all_cte_nodes_capacity += 1; @@ -436,7 +438,7 @@ impl ExecutionPlan { all_cte_nodes_capacity / cte_amount * 2 }; - let mut cte_ids: AHashSet<usize> = AHashSet::new(); + let mut cte_ids: AHashSet<NodeId> = AHashSet::new(); let mut is_reserved = false; for cte_id in cte_scans { if !is_reserved { @@ -447,7 +449,7 @@ impl ExecutionPlan { |node| plan.exec_plan_subtree_iter(node), single_cte_capacity, ); - for (_, id) in cte_subtree.iter(cte_id) { + for LevelNode(_, id) in cte_subtree.iter(cte_id) { cte_ids.insert(id); } } @@ -455,12 +457,12 @@ impl ExecutionPlan { let mut subtree_map = SubtreeMap::with_capacity(nodes.len()); let vtables_capacity = self.get_vtables().map_or_else(|| 1, HashMap::len); // Map of { plan node_id -> virtual table }. - let mut new_vtables: HashMap<usize, Rc<VirtualTable>> = + let mut new_vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::with_capacity(vtables_capacity); let mut new_plan = Plan::new(); new_plan.nodes.reserve(nodes.len()); - for (_, node_id) in nodes { + for LevelNode(_, node_id) in nodes { // We have already processed this node (sub-queries in BETWEEN // and CTEs can be referred twice). if subtree_map.contains_key(node_id) { @@ -469,7 +471,7 @@ impl ExecutionPlan { // Node from original plan that we'll take and replace with mock parameter node. let dst_node = self.get_mut_ir_plan().get_mut_node(node_id)?; - let next_id = new_plan.nodes.next_id(); + let next_id = new_plan.nodes.next_id(ArenaType::Default); // Replace the node with some invalid value. // TODO: introduce some new enum variant for this purpose. @@ -534,7 +536,7 @@ impl ExecutionPlan { } } Relational::GroupBy { gr_cols, .. } => { - let mut new_cols: Vec<usize> = Vec::with_capacity(gr_cols.len()); + let mut new_cols: Vec<NodeId> = Vec::with_capacity(gr_cols.len()); for col_id in gr_cols.iter() { let new_col_id = subtree_map.get_id(*col_id); new_plan.replace_parent_in_subtree( diff --git a/sbroad-core/src/executor/protocol.rs b/sbroad-core/src/executor/protocol.rs index d635841c1..3905635d1 100644 --- a/sbroad-core/src/executor/protocol.rs +++ b/sbroad-core/src/executor/protocol.rs @@ -11,17 +11,18 @@ use crate::debug; use crate::errors::{Action, Entity, SbroadError}; use crate::executor::ir::{ExecutionPlan, QueryType}; use crate::ir::value::Value; +use crate::ir::Options; use crate::otm::{current_id, extract_context, inject_context}; use crate::executor::engine::TableVersionMap; -use crate::ir::{NodeId, Options}; +use crate::ir::expression::NodeId; #[cfg(not(feature = "mock"))] use opentelemetry::trace::TraceContextExt; use super::engine::helpers::vshard::CacheInfo; use super::vtable::VirtualTableMeta; -pub type VTablesMeta = HashMap<usize, VirtualTableMeta>; +pub type VTablesMeta = HashMap<NodeId, VirtualTableMeta>; #[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)] pub struct Binary(Vec<u8>); diff --git a/sbroad-core/src/executor/result.rs b/sbroad-core/src/executor/result.rs index bbc2d8f77..49a8bffa2 100644 --- a/sbroad-core/src/executor/result.rs +++ b/sbroad-core/src/executor/result.rs @@ -20,6 +20,7 @@ use tarantool::tuple::Encode; use crate::debug; use crate::errors::SbroadError; use crate::executor::vtable::{VTableTuple, VirtualTable}; +use crate::ir::expression::NodeId; use crate::ir::operator::Relational; use crate::ir::relation::{Column, ColumnRole, Type}; use crate::ir::tree::traversal::{PostOrderWithFilter, REL_CAPACITY}; @@ -257,8 +258,8 @@ impl Plan { /// /// # Errors /// - If relational iterator fails to return a correct node. - pub fn subtree_contains_values(&self, top_id: usize) -> Result<bool, SbroadError> { - let filter = |node_id: usize| -> bool { + pub fn subtree_contains_values(&self, top_id: NodeId) -> Result<bool, SbroadError> { + let filter = |node_id: NodeId| -> bool { if let Ok(Node::Relational(Relational::Values { .. })) = self.get_node(node_id) { return true; } diff --git a/sbroad-core/src/executor/tests.rs b/sbroad-core/src/executor/tests.rs index 4ceca6001..71f536340 100644 --- a/sbroad-core/src/executor/tests.rs +++ b/sbroad-core/src/executor/tests.rs @@ -1,6 +1,6 @@ use pretty_assertions::assert_eq; -use crate::backend::sql::ir::PatternWithParams; +use crate::{backend::sql::ir::PatternWithParams, ir::expression::NodeId}; use crate::executor::engine::mock::RouterRuntimeMock; use crate::executor::result::ProducerResult; @@ -914,7 +914,7 @@ fn virtual_table_23(alias: Option<&str>) -> VirtualTable { virtual_table } -fn get_motion_policy(plan: &Plan, motion_id: usize) -> &MotionPolicy { +fn get_motion_policy(plan: &Plan, motion_id: NodeId) -> &MotionPolicy { let motion = plan.get_relation_node(motion_id).unwrap(); if let Relational::Motion { policy, .. } = motion { policy diff --git a/sbroad-core/src/executor/tests/exec_plan.rs b/sbroad-core/src/executor/tests/exec_plan.rs index ecd8d0dfb..6234727e1 100644 --- a/sbroad-core/src/executor/tests/exec_plan.rs +++ b/sbroad-core/src/executor/tests/exec_plan.rs @@ -13,7 +13,7 @@ use crate::ir::relation::Type; use crate::ir::tests::{column_integer_user_non_null, column_user_non_null}; use crate::ir::transformation::redistribution::MotionPolicy; use crate::ir::tree::Snapshot; -use crate::ir::{Node, Slice}; +use crate::ir::{ArenaType, Node, Slice}; use super::*; @@ -30,7 +30,7 @@ fn f_sql(s: &str) -> String { /// Used for testing. fn get_sql_from_execution_plan( exec_plan: &mut ExecutionPlan, - top_id: usize, + top_id: NodeId, snapshot: Snapshot, name_base: &str, ) -> PatternWithParams { @@ -63,7 +63,7 @@ fn exec_plan_subtree_test() { { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -116,7 +116,7 @@ fn exec_plan_subtree_two_stage_groupby_test() { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -181,7 +181,7 @@ fn exec_plan_subtree_two_stage_groupby_test_2() { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -198,12 +198,11 @@ fn exec_plan_subtree_two_stage_groupby_test_2() { assert_eq!( sql, PatternWithParams::new( - f_sql( - r#"SELECT "T1"."FIRST_NAME" as "column_12", -"T1"."sysFrom" as "column_14", -"T1"."sys_op" as "column_13" -FROM "test_space" as "T1" -GROUP BY "T1"."FIRST_NAME", "T1"."sys_op", "T1"."sysFrom""# + format!( + "{} {} {}", + r#"SELECT "T1"."FIRST_NAME" as "column_12", "T1"."sys_op" as "column_13","#, + r#""T1"."sysFrom" as "column_14" FROM "test_space" as "T1""#, + r#"GROUP BY "T1"."FIRST_NAME", "T1"."sys_op", "T1"."sysFrom""#, ), vec![] ) @@ -261,7 +260,7 @@ fn exec_plan_subtree_aggregates() { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -278,16 +277,14 @@ fn exec_plan_subtree_aggregates() { assert_eq!( sql, PatternWithParams::new( - f_sql( - r#"SELECT "T1"."sys_op" as "column_12", -("T1"."id") * ("T1"."sys_op") as "column_49", -"T1"."id" as "column_46", -group_concat ("T1"."FIRST_NAME", ?) as "group_concat_58", -count ("T1"."sysFrom") as "count_37", total ("T1"."id") as "total_64", -min ("T1"."id") as "min_67", count ("T1"."id") as "count_61", -max ("T1"."id") as "max_70", sum ("T1"."id") as "sum_42" -FROM "test_space" as "T1" -GROUP BY "T1"."sys_op", ("T1"."id") * ("T1"."sys_op"), "T1"."id""# + format!( + "{} {} {} {} {} {}", + r#"SELECT ("T1"."id") * ("T1"."sys_op") as "column_49", "T1"."sys_op" as "column_12","#, + r#""T1"."id" as "column_46", group_concat ("T1"."FIRST_NAME", ?) as "group_concat_58", count ("T1"."sysFrom") as "count_37","#, + r#"total ("T1"."id") as "total_64","#, + r#"min ("T1"."id") as "min_67", count ("T1"."id") as "count_61", max ("T1"."id") as "max_70","#, + r#"sum ("T1"."id") as "sum_42" FROM "test_space" as "T1""#, + r#"GROUP BY "T1"."sys_op", ("T1"."id") * ("T1"."sys_op"), "T1"."id""#, ), vec![Value::from("o")] ) @@ -336,7 +333,7 @@ fn exec_plan_subtree_aggregates_no_groupby() { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -392,7 +389,7 @@ fn exec_plan_subquery_under_motion_without_alias() { { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -433,7 +430,7 @@ fn exec_plan_subquery_under_motion_with_alias() { { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -468,7 +465,7 @@ fn exec_plan_motion_under_in_operator() { { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -507,7 +504,7 @@ fn exec_plan_motion_under_except() { { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -544,7 +541,7 @@ fn exec_plan_subtree_count_asterisk() { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -607,7 +604,7 @@ fn exec_plan_subtree_having() { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -631,7 +628,7 @@ fn exec_plan_subtree_having() { PatternWithParams::new( format!( "{} {} {}", - r#"SELECT "T1"."sys_op" as "column_12", ("T1"."sys_op") * (?) as "column_64","#, + r#"SELECT ("T1"."sys_op") * (?) as "column_64", "T1"."sys_op" as "column_12","#, r#"count (("T1"."sys_op") * (?)) as "count_60" FROM "test_space" as "T1""#, r#"GROUP BY "T1"."sys_op", ("T1"."sys_op") * (?)"#, ), @@ -689,7 +686,7 @@ fn exec_plan_subtree_having_without_groupby() { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); @@ -837,7 +834,7 @@ fn global_union_all2() { virtual_table.add_tuple(vec![Value::Integer(1)]); let exec_plan = query.get_mut_exec_plan(); exec_plan - .set_motion_vtable(motion_id, virtual_table.clone(), &coordinator) + .set_motion_vtable(&motion_id, virtual_table.clone(), &coordinator) .unwrap(); let top_id = exec_plan.get_ir_plan().get_top().unwrap(); @@ -863,6 +860,10 @@ fn global_union_all2() { .unwrap(); let actual_dispatch = coordinator.detailed_dispatch(sub_plan, &buckets); + let motion_id = NodeId { + offset: motion_id as u32, + arena_type: ArenaType::Default, + }; let expected = vec![ ReplicasetDispatchInfo { @@ -918,7 +919,7 @@ fn global_union_all3() { sq_vtable.add_tuple(vec![Value::Integer(1)]); query .exec_plan - .set_motion_vtable(sq_motion_id, sq_vtable.clone(), &coordinator) + .set_motion_vtable(&sq_motion_id, sq_vtable.clone(), &coordinator) .unwrap(); let groupby_motion_id = *slices.slice(1).unwrap().position(0).unwrap(); @@ -942,7 +943,7 @@ fn global_union_all3() { } query .exec_plan - .set_motion_vtable(groupby_motion_id, groupby_vtable.clone(), &coordinator) + .set_motion_vtable(&groupby_motion_id, groupby_vtable.clone(), &coordinator) .unwrap(); let top_id = query.exec_plan.get_ir_plan().get_top().unwrap(); @@ -994,6 +995,16 @@ fn global_union_all3() { let actual_dispatch = coordinator.detailed_dispatch(sub_plan, &buckets); + let groupby_motion_id = NodeId { + offset: groupby_motion_id as u32, + arena_type: ArenaType::Default, + }; + + let sq_motion_id = NodeId { + offset: sq_motion_id as u32, + arena_type: ArenaType::Default, + }; + let expected = vec![ ReplicasetDispatchInfo { rs_id: 0, @@ -1096,7 +1107,7 @@ fn global_except() { virtual_table.add_tuple(vec![Value::Integer(1)]); query .get_mut_exec_plan() - .set_motion_vtable(intersect_motion_id, virtual_table.clone(), &coordinator) + .set_motion_vtable(&intersect_motion_id, virtual_table.clone(), &coordinator) .unwrap(); } @@ -1138,7 +1149,7 @@ fn exec_plan_order_by() { { virtual_table.reshard(key, &query.coordinator).unwrap(); } - let mut vtables: HashMap<usize, Rc<VirtualTable>> = HashMap::new(); + let mut vtables: HashMap<NodeId, Rc<VirtualTable>> = HashMap::new(); vtables.insert(motion_id, Rc::new(virtual_table)); let exec_plan = query.get_mut_exec_plan(); diff --git a/sbroad-core/src/executor/vtable.rs b/sbroad-core/src/executor/vtable.rs index c5cafa405..6a83ebe87 100644 --- a/sbroad-core/src/executor/vtable.rs +++ b/sbroad-core/src/executor/vtable.rs @@ -13,6 +13,7 @@ use crate::errors::{Entity, SbroadError}; use crate::executor::engine::helpers::{TupleBuilderCommand, TupleBuilderPattern}; use crate::executor::protocol::{Binary, EncodedRows, EncodedTables}; use crate::executor::{bucket::Buckets, Vshard}; +use crate::ir::expression::NodeId; use crate::ir::helpers::RepeatableState; use crate::ir::relation::Column; use crate::ir::transformation::redistribution::{ColumnPosition, MotionKey, Target}; @@ -686,20 +687,20 @@ impl ExecutionPlan { } #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] -pub struct VirtualTableMap(HashMap<usize, Rc<VirtualTable>>); +pub struct VirtualTableMap(HashMap<NodeId, Rc<VirtualTable>>); impl VirtualTableMap { #[must_use] - pub fn new(map: HashMap<usize, Rc<VirtualTable>>) -> Self { + pub fn new(map: HashMap<NodeId, Rc<VirtualTable>>) -> Self { Self(map) } #[must_use] - pub fn map(&self) -> &HashMap<usize, Rc<VirtualTable>> { + pub fn map(&self) -> &HashMap<NodeId, Rc<VirtualTable>> { &self.0 } - pub fn mut_map(&mut self) -> &mut HashMap<usize, Rc<VirtualTable>> { + pub fn mut_map(&mut self) -> &mut HashMap<NodeId, Rc<VirtualTable>> { &mut self.0 } } diff --git a/sbroad-core/src/frontend/sql.rs b/sbroad-core/src/frontend/sql.rs index 90ad8e6ef..337ac62aa 100644 --- a/sbroad-core/src/frontend/sql.rs +++ b/sbroad-core/src/frontend/sql.rs @@ -31,7 +31,7 @@ use crate::ir::ddl::{Language, ParamDef}; use crate::ir::expression::cast::Type as CastType; use crate::ir::expression::{ ColumnPositionMap, ColumnWithScan, ColumnsRetrievalSpec, Expression, ExpressionId, - FunctionFeature, Position, TrimKind, + FunctionFeature, NodeId, Position, TrimKind, }; use crate::ir::operator::{ Arithmetic, Bool, ConflictStrategy, JoinKind, OrderByElement, OrderByEntity, OrderByType, @@ -40,7 +40,7 @@ use crate::ir::operator::{ use crate::ir::relation::{Column, ColumnRole, TableKind, Type as RelationType}; use crate::ir::tree::traversal::{PostOrder, EXPR_CAPACITY}; use crate::ir::value::Value; -use crate::ir::{Node, NodeId, OptionKind, OptionParamValue, OptionSpec, Plan}; +use crate::ir::{Node, OptionKind, OptionParamValue, OptionSpec, Plan}; use crate::otm::child_span; use crate::errors::Entity::AST; @@ -75,13 +75,13 @@ fn get_default_auth_method() -> SmolStr { /// `left >= center AND left <= right`. struct Between { /// Left node id. - left_id: usize, + left_id: NodeId, /// Less or equal node id (`left <= right`) - less_eq_id: usize, + less_eq_id: NodeId, } impl Between { - fn new(left_id: usize, less_eq_id: usize) -> Self { + fn new(left_id: NodeId, less_eq_id: NodeId) -> Self { Self { left_id, less_eq_id, @@ -962,7 +962,7 @@ fn parse_select_statement( node_id: usize, map: &mut Translation, plan: &mut Plan, -) -> Result<usize, SbroadError> { +) -> Result<NodeId, SbroadError> { let node = ast.nodes.get_node(node_id)?; assert_eq!(node.rule, Rule::SelectStatement); let mut top_id = None; @@ -1227,7 +1227,7 @@ fn parse_grant_revoke( fn parse_trim<M: Metadata>( pair: Pair<Rule>, - referred_relation_ids: &[usize], + referred_relation_ids: &[NodeId], worker: &mut ExpressionsWorker<M>, plan: &mut Plan, ) -> Result<ParseExpression, SbroadError> { @@ -1424,7 +1424,7 @@ fn parse_param<M: Metadata>( param: &ParameterSource, worker: &mut ExpressionsWorker<M>, plan: &mut Plan, -) -> Result<usize, SbroadError> { +) -> Result<NodeId, SbroadError> { let param_index = param.get_param_index()?; let parameter = match param_index { None => { @@ -1504,14 +1504,14 @@ struct ExpressionsWorker<'worker, M> where M: Metadata, { - subquery_ids_queue: VecDeque<usize>, + subquery_ids_queue: VecDeque<NodeId>, betweens: Vec<Between>, metadata: &'worker M, /// Map of { reference plan_id -> (it's column name, whether it's covered with row)} /// We have to save column name in order to use it later for alias creation. /// We use information about row coverage later when handling Row expression and need to know /// whether we should uncover our reference. - pub reference_to_name_map: HashMap<usize, (SmolStr, bool)>, + pub reference_to_name_map: HashMap<NodeId, (SmolStr, bool)>, /// Flag indicating whether parameter in Tarantool (? mark) style was met. met_tnt_param: bool, /// Flag indicating whether parameter in Postgres ($<index>) style was met. @@ -1519,7 +1519,7 @@ where /// Map of (relational_node_id, columns_position_map). /// As `ColumnPositionMap` is used for parsing references and as it may be shared for the same /// relational node we cache it so that we don't have to recreate it every time. - column_positions_cache: HashMap<usize, ColumnPositionMap>, + column_positions_cache: HashMap<NodeId, ColumnPositionMap>, /// Time at the start of the plan building stage without timezone. /// It is used to replace CURRENT_DATE to actual value. current_time: OffsetDateTime, @@ -1542,7 +1542,7 @@ where } } - fn build_columns_map(&mut self, plan: &Plan, rel_id: usize) -> Result<(), SbroadError> { + fn build_columns_map(&mut self, plan: &Plan, rel_id: NodeId) -> Result<(), SbroadError> { if self.column_positions_cache.get(&rel_id).is_none() { let new_map = ColumnPositionMap::new(plan, rel_id)?; self.column_positions_cache.insert(rel_id, new_map); @@ -1552,7 +1552,7 @@ where fn columns_map_get_positions( &self, - rel_id: usize, + rel_id: NodeId, col_name: &str, scan_name: Option<&str>, ) -> Result<Position, SbroadError> { @@ -1579,7 +1579,7 @@ enum ParseExpressionInfixOperator { #[derive(Clone, Debug)] enum ParseExpression { PlanId { - plan_id: usize, + plan_id: NodeId, }, Parentheses { child: Box<ParseExpression>, @@ -1660,7 +1660,7 @@ pub enum SelectOp { #[derive(Clone)] pub enum SelectExpr { PlanId { - plan_id: usize, + plan_id: NodeId, }, Infix { op: SelectOp, @@ -1670,7 +1670,7 @@ pub enum SelectExpr { } impl SelectExpr { - fn populate_plan(&self, plan: &mut Plan) -> Result<usize, SbroadError> { + fn populate_plan(&self, plan: &mut Plan) -> Result<NodeId, SbroadError> { match self { SelectExpr::PlanId { plan_id } => Ok(*plan_id), SelectExpr::Infix { op, left, right } => { @@ -1697,7 +1697,7 @@ impl ParseExpression { &self, plan: &mut Plan, worker: &mut ExpressionsWorker<M>, - ) -> Result<usize, SbroadError> + ) -> Result<NodeId, SbroadError> where M: Metadata, { @@ -1749,7 +1749,7 @@ impl ParseExpression { (res.populate_plan(plan, worker)?), )) }) - .collect::<Result<Vec<(usize, usize)>, SbroadError>>()?; + .collect::<Result<Vec<(NodeId, NodeId)>, SbroadError>>()?; let else_expr_id = if let Some(else_expr) = else_expr { Some(else_expr.populate_plan(plan, worker)?) } else { @@ -2074,7 +2074,7 @@ fn cast_type_from_pair(type_pair: Pair<Rule>) -> Result<CastType, SbroadError> { #[allow(clippy::too_many_lines)] fn parse_expr_pratt<M>( expression_pairs: Pairs<Rule>, - referred_relation_ids: &[usize], + referred_relation_ids: &[NodeId], worker: &mut ExpressionsWorker<M>, plan: &mut Plan, ) -> Result<ParseExpression, SbroadError> @@ -2556,10 +2556,10 @@ fn parse_select_pratt( /// * Return `plan_id` of root Expression node fn parse_expr<M>( expression_pairs: Pairs<Rule>, - referred_relation_ids: &[usize], + referred_relation_ids: &[NodeId], worker: &mut ExpressionsWorker<M>, plan: &mut Plan, -) -> Result<usize, SbroadError> +) -> Result<NodeId, SbroadError> where M: Metadata, { @@ -2572,7 +2572,7 @@ fn parse_select( pos_to_ast_id: &SelectChildPairTranslation, ast_to_plan: &Translation, plan: &mut Plan, -) -> Result<usize, SbroadError> { +) -> Result<NodeId, SbroadError> { let select_expr = parse_select_pratt(select_pairs, pos_to_ast_id, ast_to_plan)?; select_expr.populate_plan(plan) } @@ -2769,7 +2769,8 @@ impl AbstractSyntaxTree { let mut expr_tree = PostOrder::with_capacity(|node| plan.nodes.expr_iter(node, false), EXPR_CAPACITY); let mut reference_met = false; - for (_, node_id) in expr_tree.iter(expr_plan_node_id) { + for level_node in expr_tree.iter(expr_plan_node_id) { + let node_id = level_node.1; if let Expression::Reference { .. } = plan.get_expression_node(node_id)? { reference_met = true; break; @@ -2848,7 +2849,8 @@ impl AbstractSyntaxTree { let mut worker = ExpressionsWorker::new(metadata); let mut ctes = CTEs::new(); - for (_, id) in dft_post.iter(top) { + for level_node in dft_post.iter(top) { + let id = level_node.1; let node = self.nodes.get_node(id)?; match &node.rule { Rule::Scan => { @@ -2936,7 +2938,7 @@ impl AbstractSyntaxTree { } Rule::GroupBy => { // Reminder: first GroupBy child in `node.children` is always a relational node. - let mut children: Vec<usize> = Vec::with_capacity(node.children.len()); + let mut children: Vec<NodeId> = Vec::with_capacity(node.children.len()); let first_relational_child_ast_id = node.children.first().expect("GroupBy has no children"); let first_relational_child_plan_id = map.get(*first_relational_child_ast_id)?; @@ -3068,7 +3070,7 @@ impl AbstractSyntaxTree { } let plan_rel_child_id = map.get(*rel_child_id)?; - let mut proj_columns: Vec<usize> = Vec::with_capacity(ast_columns_ids.len()); + let mut proj_columns: Vec<NodeId> = Vec::with_capacity(ast_columns_ids.len()); let mut unnamed_col_pos = 0; for ast_column_id in ast_columns_ids { @@ -3151,7 +3153,7 @@ impl AbstractSyntaxTree { map.add(id, projection_id); } Rule::Values => { - let mut plan_value_row_ids: Vec<usize> = + let mut plan_value_row_ids: Vec<NodeId> = Vec::with_capacity(node.children.len()); for ast_child_id in &node.children { let row_pair = pairs_map.remove_pair(*ast_child_id); @@ -3832,7 +3834,7 @@ impl Plan { /// Leave other nodes (e.g. rows) unchanged. /// /// Used for unification of expression nodes transformations (e.g. dnf). - fn row(&mut self, expr_id: usize) -> Result<usize, SbroadError> { + fn row(&mut self, expr_id: NodeId) -> Result<NodeId, SbroadError> { let row_id = if let Node::Expression( Expression::Reference { .. } | Expression::Constant { .. } diff --git a/sbroad-core/src/frontend/sql/ir.rs b/sbroad-core/src/frontend/sql/ir.rs index 284e966c0..9f437ddfa 100644 --- a/sbroad-core/src/frontend/sql/ir.rs +++ b/sbroad-core/src/frontend/sql/ir.rs @@ -7,14 +7,14 @@ use tarantool::decimal::Decimal; use crate::errors::{Action, Entity, SbroadError}; use crate::frontend::sql::ast::Rule; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::helpers::RepeatableState; use crate::ir::operator::{OrderByElement, OrderByEntity, Relational}; use crate::ir::transformation::redistribution::MotionOpcode; -use crate::ir::tree::traversal::{PostOrder, EXPR_CAPACITY}; +use crate::ir::tree::traversal::{LevelNode, PostOrder, EXPR_CAPACITY}; use crate::ir::value::double::Double; use crate::ir::value::Value; -use crate::ir::{Node, NodeId, Plan}; +use crate::ir::{ArenaType, Node, Plan}; use super::Between; @@ -82,7 +82,7 @@ impl Value { #[derive(Debug)] /// Helper struct representing map of { `ParseNode` id -> `Node` id } pub(super) struct Translation { - map: HashMap<usize, usize>, + map: HashMap<usize, NodeId>, } impl Translation { @@ -92,11 +92,11 @@ impl Translation { } } - pub(super) fn add(&mut self, parse_id: usize, plan_id: usize) { + pub(super) fn add(&mut self, parse_id: usize, plan_id: NodeId) { self.map.insert(parse_id, plan_id); } - pub(super) fn get(&self, old: usize) -> Result<usize, SbroadError> { + pub(super) fn get(&self, old: usize) -> Result<NodeId, SbroadError> { self.map.get(&old).copied().ok_or_else(|| { SbroadError::NotFound( Entity::Node, @@ -111,17 +111,17 @@ impl Translation { struct SubQuery { /// Relational operator that is a parent of current SubQuery. /// E.g. Selection (in case SubQuery is met in WHERE expression). - relational: usize, + relational: NodeId, /// Expression operator in which this SubQuery is met. /// E.g. `Exists`. - operator: usize, + operator: NodeId, /// SubQuery id in plan. - sq: usize, + sq: NodeId, } impl Eq for SubQuery {} impl SubQuery { - fn new(relational: usize, operator: usize, sq: usize) -> SubQuery { + fn new(relational: NodeId, operator: NodeId, sq: NodeId) -> SubQuery { SubQuery { relational, operator, @@ -142,20 +142,20 @@ impl CloneExprSubtreeMap { } } - fn insert(&mut self, old_id: usize, new_id: usize) { + fn insert(&mut self, old_id: NodeId, new_id: NodeId) { self.inner.insert(old_id, new_id); } - fn replace(&self, id: &mut usize) { + fn replace(&self, id: &mut NodeId) { let new_id = self.get(*id); *id = new_id; } - fn get(&self, id: usize) -> usize { + fn get(&self, id: NodeId) -> NodeId { *self .inner .get(&id) - .unwrap_or_else(|| panic!("Node with id {id} not found in the cloning subtree map.")) + .unwrap_or_else(|| panic!("Node with id {id:?} not found in the cloning subtree map.")) } } @@ -164,7 +164,7 @@ impl Plan { let mut set: HashSet<SubQuery, RepeatableState> = HashSet::with_hasher(RepeatableState); // Traverse expression trees of the selection and join nodes. // Gather all sub-queries in the boolean expressions there. - for (relational_id, node) in self.nodes.iter().enumerate() { + for (offset, node) in self.nodes.iter().enumerate() { match node { Node::Relational( Relational::Selection { filter: tree, .. } @@ -178,7 +178,12 @@ impl Plan { |node| self.nodes.expr_iter(node, false), capacity, ); - for (_, op_id) in expr_post.iter(*tree) { + let relational_id = NodeId { + offset: u32::try_from(offset).unwrap(), + arena_type: ArenaType::Default, + }; + for level_node in expr_post.iter(*tree) { + let op_id = level_node.1; let expression_node = self.get_node(op_id)?; if let Node::Expression(Expression::Bool { left, right, .. }) = expression_node @@ -211,9 +216,9 @@ impl Plan { /// Replace sub-queries with references to the sub-query. pub(super) fn replace_sq_with_references( &mut self, - ) -> Result<AHashMap<usize, usize>, SbroadError> { + ) -> Result<AHashMap<NodeId, NodeId>, SbroadError> { let set = self.gather_sq_for_replacement()?; - let mut replaces: AHashMap<usize, usize> = AHashMap::with_capacity(set.len()); + let mut replaces: AHashMap<NodeId, NodeId> = AHashMap::with_capacity(set.len()); for sq in set { // Append sub-query to relational node if it is not already there (can happen with BETWEEN). match self.get_mut_node(sq.relational)? { @@ -298,10 +303,10 @@ impl Plan { pub(super) fn fix_betweens( &mut self, betweens: &[Between], - replaces: &AHashMap<usize, usize>, + replaces: &AHashMap<NodeId, NodeId>, ) -> Result<(), SbroadError> { for between in betweens { - let left_id: usize = if let Some(id) = replaces.get(&between.left_id) { + let left_id: NodeId = if let Some(id) = replaces.get(&between.left_id) { self.clone_expr_subtree(*id)? } else { self.clone_expr_subtree(between.left_id)? @@ -319,14 +324,15 @@ impl Plan { Ok(()) } - pub(crate) fn clone_expr_subtree(&mut self, top_id: usize) -> Result<usize, SbroadError> { + pub(crate) fn clone_expr_subtree(&mut self, top_id: NodeId) -> Result<NodeId, SbroadError> { let mut subtree = PostOrder::with_capacity(|node| self.nodes.expr_iter(node, false), EXPR_CAPACITY); subtree.populate_nodes(top_id); let nodes = subtree.take_nodes(); let mut map = CloneExprSubtreeMap::with_capacity(nodes.len()); - for (_, id) in nodes { - let next_id = self.nodes.next_id(); + let mut expr_id = NodeId::default(); + for LevelNode(_, id) in nodes { + let next_id = self.nodes.next_id(ArenaType::Default); let mut expr = self.get_expression_node(id)?.clone(); match expr { Expression::Constant { .. } @@ -392,18 +398,18 @@ impl Plan { } } } - self.nodes.push(Node::Expression(expr)); + expr_id = self.nodes.push(Node::Expression(expr)); map.insert(id, next_id); } - Ok(self.nodes.next_id() - 1) + Ok(expr_id) } } /// Helper struct to clone plan's subtree. /// Assumes that all parameters are bound. pub struct SubtreeCloner { - old_new: AHashMap<usize, usize>, - nodes_with_backward_references: Vec<usize>, + old_new: AHashMap<NodeId, NodeId>, + nodes_with_backward_references: Vec<NodeId>, } impl SubtreeCloner { @@ -414,19 +420,19 @@ impl SubtreeCloner { } } - fn get_new_id(&self, old_id: usize) -> Result<usize, SbroadError> { + fn get_new_id(&self, old_id: NodeId) -> Result<NodeId, SbroadError> { self.old_new .get(&old_id) .ok_or_else(|| { SbroadError::Invalid( Entity::Plan, - Some(format_smolstr!("new node not found for old id: {old_id}")), + Some(format_smolstr!("new node not found for old id: {old_id:?}")), ) }) .copied() } - fn copy_list(&self, list: &[usize]) -> Result<Vec<usize>, SbroadError> { + fn copy_list(&self, list: &[NodeId]) -> Result<Vec<NodeId>, SbroadError> { let mut new_list = Vec::with_capacity(list.len()); for id in list { new_list.push(self.get_new_id(*id)?); @@ -525,7 +531,7 @@ impl SubtreeCloner { fn clone_relational( &mut self, old_relational: &Relational, - id: usize, + id: NodeId, ) -> Result<Relational, SbroadError> { let mut copied = old_relational.clone(); @@ -737,14 +743,15 @@ impl SubtreeCloner { fn clone( &mut self, plan: &mut Plan, - top_id: usize, + top_id: NodeId, capacity: usize, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let mut dfs = PostOrder::with_capacity(|x| plan.subtree_iter(x, true), capacity); dfs.populate_nodes(top_id); let nodes = dfs.take_nodes(); drop(dfs); - for (_, id) in nodes { + for level_node in nodes { + let id = level_node.1; let node = plan.get_node(id)?; let new_node = match node { Node::Relational(rel) => Node::Relational(self.clone_relational(rel, id)?), @@ -753,7 +760,7 @@ impl SubtreeCloner { return Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "clone: expected relational or expression on id: {id}" + "clone: expected relational or expression on id: {id:?}" )), )) } @@ -764,7 +771,7 @@ impl SubtreeCloner { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "clone: node with id {id} was mapped twice: {old_new_id}, {new_id}" + "clone: node with id {id:?} was mapped twice: {old_new_id:?}, {new_id:?}" )), )); } @@ -779,7 +786,7 @@ impl SubtreeCloner { SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "invalid subtree traversal with top: {top_id}" + "invalid subtree traversal with top: {top_id:?}" )), ) }) @@ -796,9 +803,9 @@ impl SubtreeCloner { /// - parameters/ddl/acl nodes are found in subtree pub fn clone_subtree( plan: &mut Plan, - top_id: usize, + top_id: NodeId, subtree_capacity: usize, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let mut helper = Self::new(subtree_capacity); helper.clone(plan, top_id, subtree_capacity) } diff --git a/sbroad-core/src/frontend/sql/ir/tests.rs b/sbroad-core/src/frontend/sql/ir/tests.rs index 1122ef67f..a4a43cf03 100644 --- a/sbroad-core/src/frontend/sql/ir/tests.rs +++ b/sbroad-core/src/frontend/sql/ir/tests.rs @@ -1,6 +1,7 @@ use crate::errors::SbroadError; use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::frontend::Ast; +use crate::ir::expression::NodeId; use crate::ir::operator::Relational; use crate::ir::transformation::helpers::{sql_to_ir, sql_to_optimized_ir}; use crate::ir::tree::traversal::PostOrder; @@ -940,7 +941,7 @@ vtable_max_rows = 5000 } impl Plan { - fn get_positions(&self, node_id: usize) -> Option<Positions> { + fn get_positions(&self, node_id: NodeId) -> Option<Positions> { let mut context = self.context_mut(); context .get_shard_columns_positions(node_id, self) @@ -959,7 +960,8 @@ fn track_shard_col_pos() { let plan = sql_to_optimized_ir(input, vec![]); let top = plan.get_top().unwrap(); let mut dfs = PostOrder::with_capacity(|x| plan.nodes.rel_iter(x), 10); - for (_, node_id) in dfs.iter(top) { + for level_node in dfs.iter(top) { + let node_id = level_node.1; let node = plan.get_relation_node(node_id).unwrap(); match node { Relational::ScanRelation { .. } | Relational::Selection { .. } => { @@ -980,7 +982,8 @@ fn track_shard_col_pos() { let plan = sql_to_optimized_ir(input, vec![]); let top = plan.get_top().unwrap(); let mut dfs = PostOrder::with_capacity(|x| plan.nodes.rel_iter(x), 10); - for (_, node_id) in dfs.iter(top) { + for level_node in dfs.iter(top) { + let node_id = level_node.1; let node = plan.get_relation_node(node_id).unwrap(); if let Relational::Join { .. } = node { assert_eq!( @@ -1002,7 +1005,8 @@ fn track_shard_col_pos() { let plan = sql_to_optimized_ir(input, vec![]); let top = plan.get_top().unwrap(); let mut dfs = PostOrder::with_capacity(|x| plan.nodes.rel_iter(x), 10); - for (_, node_id) in dfs.iter(top) { + for level_node in dfs.iter(top) { + let node_id = level_node.1; let node = plan.get_relation_node(node_id).unwrap(); if let Relational::Join { .. } = node { assert_eq!([Some(4_usize), None], plan.get_positions(node_id).unwrap()); @@ -1378,10 +1382,10 @@ fn front_sql_groupby_join_1() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( r#"projection ("column_63"::string -> "product_code", "column_64"::boolean -> "product_units") - group by ("column_63"::string, "column_64"::boolean) output: ("column_64"::boolean -> "column_64", "column_63"::string -> "column_63") + group by ("column_63"::string, "column_64"::boolean) output: ("column_63"::string -> "column_63", "column_64"::boolean -> "column_64") motion [policy: segment([ref("column_63"), ref("column_64")])] scan - projection ("t2"."product_units"::boolean -> "column_64", "t2"."product_code"::string -> "column_63") + projection ("t2"."product_code"::string -> "column_63", "t2"."product_units"::boolean -> "column_64") group by ("t2"."product_code"::string, "t2"."product_units"::boolean) output: ("t2"."product_units"::boolean -> "product_units", "t2"."product_code"::string -> "product_code", "t2"."identification_number"::integer -> "identification_number", "t"."id"::unsigned -> "id") join on ROW("t2"."identification_number"::integer) = ROW("t"."id"::unsigned) scan "t2" @@ -1493,10 +1497,10 @@ fn front_sql_groupby_insert() { r#"insert "t" on conflict: fail motion [policy: segment([value(NULL), ref("d")])] projection ("column_12"::unsigned -> "b", "column_13"::unsigned -> "d") - group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_13"::unsigned -> "column_13") + group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12") motion [policy: segment([ref("column_13"), ref("column_12")])] scan - projection ("t"."b"::unsigned -> "column_12", "t"."d"::unsigned -> "column_13") + projection ("t"."d"::unsigned -> "column_13", "t"."b"::unsigned -> "column_12") group by ("t"."d"::unsigned, "t"."b"::unsigned) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" execution options: @@ -1808,10 +1812,10 @@ fn front_sql_aggregates_with_distinct2() { let expected_explain = String::from( r#"projection ("column_12"::unsigned -> "b", sum(distinct ("column_34"::decimal))::decimal -> "col_1") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_34"::unsigned -> "column_34") + group by ("column_12"::unsigned) output: ("column_34"::unsigned -> "column_34", "column_12"::unsigned -> "column_12") motion [policy: segment([ref("column_12")])] scan - projection ("t"."b"::unsigned -> "column_12", ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) + ROW(3::unsigned) -> "column_34") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) + ROW(3::unsigned) -> "column_34", "t"."b"::unsigned -> "column_12") group by ("t"."b"::unsigned, ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) + ROW(3::unsigned)) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" execution options: @@ -1820,7 +1824,7 @@ vtable_max_rows = 5000 "#, ); - assert_eq!(expected_explain, plan.as_explain().unwrap()); + assert_eq!(plan.as_explain().unwrap(), expected_explain); } #[test] @@ -2384,10 +2388,10 @@ fn front_sql_groupby_expression3() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( r#"projection ("column_16"::unsigned -> "col_1", "column_27"::unsigned * ROW(sum(("sum_59"::decimal))::decimal) / ROW(sum(("count_65"::integer))::decimal) -> "col_2") - group by ("column_16"::unsigned, "column_27"::unsigned) output: ("column_27"::unsigned -> "column_27", "column_16"::unsigned -> "column_16", "count_65"::integer -> "count_65", "sum_59"::decimal -> "sum_59") + group by ("column_16"::unsigned, "column_27"::unsigned) output: ("column_16"::unsigned -> "column_16", "column_27"::unsigned -> "column_27", "count_65"::integer -> "count_65", "sum_59"::decimal -> "sum_59") motion [policy: segment([ref("column_16"), ref("column_27")])] scan - projection ((ROW("t"."c"::unsigned) * ROW("t"."d"::unsigned)) -> "column_27", ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_16", count((ROW("t"."a"::unsigned) * ROW("t"."b"::unsigned)))::integer -> "count_65", sum((ROW("t"."c"::unsigned) * ROW("t"."d"::unsigned)))::decimal -> "sum_59") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_16", (ROW("t"."c"::unsigned) * ROW("t"."d"::unsigned)) -> "column_27", count((ROW("t"."a"::unsigned) * ROW("t"."b"::unsigned)))::integer -> "count_65", sum((ROW("t"."c"::unsigned) * ROW("t"."d"::unsigned)))::decimal -> "sum_59") group by (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned), (ROW("t"."c"::unsigned) * ROW("t"."d"::unsigned))) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" execution options: @@ -2408,10 +2412,10 @@ fn front_sql_groupby_expression4() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( r#"projection ("column_16"::unsigned -> "col_1", "column_17"::unsigned -> "a") - group by ("column_16"::unsigned, "column_17"::unsigned) output: ("column_17"::unsigned -> "column_17", "column_16"::unsigned -> "column_16") + group by ("column_16"::unsigned, "column_17"::unsigned) output: ("column_16"::unsigned -> "column_16", "column_17"::unsigned -> "column_17") motion [policy: segment([ref("column_16"), ref("column_17")])] scan - projection ("t"."a"::unsigned -> "column_17", ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_16") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_16", "t"."a"::unsigned -> "column_17") group by (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned), "t"."a"::unsigned) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" execution options: @@ -2437,19 +2441,19 @@ fn front_sql_groupby_with_aggregates() { join on ROW("t1"."a"::unsigned, "t2"."g"::unsigned) = ROW("t2"."e"::unsigned, "t1"."b"::unsigned) scan "t1" projection ("column_12"::unsigned -> "a", "column_13"::unsigned -> "b", sum(("sum_31"::decimal))::decimal -> "c") - group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_13"::unsigned -> "column_13", "sum_31"::decimal -> "sum_31") + group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12", "sum_31"::decimal -> "sum_31") motion [policy: segment([ref("column_13"), ref("column_12")])] scan - projection ("t"."a"::unsigned -> "column_12", "t"."b"::unsigned -> "column_13", sum(("t"."c"::unsigned))::decimal -> "sum_31") + projection ("t"."b"::unsigned -> "column_13", "t"."a"::unsigned -> "column_12", sum(("t"."c"::unsigned))::decimal -> "sum_31") group by ("t"."b"::unsigned, "t"."a"::unsigned) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" motion [policy: full] scan "t2" projection ("column_55"::unsigned -> "g", "column_56"::unsigned -> "e", sum(("sum_74"::decimal))::decimal -> "f") - group by ("column_55"::unsigned, "column_56"::unsigned) output: ("column_56"::unsigned -> "column_56", "column_55"::unsigned -> "column_55", "sum_74"::decimal -> "sum_74") + group by ("column_55"::unsigned, "column_56"::unsigned) output: ("column_55"::unsigned -> "column_55", "column_56"::unsigned -> "column_56", "sum_74"::decimal -> "sum_74") motion [policy: segment([ref("column_55"), ref("column_56")])] scan - projection ("t2"."e"::unsigned -> "column_56", "t2"."g"::unsigned -> "column_55", sum(("t2"."f"::unsigned))::decimal -> "sum_74") + projection ("t2"."g"::unsigned -> "column_55", "t2"."e"::unsigned -> "column_56", sum(("t2"."f"::unsigned))::decimal -> "sum_74") group by ("t2"."g"::unsigned, "t2"."e"::unsigned) output: ("t2"."e"::unsigned -> "e", "t2"."f"::unsigned -> "f", "t2"."g"::unsigned -> "g", "t2"."h"::unsigned -> "h", "t2"."bucket_id"::unsigned -> "bucket_id") scan "t2" execution options: @@ -2636,10 +2640,10 @@ fn front_sql_having1() { let expected_explain = String::from( r#"projection ("column_12"::unsigned -> "a", sum(("sum_52"::decimal))::decimal -> "col_1") having ROW("column_12"::unsigned) > ROW(1::unsigned) and ROW(sum(distinct ("column_27"::decimal))::decimal) > ROW(1::unsigned) - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_27"::unsigned -> "column_27", "sum_52"::decimal -> "sum_52") + group by ("column_12"::unsigned) output: ("column_27"::unsigned -> "column_27", "column_12"::unsigned -> "column_12", "sum_52"::decimal -> "sum_52") motion [policy: segment([ref("column_12")])] scan - projection ("t"."a"::unsigned -> "column_12", "t"."b"::unsigned -> "column_27", sum(("t"."b"::unsigned))::decimal -> "sum_52") + projection ("t"."b"::unsigned -> "column_27", "t"."a"::unsigned -> "column_12", sum(("t"."b"::unsigned))::decimal -> "sum_52") group by ("t"."a"::unsigned, "t"."b"::unsigned) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" execution options: @@ -2778,10 +2782,10 @@ fn front_sql_having_with_sq_segment_motion() { let expected_explain = String::from( r#"projection ("column_12"::unsigned -> "sysFrom", "column_13"::unsigned -> "sys_op", sum(distinct ("column_70"::decimal))::decimal -> "sum", count(distinct ("column_70"::integer))::integer -> "count") having ROW("column_12"::unsigned, "column_13"::unsigned) in ROW($0, $0) - group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_70"::unsigned -> "column_70", "column_13"::unsigned -> "column_13") + group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_70"::unsigned -> "column_70", "column_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12") motion [policy: segment([ref("column_13"), ref("column_12")])] scan - projection ("test_space"."sysFrom"::unsigned -> "column_12", "test_space"."id"::unsigned -> "column_70", "test_space"."sys_op"::unsigned -> "column_13") + projection ("test_space"."id"::unsigned -> "column_70", "test_space"."sys_op"::unsigned -> "column_13", "test_space"."sysFrom"::unsigned -> "column_12") group by ("test_space"."sys_op"::unsigned, "test_space"."sysFrom"::unsigned, "test_space"."id"::unsigned) output: ("test_space"."id"::unsigned -> "id", "test_space"."sysFrom"::unsigned -> "sysFrom", "test_space"."FIRST_NAME"::string -> "FIRST_NAME", "test_space"."sys_op"::unsigned -> "sys_op", "test_space"."bucket_id"::unsigned -> "bucket_id") scan "test_space" subquery $0: @@ -2814,10 +2818,10 @@ fn front_sql_having_with_sq_segment_local_motion() { let expected_explain = String::from( r#"projection ("column_12"::unsigned -> "sysFrom", "column_13"::unsigned -> "sys_op", sum(distinct ("column_70"::decimal))::decimal -> "sum", count(distinct ("column_70"::integer))::integer -> "count") having ROW("column_12"::unsigned, "column_13"::unsigned) in ROW($0, $0) - group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_70"::unsigned -> "column_70", "column_13"::unsigned -> "column_13") + group by ("column_13"::unsigned, "column_12"::unsigned) output: ("column_70"::unsigned -> "column_70", "column_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12") motion [policy: segment([ref("column_13"), ref("column_12")])] scan - projection ("test_space"."sysFrom"::unsigned -> "column_12", "test_space"."id"::unsigned -> "column_70", "test_space"."sys_op"::unsigned -> "column_13") + projection ("test_space"."id"::unsigned -> "column_70", "test_space"."sys_op"::unsigned -> "column_13", "test_space"."sysFrom"::unsigned -> "column_12") group by ("test_space"."sys_op"::unsigned, "test_space"."sysFrom"::unsigned, "test_space"."id"::unsigned) output: ("test_space"."id"::unsigned -> "id", "test_space"."sysFrom"::unsigned -> "sysFrom", "test_space"."FIRST_NAME"::string -> "FIRST_NAME", "test_space"."sys_op"::unsigned -> "sys_op", "test_space"."bucket_id"::unsigned -> "bucket_id") scan "test_space" subquery $0: @@ -2933,10 +2937,10 @@ fn front_sql_select_distinct() { // here we must compute only two groupby columns at local stage: a, b let expected_explain = String::from( r#"projection ("column_22"::unsigned -> "a", "column_27"::unsigned -> "col_1") - group by ("column_27"::unsigned, "column_22"::unsigned) output: ("column_22"::unsigned -> "column_22", "column_27"::unsigned -> "column_27") + group by ("column_27"::unsigned, "column_22"::unsigned) output: ("column_27"::unsigned -> "column_27", "column_22"::unsigned -> "column_22") motion [policy: segment([ref("column_27"), ref("column_22")])] scan - projection ("t"."a"::unsigned -> "column_22", ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_27") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_27", "t"."a"::unsigned -> "column_22") group by (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned), "t"."a"::unsigned) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" execution options: @@ -2956,10 +2960,10 @@ fn front_sql_select_distinct_asterisk() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( r#"projection ("column_23"::unsigned -> "a", "column_24"::unsigned -> "b", "column_25"::unsigned -> "c", "column_26"::unsigned -> "d") - group by ("column_24"::unsigned, "column_23"::unsigned, "column_25"::unsigned, "column_26"::unsigned) output: ("column_24"::unsigned -> "column_24", "column_23"::unsigned -> "column_23", "column_25"::unsigned -> "column_25", "column_26"::unsigned -> "column_26") + group by ("column_24"::unsigned, "column_23"::unsigned, "column_25"::unsigned, "column_26"::unsigned) output: ("column_23"::unsigned -> "column_23", "column_26"::unsigned -> "column_26", "column_25"::unsigned -> "column_25", "column_24"::unsigned -> "column_24") motion [policy: segment([ref("column_24"), ref("column_23"), ref("column_25"), ref("column_26")])] scan - projection ("t"."b"::unsigned -> "column_24", "t"."a"::unsigned -> "column_23", "t"."c"::unsigned -> "column_25", "t"."d"::unsigned -> "column_26") + projection ("t"."a"::unsigned -> "column_23", "t"."d"::unsigned -> "column_26", "t"."c"::unsigned -> "column_25", "t"."b"::unsigned -> "column_24") group by ("t"."b"::unsigned, "t"."a"::unsigned, "t"."c"::unsigned, "t"."d"::unsigned) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") scan "t" execution options: diff --git a/sbroad-core/src/frontend/sql/ir/tests/global.rs b/sbroad-core/src/frontend/sql/ir/tests/global.rs index a3d2f7aa6..e067aed43 100644 --- a/sbroad-core/src/frontend/sql/ir/tests/global.rs +++ b/sbroad-core/src/frontend/sql/ir/tests/global.rs @@ -1,7 +1,8 @@ use crate::ir::distribution::Distribution; +use crate::ir::expression::NodeId; use crate::ir::operator::Relational; use crate::ir::transformation::helpers::sql_to_optimized_ir; -use crate::ir::tree::traversal::{FilterFn, PostOrderWithFilter, REL_CAPACITY}; +use crate::ir::tree::traversal::{FilterFn, LevelNode, PostOrderWithFilter, REL_CAPACITY}; use crate::ir::value::Value; use crate::ir::{Node, Plan}; use pretty_assertions::assert_eq; @@ -25,7 +26,7 @@ impl From<&Distribution> for DistMock { } } -fn collect_relational(plan: &Plan, predicate: FilterFn<'_>) -> Vec<(usize, usize)> { +fn collect_relational(plan: &Plan, predicate: FilterFn<'_, NodeId>) -> Vec<LevelNode<NodeId>> { let mut rel_tree = PostOrderWithFilter::with_capacity( |node| plan.nodes.rel_iter(node), REL_CAPACITY, @@ -37,23 +38,29 @@ fn collect_relational(plan: &Plan, predicate: FilterFn<'_>) -> Vec<(usize, usize nodes } -fn check_distributions(plan: &Plan, nodes: &[(usize, usize)], expected_distributions: &[DistMock]) { +fn check_distributions( + plan: &Plan, + nodes: &[LevelNode<NodeId>], + expected_distributions: &[DistMock], +) { assert_eq!( expected_distributions.len(), nodes.len(), "different number of nodes" ); - for ((level, id), expected) in nodes.iter().zip(expected_distributions.iter()) { - let actual: DistMock = plan.get_rel_distribution(*id).unwrap().into(); + for (level_node, expected) in nodes.iter().zip(expected_distributions.iter()) { + let level = level_node.0; + let id = level_node.1; + let actual: DistMock = plan.get_rel_distribution(id).unwrap().into(); assert_eq!( expected, &actual, - "wrong distribution for node ({id}) at level {level}" + "wrong distribution for node ({id:?}) at level {level}" ); } } fn check_selection_dist(plan: &Plan, expected_dist: DistMock) { - let filter = |id: usize| -> bool { + let filter = |id: NodeId| -> bool { matches!( plan.get_node(id), Ok(Node::Relational(Relational::Selection { .. })) @@ -77,20 +84,20 @@ fn front_sql_global_tbl_sq1() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( r#"projection ("global_t"."a"::integer -> "a", "global_t"."b"::integer -> "b") - selection ROW("global_t"."a"::integer) in ROW($1) or ROW("global_t"."a"::integer) in ROW($0) + selection ROW("global_t"."a"::integer) in ROW($0) or ROW("global_t"."a"::integer) in ROW($1) scan "global_t" subquery $0: +motion [policy: full] + scan + projection ("t"."a"::unsigned -> "a1") + scan "t" +subquery $1: scan projection (sum(("sum_39"::decimal))::decimal -> "col_1") motion [policy: full] scan projection (sum(("t"."a"::unsigned))::decimal -> "sum_39") scan "t" -subquery $1: -motion [policy: full] - scan - projection ("t"."a"::unsigned -> "a1") - scan "t" execution options: sql_vdbe_max_steps = 45000 vtable_max_rows = 5000 @@ -213,7 +220,7 @@ fn front_sql_global_tbl_sq3() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( r#"projection ("global_t"."a"::integer -> "a", "global_t"."b"::integer -> "b") - selection not ROW("global_t"."a"::integer, "global_t"."b"::integer) in ROW($1, $1) or ROW("global_t"."a"::integer, "global_t"."b"::integer) < ROW($0, $0) + selection not ROW("global_t"."a"::integer, "global_t"."b"::integer) in ROW($0, $0) or ROW("global_t"."a"::integer, "global_t"."b"::integer) < ROW($1, $1) scan "global_t" subquery $0: motion [policy: full] @@ -384,7 +391,7 @@ vtable_max_rows = 5000 } fn check_join_dist(plan: &Plan, expected_distributions: &[DistMock]) { - let filter = |id: usize| -> bool { + let filter = |id: NodeId| -> bool { matches!( plan.get_node(id), Ok(Node::Relational(Relational::Join { .. })) @@ -981,7 +988,7 @@ vtable_max_rows = 5000 } fn check_union_dist(plan: &Plan, expected_distributions: &[DistMock]) { - let filter = |id: usize| -> bool { + let filter = |id: NodeId| -> bool { matches!( plan.get_node(id), Ok(Node::Relational(Relational::UnionAll { .. })) diff --git a/sbroad-core/src/frontend/sql/ir/tests/single.rs b/sbroad-core/src/frontend/sql/ir/tests/single.rs index 412d2bc72..798f10e8b 100644 --- a/sbroad-core/src/frontend/sql/ir/tests/single.rs +++ b/sbroad-core/src/frontend/sql/ir/tests/single.rs @@ -1,5 +1,6 @@ use smol_str::{SmolStr, ToSmolStr}; +use crate::ir::expression::NodeId; use crate::ir::operator::Relational; use crate::ir::transformation::helpers::sql_to_optimized_ir; use crate::ir::transformation::redistribution::{MotionKey, MotionPolicy, Target}; @@ -30,7 +31,7 @@ impl Policy { } impl Plan { - fn to_test_motion(&self, node_id: usize) -> Policy { + fn to_test_motion(&self, node_id: NodeId) -> Policy { let node = self.get_relation_node(node_id).unwrap(); match node { @@ -76,13 +77,14 @@ fn check_join_motions( ) { let plan = sql_to_optimized_ir(sql, vec![]); let mut dfs = PostOrder::with_capacity(|x| plan.nodes.rel_iter(x), REL_CAPACITY); - let (_, join_id) = dfs + let level_node = dfs .iter(plan.get_top().unwrap()) - .find(|(_, n)| -> bool { - let rel = plan.get_relation_node(*n).unwrap(); + .find(|level_node| -> bool { + let rel = plan.get_relation_node(level_node.1).unwrap(); matches!(rel, Relational::Join { .. }) }) .unwrap(); + let join_id = level_node.1; let children = plan.get_relational_children(join_id).unwrap(); let (left_id, right_id, sq_nodes_ids) = (children[0], children[1], &children[2..]); let (left_actual, right_actual) = (plan.to_test_motion(left_id), plan.to_test_motion(right_id)); diff --git a/sbroad-core/src/ir.rs b/sbroad-core/src/ir.rs index 4a4047c52..10732d04a 100644 --- a/sbroad-core/src/ir.rs +++ b/sbroad-core/src/ir.rs @@ -9,6 +9,7 @@ use std::cell::{RefCell, RefMut}; use std::collections::hash_map::IntoIter; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; +use tree::traversal::LevelNode; use std::slice::Iter; use tarantool::tlua; @@ -35,7 +36,7 @@ use crate::ir::undo::TransformationLog; use crate::ir::value::Value; use crate::{collection, error, warn}; -use self::expression::Position; +use self::expression::{NodeId, Position}; use self::parameters::Parameters; use self::relation::Relations; use self::transformation::redistribution::MotionPolicy; @@ -87,6 +88,17 @@ pub enum Node { Parameter(Option<Type>), } +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash, Copy)] +pub enum ArenaType { + Default, +} + +impl Display for ArenaType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "") + } +} + /// Plan nodes storage. #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] pub struct Nodes { @@ -98,23 +110,17 @@ pub struct Nodes { } impl Nodes { - pub(crate) fn get(&self, id: usize) -> Result<&Node, SbroadError> { - match self.arena.get(id) { - None => Err(SbroadError::NotFound( - Entity::Node, - format_smolstr!("from arena with index {id}"), - )), - Some(node) => Ok(node), + pub(crate) fn get(&self, id: NodeId) -> Option<&Node> { + let offset = usize::try_from(id.offset).unwrap(); + match id.arena_type { + ArenaType::Default => self.arena.get(offset), } } - pub(crate) fn get_mut(&mut self, id: usize) -> Result<&mut Node, SbroadError> { - match self.arena.get_mut(id) { - None => Err(SbroadError::NotFound( - Entity::Node, - format_smolstr!("from arena with index {id}"), - )), - Some(node) => Ok(node), + pub(crate) fn get_mut(&mut self, id: NodeId) -> Option<&mut Node> { + let offset = usize::try_from(id.offset).unwrap(); + match id.arena_type { + ArenaType::Default => self.arena.get_mut(offset), } } @@ -152,31 +158,47 @@ impl Nodes { /// Add new node to arena. /// + /// # Panics /// Inserts a new node to the arena and returns its position, /// that is treated as a pointer. - pub fn push(&mut self, node: Node) -> usize { + pub fn push(&mut self, node: Node) -> NodeId { let position = self.arena.len(); self.arena.push(node); - position + + NodeId { + offset: u32::try_from(position).unwrap(), + arena_type: ArenaType::Default, + } } + /// # Panics /// Returns the next node position #[must_use] - pub fn next_id(&self) -> usize { - self.arena.len() + pub fn next_id(&self, arena_type: ArenaType) -> NodeId { + match arena_type { + ArenaType::Default => NodeId { + offset: u32::try_from(self.arena.len()).unwrap(), + arena_type: ArenaType::Default, + }, + } } /// Replace a node in arena with another one. /// /// # Errors /// - The node with the given position doesn't exist. - pub fn replace(&mut self, id: usize, node: Node) -> Result<Node, SbroadError> { - if id >= self.arena.len() { - return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!( - "can't replace node with id {id} as it is out of arena bounds" - ))); - } - let old_node = std::mem::replace(&mut self.arena[id], node); + pub fn replace(&mut self, id: NodeId, node: Node) -> Result<Node, SbroadError> { + match id.arena_type { + ArenaType::Default => { + if id.offset as usize >= self.arena.len() { + return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!( + "can't replace node with id {id:?} as it is out of arena bounds" + ))); + } + } + }; + + let old_node = std::mem::replace(&mut self.arena[id.offset as usize], node); Ok(old_node) } @@ -201,23 +223,23 @@ impl<'nodes> IntoIterator for &'nodes Nodes { /// Element of `slice` vec is a `motion_id` to execute. #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] pub struct Slice { - slice: Vec<usize>, + slice: Vec<NodeId>, } -impl From<Vec<usize>> for Slice { - fn from(vec: Vec<usize>) -> Self { +impl From<Vec<NodeId>> for Slice { + fn from(vec: Vec<NodeId>) -> Self { Self { slice: vec } } } impl Slice { #[must_use] - pub fn position(&self, index: usize) -> Option<&usize> { + pub fn position(&self, index: usize) -> Option<&NodeId> { self.slice.get(index) } #[must_use] - pub fn positions(&self) -> &[usize] { + pub fn positions(&self) -> &[NodeId] { &self.slice } } @@ -235,8 +257,8 @@ impl From<Vec<Slice>> for Slices { } } -impl From<Vec<Vec<usize>>> for Slices { - fn from(vec: Vec<Vec<usize>>) -> Self { +impl From<Vec<Vec<NodeId>>> for Slices { + fn from(vec: Vec<Vec<NodeId>>) -> Self { Self { slices: vec.into_iter().map(Slice::from).collect(), } @@ -263,7 +285,7 @@ impl Slices { #[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)] pub enum OptionParamValue { Value { val: Value }, - Parameter { plan_id: usize }, + Parameter { plan_id: NodeId }, } #[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)] @@ -409,7 +431,6 @@ impl Options { } } -pub type NodeId = usize; pub type ValueIdx = usize; /// Logical plan tree structure. @@ -430,7 +451,7 @@ pub struct Plan { /// The plan top is marked as optional for tree creation convenience. /// We build the plan tree in a bottom-up manner, so the top would /// be added last. The plan without a top should be treated as invalid. - top: Option<usize>, + top: Option<NodeId>, /// The flag is enabled if user wants to get a query plan only. /// In this case we don't need to execute query. is_explain: bool, @@ -527,16 +548,22 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Plan, Some("plan tree top is None".into()), - )) - } - Some(top) => { - let _ = self.nodes.get(top)?; + )); } - } - - //TODO: additional consistency checks + Some(top) => match top.arena_type { + ArenaType::Default => { + if self.nodes.get(top).is_none() { + return Err(SbroadError::Invalid( + Entity::Plan, + Some("plan tree top index is out of bouns".into()), + )); + } + } + }, + }; Ok(()) + //TODO: additional consistency checks } /// Constructor for an empty plan structure. @@ -577,7 +604,8 @@ impl Plan { BreadthFirst::with_capacity(|x| self.nodes.rel_iter(x), REL_CAPACITY, REL_CAPACITY); bfs.populate_nodes(self.get_top()?); let nodes = bfs.take_nodes(); - for (_, id) in nodes { + for level_node in nodes { + let id = level_node.1; if let Relational::Insert { .. } = self.get_relation_node(id)? { let child_id = self.get_relational_child(id, 0)?; if let Relational::Values { children, .. } = self.get_relation_node(child_id)? { @@ -657,13 +685,15 @@ impl Plan { /// # Errors /// Returns `SbroadError` when the node with requested index /// doesn't exist. - pub fn get_node(&self, id: usize) -> Result<&Node, SbroadError> { - match self.nodes.arena.get(id) { - None => Err(SbroadError::NotFound( - Entity::Node, - format_smolstr!("from arena with index {id}"), - )), - Some(node) => Ok(node), + pub fn get_node(&self, id: NodeId) -> Result<&Node, SbroadError> { + match id.arena_type { + ArenaType::Default => match self.nodes.arena.get(id.offset as usize) { + None => Err(SbroadError::NotFound( + Entity::Node, + format_smolstr!("from {:?} arena with index {}", id.arena_type, id.offset), + )), + Some(node) => Ok(node), + }, } } @@ -672,13 +702,19 @@ impl Plan { /// # Errors /// Returns `SbroadError` when the node with requested index /// doesn't exist. - pub fn get_mut_node(&mut self, id: usize) -> Result<&mut Node, SbroadError> { - match self.nodes.arena.get_mut(id) { - None => Err(SbroadError::NotFound( - Entity::Node, - format_smolstr!("(mutable) from arena with index {id}"), - )), - Some(node) => Ok(node), + pub fn get_mut_node(&mut self, id: NodeId) -> Result<&mut Node, SbroadError> { + match id.arena_type { + ArenaType::Default => match self.nodes.arena.get_mut(id.offset as usize) { + None => Err(SbroadError::NotFound( + Entity::Node, + format_smolstr!( + "(mutable) from {:?} arena with index {}", + id.arena_type, + id.offset + ), + )), + Some(node) => Ok(node), + }, } } @@ -686,7 +722,7 @@ impl Plan { /// /// # Errors /// - top node is None (i.e. invalid plan) - pub fn get_top(&self) -> Result<usize, SbroadError> { + pub fn get_top(&self) -> Result<NodeId, SbroadError> { self.top .ok_or_else(|| SbroadError::Invalid(Entity::Plan, Some("plan tree top is None".into()))) } @@ -714,7 +750,7 @@ impl Plan { /// /// # Errors /// - Given node is not a scan - pub fn get_scan_relation(&self, scan_id: usize) -> Result<&str, SbroadError> { + pub fn get_scan_relation(&self, scan_id: NodeId) -> Result<&str, SbroadError> { let node = self.get_relation_node(scan_id)?; if let Relational::ScanRelation { relation, .. } = node { return Ok(relation.as_str()); @@ -757,10 +793,10 @@ impl Plan { /// - invalid expression tree pub fn contains_aggregates( &self, - expr_id: usize, + expr_id: NodeId, check_top: bool, ) -> Result<bool, SbroadError> { - let filter = |id: usize| -> bool { + let filter = |id: NodeId| -> bool { matches!( self.get_node(id), Ok(Node::Expression(Expression::StableFunction { .. })) @@ -771,7 +807,8 @@ impl Plan { EXPR_CAPACITY, Box::new(filter), ); - for (_, id) in dfs.iter(expr_id) { + for level_node in dfs.iter(expr_id) { + let id = level_node.1; if !check_top && id == expr_id { continue; } @@ -815,11 +852,11 @@ impl Plan { /// # Errors /// - node is not relational /// - node's output is not a row of aliases - pub fn get_row_from_rel_node(&mut self, node: usize) -> Result<usize, SbroadError> { + pub fn get_row_from_rel_node(&mut self, node: NodeId) -> Result<NodeId, SbroadError> { let n = self.get_node(node)?; if let Node::Relational(rel) = n { if let Node::Expression(Expression::Row { list, .. }) = self.get_node(rel.output())? { - let mut cols: Vec<usize> = Vec::with_capacity(list.len()); + let mut cols: Vec<NodeId> = Vec::with_capacity(list.len()); for alias in list { if let Node::Expression(Expression::Alias { child, .. }) = self.get_node(*alias)? @@ -842,8 +879,8 @@ impl Plan { } #[must_use] - pub fn next_id(&self) -> usize { - self.nodes.next_id() + pub fn next_id(&self, arena_type: ArenaType) -> NodeId { + self.nodes.next_id(arena_type) } /// Add condition node to the plan. @@ -852,10 +889,10 @@ impl Plan { /// Returns `SbroadError` when the condition node can't append'. pub fn add_cond( &mut self, - left: usize, + left: NodeId, op: operator::Bool, - right: usize, - ) -> Result<usize, SbroadError> { + right: NodeId, + ) -> Result<NodeId, SbroadError> { self.nodes.add_bool(left, op, right) } @@ -863,7 +900,7 @@ impl Plan { /// /// # Errors /// Returns `SbroadError` when the condition node can't append'. - pub fn add_covered_with_parentheses(&mut self, child: usize) -> usize { + pub fn add_covered_with_parentheses(&mut self, child: NodeId) -> NodeId { self.nodes.add_covered_with_parentheses(child) } @@ -873,10 +910,10 @@ impl Plan { /// Returns `SbroadError` when the condition node can't append'. pub fn add_arithmetic_to_plan( &mut self, - left: usize, + left: NodeId, op: Arithmetic, - right: usize, - ) -> Result<usize, SbroadError> { + right: NodeId, + ) -> Result<NodeId, SbroadError> { self.nodes.add_arithmetic_node(left, op, right) } @@ -884,17 +921,17 @@ impl Plan { /// /// # Errors /// - Child node is invalid - pub fn add_unary(&mut self, op: operator::Unary, child: usize) -> Result<usize, SbroadError> { + pub fn add_unary(&mut self, op: operator::Unary, child: NodeId) -> Result<NodeId, SbroadError> { self.nodes.add_unary_bool(op, child) } /// Add CASE ... END operator to the plan. pub fn add_case( &mut self, - search_expr: Option<usize>, - when_blocks: Vec<(usize, usize)>, - else_expr: Option<usize>, - ) -> usize { + search_expr: Option<NodeId>, + when_blocks: Vec<(NodeId, NodeId)>, + else_expr: Option<NodeId>, + ) -> NodeId { self.nodes.push(Node::Expression(Expression::Case { search_expr, else_expr, @@ -906,7 +943,12 @@ impl Plan { /// /// # Errors /// - Children node are invalid - pub fn add_bool(&mut self, left: usize, op: Bool, right: usize) -> Result<usize, SbroadError> { + pub fn add_bool( + &mut self, + left: NodeId, + op: Bool, + right: NodeId, + ) -> Result<NodeId, SbroadError> { self.nodes.add_bool(left, op, right) } @@ -963,7 +1005,7 @@ impl Plan { /// Set top node of plan /// # Errors /// - top node doesn't exist in the plan. - pub fn set_top(&mut self, top: usize) -> Result<(), SbroadError> { + pub fn set_top(&mut self, top: NodeId) -> Result<(), SbroadError> { self.get_node(top)?; self.top = Some(top); Ok(()) @@ -974,7 +1016,7 @@ impl Plan { /// # Errors /// - node doesn't exist in the plan /// - node is not a relational type - pub fn get_relation_node(&self, node_id: usize) -> Result<&Relational, SbroadError> { + pub fn get_relation_node(&self, node_id: NodeId) -> Result<&Relational, SbroadError> { let node = self.get_node(node_id)?; match node { Node::Relational(rel) => Ok(rel), @@ -996,7 +1038,7 @@ impl Plan { /// - node is not a relational type pub fn get_mut_relation_node( &mut self, - node_id: usize, + node_id: NodeId, ) -> Result<&mut Relational, SbroadError> { match self.get_mut_node(node_id)? { Node::Relational(rel) => Ok(rel), @@ -1016,7 +1058,7 @@ impl Plan { /// # Errors /// - node doesn't exist in the plan /// - node is not expression type - pub fn get_expression_node(&self, node_id: usize) -> Result<&Expression, SbroadError> { + pub fn get_expression_node(&self, node_id: NodeId) -> Result<&Expression, SbroadError> { match self.get_node(node_id)? { Node::Expression(exp) => Ok(exp), Node::Parameter(..) => { @@ -1043,7 +1085,7 @@ impl Plan { /// - node is not expression type pub fn get_mut_expression_node( &mut self, - node_id: usize, + node_id: NodeId, ) -> Result<&mut Expression, SbroadError> { let node = self.get_mut_node(node_id)?; match node { @@ -1055,7 +1097,7 @@ impl Plan { | Node::Block(..) => Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "node ({node_id}) is not expression type: {node:?}" + "node ({node_id:?}) is not expression type: {node:?}" )), )), } @@ -1065,7 +1107,7 @@ impl Plan { /// /// # Errors /// - supplied id does not correspond to `Row` node - pub fn get_row_list(&self, row_id: usize) -> Result<&[usize], SbroadError> { + pub fn get_row_list(&self, row_id: NodeId) -> Result<&[NodeId], SbroadError> { self.get_expression_node(row_id)?.get_row_list() } @@ -1074,7 +1116,7 @@ impl Plan { /// /// # Errors /// - node is not an expression node - pub fn get_child_under_alias(&self, child_id: usize) -> Result<usize, SbroadError> { + pub fn get_child_under_alias(&self, child_id: NodeId) -> Result<NodeId, SbroadError> { match self.get_expression_node(child_id)? { Expression::Alias { child: alias_child, .. @@ -1087,7 +1129,7 @@ impl Plan { /// /// # Errors /// - supplied id does not correspond to `Row` node - pub fn get_mut_row_list(&mut self, row_id: usize) -> Result<&mut Vec<usize>, SbroadError> { + pub fn get_mut_row_list(&mut self, row_id: NodeId) -> Result<&mut Vec<NodeId>, SbroadError> { self.get_mut_expression_node(row_id)?.get_mut_row_list() } @@ -1107,9 +1149,9 @@ impl Plan { /// children with the same id. So, if this happens, only one child will be replaced. pub fn replace_expression( &mut self, - parent_id: usize, - old_id: usize, - new_id: usize, + parent_id: NodeId, + old_id: NodeId, + new_id: NodeId, ) -> Result<(), SbroadError> { match self.get_mut_expression_node(parent_id)? { Expression::Unary { child, .. } @@ -1190,7 +1232,7 @@ impl Plan { Err(SbroadError::FailedTo( Action::Replace, Some(Entity::Expression), - format_smolstr!("parent expression ({parent_id}) has no child with id {old_id}"), + format_smolstr!("parent expression ({parent_id:?}) has no child with id {old_id:?}"), )) } @@ -1199,7 +1241,11 @@ impl Plan { /// # Errors /// - supplied index is out of range /// - node is not `GroupBy` - pub fn get_groupby_col(&self, groupby_id: usize, col_idx: usize) -> Result<usize, SbroadError> { + pub fn get_groupby_col( + &self, + groupby_id: NodeId, + col_idx: usize, + ) -> Result<NodeId, SbroadError> { let node = self.get_relation_node(groupby_id)?; if let Relational::GroupBy { gr_cols, .. } = node { let col_id = gr_cols.get(col_idx).ok_or_else(|| { @@ -1220,7 +1266,7 @@ impl Plan { /// # Errors /// - supplied index is out of range /// - node is not `Projection` - pub fn get_proj_col(&self, proj_id: usize, col_idx: usize) -> Result<usize, SbroadError> { + pub fn get_proj_col(&self, proj_id: NodeId, col_idx: usize) -> Result<NodeId, SbroadError> { let node = self.get_relation_node(proj_id)?; if let Relational::Projection { output, .. } = node { let col_id = self.get_row_list(*output)?.get(col_idx).ok_or_else(|| { @@ -1240,7 +1286,7 @@ impl Plan { /// /// # Errors /// - node is not `GroupBy` - pub fn get_grouping_cols(&self, groupby_id: usize) -> Result<&[usize], SbroadError> { + pub fn get_grouping_cols(&self, groupby_id: NodeId) -> Result<&[NodeId], SbroadError> { let node = self.get_relation_node(groupby_id)?; if let Relational::GroupBy { gr_cols, .. } = node { return Ok(gr_cols); @@ -1257,8 +1303,8 @@ impl Plan { /// - node is not `GroupBy` pub fn set_grouping_cols( &mut self, - groupby_id: usize, - new_cols: Vec<usize>, + groupby_id: NodeId, + new_cols: Vec<NodeId>, ) -> Result<(), SbroadError> { let node = self.get_mut_relation_node(groupby_id)?; if let Relational::GroupBy { gr_cols, .. } = node { @@ -1324,7 +1370,7 @@ impl Plan { let ref_node_target_child = ref_node_children .get(*first_target) - .unwrap_or_else(|| panic!("Failed to get target index {first_target} for reference {node:?} and ref_node [id = {parent:?}] {ref_node:?}")); + .unwrap_or_else(|| panic!("Failed to get target index {first_target:?} for reference {node:?} and ref_node [id = {parent:?}] {ref_node:?}")); let column_rel_node = self.get_relation_node(*ref_node_target_child)?; let column_expr_node = self.get_expression_node(column_rel_node.output())?; @@ -1339,19 +1385,19 @@ impl Plan { } /// Set slices of the plan. - pub fn set_slices(&mut self, slices: Vec<Vec<usize>>) { + pub fn set_slices(&mut self, slices: Vec<Vec<NodeId>>) { self.slices = slices.into(); } /// # Errors /// - serialization error (to binary) - pub fn pattern_id(&self, top_id: usize) -> Result<SmolStr, SbroadError> { - let mut dfs = - PostOrder::with_capacity(|x| self.subtree_iter(x, false), self.nodes.next_id()); + pub fn pattern_id(&self, top_id: NodeId) -> Result<SmolStr, SbroadError> { + let mut dfs = PostOrder::with_capacity(|x| self.subtree_iter(x, false), self.nodes.len()); dfs.populate_nodes(top_id); let nodes = dfs.take_nodes(); let mut plan_nodes: Vec<&Node> = Vec::with_capacity(nodes.len()); - for (_, id) in nodes { + for level_node in nodes { + let id = level_node.1; plan_nodes.push(self.get_node(id)?); } let bytes: Vec<u8> = bincode::serialize(&plan_nodes).map_err(|e| { @@ -1636,7 +1682,7 @@ impl ShardColumnsMap { fn update_subtree(&mut self, node_id: NodeId, plan: &Plan) -> Result<(), SbroadError> { let mut dfs = PostOrder::with_capacity(|x| plan.nodes.rel_iter(x), REL_CAPACITY); - for (_, id) in dfs.iter(node_id) { + for LevelNode(_, id) in dfs.iter(node_id) { self.update_node(id, plan)?; self.invalid_ids.remove(&id); } diff --git a/sbroad-core/src/ir/acl.rs b/sbroad-core/src/ir/acl.rs index adec244ce..54cf1e420 100644 --- a/sbroad-core/src/ir/acl.rs +++ b/sbroad-core/src/ir/acl.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use tarantool::decimal::Decimal; -use super::ddl::ParamDef; +use super::{ddl::ParamDef, expression::NodeId}; ::tarantool::define_str_enum! { /// Revoked or granted privilege. @@ -256,7 +256,7 @@ impl Plan { /// # Errors /// - the node index is absent in arena /// - current node is not of ACL type - pub fn get_acl_node(&self, node_id: usize) -> Result<&Acl, SbroadError> { + pub fn get_acl_node(&self, node_id: NodeId) -> Result<&Acl, SbroadError> { let node = self.get_node(node_id)?; match node { Node::Acl(acl) => Ok(acl), @@ -272,7 +272,7 @@ impl Plan { /// # Errors /// - the node index is absent in arena /// - current node is not of ACL type - pub fn get_mut_acl_node(&mut self, node_id: usize) -> Result<&mut Acl, SbroadError> { + pub fn get_mut_acl_node(&mut self, node_id: NodeId) -> Result<&mut Acl, SbroadError> { let node = self.get_mut_node(node_id)?; match node { Node::Acl(acl) => Ok(acl), @@ -287,7 +287,7 @@ impl Plan { /// /// # Errors /// - current node is not of ACL type - pub fn take_acl_node(&mut self, node_id: usize) -> Result<Acl, SbroadError> { + pub fn take_acl_node(&mut self, node_id: NodeId) -> Result<Acl, SbroadError> { // Check that node is ACL type (before making any distructive operations). let _ = self.get_acl_node(node_id)?; // Replace ACL with parameter node. diff --git a/sbroad-core/src/ir/aggregates.rs b/sbroad-core/src/ir/aggregates.rs index f1ecee6ce..7db5a343e 100644 --- a/sbroad-core/src/ir/aggregates.rs +++ b/sbroad-core/src/ir/aggregates.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::rc::Rc; -use super::expression::{ColumnPositionMap, FunctionFeature}; +use super::expression::{ColumnPositionMap, FunctionFeature, NodeId}; /// The kind of aggregate function /// @@ -90,7 +90,7 @@ impl AggregateKind { /// /// # Panics /// - Invalid argument count for aggregate - pub fn check_args_types(&self, plan: &Plan, args: &[usize]) -> Result<(), SbroadError> { + pub fn check_args_types(&self, plan: &Plan, args: &[NodeId]) -> Result<(), SbroadError> { use crate::ir::relation::Type; let get_arg_type = |idx: usize| -> Result<Type, SbroadError> { let arg_id = *args.get(idx).expect("wrong agregate"); @@ -200,7 +200,7 @@ pub struct SimpleAggregate { /// map will contain: `avg` -> `l1` pub lagg_alias: HashMap<AggregateKind, Rc<String>>, /// id of aggregate function in IR - pub fun_id: usize, + pub fun_id: NodeId, } #[cfg(not(feature = "mock"))] @@ -220,7 +220,7 @@ pub fn generate_local_alias_for_aggr(kind: &AggregateKind, suffix: &str) -> Stri impl SimpleAggregate { #[must_use] - pub fn new(name: &str, fun_id: usize) -> Option<SimpleAggregate> { + pub fn new(name: &str, fun_id: NodeId) -> Option<SimpleAggregate> { let kind = AggregateKind::new(name)?; let laggr_alias: HashMap<AggregateKind, Rc<String>> = HashMap::new(); let aggr = SimpleAggregate { @@ -297,14 +297,14 @@ impl SimpleAggregate { #[allow(clippy::too_many_lines)] pub(crate) fn create_final_aggregate_expr( &self, - parent: usize, + parent: NodeId, plan: &mut Plan, fun_type: &RelType, mut position_kinds: Vec<PositionKind>, is_distinct: bool, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { // map local AggregateKind to finalised expression of that aggregate - let mut final_aggregates: HashMap<AggregateKind, usize> = HashMap::new(); + let mut final_aggregates: HashMap<AggregateKind, NodeId> = HashMap::new(); let mut create_final_aggr = |position: Position, local_kind: AggregateKind, final_func: AggregateKind| @@ -338,7 +338,7 @@ impl SimpleAggregate { return Err(SbroadError::Invalid( Entity::Aggregate, Some(format_smolstr!( - "fun_id ({}) points to other expression node", + "fun_id ({:?}) points to other expression node", self.fun_id )), )); diff --git a/sbroad-core/src/ir/api/children.rs b/sbroad-core/src/ir/api/children.rs index d3874c90c..2b004eac7 100644 --- a/sbroad-core/src/ir/api/children.rs +++ b/sbroad-core/src/ir/api/children.rs @@ -1,15 +1,17 @@ use std::ops::{Index, Range, RangeFrom, RangeFull}; +use crate::ir::expression::NodeId; + #[derive(Debug)] pub enum Children<'r> { None, - Single(&'r usize), - Couple(&'r usize, &'r usize), - Many(&'r [usize]), + Single(&'r NodeId), + Couple(&'r NodeId, &'r NodeId), + Many(&'r [NodeId]), } impl<'r> Index<usize> for Children<'r> { - type Output = usize; + type Output = NodeId; fn index(&self, idx: usize) -> &Self::Output { match self { @@ -29,7 +31,7 @@ impl<'r> Index<usize> for Children<'r> { } impl<'r> Index<Range<usize>> for Children<'r> { - type Output = [usize]; + type Output = [NodeId]; fn index(&self, range: Range<usize>) -> &Self::Output { match self { @@ -40,7 +42,7 @@ impl<'r> Index<Range<usize>> for Children<'r> { } impl<'r> Index<RangeFrom<usize>> for Children<'r> { - type Output = [usize]; + type Output = [NodeId]; fn index(&self, range: RangeFrom<usize>) -> &Self::Output { &self[range.start..self.len()] @@ -48,7 +50,7 @@ impl<'r> Index<RangeFrom<usize>> for Children<'r> { } impl<'r> Index<RangeFull> for Children<'r> { - type Output = [usize]; + type Output = [NodeId]; fn index(&self, _: RangeFull) -> &Self::Output { &self[0..self.len()] @@ -72,7 +74,7 @@ impl<'r> Children<'r> { } #[must_use] - pub fn to_vec(&self) -> Vec<usize> { + pub fn to_vec(&self) -> Vec<NodeId> { match self { Children::None => vec![], Children::Single(i) => vec![**i], @@ -82,7 +84,7 @@ impl<'r> Children<'r> { } #[must_use] - pub fn get(&self, idx: usize) -> Option<&'r usize> { + pub fn get(&self, idx: usize) -> Option<&'r NodeId> { if idx >= self.len() { return None; } @@ -109,7 +111,7 @@ pub struct ChildrenIter<'c> { } impl<'c> Iterator for ChildrenIter<'c> { - type Item = &'c usize; + type Item = &'c NodeId; fn next(&mut self) -> Option<Self::Item> { let child = match self.inner { @@ -148,7 +150,7 @@ impl<'r> Children<'r> { } impl<'r> IntoIterator for &'r Children<'r> { - type Item = &'r usize; + type Item = &'r NodeId; type IntoIter = ChildrenIter<'r>; @@ -161,9 +163,9 @@ impl<'r> IntoIterator for &'r Children<'r> { #[allow(clippy::module_name_repetitions)] pub enum MutChildren<'r> { None, - Single(&'r mut usize), - Couple(&'r mut usize, &'r mut usize), - Many(&'r mut [usize]), + Single(&'r mut NodeId), + Couple(&'r mut NodeId, &'r mut NodeId), + Many(&'r mut [NodeId]), } impl<'r> MutChildren<'r> { @@ -183,7 +185,7 @@ impl<'r> MutChildren<'r> { } #[must_use] - pub fn to_vec(&self) -> Vec<usize> { + pub fn to_vec(&self) -> Vec<NodeId> { match self { MutChildren::None => vec![], MutChildren::Single(i) => vec![**i], @@ -196,7 +198,7 @@ impl<'r> MutChildren<'r> { // that instance lifetime '1 must be bigger than 'r and we // return '1 #[must_use] - pub fn get_mut(self, idx: usize) -> Option<&'r mut usize> { + pub fn get_mut(self, idx: usize) -> Option<&'r mut NodeId> { if idx >= self.len() { return None; } @@ -215,7 +217,7 @@ impl<'r> MutChildren<'r> { } #[must_use] - pub fn split_first(self) -> Option<(&'r mut usize, MutChildren<'r>)> { + pub fn split_first(self) -> Option<(&'r mut NodeId, MutChildren<'r>)> { let res = match self { MutChildren::None => return None, MutChildren::Single(i) => (i, MutChildren::None), @@ -236,7 +238,7 @@ pub struct MutChildrenIter<'c> { } impl<'c> Iterator for MutChildrenIter<'c> { - type Item = &'c mut usize; + type Item = &'c mut NodeId; #[must_use] fn next(&mut self) -> Option<Self::Item> { @@ -261,7 +263,7 @@ impl<'r> MutChildren<'r> { } impl<'r> IntoIterator for MutChildren<'r> { - type Item = &'r mut usize; + type Item = &'r mut NodeId; type IntoIter = MutChildrenIter<'r>; diff --git a/sbroad-core/src/ir/api/constant.rs b/sbroad-core/src/ir/api/constant.rs index c9ce32ae4..50d841a0c 100644 --- a/sbroad-core/src/ir/api/constant.rs +++ b/sbroad-core/src/ir/api/constant.rs @@ -1,9 +1,9 @@ use smol_str::format_smolstr; use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::value::Value; -use crate::ir::{Node, Nodes, Plan}; +use crate::ir::{ArenaType, Node, Nodes, Plan}; impl Expression { /// Gets value from const node @@ -45,26 +45,30 @@ impl Expression { impl Nodes { /// Adds constant node. - pub fn add_const(&mut self, value: Value) -> usize { + pub fn add_const(&mut self, value: Value) -> NodeId { self.push(Node::Expression(Expression::Constant { value })) } } impl Plan { /// Add constant value to the plan. - pub fn add_const(&mut self, v: Value) -> usize { + pub fn add_const(&mut self, v: Value) -> NodeId { self.nodes.add_const(v) } #[must_use] - pub fn get_const_list(&self) -> Vec<usize> { + /// # Panics + pub fn get_const_list(&self) -> Vec<NodeId> { self.nodes .arena .iter() .enumerate() .filter_map(|(id, node)| { if let Node::Expression(Expression::Constant { .. }) = node { - Some(id) + Some(NodeId { + offset: u32::try_from(id).unwrap(), + arena_type: ArenaType::Default, + }) } else { None } @@ -83,7 +87,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Expression, Some(format_smolstr!( - "Restoring parameters filed: node {const_node:?} (id: {id}) is not of a constant type" + "Restoring parameters filed: node {const_node:?} (id: {id:?}) is not of a constant type" )), )); } diff --git a/sbroad-core/src/ir/api/parameter.rs b/sbroad-core/src/ir/api/parameter.rs index fa5cd4e32..9875e3028 100644 --- a/sbroad-core/src/ir/api/parameter.rs +++ b/sbroad-core/src/ir/api/parameter.rs @@ -1,10 +1,10 @@ use crate::errors::SbroadError; use crate::ir::block::Block; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::Relational; use crate::ir::tree::traversal::{LevelNode, PostOrder}; use crate::ir::value::Value; -use crate::ir::{Node, NodeId, OptionParamValue, Plan, ValueIdx}; +use crate::ir::{ArenaType, Node, OptionParamValue, Plan, ValueIdx}; use crate::otm::child_span; use sbroad_proc::otm_child_span; use smol_str::format_smolstr; @@ -16,7 +16,7 @@ use std::collections::HashMap; struct ParamsBinder<'binder> { plan: &'binder mut Plan, /// Plan nodes to traverse during binding. - nodes: Vec<LevelNode>, + nodes: Vec<LevelNode<NodeId>>, /// Number of parameters met in the OPTIONs. binded_options_counter: usize, /// Flag indicating whether we use Tarantool parameters notation. @@ -34,16 +34,16 @@ struct ParamsBinder<'binder> { /// queries it is IR responsibility). /// /// Map of { param_id -> corresponding row }. - row_map: AHashMap<usize, usize, RandomState>, + row_map: AHashMap<NodeId, NodeId, RandomState>, } fn get_param_value( tnt_params_style: bool, - param_id: usize, + param_id: NodeId, param_index: usize, - value_ids: &[usize], + value_ids: &[NodeId], pg_params_map: &HashMap<NodeId, ValueIdx>, -) -> usize { +) -> NodeId { let value_index = if tnt_params_style { // In case non-pg params are used, index is the correct position param_index @@ -51,7 +51,7 @@ fn get_param_value( value_ids.len() - 1 - *pg_params_map.get(¶m_id).unwrap_or_else(|| { - panic!("Value index not found for parameter with id: {param_id}.") + panic!("Value index not found for parameter with id: {param_id:?}.") }) }; let val_id = value_ids @@ -62,7 +62,7 @@ fn get_param_value( impl<'binder> ParamsBinder<'binder> { fn new(plan: &'binder mut Plan, mut values: Vec<Value>) -> Result<Self, SbroadError> { - let capacity = plan.next_id(); + let capacity = plan.nodes.len(); let mut tree = PostOrder::with_capacity(|node| plan.subtree_iter(node, false), capacity); let top_id = plan.get_top()?; tree.populate_nodes(top_id); @@ -100,20 +100,20 @@ impl<'binder> ParamsBinder<'binder> { // than once in order to get the same hash. // See https://git.picodata.io/picodata/picodata/sbroad/-/issues/583 let mut used_values = vec![false; self.values.len()]; - let invalid_idx = |param_id: usize, value_idx: usize| { - panic!("Out of bounds value index {value_idx} for pg parameter {param_id}."); + let invalid_idx = |param_id: NodeId, value_idx: usize| { + panic!("Out of bounds value index {value_idx} for pg parameter {param_id:?}."); }; // NB: we can't use `param_node_ids`, we need to traverse // parameters in the same order they will be bound, // otherwise we may get different hashes for plans // with tnt and pg parameters. See `subtree_hash*` tests, - for (_, param_id) in &self.nodes { + for LevelNode(_, param_id) in &self.nodes { if !matches!(self.plan.get_node(*param_id)?, Node::Parameter(..)) { continue; } let value_idx = *self.pg_params_map.get(param_id).unwrap_or_else(|| { - panic!("Value index not found for parameter with id: {param_id}."); + panic!("Value index not found for parameter with id: {param_id:?}."); }); if used_values.get(value_idx).copied().unwrap_or(true) { let Some(value) = self.values.get(value_idx) else { @@ -159,7 +159,7 @@ impl<'binder> ParamsBinder<'binder> { } /// Retrieve a corresponding value (plan constant node) for a parameter node. - fn get_param_value(&self, param_id: usize, param_index: usize) -> usize { + fn get_param_value(&self, param_id: NodeId, param_index: usize) -> NodeId { get_param_value( self.tnt_params_style, param_id, @@ -173,10 +173,10 @@ impl<'binder> ParamsBinder<'binder> { /// 2.) In case `cover_with_row` is set to true, cover the param node with a row. fn cover_param_with_row( &self, - param_id: usize, + param_id: NodeId, cover_with_row: bool, param_index: &mut usize, - row_ids: &mut HashMap<usize, usize, RandomState>, + row_ids: &mut HashMap<NodeId, NodeId, RandomState>, ) { if self.param_node_ids.contains(¶m_id) { if row_ids.contains_key(¶m_id) { @@ -198,7 +198,7 @@ impl<'binder> ParamsBinder<'binder> { let mut row_ids = HashMap::with_hasher(RandomState::new()); - for (_, id) in &self.nodes { + for LevelNode(_, id) in &self.nodes { let node = self.plan.get_node(*id)?; match node { // Note: Parameter may not be met at the top of relational operators' expression @@ -353,7 +353,7 @@ impl<'binder> ParamsBinder<'binder> { } } - let fixed_row_ids: AHashMap<usize, usize, RandomState> = row_ids + let fixed_row_ids: AHashMap<NodeId, NodeId, RandomState> = row_ids .iter() .map(|(param_id, val_id)| { let row_cover = self.plan.nodes.add_row(vec![*val_id], None); @@ -368,9 +368,9 @@ impl<'binder> ParamsBinder<'binder> { /// Replace parameters in the plan. #[allow(clippy::too_many_lines)] fn bind_params(&mut self) -> Result<(), SbroadError> { - let mut exprs_to_set_ref_type: HashMap<usize, Type> = HashMap::new(); + let mut exprs_to_set_ref_type: HashMap<NodeId, Type> = HashMap::new(); - for (_, id) in &self.nodes { + for LevelNode(_, id) in &self.nodes { // Before binding, references that referred to // parameters had scalar type (by default), // but in fact they may refer to different stuff. @@ -394,13 +394,13 @@ impl<'binder> ParamsBinder<'binder> { let value_ids = std::mem::take(&mut self.value_ids); let pg_params_map = std::mem::take(&mut self.pg_params_map); - let bind_param = |param_id: &mut usize, is_row: bool, param_index: &mut usize| { + let bind_param = |param_id: &mut NodeId, is_row: bool, param_index: &mut usize| { *param_id = if self.param_node_ids.contains(param_id) { *param_index = param_index.saturating_sub(1); let binding_node_id = if is_row { *row_ids .get(param_id) - .unwrap_or_else(|| panic!("Row not found at position {param_id}")) + .unwrap_or_else(|| panic!("Row not found at position {param_id:?}")) } else { get_param_value( tnt_params_style, @@ -416,7 +416,7 @@ impl<'binder> ParamsBinder<'binder> { } }; - for (_, id) in &self.nodes { + for LevelNode(_, id) in &self.nodes { let node = self.plan.get_mut_node(*id)?; match node { Node::Relational(rel) => match rel { @@ -529,7 +529,7 @@ impl<'binder> ParamsBinder<'binder> { } fn update_value_rows(&mut self) -> Result<(), SbroadError> { - for (_, id) in &self.nodes { + for LevelNode(_, id) in &self.nodes { if let Ok(Node::Relational(Relational::ValuesRow { .. })) = self.plan.get_node(*id) { self.plan.update_values_row(*id)?; } @@ -539,7 +539,7 @@ impl<'binder> ParamsBinder<'binder> { } impl Plan { - pub fn add_param(&mut self) -> usize { + pub fn add_param(&mut self) -> NodeId { self.nodes.push(Node::Parameter(None)) } @@ -580,15 +580,19 @@ impl Plan { // Gather all parameter nodes from the tree to a hash set. #[must_use] - pub fn get_param_set(&self) -> AHashSet<usize> { - let param_set: AHashSet<usize> = self + /// # Panics + pub fn get_param_set(&self) -> AHashSet<NodeId> { + let param_set: AHashSet<NodeId> = self .nodes .arena .iter() .enumerate() .filter_map(|(id, node)| { if let Node::Parameter(..) = node { - Some(id) + Some(NodeId { + offset: u32::try_from(id).unwrap(), + arena_type: ArenaType::Default, + }) } else { None } @@ -606,7 +610,7 @@ impl Plan { /// /// # Panics /// - Plan is inconsistent state - pub fn update_values_row(&mut self, id: usize) -> Result<(), SbroadError> { + pub fn update_values_row(&mut self, id: NodeId) -> Result<(), SbroadError> { let values_row = self.get_node(id)?; let (output_id, data_id) = if let Node::Relational(Relational::ValuesRow { output, data, .. }) = values_row { diff --git a/sbroad-core/src/ir/block.rs b/sbroad-core/src/ir/block.rs index b7313321c..5dbd9ce97 100644 --- a/sbroad-core/src/ir/block.rs +++ b/sbroad-core/src/ir/block.rs @@ -1,10 +1,12 @@ //! IR nodes representing blocks of commands. use crate::errors::{Entity, SbroadError}; -use crate::ir::{Node, NodeId, Plan}; +use crate::ir::{Node, Plan}; use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr}; +use super::expression::NodeId; + #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum Block { /// Procedure body. @@ -41,7 +43,7 @@ impl Plan { | Node::Parameter(..) => Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "node {node:?} (id {node_id}) is not Block type" + "node {node:?} (id {node_id:?}) is not Block type" )), )), } @@ -62,7 +64,7 @@ impl Plan { | Node::Parameter(..) => Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "node {node:?} (id {node_id}) is not Block type" + "node {node:?} (id {node_id:?}) is not Block type" )), )), } diff --git a/sbroad-core/src/ir/ddl.rs b/sbroad-core/src/ir/ddl.rs index 55d173c17..5932af5fb 100644 --- a/sbroad-core/src/ir/ddl.rs +++ b/sbroad-core/src/ir/ddl.rs @@ -11,6 +11,8 @@ use tarantool::{ index::{IndexType, RtreeIndexDistanceType}, }; +use super::expression::NodeId; + #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] pub struct ColumnDef { pub name: SmolStr, @@ -187,7 +189,7 @@ impl Plan { /// # Errors /// - the node index is absent in arena /// - current node is not of DDL type - pub fn get_ddl_node(&self, node_id: usize) -> Result<&Ddl, SbroadError> { + pub fn get_ddl_node(&self, node_id: NodeId) -> Result<&Ddl, SbroadError> { let node = self.get_node(node_id)?; match node { Node::Ddl(ddl) => Ok(ddl), @@ -203,7 +205,7 @@ impl Plan { /// # Errors /// - the node index is absent in arena /// - current node is not of DDL type - pub fn get_mut_ddl_node(&mut self, node_id: usize) -> Result<&mut Ddl, SbroadError> { + pub fn get_mut_ddl_node(&mut self, node_id: NodeId) -> Result<&mut Ddl, SbroadError> { let node = self.get_mut_node(node_id)?; match node { Node::Ddl(ddl) => Ok(ddl), @@ -218,7 +220,7 @@ impl Plan { /// /// # Errors /// - current node is not of DDL type - pub fn take_ddl_node(&mut self, node_id: usize) -> Result<Ddl, SbroadError> { + pub fn take_ddl_node(&mut self, node_id: NodeId) -> Result<Ddl, SbroadError> { // Check that node is DDL type (before making any distructive operations). let _ = self.get_ddl_node(node_id)?; // Replace DDL with parameter node. diff --git a/sbroad-core/src/ir/distribution.rs b/sbroad-core/src/ir/distribution.rs index 16bc3e4b6..6a20a724b 100644 --- a/sbroad-core/src/ir/distribution.rs +++ b/sbroad-core/src/ir/distribution.rs @@ -12,7 +12,7 @@ use crate::ir::helpers::RepeatableState; use crate::ir::transformation::redistribution::{MotionKey, Target}; use super::api::children::Children; -use super::expression::Expression; +use super::expression::{Expression, NodeId}; use super::operator::Relational; use super::relation::{Column, ColumnPositions}; use super::{Node, Plan}; @@ -279,9 +279,9 @@ impl Distribution { enum ReferredNodes { None, - Single(usize), - Pair(usize, usize), - Multiple(Vec<usize>), + Single(NodeId), + Pair(NodeId, NodeId), + Multiple(Vec<NodeId>), } impl ReferredNodes { @@ -289,7 +289,7 @@ impl ReferredNodes { ReferredNodes::None } - fn append(&mut self, node: usize) { + fn append(&mut self, node: NodeId) { match self { ReferredNodes::None => *self = ReferredNodes::Single(node), ReferredNodes::Single(n) => { @@ -324,7 +324,7 @@ struct ReferenceInfo { impl ReferenceInfo { pub fn new( - row_id: usize, + row_id: NodeId, ir: &Plan, parent_children: &Children<'_>, ) -> Result<Self, SbroadError> { @@ -365,7 +365,7 @@ impl ReferenceInfo { } impl Iterator for ReferredNodes { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { match self { @@ -396,13 +396,13 @@ impl Iterator for ReferredNodes { #[derive(Debug, Eq, Hash, PartialEq)] struct ChildColumnReference { /// Child node id. - node_id: usize, + node_id: NodeId, /// Column position in the child node. column_position: usize, } -impl From<(usize, usize)> for ChildColumnReference { - fn from((node_id, column_position): (usize, usize)) -> Self { +impl From<(NodeId, usize)> for ChildColumnReference { + fn from((node_id, column_position): (NodeId, usize)) -> Self { ChildColumnReference { node_id, column_position, @@ -419,14 +419,14 @@ impl Plan { /// - node is not projection /// - invalid projection node (e.g. no children) /// - failed to get child distribution - pub fn set_projection_distribution(&mut self, proj_id: usize) -> Result<(), SbroadError> { + pub fn set_projection_distribution(&mut self, proj_id: NodeId) -> Result<(), SbroadError> { if !matches!( self.get_relation_node(proj_id)?, Relational::Projection { .. } ) { return Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("expected projection on id: {proj_id}")), + Some(format_smolstr!("expected projection on id: {proj_id:?}")), )); }; @@ -478,7 +478,7 @@ impl Plan { /// # Panics /// - reference has invalid targets #[allow(clippy::too_many_lines)] - pub fn set_distribution(&mut self, row_id: usize) -> Result<(), SbroadError> { + pub fn set_distribution(&mut self, row_id: NodeId) -> Result<(), SbroadError> { let row_children = self.get_expression_node(row_id)?.get_row_list()?; let mut parent_node = None; @@ -608,7 +608,7 @@ impl Plan { /// - missing Motion(Full) for sq with Any distribution pub(crate) fn dist_from_subqueries( &self, - node_id: usize, + node_id: NodeId, ) -> Result<Option<Distribution>, SbroadError> { let node = self.get_relation_node(node_id)?; @@ -644,7 +644,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Distribution, Some(format_smolstr!( - "expected Motion(Full) for subquery child ({sq_id})" + "expected Motion(Full) for subquery child ({sq_id:?})" )), )); } @@ -659,7 +659,7 @@ impl Plan { fn dist_from_child( &self, - child_rel_node: usize, + child_rel_node: NodeId, child_pos_map: &AHashMap<ChildColumnReference, ParentColumnPosition>, ) -> Result<Distribution, SbroadError> { if let Node::Relational(relational_op) = self.get_node(child_rel_node)? { @@ -724,7 +724,7 @@ impl Plan { /// /// # Errors /// - supplied node is `Row` - pub fn set_dist(&mut self, row_id: usize, dist: Distribution) -> Result<(), SbroadError> { + pub fn set_dist(&mut self, row_id: NodeId, dist: Distribution) -> Result<(), SbroadError> { if let Expression::Row { ref mut distribution, .. @@ -742,10 +742,10 @@ impl Plan { fn set_two_children_node_dist( &mut self, child_pos_map: &AHashMap<ChildColumnReference, ParentColumnPosition>, - left_id: usize, - right_id: usize, - parent_id: usize, - row_id: usize, + left_id: NodeId, + right_id: NodeId, + parent_id: NodeId, + row_id: NodeId, ) -> Result<(), SbroadError> { let left_dist = self.dist_from_child(left_id, child_pos_map)?; let right_dist = self.dist_from_child(right_id, child_pos_map)?; @@ -785,7 +785,7 @@ impl Plan { /// /// # Errors /// - Node is not of a row type. - pub fn get_distribution(&self, row_id: usize) -> Result<&Distribution, SbroadError> { + pub fn get_distribution(&self, row_id: NodeId) -> Result<&Distribution, SbroadError> { match self.get_node(row_id)? { Node::Expression(expr) => expr.distribution(), Node::Relational(_) => Err(SbroadError::Invalid( @@ -819,7 +819,7 @@ impl Plan { /// # Errors /// - Node is not realtional /// - Node is not of a row type. - pub fn get_rel_distribution(&self, rel_id: usize) -> Result<&Distribution, SbroadError> { + pub fn get_rel_distribution(&self, rel_id: NodeId) -> Result<&Distribution, SbroadError> { self.get_distribution(self.get_relation_node(rel_id)?.output()) } @@ -831,7 +831,7 @@ impl Plan { /// - row contains broken references pub fn get_or_init_distribution( &mut self, - row_id: usize, + row_id: NodeId, ) -> Result<&Distribution, SbroadError> { if let Err(SbroadError::Invalid(Entity::Distribution, _)) = self.get_distribution(row_id) { self.set_distribution(row_id)?; diff --git a/sbroad-core/src/ir/distribution/tests.rs b/sbroad-core/src/ir/distribution/tests.rs index 70eee98b4..342a394e7 100644 --- a/sbroad-core/src/ir/distribution/tests.rs +++ b/sbroad-core/src/ir/distribution/tests.rs @@ -6,8 +6,6 @@ use crate::ir::tree::traversal::{PostOrder, REL_CAPACITY}; use crate::ir::{Node, Plan}; use pretty_assertions::assert_eq; use smol_str::SmolStr; -use std::fs; -use std::path::Path; #[test] fn proj_preserve_dist_key() { @@ -33,7 +31,7 @@ fn proj_preserve_dist_key() { plan.top = Some(proj_id); - let scan_output: usize = if let Node::Relational(scan) = plan.get_node(scan_id).unwrap() { + let scan_output: NodeId = if let Node::Relational(scan) = plan.get_node(scan_id).unwrap() { scan.output() } else { panic!("Invalid plan!"); @@ -47,7 +45,7 @@ fn proj_preserve_dist_key() { ); } - let proj_output: usize = if let Node::Relational(proj) = plan.get_node(proj_id).unwrap() { + let proj_output: NodeId = if let Node::Relational(proj) = plan.get_node(proj_id).unwrap() { proj.output() } else { panic!("Invalid plan!"); @@ -62,101 +60,6 @@ fn proj_preserve_dist_key() { } } -#[test] -fn proj_shuffle_dist_key() { - // Load a table "t (a, b, c, d)" distributed by ["b", "a"] - // with projection ["a", "b"]. - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("distribution") - .join("shuffle_dist_key.yaml"); - let s = fs::read_to_string(path).unwrap(); - let mut plan = Plan::from_yaml(&s).unwrap(); - - let scan_output = 8; - let proj_output = 14; - - plan.set_distribution(scan_output).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(scan_output).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1, 0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } - - plan.set_distribution(proj_output).unwrap(); - if let Node::Expression(proj_row) = plan.get_node(proj_output).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0, 1]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - proj_row.distribution().unwrap() - ); - } -} - -#[test] -fn proj_shrink_dist_key_1() { - // Load a table "t (a, b, c, d)" distributed by ["b", "a"] - // with projection ["c", "a"]. - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("distribution") - .join("shrink_dist_key_1.yaml"); - let s = fs::read_to_string(path).unwrap(); - let mut plan = Plan::from_yaml(&s).unwrap(); - - let scan_output = 8; - let proj_output = 14; - - plan.set_distribution(scan_output).unwrap(); - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1, 0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - plan.get_distribution(scan_output).unwrap() - ); - - plan.set_distribution(proj_output).unwrap(); - assert_eq!( - &Distribution::Any, - plan.get_distribution(proj_output).unwrap() - ); -} - -#[test] -fn proj_shrink_dist_key_2() { - // Load a table "t (a, b, c, d)" distributed by ["b", "a"] - // with projection ["a"]. - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("distribution") - .join("shrink_dist_key_2.yaml"); - let s = fs::read_to_string(path).unwrap(); - let mut plan = Plan::from_yaml(&s).unwrap(); - - let scan_output = 8; - let proj_output = 12; - - plan.set_distribution(scan_output).unwrap(); - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1, 0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - plan.get_distribution(scan_output).unwrap() - ); - - plan.set_distribution(proj_output).unwrap(); - assert_eq!( - &Distribution::Any, - plan.get_distribution(proj_output).unwrap() - ); -} - #[test] fn projection_any_dist_for_expr() { let input = r#"select count("id") FROM "test_space""#; @@ -182,9 +85,9 @@ vtable_max_rows = 5000 let local_proj_id = { let mut dfs = PostOrder::with_capacity(|x| plan.nodes.rel_iter(x), REL_CAPACITY); dfs.iter(plan.top.unwrap()) - .find(|(_, x)| { + .find(|level_node| { matches!( - plan.get_relation_node(*x).unwrap(), + plan.get_relation_node(level_node.1).unwrap(), Relational::Projection { .. } ) }) @@ -197,156 +100,4 @@ vtable_max_rows = 5000 .unwrap() ); } - -#[test] -fn union_all_fallback_to_random() { - // Load table "t1 (a, b)" distributed by ["a"], - // table "t2 (a, b)" distributed by ["b"], - // union all (t1, t2) - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("distribution") - .join("union_fallback_to_random.yaml"); - let s = fs::read_to_string(path).unwrap(); - let mut plan = Plan::from_yaml(&s).unwrap(); - - let scan_t1_output = 4; - let scan_t2_output = 10; - let union_output = 16; - - plan.set_distribution(scan_t1_output).unwrap(); - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - plan.get_distribution(scan_t1_output).unwrap() - ); - - plan.set_distribution(scan_t2_output).unwrap(); - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - plan.get_distribution(scan_t2_output).unwrap() - ); - - plan.set_distribution(union_output).unwrap(); - assert_eq!( - &Distribution::Any, - plan.get_distribution(union_output).unwrap() - ); -} - -#[test] -fn union_preserve_dist() { - // Load table "t1 (a, b)" distributed by ["a"], - // table "t2 (a, b)" distributed by ["b"], - // union all (t1, t2) - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("distribution") - .join("union_preserve_dist.yaml"); - let s = fs::read_to_string(path).unwrap(); - let mut plan = Plan::from_yaml(&s).unwrap(); - - let scan_t1_output = 4; - let scan_t2_output = 10; - let union_output = 16; - - plan.set_distribution(scan_t1_output).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(scan_t1_output).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } - - plan.set_distribution(scan_t2_output).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(scan_t2_output).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } - - plan.set_distribution(union_output).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(union_output).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } -} - -#[test] -fn join_unite_keys() { - // Load table "t1 (a, b)" distributed by ["a"], - // table "t2 (c, d)" distributed by ["d"], - // select * from t1 join t2 on t1.a = t2.d - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("distribution") - .join("join_unite_keys.yaml"); - let s = fs::read_to_string(path).unwrap(); - let mut plan = Plan::from_yaml(&s).unwrap(); - let scan_t1_output = 4; - let scan_t2_output = 10; - let join_output = 27; - let t1_a = 14; - let t2_d = 17; - - plan.set_distribution(scan_t1_output).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(scan_t1_output).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } - - plan.set_distribution(scan_t2_output).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(scan_t2_output).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } - - plan.set_distribution(join_output).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(join_output).unwrap() { - let keys: HashSet<_, RepeatableState> = - collection! { Key::new(vec![0]), Key::new(vec![3]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } - - plan.set_distribution(t1_a).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(t1_a).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } - - plan.set_distribution(t2_d).unwrap(); - if let Node::Expression(scan_row) = plan.get_node(t2_d).unwrap() { - let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![0]) }; - assert_eq!( - &Distribution::Segment { keys: keys.into() }, - scan_row.distribution().unwrap() - ); - } -} - //TODO: add other distribution variants to the test cases. diff --git a/sbroad-core/src/ir/explain.rs b/sbroad-core/src/ir/explain.rs index 53c1ddffe..60c010450 100644 --- a/sbroad-core/src/ir/explain.rs +++ b/sbroad-core/src/ir/explain.rs @@ -19,7 +19,7 @@ use crate::ir::transformation::redistribution::{ }; use crate::ir::{OptionKind, Plan}; -use super::expression::FunctionFeature; +use super::expression::{FunctionFeature, NodeId}; use super::operator::{Arithmetic, Bool, Unary}; use super::tree::traversal::{PostOrder, EXPR_CAPACITY, REL_CAPACITY}; use super::value::Value; @@ -123,14 +123,15 @@ impl ColExpr { #[allow(dead_code, clippy::too_many_lines)] fn new( plan: &Plan, - subtree_top: usize, + subtree_top: NodeId, sq_ref_map: &SubQueryRefMap, ) -> Result<Self, SbroadError> { - let mut stack: Vec<(ColExpr, usize)> = Vec::new(); + let mut stack: Vec<(ColExpr, NodeId)> = Vec::new(); let mut dft_post = PostOrder::with_capacity(|node| plan.nodes.expr_iter(node, false), EXPR_CAPACITY); - for (_, id) in dft_post.iter(subtree_top) { + for level_node in dft_post.iter(subtree_top) { + let id = level_node.1; let current_node = plan.get_expression_node(id)?; match ¤t_node { @@ -192,7 +193,7 @@ impl ColExpr { Expression::Reference { position, .. } => { let mut col_name = String::new(); - let rel_id: usize = *plan.get_relational_from_reference_node(id)?; + let rel_id = *plan.get_relational_from_reference_node(id)?; let rel_node = plan.get_relation_node(rel_id)?; if let Some(name) = rel_node.scan_name(plan, *position)? { @@ -268,7 +269,7 @@ impl ColExpr { } Expression::Row { list, .. } => { let mut len = list.len(); - let mut row: Vec<(ColExpr, usize)> = Vec::with_capacity(len); + let mut row: Vec<(ColExpr, NodeId)> = Vec::with_capacity(len); while len > 0 { let expr = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( @@ -361,7 +362,7 @@ impl ColExpr { /// Alias for map of (`SubQuery` id -> it's offset). /// Offset = `SubQuery` index (e.g. in case there are several `SubQueries` in Selection WHERE condition /// index will indicate to which of them Reference is pointing). -type SubQueryRefMap = HashMap<usize, usize>; +type SubQueryRefMap = HashMap<NodeId, usize>; #[derive(Debug, PartialEq, Serialize)] struct Projection { @@ -373,7 +374,7 @@ impl Projection { #[allow(dead_code)] fn new( plan: &Plan, - output_id: usize, + output_id: NodeId, sq_ref_map: &SubQueryRefMap, ) -> Result<Self, SbroadError> { let mut result = Projection { cols: vec![] }; @@ -416,8 +417,8 @@ impl GroupBy { #[allow(dead_code)] fn new( plan: &Plan, - gr_cols: &Vec<usize>, - output_id: usize, + gr_cols: &Vec<NodeId>, + output_id: NodeId, sq_ref_map: &SubQueryRefMap, ) -> Result<Self, SbroadError> { let mut result = GroupBy { @@ -547,7 +548,7 @@ struct Update { impl Update { #[allow(dead_code)] - fn new(plan: &Plan, update_id: usize) -> Result<Self, SbroadError> { + fn new(plan: &Plan, update_id: NodeId) -> Result<Self, SbroadError> { if let Relational::Update { relation: ref rel, update_columns_map, @@ -609,7 +610,7 @@ impl Update { Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "explain: expected Update node on id: {update_id}" + "explain: expected Update node on id: {update_id:?}" )), )) } @@ -714,7 +715,7 @@ impl Row { fn from_col_exprs_with_ids( plan: &Plan, - exprs_with_ids: &mut Vec<(ColExpr, usize)>, + exprs_with_ids: &mut Vec<(ColExpr, NodeId)>, sq_ref_map: &SubQueryRefMap, ) -> Result<Self, SbroadError> { let mut row = Row::new(); @@ -724,7 +725,7 @@ impl Row { match ¤t_node { Expression::Reference { .. } => { - let rel_id: usize = *plan.get_relational_from_reference_node(expr_id)?; + let rel_id = *plan.get_relational_from_reference_node(expr_id)?; let rel_node = plan.get_relation_node(rel_id)?; if plan.is_additional_child(rel_id)? { @@ -734,7 +735,7 @@ impl Row { let sq_offset = sq_ref_map.get(&rel_id).ok_or_else(|| { SbroadError::NotFound( Entity::SubQuery, - format_smolstr!("with index {rel_id} in the map"), + format_smolstr!("with index {rel_id:?} in the map"), ) })?; row.add_col(RowVal::SqRef(Ref::new(*sq_offset))); @@ -742,7 +743,7 @@ impl Row { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "additional child ({rel_id}) is not SQ or Motion: {rel_node:?}" + "additional child ({rel_id:?}) is not SQ or Motion: {rel_node:?}" )), )); } @@ -1030,7 +1031,7 @@ impl Display for FullExplain { impl FullExplain { #[allow(dead_code)] #[allow(clippy::too_many_lines)] - pub fn new(ir: &Plan, top_id: usize) -> Result<Self, SbroadError> { + pub fn new(ir: &Plan, top_id: NodeId) -> Result<Self, SbroadError> { let mut stack: Vec<ExplainTreePart> = Vec::with_capacity(ir.nodes.relation_node_amount()); let mut result = FullExplain::default(); result @@ -1042,7 +1043,9 @@ impl FullExplain { )); let mut dft_post = PostOrder::with_capacity(|node| ir.nodes.rel_iter(node), REL_CAPACITY); - for (level, id) in dft_post.iter(top_id) { + for level_node in dft_post.iter(top_id) { + let level = level_node.0; + let id = level_node.1; let mut current_node = ExplainTreePart::with_level(level); let node = ir.get_relation_node(id)?; current_node.current = match &node { diff --git a/sbroad-core/src/ir/expression.rs b/sbroad-core/src/ir/expression.rs index e9b9eeefe..df68c1940 100644 --- a/sbroad-core/src/ir/expression.rs +++ b/sbroad-core/src/ir/expression.rs @@ -10,6 +10,7 @@ use ahash::RandomState; use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr}; use std::collections::{BTreeMap, HashSet}; +use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; use std::ops::Bound::Included; @@ -23,13 +24,34 @@ use crate::ir::Positions as Targets; use super::distribution::Distribution; use super::tree::traversal::{PostOrderWithFilter, EXPR_CAPACITY}; use super::value::Value; -use super::{operator, Node, Nodes, Plan}; +use super::{operator, ArenaType, Node, Nodes, Plan}; pub mod cast; pub mod concat; pub mod types; -pub(crate) type ExpressionId = usize; +pub(crate) type ExpressionId = NodeId; + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Hash, Copy)] +pub struct NodeId { + pub offset: u32, + pub arena_type: ArenaType, +} + +impl Display for NodeId { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.offset, self.arena_type) + } +} + +impl Default for NodeId { + fn default() -> Self { + NodeId { + offset: 0, + arena_type: ArenaType::Default, + } + } +} /// Tuple tree build blocks. /// @@ -51,18 +73,18 @@ pub enum Expression { /// Alias name. name: SmolStr, /// Child expression node index in the plan node arena. - child: usize, + child: NodeId, }, /// Binary expression returning boolean result. /// /// Example: `a > 42`, `b in (select c from ...)`. Bool { /// Left branch expression node index in the plan node arena. - left: usize, + left: NodeId, /// Boolean operator. op: operator::Bool, /// Right branch expression node index in the plan node arena. - right: usize, + right: NodeId, }, /// Binary expression returning row result. /// @@ -71,18 +93,18 @@ pub enum Expression { /// TODO: always cover children with parentheses (in to_sql). Arithmetic { /// Left branch expression node index in the plan node arena. - left: usize, + left: NodeId, /// Arithmetic operator. op: operator::Arithmetic, /// Right branch expression node index in the plan node arena. - right: usize, + right: NodeId, }, /// Type cast expression. /// /// Example: `cast(a as text)`. Cast { /// Target expression that must be casted to another type. - child: usize, + child: NodeId, /// Cast type. to: cast::Type, }, @@ -91,9 +113,9 @@ pub enum Expression { /// Example: `a || 'hello'`. Concat { /// Left expression node id. - left: usize, + left: NodeId, /// Right expression node id. - right: usize, + right: NodeId, }, /// Constant expressions. /// @@ -109,7 +131,7 @@ pub enum Expression { /// - column position in the child(ren) output tuple Reference { /// Relational node ID that contains current reference. - parent: Option<usize>, + parent: Option<NodeId>, /// Targets in the relational node children list. /// - Leaf nodes (relation scans): None. /// - Union nodes: two elements (left and right). @@ -130,7 +152,7 @@ pub enum Expression { /// Example: (a, b, 1). Row { /// A list of the alias expression node indexes in the plan node arena. - list: Vec<usize>, + list: Vec<NodeId>, /// Resulting data distribution of the tuple. Should be filled as a part /// of the last "add Motion" transformation. distribution: Option<Distribution>, @@ -146,7 +168,7 @@ pub enum Expression { /// Function name. name: SmolStr, /// Function arguments. - children: Vec<usize>, + children: Vec<NodeId>, /// Optional function feature. feature: Option<FunctionFeature>, /// Function return type. @@ -162,26 +184,26 @@ pub enum Expression { /// Trim kind. kind: Option<TrimKind>, /// Trim string pattern to remove (it can be an expression). - pattern: Option<usize>, + pattern: Option<NodeId>, /// Target expression to trim. - target: usize, + target: NodeId, }, /// Unary expression returning boolean result. Unary { /// Unary operator. op: operator::Unary, /// Child expression node index in the plan node arena. - child: usize, + child: NodeId, }, /// Argument of `count` aggregate in `count(*)` expression CountAsterisk, ExprInParentheses { - child: usize, + child: NodeId, }, Case { - search_expr: Option<usize>, - when_blocks: Vec<(usize, usize)>, - else_expr: Option<usize>, + search_expr: Option<NodeId>, + when_blocks: Vec<(NodeId, NodeId)>, + else_expr: Option<NodeId>, }, } @@ -236,7 +258,7 @@ impl Expression { /// /// # Errors /// - node isn't `Row` - pub fn clone_row_list(&self) -> Result<Vec<usize>, SbroadError> { + pub fn clone_row_list(&self) -> Result<Vec<NodeId>, SbroadError> { match self { Expression::Row { list, .. } => Ok(list.clone()), _ => Err(SbroadError::Invalid( @@ -264,7 +286,7 @@ impl Expression { /// /// # Errors /// - node isn't `Row` - pub fn get_row_list(&self) -> Result<&[usize], SbroadError> { + pub fn get_row_list(&self) -> Result<&[NodeId], SbroadError> { match self { Expression::Row { ref list, .. } => Ok(list), _ => Err(SbroadError::Invalid( @@ -278,7 +300,7 @@ impl Expression { /// /// # Errors /// - node isn't `Row` - pub fn get_mut_row_list(&mut self) -> Result<&mut Vec<usize>, SbroadError> { + pub fn get_mut_row_list(&mut self) -> Result<&mut Vec<NodeId>, SbroadError> { match self { Expression::Row { ref mut list, .. } => Ok(list), _ => Err(SbroadError::Invalid( @@ -292,7 +314,7 @@ impl Expression { /// /// # Errors /// - node isn't `Row` - pub fn get_row_list_mut(&mut self) -> Result<&mut Vec<usize>, SbroadError> { + pub fn get_row_list_mut(&mut self) -> Result<&mut Vec<NodeId>, SbroadError> { match self { Expression::Row { ref mut list, .. } => Ok(list), _ => Err(SbroadError::Invalid( @@ -330,7 +352,7 @@ impl Expression { /// # Errors /// - node isn't reference type /// - reference doesn't have a parent - pub fn get_parent(&self) -> Result<usize, SbroadError> { + pub fn get_parent(&self) -> Result<NodeId, SbroadError> { if let Expression::Reference { parent, .. } = self { return parent.ok_or_else(|| { SbroadError::Invalid(Entity::Expression, Some("Reference has no parent".into())) @@ -353,7 +375,7 @@ impl Expression { } /// Replaces parent in the reference node with the new one. - pub fn replace_parent_in_reference(&mut self, from_id: Option<usize>, to_id: Option<usize>) { + pub fn replace_parent_in_reference(&mut self, from_id: Option<NodeId>, to_id: Option<NodeId>) { if let Expression::Reference { parent, .. } = self { if *parent == from_id { *parent = to_id; @@ -374,7 +396,7 @@ impl Nodes { /// /// # Errors /// - child node is invalid - pub(crate) fn add_covered_with_parentheses(&mut self, child: usize) -> usize { + pub(crate) fn add_covered_with_parentheses(&mut self, child: NodeId) -> NodeId { let covered_with_parentheses = Expression::ExprInParentheses { child }; self.push(Node::Expression(covered_with_parentheses)) } @@ -384,7 +406,7 @@ impl Nodes { /// # Errors /// - child node is invalid /// - name is empty - pub fn add_alias(&mut self, name: &str, child: usize) -> Result<usize, SbroadError> { + pub fn add_alias(&mut self, name: &str, child: NodeId) -> Result<NodeId, SbroadError> { let alias = Expression::Alias { name: SmolStr::from(name), child, @@ -398,17 +420,17 @@ impl Nodes { /// - when left or right nodes are invalid pub fn add_bool( &mut self, - left: usize, + left: NodeId, op: operator::Bool, - right: usize, - ) -> Result<usize, SbroadError> { - self.arena.get(left).ok_or_else(|| { + right: NodeId, + ) -> Result<NodeId, SbroadError> { + self.get(left).ok_or_else(|| { SbroadError::NotFound( Entity::Node, format_smolstr!("(left child of boolean node) from arena with index {left}"), ) })?; - self.arena.get(right).ok_or_else(|| { + self.get(right).ok_or_else(|| { SbroadError::NotFound( Entity::Node, format_smolstr!("(right child of boolean node) from arena with index {right}"), @@ -423,20 +445,20 @@ impl Nodes { /// - when left or right nodes are invalid pub fn add_arithmetic_node( &mut self, - left: usize, + left: NodeId, op: operator::Arithmetic, - right: usize, - ) -> Result<usize, SbroadError> { - self.arena.get(left).ok_or_else(|| { + right: NodeId, + ) -> Result<NodeId, SbroadError> { + self.get(left).ok_or_else(|| { SbroadError::NotFound( Entity::Node, - format_smolstr!("(left child of Arithmetic node) from arena with index {left}"), + format_smolstr!("(left child of Arithmetic node) from arena with index {left:?}"), ) })?; - self.arena.get(right).ok_or_else(|| { + self.get(right).ok_or_else(|| { SbroadError::NotFound( Entity::Node, - format_smolstr!("(right child of Arithmetic node) from arena with index {right}"), + format_smolstr!("(right child of Arithmetic node) from arena with index {right:?}"), ) })?; Ok(self.push(Node::Expression(Expression::Arithmetic { left, op, right }))) @@ -445,11 +467,11 @@ impl Nodes { /// Adds reference node. pub fn add_ref( &mut self, - parent: Option<usize>, + parent: Option<NodeId>, targets: Option<Vec<usize>>, position: usize, col_type: Type, - ) -> usize { + ) -> NodeId { let r = Expression::Reference { parent, targets, @@ -460,7 +482,7 @@ impl Nodes { } /// Adds row node. - pub fn add_row(&mut self, list: Vec<usize>, distribution: Option<Distribution>) -> usize { + pub fn add_row(&mut self, list: Vec<NodeId>, distribution: Option<Distribution>) -> NodeId { self.push(Node::Expression(Expression::Row { list, distribution })) } @@ -471,9 +493,9 @@ impl Nodes { pub fn add_unary_bool( &mut self, op: operator::Unary, - child: usize, - ) -> Result<usize, SbroadError> { - self.arena.get(child).ok_or_else(|| { + child: NodeId, + ) -> Result<NodeId, SbroadError> { + self.get(child).ok_or_else(|| { SbroadError::NotFound( Entity::Node, format_smolstr!("from arena with index {child}"), @@ -487,13 +509,13 @@ impl Nodes { // plan for PlanExpression, try to put it into hasher? but what do // with equality? pub struct PlanExpr<'plan> { - pub id: usize, + pub id: NodeId, pub plan: &'plan Plan, } impl<'plan> PlanExpr<'plan> { #[must_use] - pub fn new(id: usize, plan: &'plan Plan) -> Self { + pub fn new(id: NodeId, plan: &'plan Plan) -> Self { PlanExpr { id, plan } } } @@ -564,7 +586,7 @@ impl<'plan> Comparator<'plan> { /// - invalid [`Expression::Reference`]s in either of subtrees /// - invalid children in some expression #[allow(clippy::too_many_lines)] - pub fn are_subtrees_equal(&self, lhs: usize, rhs: usize) -> Result<bool, SbroadError> { + pub fn are_subtrees_equal(&self, lhs: NodeId, rhs: NodeId) -> Result<bool, SbroadError> { let l = self.plan.get_node(lhs)?; let r = self.plan.get_node(rhs)?; if let Node::Expression(left) = l { @@ -776,7 +798,7 @@ impl<'plan> Comparator<'plan> { Ok(false) } - pub fn hash_for_child_expr(&mut self, child: usize, depth: usize) { + pub fn hash_for_child_expr(&mut self, child: NodeId, depth: usize) { self.hash_for_expr(child, depth - 1); } @@ -786,7 +808,7 @@ impl<'plan> Comparator<'plan> { /// # Panics /// - Comparator hasher wasn't set. #[allow(clippy::too_many_lines)] - pub fn hash_for_expr(&mut self, top: usize, depth: usize) { + pub fn hash_for_expr(&mut self, top: NodeId, depth: usize) { if depth == 0 { return; } @@ -948,7 +970,7 @@ pub(crate) struct ColumnPositionMap { } impl ColumnPositionMap { - pub(crate) fn new(plan: &Plan, rel_id: usize) -> Result<Self, SbroadError> { + pub(crate) fn new(plan: &Plan, rel_id: NodeId) -> Result<Self, SbroadError> { let rel_node = plan.get_relation_node(rel_id)?; let output = plan.get_expression_node(rel_node.output())?; let alias_ids = output.get_row_list()?; @@ -1110,18 +1132,18 @@ pub enum JoinTargets<'targets> { #[derive(Debug)] pub enum NewColumnsSource<'targets> { Join { - outer_child: usize, - inner_child: usize, + outer_child: NodeId, + inner_child: NodeId, targets: JoinTargets<'targets>, }, /// Enum variant used both for Except and UnionAll operators. ExceptUnion { - left_child: usize, - right_child: usize, + left_child: NodeId, + right_child: NodeId, }, /// Other relational nodes. Other { - child: usize, + child: NodeId, columns_spec: Option<ColumnsRetrievalSpec<'targets>>, }, } @@ -1134,9 +1156,9 @@ pub struct NewColumnSourceIterator<'iter> { impl<'targets> Iterator for NewColumnSourceIterator<'targets> { // Pair of (relational node id, target id) - type Item = (usize, usize); + type Item = (NodeId, usize); - fn next(&mut self) -> Option<(usize, usize)> { + fn next(&mut self) -> Option<(NodeId, usize)> { let result = match &self.source { NewColumnsSource::Join { outer_child, @@ -1178,7 +1200,7 @@ impl<'targets> Iterator for NewColumnSourceIterator<'targets> { } impl<'iter, 'source: 'iter> IntoIterator for &'source NewColumnsSource<'iter> { - type Item = (usize, usize); + type Item = (NodeId, usize); type IntoIter = NewColumnSourceIterator<'iter>; fn into_iter(self) -> Self::IntoIter { @@ -1226,7 +1248,7 @@ impl<'source> NewColumnsSource<'source> { impl Plan { /// Add `Row` to plan. - pub fn add_row(&mut self, list: Vec<usize>, distribution: Option<Distribution>) -> usize { + pub fn add_row(&mut self, list: Vec<NodeId>, distribution: Option<Distribution>) -> NodeId { self.nodes.add_row(list, distribution) } @@ -1248,9 +1270,9 @@ impl Plan { source: &NewColumnsSource, need_aliases: bool, need_sharding_column: bool, - ) -> Result<Vec<usize>, SbroadError> { + ) -> Result<Vec<NodeId>, SbroadError> { // Vec of (column position in child output, column plan id, new_targets). - let mut filtered_children_row_list: Vec<(usize, usize, Vec<usize>)> = Vec::new(); + let mut filtered_children_row_list: Vec<(usize, NodeId, Vec<usize>)> = Vec::new(); // Helper lambda to retrieve column positions we need to exclude from child `rel_id`. let column_positions_to_exclude = |rel_id| -> Result<Targets, SbroadError> { @@ -1332,7 +1354,7 @@ impl Plan { }; // List of columns to be passed into `Expression::Row`. - let mut result_row_list: Vec<usize> = Vec::with_capacity(filtered_children_row_list.len()); + let mut result_row_list: Vec<NodeId> = Vec::with_capacity(filtered_children_row_list.len()); for (pos, alias_node_id, new_targets) in filtered_children_row_list { let alias_expr = self.get_expression_node(alias_node_id)?; let alias_name = SmolStr::from(alias_expr.get_alias_name()?); @@ -1358,10 +1380,10 @@ impl Plan { /// - child is an inconsistent relational node pub fn add_row_by_indices( &mut self, - rel_node: usize, + rel_node: NodeId, indices: Vec<usize>, need_sharding_column: bool, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let list = self.new_columns( &NewColumnsSource::Other { child: rel_node, @@ -1382,10 +1404,10 @@ impl Plan { /// - column names don't exist pub fn add_row_for_output( &mut self, - rel_node: usize, + rel_node: NodeId, col_names: &[&str], need_sharding_column: bool, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let specific_columns = if col_names.is_empty() { None } else { @@ -1414,9 +1436,9 @@ impl Plan { /// - children are inconsistent relational nodes pub fn add_row_for_union_except( &mut self, - left: usize, - right: usize, - ) -> Result<usize, SbroadError> { + left: NodeId, + right: NodeId, + ) -> Result<NodeId, SbroadError> { let list = self.new_columns( &NewColumnsSource::ExceptUnion { left_child: left, @@ -1435,7 +1457,7 @@ impl Plan { /// # Errors /// Returns `SbroadError`: /// - children are inconsistent relational nodes - pub fn add_row_for_join(&mut self, left: usize, right: usize) -> Result<usize, SbroadError> { + pub fn add_row_for_join(&mut self, left: NodeId, right: NodeId) -> Result<NodeId, SbroadError> { let list = self.new_columns( &NewColumnsSource::Join { outer_child: left, @@ -1458,9 +1480,9 @@ impl Plan { /// - column names don't exist pub fn add_row_from_child( &mut self, - child: usize, + child: NodeId, col_names: &[&str], - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let specific_columns = if col_names.is_empty() { None } else { @@ -1490,10 +1512,10 @@ impl Plan { /// - children nodes are inconsistent with the target position pub(crate) fn add_row_from_subquery( &mut self, - children: &[usize], + children: &[NodeId], target: usize, - parent: Option<usize>, - ) -> Result<usize, SbroadError> { + parent: Option<NodeId>, + ) -> Result<NodeId, SbroadError> { let sq_id = *children.get(target).ok_or_else(|| { SbroadError::UnexpectedNumberOfValues(format_smolstr!( "invalid target index: {target} (children: {children:?})", @@ -1528,10 +1550,10 @@ impl Plan { /// - column names don't exist pub fn add_row_from_left_branch( &mut self, - left: usize, - right: usize, + left: NodeId, + right: NodeId, col_names: &[ColumnWithScan], - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let list = self.new_columns( &NewColumnsSource::Join { outer_child: left, @@ -1556,10 +1578,10 @@ impl Plan { /// - column names don't exist pub fn add_row_from_right_branch( &mut self, - left: usize, - right: usize, + left: NodeId, + right: NodeId, col_names: &[ColumnWithScan], - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let list = self.new_columns( &NewColumnsSource::Join { outer_child: left, @@ -1581,7 +1603,10 @@ impl Plan { /// /// # Errors /// - reference is invalid - pub fn get_relational_from_reference_node(&self, ref_id: usize) -> Result<&usize, SbroadError> { + pub fn get_relational_from_reference_node( + &self, + ref_id: NodeId, + ) -> Result<&NodeId, SbroadError> { if let Node::Expression(Expression::Reference { targets, parent, .. }) = self.get_node(ref_id)? @@ -1589,7 +1614,7 @@ impl Plan { let Some(referred_rel_id) = parent else { return Err(SbroadError::NotFound( Entity::Node, - format_smolstr!("that is Reference ({ref_id}) parent"), + format_smolstr!("that is Reference ({ref_id:?}) parent"), )); }; let rel = self.get_relation_node(*referred_rel_id)?; @@ -1639,8 +1664,8 @@ impl Plan { /// - `relational_map` is not initialized pub fn get_relational_nodes_from_row( &self, - row_id: usize, - ) -> Result<HashSet<usize, RandomState>, SbroadError> { + row_id: NodeId, + ) -> Result<HashSet<NodeId, RandomState>, SbroadError> { let row = self.get_expression_node(row_id)?; let capacity = if let Expression::Row { list, .. } = row { list.len() @@ -1650,7 +1675,7 @@ impl Plan { Some("Node is not a row".into()), )); }; - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { if let Ok(Node::Expression(Expression::Reference { .. })) = self.get_node(node_id) { return true; } @@ -1664,9 +1689,10 @@ impl Plan { post_tree.populate_nodes(row_id); let nodes = post_tree.take_nodes(); // We don't expect much relational references in a row (5 is a reasonable number). - let mut rel_nodes: HashSet<usize, RandomState> = + let mut rel_nodes: HashSet<NodeId, RandomState> = HashSet::with_capacity_and_hasher(5, RandomState::new()); - for (_, id) in nodes { + for level_node in nodes { + let id = level_node.1; let reference = self.get_expression_node(id)?; if let Expression::Reference { targets, parent, .. @@ -1675,7 +1701,7 @@ impl Plan { let referred_rel_id = parent.ok_or_else(|| { SbroadError::NotFound( Entity::Node, - format_smolstr!("that is Reference ({id}) parent"), + format_smolstr!("that is Reference ({id:?}) parent"), ) })?; let rel = self.get_relation_node(referred_rel_id)?; @@ -1694,7 +1720,7 @@ impl Plan { /// Check that the node is a boolean equality and its children are both rows. #[must_use] - pub fn is_bool_eq_with_rows(&self, node_id: usize) -> bool { + pub fn is_bool_eq_with_rows(&self, node_id: NodeId) -> bool { let Ok(node) = self.get_expression_node(node_id) else { return false; }; @@ -1723,7 +1749,7 @@ impl Plan { /// /// # Errors /// - If node is not an expression. - pub fn is_trivalent(&self, expr_id: usize) -> Result<bool, SbroadError> { + pub fn is_trivalent(&self, expr_id: NodeId) -> Result<bool, SbroadError> { let expr = self.get_expression_node(expr_id)?; match expr { Expression::Bool { .. } @@ -1748,7 +1774,7 @@ impl Plan { /// /// # Errors /// - If node is not an expression. - pub fn is_ref(&self, expr_id: usize) -> Result<bool, SbroadError> { + pub fn is_ref(&self, expr_id: NodeId) -> Result<bool, SbroadError> { let expr = self.get_expression_node(expr_id)?; match expr { Expression::Reference { .. } => return Ok(true), @@ -1771,7 +1797,7 @@ impl Plan { #[allow(dead_code)] pub fn get_child_const_from_row( &self, - row_id: usize, + row_id: NodeId, child_num: usize, ) -> Result<Value, SbroadError> { let node = self.get_expression_node(row_id)?; @@ -1797,11 +1823,11 @@ impl Plan { /// - node is not an expression pub fn replace_parent_in_subtree( &mut self, - node_id: usize, - from_id: Option<usize>, - to_id: Option<usize>, + node_id: NodeId, + from_id: Option<NodeId>, + to_id: Option<NodeId>, ) -> Result<(), SbroadError> { - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { if let Ok(Node::Expression(Expression::Reference { .. })) = self.get_node(node_id) { return true; } @@ -1815,7 +1841,8 @@ impl Plan { subtree.populate_nodes(node_id); let references = subtree.take_nodes(); drop(subtree); - for (_, id) in references { + for level_node in references { + let id = level_node.1; let node = self.get_mut_expression_node(id)?; node.replace_parent_in_reference(from_id, to_id); } @@ -1827,8 +1854,8 @@ impl Plan { /// # Errors /// - node is invalid /// - node is not an expression - pub fn flush_parent_in_subtree(&mut self, node_id: usize) -> Result<(), SbroadError> { - let filter = |node_id: usize| -> bool { + pub fn flush_parent_in_subtree(&mut self, node_id: NodeId) -> Result<(), SbroadError> { + let filter = |node_id: NodeId| -> bool { if let Ok(Node::Expression(Expression::Reference { .. })) = self.get_node(node_id) { return true; } @@ -1842,7 +1869,8 @@ impl Plan { subtree.populate_nodes(node_id); let references = subtree.take_nodes(); drop(subtree); - for (_, id) in references { + for level_node in references { + let id = level_node.1; let node = self.get_mut_expression_node(id)?; node.flush_parent_in_reference(); } diff --git a/sbroad-core/src/ir/expression/cast.rs b/sbroad-core/src/ir/expression/cast.rs index 4005fad34..d4a07d55b 100644 --- a/sbroad-core/src/ir/expression/cast.rs +++ b/sbroad-core/src/ir/expression/cast.rs @@ -8,6 +8,8 @@ use crate::ir::{Node, Plan}; use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; +use super::NodeId; + #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)] pub enum Type { Any, @@ -130,7 +132,7 @@ impl Plan { /// /// # Errors /// - Child node is not of the expression type. - pub fn add_cast(&mut self, expr_id: usize, to_type: Type) -> Result<usize, SbroadError> { + pub fn add_cast(&mut self, expr_id: NodeId, to_type: Type) -> Result<NodeId, SbroadError> { let cast_expr = Expression::Cast { child: expr_id, to: to_type, diff --git a/sbroad-core/src/ir/expression/concat.rs b/sbroad-core/src/ir/expression/concat.rs index 021ee508c..09e637988 100644 --- a/sbroad-core/src/ir/expression/concat.rs +++ b/sbroad-core/src/ir/expression/concat.rs @@ -2,12 +2,14 @@ use crate::errors::SbroadError; use crate::ir::expression::Expression; use crate::ir::{Node, Plan}; +use super::NodeId; + impl Plan { /// Add concatenation expression to the IR plan. /// /// # Errors /// - Left or right child nodes are not of the expression type. - pub fn add_concat(&mut self, left_id: usize, right_id: usize) -> Result<usize, SbroadError> { + pub fn add_concat(&mut self, left_id: NodeId, right_id: NodeId) -> Result<NodeId, SbroadError> { // Check that both children are of expression type. for child_id in &[left_id, right_id] { self.get_expression_node(*child_id)?; diff --git a/sbroad-core/src/ir/expression/types.rs b/sbroad-core/src/ir/expression/types.rs index b879baf06..0122fe56c 100644 --- a/sbroad-core/src/ir/expression/types.rs +++ b/sbroad-core/src/ir/expression/types.rs @@ -5,8 +5,10 @@ use crate::{ ir::{expression::Expression, relation::Type, Node, Plan}, }; +use super::NodeId; + impl Plan { - fn get_node_type(&self, node_id: usize) -> Result<Type, SbroadError> { + fn get_node_type(&self, node_id: NodeId) -> Result<Type, SbroadError> { match self.get_node(node_id)? { Node::Expression(expr) => expr.calculate_type(self), Node::Relational(relational) => Err(SbroadError::Invalid( diff --git a/sbroad-core/src/ir/function.rs b/sbroad-core/src/ir/function.rs index c7bea0939..5732bef6d 100644 --- a/sbroad-core/src/ir/function.rs +++ b/sbroad-core/src/ir/function.rs @@ -7,7 +7,7 @@ use crate::ir::{Node, Plan}; use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; -use super::expression::FunctionFeature; +use super::expression::{FunctionFeature, NodeId}; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub enum Behavior { @@ -61,9 +61,9 @@ impl Plan { pub fn add_stable_function( &mut self, function: &Function, - children: Vec<usize>, + children: Vec<NodeId>, feature: Option<FunctionFeature>, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { if !function.is_stable() { return Err(SbroadError::Invalid( Entity::SQLFunction, @@ -92,9 +92,9 @@ impl Plan { &mut self, function: &str, kind: AggregateKind, - children: Vec<usize>, + children: Vec<NodeId>, is_distinct: bool, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { match kind { AggregateKind::GRCONCAT => { if children.len() > 2 || children.is_empty() { diff --git a/sbroad-core/src/ir/helpers.rs b/sbroad-core/src/ir/helpers.rs index 1041a84b2..7c59ef618 100644 --- a/sbroad-core/src/ir/helpers.rs +++ b/sbroad-core/src/ir/helpers.rs @@ -12,6 +12,8 @@ use std::collections::hash_map::DefaultHasher; use std::fmt::Write; use std::hash::BuildHasher; +use super::expression::NodeId; + /// Helper macros to build a hash map or set /// from the list of arguments. #[macro_export] @@ -75,7 +77,7 @@ impl Plan { &self, buf: &mut String, tabulation_number: i32, - node_id: usize, + node_id: NodeId, ) -> Result<(), std::fmt::Error> { let expr_try = self.get_expression_node(node_id); if let Ok(expr) = expr_try { @@ -211,7 +213,7 @@ impl Plan { &self, buf: &mut String, tabulation_number: i32, - node_id: usize, + node_id: NodeId, ) -> Result<(), std::fmt::Error> { if tabulation_number == 0 { writeln!(buf, "---------------------------------------------")?; @@ -293,7 +295,7 @@ impl Plan { let text = if let Ok(gl_col_expr) = gl_col_expr { format!("Gr_col: {gl_col_expr:?}") } else { - format!("Gr_col: {gr_col}") + format!("Gr_col: {gr_col:?}") }; writeln_with_tabulation(buf, tabulation_number + 2, text.as_str())?; } @@ -428,14 +430,15 @@ impl Plan { /// /// # Errors /// Fail to format one of the relational node. - pub fn formatted_arena_subtree(&self, node_id: usize) -> Result<String, SbroadError> { + pub fn formatted_arena_subtree(&self, node_id: NodeId) -> Result<String, SbroadError> { let mut ir_tree = PostOrder::with_capacity(|node| self.nodes.rel_iter(node), EXPR_CAPACITY); ir_tree.populate_nodes(node_id); let nodes = ir_tree.take_nodes(); let mut buf = String::new(); - for (_, id) in &nodes { - if self.formatted_arena_node(&mut buf, 0, *id).is_err() { + for level_node in &nodes { + let id = level_node.1; + if self.formatted_arena_node(&mut buf, 0, id).is_err() { return Err(SbroadError::FailedTo( Action::Serialize, Some(Entity::Plan), @@ -497,7 +500,7 @@ impl SyntaxPlan<'_> { if let SyntaxData::PlanId(id) = data { let node = plan.get_node(*id); if let Ok(node) = node { - writeln!(buf, "{node:?} [id={id}]")?; + writeln!(buf, "{node:?} [id={id:?}]")?; } } else { writeln!(buf, "{data:?}")?; diff --git a/sbroad-core/src/ir/helpers/tests.rs b/sbroad-core/src/ir/helpers/tests.rs index 8be08bb6a..a910c1fa6 100644 --- a/sbroad-core/src/ir/helpers/tests.rs +++ b/sbroad-core/src/ir/helpers/tests.rs @@ -1,10 +1,10 @@ -use crate::ir::transformation::helpers::sql_to_optimized_ir; +use crate::ir::{expression::NodeId, transformation::helpers::sql_to_optimized_ir, ArenaType}; use pretty_assertions::assert_eq; #[test] fn simple_select() { let query = r#"SELECT "product_code" FROM "hash_testing""#; - let mut plan = sql_to_optimized_ir(query, vec![]); + let plan = sql_to_optimized_ir(query, vec![]); let actual_arena = plan.formatted_arena().unwrap(); @@ -17,11 +17,11 @@ fn simple_select() { Output_id: 10 [id: 10] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [id: 1] expression: Alias [name = identification_number, child = Reference { parent: Some(11), targets: None, position: 0, col_type: Integer }] - [id: 3] expression: Alias [name = product_code, child = Reference { parent: Some(11), targets: None, position: 1, col_type: String }] - [id: 5] expression: Alias [name = product_units, child = Reference { parent: Some(11), targets: None, position: 2, col_type: Boolean }] - [id: 7] expression: Alias [name = sys_op, child = Reference { parent: Some(11), targets: None, position: 3, col_type: Unsigned }] - [id: 9] expression: Alias [name = bucket_id, child = Reference { parent: Some(11), targets: None, position: 4, col_type: Unsigned }] + [id: 1] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 0, col_type: Integer }] + [id: 3] expression: Alias [name = product_code, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 1, col_type: String }] + [id: 5] expression: Alias [name = product_units, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 2, col_type: Boolean }] + [id: 7] expression: Alias [name = sys_op, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 3, col_type: Unsigned }] + [id: 9] expression: Alias [name = bucket_id, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 4, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 15] relation: Projection @@ -30,7 +30,7 @@ fn simple_select() { Output_id: 14 [id: 14] expression: Row [distribution = Some(Any)] List: - [id: 13] expression: Alias [name = product_code, child = Reference { parent: Some(15), targets: Some([0]), position: 1, col_type: String }] + [id: 13] expression: Alias [name = product_code, child = Reference { parent: Some(NodeId { offset: 15, arena_type: Default }), targets: Some([0]), position: 1, col_type: String }] --------------------------------------------- "#); @@ -44,7 +44,7 @@ fn simple_join() { INNER JOIN (SELECT "identification_number" FROM "hash_testing") as "t2" ON "t1"."id" = "t2"."identification_number""#; - let mut plan = sql_to_optimized_ir(query, vec![]); + let plan = sql_to_optimized_ir(query, vec![]); let actual_arena = plan.formatted_arena().unwrap(); let mut expected_arena = String::new(); @@ -56,11 +56,11 @@ fn simple_join() { Output_id: 10 [id: 10] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 1] expression: Alias [name = id, child = Reference { parent: Some(11), targets: None, position: 0, col_type: Unsigned }] - [id: 3] expression: Alias [name = sysFrom, child = Reference { parent: Some(11), targets: None, position: 1, col_type: Unsigned }] - [id: 5] expression: Alias [name = FIRST_NAME, child = Reference { parent: Some(11), targets: None, position: 2, col_type: String }] - [id: 7] expression: Alias [name = sys_op, child = Reference { parent: Some(11), targets: None, position: 3, col_type: Unsigned }] - [id: 9] expression: Alias [name = bucket_id, child = Reference { parent: Some(11), targets: None, position: 4, col_type: Unsigned }] + [id: 1] expression: Alias [name = id, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 0, col_type: Unsigned }] + [id: 3] expression: Alias [name = sysFrom, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 1, col_type: Unsigned }] + [id: 5] expression: Alias [name = FIRST_NAME, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 2, col_type: String }] + [id: 7] expression: Alias [name = sys_op, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 3, col_type: Unsigned }] + [id: 9] expression: Alias [name = bucket_id, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 4, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 15] relation: Projection @@ -69,7 +69,7 @@ fn simple_join() { Output_id: 14 [id: 14] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 13] expression: Alias [name = id, child = Reference { parent: Some(15), targets: Some([0]), position: 0, col_type: Unsigned }] + [id: 13] expression: Alias [name = id, child = Reference { parent: Some(NodeId { offset: 15, arena_type: Default }), targets: Some([0]), position: 0, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 19] relation: ScanSubQuery @@ -79,7 +79,7 @@ fn simple_join() { Output_id: 18 [id: 18] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 17] expression: Alias [name = id, child = Reference { parent: Some(19), targets: Some([0]), position: 0, col_type: Unsigned }] + [id: 17] expression: Alias [name = id, child = Reference { parent: Some(NodeId { offset: 19, arena_type: Default }), targets: Some([0]), position: 0, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 31] relation: ScanRelation @@ -88,11 +88,11 @@ fn simple_join() { Output_id: 30 [id: 30] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [id: 21] expression: Alias [name = identification_number, child = Reference { parent: Some(31), targets: None, position: 0, col_type: Integer }] - [id: 23] expression: Alias [name = product_code, child = Reference { parent: Some(31), targets: None, position: 1, col_type: String }] - [id: 25] expression: Alias [name = product_units, child = Reference { parent: Some(31), targets: None, position: 2, col_type: Boolean }] - [id: 27] expression: Alias [name = sys_op, child = Reference { parent: Some(31), targets: None, position: 3, col_type: Unsigned }] - [id: 29] expression: Alias [name = bucket_id, child = Reference { parent: Some(31), targets: None, position: 4, col_type: Unsigned }] + [id: 21] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 0, col_type: Integer }] + [id: 23] expression: Alias [name = product_code, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 1, col_type: String }] + [id: 25] expression: Alias [name = product_units, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 2, col_type: Boolean }] + [id: 27] expression: Alias [name = sys_op, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 3, col_type: Unsigned }] + [id: 29] expression: Alias [name = bucket_id, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 4, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 35] relation: Projection @@ -101,7 +101,7 @@ fn simple_join() { Output_id: 34 [id: 34] expression: Row [distribution = Some(Any)] List: - [id: 33] expression: Alias [name = identification_number, child = Reference { parent: Some(35), targets: Some([0]), position: 0, col_type: Integer }] + [id: 33] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 35, arena_type: Default }), targets: Some([0]), position: 0, col_type: Integer }] --------------------------------------------- --------------------------------------------- [id: 39] relation: ScanSubQuery @@ -111,7 +111,7 @@ fn simple_join() { Output_id: 38 [id: 38] expression: Row [distribution = Some(Any)] List: - [id: 37] expression: Alias [name = identification_number, child = Reference { parent: Some(39), targets: Some([0]), position: 0, col_type: Integer }] + [id: 37] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 39, arena_type: Default }), targets: Some([0]), position: 0, col_type: Integer }] --------------------------------------------- --------------------------------------------- [id: 61] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] @@ -120,7 +120,7 @@ fn simple_join() { Output_id: 60 [id: 60] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 59] expression: Alias [name = identification_number, child = Reference { parent: Some(61), targets: Some([0]), position: 0, col_type: Integer }] + [id: 59] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 61, arena_type: Default }), targets: Some([0]), position: 0, col_type: Integer }] --------------------------------------------- --------------------------------------------- [id: 50] relation: InnerJoin @@ -132,7 +132,7 @@ fn simple_join() { [id: 40] expression: Reference Alias: id Referenced table name (or alias): t1 - Parent: Some(50) + Parent: Some(NodeId { offset: 50, arena_type: Default }) target_id: 0 Column type: unsigned Right child @@ -141,7 +141,7 @@ fn simple_join() { [id: 42] expression: Reference Alias: identification_number Referenced table name (or alias): t2 - Parent: Some(50) + Parent: Some(NodeId { offset: 50, arena_type: Default }) target_id: 1 Column type: integer Children: @@ -150,8 +150,8 @@ fn simple_join() { Output_id: 49 [id: 49] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [1] }, Key { positions: [0] }}) })] List: - [id: 46] expression: Alias [name = id, child = Reference { parent: Some(50), targets: Some([0]), position: 0, col_type: Unsigned }] - [id: 48] expression: Alias [name = identification_number, child = Reference { parent: Some(50), targets: Some([1]), position: 0, col_type: Integer }] + [id: 46] expression: Alias [name = id, child = Reference { parent: Some(NodeId { offset: 50, arena_type: Default }), targets: Some([0]), position: 0, col_type: Unsigned }] + [id: 48] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 50, arena_type: Default }), targets: Some([1]), position: 0, col_type: Integer }] --------------------------------------------- --------------------------------------------- [id: 54] relation: Projection @@ -160,7 +160,7 @@ fn simple_join() { Output_id: 53 [id: 53] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 52] expression: Alias [name = id, child = Reference { parent: Some(54), targets: Some([0]), position: 0, col_type: Unsigned }] + [id: 52] expression: Alias [name = id, child = Reference { parent: Some(NodeId { offset: 54, arena_type: Default }), targets: Some([0]), position: 0, col_type: Unsigned }] --------------------------------------------- "#); @@ -174,10 +174,13 @@ fn simple_join_subtree() { INNER JOIN (SELECT "identification_number" FROM "hash_testing") as "t2" ON "t1"."id" = "t2"."identification_number""#; - let mut plan = sql_to_optimized_ir(query, vec![]); + let plan = sql_to_optimized_ir(query, vec![]); // Taken from the expected arena output in the `simple_join` test. - let inner_join_inner_child_id = 61; + let inner_join_inner_child_id = NodeId { + offset: 61, + arena_type: ArenaType::Default, + }; let actual_arena_subtree = plan .formatted_arena_subtree(inner_join_inner_child_id) @@ -192,11 +195,11 @@ fn simple_join_subtree() { Output_id: 30 [id: 30] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [id: 21] expression: Alias [name = identification_number, child = Reference { parent: Some(31), targets: None, position: 0, col_type: Integer }] - [id: 23] expression: Alias [name = product_code, child = Reference { parent: Some(31), targets: None, position: 1, col_type: String }] - [id: 25] expression: Alias [name = product_units, child = Reference { parent: Some(31), targets: None, position: 2, col_type: Boolean }] - [id: 27] expression: Alias [name = sys_op, child = Reference { parent: Some(31), targets: None, position: 3, col_type: Unsigned }] - [id: 29] expression: Alias [name = bucket_id, child = Reference { parent: Some(31), targets: None, position: 4, col_type: Unsigned }] + [id: 21] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 0, col_type: Integer }] + [id: 23] expression: Alias [name = product_code, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 1, col_type: String }] + [id: 25] expression: Alias [name = product_units, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 2, col_type: Boolean }] + [id: 27] expression: Alias [name = sys_op, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 3, col_type: Unsigned }] + [id: 29] expression: Alias [name = bucket_id, child = Reference { parent: Some(NodeId { offset: 31, arena_type: Default }), targets: None, position: 4, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 35] relation: Projection @@ -205,7 +208,7 @@ fn simple_join_subtree() { Output_id: 34 [id: 34] expression: Row [distribution = Some(Any)] List: - [id: 33] expression: Alias [name = identification_number, child = Reference { parent: Some(35), targets: Some([0]), position: 0, col_type: Integer }] + [id: 33] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 35, arena_type: Default }), targets: Some([0]), position: 0, col_type: Integer }] --------------------------------------------- --------------------------------------------- [id: 39] relation: ScanSubQuery @@ -215,7 +218,7 @@ fn simple_join_subtree() { Output_id: 38 [id: 38] expression: Row [distribution = Some(Any)] List: - [id: 37] expression: Alias [name = identification_number, child = Reference { parent: Some(39), targets: Some([0]), position: 0, col_type: Integer }] + [id: 37] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 39, arena_type: Default }), targets: Some([0]), position: 0, col_type: Integer }] --------------------------------------------- --------------------------------------------- [id: 61] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] @@ -224,7 +227,7 @@ fn simple_join_subtree() { Output_id: 60 [id: 60] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 59] expression: Alias [name = identification_number, child = Reference { parent: Some(61), targets: Some([0]), position: 0, col_type: Integer }] + [id: 59] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 61, arena_type: Default }), targets: Some([0]), position: 0, col_type: Integer }] --------------------------------------------- "# ); @@ -235,7 +238,7 @@ fn simple_join_subtree() { #[test] fn simple_aggregation_with_group_by() { let query = r#"SELECT "product_code" FROM "hash_testing" GROUP BY "product_code""#; - let mut plan = sql_to_optimized_ir(query, vec![]); + let plan = sql_to_optimized_ir(query, vec![]); let actual_arena = plan.formatted_arena().unwrap(); let mut expected_arena = String::new(); @@ -247,26 +250,26 @@ fn simple_aggregation_with_group_by() { Output_id: 10 [id: 10] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [id: 1] expression: Alias [name = identification_number, child = Reference { parent: Some(11), targets: None, position: 0, col_type: Integer }] - [id: 3] expression: Alias [name = product_code, child = Reference { parent: Some(11), targets: None, position: 1, col_type: String }] - [id: 5] expression: Alias [name = product_units, child = Reference { parent: Some(11), targets: None, position: 2, col_type: Boolean }] - [id: 7] expression: Alias [name = sys_op, child = Reference { parent: Some(11), targets: None, position: 3, col_type: Unsigned }] - [id: 9] expression: Alias [name = bucket_id, child = Reference { parent: Some(11), targets: None, position: 4, col_type: Unsigned }] + [id: 1] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 0, col_type: Integer }] + [id: 3] expression: Alias [name = product_code, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 1, col_type: String }] + [id: 5] expression: Alias [name = product_units, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 2, col_type: Boolean }] + [id: 7] expression: Alias [name = sys_op, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 3, col_type: Unsigned }] + [id: 9] expression: Alias [name = bucket_id, child = Reference { parent: Some(NodeId { offset: 11, arena_type: Default }), targets: None, position: 4, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 24] relation: GroupBy [is_final = false] Gr_cols: - Gr_col: Reference { parent: Some(24), targets: Some([0]), position: 1, col_type: String } + Gr_col: Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 1, col_type: String } Children: Child_id = 11 Output_id: 23 [id: 23] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [id: 14] expression: Alias [name = identification_number, child = Reference { parent: Some(24), targets: Some([0]), position: 0, col_type: Integer }] - [id: 16] expression: Alias [name = product_code, child = Reference { parent: Some(24), targets: Some([0]), position: 1, col_type: String }] - [id: 18] expression: Alias [name = product_units, child = Reference { parent: Some(24), targets: Some([0]), position: 2, col_type: Boolean }] - [id: 20] expression: Alias [name = sys_op, child = Reference { parent: Some(24), targets: Some([0]), position: 3, col_type: Unsigned }] - [id: 22] expression: Alias [name = bucket_id, child = Reference { parent: Some(24), targets: Some([0]), position: 4, col_type: Unsigned }] + [id: 14] expression: Alias [name = identification_number, child = Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 0, col_type: Integer }] + [id: 16] expression: Alias [name = product_code, child = Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 1, col_type: String }] + [id: 18] expression: Alias [name = product_units, child = Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 2, col_type: Boolean }] + [id: 20] expression: Alias [name = sys_op, child = Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 3, col_type: Unsigned }] + [id: 22] expression: Alias [name = bucket_id, child = Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 4, col_type: Unsigned }] --------------------------------------------- --------------------------------------------- [id: 31] relation: Projection @@ -275,7 +278,7 @@ fn simple_aggregation_with_group_by() { Output_id: 30 [id: 30] expression: Row [distribution = Some(Any)] List: - [id: 29] expression: Alias [name = column_12, child = Reference { parent: Some(24), targets: Some([0]), position: 1, col_type: String }] + [id: 29] expression: Alias [name = column_12, child = Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 1, col_type: String }] --------------------------------------------- --------------------------------------------- [id: 35] relation: ScanSubQuery @@ -284,7 +287,7 @@ fn simple_aggregation_with_group_by() { Output_id: 34 [id: 34] expression: Row [distribution = Some(Any)] List: - [id: 33] expression: Alias [name = column_12, child = Reference { parent: Some(35), targets: Some([0]), position: 0, col_type: String }] + [id: 33] expression: Alias [name = column_12, child = Reference { parent: Some(NodeId { offset: 35, arena_type: Default }), targets: Some([0]), position: 0, col_type: String }] --------------------------------------------- --------------------------------------------- [id: 45] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] @@ -293,18 +296,18 @@ fn simple_aggregation_with_group_by() { Output_id: 44 [id: 44] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 43] expression: Alias [name = column_12, child = Reference { parent: Some(45), targets: Some([0]), position: 0, col_type: String }] + [id: 43] expression: Alias [name = column_12, child = Reference { parent: Some(NodeId { offset: 45, arena_type: Default }), targets: Some([0]), position: 0, col_type: String }] --------------------------------------------- --------------------------------------------- [id: 40] relation: GroupBy [is_final = true] Gr_cols: - Gr_col: Reference { parent: Some(40), targets: Some([0]), position: 0, col_type: String } + Gr_col: Reference { parent: Some(NodeId { offset: 40, arena_type: Default }), targets: Some([0]), position: 0, col_type: String } Children: Child_id = 45 Output_id: 39 [id: 39] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 38] expression: Alias [name = column_12, child = Reference { parent: Some(40), targets: Some([0]), position: 0, col_type: String }] + [id: 38] expression: Alias [name = column_12, child = Reference { parent: Some(NodeId { offset: 40, arena_type: Default }), targets: Some([0]), position: 0, col_type: String }] --------------------------------------------- --------------------------------------------- [id: 28] relation: Projection @@ -313,7 +316,7 @@ fn simple_aggregation_with_group_by() { Output_id: 27 [id: 27] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 26] expression: Alias [name = product_code, child = Reference { parent: Some(28), targets: Some([0]), position: 0, col_type: String }] + [id: 26] expression: Alias [name = product_code, child = Reference { parent: Some(NodeId { offset: 28, arena_type: Default }), targets: Some([0]), position: 0, col_type: String }] --------------------------------------------- "#); diff --git a/sbroad-core/src/ir/operator.rs b/sbroad-core/src/ir/operator.rs index 19973b548..44728f3ed 100644 --- a/sbroad-core/src/ir/operator.rs +++ b/sbroad-core/src/ir/operator.rs @@ -17,10 +17,10 @@ use std::fmt::{Display, Formatter}; use crate::errors::{Action, Entity, SbroadError}; use super::api::children::{Children, MutChildren}; -use super::expression::{ColumnPositionMap, Expression}; +use super::expression::{ColumnPositionMap, Expression, NodeId}; use super::transformation::redistribution::{MotionPolicy, Program}; -use super::tree::traversal::{PostOrderWithFilter, EXPR_CAPACITY}; -use super::{Node, NodeId, Plan}; +use super::tree::traversal::{LevelNode, PostOrderWithFilter, EXPR_CAPACITY}; +use super::{ArenaType, Node, Plan}; use crate::ir::distribution::{Distribution, Key, KeySet}; use crate::ir::expression::{ExpressionId, PlanExpr}; use crate::ir::helpers::RepeatableState; @@ -287,7 +287,7 @@ pub enum UpdateStrategy { #[derive(Clone, Deserialize, Debug, PartialEq, Eq, Serialize)] pub enum OrderByEntity { - Expression { expr_id: usize }, + Expression { expr_id: NodeId }, Index { value: usize }, } @@ -322,25 +322,25 @@ pub enum Relational { /// CTE's name. alias: SmolStr, /// Contains exactly one single element (projection node index). - child: usize, + child: NodeId, /// An output tuple with aliases. - output: usize, + output: NodeId, }, Except { /// Left child id - left: usize, + left: NodeId, /// Right child id - right: usize, + right: NodeId, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, }, Delete { /// Relation name. relation: SmolStr, /// Contains exactly one single element. - children: Vec<usize>, + children: Vec<NodeId>, /// The output tuple (reserved for `delete returning`). - output: usize, + output: NodeId, }, Insert { /// Relation name. @@ -349,23 +349,23 @@ pub enum Relational { /// the child's tuple. columns: Vec<usize>, /// Contains exactly one single element. - children: Vec<usize>, + children: Vec<NodeId>, /// The output tuple (reserved for `insert returning`). - output: usize, + output: NodeId, /// What to do in case there is a conflict during insert on storage conflict_strategy: ConflictStrategy, }, Intersect { - left: usize, - right: usize, + left: NodeId, + right: NodeId, // id of the output tuple - output: usize, + output: NodeId, }, Update { /// Relation name. relation: SmolStr, /// Children ids. Update has exactly one child. - children: Vec<usize>, + children: Vec<NodeId>, /// Maps position of column being updated in table to corresponding position /// in `Projection` below `Update`. /// @@ -378,18 +378,18 @@ pub enum Relational { /// below `Update`. pk_positions: Vec<ColumnPosition>, /// Output id. - output: usize, + output: NodeId, }, Join { /// Contains at least two elements: left and right node indexes /// from the plan node arena. Every element other than those /// two should be treated as a `SubQuery` node. - children: Vec<usize>, + children: Vec<NodeId>, /// Left and right tuple comparison condition. /// In fact it is an expression tree top index from the plan node arena. - condition: usize, + condition: NodeId, /// Outputs tuple node index from the plan node arena. - output: usize, + output: NodeId, /// inner or left kind: JoinKind, }, @@ -398,13 +398,13 @@ pub enum Relational { alias: Option<SmolStr>, /// Contains exactly one single element: child node index /// from the plan node arena. - children: Vec<usize>, + children: Vec<NodeId>, /// Motion policy - the amount of data to be moved. policy: MotionPolicy, /// A sequence of opcodes that transform the data. program: Program, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, /// A helper field indicating whether first element of /// `children` vec is a `Relational::SubQuery`. /// We need it on the stage of translating Plan to SQL, because @@ -417,9 +417,9 @@ pub enum Relational { /// from the plan node arena. Every element other than the /// first one should be treated as a `SubQuery` node from /// the output tree. - children: Vec<usize>, + children: Vec<NodeId>, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, /// Wheter the select was marked with `distinct` keyword is_distinct: bool, }, @@ -427,7 +427,7 @@ pub enum Relational { // Scan name. alias: Option<SmolStr>, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, /// Relation name. relation: SmolStr, }, @@ -436,81 +436,81 @@ pub enum Relational { alias: Option<SmolStr>, /// Contains exactly one single element: child node index /// from the plan node arena. - children: Vec<usize>, + children: Vec<NodeId>, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, }, Selection { /// Contains at least one single element: child node index /// from the plan node arena. Every element other than the /// first one should be treated as a `SubQuery` node from /// the filter tree. - children: Vec<usize>, + children: Vec<NodeId>, /// Filters expression node index in the plan node arena. - filter: usize, + filter: NodeId, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, }, GroupBy { /// The first child is a relational operator before group by - children: Vec<usize>, - gr_cols: Vec<usize>, - output: usize, + children: Vec<NodeId>, + gr_cols: Vec<NodeId>, + output: NodeId, is_final: bool, }, Having { - children: Vec<usize>, - output: usize, - filter: usize, + children: Vec<NodeId>, + output: NodeId, + filter: NodeId, }, OrderBy { - child: usize, - output: usize, + child: NodeId, + output: NodeId, order_by_elements: Vec<OrderByElement>, }, UnionAll { /// Left child id - left: usize, + left: NodeId, /// Right child id - right: usize, + right: NodeId, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, }, Union { /// Left child id - left: usize, + left: NodeId, /// Right child id - right: usize, + right: NodeId, /// Outputs tuple node index in the plan node arena. - output: usize, + output: NodeId, }, Values { /// Output tuple. - output: usize, + output: NodeId, /// Non-empty list of value rows. - children: Vec<usize>, + children: Vec<NodeId>, }, ValuesRow { /// Output tuple of aliases. - output: usize, + output: NodeId, /// The data tuple. - data: usize, + data: NodeId, /// A list of children is required for the rows containing /// sub-queries. For example, the row `(1, (select a from t))` /// requires `children` to keep projection node. If the row /// contains only constants (i.e. `(1, 2)`), then `children` /// should be empty. - children: Vec<usize>, + children: Vec<NodeId>, }, Limit { /// Output tuple. - output: usize, + output: NodeId, // The limit value constant that comes after LIMIT keyword. limit: u64, /// Select statement that is being limited. /// Note that it can be a complex statement, like SELECT .. UNION ALL SELECT .. LIMIT 100, /// in that case limit is applied to the result of union. - child: usize, + child: NodeId, }, } @@ -518,7 +518,7 @@ pub enum Relational { impl Relational { /// Gets an immutable id of the output tuple node of the plan's arena. #[must_use] - pub fn output(&self) -> usize { + pub fn output(&self) -> NodeId { match self { Relational::ScanCte { output, .. } | Relational::Except { output, .. } @@ -545,7 +545,7 @@ impl Relational { /// Gets an immutable reference to the output tuple node id. #[must_use] - pub fn mut_output(&mut self) -> &mut usize { + pub fn mut_output(&mut self) -> &mut NodeId { match self { Relational::ScanCte { output, .. } | Relational::Except { output, .. } @@ -688,7 +688,7 @@ impl Relational { /// /// # Panics /// - wrong number of children for the given node - pub fn set_children(&mut self, children: Vec<usize>) { + pub fn set_children(&mut self, children: Vec<NodeId>) { match self { Relational::Join { children: ref mut old, @@ -909,7 +909,7 @@ impl Plan { /// /// # Errors /// - failed to oupdate shard columns info due to invalid plan subtree - pub fn add_relational(&mut self, node: Relational) -> Result<usize, SbroadError> { + pub fn add_relational(&mut self, node: Relational) -> Result<NodeId, SbroadError> { let rel_id = self.nodes.push(Node::Relational(node)); let mut context = self.context_mut(); context.shard_col_info.update_node(rel_id, self)?; @@ -920,7 +920,7 @@ impl Plan { /// /// # Errors /// - child id pointes to non-existing or non-relational node. - pub fn add_delete(&mut self, table: SmolStr, child_id: usize) -> Result<usize, SbroadError> { + pub fn add_delete(&mut self, table: SmolStr, child_id: NodeId) -> Result<NodeId, SbroadError> { let output = self.add_row_for_output(child_id, &[], true)?; let delete = Relational::Delete { relation: table, @@ -938,8 +938,8 @@ impl Plan { /// - children nodes are not relational /// - children tuples are invalid /// - children tuples have mismatching structure - pub fn add_except(&mut self, left: usize, right: usize) -> Result<usize, SbroadError> { - let child_row_len = |child: usize, plan: &Plan| -> Result<usize, SbroadError> { + pub fn add_except(&mut self, left: NodeId, right: NodeId) -> Result<NodeId, SbroadError> { + let child_row_len = |child: NodeId, plan: &Plan| -> Result<usize, SbroadError> { let child_output = plan.get_relation_node(child)?.output(); Ok(plan .get_expression_node(child_output)? @@ -1027,15 +1027,15 @@ impl Plan { &mut self, relation: &str, update_defs: &HashMap<ColumnPosition, ExpressionId, RepeatableState>, - rel_child_id: usize, - ) -> Result<usize, SbroadError> { + rel_child_id: NodeId, + ) -> Result<NodeId, SbroadError> { // Create Reference node from given table column. fn create_ref_from_column( plan: &mut Plan, relation: &str, table_position_map: &HashMap<ColumnPosition, ColumnPosition>, col_pos: usize, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let table = plan.get_relation_or_error(relation)?; let col: &Column = table.columns.get(col_pos).ok_or_else(|| { SbroadError::Invalid( @@ -1076,7 +1076,7 @@ impl Plan { .iter() .any(|col| update_defs.contains_key(col)); // Columns of Projection that will be created - let mut projection_cols: Vec<usize> = Vec::with_capacity(update_defs.len()); + let mut projection_cols: Vec<NodeId> = Vec::with_capacity(update_defs.len()); // Positions of columns in Projection that constitute the primary key let mut primary_key_positions: Vec<usize> = Vec::with_capacity(table.primary_key.positions.len()); @@ -1158,7 +1158,7 @@ impl Plan { .clone() .iter() .map(|pos| create_ref_from_column(self, relation, &child_map, *pos)) - .collect::<Result<Vec<usize>, SbroadError>>()?; + .collect::<Result<Vec<NodeId>, SbroadError>>()?; let mut pos = 0; // Add update_expressions @@ -1237,10 +1237,10 @@ impl Plan { pub fn add_insert( &mut self, relation: &str, - child: usize, + child: NodeId, columns: &[SmolStr], conflict_strategy: ConflictStrategy, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let rel = self.relations.get(relation).ok_or_else(|| { SbroadError::NotFound( Entity::Table, @@ -1297,7 +1297,7 @@ impl Plan { ))); } - let mut refs: Vec<usize> = Vec::with_capacity(rel.columns.len()); + let mut refs: Vec<NodeId> = Vec::with_capacity(rel.columns.len()); for (pos, col) in rel.columns.iter().enumerate() { let r_id = self.nodes.add_ref(None, None, pos, col.r#type.clone()); let col_alias_id = self.nodes.add_alias(&col.name, r_id)?; @@ -1329,11 +1329,11 @@ impl Plan { /// /// # Errors /// - relation is invalid - pub fn add_scan(&mut self, table: &str, alias: Option<&str>) -> Result<usize, SbroadError> { + pub fn add_scan(&mut self, table: &str, alias: Option<&str>) -> Result<NodeId, SbroadError> { let nodes = &mut self.nodes; if let Some(rel) = self.relations.get(table) { - let mut refs: Vec<usize> = Vec::with_capacity(rel.columns.len()); + let mut refs: Vec<NodeId> = Vec::with_capacity(rel.columns.len()); for (pos, col) in rel.columns.iter().enumerate() { let r_id = nodes.add_ref(None, None, pos, col.r#type.clone()); let col_alias_id = nodes.add_alias(&col.name, r_id)?; @@ -1365,11 +1365,11 @@ impl Plan { /// - children output tuples are invalid pub fn add_join( &mut self, - left: usize, - right: usize, - condition: usize, + left: NodeId, + right: NodeId, + condition: NodeId, kind: JoinKind, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { if !self.is_trivalent(condition)? { return Err(SbroadError::Invalid( Entity::Expression, @@ -1384,7 +1384,7 @@ impl Plan { // As a side effect, we also need to update the references // to the child's output in the condition expression as // we have filtered out the sharding column. - let mut children: Vec<usize> = Vec::with_capacity(2); + let mut children: Vec<NodeId> = Vec::with_capacity(2); for (child, join_child) in &[(left, JoinChild::Outer), (right, JoinChild::Inner)] { let child_node = self.get_relation_node(*child)?; if let Relational::ScanRelation { @@ -1418,7 +1418,7 @@ impl Plan { JoinChild::Outer => Some(vec![0_usize]), }; let mut refs = Vec::with_capacity(condition_nodes.len()); - for (_, id) in condition_nodes { + for LevelNode(_, id) in condition_nodes { let expr = self.get_expression_node(id)?; if let Expression::Reference { position, targets, .. @@ -1491,10 +1491,10 @@ impl Plan { /// - child output tuple is invalid pub fn add_motion( &mut self, - child_id: usize, + child_id: NodeId, policy: &MotionPolicy, program: Program, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let alias = if let Node::Relational(rel) = self.get_node(child_id)? { rel.scan_name(self, 0)?.map(SmolStr::from) } else { @@ -1507,7 +1507,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Motion, Some(format_smolstr!( - "add_motion: got MotionPolicy::None for child_id: {child_id}" + "add_motion: got MotionPolicy::None for child_id: {child_id:?}" )), )) } @@ -1557,11 +1557,11 @@ impl Plan { /// - column name do not match the ones in the child output tuple pub fn add_proj( &mut self, - child: usize, + child: NodeId, col_names: &[&str], is_distinct: bool, needs_shard_col: bool, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let output = self.add_row_for_output(child, col_names, needs_shard_col)?; let proj = Relational::Projection { children: vec![child], @@ -1582,10 +1582,10 @@ impl Plan { /// - columns are not aliases or have duplicate names pub fn add_proj_internal( &mut self, - child: usize, - columns: &[usize], + child: NodeId, + columns: &[NodeId], is_distinct: bool, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let output = self.nodes.add_row(columns.to_vec(), None); let proj = Relational::Projection { children: vec![child], @@ -1608,8 +1608,12 @@ impl Plan { /// /// # Panics /// - `children` is empty - pub fn add_select(&mut self, children: &[usize], filter: usize) -> Result<usize, SbroadError> { - let first_child: usize = *children + pub fn add_select( + &mut self, + children: &[NodeId], + filter: NodeId, + ) -> Result<NodeId, SbroadError> { + let first_child: NodeId = *children .first() .expect("No children passed to `add_select`"); @@ -1640,8 +1644,12 @@ impl Plan { /// - filter expression is not boolean /// - children nodes are not relational /// - first child output tuple is not valid - pub fn add_having(&mut self, children: &[usize], filter: usize) -> Result<usize, SbroadError> { - let first_child: usize = match children.len() { + pub fn add_having( + &mut self, + children: &[NodeId], + filter: NodeId, + ) -> Result<NodeId, SbroadError> { + let first_child: NodeId = match children.len() { 0 => { return Err(SbroadError::UnexpectedNumberOfValues( "children list is empty".into(), @@ -1687,9 +1695,9 @@ impl Plan { /// - Relational node child not found. pub fn add_order_by( &mut self, - child: usize, + child: NodeId, order_by_elements: Vec<OrderByElement>, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let output = self.add_row_for_output(child, &[], true)?; let order_by = Relational::OrderBy { child, @@ -1719,9 +1727,9 @@ impl Plan { /// - child node output is not a correct tuple pub fn add_sub_query( &mut self, - child: usize, + child: NodeId, alias: Option<&str>, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let name: Option<SmolStr> = alias.map(SmolStr::from); let output = self.add_row_for_output(child, &[], true)?; @@ -1815,11 +1823,11 @@ impl Plan { /// - children tuples have mismatching structure pub fn add_union( &mut self, - left: usize, - right: usize, + left: NodeId, + right: NodeId, remove_duplicates: bool, - ) -> Result<usize, SbroadError> { - let child_row_len = |child: usize, plan: &Plan| -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { + let child_row_len = |child: NodeId, plan: &Plan| -> Result<usize, SbroadError> { let child_output = plan.get_relation_node(child)?.output(); Ok(plan .get_expression_node(child_output)? @@ -1859,7 +1867,7 @@ impl Plan { /// /// # Errors /// - Row node is not of a row type - pub fn add_limit(&mut self, select: usize, limit: u64) -> Result<usize, SbroadError> { + pub fn add_limit(&mut self, select: NodeId, limit: u64) -> Result<NodeId, SbroadError> { let output = self.add_row_for_output(select, &[], true)?; let limit = Relational::Limit { output, @@ -1878,12 +1886,12 @@ impl Plan { /// - Row node is not of a row type pub fn add_values_row( &mut self, - row_id: usize, + row_id: NodeId, col_idx: &mut usize, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let row = self.get_expression_node(row_id)?; let columns = row.clone_row_list()?; - let mut aliases: Vec<usize> = Vec::with_capacity(columns.len()); + let mut aliases: Vec<NodeId> = Vec::with_capacity(columns.len()); for col_id in columns { // Generate a row of aliases for the incoming row. *col_idx += 1; @@ -1909,7 +1917,7 @@ impl Plan { /// # Errors /// - No child nodes /// - Child node is not relational - pub fn add_values(&mut self, value_rows: Vec<usize>) -> Result<usize, SbroadError> { + pub fn add_values(&mut self, value_rows: Vec<NodeId>) -> Result<NodeId, SbroadError> { // In case we have several `ValuesRow` under `Values` // (e.g. VALUES (1, "test_1"), (2, "test_2")), // the list of alias column names for it will look like: @@ -1954,7 +1962,7 @@ impl Plan { }; // Generate a row of aliases referencing all the children. - let mut aliases: Vec<usize> = Vec::with_capacity(names.len()); + let mut aliases: Vec<NodeId> = Vec::with_capacity(names.len()); let columns = last_output.clone_row_list()?; for (pos, name) in names.iter().enumerate() { let col_id = *columns.get(pos).ok_or_else(|| { @@ -1988,7 +1996,7 @@ impl Plan { /// /// # Errors /// - node is not relational - pub fn get_relational_output(&self, rel_id: usize) -> Result<usize, SbroadError> { + pub fn get_relational_output(&self, rel_id: NodeId) -> Result<NodeId, SbroadError> { if let Node::Relational(rel) = self.get_node(rel_id)? { Ok(rel.output()) } else { @@ -2002,7 +2010,7 @@ impl Plan { /// - node is not relational /// - output is not `Expression::Row` /// - any node in the output tuple is not `Expression::Alias` - pub fn get_relational_aliases(&self, rel_id: usize) -> Result<Vec<SmolStr>, SbroadError> { + pub fn get_relational_aliases(&self, rel_id: NodeId) -> Result<Vec<SmolStr>, SbroadError> { let output = self.get_relational_output(rel_id)?; if let Expression::Row { list, .. } = self.get_expression_node(output)? { return list @@ -2017,7 +2025,7 @@ impl Plan { Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "expected output of Relational node {rel_id} to be Row" + "expected output of Relational node {rel_id:?} to be Row" )), )) } @@ -2026,7 +2034,7 @@ impl Plan { /// /// # Errors /// - node is not relational - pub fn get_relational_children(&self, rel_id: usize) -> Result<Children<'_>, SbroadError> { + pub fn get_relational_children(&self, rel_id: NodeId) -> Result<Children<'_>, SbroadError> { if let Node::Relational(rel) = self.get_node(rel_id)? { Ok(rel.children()) } else { @@ -2044,9 +2052,9 @@ impl Plan { /// - node does not have child with specified index pub fn get_relational_child( &self, - rel_id: usize, + rel_id: NodeId, child_idx: usize, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { if let Node::Relational(rel) = self.get_node(rel_id)? { return Ok(*rel.children().get(child_idx).ok_or_else(|| { SbroadError::Invalid( @@ -2059,7 +2067,7 @@ impl Plan { } Err(SbroadError::NotFound( Entity::Relational, - format_smolstr!("with id ({rel_id})"), + format_smolstr!("with id ({rel_id:?})"), )) } @@ -2070,7 +2078,7 @@ impl Plan { /// /// # Errors /// - Node is not Join, Having, Selection - pub fn get_required_children_len(&self, node_id: usize) -> Result<usize, SbroadError> { + pub fn get_required_children_len(&self, node_id: NodeId) -> Result<usize, SbroadError> { let len = match self.get_relation_node(node_id)? { Relational::Join { .. } => 2, Relational::Having { .. } | Relational::Selection { .. } => 1, @@ -2078,7 +2086,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "expected Join, Having or Selection on id ({node_id})" + "expected Join, Having or Selection on id ({node_id:?})" )), )) } @@ -2088,17 +2096,25 @@ impl Plan { /// Finds the parent of the given relational node. /// + /// # Panics /// # Errors /// - node is not relational /// - Plan has no top - pub fn find_parent_rel(&self, target_id: usize) -> Result<Option<usize>, SbroadError> { + pub fn find_parent_rel(&self, target_id: NodeId) -> Result<Option<NodeId>, SbroadError> { for (id, node) in self.nodes.iter().enumerate() { if !matches!(node, Node::Relational(_)) { continue; } - for child_id in self.nodes.rel_iter(id) { + + let rel_id = NodeId { + offset: u32::try_from(id).unwrap(), + arena_type: ArenaType::Default, + }; + + // It will work with one arena but fails with many. Needs to be refactored. + for child_id in self.nodes.rel_iter(rel_id) { if child_id == target_id { - return Ok(Some(id)); + return Ok(Some(rel_id)); } } } @@ -2112,9 +2128,9 @@ impl Plan { /// - node does not have child with specified id pub fn change_child( &mut self, - parent_id: usize, - old_child_id: usize, - new_child_id: usize, + parent_id: NodeId, + old_child_id: NodeId, + new_child_id: NodeId, ) -> Result<(), SbroadError> { let node = self.get_mut_relation_node(parent_id)?; let children = node.mut_children(); @@ -2128,7 +2144,7 @@ impl Plan { Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "node ({parent_id}) has no child with id ({old_child_id})" + "node ({parent_id:?}) has no child with id ({old_child_id:?})" )), )) } @@ -2145,7 +2161,7 @@ impl Plan { pub fn table_position_map( &self, table_name: &str, - rel_id: usize, + rel_id: NodeId, ) -> Result<HashMap<ColumnPosition, ColumnPosition>, SbroadError> { let table = self.get_relation_or_error(table_name)?; let alias_to_pos = ColumnPositionMap::new(self, rel_id)?; @@ -2168,10 +2184,10 @@ impl Plan { /// - node is scan (always a leaf node) pub fn set_relational_children( &mut self, - rel_id: usize, - children: Vec<usize>, + rel_id: NodeId, + children: Vec<NodeId>, ) -> Result<(), SbroadError> { - if let Node::Relational(ref mut rel) = self.nodes.get_mut(rel_id)? { + if let Some(Node::Relational(ref mut rel)) = self.nodes.get_mut(rel_id) { rel.set_children(children); return Ok(()); } @@ -2186,7 +2202,7 @@ impl Plan { /// # Errors /// - Failed to get plan top /// - Node returned by the relational iterator is not relational (bug) - pub fn is_additional_child(&self, node_id: usize) -> Result<bool, SbroadError> { + pub fn is_additional_child(&self, node_id: NodeId) -> Result<bool, SbroadError> { for node in &self.nodes { match node { Node::Relational( @@ -2213,8 +2229,8 @@ impl Plan { /// - If the node is not relational. pub fn is_additional_child_of_rel( &self, - rel_id: usize, - sq_id: usize, + rel_id: NodeId, + sq_id: NodeId, ) -> Result<bool, SbroadError> { let children = self.get_relational_children(rel_id)?; match self.get_relation_node(rel_id)? { @@ -2232,7 +2248,7 @@ impl Plan { /// /// # Errors /// - node is not motion - pub fn get_motion_policy(&self, motion_id: usize) -> Result<&MotionPolicy, SbroadError> { + pub fn get_motion_policy(&self, motion_id: NodeId) -> Result<&MotionPolicy, SbroadError> { let node = self.get_relation_node(motion_id)?; if let Relational::Motion { policy, .. } = node { return Ok(policy); diff --git a/sbroad-core/src/ir/operator/tests.rs b/sbroad-core/src/ir/operator/tests.rs index 3c7bd2fc8..6bc322422 100644 --- a/sbroad-core/src/ir/operator/tests.rs +++ b/sbroad-core/src/ir/operator/tests.rs @@ -1,6 +1,3 @@ -use std::fs; -use std::path::Path; - use pretty_assertions::assert_eq; use crate::collection; @@ -8,7 +5,6 @@ use crate::errors::{Entity, SbroadError}; use crate::ir::distribution::{Distribution, Key}; use crate::ir::expression::ColumnWithScan; use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type}; -use crate::ir::tests::column_integer_user_non_null; use crate::ir::tests::{column_user_non_null, sharding_column}; use crate::ir::value::Value; use crate::ir::{Node, Plan}; @@ -34,8 +30,14 @@ fn scan_rel() { .unwrap(); plan.add_rel(t); - let scan_output = 8; - let scan_node = 9; + let scan_output = NodeId { + offset: 8, + arena_type: ArenaType::Default, + }; + let scan_node = NodeId { + offset: 9, + arena_type: ArenaType::Default, + }; let scan_id = plan.add_scan("t", None).unwrap(); assert_eq!(scan_node, scan_id); @@ -53,44 +55,6 @@ fn scan_rel() { } } -#[test] -fn scan_rel_serialized() { - let mut plan = Plan::default(); - - let t = Table::new_sharded( - "t", - vec![ - column_user_non_null(SmolStr::from("a"), Type::Boolean), - column_user_non_null(SmolStr::from("b"), Type::Number), - column_user_non_null(SmolStr::from("c"), Type::String), - column_user_non_null(SmolStr::from("d"), Type::String), - ], - &["b", "a"], - &["b", "a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t); - - let scan_id = plan.add_scan("t", None).unwrap(); - plan.top = Some(scan_id); - - let scan_output = scan_id - 1; - - plan.set_distribution(scan_output).unwrap(); - - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("operator") - .join("scan_rel.yaml"); - let s = fs::read_to_string(path).unwrap(); - // This field is not serialized, do not check it - plan.context = None; - assert_eq!(plan, Plan::from_yaml(&s).unwrap()); -} - #[test] fn projection() { let mut plan = Plan::default(); @@ -119,34 +83,32 @@ fn projection() { .unwrap_err() ); + let mut test_node = NodeId { + offset: 1, + arena_type: ArenaType::Default, + }; + // Expression node instead of relational one assert_eq!( SbroadError::Invalid( Entity::Node, - Some("node is not Relational type: Expression(Alias { name: \"a\", child: 0 })".into()) + Some("node is not Relational type: Expression(Alias { name: \"a\", child: NodeId { offset: 0, arena_type: Default } })".into()) ), - plan.add_proj(1, &["a"], false, false).unwrap_err() + plan.add_proj(test_node, &["a"], false, false).unwrap_err() ); + test_node.offset = 42; + // Try to build projection from the non-existing node assert_eq!( - SbroadError::NotFound(Entity::Node, "from arena with index 42".to_smolstr()), - plan.add_proj(42, &["a"], false, false).unwrap_err() + SbroadError::NotFound( + Entity::Node, + "from Default arena with index 42".to_smolstr() + ), + plan.add_proj(test_node, &["a"], false, false).unwrap_err() ); } -#[test] -fn projection_serialize() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("operator") - .join("projection.yaml"); - let s = fs::read_to_string(path).unwrap(); - Plan::from_yaml(&s).unwrap(); -} - #[test] fn selection() { // select * from t where (a, b) = (1, 10) @@ -189,18 +151,6 @@ fn selection() { ); } -#[test] -fn selection_serialize() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("operator") - .join("selection.yaml"); - let s = fs::read_to_string(path).unwrap(); - Plan::from_yaml(&s).unwrap(); -} - #[test] fn except() { let mut valid_plan = Plan::default(); @@ -417,87 +367,19 @@ fn sub_query() { plan.add_sub_query(scan_id, Some("sq")).unwrap(); // Non-relational child node - let a = 1; + let a = NodeId { + offset: 1, + arena_type: ArenaType::Default, + }; assert_eq!( SbroadError::Invalid( Entity::Node, - Some("node is not Relational type: Expression(Alias { name: \"a\", child: 0 })".into()) + Some("node is not Relational type: Expression(Alias { name: \"a\", child: NodeId { offset: 0, arena_type: Default } })".into()) ), plan.add_sub_query(a, Some("sq")).unwrap_err() ); } -#[test] -fn sub_query_serialize() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("operator") - .join("sub_query.yaml"); - let s = fs::read_to_string(path).unwrap(); - Plan::from_yaml(&s).unwrap(); -} - -#[test] -#[allow(clippy::similar_names)] -fn selection_with_sub_query() { - // t1(a int) key [a] - // t2(b int) key [b] - // select * from t1 where a = (select b from t2) - - let mut plan = Plan::default(); - let mut children: Vec<usize> = Vec::new(); - - let t1 = Table::new_sharded( - "t1", - vec![column_integer_user_non_null(SmolStr::from("a"))], - &["a"], - &["a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t1); - let scan_t1_id = plan.add_scan("t1", None).unwrap(); - children.push(scan_t1_id); - - let t2 = Table::new_sharded( - "t2", - vec![column_integer_user_non_null(SmolStr::from("b"))], - &["b"], - &["b"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t2); - let scan_t2_id = plan.add_scan("t2", None).unwrap(); - let proj_id = plan.add_proj(scan_t2_id, &["b"], false, false).unwrap(); - let sq_id = plan.add_sub_query(proj_id, None).unwrap(); - children.push(sq_id); - - let b_id = plan - .add_row_from_subquery(&children[..], children.len() - 1, None) - .unwrap(); - let a_id = plan.add_row_from_child(scan_t1_id, &["a"]).unwrap(); - let eq_id = plan.add_cond(a_id, Bool::Eq, b_id).unwrap(); - - let select_id = plan.add_select(&children[..], eq_id).unwrap(); - plan.set_top(select_id).unwrap(); - - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("operator") - .join("selection_with_sub_query.yaml"); - let s = fs::read_to_string(path).unwrap(); - let expected_plan = Plan::from_yaml(&s).unwrap(); - - // This field is not serialized, do not check it - plan.context = None; - assert_eq!(expected_plan, plan); -} - #[test] fn join() { // t1(a, b), t2(c, d) @@ -550,18 +432,6 @@ fn join() { plan.top = Some(join); } -#[test] -fn join_serialize() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("operator") - .join("join.yaml"); - let s = fs::read_to_string(path).unwrap(); - Plan::from_yaml(&s).unwrap(); -} - #[test] fn join_duplicate_columns() { // t1(a, b), t2(a, d) diff --git a/sbroad-core/src/ir/parameters.rs b/sbroad-core/src/ir/parameters.rs index d9418ba7f..eb5e001fc 100644 --- a/sbroad-core/src/ir/parameters.rs +++ b/sbroad-core/src/ir/parameters.rs @@ -5,8 +5,10 @@ use std::collections::HashMap; use crate::ir::Node; +use super::expression::NodeId; + #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct Parameters(HashMap<usize, Node>); +pub struct Parameters(HashMap<NodeId, Node>); impl Default for Parameters { fn default() -> Self { @@ -20,16 +22,16 @@ impl Parameters { Self(HashMap::new()) } - pub fn insert(&mut self, index: usize, node: Node) { + pub fn insert(&mut self, index: NodeId, node: Node) { self.0.insert(index, node); } #[must_use] - pub fn get(&self, index: usize) -> Option<&Node> { + pub fn get(&self, index: NodeId) -> Option<&Node> { self.0.get(&index) } - pub fn drain(&mut self) -> HashMap<usize, Node> { + pub fn drain(&mut self) -> HashMap<NodeId, Node> { std::mem::take(&mut self.0) } } diff --git a/sbroad-core/src/ir/relation/tests.rs b/sbroad-core/src/ir/relation/tests.rs index 7873286bf..1ad4f143c 100644 --- a/sbroad-core/src/ir/relation/tests.rs +++ b/sbroad-core/src/ir/relation/tests.rs @@ -1,6 +1,3 @@ -use std::fs; -use std::path::Path; - use pretty_assertions::{assert_eq, assert_ne}; use super::*; @@ -156,105 +153,6 @@ fn table_seg_compound_type_in_key() { ); } -#[test] -fn table_seg_serialized() { - let t = Table::new_sharded( - "t", - vec![ - column_user_non_null(SmolStr::from("a"), Type::Boolean), - column_user_non_null(SmolStr::from("b"), Type::Number), - column_user_non_null(SmolStr::from("c"), Type::String), - column_user_non_null(SmolStr::from("d"), Type::String), - column_user_non_null(SmolStr::from("e"), Type::Integer), - column_user_non_null(SmolStr::from("f"), Type::Unsigned), - ], - &["a", "d"], - &["a", "d"], - SpaceEngine::Memtx, - ) - .unwrap(); - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("relation") - .join("table_seg_serialized.yaml"); - let s = fs::read_to_string(path).unwrap(); - let t_yaml = Table::seg_from_yaml(&s).unwrap(); - assert_eq!(t, t_yaml); -} - -#[test] -fn table_seg_serialized_duplicate_columns() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("relation") - .join("table_seg_serialized_duplicate_columns.yaml"); - let s = fs::read_to_string(path).unwrap(); - assert_eq!( - Table::seg_from_yaml(&s).unwrap_err(), - SbroadError::DuplicatedValue( - "Table contains duplicate columns. Unable to convert to YAML.".into() - ) - ); -} - -#[test] -fn table_seg_serialized_out_of_range_key() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("relation") - .join("table_seg_serialized_out_of_range_key.yaml"); - let s = fs::read_to_string(path).unwrap(); - assert_eq!( - Table::seg_from_yaml(&s).unwrap_err(), - SbroadError::Invalid( - Entity::Value, - Some("key positions must be less than 1".into()) - ) - ); -} - -#[test] -fn table_seg_serialized_no_key() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("relation") - .join("table_seg_serialized_no_key.yaml"); - let s = fs::read_to_string(path).unwrap(); - let t = Table::seg_from_yaml(&s); - assert_eq!(t.unwrap_err(), SbroadError::FailedTo( - Action::Serialize, - Some(Entity::Table), - "Message(\"invalid type: unit value, expected struct Key\", Some(Pos { marker: Marker { index: 121, line: 10, col: 18 }, path: \"kind.ShardedSpace.sharding_key\" }))".into()), - ); -} - -#[test] -fn table_seg_serialized_no_columns() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("relation") - .join("table_seg_serialized_no_columns.yaml"); - let s = fs::read_to_string(path).unwrap(); - assert_eq!( - Table::seg_from_yaml(&s).unwrap_err(), - SbroadError::FailedTo( - Action::Serialize, - Some(Entity::Table), - "Message(\"invalid type: unit value, expected a sequence\", Some(Pos { marker: Marker { index: 9, line: 1, col: 9 }, path: \"columns\" }))".into() - ) - ); -} - #[test] fn column_msgpack_serialize() { let c = column_user_non_null(SmolStr::from("name"), Type::Boolean); diff --git a/sbroad-core/src/ir/tests.rs b/sbroad-core/src/ir/tests.rs index 0de64fd0f..b807ac665 100644 --- a/sbroad-core/src/ir/tests.rs +++ b/sbroad-core/src/ir/tests.rs @@ -2,8 +2,6 @@ use super::*; use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type}; use pretty_assertions::assert_eq; use smol_str::SmolStr; -use std::fs; -use std::path::Path; /// Helper function to create `Column` object with given name and default: /// @@ -53,34 +51,6 @@ pub fn sharding_column() -> Column { } } -#[test] -fn plan_no_top() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("plan_no_top.yaml"); - let s = fs::read_to_string(path).unwrap(); - assert_eq!( - SbroadError::Invalid(Entity::Plan, Some("plan tree top is None".into())), - Plan::from_yaml(&s).unwrap_err() - ); -} - -#[test] -fn plan_oor_top() { - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("plan_oor_top.yaml"); - let s = fs::read_to_string(path).unwrap(); - assert_eq!( - SbroadError::NotFound(Entity::Node, "from arena with index 42".into()), - Plan::from_yaml(&s).unwrap_err() - ); -} - #[test] fn get_node() { let mut plan = Plan::default(); @@ -110,8 +80,12 @@ fn get_node() { fn get_node_oor() { let plan = Plan::default(); assert_eq!( - SbroadError::NotFound(Entity::Node, "from arena with index 42".into()), - plan.get_node(42).unwrap_err() + SbroadError::NotFound(Entity::Node, "from Default arena with index 42".into()), + plan.get_node(NodeId { + offset: 42, + arena_type: ArenaType::Default + }) + .unwrap_err() ); } diff --git a/sbroad-core/src/ir/transformation.rs b/sbroad-core/src/ir/transformation.rs index c85d27d55..b7779f0e2 100644 --- a/sbroad-core/src/ir/transformation.rs +++ b/sbroad-core/src/ir/transformation.rs @@ -12,6 +12,7 @@ pub mod split_columns; use smol_str::format_smolstr; +use super::expression::NodeId; use super::tree::traversal::{PostOrder, PostOrderWithFilter, EXPR_CAPACITY}; use crate::errors::{Entity, SbroadError}; use crate::ir::expression::Expression; @@ -19,7 +20,7 @@ use crate::ir::operator::{Bool, Relational}; use crate::ir::{Node, Plan}; use std::collections::HashMap; -pub type ExprId = usize; +pub type ExprId = NodeId; /// Helper struct representing map of (`old_expr_id` -> `changed_expr_id`). struct OldNewExpressionMap { inner: HashMap<ExprId, ExprId>, @@ -32,11 +33,11 @@ impl OldNewExpressionMap { } } - fn insert(&mut self, old_id: usize, new_id: usize) { + fn insert(&mut self, old_id: ExprId, new_id: ExprId) { self.inner.insert(old_id, new_id); } - fn replace(&self, child: &mut usize) { + fn replace(&self, child: &mut ExprId) { if let Some(new_id) = self.inner.get(child) { *child = *new_id; } @@ -46,7 +47,7 @@ impl OldNewExpressionMap { self.inner.is_empty() } - fn get(&self, key: usize) -> Option<&ExprId> { + fn get(&self, key: ExprId) -> Option<&ExprId> { self.inner.get(&key) } @@ -70,9 +71,9 @@ impl Plan { /// - If the left or right child is not a trivalent. pub fn concat_and( &mut self, - left_expr_id: usize, - right_expr_id: usize, - ) -> Result<usize, SbroadError> { + left_expr_id: NodeId, + right_expr_id: NodeId, + ) -> Result<NodeId, SbroadError> { if !self.is_trivalent(left_expr_id)? { return Err(SbroadError::Invalid( Entity::Expression, @@ -100,9 +101,9 @@ impl Plan { /// - If the left or right child is not a trivalent. pub fn concat_or( &mut self, - left_expr_id: usize, - right_expr_id: usize, - ) -> Result<usize, SbroadError> { + left_expr_id: NodeId, + right_expr_id: NodeId, + ) -> Result<NodeId, SbroadError> { if !self.is_trivalent(left_expr_id)? { return Err(SbroadError::Invalid( Entity::Expression, @@ -137,8 +138,9 @@ impl Plan { let mut ir_tree = PostOrder::with_capacity(|node| self.nodes.rel_iter(node), EXPR_CAPACITY); ir_tree.populate_nodes(top_id); let nodes = ir_tree.take_nodes(); - for (_, id) in &nodes { - let rel = self.get_relation_node(*id)?; + for level_node in &nodes { + let id = level_node.1; + let rel = self.get_relation_node(id)?; let (old_tree_id, new_tree_id) = match rel { Relational::Selection { filter: tree_id, .. @@ -151,7 +153,7 @@ impl Plan { if old_tree_id != new_tree_id { self.undo.add(new_tree_id, old_tree_id); } - let rel = self.get_mut_relation_node(*id)?; + let rel = self.get_mut_relation_node(id)?; match rel { Relational::Selection { filter: tree_id, .. @@ -175,7 +177,7 @@ impl Plan { #[allow(clippy::too_many_lines)] pub fn expr_tree_replace_bool( &mut self, - top_id: usize, + top_id: NodeId, f: TransformFunction, ops: &[Bool], ) -> Result<OldNewTopIdPair, SbroadError> { @@ -183,7 +185,7 @@ impl Plan { // Note, that filter accepts nodes: // * On which we'd like to apply transformation // * That will contain transformed nodes as children - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { if let Ok(Node::Expression( Expression::Bool { .. } | Expression::ExprInParentheses { .. } @@ -208,13 +210,14 @@ impl Plan { subtree.populate_nodes(top_id); let nodes = subtree.take_nodes(); drop(subtree); - for (_, id) in &nodes { - let expr = self.get_expression_node(*id)?; + for level_node in &nodes { + let id = level_node.1; + let expr = self.get_expression_node(id)?; if let Expression::Bool { op, .. } = expr { if ops.contains(op) || ops.is_empty() { - let (old_top_id, new_top_id) = f(self, *id)?; + let (old_top_id, new_top_id) = f(self, id)?; if old_top_id != new_top_id { - map.insert(*id, new_top_id); + map.insert(id, new_top_id); } } } @@ -228,8 +231,9 @@ impl Plan { self.clone_expr_subtree(top_id)? }; let mut new_top_id = top_id; - for (_, id) in &nodes { - let expr = self.get_mut_expression_node(*id)?; + for level_node in &nodes { + let id = level_node.1; + let expr = self.get_mut_expression_node(id)?; // For all expressions in the subtree tries to replace their children // with the new nodes from the map. // diff --git a/sbroad-core/src/ir/transformation/bool_in.rs b/sbroad-core/src/ir/transformation/bool_in.rs index 191cfbb7d..be1bb8c5b 100644 --- a/sbroad-core/src/ir/transformation/bool_in.rs +++ b/sbroad-core/src/ir/transformation/bool_in.rs @@ -11,7 +11,7 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; use crate::ir::Plan; @@ -22,18 +22,18 @@ use smol_str::format_smolstr; /// Replace IN operator with the chain of the OR-ed equalities in the expression tree. fn call_expr_tree_replace_in( plan: &mut Plan, - top_id: usize, + top_id: NodeId, ) -> Result<OldNewTopIdPair, SbroadError> { plan.expr_tree_replace_bool(top_id, &call_from_in, &[Bool::In]) } -fn call_from_in(plan: &mut Plan, top_id: usize) -> Result<OldNewTopIdPair, SbroadError> { +fn call_from_in(plan: &mut Plan, top_id: NodeId) -> Result<OldNewTopIdPair, SbroadError> { plan.in_to_or(top_id) } impl Plan { /// Convert the IN operator to the chain of the OR-ed equalities. - fn in_to_or(&mut self, top_id: usize) -> Result<OldNewTopIdPair, SbroadError> { + fn in_to_or(&mut self, top_id: NodeId) -> Result<OldNewTopIdPair, SbroadError> { let top_expr = self.get_expression_node(top_id)?; let (left_id, right_id) = match top_expr { Expression::Bool { diff --git a/sbroad-core/src/ir/transformation/dnf.rs b/sbroad-core/src/ir/transformation/dnf.rs index 6a53adc6d..0cc77cedd 100644 --- a/sbroad-core/src/ir/transformation/dnf.rs +++ b/sbroad-core/src/ir/transformation/dnf.rs @@ -71,7 +71,7 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; use crate::ir::{Node, Plan}; @@ -82,12 +82,12 @@ use std::collections::VecDeque; /// A chain of the trivalents (boolean or NULL expressions) concatenated by AND. #[derive(Clone, Debug)] pub struct Chain { - nodes: VecDeque<usize>, + nodes: VecDeque<NodeId>, } /// Helper function to identify whether we are dealing with AND/OR operator that /// may be covered with parentheses. -fn optionally_covered_and_or(expr_id: usize, plan: &Plan) -> Result<Option<usize>, SbroadError> { +fn optionally_covered_and_or(expr_id: NodeId, plan: &Plan) -> Result<Option<NodeId>, SbroadError> { let expr = plan.get_expression_node(expr_id)?; let and_or = match expr { Expression::Bool { op, .. } => { @@ -120,7 +120,7 @@ impl Chain { /// Append a new node to the chain. Keep AND and OR nodes in the back, /// while other nodes in the front of the chain queue. - fn push(&mut self, expr_id: usize, plan: &Plan) -> Result<(), SbroadError> { + fn push(&mut self, expr_id: NodeId, plan: &Plan) -> Result<(), SbroadError> { let and_or = optionally_covered_and_or(expr_id, plan)?; if let Some(and_or_id) = and_or { self.nodes.push_back(and_or_id); @@ -131,7 +131,7 @@ impl Chain { } /// Pop AND and OR nodes (we append them to the back). - fn pop_back(&mut self, plan: &Plan) -> Result<Option<usize>, SbroadError> { + fn pop_back(&mut self, plan: &Plan) -> Result<Option<NodeId>, SbroadError> { if let Some(expr_id) = self.nodes.back() { let expr = plan.get_expression_node(*expr_id)?; if let Expression::Bool { @@ -146,13 +146,13 @@ impl Chain { } /// Pop trivalent nodes other than AND and OR (we keep then in the front). - fn pop_front(&mut self) -> Option<usize> { + fn pop_front(&mut self) -> Option<NodeId> { self.nodes.pop_front() } /// Convert a chain to a new expression tree (reuse trivalent expressions). - fn as_plan(&mut self, plan: &mut Plan) -> Result<usize, SbroadError> { - let mut top_id: Option<usize> = None; + fn as_plan(&mut self, plan: &mut Plan) -> Result<NodeId, SbroadError> { + let mut top_id: Option<NodeId> = None; while let Some(expr_id) = self.pop_front() { match top_id { None => { @@ -170,12 +170,12 @@ impl Chain { } /// Return a mutable reference to the chain nodes. - pub fn get_mut_nodes(&mut self) -> &mut VecDeque<usize> { + pub fn get_mut_nodes(&mut self) -> &mut VecDeque<NodeId> { &mut self.nodes } } -fn call_expr_tree_to_dnf(plan: &mut Plan, top_id: usize) -> Result<OldNewTopIdPair, SbroadError> { +fn call_expr_tree_to_dnf(plan: &mut Plan, top_id: NodeId) -> Result<OldNewTopIdPair, SbroadError> { plan.expr_tree_to_dnf(top_id) } @@ -185,7 +185,7 @@ impl Plan { /// # Errors /// - If the expression tree is not a trivalent expression. /// - Failed to append node to the AND chain. - pub fn get_dnf_chains(&self, top_id: usize) -> Result<VecDeque<Chain>, SbroadError> { + pub fn get_dnf_chains(&self, top_id: NodeId) -> Result<VecDeque<Chain>, SbroadError> { let capacity: usize = self.nodes.arena.iter().fold(0_usize, |acc, node| { acc + match node { Node::Expression(Expression::Bool { @@ -244,10 +244,10 @@ impl Plan { /// - Failed to retrieve DNF chains. /// - Failed to convert the AND chain to a new expression tree. /// - Failed to concatenate the AND expression trees to the OR tree. - pub fn expr_tree_to_dnf(&mut self, top_id: usize) -> Result<OldNewTopIdPair, SbroadError> { + pub fn expr_tree_to_dnf(&mut self, top_id: NodeId) -> Result<OldNewTopIdPair, SbroadError> { let mut result = self.get_dnf_chains(top_id)?; - let mut new_top_id: Option<usize> = None; + let mut new_top_id: Option<NodeId> = None; while let Some(mut chain) = result.pop_front() { let ir_chain_top = chain.as_plan(self)?; new_top_id = match new_top_id { diff --git a/sbroad-core/src/ir/transformation/equality_propagation.rs b/sbroad-core/src/ir/transformation/equality_propagation.rs index 6ea30eb01..dc7132d93 100644 --- a/sbroad-core/src/ir/transformation/equality_propagation.rs +++ b/sbroad-core/src/ir/transformation/equality_propagation.rs @@ -90,7 +90,7 @@ //! to the plan tree. use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::helpers::RepeatableState; use crate::ir::operator::Bool; use crate::ir::relation::Type; @@ -109,7 +109,7 @@ use std::collections::{HashMap, HashSet}; struct EqClassRef { targets: Option<Vec<usize>>, position: usize, - parent: Option<usize>, + parent: Option<NodeId>, col_type: Type, } @@ -132,7 +132,7 @@ impl EqClassRef { Err(SbroadError::Invalid(Entity::Expression, None)) } - fn to_single_col_row(&self, plan: &mut Plan) -> usize { + fn to_single_col_row(&self, plan: &mut Plan) -> NodeId { let id = plan.nodes.add_ref( self.parent, self.targets.clone(), @@ -168,7 +168,7 @@ impl EqClassConst { )) } - fn to_const(&self, plan: &mut Plan) -> usize { + fn to_const(&self, plan: &mut Plan) -> NodeId { let const_id = plan.add_const(self.value.clone()); plan.nodes.add_row(vec![const_id], None) } @@ -182,7 +182,7 @@ enum EqClassExpr { } impl EqClassExpr { - fn to_plan(&self, plan: &mut Plan) -> usize { + fn to_plan(&self, plan: &mut Plan) -> NodeId { match self { EqClassExpr::EqClassConst(ec_const) => ec_const.to_const(plan), EqClassExpr::EqClassRef(ec_ref) => ec_ref.to_single_col_row(plan), @@ -353,15 +353,15 @@ impl EqClassChain { /// Replace IN operator with the chain of the OR-ed equalities in the expression tree. fn call_expr_tree_derive_equalities( plan: &mut Plan, - top_id: usize, + top_id: NodeId, ) -> Result<OldNewTopIdPair, SbroadError> { plan.expr_tree_modify_and_chains(top_id, &call_build_and_chains, &call_as_plan) } fn call_build_and_chains( plan: &mut Plan, - nodes: &[usize], -) -> Result<HashMap<usize, Chain, RepeatableState>, SbroadError> { + nodes: &[NodeId], +) -> Result<HashMap<NodeId, Chain, RepeatableState>, SbroadError> { let mut chains = plan.populate_and_chains(nodes)?; for chain in chains.values_mut() { chain.extend_equality_operator(plan)?; @@ -369,7 +369,7 @@ fn call_build_and_chains( Ok(chains) } -fn call_as_plan(chain: &Chain, plan: &mut Plan) -> Result<usize, SbroadError> { +fn call_as_plan(chain: &Chain, plan: &mut Plan) -> Result<NodeId, SbroadError> { chain.as_plan_ecs(plan) } @@ -409,7 +409,7 @@ impl Chain { Ok(()) } - fn as_plan_ecs(&self, plan: &mut Plan) -> Result<usize, SbroadError> { + fn as_plan_ecs(&self, plan: &mut Plan) -> Result<NodeId, SbroadError> { let other_top_id = match self.get_other().split_first() { Some((first, other)) => { let mut top_id = *first; @@ -424,7 +424,7 @@ impl Chain { // Chain is grouped by the operators in the hash map. // To make serialization non-flaky, we extract operators // in a deterministic order. - let mut grouped_top_id: Option<usize> = None; + let mut grouped_top_id: Option<NodeId> = None; // No need for "And" and "Or" operators. let ordered_ops = &[ Bool::Eq, @@ -441,7 +441,7 @@ impl Chain { .iter() .zip(right_vec.iter()) .map(|(l, r)| (*l, *r)) - .collect::<Vec<(usize, usize)>>() + .collect::<Vec<(NodeId, NodeId)>>() .split_first() { let left_row_id = plan.nodes.add_row(vec![first.0], None); @@ -481,7 +481,7 @@ impl Chain { impl Plan { // DoSkip is a special case of an error - nothing bad had happened, the target node doesn't contain // anything interesting for us, skip it without any serious error. - fn try_to_eq_class_expr(&self, expr_id: usize) -> Result<EqClassExpr, SbroadError> { + fn try_to_eq_class_expr(&self, expr_id: NodeId) -> Result<EqClassExpr, SbroadError> { let expr = self.get_expression_node(expr_id)?; match expr { Expression::Constant { .. } => { diff --git a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs index ba9182fe2..83f6bfa30 100644 --- a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs +++ b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs @@ -18,7 +18,7 @@ fn equality_propagation1() { "{} {} {}", r#"SELECT "t"."a" FROM "t""#, r#"WHERE ("t"."c") = (?) and ("t"."a") = (?) and ("t"."b") = (?)"#, - r#"and ("t"."c") = ("t"."a") or ("t"."d") = (?)"#, + r#"and ("t"."a") = ("t"."c") or ("t"."d") = (?)"#, ), vec![ Value::from(1_u64), @@ -107,8 +107,8 @@ fn equality_propagation5() { r#"SELECT "t"."a" FROM "t""#, r#"WHERE ("t"."d") = (?) and ("t"."c") = (?)"#, r#"and ("t"."a") = (?) and ("t"."b") = (?)"#, - r#"and ("t"."c") = ("t"."a") and ("t"."a") = ("t"."d")"#, - r#"and ("t"."d") = ("t"."b")"#, + r#"and ("t"."a") = ("t"."b") and ("t"."b") = ("t"."c")"#, + r#"and ("t"."c") = ("t"."d")"#, ), vec![ Value::from(1_u64), diff --git a/sbroad-core/src/ir/transformation/merge_tuples.rs b/sbroad-core/src/ir/transformation/merge_tuples.rs index bb2fb2f83..30f76a9de 100644 --- a/sbroad-core/src/ir/transformation/merge_tuples.rs +++ b/sbroad-core/src/ir/transformation/merge_tuples.rs @@ -11,7 +11,7 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::helpers::RepeatableState; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; @@ -25,19 +25,19 @@ use std::collections::{hash_map::Entry, HashMap, HashSet}; fn call_expr_tree_merge_tuples( plan: &mut Plan, - top_id: usize, + top_id: NodeId, ) -> Result<OldNewTopIdPair, SbroadError> { plan.expr_tree_modify_and_chains(top_id, &call_build_and_chains, &call_as_plan) } fn call_build_and_chains( plan: &mut Plan, - nodes: &[usize], -) -> Result<HashMap<usize, Chain, RepeatableState>, SbroadError> { + nodes: &[NodeId], +) -> Result<HashMap<NodeId, Chain, RepeatableState>, SbroadError> { plan.populate_and_chains(nodes) } -fn call_as_plan(chain: &Chain, plan: &mut Plan) -> Result<usize, SbroadError> { +fn call_as_plan(chain: &Chain, plan: &mut Plan) -> Result<NodeId, SbroadError> { chain.as_plan(plan) } @@ -46,9 +46,9 @@ fn call_as_plan(chain: &Chain, plan: &mut Plan) -> Result<usize, SbroadError> { pub struct Chain { // Left and right sides of the equality (and non-equality) expressions // grouped by the operator. - grouped: HashMap<Bool, (Vec<usize>, Vec<usize>)>, + grouped: HashMap<Bool, (Vec<NodeId>, Vec<NodeId>)>, // Other boolean expressions in the AND chain (true, false, null, Lt, GtEq, etc). - other: Vec<usize>, + other: Vec<NodeId>, } impl Chain { @@ -67,7 +67,7 @@ impl Chain { /// - Failed if the node is not an expression. /// - Failed if expression is not an "AND" or "OR". /// - There is something wrong with our sub-queries. - pub fn insert(&mut self, plan: &mut Plan, expr_id: usize) -> Result<(), SbroadError> { + pub fn insert(&mut self, plan: &mut Plan, expr_id: NodeId) -> Result<(), SbroadError> { let bool_expr = plan.get_expression_node(expr_id)?; if let Expression::Bool { left, op, right } = bool_expr { if let Bool::And | Bool::Or = op { @@ -143,7 +143,7 @@ impl Chain { Ok(()) } - fn as_plan(&self, plan: &mut Plan) -> Result<usize, SbroadError> { + fn as_plan(&self, plan: &mut Plan) -> Result<NodeId, SbroadError> { let other_top_id = match self.other.split_first() { Some((first, other)) => { let mut top_id = *first; @@ -158,7 +158,7 @@ impl Chain { // Chain is grouped by the operators in the hash map. // To make serialization non-flaky, we extract operators // in a deterministic order. - let mut grouped_top_id: Option<usize> = None; + let mut grouped_top_id: Option<NodeId> = None; let ordered_ops = &[Bool::Eq, Bool::NotEq]; for op in ordered_ops { if let Some((left, right)) = self.grouped.get(op) { @@ -193,19 +193,19 @@ impl Chain { /// Return boolean expression nodes grouped by the operator. #[must_use] - pub fn get_grouped(&self) -> &HashMap<Bool, (Vec<usize>, Vec<usize>)> { + pub fn get_grouped(&self) -> &HashMap<Bool, (Vec<NodeId>, Vec<NodeId>)> { &self.grouped } /// Return "other" boolean expression nodes. #[must_use] - pub fn get_other(&self) -> &Vec<usize> { + pub fn get_other(&self) -> &Vec<NodeId> { &self.other } } impl Plan { - fn get_columns_or_self(&self, expr_id: usize) -> Result<Vec<usize>, SbroadError> { + fn get_columns_or_self(&self, expr_id: NodeId) -> Result<Vec<NodeId>, SbroadError> { let expr = self.get_expression_node(expr_id)?; match expr { Expression::Row { list, .. } => Ok(list.clone()), @@ -220,10 +220,10 @@ impl Plan { /// - Failed to insert the node to the "And" chain. pub fn populate_and_chains( &mut self, - nodes: &[usize], - ) -> Result<HashMap<usize, Chain, RepeatableState>, SbroadError> { - let mut visited: HashSet<usize> = HashSet::with_capacity(self.nodes.next_id()); - let mut chains: HashMap<usize, Chain, RepeatableState> = + nodes: &[NodeId], + ) -> Result<HashMap<NodeId, Chain, RepeatableState>, SbroadError> { + let mut visited: HashSet<NodeId> = HashSet::with_capacity(self.nodes.len()); + let mut chains: HashMap<NodeId, Chain, RepeatableState> = HashMap::with_capacity_and_hasher(nodes.len(), RepeatableState); for id in nodes { @@ -237,8 +237,9 @@ impl Plan { EXPR_CAPACITY, EXPR_CAPACITY, ); - let nodes_and: Vec<usize> = tree_and.iter(*id).map(|(_, id)| id).collect(); - let mut nodes_for_chain: Vec<usize> = Vec::with_capacity(nodes_and.len()); + let nodes_and: Vec<NodeId> = + tree_and.iter(*id).map(|level_node| level_node.1).collect(); + let mut nodes_for_chain: Vec<NodeId> = Vec::with_capacity(nodes_and.len()); for and_id in nodes_and { let expr = self.get_expression_node(and_id)?; if let Expression::Bool { @@ -285,20 +286,20 @@ impl Plan { #[allow(clippy::type_complexity, clippy::too_many_lines)] pub fn expr_tree_modify_and_chains( &mut self, - expr_id: usize, + expr_id: NodeId, f_build_chains: &dyn Fn( &mut Plan, - &[usize], + &[NodeId], ) - -> Result<HashMap<usize, Chain, RepeatableState>, SbroadError>, - f_to_plan: &dyn Fn(&Chain, &mut Plan) -> Result<usize, SbroadError>, + -> Result<HashMap<NodeId, Chain, RepeatableState>, SbroadError>, + f_to_plan: &dyn Fn(&Chain, &mut Plan) -> Result<NodeId, SbroadError>, ) -> Result<OldNewTopIdPair, SbroadError> { let mut tree = BreadthFirst::with_capacity( |node| self.nodes.expr_iter(node, false), EXPR_CAPACITY, EXPR_CAPACITY, ); - let nodes: Vec<usize> = tree.iter(expr_id).map(|(_, id)| id).collect(); + let nodes: Vec<NodeId> = tree.iter(expr_id).map(|level_node| level_node.1).collect(); let chains = f_build_chains(self, &nodes)?; // Replace nodes' children with the merged tuples. diff --git a/sbroad-core/src/ir/transformation/not_push_down.rs b/sbroad-core/src/ir/transformation/not_push_down.rs index 867fb970e..06a672118 100644 --- a/sbroad-core/src/ir/transformation/not_push_down.rs +++ b/sbroad-core/src/ir/transformation/not_push_down.rs @@ -5,7 +5,7 @@ //! * To: `select * from "t" where "a" = 1 and "b" = 2` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::{Bool, Unary}; use crate::ir::transformation::{OldNewExpressionMap, OldNewTopIdPair}; use crate::ir::tree::traversal::{PostOrderWithFilter, EXPR_CAPACITY}; @@ -36,19 +36,19 @@ enum NotState { /// * cast -> On { parent_not_op: None } -> don't change self, because we don't know, what /// value will cast return. As soon as parent_not_op is None, create one as a parent /// node. - On { parent_not_op: Option<usize> }, + On { parent_not_op: Option<NodeId> }, } impl NotState { /// Create new `NotState::On`. - fn on(parent_not_op: Option<usize>) -> Self { + fn on(parent_not_op: Option<NodeId>) -> Self { NotState::On { parent_not_op } } } fn call_expr_tree_not_push_down( plan: &mut Plan, - top_id: usize, + top_id: NodeId, ) -> Result<OldNewTopIdPair, SbroadError> { // Because of the borrow checker we can't change `Bool` and `Row` children during recursive // traversal and have to do it using this map after transformation. @@ -60,7 +60,7 @@ fn call_expr_tree_not_push_down( (top_id, top_id) } else { let old_top_id = plan.clone_expr_subtree(top_id)?; - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { matches!( plan.get_node(node_id), Ok(Node::Expression( @@ -78,8 +78,9 @@ fn call_expr_tree_not_push_down( subtree.populate_nodes(top_id); let nodes = subtree.take_nodes(); drop(subtree); - for (_, id) in &nodes { - let expr = plan.get_mut_expression_node(*id)?; + for level_node in &nodes { + let id = level_node.1; + let expr = plan.get_mut_expression_node(id)?; match expr { Expression::ExprInParentheses { child } => { old_new_expression_map.replace(child); @@ -131,9 +132,9 @@ impl Plan { /// * `not_state` is on and parent `Not` operator is absent -> create new not node. fn cover_with_not( &mut self, - expr_id: usize, + expr_id: NodeId, not_state: &NotState, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { if let NotState::On { parent_not_op } = not_state { if let Some(parent_not_op) = parent_not_op { let parent_not_expr = self.get_mut_expression_node(*parent_not_op)?; @@ -166,10 +167,10 @@ impl Plan { /// Recursive push down of `Not` operator. fn push_down_not_for_expression( &mut self, - expr_id: usize, + expr_id: NodeId, not_state: NotState, map: &mut OldNewExpressionMap, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let expr = self.get_expression_node(expr_id)?; let new_expr_id = match expr { Expression::ExprInParentheses { child } => { diff --git a/sbroad-core/src/ir/transformation/redistribution.rs b/sbroad-core/src/ir/transformation/redistribution.rs index afd9e0f48..1832013da 100644 --- a/sbroad-core/src/ir/transformation/redistribution.rs +++ b/sbroad-core/src/ir/transformation/redistribution.rs @@ -10,8 +10,8 @@ use crate::errors::{Action, Entity, SbroadError}; use crate::frontend::sql::ir::SubtreeCloner; use crate::ir::api::children::Children; use crate::ir::distribution::{Distribution, Key, KeySet}; -use crate::ir::expression::ColumnPositionMap; use crate::ir::expression::Expression; +use crate::ir::expression::{ColumnPositionMap, NodeId}; use crate::ir::operator::{Bool, JoinKind, Relational, Unary, UpdateStrategy}; use crate::ir::transformation::redistribution::eq_cols::EqualityCols; @@ -131,12 +131,12 @@ pub enum MotionOpcode { /// Call `rearrange_for_update` method on vtable and then call `set_update_delete_tuple_len` /// on `Update` relational node. RearrangeForShardedUpdate { - update_id: usize, + update_id: NodeId, old_shard_columns_len: usize, new_shard_columns_positions: Vec<ColumnPosition>, }, AddMissingRowsForLeftJoin { - motion_id: usize, + motion_id: NodeId, }, /// When set to `true` this opcode serializes motion subtree to sql that produces /// empty table. @@ -154,13 +154,13 @@ pub enum MotionOpcode { /// Helper struct that unwraps `Expression::Bool` fields. struct BoolOp { - left: usize, + left: NodeId, op: Bool, - right: usize, + right: NodeId, } impl BoolOp { - fn from_expr(plan: &Plan, expr_id: usize) -> Result<Self, SbroadError> { + fn from_expr(plan: &Plan, expr_id: NodeId) -> Result<Self, SbroadError> { if let Expression::Bool { left, op, right, .. } = plan.get_expression_node(expr_id)? @@ -197,19 +197,19 @@ impl Program { } } -type ChildId = usize; +type ChildId = NodeId; type DataTransformation = (MotionPolicy, Program); /// Helper struct to store motion policy for every child of /// relational node with `parent_id`. #[derive(Debug)] struct Strategy { - parent_id: usize, + parent_id: NodeId, children_policy: HashMap<ChildId, DataTransformation>, } impl Strategy { - fn new(parent_id: usize) -> Self { + fn new(parent_id: NodeId) -> Self { Self { parent_id, children_policy: HashMap::new(), @@ -218,7 +218,7 @@ impl Strategy { /// Add motion policy for child node. /// Update policy in case `child_id` key is already in the `children_policy` map. - fn add_child(&mut self, child_id: usize, policy: MotionPolicy, program: Program) { + fn add_child(&mut self, child_id: NodeId, policy: MotionPolicy, program: Program) { self.children_policy.insert(child_id, (policy, program)); } } @@ -273,8 +273,8 @@ fn join_policy_for_and( impl Plan { /// Get unary NOT expression nodes. - pub(crate) fn get_not_unary_nodes(&self, top: usize) -> Vec<LevelNode> { - let filter = |node_id: usize| -> bool { + pub(crate) fn get_not_unary_nodes(&self, top: NodeId) -> Vec<LevelNode<NodeId>> { + let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), Ok(Node::Expression(Expression::Unary { op: Unary::Not, .. })) @@ -296,8 +296,8 @@ impl Plan { /// /// # Errors /// - some of the expression nodes are invalid - pub(crate) fn get_bool_nodes_with_row_children(&self, top: usize) -> Vec<LevelNode> { - let filter = |node_id: usize| -> bool { + pub(crate) fn get_bool_nodes_with_row_children(&self, top: NodeId) -> Vec<LevelNode<NodeId>> { + let filter = |node_id: NodeId| -> bool { // Append only booleans with row children. if let Ok(Node::Expression(Expression::Bool { left, right, .. })) = self.get_node(node_id) @@ -332,8 +332,8 @@ impl Plan { /// /// # Errors /// - some of the expression nodes are invalid - pub(crate) fn get_unary_nodes_with_row_children(&self, top: usize) -> Vec<LevelNode> { - let filter = |node_id: usize| -> bool { + pub(crate) fn get_unary_nodes_with_row_children(&self, top: NodeId) -> Vec<LevelNode<NodeId>> { + let filter = |node_id: NodeId| -> bool { // Append only unaries with row children. if let Ok(Node::Expression(Expression::Unary { child, .. })) = self.get_node(node_id) { let child_is_row = matches!( @@ -360,7 +360,10 @@ impl Plan { /// # Errors /// - Row node is not of a row type /// There are more than one sub-queries in the row node. - pub fn get_sub_query_from_row_node(&self, row_id: usize) -> Result<Option<usize>, SbroadError> { + pub fn get_sub_query_from_row_node( + &self, + row_id: NodeId, + ) -> Result<Option<NodeId>, SbroadError> { let rel_ids = self.get_relational_nodes_from_row(row_id)?; self.get_sub_query_among_rel_nodes(&rel_ids) } @@ -372,9 +375,9 @@ impl Plan { /// - There are more than one sub-query pub fn get_sub_query_among_rel_nodes( &self, - rel_nodes: &HashSet<usize, RandomState>, - ) -> Result<Option<usize>, SbroadError> { - let mut sq_set: HashSet<usize, RandomState> = HashSet::with_hasher(RandomState::new()); + rel_nodes: &HashSet<NodeId, RandomState>, + ) -> Result<Option<NodeId>, SbroadError> { + let mut sq_set: HashSet<NodeId, RandomState> = HashSet::with_hasher(RandomState::new()); for rel_id in rel_nodes { if let Node::Relational(Relational::ScanSubQuery { .. }) = self.get_node(*rel_id)? { sq_set.insert(*rel_id); @@ -398,7 +401,7 @@ impl Plan { /// # Errors /// - Row node is not of a row type /// - There are more than one motion nodes in the row node - pub fn get_motion_from_row(&self, node_id: usize) -> Result<Option<usize>, SbroadError> { + pub fn get_motion_from_row(&self, node_id: NodeId) -> Result<Option<NodeId>, SbroadError> { let rel_nodes = self.get_relational_nodes_from_row(node_id)?; self.get_motion_among_rel_nodes(&rel_nodes) } @@ -409,9 +412,9 @@ impl Plan { /// - Some of the nodes are not relational pub fn get_motion_among_rel_nodes( &self, - rel_nodes: &HashSet<usize, RandomState>, - ) -> Result<Option<usize>, SbroadError> { - let mut motion_set: HashSet<usize> = HashSet::new(); + rel_nodes: &HashSet<NodeId, RandomState>, + ) -> Result<Option<NodeId>, SbroadError> { + let mut motion_set: HashSet<NodeId> = HashSet::new(); for child in rel_nodes { if self.get_relation_node(*child)?.is_motion() { @@ -442,9 +445,9 @@ impl Plan { /// In such case join/selection can be done locally. fn has_eq_on_bucket_id( &self, - left_row_id: usize, - right_row_id: usize, - rel_id: usize, + left_row_id: NodeId, + right_row_id: NodeId, + rel_id: NodeId, op: &Bool, ) -> Result<bool, SbroadError> { if !(Bool::Eq == *op || Bool::In == *op) { @@ -461,8 +464,8 @@ impl Plan { // Equality pair `a = b` allows us to do local join. // // position in row that refers to shard column -> child id - let mut memo: AHashMap<usize, usize> = AHashMap::new(); - let mut search_row = |row_id: usize| -> Result<bool, SbroadError> { + let mut memo: AHashMap<usize, NodeId> = AHashMap::new(); + let mut search_row = |row_id: NodeId| -> Result<bool, SbroadError> { let refs = self.get_row_list(row_id)?; for (pos_in_row, ref_id) in refs.iter().enumerate() { let node @ Expression::Reference { @@ -477,7 +480,7 @@ impl Plan { SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "ref ({ref_id}) in join condition with no targets: {node:?}" + "ref ({ref_id:?}) in join condition with no targets: {node:?}" )), ) })?; @@ -485,7 +488,7 @@ impl Plan { SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "ref ({ref_id}) in join condition with empty targets: {node:?}" + "ref ({ref_id:?}) in join condition with empty targets: {node:?}" )), ) })?; @@ -517,8 +520,8 @@ impl Plan { /// - uninitialized distribution for some row fn choose_strategy_for_bool_op_inner_sq( &self, - outer_id: usize, - inner_id: usize, + outer_id: NodeId, + inner_id: NodeId, op: &Bool, ) -> Result<MotionPolicy, SbroadError> { let outer_dist = self.get_distribution(outer_id)?; @@ -574,7 +577,7 @@ impl Plan { } // Check that all children we need to add motions exist in the current relational node. - let children_set: HashSet<usize> = children.iter().copied().collect(); + let children_set: HashSet<NodeId> = children.iter().copied().collect(); if !strategy .children_policy .iter() @@ -588,7 +591,7 @@ impl Plan { } // Add motions. - let mut children_with_motions: Vec<usize> = Vec::new(); + let mut children_with_motions: Vec<NodeId> = Vec::new(); let children_owned = children.to_vec(); for child in children_owned { if let Some((policy, ref mut program)) = strategy.children_policy.get_mut(&child) { @@ -610,9 +613,9 @@ impl Plan { /// Only returns `SubQuery` that is an additional child of passed `rel_id` node. fn get_additional_sq( &self, - rel_id: usize, - row_id: usize, - ) -> Result<Option<usize>, SbroadError> { + rel_id: NodeId, + row_id: NodeId, + ) -> Result<Option<NodeId>, SbroadError> { if self.get_expression_node(row_id)?.is_row() { if let Some(sq_id) = self.get_sub_query_from_row_node(row_id)? { if self.is_additional_child_of_rel(rel_id, sq_id)? { @@ -626,10 +629,10 @@ impl Plan { /// Get `SubQuery`s from passed boolean `op_id` node (e.g. `In`). fn get_sq_node_strategies_for_bool_op( &self, - rel_id: usize, - op_id: usize, - ) -> Result<Vec<(usize, MotionPolicy)>, SbroadError> { - let mut strategies: Vec<(usize, MotionPolicy)> = Vec::new(); + rel_id: NodeId, + op_id: NodeId, + ) -> Result<Vec<(NodeId, MotionPolicy)>, SbroadError> { + let mut strategies: Vec<(NodeId, MotionPolicy)> = Vec::new(); let bool_op = BoolOp::from_expr(self, op_id)?; let left = self.get_additional_sq(rel_id, bool_op.left)?; let right = self.get_additional_sq(rel_id, bool_op.right)?; @@ -693,9 +696,9 @@ impl Plan { /// Get `SubQuery`s from passed unary `op_id` node (e.g. `Exists`). fn get_sq_node_strategy_for_unary_op( &self, - rel_id: usize, - op_id: usize, - ) -> Result<Option<(usize, MotionPolicy)>, SbroadError> { + rel_id: NodeId, + op_id: NodeId, + ) -> Result<Option<(NodeId, MotionPolicy)>, SbroadError> { let unary_op_expr = self.get_expression_node(op_id)?; let Expression::Unary { child, op } = unary_op_expr else { return Err(SbroadError::Invalid( @@ -722,15 +725,16 @@ impl Plan { /// Resolve sub-query conflicts with motion policies. fn resolve_sub_query_conflicts( &mut self, - select_id: usize, - filter_id: usize, + select_id: NodeId, + filter_id: NodeId, ) -> Result<Strategy, SbroadError> { let mut strategy = Strategy::new(select_id); let not_nodes = self.get_not_unary_nodes(filter_id); let mut not_nodes_children = HashSet::with_capacity(not_nodes.len()); - for (_, not_node_id) in ¬_nodes { - let not_node = self.get_expression_node(*not_node_id)?; + for level_node in ¬_nodes { + let not_node_id = level_node.1; + let not_node = self.get_expression_node(not_node_id)?; if let Expression::Unary { child, .. } = not_node { not_nodes_children.insert(*child); } else { @@ -742,13 +746,13 @@ impl Plan { } let bool_nodes = self.get_bool_nodes_with_row_children(filter_id); - for (_, bool_node) in &bool_nodes { + for LevelNode(_, bool_node) in &bool_nodes { let bool_op = BoolOp::from_expr(self, *bool_node)?; self.set_distribution(bool_op.left)?; self.set_distribution(bool_op.right)?; } - for (_, bool_node) in &bool_nodes { + for LevelNode(_, bool_node) in &bool_nodes { let strategies = self.get_sq_node_strategies_for_bool_op(select_id, *bool_node)?; for (id, policy) in strategies { // In case we faced with `not ... in ...`, we @@ -762,8 +766,9 @@ impl Plan { } let unary_nodes = self.get_unary_nodes_with_row_children(filter_id); - for (_, unary_node) in &unary_nodes { - let unary_strategy = self.get_sq_node_strategy_for_unary_op(select_id, *unary_node)?; + for level_node in &unary_nodes { + let unary_node = level_node.1; + let unary_strategy = self.get_sq_node_strategy_for_unary_op(select_id, unary_node)?; if let Some((id, policy)) = unary_strategy { strategy.add_child(id, policy, Program::default()); } @@ -783,7 +788,7 @@ impl Plan { /// # Errors /// - If the node is not a join node. /// - Join node has no children. - fn get_join_children(&self, join_id: usize) -> Result<Children<'_>, SbroadError> { + fn get_join_children(&self, join_id: NodeId) -> Result<Children<'_>, SbroadError> { let join = self.get_relation_node(join_id)?; if let Relational::Join { .. } = join { } else { @@ -799,10 +804,10 @@ impl Plan { fn get_join_child_by_key( &self, key: &Key, - row_map: &HashMap<usize, usize>, + row_map: &HashMap<usize, NodeId>, join_children: &Children<'_>, - ) -> Result<usize, SbroadError> { - let mut children_set: HashSet<usize> = HashSet::new(); + ) -> Result<NodeId, SbroadError> { + let mut children_set: HashSet<NodeId> = HashSet::new(); for pos in &key.positions { let column_id = *row_map.get(pos).ok_or_else(|| { SbroadError::NotFound( @@ -845,9 +850,9 @@ impl Plan { /// /// # Errors /// - If the node is not a row node. - fn build_row_map(&self, row_id: usize) -> Result<HashMap<usize, usize>, SbroadError> { + fn build_row_map(&self, row_id: NodeId) -> Result<HashMap<usize, NodeId>, SbroadError> { let columns = self.get_expression_node(row_id)?.get_row_list()?; - let mut map: HashMap<usize, usize> = HashMap::new(); + let mut map: HashMap<usize, NodeId> = HashMap::new(); for (pos, col) in columns.iter().enumerate() { map.insert(pos, *col); } @@ -863,9 +868,9 @@ impl Plan { /// - Distribution keys do not refer to inner or outer children of the join. fn split_join_keys_to_inner_and_outer( &self, - join_id: usize, + join_id: NodeId, keys: &[Key], - row_map: &HashMap<usize, usize>, + row_map: &HashMap<usize, NodeId>, ) -> Result<(Vec<Key>, Vec<Key>), SbroadError> { let mut outer_keys: Vec<Key> = Vec::new(); let mut inner_keys: Vec<Key> = Vec::new(); @@ -903,7 +908,7 @@ impl Plan { /// This function extracts only the positions of the references to the inner child. fn get_inner_positions_from_condition_row( &self, - row_map: &HashMap<usize, usize>, + row_map: &HashMap<usize, NodeId>, ) -> Result<AHashSet<usize>, SbroadError> { let mut inner_positions: AHashSet<usize> = AHashSet::with_capacity(row_map.len()); for (pos, col) in row_map { @@ -927,7 +932,7 @@ impl Plan { fn get_referred_inner_child_column_positions( &self, column_positions: &[usize], - condition_row_map: &HashMap<usize, usize>, + condition_row_map: &HashMap<usize, NodeId>, ) -> Result<Vec<usize>, SbroadError> { let mut referred_column_positions: Vec<usize> = Vec::with_capacity(column_positions.len()); for pos in column_positions { @@ -967,7 +972,7 @@ impl Plan { fn get_inner_policy_by_outer_segment( &self, outer_keys: &[Key], - inner_row_map: &HashMap<usize, usize>, + inner_row_map: &HashMap<usize, NodeId>, ) -> Result<MotionPolicy, SbroadError> { let inner_position_map = self.get_inner_positions_from_condition_row(inner_row_map)?; for outer_key in outer_keys { @@ -1004,9 +1009,9 @@ impl Plan { /// - Failed to split distribution keys in the row to inner and outer keys. fn join_policy_for_eq( &self, - join_id: usize, - left_row_id: usize, - right_row_id: usize, + join_id: NodeId, + left_row_id: NodeId, + right_row_id: NodeId, ) -> Result<MotionPolicy, SbroadError> { if self.has_eq_on_bucket_id(left_row_id, right_row_id, join_id, &Bool::Eq)? { return Ok(MotionPolicy::None); @@ -1086,10 +1091,11 @@ impl Plan { } } - fn set_rows_distributions_in_expr(&mut self, expr_id: usize) -> Result<(), SbroadError> { + fn set_rows_distributions_in_expr(&mut self, expr_id: NodeId) -> Result<(), SbroadError> { let nodes = self.get_bool_nodes_with_row_children(expr_id); - for (_, node) in &nodes { - let bool_op = BoolOp::from_expr(self, *node)?; + for level_node in &nodes { + let node = level_node.1; + let bool_op = BoolOp::from_expr(self, node)?; self.set_distribution(bool_op.left)?; self.set_distribution(bool_op.right)?; } @@ -1103,8 +1109,8 @@ impl Plan { #[allow(clippy::too_many_lines)] fn resolve_join_conflicts( &mut self, - rel_id: usize, - cond_id: usize, + rel_id: NodeId, + cond_id: NodeId, join_kind: &JoinKind, ) -> Result<(), SbroadError> { // If one of the children has Distribution::Single, then we can't compute Distribution of @@ -1154,9 +1160,9 @@ impl Plan { (inner, outer) }; - let mut inner_map: HashMap<usize, MotionPolicy> = HashMap::new(); + let mut inner_map: HashMap<NodeId, MotionPolicy> = HashMap::new(); let mut new_inner_policy = MotionPolicy::Full; - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), Ok(Node::Expression( @@ -1172,7 +1178,8 @@ impl Plan { expr_tree.populate_nodes(cond_id); let nodes = expr_tree.take_nodes(); drop(expr_tree); - for (_, node_id) in nodes { + for level_node in nodes { + let node_id = level_node.1; let expr = self.get_expression_node(node_id)?; // Under `not ... in ...` we should change the policy to `Full` @@ -1345,12 +1352,12 @@ impl Plan { /// for `Single` no motion is needed. fn fix_sq_strategy_for_global_tbl( &self, - rel_id: usize, - cond_id: usize, + rel_id: NodeId, + cond_id: NodeId, strategy: &mut Strategy, ) -> Result<(), SbroadError> { let chains = self.get_dnf_chains(cond_id)?; - let mut subqueries: Vec<usize> = vec![]; + let mut subqueries: Vec<NodeId> = vec![]; let mut chain_count: usize = 0; for mut chain in chains { let nodes = chain.get_mut_nodes(); @@ -1485,8 +1492,8 @@ impl Plan { #[allow(clippy::too_many_lines)] fn calculate_strategy_for_single_distribution( &mut self, - join_id: usize, - condition_id: usize, + join_id: NodeId, + condition_id: NodeId, join_kind: &JoinKind, ) -> Result<Option<Strategy>, SbroadError> { let (outer_id, inner_id) = { @@ -1494,12 +1501,12 @@ impl Plan { ( *children.get(0).ok_or_else(|| { SbroadError::UnexpectedNumberOfValues(format_smolstr!( - "join {join_id} has no children!" + "join {join_id:?} has no children!" )) })?, *children.get(1).ok_or_else(|| { SbroadError::UnexpectedNumberOfValues(format_smolstr!( - "join {join_id} has one child!" + "join {join_id:?} has one child!" )) })?, ) @@ -1581,7 +1588,7 @@ impl Plan { } #[allow(clippy::too_many_lines)] - fn resolve_update_conflicts(&mut self, update_id: usize) -> Result<Strategy, SbroadError> { + fn resolve_update_conflicts(&mut self, update_id: NodeId) -> Result<Strategy, SbroadError> { if self.dml_node_table(update_id)?.is_global() { return self.resolve_dml_node_conflict_for_global_table(update_id); } @@ -1597,7 +1604,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Update, Some(format_smolstr!( - "expected Projection under Update ({update_id})" + "expected Projection under Update ({update_id:?})" )), )); } @@ -1728,12 +1735,12 @@ impl Plan { } else { Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("expected Update node on id {update_id}")), + Some(format_smolstr!("expected Update node on id {update_id:?}")), )) } } - fn resolve_delete_conflicts(&mut self, rel_id: usize) -> Result<Strategy, SbroadError> { + fn resolve_delete_conflicts(&mut self, rel_id: NodeId) -> Result<Strategy, SbroadError> { if self.dml_node_table(rel_id)?.is_global() { return self.resolve_dml_node_conflict_for_global_table(rel_id); } @@ -1766,7 +1773,7 @@ impl Plan { fn resolve_dml_node_conflict_for_global_table( &mut self, - rel_id: usize, + rel_id: NodeId, ) -> Result<Strategy, SbroadError> { let mut map = Strategy::new(rel_id); let child_id = self.dml_child_id(rel_id)?; @@ -1777,7 +1784,7 @@ impl Plan { Ok(map) } - fn resolve_insert_conflicts(&mut self, rel_id: usize) -> Result<Strategy, SbroadError> { + fn resolve_insert_conflicts(&mut self, rel_id: NodeId) -> Result<Strategy, SbroadError> { if self.dml_node_table(rel_id)?.is_global() { return self.resolve_dml_node_conflict_for_global_table(rel_id); } @@ -1812,7 +1819,7 @@ impl Plan { Ok(map) } - fn resolve_cte_conflicts(&mut self, cte_id: usize) -> Result<Strategy, SbroadError> { + fn resolve_cte_conflicts(&mut self, cte_id: NodeId) -> Result<Strategy, SbroadError> { // We always gather CTE data on the router node. let mut map = Strategy::new(cte_id); let child_id = self.get_relational_child(cte_id, 0)?; @@ -1852,7 +1859,11 @@ impl Plan { // select "bucket_id" as a from t1 // except // select "bucket_id" as b from t1 - fn is_except_on_bucket_id(&self, left_id: usize, right_id: usize) -> Result<bool, SbroadError> { + fn is_except_on_bucket_id( + &self, + left_id: NodeId, + right_id: NodeId, + ) -> Result<bool, SbroadError> { let mut context = self.context_mut(); let Some(left_shard_positions) = context.get_shard_columns_positions(left_id, self)?.copied() @@ -1874,7 +1885,7 @@ impl Plan { } #[allow(clippy::too_many_lines)] - fn resolve_except_conflicts(&mut self, rel_id: usize) -> Result<Strategy, SbroadError> { + fn resolve_except_conflicts(&mut self, rel_id: NodeId) -> Result<Strategy, SbroadError> { if !matches!(self.get_relation_node(rel_id)?, Relational::Except { .. }) { return Err(SbroadError::Invalid( Entity::Relational, @@ -1940,7 +1951,7 @@ impl Plan { SbroadError::Invalid( Entity::Distribution, Some(format_smolstr!( - "{} {} {right_id}", + "{} {} {right_id:?}", "Segment distribution with no keys.", "Except right child:" )), @@ -1998,7 +2009,7 @@ impl Plan { /// Projection a /// scan g /// ``` - fn resolve_except_global_vs_sharded(&mut self, except_id: usize) -> Result<bool, SbroadError> { + fn resolve_except_global_vs_sharded(&mut self, except_id: NodeId) -> Result<bool, SbroadError> { let left_id = self.get_relational_child(except_id, 0)?; let right_id = self.get_relational_child(except_id, 1)?; let left_dist = self.get_rel_distribution(left_id)?; @@ -2013,7 +2024,7 @@ impl Plan { return Ok(false); } - let cloned_left_id = SubtreeCloner::clone_subtree(self, left_id, left_id)?; + let cloned_left_id = SubtreeCloner::clone_subtree(self, left_id, left_id.offset as usize)?; let right_output_id = self.get_relational_output(right_id)?; let intersect_output_id = self.clone_expr_subtree(right_output_id)?; let intersect = Relational::Intersect { @@ -2032,7 +2043,7 @@ impl Plan { Ok(true) } - fn resolve_union_conflicts(&mut self, rel_id: usize) -> Result<Strategy, SbroadError> { + fn resolve_union_conflicts(&mut self, rel_id: NodeId) -> Result<Strategy, SbroadError> { if !matches!( self.get_relation_node(rel_id)?, Relational::UnionAll { .. } | Relational::Union { .. } @@ -2125,8 +2136,8 @@ impl Plan { /// - failed to set distribution #[otm_child_span("plan.transformation.add_motions")] pub fn add_motions(&mut self) -> Result<(), SbroadError> { - type CteChildId = usize; - type MotionId = usize; + type CteChildId = ChildId; + type MotionId = ChildId; let mut cte_motions: AHashMap<CteChildId, MotionId> = AHashMap::with_capacity(CTE_CAPACITY); let top = self.get_top()?; let mut post_tree = @@ -2134,9 +2145,9 @@ impl Plan { post_tree.populate_nodes(top); let nodes = post_tree.take_nodes(); let mut visited = AHashSet::with_capacity(nodes.len()); - let mut old_new: AHashMap<usize, usize> = AHashMap::new(); + let mut old_new: AHashMap<NodeId, NodeId> = AHashMap::new(); - for (_, id) in nodes { + for LevelNode(_, id) in nodes { if visited.contains(&id) { continue; } @@ -2350,8 +2361,8 @@ impl Plan { /// /// # Errors /// - failed to traverse plan - pub fn calculate_slices(&self, top_id: usize) -> Result<Vec<Vec<usize>>, SbroadError> { - let mut motions: Vec<Vec<usize>> = Vec::new(); + pub fn calculate_slices(&self, top_id: NodeId) -> Result<Vec<Vec<NodeId>>, SbroadError> { + let mut motions: Vec<Vec<NodeId>> = Vec::new(); let mut bft_tree = BreadthFirst::with_capacity( |node| self.nodes.rel_iter(node), REL_CAPACITY, @@ -2359,7 +2370,7 @@ impl Plan { ); let mut map: HashMap<usize, usize> = HashMap::new(); let mut max_level: usize = 0; - for (level, id) in bft_tree.iter(top_id) { + for LevelNode(level, id) in bft_tree.iter(top_id) { if let Node::Relational(Relational::Motion { .. }) = self.get_node(id)? { let key: usize = match map.entry(level) { Entry::Occupied(o) => *o.into_mut(), diff --git a/sbroad-core/src/ir/transformation/redistribution/dml.rs b/sbroad-core/src/ir/transformation/redistribution/dml.rs index 29afb5da0..b29de812b 100644 --- a/sbroad-core/src/ir/transformation/redistribution/dml.rs +++ b/sbroad-core/src/ir/transformation/redistribution/dml.rs @@ -1,4 +1,5 @@ use crate::errors::{Entity, SbroadError}; +use crate::ir::expression::NodeId; use crate::ir::operator::{ConflictStrategy, Relational, UpdateStrategy}; use crate::ir::relation::{Column, Table}; use crate::ir::transformation::redistribution::MotionOpcode; @@ -14,7 +15,7 @@ impl Plan { /// # Errors /// - node is not `Insert` /// - `Insert` has 0 or more than 1 child - pub fn dml_child_id(&self, dml_node_id: usize) -> Result<usize, SbroadError> { + pub fn dml_child_id(&self, dml_node_id: NodeId) -> Result<NodeId, SbroadError> { let dml_node = self.get_relation_node(dml_node_id)?; if let Relational::Insert { children, .. } | Relational::Update { children, .. } @@ -30,7 +31,7 @@ impl Plan { } Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("dml node with id {dml_node_id}")), + Some(format_smolstr!("dml node with id {dml_node_id:?}")), )) } @@ -40,7 +41,7 @@ impl Plan { /// - node is not an `Insert` pub fn insert_conflict_strategy( &self, - insert_id: usize, + insert_id: NodeId, ) -> Result<&ConflictStrategy, SbroadError> { let insert = self.get_relation_node(insert_id)?; if let Relational::Insert { @@ -52,12 +53,12 @@ impl Plan { Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "INSERT with id {insert_id} (conflict strategy))" + "INSERT with id {insert_id:?} (conflict strategy))" )), )) } - pub(crate) fn insert_motion_key(&self, insert_id: usize) -> Result<MotionKey, SbroadError> { + pub(crate) fn insert_motion_key(&self, insert_id: NodeId) -> Result<MotionKey, SbroadError> { let columns = self.insert_columns(insert_id)?; // Revert map of { pos_in_child_node -> pos_in_relation } // into map of { pos_in_relation -> pos_in_child_node }. @@ -76,7 +77,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "INSERT with id {} has {} columns, but the child node with id {} has {}", + "INSERT with id {:?} has {} columns, but the child node with id {:?} has {}", insert_id, columns.len(), child_id, @@ -114,14 +115,14 @@ impl Plan { /// /// # Errors /// - node is not `Insert` - pub(crate) fn insert_columns(&self, insert_id: usize) -> Result<&[usize], SbroadError> { + pub(crate) fn insert_columns(&self, insert_id: NodeId) -> Result<&[usize], SbroadError> { let insert = self.get_relation_node(insert_id)?; if let Relational::Insert { ref columns, .. } = insert { return Ok(columns); } Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("expected insert node on id {insert_id}")), + Some(format_smolstr!("expected insert node on id {insert_id:?}")), )) } @@ -129,7 +130,7 @@ impl Plan { /// /// # Errors /// - Node is not an `Insert` - pub fn dml_node_table(&self, node_id: usize) -> Result<&Table, SbroadError> { + pub fn dml_node_table(&self, node_id: NodeId) -> Result<&Table, SbroadError> { let node = self.get_relation_node(node_id)?; if let Relational::Insert { relation, .. } | Relational::Update { relation, .. } @@ -139,7 +140,7 @@ impl Plan { } Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("DML node with id {node_id}")), + Some(format_smolstr!("DML node with id {node_id:?}")), )) } @@ -150,7 +151,7 @@ impl Plan { /// - Node is not an sharded `Update` pub fn set_update_delete_tuple_len( &mut self, - update_id: usize, + update_id: NodeId, len: usize, ) -> Result<(), SbroadError> { let node = self.get_mut_relation_node(update_id)?; @@ -178,7 +179,7 @@ impl Plan { /// # Errors /// - Node is not an sharded `Update` /// - length not set on current `Update` node - pub fn get_update_delete_tuple_len(&self, update_id: usize) -> Result<usize, SbroadError> { + pub fn get_update_delete_tuple_len(&self, update_id: NodeId) -> Result<usize, SbroadError> { let node = self.get_relation_node(update_id)?; if let Relational::Update { strategy: @@ -206,7 +207,7 @@ impl Plan { /// - invalid index pub fn get_motion_opcode( &self, - motion_id: usize, + motion_id: NodeId, opcode_idx: usize, ) -> Result<&MotionOpcode, SbroadError> { let node = self.get_relation_node(motion_id)?; @@ -229,7 +230,7 @@ impl Plan { /// /// # Errors /// - Node is not an `Update` - pub fn is_sharded_update(&self, update_id: usize) -> Result<bool, SbroadError> { + pub fn is_sharded_update(&self, update_id: NodeId) -> Result<bool, SbroadError> { let node = self.get_relation_node(update_id)?; if let Relational::Update { strategy, .. } = node { return Ok(matches!(strategy, UpdateStrategy::ShardedUpdate { .. })); diff --git a/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs b/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs index 7cb632af0..67e531528 100644 --- a/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs +++ b/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs @@ -1,5 +1,5 @@ use crate::errors::SbroadError; -use crate::ir::expression::{Expression, ExpressionId}; +use crate::ir::expression::{Expression, ExpressionId, NodeId}; use crate::ir::operator::Bool; use crate::ir::transformation::redistribution::BoolOp; use crate::ir::tree::traversal::{PostOrder, PostOrderWithFilter, EXPR_CAPACITY}; @@ -65,13 +65,14 @@ impl ReferredMap { pub fn new_from_join_condition( plan: &Plan, - condition_id: usize, - join_id: usize, + condition_id: NodeId, + join_id: NodeId, ) -> Result<Self, SbroadError> { let mut referred = ReferredMap::with_capacity(EXPR_CAPACITY); let mut expr_tree = PostOrder::with_capacity(|node| plan.nodes.expr_iter(node, false), EXPR_CAPACITY); - for (_, node_id) in expr_tree.iter(condition_id) { + for level_node in expr_tree.iter(condition_id) { + let node_id = level_node.1; let expr = plan.get_expression_node(node_id)?; let res = match expr { Expression::Bool { left, right, .. } @@ -225,7 +226,7 @@ impl EqualityCols { /// by returned `EqualityCols`. fn eq_cols_for_bool( op: &BoolOp, - node_id: usize, + node_id: NodeId, refers_to: &ReferredMap, node_eq_cols: &mut EqualityColsMap, ) -> Option<EqualityCols> { @@ -276,10 +277,10 @@ impl EqualityCols { /// - non-empty `EqualityCols` in case the subtree is "good" and supports repartition join /// by returned `EqualityCols`. fn eq_cols_for_eq( - list_left: &[usize], - list_right: &[usize], - node_id: usize, - inner_id: usize, + list_left: &[NodeId], + list_right: &[NodeId], + node_id: NodeId, + inner_id: NodeId, plan: &Plan, refers_to: &ReferredMap, ) -> Result<Option<EqualityCols>, SbroadError> { @@ -350,9 +351,9 @@ impl EqualityCols { /// by returned `EqualityCols`. fn eq_cols_for_rows( op: &BoolOp, - node_id: usize, + node_id: NodeId, refers_to: &ReferredMap, - inner_id: usize, + inner_id: NodeId, plan: &Plan, ) -> Result<Option<EqualityCols>, SbroadError> { let left_expr = plan.get_expression_node(op.left)?; @@ -413,8 +414,8 @@ impl EqualityCols { /// - non-empty `EqualityCols` in case the subtree is "good" and supports repartition join /// by returned `EqualityCols`. fn eq_cols_for_and( - left: usize, - right: usize, + left: NodeId, + right: NodeId, refers_to: &ReferredMap, map: &mut EqualityColsMap, ) -> Option<EqualityCols> { @@ -481,13 +482,13 @@ impl EqualityCols { /// - Otherwise, returns non-empty `EqualityCols` wrapped in `Option` pub fn from_join_condition( plan: &Plan, - join_id: usize, - inner_id: usize, - condition_id: usize, + join_id: NodeId, + inner_id: NodeId, + condition_id: NodeId, ) -> Result<Option<EqualityCols>, SbroadError> { let mut node_eq_cols: EqualityColsMap = EqualityColsMap::new(); let refers_to = ReferredMap::new_from_join_condition(plan, condition_id, join_id)?; - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { if let Ok(Node::Expression(Expression::Bool { .. })) = plan.get_node(node_id) { return true; } @@ -498,7 +499,8 @@ impl EqualityCols { EXPR_CAPACITY, Box::new(filter), ); - for (_, node_id) in expr_tree.iter(condition_id) { + for level_node in expr_tree.iter(condition_id) { + let node_id = level_node.1; let bool_op = BoolOp::from_expr(plan, node_id)?; let left_expr = plan.get_expression_node(bool_op.left)?; let right_expr = plan.get_expression_node(bool_op.right)?; diff --git a/sbroad-core/src/ir/transformation/redistribution/groupby.rs b/sbroad-core/src/ir/transformation/redistribution/groupby.rs index bb87f2532..ac587a759 100644 --- a/sbroad-core/src/ir/transformation/redistribution/groupby.rs +++ b/sbroad-core/src/ir/transformation/redistribution/groupby.rs @@ -6,7 +6,8 @@ use crate::ir::aggregates::{generate_local_alias_for_aggr, AggregateKind, Simple use crate::ir::distribution::Distribution; use crate::ir::expression::Expression::StableFunction; use crate::ir::expression::{ - ColumnPositionMap, Comparator, Expression, FunctionFeature, ReferencePolicy, EXPR_HASH_DEPTH, + ColumnPositionMap, Comparator, Expression, FunctionFeature, NodeId, ReferencePolicy, + EXPR_HASH_DEPTH, }; use crate::ir::operator::Relational; use crate::ir::relation::Type; @@ -14,7 +15,7 @@ use crate::ir::transformation::redistribution::{ MotionKey, MotionPolicy, Program, Strategy, Target, }; use crate::ir::tree::traversal::{BreadthFirst, PostOrderWithFilter, EXPR_CAPACITY}; -use crate::ir::{Node, Plan}; +use crate::ir::{ArenaType, Node, Plan}; use std::collections::{HashMap, HashSet}; use crate::ir::function::{Behavior, Function}; @@ -29,10 +30,10 @@ const AGGR_CAPACITY: usize = 10; struct AggrInfo { /// id of Relational node in which this aggregate is located. /// It can be located in `Projection`, `Having`, `OrderBy` - parent_rel: usize, + parent_rel: NodeId, /// id of parent expression of aggregate function, /// if there is no parent it's `None` - parent_expr: Option<usize>, + parent_expr: Option<NodeId>, /// info about what aggregate it is: sum, count, ... aggr: SimpleAggregate, /// whether this aggregate was marked distinct in original user query @@ -42,7 +43,7 @@ struct AggrInfo { /// Helper struct to find aggregates in expressions of finals struct AggrCollector<'plan> { /// id of final node in which matches are searched - parent_rel: Option<usize>, + parent_rel: Option<NodeId>, /// collected aggregates infos: Vec<AggrInfo>, plan: &'plan Plan, @@ -55,13 +56,13 @@ struct AggrCollector<'plan> { /// For example grouping expressions can appear /// in `Projection`, `Having`, `OrderBy` struct ExpressionLocationIds { - pub parent_expr: Option<usize>, - pub expr: usize, - pub rel: usize, + pub parent_expr: Option<NodeId>, + pub expr: NodeId, + pub rel: NodeId, } impl ExpressionLocationIds { - pub fn new(expr_id: usize, parent_expr_id: Option<usize>, rel_id: usize) -> Self { + pub fn new(expr_id: NodeId, parent_expr_id: Option<NodeId>, rel_id: NodeId) -> Self { ExpressionLocationIds { parent_expr: parent_expr_id, expr: expr_id, @@ -80,7 +81,7 @@ impl ExpressionLocationIds { struct AggregateSignature<'plan, 'args> { pub kind: AggregateKind, /// ids of expressions used as arguments to aggregate - pub arguments: &'args Vec<usize>, + pub arguments: &'args Vec<NodeId>, pub plan: &'plan Plan, /// reference to local alias of this local aggregate pub local_alias: Option<Rc<String>>, @@ -131,12 +132,12 @@ impl<'plan, 'args> PartialEq<Self> for AggregateSignature<'plan, 'args> { impl<'plan, 'args> Eq for AggregateSignature<'plan, 'args> {} struct GroupingExpression<'plan> { - pub id: usize, + pub id: NodeId, pub plan: &'plan Plan, } impl<'plan> GroupingExpression<'plan> { - pub fn new(id: usize, plan: &'plan Plan) -> Self { + pub fn new(id: NodeId, plan: &'plan Plan) -> Self { GroupingExpression { id, plan } } } @@ -180,14 +181,18 @@ impl<'plan> AggrCollector<'plan> { /// /// # Errors /// - invalid expression tree pointed by `top` - pub fn collect_aggregates(&mut self, top: usize, parent_rel: usize) -> Result<(), SbroadError> { + pub fn collect_aggregates( + &mut self, + top: NodeId, + parent_rel: NodeId, + ) -> Result<(), SbroadError> { self.parent_rel = Some(parent_rel); self.find(top, None)?; self.parent_rel = None; Ok(()) } - fn find(&mut self, current: usize, parent: Option<usize>) -> Result<(), SbroadError> { + fn find(&mut self, current: NodeId, parent: Option<NodeId>) -> Result<(), SbroadError> { let expr = self.plan.get_expression_node(current)?; if let StableFunction { name, feature, .. } = expr { let is_distinct = matches!(feature, Some(FunctionFeature::Distinct)); @@ -219,7 +224,7 @@ impl<'plan> AggrCollector<'plan> { /// For example: /// `select a from t group by a having a = 1` /// Here expression in `GroupBy` is mapped to `a` in `Projection` and `a` in `Having` -type GroupbyExpressionsMap = HashMap<usize, Vec<ExpressionLocationIds>>; +type GroupbyExpressionsMap = HashMap<NodeId, Vec<ExpressionLocationIds>>; /// Maps id of `GroupBy` expression used in `GroupBy` (from local stage) /// to corresponding local alias used in local Projection. Note: /// this map does not contain mappings between grouping expressions from @@ -230,22 +235,22 @@ type GroupbyExpressionsMap = HashMap<usize, Vec<ExpressionLocationIds>>; /// initial query: `select a, count(distinct b) from t group by a` /// map query: `select a as l1, b group by a, b` /// Then this map will map id of `a` to `l1` -type LocalAliasesMap = HashMap<usize, Rc<String>>; -type LocalAggrInfo = (AggregateKind, Vec<usize>, Rc<String>); +type LocalAliasesMap = HashMap<NodeId, Rc<String>>; +type LocalAggrInfo = (AggregateKind, Vec<NodeId>, Rc<String>); /// Helper struct to map expressions used in `GroupBy` to /// expressions used in some other node (`Projection`, `Having`, `OrderBy`) struct ExpressionMapper<'plan> { /// List of expressions ids of `GroupBy` - gr_exprs: &'plan Vec<usize>, + gr_exprs: &'plan Vec<NodeId>, map: GroupbyExpressionsMap, plan: &'plan Plan, /// Id of relational node (`Projection`, `Having`, `OrderBy`) - node_id: Option<usize>, + node_id: Option<NodeId>, } impl<'plan> ExpressionMapper<'plan> { - fn new(gr_expressions: &'plan Vec<usize>, plan: &'plan Plan) -> ExpressionMapper<'plan> { + fn new(gr_expressions: &'plan Vec<NodeId>, plan: &'plan Plan) -> ExpressionMapper<'plan> { let map: GroupbyExpressionsMap = HashMap::new(); ExpressionMapper { gr_exprs: gr_expressions, @@ -270,7 +275,7 @@ impl<'plan> ExpressionMapper<'plan> { /// - invalid query: node expression contains references that are not /// found in `GroupBy` expression. The reason is that user specified expression in /// node that does not match any expression in `GroupBy` - fn find_matches(&mut self, expr_root: usize, node_id: usize) -> Result<(), SbroadError> { + fn find_matches(&mut self, expr_root: NodeId, node_id: NodeId) -> Result<(), SbroadError> { self.node_id = Some(node_id); self.find(expr_root, None)?; self.node_id = None; @@ -279,7 +284,7 @@ impl<'plan> ExpressionMapper<'plan> { /// Helper function for `find_matches` which compares current node to `GroupBy` expressions /// and if no match is found recursively calls itself. - fn find(&mut self, current: usize, parent: Option<usize>) -> Result<(), SbroadError> { + fn find(&mut self, current: NodeId, parent: Option<NodeId>) -> Result<(), SbroadError> { let Some(node_id) = self.node_id else { return Err(SbroadError::Invalid(Entity::ExpressionMapper, None)); }; @@ -346,7 +351,7 @@ impl<'plan> ExpressionMapper<'plan> { impl Plan { #[allow(unreachable_code)] - fn generate_local_alias(id: usize) -> String { + fn generate_local_alias(id: NodeId) -> String { #[cfg(feature = "mock")] { return format!("column_{id}"); @@ -379,8 +384,8 @@ impl Plan { /// - invalid [`Expression::Reference`]s in either of subtrees pub fn are_aggregate_subtrees_equal( &self, - lhs: usize, - rhs: usize, + lhs: NodeId, + rhs: NodeId, ) -> Result<bool, SbroadError> { let l = self.get_node(lhs)?; let r = self.get_node(rhs)?; @@ -616,7 +621,7 @@ impl Plan { /// # Errors /// - invalid children count /// - failed to create output for `GroupBy` - pub fn add_groupby_from_ast(&mut self, children: &[usize]) -> Result<usize, SbroadError> { + pub fn add_groupby_from_ast(&mut self, children: &[NodeId]) -> Result<NodeId, SbroadError> { let Some((first_child, other)) = children.split_first() else { return Err(SbroadError::UnexpectedNumberOfValues( "GroupBy ast has no children".into(), @@ -627,7 +632,7 @@ impl Plan { // 1) aggregates are not allowed // 2) must contain at least one column (group by 1 - is not valid) for (pos, grouping_expr_id) in other.iter().enumerate() { - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), Ok(Node::Expression( @@ -641,7 +646,8 @@ impl Plan { Box::new(filter), ); let mut contains_at_least_one_col = false; - for (_, node_id) in dfs.iter(*grouping_expr_id) { + for level_node in dfs.iter(*grouping_expr_id) { + let node_id = level_node.1; let node = self.get_node(node_id)?; match node { Node::Expression(Expression::Reference { .. }) => { @@ -661,7 +667,7 @@ impl Plan { if !contains_at_least_one_col { return Err(SbroadError::Invalid( Entity::Query, - Some(format_smolstr!("grouping expression must contain at least one column. Invalid expression number: {pos}")) + Some(format_smolstr!("grouping expression must contain at least one column. Invalid expression number: {pos:?}")) )); } } @@ -677,11 +683,11 @@ impl Plan { /// - `grouping_exprs` - contains non-expr id pub fn add_groupby( &mut self, - child_id: usize, - grouping_exprs: &[usize], + child_id: NodeId, + grouping_exprs: &[NodeId], is_final: bool, - expr_parent: Option<usize>, - ) -> Result<usize, SbroadError> { + expr_parent: Option<NodeId>, + ) -> Result<NodeId, SbroadError> { let final_output = self.add_row_for_output(child_id, &[], true)?; let groupby = Relational::GroupBy { children: [child_id].to_vec(), @@ -708,7 +714,7 @@ impl Plan { /// [`finals`] - ids of nodes in final (reduce stage) before adding two stage aggregation. /// It may contain ids of `Projection`, `Having`, `Limit`, `OrderBy`. /// Note: final `GroupBy` is not present because it will be added later in 2-stage pipeline. - fn collect_aggregates(&self, finals: &Vec<usize>) -> Result<Vec<AggrInfo>, SbroadError> { + fn collect_aggregates(&self, finals: &Vec<NodeId>) -> Result<Vec<AggrInfo>, SbroadError> { let mut collector = AggrCollector::with_capacity(self, AGGR_CAPACITY); for node_id in finals { let node = self.get_relation_node(*node_id)?; @@ -725,7 +731,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "unexpected relational node ({node_id}): {node:?}" + "unexpected relational node ({node_id:?}): {node:?}" )), )) } @@ -769,20 +775,23 @@ impl Plan { /// Scan (4) /// ``` /// Then this function will return `([1, 2], 4)` - fn split_reduce_stage(&self, final_proj_id: usize) -> Result<(Vec<usize>, usize), SbroadError> { - let mut finals: Vec<usize> = vec![]; - let get_first_child = |rel_id: usize| -> Result<usize, SbroadError> { + fn split_reduce_stage( + &self, + final_proj_id: NodeId, + ) -> Result<(Vec<NodeId>, NodeId), SbroadError> { + let mut finals: Vec<NodeId> = vec![]; + let get_first_child = |rel_id: NodeId| -> Result<NodeId, SbroadError> { let c = *self .get_relational_children(rel_id)? .get(0) .ok_or_else(|| { SbroadError::UnexpectedNumberOfValues(format_smolstr!( - "expected relation node ({rel_id}) to have children!" + "expected relation node ({rel_id:?}) to have children!" )) })?; Ok(c) }; - let mut next: usize = final_proj_id; + let mut next = final_proj_id; let max_reduce_nodes = 2; for _ in 0..=max_reduce_nodes { match self.get_relation_node(next)? { @@ -832,10 +841,10 @@ impl Plan { #[allow(clippy::too_many_lines)] fn collect_grouping_expressions( &mut self, - upper: usize, - finals: &Vec<usize>, + upper: NodeId, + finals: &Vec<NodeId>, has_aggregates: bool, - ) -> Result<(usize, Vec<usize>, GroupbyExpressionsMap), SbroadError> { + ) -> Result<(NodeId, Vec<NodeId>, GroupbyExpressionsMap), SbroadError> { let mut grouping_expr = vec![]; let mut gr_expr_map: GroupbyExpressionsMap = HashMap::new(); let mut upper = upper; @@ -852,7 +861,7 @@ impl Plan { { if *is_distinct { let proj_cols_len = self.get_row_list(*output)?.len(); - let mut grouping_exprs: Vec<usize> = Vec::with_capacity(proj_cols_len); + let mut grouping_exprs: Vec<NodeId> = Vec::with_capacity(proj_cols_len); for i in 0..proj_cols_len { let aliased_col = self.get_proj_col(*proj_id, i)?; let proj_col_id = if let Expression::Alias { child, .. } = @@ -885,7 +894,7 @@ impl Plan { let grouping_exprs = unique_grouping_exprs .into_iter() .map(|x| x.id) - .collect::<Vec<usize>>(); + .collect::<Vec<NodeId>>(); grouping_expr.extend(grouping_exprs.iter()); self.set_grouping_cols(upper, grouping_exprs)?; @@ -913,7 +922,7 @@ impl Plan { match node { Relational::Projection { output, .. } => { for col in self.get_row_list(*output)? { - let filter = |node_id: usize| -> bool { + let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), Ok(Node::Expression(Expression::Reference { .. })) @@ -926,7 +935,8 @@ impl Plan { ); dfs.populate_nodes(*col); let nodes = dfs.take_nodes(); - for (_, id) in nodes { + for level_node in nodes { + let id = level_node.1; let n = self.get_expression_node(id)?; if let Expression::Reference { .. } = n { let alias = match self.get_alias_from_reference_node(n) { @@ -947,7 +957,8 @@ impl Plan { ); bfs.populate_nodes(*filter); let nodes = bfs.take_nodes(); - for (_, id) in nodes { + for level_node in nodes { + let id = level_node.1; if let Expression::Reference { .. } = self.get_expression_node(id)? { return Err(SbroadError::Invalid( Entity::Query, @@ -972,9 +983,9 @@ impl Plan { /// Reduce: `select l1, sum(distinct l2), sum(l3) from tmp_space group by l1` fn add_distinct_aggregates_to_local_groupby( &mut self, - upper: usize, - additional_grouping_exprs: Vec<usize>, - ) -> Result<usize, SbroadError> { + upper: NodeId, + additional_grouping_exprs: Vec<NodeId>, + ) -> Result<NodeId, SbroadError> { let mut local_proj_child_id = upper; if !additional_grouping_exprs.is_empty() { if let Relational::GroupBy { gr_cols, .. } = @@ -1050,10 +1061,10 @@ impl Plan { /// - map between `GroupBy` expression and corresponding local alias. fn add_local_projection( &mut self, - child_id: usize, + child_id: NodeId, aggr_infos: &mut Vec<AggrInfo>, - grouping_exprs: &Vec<usize>, - ) -> Result<(usize, Vec<usize>, LocalAliasesMap), SbroadError> { + grouping_exprs: &Vec<NodeId>, + ) -> Result<(NodeId, Vec<usize>, LocalAliasesMap), SbroadError> { let (child_id, proj_output_cols, groupby_local_aliases, grouping_positions) = self.create_columns_for_local_proj(aggr_infos, child_id, grouping_exprs)?; let proj_output = self.nodes.add_row(proj_output_cols, None); @@ -1076,9 +1087,9 @@ impl Plan { fn create_local_aggregate( &mut self, kind: AggregateKind, - arguments: &[usize], + arguments: &[NodeId], local_alias: &str, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { let fun = Function { name: kind.to_smolstr(), behavior: Behavior::Stable, @@ -1110,10 +1121,10 @@ impl Plan { fn create_columns_for_local_proj( &mut self, aggr_infos: &mut [AggrInfo], - upper_id: usize, - grouping_exprs: &Vec<usize>, - ) -> Result<(usize, Vec<usize>, LocalAliasesMap, Vec<usize>), SbroadError> { - let mut output_cols: Vec<usize> = vec![]; + upper_id: NodeId, + grouping_exprs: &Vec<NodeId>, + ) -> Result<(NodeId, Vec<NodeId>, LocalAliasesMap, Vec<usize>), SbroadError> { + let mut output_cols: Vec<NodeId> = vec![]; let (local_aliases, child_id, grouping_positions) = self.add_grouping_exprs(aggr_infos, upper_id, grouping_exprs, &mut output_cols)?; self.add_local_aggregates(aggr_infos, &mut output_cols)?; @@ -1145,10 +1156,10 @@ impl Plan { fn add_grouping_exprs( &mut self, aggr_infos: &mut [AggrInfo], - upper_id: usize, - grouping_exprs: &Vec<usize>, - output_cols: &mut Vec<usize>, - ) -> Result<(LocalAliasesMap, usize, Vec<usize>), SbroadError> { + upper_id: NodeId, + grouping_exprs: &Vec<NodeId>, + output_cols: &mut Vec<NodeId>, + ) -> Result<(LocalAliasesMap, NodeId, Vec<usize>), SbroadError> { let mut unique_grouping_exprs_for_local_stage: HashMap< GroupingExpression, Rc<String>, @@ -1162,13 +1173,13 @@ impl Plan { } // add grouping expressions found from distinct aggregates to local groupby - let mut grouping_exprs_from_aggregates: Vec<usize> = vec![]; + let mut grouping_exprs_from_aggregates: Vec<NodeId> = vec![]; for info in aggr_infos.iter_mut().filter(|x| x.is_distinct) { let argument = { let args = self .nodes .expr_iter(info.aggr.fun_id, false) - .collect::<Vec<usize>>(); + .collect::<Vec<NodeId>>(); if args.len() > 1 && !matches!(info.aggr.kind, AggregateKind::GRCONCAT) { return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!( "aggregate ({info:?}) have more than one argument" @@ -1194,11 +1205,14 @@ impl Plan { } // Because of borrow checker we need to remove references to Plan from map - let mut unique_grouping_exprs_for_local_stage: HashMap<usize, Rc<String>, RepeatableState> = - unique_grouping_exprs_for_local_stage - .into_iter() - .map(|(e, s)| (e.id, s)) - .collect(); + let mut unique_grouping_exprs_for_local_stage: HashMap< + NodeId, + Rc<String>, + RepeatableState, + > = unique_grouping_exprs_for_local_stage + .into_iter() + .map(|(e, s)| (e.id, s)) + .collect(); let mut alias_to_pos: HashMap<Rc<String>, usize> = HashMap::new(); // add grouping expressions to local projection @@ -1234,7 +1248,7 @@ impl Plan { } else { return Err(SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("invalid map with unique grouping expressions. Could not find grouping expression with id: {expr_id}")))); + Some(format_smolstr!("invalid map with unique grouping expressions. Could not find grouping expression with id: {expr_id:?}")))); } } let child_id = self @@ -1250,7 +1264,7 @@ impl Plan { fn add_local_aggregates( &mut self, aggr_infos: &mut [AggrInfo], - output_cols: &mut Vec<usize>, + output_cols: &mut Vec<NodeId>, ) -> Result<(), SbroadError> { // Aggregate expressions can appear in `Projection`, `Having`, `OrderBy`, if the // same expression appears in different places, we must not calculate it separately: @@ -1275,7 +1289,7 @@ impl Plan { } else { return Err(SbroadError::Invalid( Entity::Aggregate, - Some(format_smolstr!("invalid fun_id: {}", info.aggr.fun_id)), + Some(format_smolstr!("invalid fun_id: {:?}", info.aggr.fun_id)), )); } }; @@ -1308,7 +1322,7 @@ impl Plan { })?; let alias = Rc::new(generate_local_alias_for_aggr( &kind, - &info.aggr.fun_id.to_string(), + &format_smolstr!("{}", info.aggr.fun_id), )); info.aggr.lagg_alias.insert(kind, alias.clone()); signature.local_alias = Some(alias); @@ -1321,7 +1335,7 @@ impl Plan { let local_aggregates: Result<Vec<LocalAggrInfo>, SbroadError> = unique_local_aggregates .into_iter() .map( - |x| -> Result<(AggregateKind, Vec<usize>, Rc<String>), SbroadError> { + |x| -> Result<(AggregateKind, Vec<NodeId>, Rc<String>), SbroadError> { match x.get_alias() { Ok(s) => Ok((x.kind, x.arguments.clone(), s)), Err(e) => Err(e), @@ -1351,15 +1365,15 @@ impl Plan { /// - if `GroupBy` node was not created, return `child_id` fn add_final_groupby( &mut self, - child_id: usize, - grouping_exprs: &Vec<usize>, + child_id: NodeId, + grouping_exprs: &Vec<NodeId>, local_aliases_map: &LocalAliasesMap, - ) -> Result<usize, SbroadError> { + ) -> Result<NodeId, SbroadError> { if grouping_exprs.is_empty() { // no GroupBy in the original query, nothing to do return Ok(child_id); } - let mut gr_cols: Vec<usize> = Vec::with_capacity(grouping_exprs.len()); + let mut gr_cols: Vec<NodeId> = Vec::with_capacity(grouping_exprs.len()); let child_map = ColumnPositionMap::new(self, child_id)?; let mut nodes = Vec::with_capacity(grouping_exprs.len()); for expr_id in grouping_exprs { @@ -1367,7 +1381,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "could not find local alias for GroupBy expr ({expr_id})" + "could not find local alias for GroupBy expr ({expr_id:?})" )), )); }; @@ -1377,7 +1391,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Type, Some(format_smolstr!( - "add_final_groupby: GroupBy expr ({expr_id}) is not scalar ({col_type})!" + "add_final_groupby: GroupBy expr ({expr_id:?}) is not scalar ({col_type})!" )), )); } @@ -1394,7 +1408,7 @@ impl Plan { gr_cols.push(new_col_id); } let output = self.add_row_for_output(child_id, &[], true)?; - let final_id = self.nodes.next_id(); + let final_id = self.nodes.next_id(ArenaType::Default); for col in &gr_cols { self.replace_parent_in_subtree(*col, None, Some(final_id))?; } @@ -1424,10 +1438,10 @@ impl Plan { local_aliases_map: &LocalAliasesMap, map: GroupbyExpressionsMap, ) -> Result<(), SbroadError> { - type RelationalID = usize; - type GroupByExpressionID = usize; - type ExpressionID = usize; - type ExpressionParent = Option<usize>; + type RelationalID = NodeId; + type GroupByExpressionID = NodeId; + type ExpressionID = NodeId; + type ExpressionParent = Option<NodeId>; type ParentExpressionMap = HashMap<RelationalID, Vec<(GroupByExpressionID, ExpressionID, ExpressionParent)>>; let map: ParentExpressionMap = { @@ -1450,7 +1464,7 @@ impl Plan { .get(0) .ok_or_else(|| { SbroadError::UnexpectedNumberOfValues(format_smolstr!( - "expected relation node ({rel_id}) to have children!" + "expected relation node ({rel_id:?}) to have children!" )) })?; let alias_to_pos_map = ColumnPositionMap::new(self, child_id)?; @@ -1460,7 +1474,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "failed to find local alias for groupby expression {gr_expr_id}" + "failed to find local alias for groupby expression {gr_expr_id:?}" )), )); }; @@ -1492,7 +1506,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "{} {gr_expr_id} {} {expr_id} {}", + "{} {gr_expr_id:?} {} {expr_id:?} {}", "invalid mapping between group by expression", "and projection one: expression", "has no parent", @@ -1505,7 +1519,9 @@ impl Plan { _ => { return Err(SbroadError::Invalid( Entity::Plan, - Some(format_smolstr!("unexpected node in Reduce stage: {rel_id}")), + Some(format_smolstr!( + "unexpected node in Reduce stage: {rel_id:?}" + )), )) } } @@ -1540,8 +1556,8 @@ impl Plan { /// used in `finals`. fn patch_finals( &mut self, - finals: &[usize], - finals_child_id: usize, + finals: &[NodeId], + finals_child_id: NodeId, local_aliases_map: &LocalAliasesMap, aggr_infos: &Vec<AggrInfo>, gr_expr_map: GroupbyExpressionsMap, @@ -1564,7 +1580,7 @@ impl Plan { let child_id = *children.first().ok_or_else(|| { SbroadError::Invalid( Entity::Node, - Some(format_smolstr!("Having ({node_id}) has no children!")), + Some(format_smolstr!("Having ({node_id:?}) has no children!")), ) })?; let output = self.add_row_for_output(child_id, &[], true)?; @@ -1581,7 +1597,7 @@ impl Plan { } self.patch_grouping_expressions(local_aliases_map, gr_expr_map)?; - let mut parent_to_infos: HashMap<usize, Vec<AggrInfo>> = + let mut parent_to_infos: HashMap<NodeId, Vec<AggrInfo>> = HashMap::with_capacity(finals.len()); for info in aggr_infos { if let Some(v) = parent_to_infos.get_mut(&info.parent_rel) { @@ -1597,7 +1613,7 @@ impl Plan { SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "patch aggregates: rel node ({parent}) has no children!" + "patch aggregates: rel node ({parent:?}) has no children!" )), ) })? @@ -1639,8 +1655,8 @@ impl Plan { fn add_motion_to_2stage( &mut self, grouping_positions: &[usize], - motion_parent: usize, - finals: &[usize], + motion_parent: NodeId, + finals: &[NodeId], ) -> Result<(), SbroadError> { let proj_id = *finals.first().ok_or_else(|| { SbroadError::Invalid(Entity::Plan, Some("no nodes in Reduce stage!".into())) @@ -1671,7 +1687,7 @@ impl Plan { SbroadError::Invalid( Entity::Node, Some(format_smolstr!( - "final GroupBy ({motion_parent}) has no children!" + "final GroupBy ({motion_parent:?}) has no children!" )), ) })? @@ -1679,7 +1695,7 @@ impl Plan { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "expected to have GroupBy under reduce nodes on id: {motion_parent}" + "expected to have GroupBy under reduce nodes on id: {motion_parent:?}" )), )); }; @@ -1713,7 +1729,10 @@ impl Plan { /// - failed to create `SQ` node /// - failed to change final `GroupBy` child to `SQ` /// - failed to update expressions in final `Projection` - pub fn add_two_stage_aggregation(&mut self, final_proj_id: usize) -> Result<bool, SbroadError> { + pub fn add_two_stage_aggregation( + &mut self, + final_proj_id: NodeId, + ) -> Result<bool, SbroadError> { let (finals, upper) = self.split_reduce_stage(final_proj_id)?; let mut aggr_infos = self.collect_aggregates(&finals)?; let has_aggregates = !aggr_infos.is_empty(); @@ -1760,7 +1779,7 @@ impl Plan { )?; self.add_motion_to_2stage(&grouping_positions, finals_child_id, &finals)?; - let mut having_id: Option<usize> = None; + let mut having_id: Option<NodeId> = None; // skip Projection for node_id in finals.iter().skip(1).rev() { self.set_distribution(self.get_relational_output(*node_id)?)?; diff --git a/sbroad-core/src/ir/transformation/redistribution/left_join.rs b/sbroad-core/src/ir/transformation/redistribution/left_join.rs index ea0d83d0f..546f72040 100644 --- a/sbroad-core/src/ir/transformation/redistribution/left_join.rs +++ b/sbroad-core/src/ir/transformation/redistribution/left_join.rs @@ -7,6 +7,7 @@ use crate::{ errors::{Entity, SbroadError}, ir::{ distribution::Distribution, + expression::NodeId, operator::{JoinKind, Relational}, Plan, }, @@ -17,7 +18,7 @@ use super::{MotionOpcode, MotionPolicy, Program, Strategy}; impl Plan { pub(super) fn calculate_strategy_for_left_join_with_global_tbl( &mut self, - join_id: usize, + join_id: NodeId, join_kind: &JoinKind, ) -> Result<Option<Strategy>, SbroadError> { let is_left_join = matches!(join_kind, JoinKind::LeftOuter); @@ -41,7 +42,7 @@ impl Plan { let Some(parent_id) = self.find_parent_rel(join_id)? else { return Err(SbroadError::Invalid( Entity::Plan, - Some(format_smolstr!("join ({join_id}) has no parent!")), + Some(format_smolstr!("join ({join_id:?}) has no parent!")), )); }; let projection_id = create_projection(self, join_id)?; @@ -89,7 +90,7 @@ impl Plan { } } -fn create_projection(plan: &mut Plan, join_id: usize) -> Result<usize, SbroadError> { +fn create_projection(plan: &mut Plan, join_id: NodeId) -> Result<NodeId, SbroadError> { let proj_id = plan.add_proj(join_id, &[], false, false)?; let output_id = plan.get_relational_output(proj_id)?; plan.replace_parent_in_subtree(output_id, Some(join_id), Some(proj_id))?; diff --git a/sbroad-core/src/ir/transformation/redistribution/tests.rs b/sbroad-core/src/ir/transformation/redistribution/tests.rs index 2771326d0..9a5ef710d 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests.rs @@ -1,288 +1,9 @@ use super::*; use crate::ir::operator::Relational; -use crate::ir::relation::{SpaceEngine, Table}; -use crate::ir::tests::column_integer_user_non_null; use crate::ir::transformation::helpers::sql_to_ir; use crate::ir::Plan; use crate::ir::Slices; use pretty_assertions::assert_eq; -use smol_str::SmolStr; -use std::fs; -use std::path::Path; - -#[test] -fn full_motion_less_for_sub_query() { - // t1(a int) key [a] - // t2(a int, b int) key [a] - // select * from t1 where a < (select b from t2) - let mut plan = Plan::default(); - let mut children: Vec<usize> = Vec::new(); - - let t1 = Table::new_sharded( - "t1", - vec![column_integer_user_non_null(SmolStr::from("a"))], - &["a"], - &["a"], - SpaceEngine::Vinyl, - ) - .unwrap(); - plan.add_rel(t1); - let scan_t1_id = plan.add_scan("t1", None).unwrap(); - children.push(scan_t1_id); - - let t2 = Table::new_sharded( - "t2", - vec![ - column_integer_user_non_null(SmolStr::from("a")), - column_integer_user_non_null(SmolStr::from("b")), - ], - &["a"], - &["a"], - SpaceEngine::Vinyl, - ) - .unwrap(); - plan.add_rel(t2); - let scan_t2_id = plan.add_scan("t2", None).unwrap(); - let proj_id = plan.add_proj(scan_t2_id, &["b"], false, false).unwrap(); - let sq_id = plan.add_sub_query(proj_id, None).unwrap(); - children.push(sq_id); - - let b_id = plan - .add_row_from_subquery(&children[..], children.len() - 1, None) - .unwrap(); - let a_id = plan.add_row_from_child(scan_t1_id, &["a"]).unwrap(); - let less_id = plan.add_cond(a_id, Bool::Lt, b_id).unwrap(); - - let select_id = plan.add_select(&children[..], less_id).unwrap(); - plan.set_top(select_id).unwrap(); - - plan.add_motions().unwrap(); - - // Check the modified plan - plan.derive_equalities().unwrap(); - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("transformation") - .join("redistribution") - .join("full_motion_less_for_sub_query.yaml"); - let s = fs::read_to_string(path).unwrap(); - let expected_plan = Plan::from_yaml(&s).unwrap(); - // This field is not serialized, do not check it - plan.context = None; - assert_eq!(plan, expected_plan); -} - -#[test] -#[allow(clippy::similar_names)] -fn full_motion_non_segment_outer_for_sub_query() { - // t1(a int, b int) key [a] - // t2(a int) key [a] - // select * from t1 where b = (select a from t2) - let mut plan = Plan::default(); - let mut children: Vec<usize> = Vec::new(); - - let t1 = Table::new_sharded( - "t1", - vec![ - column_integer_user_non_null(SmolStr::from("a")), - column_integer_user_non_null(SmolStr::from("b")), - ], - &["a"], - &["a"], - SpaceEngine::Vinyl, - ) - .unwrap(); - plan.add_rel(t1); - let scan_t1_id = plan.add_scan("t1", None).unwrap(); - children.push(scan_t1_id); - - let t2 = Table::new_sharded( - "t2", - vec![column_integer_user_non_null(SmolStr::from("a"))], - &["a"], - &["a"], - SpaceEngine::Vinyl, - ) - .unwrap(); - plan.add_rel(t2); - let scan_t2_id = plan.add_scan("t2", None).unwrap(); - let proj_id = plan.add_proj(scan_t2_id, &["a"], false, false).unwrap(); - let sq_id = plan.add_sub_query(proj_id, None).unwrap(); - children.push(sq_id); - - let a_id = plan - .add_row_from_subquery(&children[..], children.len() - 1, None) - .unwrap(); - let b_id = plan.add_row_from_child(scan_t1_id, &["b"]).unwrap(); - let eq_id = plan.add_cond(b_id, Bool::Eq, a_id).unwrap(); - - let select_id = plan.add_select(&children[..], eq_id).unwrap(); - plan.set_top(select_id).unwrap(); - - plan.add_motions().unwrap(); - - // Check the modified plan - plan.derive_equalities().unwrap(); - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("transformation") - .join("redistribution") - .join("full_motion_non_segment_outer_for_sub_query.yaml"); - let s = fs::read_to_string(path).unwrap(); - let expected_plan = Plan::from_yaml(&s).unwrap(); - // This field is not serialized, do not check it - plan.context = None; - assert_eq!(plan, expected_plan); -} - -#[test] -#[allow(clippy::similar_names)] -fn local_sub_query() { - // t1(a int) key [a] - // t2(a int, b int) key [a] - // select * from t1 where a = (select a from t2) - let mut plan = Plan::default(); - let mut children: Vec<usize> = Vec::new(); - - let t1 = Table::new_sharded( - "t1", - vec![column_integer_user_non_null(SmolStr::from("a"))], - &["a"], - &["a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t1); - let scan_t1_id = plan.add_scan("t1", None).unwrap(); - children.push(scan_t1_id); - - let t2 = Table::new_sharded( - "t2", - vec![column_integer_user_non_null(SmolStr::from("a"))], - &["a"], - &["a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t2); - let scan_t2_id = plan.add_scan("t2", None).unwrap(); - let proj_id = plan.add_proj(scan_t2_id, &["a"], false, false).unwrap(); - let sq_id = plan.add_sub_query(proj_id, None).unwrap(); - children.push(sq_id); - - let inner_a_id = plan - .add_row_from_subquery(&children[..], children.len() - 1, None) - .unwrap(); - let outer_a_id = plan.add_row_from_child(scan_t1_id, &["a"]).unwrap(); - let eq_id = plan.add_cond(outer_a_id, Bool::Eq, inner_a_id).unwrap(); - - let select_id = plan.add_select(&children[..], eq_id).unwrap(); - plan.set_top(select_id).unwrap(); - - plan.add_motions().unwrap(); - - // Check the modified plan - plan.derive_equalities().unwrap(); - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("transformation") - .join("redistribution") - .join("local_sub_query.yaml"); - let s = fs::read_to_string(path).unwrap(); - let expected_plan = Plan::from_yaml(&s).unwrap(); - // This field is not serialized, do not check it - plan.context = None; - assert_eq!(plan, expected_plan); -} - -#[test] -fn multiple_sub_queries() { - // t1(a int) key [a] - // t2(a int, b int) key [a] - // select * from t1 where a < (select a from t2) or a = (select b from t2) - let mut plan = Plan::default(); - let mut children: Vec<usize> = Vec::new(); - - let t1 = Table::new_sharded( - "t1", - vec![column_integer_user_non_null(SmolStr::from("a"))], - &["a"], - &["a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t1); - let scan_t1_id = plan.add_scan("t1", None).unwrap(); - children.push(scan_t1_id); - - let t2 = Table::new_sharded( - "t2", - vec![ - column_integer_user_non_null(SmolStr::from("a")), - column_integer_user_non_null(SmolStr::from("b")), - ], - &["a"], - &["a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t2); - let sq1_scan_t2_id = plan.add_scan("t2", None).unwrap(); - let sq1_proj_id = plan.add_proj(sq1_scan_t2_id, &["a"], false, false).unwrap(); - let sq1_id = plan.add_sub_query(sq1_proj_id, None).unwrap(); - children.push(sq1_id); - let sq1_pos = children.len() - 1; - - let sq2_scan_t2_id = plan.add_scan("t2", None).unwrap(); - let sq2_proj_id = plan.add_proj(sq2_scan_t2_id, &["b"], false, false).unwrap(); - let sq2_id = plan.add_sub_query(sq2_proj_id, None).unwrap(); - children.push(sq2_id); - let sq2_pos = children.len() - 1; - - let sq1_inner_a_id = plan - .add_row_from_subquery(&children[..], sq1_pos, None) - .unwrap(); - let sq1_outer_a_id = plan.add_row_from_child(scan_t1_id, &["a"]).unwrap(); - let less_id = plan - .add_cond(sq1_outer_a_id, Bool::Lt, sq1_inner_a_id) - .unwrap(); - - let sq2_inner_a_id = plan - .add_row_from_subquery(&children[..], sq2_pos, None) - .unwrap(); - let sq2_outer_a_id = plan.add_row_from_child(scan_t1_id, &["a"]).unwrap(); - let eq_id = plan - .add_cond(sq2_outer_a_id, Bool::Eq, sq2_inner_a_id) - .unwrap(); - - let or_id = plan.add_cond(less_id, Bool::Or, eq_id).unwrap(); - - let select_id = plan.add_select(&children[..], or_id).unwrap(); - plan.set_top(select_id).unwrap(); - - plan.add_motions().unwrap(); - - // Check the modified plan - plan.derive_equalities().unwrap(); - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("transformation") - .join("redistribution") - .join("multiple_sub_queries.yaml"); - let s = fs::read_to_string(path).unwrap(); - let expected_plan = Plan::from_yaml(&s).unwrap(); - // This field is not serialized, do not check it - plan.context = None; - assert_eq!(plan, expected_plan); -} #[test] fn union_all_in_sq() { @@ -475,7 +196,7 @@ fn join_inner_or_local_full_policies() { /// # Panics /// Motion node does not found #[must_use] -pub fn get_motion_id(plan: &Plan, slice_id: usize, motion_idx: usize) -> Option<&usize> { +pub fn get_motion_id(plan: &Plan, slice_id: usize, motion_idx: usize) -> Option<&NodeId> { plan.slices.slice(slice_id).unwrap().position(motion_idx) } diff --git a/sbroad-core/src/ir/transformation/redistribution/tests/not_in.rs b/sbroad-core/src/ir/transformation/redistribution/tests/not_in.rs index cb396f44e..8593501b9 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests/not_in.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests/not_in.rs @@ -1,8 +1,8 @@ use crate::ir::operator::Relational; use crate::ir::transformation::helpers::sql_to_ir; -use crate::ir::transformation::redistribution::tests::get_motion_id; +use crate::ir::transformation::redistribution::tests::{get_motion_id, NodeId}; use crate::ir::transformation::redistribution::MotionPolicy; -use crate::ir::{Slice, Slices}; +use crate::ir::{ArenaType, Slice, Slices}; use pretty_assertions::assert_eq; #[test] @@ -28,7 +28,15 @@ fn not_in2() { let mut plan = sql_to_ir(query, vec![]); plan.add_motions().unwrap(); - assert_eq!(Slices::from(vec![Slice { slice: vec![65] }]), plan.slices); + assert_eq!( + Slices::from(vec![Slice { + slice: vec![NodeId { + offset: 65, + arena_type: ArenaType::Default, + }] + }]), + plan.slices + ); } #[test] diff --git a/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs b/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs index fe89c1f62..a42085758 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs @@ -1,102 +1,13 @@ use crate::collection; -use crate::errors::{Entity, SbroadError}; use crate::ir::distribution::{Distribution, Key}; use crate::ir::helpers::RepeatableState; -use crate::ir::operator::{Bool, Relational}; -use crate::ir::relation::{Column, SpaceEngine, Table}; -use crate::ir::tests::column_integer_user_non_null; +use crate::ir::operator::Relational; +use crate::ir::relation::Column; use crate::ir::transformation::helpers::sql_to_ir; use crate::ir::transformation::redistribution::{MotionKey, MotionPolicy, Target}; -use crate::ir::{Node, Plan}; -use ahash::RandomState; +use crate::ir::Node; use pretty_assertions::assert_eq; -use smol_str::SmolStr; use std::collections::HashSet; -use std::fs; -use std::path::Path; - -#[test] -#[allow(clippy::similar_names)] -fn sub_query1() { - // t1(a int) key [a] - // t2(a int, b int) key [a] - // select * from t1 where a = (select b from t2) - let mut plan = Plan::default(); - let mut children: Vec<usize> = Vec::new(); - - let t1 = Table::new_sharded( - "t1", - vec![column_integer_user_non_null(SmolStr::from("a"))], - &["a"], - &["a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t1); - let scan_t1_id = plan.add_scan("t1", None).unwrap(); - children.push(scan_t1_id); - - let t2 = Table::new_sharded( - "t2", - vec![ - column_integer_user_non_null(SmolStr::from("a")), - column_integer_user_non_null(SmolStr::from("b")), - ], - &["a"], - &["a"], - SpaceEngine::Memtx, - ) - .unwrap(); - plan.add_rel(t2); - let scan_t2_id = plan.add_scan("t2", None).unwrap(); - let proj_id = plan.add_proj(scan_t2_id, &["b"], false, false).unwrap(); - let sq_id = plan.add_sub_query(proj_id, None).unwrap(); - children.push(sq_id); - - let b_id = plan - .add_row_from_subquery(&children[..], children.len() - 1, None) - .unwrap(); - let a_id = plan.add_row_from_child(scan_t1_id, &["a"]).unwrap(); - let eq_id = plan.add_cond(a_id, Bool::Eq, b_id).unwrap(); - - let select_id = plan.add_select(&children[..], eq_id).unwrap(); - plan.set_top(select_id).unwrap(); - - let mut expected_rel_set: HashSet<usize, RandomState> = - HashSet::with_hasher(RandomState::new()); - expected_rel_set.insert(sq_id); - assert_eq!( - expected_rel_set, - plan.get_relational_nodes_from_row(b_id).unwrap() - ); - assert_eq!(Some(sq_id), plan.get_sub_query_from_row_node(b_id).unwrap()); - - assert_eq!( - SbroadError::Invalid( - Entity::Distribution, - Some("distribution is uninitialized".into()), - ), - plan.resolve_sub_query_conflicts(select_id, eq_id) - .unwrap_err() - ); - - plan.add_motions().unwrap(); - - // Check the modified plan - plan.derive_equalities().unwrap(); - let path = Path::new("") - .join("tests") - .join("artifactory") - .join("ir") - .join("transformation") - .join("redistribution") - .join("segment_motion_for_sub_query.yaml"); - let s = fs::read_to_string(path).unwrap(); - let expected_plan = Plan::from_yaml(&s).unwrap(); - // This field is not serialized, do not check it - plan.context = None; - assert_eq!(plan, expected_plan); -} #[test] fn inner_join1() { diff --git a/sbroad-core/src/ir/transformation/split_columns.rs b/sbroad-core/src/ir/transformation/split_columns.rs index 4b707001c..4b9cfe655 100644 --- a/sbroad-core/src/ir/transformation/split_columns.rs +++ b/sbroad-core/src/ir/transformation/split_columns.rs @@ -13,7 +13,7 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; use crate::ir::Plan; @@ -23,7 +23,7 @@ use smol_str::format_smolstr; fn call_expr_tree_split_columns( plan: &mut Plan, - top_id: usize, + top_id: NodeId, ) -> Result<OldNewTopIdPair, SbroadError> { plan.expr_tree_replace_bool( top_id, @@ -39,7 +39,7 @@ fn call_expr_tree_split_columns( ) } -fn call_split_bool(plan: &mut Plan, top_id: usize) -> Result<OldNewTopIdPair, SbroadError> { +fn call_split_bool(plan: &mut Plan, top_id: NodeId) -> Result<OldNewTopIdPair, SbroadError> { plan.split_bool(top_id) } @@ -51,7 +51,7 @@ impl Plan { /// - If the operator is not a boolean operator. /// - If left and right tuples have different number of columns. /// - If the plan is invalid for some unknown reason. - fn split_bool(&mut self, top_id: usize) -> Result<OldNewTopIdPair, SbroadError> { + fn split_bool(&mut self, top_id: NodeId) -> Result<OldNewTopIdPair, SbroadError> { let top_expr = self.get_expression_node(top_id)?; let (left_id, right_id, op) = match top_expr { Expression::Bool { diff --git a/sbroad-core/src/ir/transformation/split_columns/tests.rs b/sbroad-core/src/ir/transformation/split_columns/tests.rs index 427f480d3..0c038731c 100644 --- a/sbroad-core/src/ir/transformation/split_columns/tests.rs +++ b/sbroad-core/src/ir/transformation/split_columns/tests.rs @@ -53,8 +53,8 @@ fn split_columns3() { "{} {} {} {}", r#"unexpected number of values:"#, r#"left and right rows have different number of columns:"#, - r#"Row { list: [12, 13, 14], distribution: None },"#, - r#"Row { list: [15, 16], distribution: None }"#, + r#"Row { list: [NodeId { offset: 12, arena_type: Default }, NodeId { offset: 13, arena_type: Default }, NodeId { offset: 14, arena_type: Default }], distribution: None },"#, + r#"Row { list: [NodeId { offset: 15, arena_type: Default }, NodeId { offset: 16, arena_type: Default }], distribution: None }"#, ), format!("{plan_err}") ); diff --git a/sbroad-core/src/ir/tree.rs b/sbroad-core/src/ir/tree.rs index f301a2a99..761135770 100644 --- a/sbroad-core/src/ir/tree.rs +++ b/sbroad-core/src/ir/tree.rs @@ -1,15 +1,17 @@ //! IR tree traversal module. -use super::{Nodes, Plan}; -use crate::ir::expression::Expression; +use super::{ + expression::{Expression, NodeId}, + Nodes, Plan, +}; use std::cell::RefCell; trait TreeIterator<'nodes> { - fn get_current(&self) -> usize; + fn get_current(&self) -> NodeId; fn get_child(&self) -> &RefCell<usize>; fn get_nodes(&self) -> &'nodes Nodes; - fn handle_trim(&mut self, expr: &'nodes Expression) -> Option<&'nodes usize> { + fn handle_trim(&mut self, expr: &'nodes Expression) -> Option<&'nodes NodeId> { let Expression::Trim { pattern, target, .. } = expr @@ -36,7 +38,7 @@ trait TreeIterator<'nodes> { } } - fn handle_left_right_children(&mut self, expr: &'nodes Expression) -> Option<&'nodes usize> { + fn handle_left_right_children(&mut self, expr: &'nodes Expression) -> Option<&'nodes NodeId> { let (Expression::Bool { left, right, .. } | Expression::Arithmetic { left, right, .. } | Expression::Concat { left, right, .. }) = expr @@ -54,7 +56,7 @@ trait TreeIterator<'nodes> { None } - fn handle_single_child(&mut self, expr: &'nodes Expression) -> Option<&'nodes usize> { + fn handle_single_child(&mut self, expr: &'nodes Expression) -> Option<&'nodes NodeId> { let (Expression::Alias { child, .. } | Expression::ExprInParentheses { child } | Expression::Cast { child, .. } @@ -70,7 +72,7 @@ trait TreeIterator<'nodes> { None } - fn handle_case_iter(&mut self, expr: &'nodes Expression) -> Option<&'nodes usize> { + fn handle_case_iter(&mut self, expr: &'nodes Expression) -> Option<&'nodes NodeId> { let Expression::Case { search_expr, when_blocks, diff --git a/sbroad-core/src/ir/tree/and.rs b/sbroad-core/src/ir/tree/and.rs index 3b4a080c1..c3cfc3167 100644 --- a/sbroad-core/src/ir/tree/and.rs +++ b/sbroad-core/src/ir/tree/and.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use super::TreeIterator; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::Bool; use crate::ir::{Node, Nodes}; @@ -13,13 +13,13 @@ trait AndTreeIterator<'nodes>: TreeIterator<'nodes> {} #[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct AndIterator<'n> { - current: usize, + current: NodeId, child: RefCell<usize>, nodes: &'n Nodes, } impl<'nodes> TreeIterator<'nodes> for AndIterator<'nodes> { - fn get_current(&self) -> usize { + fn get_current(&self) -> NodeId { self.current } @@ -36,7 +36,7 @@ impl<'nodes> AndTreeIterator<'nodes> for AndIterator<'nodes> {} impl<'n> Nodes { #[must_use] - pub fn and_iter(&'n self, current: usize) -> AndIterator<'n> { + pub fn and_iter(&'n self, current: NodeId) -> AndIterator<'n> { AndIterator { current, child: RefCell::new(0), @@ -46,15 +46,15 @@ impl<'n> Nodes { } impl<'n> Iterator for AndIterator<'n> { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { and_next(self).copied() } } -fn and_next<'nodes>(iter: &mut impl AndTreeIterator<'nodes>) -> Option<&'nodes usize> { - let node = iter.get_nodes().arena.get(iter.get_current()); +fn and_next<'nodes>(iter: &mut impl AndTreeIterator<'nodes>) -> Option<&'nodes NodeId> { + let node = iter.get_nodes().get(iter.get_current()); if let Some(Node::Expression(Expression::Bool { left, op, right, .. })) = node diff --git a/sbroad-core/src/ir/tree/expression.rs b/sbroad-core/src/ir/tree/expression.rs index 53737b4f5..faaac377a 100644 --- a/sbroad-core/src/ir/tree/expression.rs +++ b/sbroad-core/src/ir/tree/expression.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use super::TreeIterator; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::{Node, Nodes}; trait ExpressionTreeIterator<'nodes>: TreeIterator<'nodes> { @@ -15,7 +15,7 @@ trait ExpressionTreeIterator<'nodes>: TreeIterator<'nodes> { #[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct ExpressionIterator<'n> { - current: usize, + current: NodeId, child: RefCell<usize>, nodes: &'n Nodes, make_row_leaf: bool, @@ -28,7 +28,7 @@ pub struct AggregateIterator<'p> { impl<'n> Nodes { #[must_use] - pub fn expr_iter(&'n self, current: usize, make_row_leaf: bool) -> ExpressionIterator<'n> { + pub fn expr_iter(&'n self, current: NodeId, make_row_leaf: bool) -> ExpressionIterator<'n> { ExpressionIterator { current, child: RefCell::new(0), @@ -38,9 +38,9 @@ impl<'n> Nodes { } #[must_use] - pub fn aggregate_iter(&'n self, current: usize, make_row_leaf: bool) -> AggregateIterator<'n> { + pub fn aggregate_iter(&'n self, current: NodeId, make_row_leaf: bool) -> AggregateIterator<'n> { let must_stop = if let Some(Node::Expression(Expression::StableFunction { name, .. })) = - self.arena.get(current) + self.get(current) { Expression::is_aggregate_name(name) } else { @@ -59,7 +59,7 @@ impl<'n> Nodes { } impl<'nodes> TreeIterator<'nodes> for ExpressionIterator<'nodes> { - fn get_current(&self) -> usize { + fn get_current(&self) -> NodeId { self.current } @@ -79,7 +79,7 @@ impl<'nodes> ExpressionTreeIterator<'nodes> for ExpressionIterator<'nodes> { } impl<'n> Iterator for ExpressionIterator<'n> { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { expression_next(self).copied() @@ -87,7 +87,7 @@ impl<'n> Iterator for ExpressionIterator<'n> { } impl<'n> Iterator for AggregateIterator<'n> { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { if self.must_stop { @@ -100,8 +100,8 @@ impl<'n> Iterator for AggregateIterator<'n> { #[allow(clippy::too_many_lines)] fn expression_next<'nodes>( iter: &mut impl ExpressionTreeIterator<'nodes>, -) -> Option<&'nodes usize> { - let node = iter.get_nodes().arena.get(iter.get_current()); +) -> Option<&'nodes NodeId> { + let node = iter.get_nodes().get(iter.get_current()); match node { Some(node) => { match node { @@ -123,7 +123,7 @@ fn expression_next<'nodes>( is_leaf = true; for col in list { if !matches!( - iter.get_nodes().arena.get(*col), + iter.get_nodes().get(*col), Some(Node::Expression( Expression::Reference { .. } | Expression::Constant { .. } diff --git a/sbroad-core/src/ir/tree/relation.rs b/sbroad-core/src/ir/tree/relation.rs index 40733e65e..cc14584d1 100644 --- a/sbroad-core/src/ir/tree/relation.rs +++ b/sbroad-core/src/ir/tree/relation.rs @@ -1,8 +1,9 @@ use std::cell::RefCell; use super::TreeIterator; +use crate::ir::expression::NodeId; use crate::ir::operator::Relational; -use crate::ir::{Node, Nodes}; +use crate::ir::{ArenaType, Node, Nodes}; trait RelationalTreeIterator<'nodes>: TreeIterator<'nodes> {} @@ -11,14 +12,14 @@ trait RelationalTreeIterator<'nodes>: TreeIterator<'nodes> {} /// The iterator returns the next relational node in the plan tree. #[derive(Debug)] pub struct RelationalIterator<'n> { - current: usize, + current: NodeId, child: RefCell<usize>, nodes: &'n Nodes, } impl<'n> Nodes { #[must_use] - pub fn rel_iter(&'n self, current: usize) -> RelationalIterator<'n> { + pub fn rel_iter(&'n self, current: NodeId) -> RelationalIterator<'n> { RelationalIterator { current, child: RefCell::new(0), @@ -29,15 +30,15 @@ impl<'n> Nodes { #[must_use] pub fn empty_rel_iter(&'n self) -> RelationalIterator<'n> { RelationalIterator { - current: self.next_id(), - child: RefCell::new(1000), + current: self.next_id(ArenaType::Default), + child: RefCell::new(0), nodes: self, } } } impl<'nodes> TreeIterator<'nodes> for RelationalIterator<'nodes> { - fn get_current(&self) -> usize { + fn get_current(&self) -> NodeId { self.current } @@ -53,7 +54,7 @@ impl<'nodes> TreeIterator<'nodes> for RelationalIterator<'nodes> { impl<'nodes> RelationalTreeIterator<'nodes> for RelationalIterator<'nodes> {} impl<'n> Iterator for RelationalIterator<'n> { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { relational_next(self).copied() @@ -62,8 +63,8 @@ impl<'n> Iterator for RelationalIterator<'n> { fn relational_next<'nodes>( iter: &mut impl RelationalTreeIterator<'nodes>, -) -> Option<&'nodes usize> { - match iter.get_nodes().arena.get(iter.get_current()) { +) -> Option<&'nodes NodeId> { + match iter.get_nodes().get(iter.get_current()) { Some(Node::Relational( node @ (Relational::Except { .. } | Relational::Join { .. } diff --git a/sbroad-core/src/ir/tree/subtree.rs b/sbroad-core/src/ir/tree/subtree.rs index ce331404a..4612eae7d 100644 --- a/sbroad-core/src/ir/tree/subtree.rs +++ b/sbroad-core/src/ir/tree/subtree.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; use std::cmp::Ordering; use super::{PlanTreeIterator, Snapshot, TreeIterator}; -use crate::ir::expression::Expression; +use crate::ir::expression::{Expression, NodeId}; use crate::ir::operator::{OrderByElement, OrderByEntity, Relational}; use crate::ir::{Node, Nodes, Plan}; @@ -15,14 +15,14 @@ trait SubtreePlanIterator<'plan>: PlanTreeIterator<'plan> { #[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct SubtreeIterator<'plan> { - current: usize, + current: NodeId, child: RefCell<usize>, plan: &'plan Plan, need_output: bool, } impl<'nodes> TreeIterator<'nodes> for SubtreeIterator<'nodes> { - fn get_current(&self) -> usize { + fn get_current(&self) -> NodeId { self.current } @@ -52,7 +52,7 @@ impl<'plan> SubtreePlanIterator<'plan> for SubtreeIterator<'plan> { } impl<'plan> Iterator for SubtreeIterator<'plan> { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { subtree_next(self, &Snapshot::Latest).copied() @@ -61,7 +61,7 @@ impl<'plan> Iterator for SubtreeIterator<'plan> { impl<'plan> Plan { #[must_use] - pub fn subtree_iter(&'plan self, current: usize, need_output: bool) -> SubtreeIterator<'plan> { + pub fn subtree_iter(&'plan self, current: NodeId, need_output: bool) -> SubtreeIterator<'plan> { SubtreeIterator { current, child: RefCell::new(0), @@ -77,13 +77,13 @@ impl<'plan> Plan { /// at the moment). #[derive(Debug)] pub struct FlashbackSubtreeIterator<'plan> { - current: usize, + current: NodeId, child: RefCell<usize>, plan: &'plan Plan, } impl<'nodes> TreeIterator<'nodes> for FlashbackSubtreeIterator<'nodes> { - fn get_current(&self) -> usize { + fn get_current(&self) -> NodeId { self.current } @@ -113,7 +113,7 @@ impl<'plan> SubtreePlanIterator<'plan> for FlashbackSubtreeIterator<'plan> { } impl<'plan> Iterator for FlashbackSubtreeIterator<'plan> { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { subtree_next(self, &Snapshot::Oldest).copied() @@ -122,7 +122,7 @@ impl<'plan> Iterator for FlashbackSubtreeIterator<'plan> { impl<'plan> Plan { #[must_use] - pub fn flashback_subtree_iter(&'plan self, current: usize) -> FlashbackSubtreeIterator<'plan> { + pub fn flashback_subtree_iter(&'plan self, current: NodeId) -> FlashbackSubtreeIterator<'plan> { FlashbackSubtreeIterator { current, child: RefCell::new(0), @@ -134,13 +134,13 @@ impl<'plan> Plan { /// An iterator used while copying and execution plan subtree. #[derive(Debug)] pub struct ExecPlanSubtreeIterator<'plan> { - current: usize, + current: NodeId, child: RefCell<usize>, plan: &'plan Plan, } impl<'nodes> TreeIterator<'nodes> for ExecPlanSubtreeIterator<'nodes> { - fn get_current(&self) -> usize { + fn get_current(&self) -> NodeId { self.current } @@ -170,7 +170,7 @@ impl<'plan> SubtreePlanIterator<'plan> for ExecPlanSubtreeIterator<'plan> { } impl<'plan> Iterator for ExecPlanSubtreeIterator<'plan> { - type Item = usize; + type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { subtree_next(self, &Snapshot::Oldest).copied() @@ -179,7 +179,7 @@ impl<'plan> Iterator for ExecPlanSubtreeIterator<'plan> { impl<'plan> Plan { #[must_use] - pub fn exec_plan_subtree_iter(&'plan self, current: usize) -> ExecPlanSubtreeIterator<'plan> { + pub fn exec_plan_subtree_iter(&'plan self, current: NodeId) -> ExecPlanSubtreeIterator<'plan> { ExecPlanSubtreeIterator { current, child: RefCell::new(0), @@ -192,8 +192,8 @@ impl<'plan> Plan { fn subtree_next<'plan>( iter: &mut impl SubtreePlanIterator<'plan>, snapshot: &Snapshot, -) -> Option<&'plan usize> { - if let Some(child) = iter.get_nodes().arena.get(iter.get_current()) { +) -> Option<&'plan NodeId> { + if let Some(child) = iter.get_nodes().get(iter.get_current()) { return match child { Node::Parameter(..) | Node::Ddl(..) | Node::Acl(..) | Node::Block(..) => None, Node::Expression(expr) => match expr { diff --git a/sbroad-core/src/ir/tree/tests.rs b/sbroad-core/src/ir/tree/tests.rs index cd1589acc..c188bbcce 100644 --- a/sbroad-core/src/ir/tree/tests.rs +++ b/sbroad-core/src/ir/tree/tests.rs @@ -1,9 +1,9 @@ use crate::ir::operator::Bool; use crate::ir::relation::{SpaceEngine, Table, Type}; use crate::ir::tests::column_user_non_null; -use crate::ir::tree::traversal::{BreadthFirst, PostOrder, EXPR_CAPACITY, REL_CAPACITY}; +use crate::ir::tree::traversal::{BreadthFirst, LevelNode, PostOrder, EXPR_CAPACITY, REL_CAPACITY}; use crate::ir::value::Value; -use crate::ir::{Expression, Plan}; +use crate::ir::{ArenaType, Expression, Plan}; use pretty_assertions::assert_eq; use smol_str::SmolStr; @@ -33,17 +33,17 @@ fn expression_bft() { EXPR_CAPACITY, ); let mut iter = bft_tree.iter(top); - assert_eq!(iter.next(), Some((0, top))); - assert_eq!(iter.next(), Some((1, c1c2_and_c2c3))); - assert_eq!(iter.next(), Some((1, c4_eq_c5))); - assert_eq!(iter.next(), Some((2, c1_eq_c2))); - assert_eq!(iter.next(), Some((2, c2_eq_c3))); - assert_eq!(iter.next(), Some((2, c4))); - assert_eq!(iter.next(), Some((2, c5))); - assert_eq!(iter.next(), Some((3, c1))); - assert_eq!(iter.next(), Some((3, c2))); - assert_eq!(iter.next(), Some((3, c2))); - assert_eq!(iter.next(), Some((3, c3))); + assert_eq!(iter.next(), Some(LevelNode(0, top))); + assert_eq!(iter.next(), Some(LevelNode(1, c1c2_and_c2c3))); + assert_eq!(iter.next(), Some(LevelNode(1, c4_eq_c5))); + assert_eq!(iter.next(), Some(LevelNode(2, c1_eq_c2))); + assert_eq!(iter.next(), Some(LevelNode(2, c2_eq_c3))); + assert_eq!(iter.next(), Some(LevelNode(2, c4))); + assert_eq!(iter.next(), Some(LevelNode(2, c5))); + assert_eq!(iter.next(), Some(LevelNode(3, c1))); + assert_eq!(iter.next(), Some(LevelNode(3, c2))); + assert_eq!(iter.next(), Some(LevelNode(3, c2))); + assert_eq!(iter.next(), Some(LevelNode(3, c3))); assert_eq!(iter.next(), None); } @@ -89,10 +89,10 @@ fn relational_post() { // Traverse the tree let mut dft_post = PostOrder::with_capacity(|node| plan.nodes.rel_iter(node), REL_CAPACITY); let mut iter = dft_post.iter(top); - assert_eq!(iter.next(), Some((1, scan_t1_id))); - assert_eq!(iter.next(), Some((2, scan_t2_id))); - assert_eq!(iter.next(), Some((1, selection_id))); - assert_eq!(iter.next(), Some((0, union_id))); + assert_eq!(iter.next(), Some(LevelNode(1, scan_t1_id))); + assert_eq!(iter.next(), Some(LevelNode(2, scan_t2_id))); + assert_eq!(iter.next(), Some(LevelNode(1, selection_id))); + assert_eq!(iter.next(), Some(LevelNode(0, union_id))); assert_eq!(iter.next(), None); } @@ -164,30 +164,30 @@ fn selection_subquery_dfs_post() { // Traverse relational nodes in the plan tree let mut dft_post = PostOrder::with_capacity(|node| plan.nodes.rel_iter(node), REL_CAPACITY); let mut iter = dft_post.iter(top); - assert_eq!(iter.next(), Some((1, scan_t1_id))); - assert_eq!(iter.next(), Some((4, scan_t2_id))); - assert_eq!(iter.next(), Some((3, selection_t2_id))); - assert_eq!(iter.next(), Some((2, proj_id))); - assert_eq!(iter.next(), Some((1, sq_id))); - assert_eq!(iter.next(), Some((0, selection_t1_id))); + assert_eq!(iter.next(), Some(LevelNode(1, scan_t1_id))); + assert_eq!(iter.next(), Some(LevelNode(4, scan_t2_id))); + assert_eq!(iter.next(), Some(LevelNode(3, selection_t2_id))); + assert_eq!(iter.next(), Some(LevelNode(2, proj_id))); + assert_eq!(iter.next(), Some(LevelNode(1, sq_id))); + assert_eq!(iter.next(), Some(LevelNode(0, selection_t1_id))); assert_eq!(iter.next(), None); // Traverse expression nodes in the selection t2 filter let mut dft_post = PostOrder::with_capacity(|node| plan.nodes.expr_iter(node, true), EXPR_CAPACITY); let mut iter = dft_post.iter(eq_op); - assert_eq!(iter.next(), Some((1, b))); - assert_eq!(iter.next(), Some((1, const1))); - assert_eq!(iter.next(), Some((0, eq_op))); + assert_eq!(iter.next(), Some(LevelNode(1, b))); + assert_eq!(iter.next(), Some(LevelNode(1, const1))); + assert_eq!(iter.next(), Some(LevelNode(0, eq_op))); assert_eq!(iter.next(), None); // Traverse expression nodes in the selection t1 filter let mut dft_post = PostOrder::with_capacity(|node| plan.nodes.expr_iter(node, true), EXPR_CAPACITY); let mut iter = dft_post.iter(in_op); - assert_eq!(iter.next(), Some((1, a))); - assert_eq!(iter.next(), Some((1, c))); - assert_eq!(iter.next(), Some((0, in_op))); + assert_eq!(iter.next(), Some(LevelNode(1, a))); + assert_eq!(iter.next(), Some(LevelNode(1, c))); + assert_eq!(iter.next(), Some(LevelNode(0, in_op))); assert_eq!(iter.next(), None); } @@ -221,7 +221,7 @@ fn subtree_dfs_post() { .unwrap(); plan.add_rel(t1); let scan_t1_id = plan.add_scan("t1", None).unwrap(); - let a_ref = plan.nodes.next_id(); + let a_ref = plan.nodes.next_id(ArenaType::Default); let a = plan.add_row_from_child(scan_t1_id, &["a"]).unwrap(); let const1 = plan.add_const(Value::from(1_i64)); let eq_op = plan.nodes.add_bool(a, Bool::Eq, const1).unwrap(); @@ -249,17 +249,17 @@ fn subtree_dfs_post() { // Traverse relational nodes in the plan tree let mut dft_post = - PostOrder::with_capacity(|node| plan.subtree_iter(node, false), plan.next_id()); + PostOrder::with_capacity(|node| plan.subtree_iter(node, false), plan.nodes.len()); let mut iter = dft_post.iter(top); - assert_eq!(iter.next(), Some((3, *c_ref_id))); - assert_eq!(iter.next(), Some((2, *alias_id))); - assert_eq!(iter.next(), Some((1, proj_row_id))); - assert_eq!(iter.next(), Some((2, scan_t1_id))); - assert_eq!(iter.next(), Some((4, a_ref))); - assert_eq!(iter.next(), Some((3, a))); - assert_eq!(iter.next(), Some((3, const1))); - assert_eq!(iter.next(), Some((2, eq_op))); - assert_eq!(iter.next(), Some((1, selection_t1_id))); - assert_eq!(iter.next(), Some((0, proj_id))); + assert_eq!(iter.next(), Some(LevelNode(3, *c_ref_id))); + assert_eq!(iter.next(), Some(LevelNode(2, *alias_id))); + assert_eq!(iter.next(), Some(LevelNode(1, proj_row_id))); + assert_eq!(iter.next(), Some(LevelNode(2, scan_t1_id))); + assert_eq!(iter.next(), Some(LevelNode(4, a_ref))); + assert_eq!(iter.next(), Some(LevelNode(3, a))); + assert_eq!(iter.next(), Some(LevelNode(3, const1))); + assert_eq!(iter.next(), Some(LevelNode(2, eq_op))); + assert_eq!(iter.next(), Some(LevelNode(1, selection_t1_id))); + assert_eq!(iter.next(), Some(LevelNode(0, proj_id))); assert_eq!(iter.next(), None); } diff --git a/sbroad-core/src/ir/tree/traversal.rs b/sbroad-core/src/ir/tree/traversal.rs index e07788711..40478b9f2 100644 --- a/sbroad-core/src/ir/tree/traversal.rs +++ b/sbroad-core/src/ir/tree/traversal.rs @@ -4,36 +4,41 @@ pub const EXPR_CAPACITY: usize = 64; pub const REL_CAPACITY: usize = 32; /// Pair of (Level of the node in traversal algorithm, `node_id`). -pub type LevelNode = (usize, usize); +#[derive(Debug, PartialEq)] +pub struct LevelNode<T>(pub usize, pub T) +where + T: Copy; -pub struct PostOrder<F, I> +pub struct PostOrder<F, I, T> where - F: FnMut(usize) -> I, - I: Iterator<Item = usize>, + F: FnMut(T) -> I, + I: Iterator<Item = T>, + T: Copy, { - inner: PostOrderWithFilter<'static, F, I>, + inner: PostOrderWithFilter<'static, F, I, T>, } -impl<F, I> PostOrder<F, I> +impl<F, I, T> PostOrder<F, I, T> where - F: FnMut(usize) -> I, - I: Iterator<Item = usize>, + F: FnMut(T) -> I, + I: Iterator<Item = T>, + T: Copy, { - pub fn iter(&mut self, root: usize) -> impl Iterator<Item = LevelNode> { + pub fn iter(&mut self, root: T) -> impl Iterator<Item = LevelNode<T>> { self.inner.iter(root) } - pub fn new(iter_children: F, nodes: Vec<LevelNode>) -> Self { + pub fn new(iter_children: F, nodes: Vec<LevelNode<T>>) -> Self { Self { inner: PostOrderWithFilter::new(iter_children, nodes, Box::new(|_| true)), } } - pub fn populate_nodes(&mut self, root: usize) { + pub fn populate_nodes(&mut self, root: T) { self.inner.populate_nodes(root); } - pub fn take_nodes(&mut self) -> Vec<LevelNode> { + pub fn take_nodes(&mut self) -> Vec<LevelNode<T>> { self.inner.take_nodes() } @@ -44,29 +49,35 @@ where } } -pub type FilterFn<'filter> = Box<dyn Fn(usize) -> bool + 'filter>; +pub type FilterFn<'filter, T> = Box<dyn Fn(T) -> bool + 'filter>; -pub struct PostOrderWithFilter<'filter, F, I> +pub struct PostOrderWithFilter<'filter, F, I, T> where - F: FnMut(usize) -> I, - I: Iterator<Item = usize>, + F: FnMut(T) -> I, + I: Iterator<Item = T>, + T: Copy, { iter_children: F, - nodes: Vec<LevelNode>, - filter_fn: FilterFn<'filter>, + nodes: Vec<LevelNode<T>>, + filter_fn: FilterFn<'filter, T>, } -impl<'filter, F, I> PostOrderWithFilter<'filter, F, I> +impl<'filter, F, I, T> PostOrderWithFilter<'filter, F, I, T> where - F: FnMut(usize) -> I, - I: Iterator<Item = usize>, + F: FnMut(T) -> I, + I: Iterator<Item = T>, + T: Copy, { - pub fn iter(&mut self, root: usize) -> impl Iterator<Item = LevelNode> { + pub fn iter(&mut self, root: T) -> impl Iterator<Item = LevelNode<T>> { self.populate_nodes(root); self.take_nodes().into_iter() } - pub fn new(iter_children: F, nodes: Vec<LevelNode>, filter_fn: FilterFn<'filter>) -> Self { + pub fn new( + iter_children: F, + nodes: Vec<LevelNode<T>>, + filter_fn: FilterFn<'filter, T>, + ) -> Self { Self { iter_children, nodes, @@ -74,25 +85,25 @@ where } } - pub fn populate_nodes(&mut self, root: usize) { + pub fn populate_nodes(&mut self, root: T) { self.nodes.clear(); self.traverse(root, 0); } - pub fn take_nodes(&mut self) -> Vec<LevelNode> { + pub fn take_nodes(&mut self) -> Vec<LevelNode<T>> { std::mem::take(&mut self.nodes) } - fn traverse(&mut self, root: usize, level: usize) { + fn traverse(&mut self, root: T, level: usize) { for child in (self.iter_children)(root) { self.traverse(child, level + 1); } if (self.filter_fn)(root) { - self.nodes.push((level, root)); + self.nodes.push(LevelNode(level, root)); } } - pub fn with_capacity(iter_children: F, capacity: usize, filter: FilterFn<'filter>) -> Self { + pub fn with_capacity(iter_children: F, capacity: usize, filter: FilterFn<'filter, T>) -> Self { Self { iter_children, nodes: Vec::with_capacity(capacity), @@ -101,27 +112,29 @@ where } } -pub struct BreadthFirst<F, I> +pub struct BreadthFirst<F, I, T> where - F: FnMut(usize) -> I, - I: Iterator<Item = usize>, + F: FnMut(T) -> I, + I: Iterator<Item = T>, + T: Copy, { iter_children: F, - queue: VecDeque<LevelNode>, - nodes: Vec<LevelNode>, + queue: VecDeque<LevelNode<T>>, + nodes: Vec<LevelNode<T>>, } -impl<F, I> BreadthFirst<F, I> +impl<F, I, T> BreadthFirst<F, I, T> where - F: FnMut(usize) -> I, - I: Iterator<Item = usize>, + F: FnMut(T) -> I, + I: Iterator<Item = T>, + T: Copy, { - pub fn iter(&mut self, root: usize) -> impl Iterator<Item = LevelNode> { + pub fn iter(&mut self, root: T) -> impl Iterator<Item = LevelNode<T>> { self.populate_nodes(root); self.take_nodes().into_iter() } - pub fn new(iter_children: F, queue: VecDeque<LevelNode>, nodes: Vec<LevelNode>) -> Self { + pub fn new(iter_children: F, queue: VecDeque<LevelNode<T>>, nodes: Vec<LevelNode<T>>) -> Self { Self { iter_children, queue, @@ -129,17 +142,17 @@ where } } - pub fn populate_nodes(&mut self, root: usize) { - self.queue.push_back((0, root)); - while let Some((level, node)) = self.queue.pop_front() { - self.nodes.push((level, node)); + pub fn populate_nodes(&mut self, root: T) { + self.queue.push_back(LevelNode(0, root)); + while let Some(LevelNode(level, node)) = self.queue.pop_front() { + self.nodes.push(LevelNode(level, node)); for child in (self.iter_children)(node) { - self.queue.push_back((level + 1, child)); + self.queue.push_back(LevelNode(level + 1, child)); } } } - pub fn take_nodes(&mut self) -> Vec<LevelNode> { + pub fn take_nodes(&mut self) -> Vec<LevelNode<T>> { std::mem::take(&mut self.nodes) } diff --git a/sbroad-core/src/ir/undo.rs b/sbroad-core/src/ir/undo.rs index 3062be50c..828f5d67c 100644 --- a/sbroad-core/src/ir/undo.rs +++ b/sbroad-core/src/ir/undo.rs @@ -3,12 +3,14 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use super::expression::NodeId; + /// Transformation log keep the history of the plan subtree modifications. /// When we modify the plan subtree, we add a new entry to the log, where /// the key is a new subtree top node and the value is the previous version. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TransformationLog { - log: HashMap<usize, usize>, + log: HashMap<NodeId, NodeId>, } impl Default for TransformationLog { @@ -25,7 +27,7 @@ impl TransformationLog { } } - pub fn add(&mut self, new_id: usize, old_id: usize) { + pub fn add(&mut self, new_id: NodeId, old_id: NodeId) { match self.log.get_key_value(&new_id) { None => { self.log.insert(new_id, old_id); @@ -38,12 +40,12 @@ impl TransformationLog { } #[must_use] - pub fn get(&self, new_id: &usize) -> Option<&usize> { + pub fn get(&self, new_id: &NodeId) -> Option<&NodeId> { self.log.get(new_id) } #[must_use] - pub fn get_oldest(&self, new_id: &usize) -> Option<&usize> { + pub fn get_oldest(&self, new_id: &NodeId) -> Option<&NodeId> { match self.log.get_key_value(new_id) { None => None, Some((id, _)) => { -- GitLab