From 83e269eb3884800c4679da9704e80075b0fa74ee Mon Sep 17 00:00:00 2001 From: Andrey Strochuk <a.strochuk@picodata.io> Date: Tue, 20 Aug 2024 01:09:00 +0300 Subject: [PATCH] feat: add multiple subarenas --- sbroad-benches/benches/parse.rs | 3 +- sbroad-cartridge/src/cartridge/router.rs | 2 +- sbroad-cartridge/src/cartridge/storage.rs | 2 +- .../test/integration/arithmetic_test.lua | 7 +- sbroad-core/src/backend/sql/ir.rs | 54 +- .../src/backend/sql/ir/tests/except.rs | 11 + .../src/backend/sql/ir/tests/selection.rs | 4 +- sbroad-core/src/backend/sql/space.rs | 9 +- sbroad-core/src/backend/sql/tree.rs | 140 +- sbroad-core/src/cbo/histogram.rs | 6 +- sbroad-core/src/errors.rs | 13 +- sbroad-core/src/executor.rs | 8 +- sbroad-core/src/executor/bucket.rs | 82 +- sbroad-core/src/executor/engine.rs | 2 +- sbroad-core/src/executor/engine/helpers.rs | 94 +- .../src/executor/engine/helpers/storage.rs | 2 +- .../src/executor/engine/helpers/vshard.rs | 28 +- sbroad-core/src/executor/engine/mock.rs | 2 +- sbroad-core/src/executor/ir.rs | 176 ++- sbroad-core/src/executor/protocol.rs | 2 +- sbroad-core/src/executor/result.rs | 8 +- sbroad-core/src/executor/tests.rs | 46 +- sbroad-core/src/executor/tests/between.rs | 6 +- .../src/executor/tests/empty_motion.rs | 4 +- sbroad-core/src/executor/tests/exec_plan.rs | 141 +- sbroad-core/src/executor/tests/not_eq.rs | 2 +- sbroad-core/src/executor/tests/not_in.rs | 2 +- sbroad-core/src/executor/vtable.rs | 8 +- sbroad-core/src/frontend/sql.rs | 197 +-- sbroad-core/src/frontend/sql/ir.rs | 285 ++-- sbroad-core/src/frontend/sql/ir/tests.rs | 366 ++--- sbroad-core/src/frontend/sql/ir/tests/ddl.rs | 20 +- .../src/frontend/sql/ir/tests/global.rs | 67 +- .../src/frontend/sql/ir/tests/limit.rs | 14 +- .../src/frontend/sql/ir/tests/single.rs | 8 +- sbroad-core/src/ir.rs | 895 +++++++---- sbroad-core/src/ir/acl.rs | 100 +- sbroad-core/src/ir/aggregates.rs | 17 +- sbroad-core/src/ir/api/children.rs | 12 +- sbroad-core/src/ir/api/constant.rs | 58 +- sbroad-core/src/ir/api/parameter.rs | 165 ++- sbroad-core/src/ir/block.rs | 48 +- sbroad-core/src/ir/ddl.rs | 141 +- sbroad-core/src/ir/distribution.rs | 72 +- sbroad-core/src/ir/distribution/tests.rs | 40 +- sbroad-core/src/ir/explain.rs | 129 +- sbroad-core/src/ir/expression.rs | 592 ++------ sbroad-core/src/ir/expression/cast.rs | 14 +- sbroad-core/src/ir/expression/concat.rs | 15 +- sbroad-core/src/ir/expression/types.rs | 52 +- sbroad-core/src/ir/function.rs | 14 +- sbroad-core/src/ir/helpers.rs | 173 +-- sbroad-core/src/ir/helpers/tests.rs | 292 ++-- sbroad-core/src/ir/node.rs | 1310 +++++++++++++++++ sbroad-core/src/ir/node/acl.rs | 121 ++ sbroad-core/src/ir/node/block.rs | 50 + sbroad-core/src/ir/node/ddl.rs | 134 ++ sbroad-core/src/ir/node/expression.rs | 263 ++++ sbroad-core/src/ir/node/relational.rs | 704 +++++++++ sbroad-core/src/ir/node/util.rs | 14 + sbroad-core/src/ir/operator.rs | 956 ++++-------- sbroad-core/src/ir/operator/tests.rs | 34 +- sbroad-core/src/ir/parameters.rs | 12 +- sbroad-core/src/ir/tests.rs | 6 +- sbroad-core/src/ir/transformation.rs | 78 +- sbroad-core/src/ir/transformation/bool_in.rs | 7 +- sbroad-core/src/ir/transformation/dnf.rs | 23 +- .../ir/transformation/equality_propagation.rs | 29 +- .../equality_propagation/tests.rs | 8 +- .../src/ir/transformation/merge_tuples.rs | 41 +- .../src/ir/transformation/not_push_down.rs | 34 +- .../src/ir/transformation/redistribution.rs | 173 +-- .../ir/transformation/redistribution/dml.rs | 37 +- .../transformation/redistribution/eq_cols.rs | 66 +- .../transformation/redistribution/groupby.rs | 203 +-- .../redistribution/left_join.rs | 7 +- .../ir/transformation/redistribution/tests.rs | 12 +- .../redistribution/tests/between.rs | 7 +- .../redistribution/tests/except.rs | 11 +- .../redistribution/tests/not_in.rs | 15 +- .../redistribution/tests/segment.rs | 43 +- .../src/ir/transformation/split_columns.rs | 19 +- .../ir/transformation/split_columns/tests.rs | 4 +- sbroad-core/src/ir/tree.rs | 63 +- sbroad-core/src/ir/tree/and.rs | 7 +- sbroad-core/src/ir/tree/expression.rs | 40 +- sbroad-core/src/ir/tree/relation.rs | 29 +- sbroad-core/src/ir/tree/subtree.rs | 152 +- sbroad-core/src/ir/tree/tests.rs | 10 +- sbroad-core/src/ir/undo.rs | 2 +- 90 files changed, 5813 insertions(+), 3561 deletions(-) create mode 100644 sbroad-core/src/ir/node.rs create mode 100644 sbroad-core/src/ir/node/acl.rs create mode 100644 sbroad-core/src/ir/node/block.rs create mode 100644 sbroad-core/src/ir/node/ddl.rs create mode 100644 sbroad-core/src/ir/node/expression.rs create mode 100644 sbroad-core/src/ir/node/relational.rs create mode 100644 sbroad-core/src/ir/node/util.rs diff --git a/sbroad-benches/benches/parse.rs b/sbroad-benches/benches/parse.rs index 71c49f950..c875a7a5e 100644 --- a/sbroad-benches/benches/parse.rs +++ b/sbroad-benches/benches/parse.rs @@ -420,7 +420,6 @@ criterion_group!( benches, bench_pure_pest_parsing, bench_full_parsing, - bench_serde_clone, - bench_take_subtree, + bench_serde_clone ); criterion_main!(benches); diff --git a/sbroad-cartridge/src/cartridge/router.rs b/sbroad-cartridge/src/cartridge/router.rs index a5de1d2f6..33234893c 100644 --- a/sbroad-cartridge/src/cartridge/router.rs +++ b/sbroad-cartridge/src/cartridge/router.rs @@ -3,7 +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::ir::node::NodeId; use sbroad::utils::MutexLike; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use tarantool::fiber::Mutex; diff --git a/sbroad-cartridge/src/cartridge/storage.rs b/sbroad-cartridge/src/cartridge/storage.rs index 50c55146a..99b244129 100644 --- a/sbroad-cartridge/src/cartridge/storage.rs +++ b/sbroad-cartridge/src/cartridge/storage.rs @@ -15,8 +15,8 @@ use sbroad::executor::hash::bucket_id_by_tuple; use sbroad::executor::ir::{ExecutionPlan, QueryType}; use sbroad::executor::lru::{Cache, LRUCache, DEFAULT_CAPACITY}; use sbroad::executor::protocol::{RequiredData, SchemaInfo}; +use sbroad::ir::node::NodeId; use sbroad::ir::value::Value; -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-cartridge/test_app/test/integration/arithmetic_test.lua b/sbroad-cartridge/test_app/test/integration/arithmetic_test.lua index d6de46268..b88fc3bff 100644 --- a/sbroad-cartridge/test_app/test/integration/arithmetic_test.lua +++ b/sbroad-cartridge/test_app/test/integration/arithmetic_test.lua @@ -924,9 +924,9 @@ g2.test_alias = function() {name = "a", type = "integer"}, }) - local res, err = api:call("sbroad.execute", { [[ - select "id", "id" + "a" as "sum", "id" * "a" as "mul", "a" from "arithmetic_space" - ]], {}}) + local res, err = api:call("sbroad.execute", { + [[select "id", "id" + "a" as "sum", "id" * "a" as "mul", "a" from "arithmetic_space"]], {} + }) t.assert_equals(err, nil) t.assert_equals(res.metadata, { {name = "id", type = "integer"}, @@ -934,6 +934,7 @@ g2.test_alias = function() {name = "mul", type = "integer"}, {name = "a", type = "integer"}, }) + end g2.test_associativity = function() diff --git a/sbroad-core/src/backend/sql/ir.rs b/sbroad-core/src/backend/sql/ir.rs index b033e3f71..44ff43d87 100644 --- a/sbroad-core/src/backend/sql/ir.rs +++ b/sbroad-core/src/backend/sql/ir.rs @@ -1,5 +1,10 @@ use crate::debug; use crate::executor::protocol::VTablesMeta; +use crate::ir::node::expression::Expression; +use crate::ir::node::relational::Relational; +use crate::ir::node::{ + Constant, Insert, Join, Motion, Node, NodeId, Reference, ScanRelation, StableFunction, +}; use crate::ir::relation::Column; use crate::ir::transformation::redistribution::MotionPolicy; use crate::ir::tree::traversal::{LevelNode, PostOrderWithFilter}; @@ -14,10 +19,8 @@ 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, NodeId}; -use crate::ir::operator::{OrderByType, Relational}; +use crate::ir::operator::OrderByType; use crate::ir::value::{LuaValue, Value}; -use crate::ir::Node; use crate::otm::{child_span, current_id, deserialize_context, inject_context, query_id}; use super::space::{create_table, TableGuard}; @@ -173,7 +176,8 @@ impl ExecutionPlan { let nodes = tree.take_nodes(); let mut params: Vec<Value> = Vec::with_capacity(nodes.len()); for LevelNode(_, param_id) in nodes { - let Expression::Constant { value } = plan.get_expression_node(param_id)? else { + let Expression::Constant(Constant { value }) = plan.get_expression_node(param_id)? + else { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( @@ -209,10 +213,10 @@ impl ExecutionPlan { let motion = ir.get_relation_node(motion_id)?; if !matches!( motion, - Relational::Motion { + Relational::Motion(Motion { policy: MotionPolicy::LocalSegment { .. } | MotionPolicy::Local, .. - } + }) ) { reserved_motion_id = Some(motion_id); } @@ -369,6 +373,15 @@ impl ExecutionPlan { ), )); } + Node::Invalid(..) => { + return Err(SbroadError::Unsupported( + Entity::Node, + Some( + "Invalid nodes are not supported in the generated SQL" + .into(), + ), + )); + } Node::Relational(rel) => match rel { Relational::Except { .. } => sql.push_str("EXCEPT"), Relational::GroupBy { .. } => sql.push_str("GROUP BY"), @@ -384,15 +397,15 @@ impl ExecutionPlan { ), )); } - Relational::Insert { relation, .. } => { + Relational::Insert(Insert { relation, .. }) => { sql.push_str("INSERT INTO "); push_identifier(&mut sql, relation); } - Relational::Join { kind, .. } => sql.push_str( + Relational::Join(Join { kind, .. }) => sql.push_str( format!("{} JOIN", kind.to_string().to_uppercase()).as_str(), ), Relational::Projection { .. } => sql.push_str("SELECT"), - Relational::ScanRelation { relation, .. } => { + Relational::ScanRelation(ScanRelation { relation, .. }) => { push_identifier(&mut sql, relation); } Relational::ScanSubQuery { .. } @@ -418,7 +431,7 @@ impl ExecutionPlan { | Expression::Row { .. } | Expression::Trim { .. } | Expression::Unary { .. } => {} - Expression::Constant { value, .. } => { + Expression::Constant(Constant { value, .. }) => { write!(sql, "{value}").map_err(|e| { SbroadError::FailedTo( Action::Put, @@ -427,7 +440,7 @@ impl ExecutionPlan { ) })?; } - Expression::Reference { position, .. } => { + Expression::Reference(Reference { position, .. }) => { let rel_id = *ir_plan.get_relational_from_reference_node(*id)?; let rel_node = ir_plan.get_relation_node(rel_id)?; @@ -455,16 +468,15 @@ impl ExecutionPlan { } } - let alias = &ir_plan.get_alias_from_reference_node(expr)?; + let alias = + &ir_plan.get_alias_from_reference_node(&expr)?; if rel_node.is_insert() { // We expect `INSERT INTO t(a, b) VALUES(1, 2)` // rather then `INSERT INTO t(t.a, t.b) VALUES(1, 2)`. push_identifier(&mut sql, alias); continue; } - if let Some(name) = - rel_node.scan_name(ir_plan, *position)? - { + if let Some(name) = ir_plan.scan_name(rel_id, *position)? { push_identifier(&mut sql, name); sql.push('.'); push_identifier(&mut sql, alias); @@ -473,16 +485,18 @@ impl ExecutionPlan { } push_identifier(&mut sql, alias); } - Expression::StableFunction { - name, is_system, .. - } => { + Expression::StableFunction(StableFunction { + name, + is_system, + .. + }) => { if *is_system { sql.push_str(name); } else { push_identifier(&mut sql, name); } } - Expression::CountAsterisk => { + Expression::CountAsterisk { .. } => { sql.push('*'); } } @@ -492,7 +506,7 @@ impl ExecutionPlan { SyntaxData::Parameter(id) => { sql.push('?'); let value = ir_plan.get_expression_node(*id)?; - if let Expression::Constant { value, .. } = value { + if let Expression::Constant(Constant { value, .. }) = value { params.push(value.clone()); } else { return Err(SbroadError::Invalid( diff --git a/sbroad-core/src/backend/sql/ir/tests/except.rs b/sbroad-core/src/backend/sql/ir/tests/except.rs index 2180d36f1..83fffff38 100644 --- a/sbroad-core/src/backend/sql/ir/tests/except.rs +++ b/sbroad-core/src/backend/sql/ir/tests/except.rs @@ -1,4 +1,5 @@ use super::*; +use crate::ir::node::*; use crate::ir::tree::Snapshot; use crate::ir::value::Value; @@ -49,3 +50,13 @@ fn except1_oldest() { ); check_sql_with_snapshot(query, vec![], expected, Snapshot::Oldest); } + +// TODO create test for size equals than 40(32) for 64, 96, 136 +#[test] +fn test_node_size() { + assert!(std::mem::size_of::<Node32>() == 40); + assert!(std::mem::size_of::<Node64>() == 72); + assert!(std::mem::size_of::<Node96>() == 96); + assert!(std::mem::size_of::<Node136>() == 136); + assert!(std::mem::size_of::<Node224>() == 224); +} diff --git a/sbroad-core/src/backend/sql/ir/tests/selection.rs b/sbroad-core/src/backend/sql/ir/tests/selection.rs index 7e1b97e2c..20080afa2 100644 --- a/sbroad-core/src/backend/sql/ir/tests/selection.rs +++ b/sbroad-core/src/backend/sql/ir/tests/selection.rs @@ -67,9 +67,9 @@ fn selection2_latest() { let expected = PatternWithParams::new( [ r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, - r#"WHERE ("hash_testing"."product_units", "hash_testing"."product_units", "hash_testing"."identification_number") = ("hash_testing"."identification_number", ?, ?)"#, + r#"WHERE ("hash_testing"."identification_number", "hash_testing"."product_units", "hash_testing"."identification_number") = ("hash_testing"."product_units", ?, ?)"#, r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op")"#, - r#"or ("hash_testing"."product_units", "hash_testing"."product_units", "hash_testing"."identification_number") = ("hash_testing"."identification_number", ?, ?)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_units", "hash_testing"."identification_number") = ("hash_testing"."product_units", ?, ?)"#, r#"and ("hash_testing"."product_units") is null"# ].join(" "), vec![Value::Unsigned(1), Value::Unsigned(1), Value::Unsigned(1), Value::Unsigned(1)], diff --git a/sbroad-core/src/backend/sql/space.rs b/sbroad-core/src/backend/sql/space.rs index 4807b384b..d6c40c502 100644 --- a/sbroad-core/src/backend/sql/space.rs +++ b/sbroad-core/src/backend/sql/space.rs @@ -1,7 +1,9 @@ +use std::fmt::Debug; + use crate::executor::ir::ExecutionPlan; -use crate::ir::expression::NodeId; +use crate::executor::protocol::VTablesMeta; use crate::ir::relation::SpaceEngine; -use crate::{errors::SbroadError, executor::protocol::VTablesMeta}; +use crate::{errors::SbroadError, ir::node::NodeId}; #[cfg(not(feature = "mock"))] mod prod_imports { @@ -11,6 +13,7 @@ mod prod_imports { pub use crate::executor::engine::helpers::{pk_name, table_name}; pub use crate::executor::ir::ExecutionPlan; use crate::executor::protocol::VTablesMeta; + pub use crate::ir::node::NodeId; pub use crate::ir::relation::SpaceEngine; pub use smol_str::{format_smolstr, SmolStr}; pub use tarantool::index::{FieldType, IndexOptions, IndexType, Part}; @@ -20,7 +23,7 @@ mod prod_imports { pub fn create_tmp_space_impl( exec_plan: &ExecutionPlan, plan_id: &str, - motion_id: usize, + motion_id: NodeId, engine: &SpaceEngine, vtables_meta: Option<&VTablesMeta>, ) -> Result<SmolStr, SbroadError> { diff --git a/sbroad-core/src/backend/sql/tree.rs b/sbroad-core/src/backend/sql/tree.rs index 51954121c..d1ac606c1 100644 --- a/sbroad-core/src/backend/sql/tree.rs +++ b/sbroad-core/src/backend/sql/tree.rs @@ -4,12 +4,20 @@ use std::mem::take; use crate::errors::{Entity, SbroadError}; use crate::executor::ir::ExecutionPlan; -use crate::ir::expression::{Expression, FunctionFeature, NodeId, TrimKind}; -use crate::ir::operator::{Bool, OrderByElement, OrderByEntity, OrderByType, Relational, Unary}; +use crate::ir::expression::{FunctionFeature, TrimKind}; +use crate::ir::node::expression::Expression; +use crate::ir::node::relational::Relational; +use crate::ir::node::{ + Alias, ArithmeticExpr, BoolExpr, Case, Cast, Concat, Except, ExprInParentheses, GroupBy, + Having, Intersect, Join, Limit, Motion, Node, NodeId, OrderBy, Projection, Reference, Row, + ScanCte, ScanRelation, ScanSubQuery, Selection, StableFunction, Trim, UnaryExpr, Union, + UnionAll, Values, ValuesRow, +}; +use crate::ir::operator::{Bool, OrderByElement, OrderByEntity, OrderByType, Unary}; use crate::ir::transformation::redistribution::{MotionOpcode, MotionPolicy}; use crate::ir::tree::traversal::{LevelNode, PostOrder}; use crate::ir::tree::Snapshot; -use crate::ir::{Node, Plan}; +use crate::ir::Plan; use crate::otm::child_span; use sbroad_proc::otm_child_span; @@ -479,7 +487,7 @@ impl Select { id: usize, ) -> Result<Option<Select>, SbroadError> { let sn = sp.nodes.get_sn(id); - if let Some(Node::Relational(Relational::Projection { .. })) = sp.get_plan_node(&sn.data)? { + if let Some(Node::Relational(Relational::Projection(_))) = sp.get_plan_node(&sn.data)? { let mut select = Select { parent, branch, @@ -495,10 +503,10 @@ impl Select { let sn_left = sp.nodes.get_sn(left_id); let plan_node_left = sp.plan_node_or_err(&sn_left.data)?; if let Node::Relational( - Relational::ScanRelation { .. } - | Relational::ScanCte { .. } - | Relational::ScanSubQuery { .. } - | Relational::Motion { .. }, + Relational::ScanRelation(_) + | Relational::ScanCte(_) + | Relational::ScanSubQuery(_) + | Relational::Motion(_), ) = plan_node_left { select.scan = left_id; @@ -564,13 +572,13 @@ impl<'p> SyntaxPlan<'p> { let plan = self.plan.get_ir_plan(); let node = plan.get_node(plan_id).expect("node in the plan must exist"); match node { - Node::Relational(Relational::Motion { children, .. }) => { + Node::Relational(Relational::Motion(Motion { children, .. })) => { let child_id = *children.first().expect("MOTION child must exist"); if *id == child_id { return; } } - Node::Expression(Expression::Row { .. }) => { + Node::Expression(Expression::Row(_)) => { let rel_ids = plan .get_relational_nodes_from_row(plan_id) .expect("row relational nodes"); @@ -618,11 +626,11 @@ impl<'p> SyntaxPlan<'p> { Node::Ddl(..) => panic!("DDL node {node:?} is not supported in the syntax plan"), Node::Acl(..) => panic!("ACL node {node:?} is not supported in the syntax plan"), Node::Block(..) => panic!("Block node {node:?} is not supported in the syntax plan"), - Node::Parameter(..) => { + Node::Invalid(..) | Node::Parameter(..) => { let sn = SyntaxNode::new_parameter(id); self.nodes.push_sn_plan(sn); } - Node::Relational(rel) => match rel { + Node::Relational(ref rel) => match rel { Relational::Insert { .. } | Relational::Delete { .. } | Relational::Update { .. } => { @@ -654,7 +662,7 @@ impl<'p> SyntaxPlan<'p> { let sn = SyntaxNode::new_parameter(id); self.nodes.push_sn_plan(sn); } - Expression::Reference { .. } | Expression::CountAsterisk => { + Expression::Reference { .. } | Expression::CountAsterisk { .. } => { let sn = SyntaxNode::new_pointer(id, None, vec![]); self.nodes.push_sn_plan(sn); } @@ -668,7 +676,7 @@ impl<'p> SyntaxPlan<'p> { } } - fn prologue_rel(&self, id: NodeId) -> (&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 +684,7 @@ impl<'p> SyntaxPlan<'p> { (plan, rel) } - fn prologue_expr(&self, id: NodeId) -> (&Plan, &Expression) { + fn prologue_expr(&self, id: NodeId) -> (&Plan, Expression) { let plan = self.plan.get_ir_plan(); let expr = plan .get_expression_node(id) @@ -688,7 +696,7 @@ impl<'p> SyntaxPlan<'p> { fn add_cte(&mut self, id: NodeId) { let (_, cte) = self.prologue_rel(id); - let Relational::ScanCte { alias, child, .. } = cte else { + let Relational::ScanCte(ScanCte { alias, child, .. }) = cte else { panic!("expected CTE node"); }; let (child, alias) = (*child, alias.clone()); @@ -706,12 +714,12 @@ impl<'p> SyntaxPlan<'p> { fn add_filter(&mut self, id: NodeId) { let (plan, rel) = self.prologue_rel(id); - let (Relational::Selection { + let (Relational::Selection(Selection { children, filter, .. - } - | Relational::Having { + }) + | Relational::Having(Having { children, filter, .. - }) = rel + })) = rel else { panic!("Expected FILTER node"); }; @@ -728,9 +736,9 @@ impl<'p> SyntaxPlan<'p> { fn add_group_by(&mut self, id: NodeId) { let (_, gb) = self.prologue_rel(id); - let Relational::GroupBy { + let Relational::GroupBy(GroupBy { children, gr_cols, .. - } = gb + }) = gb else { panic!("Expected GROUP BY node"); }; @@ -759,11 +767,11 @@ impl<'p> SyntaxPlan<'p> { fn add_join(&mut self, id: NodeId) { let (plan, join) = self.prologue_rel(id); - let Relational::Join { + let Relational::Join(Join { children, condition, .. - } = join + }) = join else { panic!("Expected JOIN node"); }; @@ -794,14 +802,14 @@ impl<'p> SyntaxPlan<'p> { fn add_motion(&mut self, id: NodeId) { let (plan, motion) = self.prologue_rel(id); - let Relational::Motion { + let Relational::Motion(Motion { policy, children, is_child_subquery, program, output, .. - } = motion + }) = motion else { panic!("Expected MOTION node"); }; @@ -841,7 +849,7 @@ impl<'p> SyntaxPlan<'p> { .get_child_under_alias(*col) .expect("motion output must be a row of aliases!"); let ref_expr = plan.get_expression_node(ref_id).expect("reference node"); - let Expression::Reference { col_type, .. } = ref_expr else { + let Expression::Reference(Reference { col_type, .. }) = ref_expr else { panic!("expected Reference under Alias in Motion output"); }; select_columns.push(format_smolstr!("cast(null as {col_type})")); @@ -899,11 +907,11 @@ impl<'p> SyntaxPlan<'p> { fn add_order_by(&mut self, id: NodeId) { let (_, order_by) = self.prologue_rel(id); - let Relational::OrderBy { + let Relational::OrderBy(OrderBy { order_by_elements, child, .. - } = order_by + }) = order_by else { panic!("expect ORDER BY node"); }; @@ -955,9 +963,9 @@ impl<'p> SyntaxPlan<'p> { fn add_proj(&mut self, id: NodeId) { let (_, proj) = self.prologue_rel(id); - let Relational::Projection { + let Relational::Projection(Projection { children, output, .. - } = proj + }) = proj else { panic!("Expected PROJECTION node"); }; @@ -988,7 +996,7 @@ impl<'p> SyntaxPlan<'p> { fn add_scan_relation(&mut self, id: NodeId) { let (_, scan) = self.prologue_rel(id); - let Relational::ScanRelation { alias, .. } = scan else { + let Relational::ScanRelation(ScanRelation { alias, .. }) = scan else { panic!("Expected SCAN node"); }; let scan_alias = alias.clone(); @@ -1004,10 +1012,10 @@ impl<'p> SyntaxPlan<'p> { fn add_set(&mut self, id: NodeId) { let (_, set) = self.prologue_rel(id); - let (Relational::Except { left, right, .. } - | Relational::Union { left, right, .. } - | Relational::UnionAll { left, right, .. } - | Relational::Intersect { left, right, .. }) = set + let (Relational::Except(Except { left, right, .. }) + | Relational::Union(Union { left, right, .. }) + | Relational::UnionAll(UnionAll { left, right, .. }) + | Relational::Intersect(Intersect { left, right, .. })) = set else { panic!("Expected SET node"); }; @@ -1020,9 +1028,9 @@ impl<'p> SyntaxPlan<'p> { fn add_sq(&mut self, id: NodeId) { let (_, sq) = self.prologue_rel(id); - let Relational::ScanSubQuery { + let Relational::ScanSubQuery(ScanSubQuery { children, alias, .. - } = sq + }) = sq else { panic!("Expected SUBQUERY node"); }; @@ -1045,7 +1053,7 @@ impl<'p> SyntaxPlan<'p> { fn add_values_row(&mut self, id: NodeId) { let (_, row) = self.prologue_rel(id); - let Relational::ValuesRow { data, .. } = row else { + let Relational::ValuesRow(ValuesRow { data, .. }) = row else { panic!("Expected VALUES ROW node"); }; let data_sn_id = self.pop_from_stack(*data); @@ -1055,9 +1063,9 @@ impl<'p> SyntaxPlan<'p> { fn add_values(&mut self, id: NodeId) { let (_, values) = self.prologue_rel(id); - let Relational::Values { + let Relational::Values(Values { children, output, .. - } = values + }) = values else { panic!("Expected VALUES node"); }; @@ -1091,7 +1099,7 @@ impl<'p> SyntaxPlan<'p> { fn add_limit(&mut self, id: NodeId) { let (_, limit) = self.prologue_rel(id); - let Relational::Limit { limit, child, .. } = limit else { + let Relational::Limit(Limit { limit, child, .. }) = limit else { panic!("expected LIMIT node"); }; let (limit, child) = (*limit, *child); @@ -1109,7 +1117,7 @@ impl<'p> SyntaxPlan<'p> { fn add_alias(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); - let Expression::Alias { child, name } = expr else { + let Expression::Alias(Alias { child, name }) = expr else { panic!("Expected ALIAS node"); }; let (child, name) = (*child, name.clone()); @@ -1119,9 +1127,9 @@ impl<'p> SyntaxPlan<'p> { let child_expr = plan .get_expression_node(child) .expect("alias child expression"); - if let Expression::Reference { .. } = child_expr { + if let Expression::Reference(_) = child_expr { let alias = plan - .get_alias_from_reference_node(child_expr) + .get_alias_from_reference_node(&child_expr) .expect("alias name"); if alias == name { let sn = SyntaxNode::new_pointer(id, None, vec![child_sn_id]); @@ -1137,18 +1145,18 @@ impl<'p> SyntaxPlan<'p> { 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 { + Expression::Bool(BoolExpr { left, right, op, .. - } => { + }) => { let (op, left, right) = (op.clone(), *left, *right); let op_sn_id = self .nodes .push_sn_non_plan(SyntaxNode::new_operator(&format!("{op}"))); (left, right, op_sn_id) } - Expression::Arithmetic { + Expression::Arithmetic(ArithmeticExpr { left, right, op, .. - } => { + }) => { let (op, left, right) = (op.clone(), *left, *right); let op_sn_id = self .nodes @@ -1166,11 +1174,11 @@ impl<'p> SyntaxPlan<'p> { fn add_case(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); - let Expression::Case { + let Expression::Case(Case { search_expr, when_blocks, else_expr, - } = expr + }) = expr else { panic!("Expected CASE node"); }; @@ -1204,7 +1212,7 @@ impl<'p> SyntaxPlan<'p> { fn add_cast(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); - let Expression::Cast { child, to } = expr else { + let Expression::Cast(Cast { child, to }) = expr else { panic!("Expected CAST node"); }; let to_alias = SmolStr::from(to); @@ -1224,7 +1232,7 @@ impl<'p> SyntaxPlan<'p> { fn add_concat(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); - let Expression::Concat { left, right } = expr else { + let Expression::Concat(Concat { left, right }) = expr else { panic!("Expected CONCAT node"); }; let (left, right) = (*left, *right); @@ -1240,7 +1248,7 @@ impl<'p> SyntaxPlan<'p> { fn add_expr_in_parentheses(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); - let Expression::ExprInParentheses { child } = expr else { + let Expression::ExprInParentheses(ExprInParentheses { child }) = expr else { panic!("Expected expression in parentheses node"); }; let child_sn_id = self.pop_from_stack(*child); @@ -1259,7 +1267,7 @@ impl<'p> SyntaxPlan<'p> { let expr = plan .get_expression_node(id) .expect("node {id} must exist in the plan"); - let Expression::Row { list, .. } = expr else { + let Expression::Row(Row { list, .. }) = expr else { panic!("Expected ROW node"); }; @@ -1284,7 +1292,7 @@ impl<'p> SyntaxPlan<'p> { let first_child = plan .get_expression_node(first_child_id) .expect("row child is expression"); - let first_child_is_ref = matches!(first_child, Expression::Reference { .. }); + let first_child_is_ref = matches!(first_child, Expression::Reference(_)); // Replace motion node to virtual table node. let vtable = self @@ -1305,7 +1313,7 @@ impl<'p> SyntaxPlan<'p> { let expr = plan .get_expression_node(*child_id) .expect("row child is expression"); - if matches!(expr, Expression::Reference { .. }) { + if matches!(expr, Expression::Reference(_)) { let referred_id = *plan .get_relational_from_reference_node(*child_id) .expect("referred id"); @@ -1346,7 +1354,7 @@ impl<'p> SyntaxPlan<'p> { let expr = plan .get_expression_node(*child_id) .expect("row child is expression"); - if matches!(expr, Expression::Reference { .. }) { + if matches!(expr, Expression::Reference(_)) { let referred_id = *plan .get_relational_from_reference_node(*child_id) .expect("referred id"); @@ -1383,11 +1391,11 @@ impl<'p> SyntaxPlan<'p> { let expr = plan .get_expression_node(id) .expect("node {id} must exist in the plan"); - let Expression::StableFunction { + let Expression::StableFunction(StableFunction { children: args, feature, .. - } = expr + }) = expr else { panic!("Expected stable function node"); }; @@ -1413,11 +1421,11 @@ impl<'p> SyntaxPlan<'p> { fn add_trim(&mut self, id: NodeId) { let (_, expr) = self.prologue_expr(id); - let Expression::Trim { + let Expression::Trim(Trim { kind, pattern, target, - } = expr + }) = expr else { panic!("Expected TRIM node"); }; @@ -1461,12 +1469,12 @@ impl<'p> SyntaxPlan<'p> { fn add_unary_op(&mut self, id: NodeId) { let (plan, expr) = self.prologue_expr(id); - let Expression::Unary { child, op } = expr else { + let Expression::Unary(UnaryExpr { child, op }) = expr else { panic!("Expected unary expression node"); }; let (child, op) = (*child, op.clone()); let child_node = plan.get_expression_node(child).expect("child expression"); - let is_and = matches!(child_node, Expression::Bool { op: Bool::And, .. }); + let is_and = matches!(child_node, Expression::Bool(BoolExpr { op: Bool::And, .. })); let operator_node_id = self .nodes .push_sn_non_plan(SyntaxNode::new_operator(&format!("{op}"))); @@ -1497,7 +1505,7 @@ impl<'p> SyntaxPlan<'p> { /// /// # Errors /// - syntax node wraps an invalid plan node - pub fn get_plan_node(&self, data: &SyntaxData) -> Result<Option<&Node>, SbroadError> { + pub fn get_plan_node(&self, data: &SyntaxData) -> Result<Option<Node>, SbroadError> { if let SyntaxData::PlanId(id) = data { Ok(Some(self.plan.get_ir_plan().get_node(*id)?)) } else { @@ -1510,7 +1518,7 @@ impl<'p> SyntaxPlan<'p> { /// # Errors /// - plan node is invalid /// - syntax tree node doesn't have a plan node - pub fn plan_node_or_err(&self, data: &SyntaxData) -> Result<&Node, SbroadError> { + pub fn plan_node_or_err(&self, data: &SyntaxData) -> Result<Node, SbroadError> { self.get_plan_node(data)?.ok_or_else(|| { SbroadError::Invalid( Entity::SyntaxPlan, diff --git a/sbroad-core/src/cbo/histogram.rs b/sbroad-core/src/cbo/histogram.rs index 5d6137a19..6d50610e7 100644 --- a/sbroad-core/src/cbo/histogram.rs +++ b/sbroad-core/src/cbo/histogram.rs @@ -197,7 +197,7 @@ pub struct Mcv<T: Scalar> { /// Number of such a value divided by the number of all values in a column. /// /// Represented not with `f64`, but with `Decimal` type because the former doesn't support NaNs - /// and implements `Eq` trait, that we need for putting this struct into the HashSet. + /// and implements `Eq` trait, that we need for putting this struct into the 'HashSet'. pub(crate) frequency: Decimal, } @@ -512,8 +512,8 @@ pub struct Histogram<T: Scalar> { /// **Note**: Values from mcv are not included in histogram buckets. /// /// Boundaries: - /// * i = 0 -> [b_0; b_1] (where `from` field of the bucket is included) - /// * i = 1 -> (b_1; b_2] + /// * i = 0 -> ['b_0'; 'b_1'] (where `from` field of the bucket is included) + /// * i = 1 -> ('b_1'; 'b_2'] /// * ... /// * i = n -> (b_(n-2); b_(n-1)] pub(crate) buckets: HistogramBuckets<T>, diff --git a/sbroad-core/src/errors.rs b/sbroad-core/src/errors.rs index 88afdc47f..0353089e1 100644 --- a/sbroad-core/src/errors.rs +++ b/sbroad-core/src/errors.rs @@ -14,15 +14,15 @@ pub enum Entity { Acl, /// corresponding to enum Args Args, - /// corresponding to struct AbstractSyntaxTree + /// corresponding to struct 'AbstractSyntaxTree' AST, - /// corresponding to struct ParseNode + /// corresponding to struct 'ParseNode' ParseNode, /// corresponding to trait Aggregate Aggregate, - /// corresponding to struct AggregateSignature + /// corresponding to struct 'AggregateSignature' AggregateSignature, - /// corresponding to struct AggregateCollector + /// corresponding to struct 'AggregateCollector' AggregateCollector, /// corresponding to struct Buckets Buckets, @@ -38,6 +38,8 @@ pub enum Entity { Column, /// CTE Cte, + /// corresponding to operations on DDL. + Ddl, /// corresponds to enum Distribution Distribution, /// tarantool distribution key @@ -46,7 +48,7 @@ pub enum Entity { Engine, /// corresponds to enum Expression Expression, - /// corresponds to struct ExpressionMapper + /// corresponds to struct 'ExpressionMapper' ExpressionMapper, /// corresponds to struct Histogram Histogram, @@ -164,6 +166,7 @@ impl fmt::Display for Entity { Entity::ClusterSchema => "cluster schema".to_smolstr(), Entity::Column => "column".to_smolstr(), Entity::Cte => "CTE".to_smolstr(), + Entity::Ddl => "DDL".to_smolstr(), Entity::Distribution => "distribution".to_smolstr(), Entity::DistributionKey => "distribution key".to_smolstr(), Entity::Engine => "engine".to_smolstr(), diff --git a/sbroad-core/src/executor.rs b/sbroad-core/src/executor.rs index b708f8af1..7b944a796 100644 --- a/sbroad-core/src/executor.rs +++ b/sbroad-core/src/executor.rs @@ -33,8 +33,8 @@ 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::node::relational::Relational; +use crate::ir::node::{Motion, NodeId}; use crate::ir::transformation::redistribution::MotionPolicy; use crate::ir::value::Value; use crate::ir::{Plan, Slices}; @@ -192,8 +192,7 @@ where } } let motion = self.exec_plan.get_ir_plan().get_relation_node(*motion_id)?; - - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { match policy { MotionPolicy::Segment(_) => { // if child is values, then we can materialize it @@ -225,6 +224,7 @@ where } let top_id = self.exec_plan.get_motion_subtree_root(*motion_id)?; + let buckets = self.bucket_discovery(top_id)?; let virtual_table = self.coordinator.materialize_motion( &mut self.exec_plan, diff --git a/sbroad-core/src/executor/bucket.rs b/sbroad-core/src/executor/bucket.rs index ebaae19bb..478761d66 100644 --- a/sbroad-core/src/executor/bucket.rs +++ b/sbroad-core/src/executor/bucket.rs @@ -7,13 +7,18 @@ 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, NodeId}; use crate::ir::helpers::RepeatableState; -use crate::ir::operator::{Bool, JoinKind, Relational}; +use crate::ir::node::expression::Expression; +use crate::ir::node::relational::Relational; +use crate::ir::node::{ + BoolExpr, Delete, Except, GroupBy, Having, Insert, Intersect, Join, Limit, Motion, Node, + NodeId, OrderBy, Projection, Row, ScanCte, ScanRelation, ScanSubQuery, Selection, Union, + UnionAll, Update, Values, ValuesRow, +}; +use crate::ir::operator::{Bool, JoinKind}; use crate::ir::transformation::redistribution::MotionPolicy; use crate::ir::tree::traversal::{LevelNode, PostOrderWithFilter, REL_CAPACITY}; use crate::ir::value::Value; -use crate::ir::Node; use crate::otm::child_span; use sbroad_proc::otm_child_span; @@ -97,22 +102,22 @@ where let expr = ir_plan.get_expression_node(expr_id)?; // Try to collect buckets from expression of type `sharding_key = value` - if let Expression::Bool { + if let Expression::Bool(BoolExpr { op: Bool::Eq | Bool::In, left, right, .. - } = expr + }) = expr { let pairs = vec![(*left, *right), (*right, *left)]; for (left_id, right_id) in pairs { let left_expr = ir_plan.get_expression_node(left_id)?; - if !matches!(left_expr, Expression::Row { .. }) { + if !matches!(left_expr, Expression::Row(_)) { continue; } let right_expr = ir_plan.get_expression_node(right_id)?; - let right_columns = if let Expression::Row { list, .. } = right_expr { + let right_columns = if let Expression::Row(Row { list, .. }) = right_expr { list.clone() } else { continue; @@ -160,8 +165,8 @@ where ) })?; let right_column_expr = ir_plan.get_expression_node(right_column_id)?; - if let Expression::Constant { .. } = right_column_expr { - values.push(right_column_expr.as_const_value_ref()?); + if let Expression::Constant(_) = right_column_expr { + values.push(ir_plan.as_const_value_ref(right_column_id)?); } else { // One of the columns is not a constant. Skip this key. values = Vec::new(); @@ -277,10 +282,10 @@ where // 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)?; - if let Expression::Row { + if let Expression::Row(Row { distribution: Some(dist), .. - } = self + }) = self .exec_plan .get_ir_plan() .get_expression_node(top_output_id)? @@ -292,7 +297,7 @@ where let ir_plan = self.exec_plan.get_ir_plan(); let filter = |node_id: NodeId| -> bool { - if let Ok(Node::Relational(_)) = ir_plan.get_node(node_id) { + if let Ok(Node::Relational(..)) = ir_plan.get_node(node_id) { return true; } false @@ -312,9 +317,9 @@ where let rel = self.exec_plan.get_ir_plan().get_relation_node(node_id)?; match rel { - Relational::ScanRelation { + Relational::ScanRelation(ScanRelation { output, relation, .. - } => { + }) => { if ir_plan .get_relation_or_error(relation.as_str())? .is_global() @@ -324,12 +329,12 @@ where self.bucket_map.insert(*output, Buckets::All); } } - Relational::Motion { + Relational::Motion(Motion { children, policy, output, .. - } => match policy { + }) => match policy { MotionPolicy::Full | MotionPolicy::Local => { self.bucket_map.insert(*output, Buckets::Any); } @@ -391,9 +396,9 @@ where )); } }, - Relational::Delete { output, .. } - | Relational::Insert { output, .. } - | Relational::Update { output, .. } => { + Relational::Delete(Delete { output, .. }) + | Relational::Insert(Insert { output, .. }) + | Relational::Update(Update { output, .. }) => { let child_id = ir_plan.get_relational_child(node_id, 0)?; let child_buckets = self .bucket_map @@ -418,13 +423,13 @@ where } self.bucket_map.insert(*output, my_buckets); } - Relational::Projection { output, .. } - | Relational::GroupBy { output, .. } - | Relational::Having { output, .. } - | Relational::OrderBy { output, .. } - | Relational::ScanCte { output, .. } - | Relational::ScanSubQuery { output, .. } - | Relational::Limit { output, .. } => { + Relational::Projection(Projection { output, .. }) + | Relational::GroupBy(GroupBy { output, .. }) + | Relational::Having(Having { output, .. }) + | Relational::OrderBy(OrderBy { output, .. }) + | Relational::ScanCte(ScanCte { output, .. }) + | Relational::ScanSubQuery(ScanSubQuery { output, .. }) + | Relational::Limit(Limit { output, .. }) => { let child_id = ir_plan.get_relational_child(node_id, 0)?; let child_rel = ir_plan.get_relation_node(child_id)?; let child_buckets = self @@ -440,7 +445,7 @@ where .clone(); self.bucket_map.insert(*output, child_buckets); } - Relational::Except { left, output, .. } => { + Relational::Except(Except { left, output, .. }) => { // We are only interested in the first child (the left one). // The rows from the second child would be transferred to the // first child by the motion or already located in the first @@ -454,18 +459,18 @@ where .clone(); self.bucket_map.insert(*output, first_buckets); } - Relational::Union { + Relational::Union(Union { left, right, output, .. - } - | Relational::UnionAll { + }) + | Relational::UnionAll(UnionAll { left, right, output, .. - } => { + }) => { let first_rel = self.exec_plan.get_ir_plan().get_relation_node(*left)?; let second_rel = self.exec_plan.get_ir_plan().get_relation_node(*right)?; let first_buckets = self @@ -479,12 +484,12 @@ where let buckets = first_buckets.disjunct(second_buckets)?; self.bucket_map.insert(*output, buckets); } - Relational::Intersect { + Relational::Intersect(Intersect { left, right, output, .. - } => { + }) => { let first_rel = self.exec_plan.get_ir_plan().get_relation_node(*left)?; let second_rel = self.exec_plan.get_ir_plan().get_relation_node(*right)?; let first_buckets = self @@ -498,12 +503,12 @@ where let buckets = first_buckets.disjunct(second_buckets)?; self.bucket_map.insert(*output, buckets); } - Relational::Selection { + Relational::Selection(Selection { children, filter, output, .. - } => { + }) => { // We need to get the buckets of the child node for the case // when the filter returns no buckets to reduce. let child_id = children.first().ok_or_else(|| { @@ -529,12 +534,12 @@ where self.bucket_map .insert(output_id, child_buckets.conjuct(&filter_buckets)?); } - Relational::Join { + Relational::Join(Join { children, condition, output, kind, - } => { + }) => { if let (Some(inner_id), Some(outer_id)) = (children.first(), children.get(1)) { let inner_rel = self.exec_plan.get_ir_plan().get_relation_node(*inner_id)?; @@ -581,7 +586,8 @@ where )); } } - Relational::Values { output, .. } | Relational::ValuesRow { output, .. } => { + Relational::Values(Values { output, .. }) + | Relational::ValuesRow(ValuesRow { output, .. }) => { // At the moment values rows are located on the coordinator, // so there are no buckets to execute on. self.bucket_map.insert(*output, Buckets::new_empty()); diff --git a/sbroad-core/src/executor/engine.rs b/sbroad-core/src/executor/engine.rs index 509a93a58..d65d8407b 100644 --- a/sbroad-core/src/executor/engine.rs +++ b/sbroad-core/src/executor/engine.rs @@ -7,7 +7,7 @@ use tarantool::tuple::Tuple; use crate::cbo::histogram::Scalar; use crate::cbo::{ColumnStats, TableColumnPair, TableStats}; -use crate::ir::expression::NodeId; +use crate::ir::node::NodeId; use crate::utils::MutexLike; use std::any::Any; diff --git a/sbroad-core/src/executor/engine/helpers.rs b/sbroad-core/src/executor/engine/helpers.rs index 77a7cc8a9..1d1e2a0b4 100644 --- a/sbroad-core/src/executor/engine/helpers.rs +++ b/sbroad-core/src/executor/engine/helpers.rs @@ -1,6 +1,15 @@ use ahash::AHashMap; -use crate::{error, ir::expression::NodeId, utils::MutexLike}; +use crate::{ + error, + ir::node::{ + expression::{ExprOwned, Expression}, + relational::{RelOwned, Relational}, + Alias, Constant, Delete, Insert, Limit, Motion, NodeId, NodeOwned, Update, Values, + ValuesRow, + }, + utils::MutexLike, +}; use itertools::enumerate; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use std::{ @@ -42,13 +51,11 @@ use crate::{ }, ir::{ distribution::Distribution, - expression::Expression, - operator::Relational, relation::{Column, ColumnRole, Type}, transformation::redistribution::{MotionKey, MotionPolicy}, tree::Snapshot, value::Value, - Node, Plan, + Plan, }, }; use sbroad_proc::otm_child_span; @@ -140,10 +147,10 @@ pub fn build_required_binary(exec_plan: &mut ExecutionPlan) -> Result<Binary, Sb let child_id = ir.get_relational_child(top_id, 0)?; let is_cacheable = matches!( ir.get_relation_node(child_id)?, - Relational::Motion { + Relational::Motion(Motion { policy: MotionPolicy::Local | MotionPolicy::LocalSegment { .. }, .. - } + }) ); if is_cacheable { let cacheable_subtree_root_id = exec_plan.get_motion_subtree_root(child_id)?; @@ -187,16 +194,18 @@ pub fn build_optional_binary(mut exec_plan: ExecutionPlan) -> Result<Binary, Sbr let sp_top_id = plan.get_top()?; let sp_top = plan.get_relation_node(sp_top_id)?; let motion_id = match sp_top { - Relational::Insert { children, .. } - | Relational::Delete { children, .. } - | Relational::Update { children, .. } => *children.first().ok_or_else(|| { - SbroadError::Invalid( - Entity::Plan, - Some(format_smolstr!( - "expected at least one child under DML node {sp_top:?}", - )), - ) - })?, + Relational::Insert(Insert { children, .. }) + | Relational::Update(Update { children, .. }) + | Relational::Delete(Delete { children, .. }) => { + *children.first().ok_or_else(|| { + SbroadError::Invalid( + Entity::Plan, + Some(format_smolstr!( + "expected at least one child under DML node {sp_top:?}", + )), + ) + })? + } _ => { return Err(SbroadError::Invalid( Entity::Plan, @@ -205,7 +214,7 @@ pub fn build_optional_binary(mut exec_plan: ExecutionPlan) -> Result<Binary, Sbr } }; let motion = plan.get_relation_node(motion_id)?; - let Relational::Motion { policy, .. } = motion else { + let Relational::Motion(Motion { policy, .. }) = motion else { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( @@ -437,12 +446,12 @@ pub fn init_local_update_tuple_builder( vtable: &VirtualTable, update_id: NodeId, ) -> Result<TupleBuilderPattern, SbroadError> { - if let Relational::Update { + if let Relational::Update(Update { relation, update_columns_map, pk_positions, .. - } = plan.get_relation_node(update_id)? + }) = plan.get_relation_node(update_id)? { let mut commands: TupleBuilderPattern = Vec::with_capacity(update_columns_map.len() + pk_positions.len()); @@ -664,9 +673,9 @@ fn init_sharded_update_tuple_builder( vtable: &VirtualTable, update_id: NodeId, ) -> Result<TupleBuilderPattern, SbroadError> { - let Relational::Update { + let Relational::Update(Update { update_columns_map, .. - } = plan.get_relation_node(update_id)? + }) = plan.get_relation_node(update_id)? else { return Err(SbroadError::Invalid( Entity::Node, @@ -759,7 +768,7 @@ pub fn empty_query_result( for col_id in columns { let column = ir_plan.get_expression_node(*col_id)?; let column_type = column.calculate_type(ir_plan)?; - let column_name = if let Expression::Alias { name, .. } = column { + let column_name = if let Expression::Alias(Alias { name, .. }) = column { name.clone() } else { return Err(SbroadError::Invalid( @@ -811,7 +820,7 @@ pub fn explain_format(explain: &str) -> Result<Box<dyn Any>, SbroadError> { fn has_zero_limit_clause(plan: &ExecutionPlan) -> Result<bool, SbroadError> { let ir = plan.get_ir_plan(); let top_id = ir.get_top()?; - if let Relational::Limit { limit, .. } = ir.get_relation_node(top_id)? { + if let Relational::Limit(Limit { limit, .. }) = ir.get_relation_node(top_id)? { return Ok(*limit == 0); } Ok(false) @@ -900,10 +909,10 @@ pub(crate) fn materialize_values( ) -> 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)?; - if let Relational::Motion { + if let Relational::Motion(Motion { policy: MotionPolicy::LocalSegment(_), .. - } = motion_node + }) = motion_node { } else { return Ok(None); @@ -917,17 +926,16 @@ pub(crate) fn materialize_values( let child_id = plan.get_motion_child(motion_node_id)?; if !matches!( plan.get_ir_plan().get_relation_node(child_id)?, - Relational::Values { .. } + Relational::Values(_) ) { return Ok(None); } - let child_node_ref = plan.get_mut_ir_plan().get_mut_node(child_id)?; - let child_node = std::mem::replace(child_node_ref, Node::Parameter(None)); - if let Node::Relational(Relational::Values { + let child_node = plan.get_mut_ir_plan().replace_with_stub(child_id); + if let NodeOwned::Relational(RelOwned::Values(Values { ref children, output, .. - }) = child_node + })) = child_node { // Build a new virtual table (check that all the rows are made of constants only). let mut vtable = VirtualTable::new(); @@ -935,7 +943,7 @@ pub(crate) fn materialize_values( let columns_len = if let Some(first_row_id) = children.first() { let row_node = plan.get_ir_plan().get_relation_node(*first_row_id)?; - let Relational::ValuesRow { data, .. } = row_node else { + let Relational::ValuesRow(ValuesRow { data, .. }) = row_node else { return Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!("Expected ValuesRow, got {row_node:?}")), @@ -956,7 +964,7 @@ pub(crate) fn materialize_values( let mut nullable_column_indices = HashSet::with_capacity(columns_len); for row_id in children { let row_node = plan.get_ir_plan().get_relation_node(*row_id)?; - if let Relational::ValuesRow { data, children, .. } = row_node { + if let Relational::ValuesRow(ValuesRow { data, children, .. }) = row_node { // Check that there are no subqueries in the values node. // (If any we'll need to materialize them first with dispatch // to the storages.) @@ -982,9 +990,10 @@ pub(crate) fn materialize_values( format_smolstr!("at position {idx} in the row"), ) })?; - let column_node_ref = plan.get_mut_ir_plan().get_mut_node(column_id)?; - let column_node = std::mem::replace(column_node_ref, Node::Parameter(None)); - if let Node::Expression(Expression::Constant { value, .. }) = column_node { + let column_node = plan.get_mut_ir_plan().replace_with_stub(column_id); + if let NodeOwned::Expression(ExprOwned::Constant(Constant { value, .. })) = + column_node + { if let Value::Null = value { nullable_column_indices.insert(idx); } @@ -1009,16 +1018,13 @@ pub(crate) fn materialize_values( } } // Build virtual table's columns. - let output_cols = plan - .get_ir_plan() - .get_expression_node(output)? - .get_row_list()?; + let output_cols = plan.get_ir_plan().get_row_list(output)?; let columns = vtable.get_mut_columns(); columns.reserve(output_cols.len()); for (idx, column_id) in enumerate(output_cols) { let is_nullable = nullable_column_indices.contains(&idx); let alias = plan.get_ir_plan().get_expression_node(*column_id)?; - if let Expression::Alias { name, .. } = alias { + if let Expression::Alias(Alias { name, .. }) = alias { let column = Column { name: name.clone(), r#type: Type::Scalar, @@ -1530,9 +1536,9 @@ where let top_id = plan.get_top()?; let top = plan.get_relation_node(top_id)?; match top { - Relational::Insert { .. } => execute_insert_on_storage(runtime, &mut optional, required), - Relational::Delete { .. } => execute_delete_on_storage(runtime, &mut optional, required), - Relational::Update { .. } => execute_update_on_storage(runtime, &mut optional, required), + Relational::Insert(_) => execute_insert_on_storage(runtime, &mut optional, required), + Relational::Delete(_) => execute_delete_on_storage(runtime, &mut optional, required), + Relational::Update(_) => execute_update_on_storage(runtime, &mut optional, required), _ => Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( @@ -2216,7 +2222,7 @@ pub fn try_get_metadata_from_plan( for col_id in columns { let column = ir.get_expression_node(*col_id)?; let column_type = column.calculate_type(ir)?.to_string(); - let column_name = if let Expression::Alias { name, .. } = column { + let column_name = if let Expression::Alias(Alias { name, .. }) = column { name.to_string() } else { return Err(SbroadError::Invalid( diff --git a/sbroad-core/src/executor/engine/helpers/storage.rs b/sbroad-core/src/executor/engine/helpers/storage.rs index c1756ffb9..14d741029 100644 --- a/sbroad-core/src/executor/engine/helpers/storage.rs +++ b/sbroad-core/src/executor/engine/helpers/storage.rs @@ -16,8 +16,8 @@ use crate::errors::SbroadError; 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::node::NodeId; use crate::ir::value::{EncodedValue, Value}; -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 87302d9d5..d9d08730e 100644 --- a/sbroad-core/src/executor/engine/helpers/vshard.rs +++ b/sbroad-core/src/executor/engine/helpers/vshard.rs @@ -18,19 +18,21 @@ use crate::{ protocol::{FullMessage, RequiredMessage}, result::ProducerResult, }, - ir::{ - expression::NodeId, + ir::node::{ + relational::{MutRelational, Relational}, + Motion, Node, NodeId, + }, + otm::child_span, +}; +use crate::ir::{ helpers::RepeatableState, - operator::Relational, transformation::redistribution::{MotionOpcode, MotionPolicy}, tree::{ relation::RelationalIterator, traversal::{LevelNode, PostOrderWithFilter, REL_CAPACITY}, }, - Node, Plan, - }, - otm::child_span, -}; + Plan, + }; use ahash::AHashMap; use rand::{thread_rng, Rng}; use sbroad_proc::otm_child_span; @@ -750,7 +752,9 @@ 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: NodeId, check_enabled: bool) -> bool { - if let Ok(Node::Relational(Relational::Motion { program, .. })) = self.get_node(node_id) { + if let Ok(Node::Relational(Relational::Motion(Motion { program, .. }))) = + self.get_node(node_id) + { if let Some(op) = program .0 .iter() @@ -787,7 +791,7 @@ impl Plan { let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), - Ok(Node::Relational(Relational::Motion { .. })) + Ok(Node::Relational(Relational::Motion(_))) ) }; let mut dfs = @@ -809,7 +813,7 @@ impl Plan { let is_motion = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), - Ok(Node::Relational(Relational::Motion { .. })) + Ok(Node::Relational(Relational::Motion(_))) ) }; let mut all_motions = Vec::new(); @@ -913,9 +917,9 @@ fn disable_serialize_as_empty_opcode( info: &SerializeAsEmptyInfo, ) -> Result<(), SbroadError> { for motion_id in &info.target_motion_ids { - let program = if let Relational::Motion { + let program = if let MutRelational::Motion(Motion { policy, program, .. - } = sub_plan + }) = sub_plan .get_mut_ir_plan() .get_mut_relation_node(*motion_id)? { diff --git a/sbroad-core/src/executor/engine/mock.rs b/sbroad-core/src/executor/engine/mock.rs index 900d90740..6fcf8cfba 100644 --- a/sbroad-core/src/executor/engine/mock.rs +++ b/sbroad-core/src/executor/engine/mock.rs @@ -30,8 +30,8 @@ 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::node::NodeId; use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type}; use crate::ir::tree::Snapshot; use crate::ir::value::{LuaValue, Value}; diff --git a/sbroad-core/src/executor/ir.rs b/sbroad-core/src/executor/ir.rs index 5a4fb3743..d8f23c5e4 100644 --- a/sbroad-core/src/executor/ir.rs +++ b/sbroad-core/src/executor/ir.rs @@ -8,12 +8,19 @@ 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, NodeId}; -use crate::ir::operator::{OrderByElement, OrderByEntity, Relational}; +use crate::ir::node::expression::ExprOwned; +use crate::ir::node::relational::{MutRelational, RelOwned, Relational}; +use crate::ir::node::{ + Alias, ArenaType, ArithmeticExpr, BoolExpr, Case, Cast, Concat, Delete, ExprInParentheses, + GroupBy, Having, Insert, Join, Motion, Node, Node136, NodeId, NodeOwned, OrderBy, Reference, + Row, ScanCte, ScanRelation, ScanSubQuery, Selection, StableFunction, Trim, UnaryExpr, Update, + ValuesRow, +}; +use crate::ir::operator::{OrderByElement, OrderByEntity}; use crate::ir::relation::SpaceEngine; use crate::ir::transformation::redistribution::{MotionOpcode, MotionPolicy}; use crate::ir::tree::traversal::{LevelNode, PostOrder}; -use crate::ir::{ArenaType, ExecuteOptions, Node, Plan}; +use crate::ir::{ExecuteOptions, Plan}; use crate::otm::child_span; use sbroad_proc::otm_child_span; @@ -156,7 +163,7 @@ impl ExecutionPlan { runtime: &impl Vshard, ) -> Result<(), SbroadError> { let mut vtable = vtable; - let program_len = if let Relational::Motion { program, .. } = + let program_len = if let Relational::Motion(Motion { program, .. }) = self.get_ir_plan().get_relation_node(*motion_id)? { program.0.len() @@ -253,8 +260,8 @@ impl ExecutionPlan { /// nodes that are not referenced by actual plan tree. #[must_use] pub fn has_customization_opcodes(&self) -> bool { - for node in &self.get_ir_plan().nodes { - if let Node::Relational(Relational::Motion { program, .. }) = node { + for node in self.get_ir_plan().nodes.iter136() { + if let Node136::Motion(Motion { program, .. }) = node { if program .0 .iter() @@ -273,7 +280,7 @@ impl ExecutionPlan { /// - node is not `Relation` type /// - node is not `Motion` type pub fn get_motion_policy(&self, node_id: NodeId) -> Result<MotionPolicy, SbroadError> { - if let Relational::Motion { policy, .. } = &self.plan.get_relation_node(node_id)? { + if let Relational::Motion(Motion { policy, .. }) = &self.plan.get_relation_node(node_id)? { return Ok(policy.clone()); } @@ -291,8 +298,8 @@ impl ExecutionPlan { let child_id = &self.get_motion_child(node_id)?; let child_rel = self.get_ir_plan().get_relation_node(*child_id)?; match child_rel { - Relational::ScanSubQuery { alias, .. } => Ok(alias.clone()), - Relational::ScanCte { alias, .. } => Ok(Some(alias.clone())), + Relational::ScanSubQuery(ScanSubQuery { alias, .. }) => Ok(alias.clone()), + Relational::ScanCte(ScanCte { alias, .. }) => Ok(Some(alias.clone())), _ => Ok(None), } } @@ -368,9 +375,9 @@ impl ExecutionPlan { /// - not a motion node 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 { + if let MutRelational::Motion(Motion { ref mut children, .. - } = motion + }) = motion { *children = vec![]; } else { @@ -408,7 +415,7 @@ impl ExecutionPlan { .filter(|id| { matches!( plan.get_node(*id), - Ok(Node::Relational(Relational::ScanCte { .. })) + Ok(Node::Relational(Relational::ScanCte(_))) ) }) .collect::<Vec<_>>(); @@ -420,15 +427,13 @@ impl ExecutionPlan { let mut cte_amount = 0; for cte_id in &cte_scans { let cte_node = plan.get_relation_node(*cte_id)?; - let Relational::ScanCte { child, .. } = cte_node else { + let Relational::ScanCte(ScanCte { child, .. }) = cte_node else { unreachable!("Expected CTE scan node."); }; let child_id = *child; - let offset = usize::try_from(child_id.offset).unwrap(); - if all_cte_nodes_capacity < offset { - all_cte_nodes_capacity = offset; + if all_cte_nodes_capacity < child_id.offset as usize { + all_cte_nodes_capacity = child_id.offset as usize; } - cte_amount += 1; } all_cte_nodes_capacity += 1; @@ -461,7 +466,6 @@ impl ExecutionPlan { HashMap::with_capacity(vtables_capacity); let mut new_plan = Plan::new(); - new_plan.nodes.reserve(nodes.len()); for LevelNode(_, node_id) in nodes { // We have already processed this node (sub-queries in BETWEEN // and CTEs can be referred twice). @@ -469,33 +473,33 @@ impl ExecutionPlan { continue; } - // 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(ArenaType::Default); + let mut_plan = self.get_mut_ir_plan(); // Replace the node with some invalid value. - // TODO: introduce some new enum variant for this purpose. - let mut node: Node = if cte_ids.contains(&node_id) { - dst_node.clone() + let mut node: NodeOwned = if cte_ids.contains(&node_id) { + mut_plan.get_mut_node(node_id)?.get_common_node() } else { - std::mem::replace(dst_node, Node::Parameter(None)) + mut_plan.replace_with_stub(node_id) }; + + let mut relational_output_id: Option<NodeId> = None; let ir_plan = self.get_ir_plan(); match node { - Node::Relational(ref mut rel) => { + NodeOwned::Relational(ref mut rel) => { match rel { - Relational::Selection { + RelOwned::Selection(Selection { filter: ref mut expr_id, .. - } - | Relational::Having { + }) + | RelOwned::Having(Having { filter: ref mut expr_id, .. - } - | Relational::Join { + }) + | RelOwned::Join(Join { condition: ref mut expr_id, .. - } => { + }) => { + let next_id = new_plan.nodes.next_id(ArenaType::Arena64); // We transform selection's, having's filter and join's condition to DNF for a better bucket calculation. // But as a result we can produce an extremely verbose SQL query from such a plan (tarantool's // parser can fail to parse such SQL). @@ -506,10 +510,10 @@ impl ExecutionPlan { *expr_id = subtree_map.get_id(*undo_expr_id); new_plan.replace_parent_in_subtree(*expr_id, None, Some(next_id))?; } - Relational::ScanRelation { relation, .. } - | Relational::Insert { relation, .. } - | Relational::Delete { relation, .. } - | Relational::Update { relation, .. } => { + RelOwned::ScanRelation(ScanRelation { relation, .. }) + | RelOwned::Insert(Insert { relation, .. }) + | RelOwned::Delete(Delete { relation, .. }) + | RelOwned::Update(Update { relation, .. }) => { let table = ir_plan .relations .get(relation) @@ -521,12 +525,13 @@ impl ExecutionPlan { .clone(); new_plan.add_rel(table); } - Relational::Motion { + RelOwned::Motion(Motion { children, policy, .. - } => { + }) => { if let Some(vtable) = self.get_vtables().map_or_else(|| None, |v| v.get(&node_id)) { + let next_id = new_plan.nodes.next_id(ArenaType::Arena136); new_vtables.insert(next_id, Rc::clone(vtable)); } // We should not remove the child of a local motion node. @@ -535,7 +540,8 @@ impl ExecutionPlan { *children = Vec::new(); } } - Relational::GroupBy { gr_cols, .. } => { + RelOwned::GroupBy(GroupBy { gr_cols, .. }) => { + let next_id = new_plan.nodes.next_id(ArenaType::Arena64); 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); @@ -548,9 +554,10 @@ impl ExecutionPlan { } *gr_cols = new_cols; } - Relational::OrderBy { + RelOwned::OrderBy(OrderBy { order_by_elements, .. - } => { + }) => { + let next_id = new_plan.nodes.next_id(ArenaType::Arena64); let mut new_elements: Vec<OrderByElement> = Vec::with_capacity(order_by_elements.len()); for element in order_by_elements.iter() { @@ -577,84 +584,84 @@ impl ExecutionPlan { } *order_by_elements = new_elements; } - Relational::ValuesRow { data, .. } => { + RelOwned::ValuesRow(ValuesRow { data, .. }) => { *data = subtree_map.get_id(*data); } - Relational::Except { .. } - | Relational::Intersect { .. } - | Relational::Projection { .. } - | Relational::ScanSubQuery { .. } - | Relational::ScanCte { .. } - | Relational::Union { .. } - | Relational::UnionAll { .. } - | Relational::Values { .. } - | Relational::Limit { .. } => {} + RelOwned::Except { .. } + | RelOwned::Intersect { .. } + | RelOwned::Projection { .. } + | RelOwned::ScanSubQuery { .. } + | RelOwned::ScanCte { .. } + | RelOwned::Union { .. } + | RelOwned::UnionAll { .. } + | RelOwned::Values { .. } + | RelOwned::Limit { .. } => {} } for child_id in rel.mut_children() { *child_id = subtree_map.get_id(*child_id); } - let output = rel.output(); - *rel.mut_output() = subtree_map.get_id(output); - new_plan.replace_parent_in_subtree(rel.output(), None, Some(next_id))?; + let output = rel.mut_output(); + *rel.mut_output() = subtree_map.get_id(*output); + relational_output_id = Some(*rel.mut_output()); } - Node::Expression(ref mut expr) => match expr { - Expression::Alias { ref mut child, .. } - | Expression::ExprInParentheses { ref mut child } - | Expression::Cast { ref mut child, .. } - | Expression::Unary { ref mut child, .. } => { + NodeOwned::Expression(ref mut expr) => match expr { + ExprOwned::Alias(Alias { ref mut child, .. }) + | ExprOwned::ExprInParentheses(ExprInParentheses { ref mut child }) + | ExprOwned::Cast(Cast { ref mut child, .. }) + | ExprOwned::Unary(UnaryExpr { ref mut child, .. }) => { *child = subtree_map.get_id(*child); } - Expression::Bool { + ExprOwned::Bool(BoolExpr { ref mut left, ref mut right, .. - } - | Expression::Arithmetic { + }) + | ExprOwned::Arithmetic(ArithmeticExpr { ref mut left, ref mut right, .. - } - | Expression::Concat { + }) + | ExprOwned::Concat(Concat { ref mut left, ref mut right, .. - } => { + }) => { *left = subtree_map.get_id(*left); *right = subtree_map.get_id(*right); } - Expression::Trim { + ExprOwned::Trim(Trim { ref mut pattern, ref mut target, .. - } => { + }) => { if let Some(pattern) = pattern { *pattern = subtree_map.get_id(*pattern); } *target = subtree_map.get_id(*target); } - Expression::Reference { ref mut parent, .. } => { + ExprOwned::Reference(Reference { ref mut parent, .. }) => { // The new parent node id MUST be set while processing the relational nodes. *parent = None; } - Expression::Row { + ExprOwned::Row(Row { list: ref mut children, .. - } - | Expression::StableFunction { + }) + | ExprOwned::StableFunction(StableFunction { ref mut children, .. - } => { + }) => { for child in children { *child = subtree_map.get_id(*child); } } - Expression::Constant { .. } | Expression::CountAsterisk => {} - Expression::Case { + ExprOwned::Constant { .. } | ExprOwned::CountAsterisk { .. } => {} + ExprOwned::Case(Case { search_expr, when_blocks, else_expr, - } => { + }) => { if let Some(search_expr) = search_expr { *search_expr = subtree_map.get_id(*search_expr); } @@ -667,15 +674,23 @@ impl ExecutionPlan { } } }, - Node::Parameter { .. } => {} - Node::Ddl { .. } | Node::Acl { .. } | Node::Block { .. } => { + NodeOwned::Parameter { .. } => {} + NodeOwned::Invalid { .. } + | NodeOwned::Ddl { .. } + | NodeOwned::Acl { .. } + | NodeOwned::Block { .. } => { panic!("Unexpected node in `take_subtree`: {node:?}") } } - new_plan.nodes.push(node); - subtree_map.insert(node_id, next_id); + + let id = new_plan.nodes.push(node.into()); + if let Some(output_id) = relational_output_id { + new_plan.replace_parent_in_subtree(output_id, None, Some(id))?; + } + + subtree_map.insert(node_id, id); if top_id == node_id { - new_plan.set_top(next_id)?; + new_plan.set_top(id)?; } } @@ -694,7 +709,6 @@ impl ExecutionPlan { }; Ok(new_exec_plan) } - /// # Errors /// - execution plan is invalid pub fn query_type(&self) -> Result<QueryType, SbroadError> { diff --git a/sbroad-core/src/executor/protocol.rs b/sbroad-core/src/executor/protocol.rs index 3905635d1..2e41f1c5a 100644 --- a/sbroad-core/src/executor/protocol.rs +++ b/sbroad-core/src/executor/protocol.rs @@ -15,7 +15,7 @@ use crate::ir::Options; use crate::otm::{current_id, extract_context, inject_context}; use crate::executor::engine::TableVersionMap; -use crate::ir::expression::NodeId; +use crate::ir::node::NodeId; #[cfg(not(feature = "mock"))] use opentelemetry::trace::TraceContextExt; diff --git a/sbroad-core/src/executor/result.rs b/sbroad-core/src/executor/result.rs index 49a8bffa2..d2cfa4a74 100644 --- a/sbroad-core/src/executor/result.rs +++ b/sbroad-core/src/executor/result.rs @@ -20,12 +20,12 @@ 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::node::relational::Relational; +use crate::ir::node::{Node, NodeId}; use crate::ir::relation::{Column, ColumnRole, Type}; use crate::ir::tree::traversal::{PostOrderWithFilter, REL_CAPACITY}; use crate::ir::value::{LuaValue, Value}; -use crate::ir::{Node, Plan}; +use crate::ir::Plan; pub type ExecutorTuple = Vec<LuaValue>; @@ -260,7 +260,7 @@ impl Plan { /// - If relational iterator fails to return a correct node. 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) { + if let Ok(Node::Relational(Relational::Values(_))) = self.get_node(node_id) { return true; } false diff --git a/sbroad-core/src/executor/tests.rs b/sbroad-core/src/executor/tests.rs index 71f536340..c0a27f82c 100644 --- a/sbroad-core/src/executor/tests.rs +++ b/sbroad-core/src/executor/tests.rs @@ -1,11 +1,10 @@ use pretty_assertions::assert_eq; -use crate::{backend::sql::ir::PatternWithParams, ir::expression::NodeId}; +use crate::backend::sql::ir::PatternWithParams; use crate::executor::engine::mock::RouterRuntimeMock; use crate::executor::result::ProducerResult; use crate::executor::vtable::VirtualTable; -use crate::ir::operator::Relational; use crate::ir::tests::column_integer_user_non_null; use crate::ir::transformation::redistribution::MotionPolicy; use smol_str::SmolStr; @@ -178,7 +177,7 @@ fn linker_test() { "{} {} {}", r#"SELECT "test_space"."FIRST_NAME""#, r#"FROM "test_space""#, - r#"WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_76")"#, + r#"WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_0136")"#, ), vec![], ) ) @@ -193,7 +192,7 @@ fn linker_test() { "{} {} {}", r#"SELECT "test_space"."FIRST_NAME""#, r#"FROM "test_space""#, - r#"WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_76")"#, + r#"WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_0136")"#, ), vec![], ) ) @@ -268,7 +267,7 @@ fn union_linker_test() { r#"FROM "test_space_hist""#, r#"WHERE ("test_space_hist"."sys_op") > (?)"#, r#") as "t1""#, - r#"WHERE ("t1"."id") in (SELECT "identification_number" FROM "TMP_test_219")"#, + r#"WHERE ("t1"."id") in (SELECT "identification_number" FROM "TMP_test_0136")"#, ), vec![Value::from(0_u64), Value::from(0_u64)], ))), @@ -288,7 +287,7 @@ fn union_linker_test() { r#"FROM "test_space_hist""#, r#"WHERE ("test_space_hist"."sys_op") > (?)"#, r#") as "t1""#, - r#"WHERE ("t1"."id") in (SELECT "identification_number" FROM "TMP_test_219")"#, + r#"WHERE ("t1"."id") in (SELECT "identification_number" FROM "TMP_test_0136")"#, ), vec![Value::from(0_u64), Value::from(0_u64)], ))), @@ -370,7 +369,7 @@ WHERE "t3"."id" = 2 AND "t8"."identification_number" = 2"#; r#"WHERE ("test_space_hist"."sysFrom") <= (?)"#, r#") as "t3""#, r#"INNER JOIN"#, - r#"(SELECT "identification_number" FROM "TMP_test_275""#, + r#"(SELECT "identification_number" FROM "TMP_test_0136""#, r#") as "t8""#, r#"ON ("t3"."id") = ("t8"."identification_number")"#, r#"WHERE ("t3"."id") = (?) and ("t8"."identification_number") = (?)"# @@ -441,7 +440,7 @@ fn join_linker2_test() { r#""t1"."id", "t1"."sysFrom", "t1"."FIRST_NAME", "t1"."sys_op""#, r#"FROM "test_space" as "t1") as "t1""#, r#"INNER JOIN"#, - r#"(SELECT "id1","id2" FROM "TMP_test_87")"#, + r#"(SELECT "id1","id2" FROM "TMP_test_0136")"#, r#"as "t2" ON ("t1"."id") = (?)"# ), vec![Value::from(1_u64)], @@ -504,7 +503,7 @@ fn join_linker3_test() { r#"SELECT "t2"."id1" FROM"#, r#"(SELECT "test_space"."id" FROM "test_space") as "t1""#, r#"INNER JOIN"#, - r#"(SELECT "id1","FIRST_NAME" FROM "TMP_test_69") as "t2""#, + r#"(SELECT "id1","FIRST_NAME" FROM "TMP_test_0136") as "t2""#, r#"ON ("t2"."id1") = (?)"#, ), vec![Value::from(1_u64)], @@ -592,9 +591,9 @@ fn join_linker4_test() { r#""T1"."id", "T1"."sysFrom", "T1"."FIRST_NAME", "T1"."sys_op""#, r#"FROM "test_space" as "T1") as "T1""#, r#"INNER JOIN"#, - r#"(SELECT "r_id" FROM "TMP_test_148") as "T2""#, + r#"(SELECT "r_id" FROM "TMP_test_0136") as "T2""#, r#"ON ("T1"."id") = ("T2"."r_id")"#, - r#"and ("T1"."FIRST_NAME") = (SELECT "fn" FROM "TMP_test_152")"#, + r#"and ("T1"."FIRST_NAME") = (SELECT "fn" FROM "TMP_test_1136")"#, ), vec![], ))), @@ -608,9 +607,9 @@ fn join_linker4_test() { r#""T1"."id", "T1"."sysFrom", "T1"."FIRST_NAME", "T1"."sys_op""#, r#"FROM "test_space" as "T1") as "T1""#, r#"INNER JOIN"#, - r#"(SELECT "r_id" FROM "TMP_test_148") as "T2""#, + r#"(SELECT "r_id" FROM "TMP_test_0136") as "T2""#, r#"ON ("T1"."id") = ("T2"."r_id")"#, - r#"and ("T1"."FIRST_NAME") = (SELECT "fn" FROM "TMP_test_152")"#, + r#"and ("T1"."FIRST_NAME") = (SELECT "fn" FROM "TMP_test_1136")"#, ), vec![], ))), @@ -686,7 +685,7 @@ on q."f" = "t1"."a""#; "{} {} {} {}", r#"SELECT "t1"."a", "t1"."b", "q"."f", "q"."b" FROM"#, r#"(SELECT "t1"."a", "t1"."b" FROM "t1") as "t1""#, - r#"INNER JOIN (SELECT "f","B" FROM "TMP_test_146")"#, + r#"INNER JOIN (SELECT "f","B" FROM "TMP_test_1136")"#, r#"as "q" ON ("q"."f") = ("t1"."a")"#, ), vec![], @@ -728,7 +727,7 @@ fn dispatch_order_by() { expected.rows.extend(vec![vec![ LuaValue::String("Execute query locally".to_string()), LuaValue::String(String::from(PatternWithParams::new( - r#"SELECT "id" FROM (SELECT "id" FROM "TMP_test_40") ORDER BY "id""#.to_string(), + r#"SELECT "id" FROM (SELECT "id" FROM "TMP_test_0136") ORDER BY "id""#.to_string(), vec![], ))), ]]); @@ -802,9 +801,9 @@ fn anonymous_col_index_test() { r#""test_space"."sys_op""#, r#"FROM "test_space""#, r#"WHERE ("test_space"."id") in"#, - r#"(SELECT "identification_number" FROM "TMP_test_130")"#, + r#"(SELECT "identification_number" FROM "TMP_test_1136")"#, r#"or ("test_space"."id") in"#, - r#"(SELECT "identification_number" FROM "TMP_test_134")"#, + r#"(SELECT "identification_number" FROM "TMP_test_0136")"#, ), vec![], ))), @@ -821,15 +820,14 @@ fn anonymous_col_index_test() { r#""test_space"."sys_op""#, r#"FROM "test_space""#, r#"WHERE ("test_space"."id") in"#, - r#"(SELECT "identification_number" FROM "TMP_test_130")"#, + r#"(SELECT "identification_number" FROM "TMP_test_1136")"#, r#"or ("test_space"."id") in"#, - r#"(SELECT "identification_number" FROM "TMP_test_134")"#, + r#"(SELECT "identification_number" FROM "TMP_test_0136")"#, ), vec![], ))), ], ]); - assert_eq!(expected, result); } @@ -916,7 +914,7 @@ fn virtual_table_23(alias: Option<&str>) -> VirtualTable { 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 { + if let Relational::Motion(Motion { policy, .. }) = motion { policy } else { panic!("Expected a motion node"); @@ -997,9 +995,9 @@ fn groupby_linker_test() { LuaValue::String(String::from(PatternWithParams::new( format!( "{} {} {}", - r#"SELECT "column_12" as "ii" FROM"#, - r#"(SELECT "id" FROM "TMP_test_45")"#, - r#"GROUP BY "column_12""#, + r#"SELECT "column_764" as "ii" FROM"#, + r#"(SELECT "id" FROM "TMP_test_0136")"#, + r#"GROUP BY "column_764""#, ), vec![], ))), diff --git a/sbroad-core/src/executor/tests/between.rs b/sbroad-core/src/executor/tests/between.rs index 2678106ee..8de0a3f0d 100644 --- a/sbroad-core/src/executor/tests/between.rs +++ b/sbroad-core/src/executor/tests/between.rs @@ -55,7 +55,7 @@ fn between1_test() { "{} {} {}", r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#, r#"WHERE ("t"."identification_number") >= (?)"#, - r#"and ("t"."identification_number") <= (SELECT "id" FROM "TMP_test_102")"#, + r#"and ("t"."identification_number") <= (SELECT "id" FROM "TMP_test_0136")"#, ), vec![Value::from(1_u64)], ))), @@ -108,8 +108,8 @@ fn between2_test() { format!( "{} {} {}", r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#, - r#"WHERE (SELECT "id" FROM "TMP_test_104") >= (?)"#, - r#"and (SELECT "id" FROM "TMP_test_104") <= (?)"#, + r#"WHERE (SELECT "id" FROM "TMP_test_0136") >= (?)"#, + r#"and (SELECT "id" FROM "TMP_test_0136") <= (?)"#, ), vec![Value::from(1_u64), Value::from(3_u64)], ))), diff --git a/sbroad-core/src/executor/tests/empty_motion.rs b/sbroad-core/src/executor/tests/empty_motion.rs index 3b4e531a3..8016c3379 100644 --- a/sbroad-core/src/executor/tests/empty_motion.rs +++ b/sbroad-core/src/executor/tests/empty_motion.rs @@ -69,14 +69,14 @@ fn empty_motion1_test() { r#"(SELECT "t"."a", "t"."b" FROM"#, r#"(SELECT "t"."a", "t"."b", "t"."c", "t"."d" FROM "t") as "t""#, r#"INNER JOIN"#, - r#"(SELECT "g","h" FROM "TMP_test_334") as "t2""#, + r#"(SELECT "g","h" FROM "TMP_test_0136") as "t2""#, r#"ON ("t"."a") = ("t2"."g") and ("t"."b") = ("t2"."h")"#, r#"WHERE ("t"."a") = (?)"#, r#"EXCEPT"#, r#"SELECT "t"."a", "t"."b" FROM"#, r#"(SELECT "t"."a", "t"."b", "t"."c", "t"."d" FROM "t") as "t""#, r#"INNER JOIN"#, - r#"(SELECT "g","h" FROM "TMP_test_344") as "t2""#, + r#"(SELECT "g","h" FROM "TMP_test_1136") as "t2""#, r#"ON ("t"."a") = ("t2"."g") and ("t"."b") = ("t2"."h")"#, r#"WHERE ("t"."a") = (?)) as "Q""#, ), diff --git a/sbroad-core/src/executor/tests/exec_plan.rs b/sbroad-core/src/executor/tests/exec_plan.rs index 6234727e1..3992cee46 100644 --- a/sbroad-core/src/executor/tests/exec_plan.rs +++ b/sbroad-core/src/executor/tests/exec_plan.rs @@ -1,19 +1,19 @@ use std::rc::Rc; +use engine::mock::TEMPLATE; use itertools::Itertools; use pretty_assertions::assert_eq; use smol_str::SmolStr; use crate::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan}; use crate::collection; -use crate::executor::engine::mock::{ - ReplicasetDispatchInfo, RouterRuntimeMock, VshardMock, TEMPLATE, -}; +use crate::executor::engine::mock::{ReplicasetDispatchInfo, RouterRuntimeMock, VshardMock}; +use crate::ir::node::{ArenaType, Node136}; 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::{ArenaType, Node, Slice}; +use crate::ir::Slice; use super::*; @@ -85,7 +85,7 @@ fn exec_plan_subtree_test() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "test_space"."FIRST_NAME" FROM "test_space" WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_20")"#.to_string(), + r#"SELECT "test_space"."FIRST_NAME" FROM "test_space" WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_0136")"#.to_string(), vec![] )); } @@ -133,7 +133,7 @@ fn exec_plan_subtree_two_stage_groupby_test() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "T1"."FIRST_NAME" as "column_12" FROM "test_space" as "T1" GROUP BY "T1"."FIRST_NAME""# + r#"SELECT "T1"."FIRST_NAME" as "column_764" FROM "test_space" as "T1" GROUP BY "T1"."FIRST_NAME""# .to_string(), vec![] ) @@ -144,7 +144,7 @@ fn exec_plan_subtree_two_stage_groupby_test() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "column_12" as "FIRST_NAME" FROM (SELECT "FIRST_NAME" FROM "TMP_test_6") GROUP BY "column_12""#.to_string(), + r#"SELECT "column_764" as "FIRST_NAME" FROM (SELECT "FIRST_NAME" FROM "TMP_test_0136") GROUP BY "column_764""#.to_string(), vec![] )); } @@ -165,15 +165,15 @@ fn exec_plan_subtree_two_stage_groupby_test_2() { .unwrap(); let mut virtual_table = VirtualTable::new(); virtual_table.add_column(column_user_non_null( - SmolStr::from("column_12"), + SmolStr::from("column_764"), Type::String, )); virtual_table.add_column(column_user_non_null( - SmolStr::from("column_13"), + SmolStr::from("column_864"), Type::Integer, )); virtual_table.add_column(column_user_non_null( - SmolStr::from("column_14"), + SmolStr::from("column_964"), Type::Integer, )); if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id) @@ -200,8 +200,8 @@ fn exec_plan_subtree_two_stage_groupby_test_2() { PatternWithParams::new( 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#"SELECT "T1"."sysFrom" as "column_964", "T1"."FIRST_NAME" as "column_764","#, + r#""T1"."sys_op" as "column_864" FROM "test_space" as "T1""#, r#"GROUP BY "T1"."FIRST_NAME", "T1"."sys_op", "T1"."sysFrom""#, ), vec![] @@ -213,11 +213,12 @@ fn exec_plan_subtree_two_stage_groupby_test_2() { assert_eq!( sql, PatternWithParams::new( - f_sql( - r#"SELECT "column_12" as "FIRST_NAME", -"column_13" as "sys_op", "column_14" as "sysFrom" -FROM (SELECT "column_12","column_13","column_14" FROM "TMP_test_14") -GROUP BY "column_12", "column_13", "column_14""# + format!( + "{} {} {} {}", + r#"SELECT "column_764" as "FIRST_NAME", "column_864" as "sys_op","#, + r#""column_964" as "sysFrom" FROM"#, + r#"(SELECT "column_764","column_864","column_964" FROM "TMP_test_0136")"#, + r#"GROUP BY "column_764", "column_864", "column_964""#, ), vec![] ) @@ -278,12 +279,13 @@ fn exec_plan_subtree_aggregates() { sql, PatternWithParams::new( 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#"SELECT "T1"."sys_op" as "column_764", "T1"."id" as "column_2864","#, + r#"("T1"."id") * ("T1"."sys_op") as "column_1632", group_concat ("T1"."FIRST_NAME", ?) as "group_concat_496","#, + r#"count ("T1"."sysFrom") as "count_096", total ("T1"."id") as "total_696","#, + r#"min ("T1"."id") as "min_796", count ("T1"."id") as "count_596","#, + r#"max ("T1"."id") as "max_896", sum ("T1"."id") as "sum_196""#, + r#"FROM "test_space" as "T1""#, r#"GROUP BY "T1"."sys_op", ("T1"."id") * ("T1"."sys_op"), "T1"."id""#, ), vec![Value::from("o")] @@ -297,14 +299,14 @@ fn exec_plan_subtree_aggregates() { PatternWithParams::new( format!( "{} {} {} {} {} {} {} {}", - r#"SELECT ("column_12") || ("column_12") as "col_1","#, - r#"("column_12") * (?) + (sum ("count_37")) as "col_2", sum ("sum_42") as "col_3","#, - r#"(sum (DISTINCT "column_49")) / (count (DISTINCT "column_46")) as "col_4","#, - r#"group_concat ("group_concat_58", ?) as "col_5","#, - r#"sum (CAST ("sum_42" as double)) / sum (CAST ("count_61" as double)) as "col_6","#, - r#"total ("total_64") as "col_7", min ("min_67") as "col_8", max ("max_70") as "col_9""#, - r#"FROM (SELECT "sys_op","sum_42","count_37","sum_49","count_51","group_concat_58","count_61","total_64","min_67","max_70" FROM "TMP_test_70")"#, - r#"GROUP BY "column_12""# + r#"SELECT ("column_764") || ("column_764") as "col_1","#, + r#"("column_764") * (?) + (sum ("count_096")) as "col_2", sum ("sum_196") as "col_3","#, + r#"(sum (DISTINCT "column_1632")) / (count (DISTINCT "column_2864")) as "col_4","#, + r#"group_concat ("group_concat_496", ?) as "col_5","#, + r#"sum (CAST ("sum_196" as double)) / sum (CAST ("count_596" as double)) as "col_6","#, + r#"total ("total_696") as "col_7", min ("min_796") as "col_8", max ("max_896") as "col_9""#, + r#"FROM (SELECT "sys_op","sum_42","count_37","sum_49","count_51","group_concat_58","count_61","total_64","min_67","max_70" FROM "TMP_test_0136")"#, + r#"GROUP BY "column_764""# ), vec![Value::Unsigned(2), Value::from("o")] ) @@ -326,8 +328,8 @@ fn exec_plan_subtree_aggregates_no_groupby() { .position(0) .unwrap(); let mut virtual_table = VirtualTable::new(); - virtual_table.add_column(column_integer_user_non_null(SmolStr::from("column_19"))); - virtual_table.add_column(column_integer_user_non_null(SmolStr::from("count_13"))); + virtual_table.add_column(column_integer_user_non_null(SmolStr::from("column_932"))); + virtual_table.add_column(column_integer_user_non_null(SmolStr::from("count_096"))); if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id) { virtual_table.reshard(key, &query.coordinator).unwrap(); @@ -350,7 +352,7 @@ fn exec_plan_subtree_aggregates_no_groupby() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT ("T1"."id") + ("T1"."sysFrom") as "column_19", count ("T1"."sysFrom") as "count_13" FROM "test_space" as "T1" GROUP BY ("T1"."id") + ("T1"."sysFrom")"#.to_string(), + r#"SELECT ("T1"."id") + ("T1"."sysFrom") as "column_632", count ("T1"."sysFrom") as "count_096" FROM "test_space" as "T1" GROUP BY ("T1"."id") + ("T1"."sysFrom")"#.to_string(), vec![] )); @@ -359,7 +361,7 @@ fn exec_plan_subtree_aggregates_no_groupby() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT sum ("count_13") as "col_1", sum (DISTINCT "column_19") as "col_2" FROM (SELECT "column_19","count_13" FROM "TMP_test_12")"#.to_string(), + r#"SELECT sum ("count_096") as "col_1", sum (DISTINCT "column_632") as "col_2" FROM (SELECT "column_932","count_096" FROM "TMP_test_0136")"#.to_string(), vec![] )); } @@ -400,7 +402,7 @@ fn exec_plan_subquery_under_motion_without_alias() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "tid", "sid" FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "identification_number" FROM "TMP_test_28") ON ?"#.to_string(), + r#"SELECT "tid", "sid" FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "identification_number" FROM "TMP_test_0136") ON ?"#.to_string(), vec![Value::Boolean(true)] )); } @@ -441,7 +443,7 @@ fn exec_plan_subquery_under_motion_with_alias() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "tid", "hti"."sid" FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "identification_number" FROM "TMP_test_28") as "hti" ON ?"#.to_string(), + r#"SELECT "tid", "hti"."sid" FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "identification_number" FROM "TMP_test_0136") as "hti" ON ?"#.to_string(), vec![Value::Boolean(true)] )); } @@ -476,7 +478,7 @@ fn exec_plan_motion_under_in_operator() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "test_space"."id" FROM "test_space" WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_20")"#.to_string(), + r#"SELECT "test_space"."id" FROM "test_space" WHERE ("test_space"."id") in (SELECT "identification_number" FROM "TMP_test_0136")"#.to_string(), vec![] )); } @@ -515,7 +517,7 @@ fn exec_plan_motion_under_except() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "test_space"."id" FROM "test_space" EXCEPT SELECT "identification_number" FROM "TMP_test_19""#.to_string(), + r#"SELECT "test_space"."id" FROM "test_space" EXCEPT SELECT "identification_number" FROM "TMP_test_0136""#.to_string(), vec![] )); } @@ -535,7 +537,7 @@ fn exec_plan_subtree_count_asterisk() { .position(0) .unwrap(); let mut virtual_table = VirtualTable::new(); - virtual_table.add_column(column_integer_user_non_null(SmolStr::from("count_13"))); + virtual_table.add_column(column_integer_user_non_null(SmolStr::from("count_096"))); if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id) { virtual_table.reshard(key, &query.coordinator).unwrap(); @@ -559,7 +561,7 @@ fn exec_plan_subtree_count_asterisk() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT count (*) as "count_13" FROM "test_space""#.to_string(), + r#"SELECT count (*) as "count_096" FROM "test_space""#.to_string(), vec![] ) ); @@ -569,7 +571,7 @@ fn exec_plan_subtree_count_asterisk() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT sum ("count_13") as "col_1" FROM (SELECT "count_13" FROM "TMP_test_7")"# + r#"SELECT sum ("count_096") as "col_1" FROM (SELECT "count_096" FROM "TMP_test_0136")"# .to_string(), vec![] ) @@ -628,8 +630,8 @@ fn exec_plan_subtree_having() { PatternWithParams::new( format!( "{} {} {}", - 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#"SELECT "T1"."sys_op" as "column_764", ("T1"."sys_op") * (?) as "column_2032","#, + r#"count (("T1"."sys_op") * (?)) as "count_196" FROM "test_space" as "T1""#, r#"GROUP BY "T1"."sys_op", ("T1"."sys_op") * (?)"#, ), vec![Value::Unsigned(2), Value::Unsigned(2), Value::Unsigned(2)] @@ -648,10 +650,10 @@ fn exec_plan_subtree_having() { PatternWithParams::new( format!( "{} {} {} {}", - r#"SELECT ("column_12") || ("column_12") as "col_1","#, - r#"(sum ("count_60")) + (count (DISTINCT "column_64")) as "col_2" FROM"#, - r#"(SELECT "column_63","column_12","count_58" FROM "TMP_test_22")"#, - r#"GROUP BY "column_12" HAVING (sum (DISTINCT "column_64")) > (?)"# + r#"SELECT ("column_764") || ("column_764") as "col_1","#, + r#"(sum ("count_196")) + (count (DISTINCT "column_2032")) as "col_2" FROM"#, + r#"(SELECT "column_63","column_12","count_58" FROM "TMP_test_0136")"#, + r#"GROUP BY "column_764" HAVING (sum (DISTINCT "column_2032")) > (?)"# ), vec![Value::Unsigned(1u64)] ) @@ -711,8 +713,8 @@ fn exec_plan_subtree_having_without_groupby() { PatternWithParams::new( format!( "{} {} {}", - r#"SELECT ("T1"."sys_op") * (?) as "column_45","#, - r#"count (("T1"."sys_op") * (?)) as "count_41" FROM "test_space" as "T1""#, + r#"SELECT ("T1"."sys_op") * (?) as "column_1332","#, + r#"count (("T1"."sys_op") * (?)) as "count_196" FROM "test_space" as "T1""#, r#"GROUP BY ("T1"."sys_op") * (?)"#, ), vec![Value::Unsigned(2), Value::Unsigned(2), Value::Unsigned(2)] @@ -731,9 +733,9 @@ fn exec_plan_subtree_having_without_groupby() { PatternWithParams::new( format!( "{} {} {}", - r#"SELECT (sum ("count_41")) + (count (DISTINCT "column_45")) as "col_1""#, - r#"FROM (SELECT "column_63","column_12","count_58" FROM "TMP_test_14")"#, - r#"HAVING (sum (DISTINCT "column_45")) > (?)"#, + r#"SELECT (sum ("count_196")) + (count (DISTINCT "column_1332")) as "col_1""#, + r#"FROM (SELECT "column_63","column_12","count_58" FROM "TMP_test_0136")"#, + r#"HAVING (sum (DISTINCT "column_1332")) > (?)"#, ), vec![Value::Unsigned(1u64)] ) @@ -847,11 +849,11 @@ fn global_union_all2() { let (motion_id, _) = sub_plan .get_ir_plan() .nodes - .iter() + .iter136() .find_position(|n| { matches!( n, - Node::Relational(Relational::Motion { + Node136::Motion(Motion { policy: MotionPolicy::Full, .. }) @@ -862,7 +864,7 @@ fn global_union_all2() { let actual_dispatch = coordinator.detailed_dispatch(sub_plan, &buckets); let motion_id = NodeId { offset: motion_id as u32, - arena_type: ArenaType::Default, + arena_type: ArenaType::Arena136, }; let expected = vec![ @@ -880,7 +882,7 @@ fn global_union_all2() { }, ReplicasetDispatchInfo { rs_id: 2, - pattern: r#"SELECT "global_t"."a", "global_t"."b" FROM "global_t" WHERE ("global_t"."b") in (SELECT "e" FROM "TMP_test_16") UNION ALL SELECT "t2"."e", "t2"."f" FROM "t2""#.to_string(), + pattern: r#"SELECT "global_t"."a", "global_t"."b" FROM "global_t" WHERE ("global_t"."b") in (SELECT "e" FROM "TMP_test_0136") UNION ALL SELECT "t2"."e", "t2"."f" FROM "t2""#.to_string(), params: vec![], vtables_map: collection!(motion_id => Rc::new(virtual_table)), }, @@ -933,7 +935,7 @@ fn global_union_all3() { // these tuples must belong to different replicasets let tuple1 = vec![Value::Integer(3)]; let tuple2 = vec![Value::Integer(2929)]; - groupby_vtable.add_column(column_integer_user_non_null(SmolStr::from("column_51"))); + groupby_vtable.add_column(column_integer_user_non_null(SmolStr::from("column_3364"))); groupby_vtable.add_tuple(tuple1.clone()); groupby_vtable.add_tuple(tuple2.clone()); if let MotionPolicy::Segment(key) = @@ -967,11 +969,11 @@ fn global_union_all3() { let (groupby_motion_id, _) = sub_plan .get_ir_plan() .nodes - .iter() + .iter136() .find_position(|n| { matches!( n, - Node::Relational(Relational::Motion { + Node136::Motion(Motion { policy: MotionPolicy::Segment(_), .. }) @@ -981,11 +983,11 @@ fn global_union_all3() { let (sq_motion_id, _) = sub_plan .get_ir_plan() .nodes - .iter() + .iter136() .find_position(|n| { matches!( n, - Node::Relational(Relational::Motion { + Node136::Motion(Motion { policy: MotionPolicy::Full, .. }) @@ -997,24 +999,24 @@ fn global_union_all3() { let groupby_motion_id = NodeId { offset: groupby_motion_id as u32, - arena_type: ArenaType::Default, + arena_type: ArenaType::Arena136, }; let sq_motion_id = NodeId { offset: sq_motion_id as u32, - arena_type: ArenaType::Default, + arena_type: ArenaType::Arena136, }; let expected = vec![ ReplicasetDispatchInfo { rs_id: 0, - pattern: r#" select cast(null as integer) where false UNION ALL SELECT "column_51" as "f" FROM (SELECT "column_51" FROM "TMP_test_35") GROUP BY "column_51""#.to_string(), + pattern: r#" select cast(null as integer) where false UNION ALL SELECT "column_3364" as "f" FROM (SELECT "column_3364" FROM "TMP_test_2136") GROUP BY "column_3364""#.to_string(), params: vec![], vtables_map: collection!(groupby_motion_id => Rc::new(groupby_vtable1)), }, ReplicasetDispatchInfo { rs_id: 1, - pattern: r#"SELECT "global_t"."a" FROM "global_t" WHERE ("global_t"."b") in (SELECT "f" FROM "TMP_test_14") UNION ALL SELECT "column_51" as "f" FROM (SELECT "column_51" FROM "TMP_test_35") GROUP BY "column_51""#.to_string(), + pattern: r#"SELECT "global_t"."a" FROM "global_t" WHERE ("global_t"."b") in (SELECT "f" FROM "TMP_test_0136") UNION ALL SELECT "column_3364" as "f" FROM (SELECT "column_3364" FROM "TMP_test_2136") GROUP BY "column_3364""#.to_string(), params: vec![], vtables_map: collection!(sq_motion_id => Rc::new(sq_vtable), groupby_motion_id => Rc::new(groupby_vtable2)), }, @@ -1121,11 +1123,12 @@ fn global_except() { expected.rows.extend(vec![vec![ LuaValue::String(format!("Execute query locally")), LuaValue::String(String::from(PatternWithParams::new( - r#"SELECT "global_t"."a" FROM "global_t" EXCEPT SELECT "e" FROM "TMP_test_47""#.into(), + r#"SELECT "global_t"."a" FROM "global_t" EXCEPT SELECT "e" FROM "TMP_test_0136""# + .into(), vec![], ))), ]]); - assert_eq!(expected, res,) + assert_eq!(expected, res) } #[test] @@ -1172,7 +1175,7 @@ fn exec_plan_order_by() { assert_eq!( sql, PatternWithParams::new( - r#"SELECT "identification_number" FROM (SELECT "identification_number" FROM "TMP_test_6") ORDER BY "identification_number""#.to_string(), + r#"SELECT "identification_number" FROM (SELECT "identification_number" FROM "TMP_test_0136") ORDER BY "identification_number""#.to_string(), vec![] )); } diff --git a/sbroad-core/src/executor/tests/not_eq.rs b/sbroad-core/src/executor/tests/not_eq.rs index 66453735e..5d72e740d 100644 --- a/sbroad-core/src/executor/tests/not_eq.rs +++ b/sbroad-core/src/executor/tests/not_eq.rs @@ -93,7 +93,7 @@ fn not_eq2_test() { format!( "{} {}", r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#, - r#"WHERE ("t"."identification_number") <> (SELECT "id" FROM "TMP_test_79")"#, + r#"WHERE ("t"."identification_number") <> (SELECT "id" FROM "TMP_test_0136")"#, ), vec![], ))), diff --git a/sbroad-core/src/executor/tests/not_in.rs b/sbroad-core/src/executor/tests/not_in.rs index 4295df354..f89ddd10f 100644 --- a/sbroad-core/src/executor/tests/not_in.rs +++ b/sbroad-core/src/executor/tests/not_in.rs @@ -55,7 +55,7 @@ fn not_in1_test() { format!( "{} {}", r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#, - r#"WHERE not ("t"."identification_number") in (SELECT "id" FROM "TMP_test_77")"#, + r#"WHERE not ("t"."identification_number") in (SELECT "id" FROM "TMP_test_0136")"#, ), vec![], ))), diff --git a/sbroad-core/src/executor/vtable.rs b/sbroad-core/src/executor/vtable.rs index 6a83ebe87..69d2d8151 100644 --- a/sbroad-core/src/executor/vtable.rs +++ b/sbroad-core/src/executor/vtable.rs @@ -13,8 +13,8 @@ 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::node::NodeId; use crate::ir::relation::Column; use crate::ir::transformation::redistribution::{ColumnPosition, MotionKey, Target}; use crate::ir::value::{EncodedValue, LuaValue, MsgPackValue, Value}; @@ -231,10 +231,10 @@ impl VirtualTable { /// - bucket index is corrupted pub fn new_with_buckets(&self, bucket_ids: &[u64]) -> Result<Self, SbroadError> { let mut result = Self::new(); - result.columns = self.columns.clone(); - result.name = self.name.clone(); + result.columns.clone_from(&self.columns); + result.name.clone_from(&self.name); - result.primary_key = self.primary_key.clone(); + result.primary_key.clone_from(&self.primary_key); for bucket_id in bucket_ids { // If bucket_id is met among those that are present in self. if let Some(pointers) = self.get_bucket_index().get(bucket_id) { diff --git a/sbroad-core/src/frontend/sql.rs b/sbroad-core/src/frontend/sql.rs index 337ac62aa..8bcbb6b74 100644 --- a/sbroad-core/src/frontend/sql.rs +++ b/sbroad-core/src/frontend/sql.rs @@ -26,29 +26,35 @@ use crate::frontend::sql::ast::{ }; use crate::frontend::sql::ir::Translation; use crate::frontend::Ast; -use crate::ir::ddl::{AlterSystemType, ColumnDef, Ddl, SetParamScopeType, SetParamValue}; +use crate::ir::ddl::{AlterSystemType, ColumnDef, SetParamScopeType, SetParamValue}; use crate::ir::ddl::{Language, ParamDef}; use crate::ir::expression::cast::Type as CastType; use crate::ir::expression::{ - ColumnPositionMap, ColumnWithScan, ColumnsRetrievalSpec, Expression, ExpressionId, - FunctionFeature, NodeId, Position, TrimKind, + ColumnPositionMap, ColumnWithScan, ColumnsRetrievalSpec, ExpressionId, FunctionFeature, + Position, TrimKind, +}; +use crate::ir::node::expression::{Expression, MutExpression}; +use crate::ir::node::relational::Relational; +use crate::ir::node::{ + AlterSystem, AlterUser, BoolExpr, Constant, CountAsterisk, CreateIndex, CreateProc, CreateRole, + CreateTable, CreateUser, DropIndex, DropProc, DropRole, DropTable, DropUser, GrantPrivilege, + Node, NodeId, Procedure, RenameRoutine, RevokePrivilege, ScanCte, ScanRelation, SetParam, + SetTransaction, Trim, }; use crate::ir::operator::{ - Arithmetic, Bool, ConflictStrategy, JoinKind, OrderByElement, OrderByEntity, OrderByType, - Relational, Unary, + Arithmetic, Bool, ConflictStrategy, JoinKind, OrderByElement, OrderByEntity, OrderByType, Unary, }; use crate::ir::relation::{Column, ColumnRole, TableKind, Type as RelationType}; -use crate::ir::tree::traversal::{PostOrder, EXPR_CAPACITY}; +use crate::ir::tree::traversal::{LevelNode, PostOrder, EXPR_CAPACITY}; use crate::ir::value::Value; -use crate::ir::{Node, OptionKind, OptionParamValue, OptionSpec, Plan}; +use crate::ir::{OptionKind, OptionParamValue, OptionSpec, Plan}; use crate::otm::child_span; use crate::errors::Entity::AST; use crate::executor::engine::helpers::{normalize_name_from_sql, to_user}; use crate::ir::acl::AlterOption; -use crate::ir::acl::{Acl, GrantRevokeType, Privilege}; +use crate::ir::acl::{GrantRevokeType, Privilege}; use crate::ir::aggregates::AggregateKind; -use crate::ir::block::Block; use crate::ir::expression::NewColumnsSource; use crate::ir::helpers::RepeatableState; use crate::ir::transformation::redistribution::ColumnPosition; @@ -189,7 +195,7 @@ fn parse_call_proc<M: Metadata>( pairs_map: &mut ParsingPairsMap, worker: &mut ExpressionsWorker<M>, plan: &mut Plan, -) -> Result<Block, SbroadError> { +) -> Result<Procedure, SbroadError> { let proc_name_ast_id = node.children.first().expect("Expected to get Proc name"); let proc_name = parse_identifier(ast, *proc_name_ast_id)?; @@ -216,14 +222,17 @@ fn parse_call_proc<M: Metadata>( values.push(plan_value_id); } - let call_proc = Block::Procedure { + let call_proc = Procedure { name: proc_name, values, }; Ok(call_proc) } -fn parse_rename_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, SbroadError> { +fn parse_rename_proc( + ast: &AbstractSyntaxTree, + node: &ParseNode, +) -> Result<RenameRoutine, SbroadError> { if node.rule != Rule::RenameProc { return Err(SbroadError::Invalid( Entity::Type, @@ -253,7 +262,7 @@ fn parse_rename_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, _ => panic!("Unexpected node: {child_node:?}"), } } - Ok(Ddl::RenameRoutine { + Ok(RenameRoutine { old_name, new_name, params, @@ -261,7 +270,10 @@ fn parse_rename_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, }) } -fn parse_create_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, SbroadError> { +fn parse_create_proc( + ast: &AbstractSyntaxTree, + node: &ParseNode, +) -> Result<CreateProc, SbroadError> { let proc_name_id = node.children.first().expect("Expected to get Proc name"); let proc_name = parse_identifier(ast, *proc_name_id)?; @@ -291,7 +303,7 @@ fn parse_create_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, _ => unreachable!("Unexpected node: {child_node:?}"), } } - let create_proc = Ddl::CreateProc { + let create_proc = CreateProc { name: proc_name, params, language, @@ -307,7 +319,7 @@ fn parse_alter_system<M: Metadata>( pairs_map: &mut ParsingPairsMap, worker: &mut ExpressionsWorker<M>, plan: &mut Plan, -) -> Result<Ddl, SbroadError> { +) -> Result<AlterSystem, SbroadError> { let alter_system_type_node_id = node .children .first() @@ -335,7 +347,7 @@ fn parse_alter_system<M: Metadata>( let expr_pair = pairs_map.remove_pair(*param_value_node_id); let expr_plan_node_id = parse_expr(Pairs::single(expr_pair), &[], worker, plan)?; let value_node = plan.get_node(expr_plan_node_id)?; - if let Node::Expression(Expression::Constant { value }) = value_node { + if let Node::Expression(Expression::Constant(Constant { value })) = value_node { AlterSystemType::AlterSystemSet { param_name, param_value: value.clone(), @@ -383,7 +395,7 @@ fn parse_alter_system<M: Metadata>( None }; - Ok(Ddl::AlterSystem { + Ok(AlterSystem { ty, tier_name, timeout: get_default_timeout(), @@ -407,7 +419,7 @@ fn parse_proc_with_optional_params( Ok((proc_name, params)) } -fn parse_drop_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, SbroadError> { +fn parse_drop_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<DropProc, SbroadError> { let proc_with_optional_params_id = node .children .first() @@ -421,7 +433,7 @@ fn parse_drop_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, Sb get_default_timeout() }; - Ok(Ddl::DropProc { + Ok(DropProc { name, params, timeout, @@ -429,7 +441,10 @@ fn parse_drop_proc(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, Sb } #[allow(clippy::too_many_lines)] -fn parse_create_index(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, SbroadError> { +fn parse_create_index( + ast: &AbstractSyntaxTree, + node: &ParseNode, +) -> Result<CreateIndex, SbroadError> { assert_eq!(node.rule, Rule::CreateIndex); let mut name = SmolStr::default(); let mut table_name = SmolStr::default(); @@ -545,7 +560,7 @@ fn parse_create_index(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, _ => panic!("Unexpected index rule: {child_node:?}"), } } - let index = Ddl::CreateIndex { + let index = CreateIndex { name, table_name, columns, @@ -564,7 +579,7 @@ fn parse_create_index(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, Ok(index) } -fn parse_drop_index(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, SbroadError> { +fn parse_drop_index(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<DropIndex, SbroadError> { assert_eq!(node.rule, Rule::DropIndex); let mut name = SmolStr::default(); let mut timeout = get_default_timeout(); @@ -576,12 +591,15 @@ fn parse_drop_index(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, S _ => panic!("Unexpected drop index node: {child_node:?}"), } } - Ok(Ddl::DropIndex { name, timeout }) + Ok(DropIndex { name, timeout }) } #[allow(clippy::too_many_lines)] #[allow(clippy::uninlined_format_args)] -fn parse_create_table(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, SbroadError> { +fn parse_create_table( + ast: &AbstractSyntaxTree, + node: &ParseNode, +) -> Result<CreateTable, SbroadError> { assert_eq!( node.rule, Rule::CreateTable, @@ -862,8 +880,7 @@ fn parse_create_table(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, Some("global spaces can use only memtx engine".into()), )); } - - Ddl::CreateTable { + CreateTable { name: table_name, format: columns, primary_key: pk_keys, @@ -873,7 +890,7 @@ fn parse_create_table(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, tier, } } else { - Ddl::CreateTable { + CreateTable { name: table_name, format: columns, primary_key: pk_keys, @@ -886,7 +903,7 @@ fn parse_create_table(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, Ok(create_sharded_table) } -fn parse_set_param(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, SbroadError> { +fn parse_set_param(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<SetParam, SbroadError> { let mut scope_type = SetParamScopeType::Session; let mut param_value = None; for child_id in &node.children { @@ -926,7 +943,7 @@ fn parse_set_param(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl, Sb _ => panic!("Unexpected rule met under SetParam."), } } - Ok(Ddl::SetParam { + Ok(SetParam { scope_type, param_value: param_value.unwrap(), timeout: get_default_timeout(), @@ -1543,10 +1560,13 @@ where } fn build_columns_map(&mut self, plan: &Plan, rel_id: NodeId) -> Result<(), SbroadError> { - if self.column_positions_cache.get(&rel_id).is_none() { + if let std::collections::hash_map::Entry::Vacant(e) = + self.column_positions_cache.entry(rel_id) + { let new_map = ColumnPositionMap::new(plan, rel_id)?; - self.column_positions_cache.insert(rel_id, new_map); + e.insert(new_map); } + Ok(()) } @@ -1707,7 +1727,7 @@ impl ParseExpression { let child_plan_id = child.populate_plan(plan, worker)?; let child_expr = plan.get_node(child_plan_id)?; - if let Node::Expression(Expression::Bool { op, .. }) = child_expr { + if let Node::Expression(Expression::Bool(BoolExpr { op, .. })) = child_expr { // We don't want simple infix comparisons to be covered with parentheses // as soon as it breaks logic of conflicts resolving which currently // work adequately only with ROWs. @@ -1766,12 +1786,12 @@ impl ParseExpression { Some(p) => Some(p.populate_plan(plan, worker)?), None => None, }; - let trim_expr = Expression::Trim { + let trim_expr = Trim { kind: kind.clone(), pattern, target: target.populate_plan(plan, worker)?, }; - plan.nodes.push(Node::Expression(trim_expr)) + plan.nodes.push(trim_expr.into()) } ParseExpression::FinalBetween { is_not, @@ -1849,18 +1869,18 @@ impl ParseExpression { let right_expr = plan.get_node(right_plan_id)?; matches!( right_expr, - Node::Expression(Expression::Bool { op: Bool::And, .. }) + Node::Expression(Expression::Bool(BoolExpr { op: Bool::And, .. })) ) }; if matches!(op, ParseExpressionInfixOperator::InfixBool(Bool::And)) && right_plan_is_and { let right_expr = plan.get_expression_node(right_plan_id)?; - let fixed_left_and_id = if let Expression::Bool { + let fixed_left_and_id = if let Expression::Bool(BoolExpr { op: Bool::And, left, .. - } = right_expr + }) = right_expr { plan.add_cond(left_row_id, Bool::And, *left)? } else { @@ -1868,11 +1888,11 @@ impl ParseExpression { }; let right_expr_mut = plan.get_mut_expression_node(right_plan_id)?; - if let Expression::Bool { + if let MutExpression::Bool(BoolExpr { op: Bool::And, left, .. - } = right_expr_mut + }) = right_expr_mut { *left = fixed_left_and_id; return Ok(right_plan_id); @@ -2144,7 +2164,7 @@ where )) )); } - let count_asterisk_plan_id = plan.nodes.push(Node::Expression(Expression::CountAsterisk)); + let count_asterisk_plan_id = plan.nodes.push(CountAsterisk{}.into()); parse_exprs_args.push(ParseExpression::PlanId { plan_id: count_asterisk_plan_id }); } Rule::FunctionArgs => { @@ -2241,9 +2261,7 @@ where Err(e) => return Err(e) }; let child = plan.get_relation_node(*plan_left_id)?; - let child_alias_ids = plan.get_expression_node( - child.output() - )?.get_row_list()?; + let child_alias_ids = plan.get_row_list(child.output())?; let child_alias_id = child_alias_ids .get(col_position) .expect("column position is invalid"); @@ -2398,7 +2416,7 @@ where ParseExpression::PlanId { plan_id } } Rule::CountAsterisk => { - let plan_id = plan.nodes.push(Node::Expression(Expression::CountAsterisk)); + let plan_id = plan.nodes.push(CountAsterisk{}.into()); ParseExpression::PlanId { plan_id } } rule => unreachable!("Expr::parse expected atomic rule, found {:?}", rule), @@ -2747,7 +2765,7 @@ impl AbstractSyntaxTree { let entity = match expr { Node::Expression(expr) => { - if let Expression::Constant {value: Value::Unsigned(index)} = expr { + if let Expression::Constant(Constant {value: Value::Unsigned(index)}) = expr { let index_usize = usize::try_from(*index).map_err(|_| { SbroadError::Invalid( Entity::Expression, @@ -2769,8 +2787,7 @@ impl AbstractSyntaxTree { let mut expr_tree = PostOrder::with_capacity(|node| plan.nodes.expr_iter(node, false), EXPR_CAPACITY); let mut reference_met = false; - for level_node in expr_tree.iter(expr_plan_node_id) { - let node_id = level_node.1; + for LevelNode(_, node_id) in expr_tree.iter(expr_plan_node_id) { if let Expression::Reference { .. } = plan.get_expression_node(node_id)? { reference_met = true; break; @@ -2860,7 +2877,7 @@ impl AbstractSyntaxTree { .expect("could not find first child id in scan node"); let rel_child_id_plan = map.get(*rel_child_id_ast)?; let rel_child_node = plan.get_relation_node(rel_child_id_plan)?; - if let Relational::ScanSubQuery { .. } = rel_child_node { + if let Relational::ScanSubQuery(_) = rel_child_node { // We want `SubQuery` ids to be used only during expressions parsing. worker.subquery_ids_queue.pop_back(); } @@ -2870,11 +2887,11 @@ impl AbstractSyntaxTree { let alias_name = parse_normalized_identifier(self, *ast_alias_id)?; // CTE scans can have different aliases, so clone the CTE scan node, // preserving its subtree. - if let Relational::ScanCte { child, .. } = rel_child_node { + if let Relational::ScanCte(ScanCte { child, .. }) = rel_child_node { let scan_id = plan.add_cte(*child, alias_name, vec![])?; map.add(id, scan_id); } else { - let scan = plan.get_mut_relation_node(rel_child_id_plan)?; + let mut scan = plan.get_mut_relation_node(rel_child_id_plan)?; scan.set_scan_name(Some(alias_name.to_smolstr()))?; } } @@ -3094,7 +3111,7 @@ impl AbstractSyntaxTree { parse_normalized_identifier(self, *alias_ast_node_id)? } else { // We don't use `get_expression_node` here, because we may encounter a `Parameter`. - if let Node::Expression(Expression::Reference { .. }) = + if let Node::Expression(Expression::Reference(_)) = plan.get_node(expr_plan_node_id)? { let (col_name, _) = worker @@ -3179,7 +3196,9 @@ impl AbstractSyntaxTree { let plan_scan_id = map.get(*ast_scan_table_id)?; let plan_scan_node = plan.get_relation_node(plan_scan_id)?; let scan_relation = - if let Relational::ScanRelation { relation, .. } = plan_scan_node { + if let Relational::ScanRelation(ScanRelation { relation, .. }) = + plan_scan_node + { relation.clone() } else { unreachable!("Scan expected under Update") @@ -3305,7 +3324,9 @@ impl AbstractSyntaxTree { Rule::ScanTable => { let plan_scan_id = map.get(*first_child_id)?; let plan_scan_node = plan.get_relation_node(plan_scan_id)?; - let Relational::ScanRelation { relation, .. } = plan_scan_node else { + let Relational::ScanRelation(ScanRelation { relation, .. }) = + plan_scan_node + else { unreachable!("Scan expected under ScanTable") }; (plan_scan_id, relation.clone()) @@ -3318,7 +3339,9 @@ impl AbstractSyntaxTree { let plan_scan_id = map.get(*ast_table_id)?; let plan_scan_node = plan.get_relation_node(plan_scan_id)?; let relation_name = - if let Relational::ScanRelation { relation, .. } = plan_scan_node { + if let Relational::ScanRelation(ScanRelation { relation, .. }) = + plan_scan_node + { relation.clone() } else { unreachable!("Scan expected under DeleteFilter") @@ -3493,53 +3516,53 @@ impl AbstractSyntaxTree { } Rule::CallProc => { let call_proc = parse_call_proc(self, node, pairs_map, &mut worker, &mut plan)?; - let plan_id = plan.nodes.push(Node::Block(call_proc)); + let plan_id = plan.nodes.push(call_proc.into()); map.add(id, plan_id); } Rule::CreateIndex => { let create_index = parse_create_index(self, node)?; - let plan_id = plan.nodes.push(Node::Ddl(create_index)); + let plan_id = plan.nodes.push(create_index.into()); map.add(id, plan_id); } Rule::AlterSystem => { let alter_system = parse_alter_system(self, node, pairs_map, &mut worker, &mut plan)?; - let plan_id = plan.nodes.push(Node::Ddl(alter_system)); + let plan_id = plan.nodes.push(alter_system.into()); map.add(id, plan_id); } Rule::CreateProc => { let create_proc = parse_create_proc(self, node)?; - let plan_id = plan.nodes.push(Node::Ddl(create_proc)); + let plan_id = plan.nodes.push(create_proc.into()); map.add(id, plan_id); } Rule::CreateTable => { let create_sharded_table = parse_create_table(self, node)?; - let plan_id = plan.nodes.push(Node::Ddl(create_sharded_table)); + let plan_id = plan.nodes.push(create_sharded_table.into()); map.add(id, plan_id); } Rule::GrantPrivilege => { let (grant_type, grantee_name, timeout) = parse_grant_revoke(node, self)?; - let grant_privilege = Acl::GrantPrivilege { + let grant_privilege = GrantPrivilege { grant_type, grantee_name, timeout, }; - let plan_id = plan.nodes.push(Node::Acl(grant_privilege)); + let plan_id = plan.nodes.push(grant_privilege.into()); map.add(id, plan_id); } Rule::RevokePrivilege => { let (revoke_type, grantee_name, timeout) = parse_grant_revoke(node, self)?; - let revoke_privilege = Acl::RevokePrivilege { + let revoke_privilege = RevokePrivilege { revoke_type, grantee_name, timeout, }; - let plan_id = plan.nodes.push(Node::Acl(revoke_privilege)); + let plan_id = plan.nodes.push(revoke_privilege.into()); map.add(id, plan_id); } Rule::DropIndex => { let drop_index = parse_drop_index(self, node)?; - let plan_id = plan.nodes.push(Node::Ddl(drop_index)); + let plan_id = plan.nodes.push(drop_index.into()); map.add(id, plan_id); } Rule::DropRole => { @@ -3553,11 +3576,11 @@ impl AbstractSyntaxTree { if let Some(timeout_child_id) = node.children.get(1) { timeout = get_timeout(self, *timeout_child_id)?; } - let drop_role = Acl::DropRole { + let drop_role = DropRole { name: role_name, timeout, }; - let plan_id = plan.nodes.push(Node::Acl(drop_role)); + let plan_id = plan.nodes.push(drop_role.into()); map.add(id, plan_id); } Rule::DropTable => { @@ -3583,21 +3606,21 @@ impl AbstractSyntaxTree { } } } - let drop_table = Ddl::DropTable { + let drop_table = DropTable { name: table_name, timeout, }; - let plan_id = plan.nodes.push(Node::Ddl(drop_table)); + let plan_id = plan.nodes.push(drop_table.into()); map.add(id, plan_id); } Rule::DropProc => { let drop_proc = parse_drop_proc(self, node)?; - let plan_id = plan.nodes.push(Node::Ddl(drop_proc)); + let plan_id = plan.nodes.push(drop_proc.into()); map.add(id, plan_id); } Rule::RenameProc => { let rename_proc = parse_rename_proc(self, node)?; - let plan_id = plan.nodes.push(Node::Ddl(rename_proc)); + let plan_id = plan.nodes.push(rename_proc.into()); map.add(id, plan_id); } Rule::AlterUser => { @@ -3663,12 +3686,12 @@ impl AbstractSyntaxTree { timeout = get_timeout(self, *timeout_node_id)?; } - let alter_user = Acl::AlterUser { + let alter_user = AlterUser { name: user_name, alter_option, timeout, }; - let plan_id = plan.nodes.push(Node::Acl(alter_user)); + let plan_id = plan.nodes.push(alter_user.into()); map.add(id, plan_id); } Rule::CreateUser => { @@ -3718,13 +3741,13 @@ impl AbstractSyntaxTree { } } - let create_user = Acl::CreateUser { + let create_user = CreateUser { name: user_name, password, auth_method, timeout, }; - let plan_id = plan.nodes.push(Node::Acl(create_user)); + let plan_id = plan.nodes.push(create_user.into()); map.add(id, plan_id); } Rule::DropUser => { @@ -3738,11 +3761,11 @@ impl AbstractSyntaxTree { if let Some(timeout_child_id) = node.children.get(1) { timeout = get_timeout(self, *timeout_child_id)?; } - let drop_user = Acl::DropUser { + let drop_user = DropUser { name: user_name, timeout, }; - let plan_id = plan.nodes.push(Node::Acl(drop_user)); + let plan_id = plan.nodes.push(drop_user.into()); map.add(id, plan_id); } Rule::CreateRole => { @@ -3756,23 +3779,23 @@ impl AbstractSyntaxTree { if let Some(timeout_child_id) = node.children.get(1) { timeout = get_timeout(self, *timeout_child_id)?; } - let create_role = Acl::CreateRole { + let create_role = CreateRole { name: role_name, timeout, }; - let plan_id = plan.nodes.push(Node::Acl(create_role)); + let plan_id = plan.nodes.push(create_role.into()); map.add(id, plan_id); } Rule::SetParam => { let set_param_node = parse_set_param(self, node)?; - let plan_id = plan.nodes.push(Node::Ddl(set_param_node)); + let plan_id = plan.nodes.push(set_param_node.into()); map.add(id, plan_id); } Rule::SetTransaction => { - let set_transaction_node = Ddl::SetTransaction { + let set_transaction_node = SetTransaction { timeout: get_default_timeout(), }; - let plan_id = plan.nodes.push(Node::Ddl(set_transaction_node)); + let plan_id = plan.nodes.push(set_transaction_node.into()); map.add(id, plan_id); } _ => {} @@ -3836,11 +3859,11 @@ impl Plan { /// Used for unification of expression nodes transformations (e.g. dnf). fn row(&mut self, expr_id: NodeId) -> Result<NodeId, SbroadError> { let row_id = if let Node::Expression( - Expression::Reference { .. } - | Expression::Constant { .. } - | Expression::Cast { .. } - | Expression::Concat { .. } - | Expression::StableFunction { .. }, + Expression::Reference(_) + | Expression::Constant(_) + | Expression::Cast(_) + | Expression::Concat(_) + | Expression::StableFunction(_), ) = self.get_node(expr_id)? { self.nodes.add_row(vec![expr_id], None) diff --git a/sbroad-core/src/frontend/sql/ir.rs b/sbroad-core/src/frontend/sql/ir.rs index 9f437ddfa..96187f2ef 100644 --- a/sbroad-core/src/frontend/sql/ir.rs +++ b/sbroad-core/src/frontend/sql/ir.rs @@ -7,14 +7,21 @@ use tarantool::decimal::Decimal; use crate::errors::{Action, Entity, SbroadError}; use crate::frontend::sql::ast::Rule; -use crate::ir::expression::{Expression, NodeId}; use crate::ir::helpers::RepeatableState; -use crate::ir::operator::{OrderByElement, OrderByEntity, Relational}; +use crate::ir::node::expression::{ExprOwned, Expression, MutExpression}; +use crate::ir::node::relational::{MutRelational, RelOwned, Relational}; +use crate::ir::node::{ + Alias, ArenaType, ArithmeticExpr, BoolExpr, Case, Cast, Concat, Constant, Delete, Except, + ExprInParentheses, GroupBy, Having, Insert, Intersect, Join, Limit, Motion, MutNode, Node, + NodeId, OrderBy, Projection, Reference, Row, ScanCte, ScanRelation, ScanSubQuery, Selection, + SizeNode, StableFunction, Trim, UnaryExpr, Union, UnionAll, Update, Values, ValuesRow, +}; +use crate::ir::operator::{OrderByElement, OrderByEntity}; use crate::ir::transformation::redistribution::MotionOpcode; use crate::ir::tree::traversal::{LevelNode, PostOrder, EXPR_CAPACITY}; use crate::ir::value::double::Double; use crate::ir::value::Value; -use crate::ir::{ArenaType, Node, Plan}; +use crate::ir::Plan; use super::Between; @@ -164,44 +171,53 @@ 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 (offset, node) in self.nodes.iter().enumerate() { + for (relational_id, _node) in self.nodes.iter64().enumerate() { + let node = self.get_node(NodeId { + offset: u32::try_from(relational_id).unwrap(), + arena_type: ArenaType::Arena64, + })?; match node { Node::Relational( - Relational::Selection { filter: tree, .. } - | Relational::Join { + Relational::Selection(Selection { filter: tree, .. }) + | Relational::Join(Join { condition: tree, .. - } - | Relational::Having { filter: tree, .. }, + }) + | Relational::Having(Having { filter: tree, .. }), ) => { let capacity = self.nodes.len(); let mut expr_post = PostOrder::with_capacity( |node| self.nodes.expr_iter(node, false), capacity, ); - 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; + for LevelNode(_, op_id) in expr_post.iter(*tree) { let expression_node = self.get_node(op_id)?; - if let Node::Expression(Expression::Bool { left, right, .. }) = - expression_node + if let Node::Expression(Expression::Bool(BoolExpr { + left, right, .. + })) = expression_node { let children = &[*left, *right]; for child in children { if let Node::Relational(Relational::ScanSubQuery { .. }) = self.get_node(*child)? { + let relational_id = NodeId { + offset: u32::try_from(relational_id).unwrap(), + arena_type: ArenaType::Arena64, + }; set.insert(SubQuery::new(relational_id, op_id, *child)); } } - } else if let Node::Expression(Expression::Unary { child, .. }) = - expression_node + } else if let Node::Expression(Expression::Unary(UnaryExpr { + child, .. + })) = expression_node { if let Node::Relational(Relational::ScanSubQuery { .. }) = self.get_node(*child)? { + let relational_id = NodeId { + offset: u32::try_from(relational_id).unwrap(), + arena_type: ArenaType::Arena64, + }; set.insert(SubQuery::new(relational_id, op_id, *child)); } } @@ -222,10 +238,10 @@ impl Plan { 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)? { - Node::Relational( - Relational::Selection { children, .. } - | Relational::Join { children, .. } - | Relational::Having { children, .. }, + MutNode::Relational( + MutRelational::Selection(Selection { children, .. }) + | MutRelational::Join(Join { children, .. }) + | MutRelational::Having(Having { children, .. }), ) => { // O(n) can become a problem. if !children.contains(&sq.sq) { @@ -243,9 +259,9 @@ impl Plan { // Generate a reference to the sub-query. let rel = self.get_relation_node(sq.relational)?; let children = match rel { - Relational::Join { children, .. } - | Relational::Having { children, .. } - | Relational::Selection { children, .. } => children.clone(), + Relational::Join(Join { children, .. }) + | Relational::Having(Having { children, .. }) + | Relational::Selection(Selection { children, .. }) => children.clone(), _ => { return Err(SbroadError::Invalid( Entity::Relational, @@ -260,11 +276,11 @@ impl Plan { // Replace sub-query with reference. let op = self.get_mut_expression_node(sq.operator)?; - if let Expression::Bool { + if let MutExpression::Bool(BoolExpr { ref mut left, ref mut right, .. - } = op + }) = op { if *left == sq.sq { *left = row_id; @@ -277,7 +293,7 @@ impl Plan { )); } replaces.insert(sq.sq, row_id); - } else if let Expression::Unary { child, .. } = op { + } else if let MutExpression::Unary(UnaryExpr { child, .. }) = op { *child = row_id; replaces.insert(sq.sq, row_id); } else { @@ -312,7 +328,7 @@ impl Plan { self.clone_expr_subtree(between.left_id)? }; let less_eq_expr = self.get_mut_expression_node(between.less_eq_id)?; - if let Expression::Bool { ref mut left, .. } = less_eq_expr { + if let MutExpression::Bool(BoolExpr { ref mut left, .. }) = less_eq_expr { *left = left_id; } else { return Err(SbroadError::Invalid( @@ -330,62 +346,60 @@ impl Plan { subtree.populate_nodes(top_id); let nodes = subtree.take_nodes(); let mut map = CloneExprSubtreeMap::with_capacity(nodes.len()); - 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(); + let mut expr = self.get_mut_expression_node(id)?.get_expr_owned(); match expr { - Expression::Constant { .. } - | Expression::Reference { .. } - | Expression::CountAsterisk => {} - Expression::Alias { ref mut child, .. } - | Expression::ExprInParentheses { ref mut child } - | Expression::Cast { ref mut child, .. } - | Expression::Unary { ref mut child, .. } => map.replace(child), - Expression::Bool { + ExprOwned::Constant { .. } + | ExprOwned::Reference { .. } + | ExprOwned::CountAsterisk { .. } => {} + ExprOwned::Alias(Alias { ref mut child, .. }) + | ExprOwned::ExprInParentheses(ExprInParentheses { ref mut child }) + | ExprOwned::Cast(Cast { ref mut child, .. }) + | ExprOwned::Unary(UnaryExpr { ref mut child, .. }) => map.replace(child), + ExprOwned::Bool(BoolExpr { ref mut left, ref mut right, .. - } - | Expression::Arithmetic { + }) + | ExprOwned::Arithmetic(ArithmeticExpr { ref mut left, ref mut right, .. - } - | Expression::Concat { + }) + | ExprOwned::Concat(Concat { ref mut left, ref mut right, .. - } => { + }) => { map.replace(left); map.replace(right); } - Expression::Trim { + ExprOwned::Trim(Trim { ref mut pattern, ref mut target, .. - } => { + }) => { if let Some(pattern) = pattern { map.replace(pattern); } map.replace(target); } - Expression::Row { + ExprOwned::Row(Row { list: ref mut children, .. - } - | Expression::StableFunction { + }) + | ExprOwned::StableFunction(StableFunction { ref mut children, .. - } => { + }) => { for child in children { map.replace(child); } } - Expression::Case { + ExprOwned::Case(Case { ref mut search_expr, ref mut when_blocks, ref mut else_expr, - } => { + }) => { if let Some(search_expr) = search_expr { map.replace(search_expr); } @@ -398,10 +412,10 @@ impl Plan { } } } - expr_id = self.nodes.push(Node::Expression(expr)); + let next_id = self.nodes.push(expr.into()); map.insert(id, next_id); } - Ok(expr_id) + Ok(map.get(top_id)) } } @@ -440,41 +454,41 @@ impl SubtreeCloner { Ok(new_list) } - fn clone_expression(&mut self, expr: &Expression) -> Result<Expression, SbroadError> { - let mut copied = expr.clone(); + fn clone_expression(&mut self, expr: &Expression) -> Result<ExprOwned, SbroadError> { + let mut copied = expr.get_expr_owned(); // note: all struct fields are listed explicitly (instead of `..`), so that // when a new field is added to a struct, this match must // be updated, or compilation will fail. match &mut copied { - Expression::Constant { value: _ } - | Expression::Reference { + ExprOwned::Constant(Constant { value: _ }) + | ExprOwned::Reference(Reference { parent: _, targets: _, position: _, col_type: _, - } - | Expression::CountAsterisk => {} - Expression::Alias { + }) + | ExprOwned::CountAsterisk { .. } => {} + ExprOwned::Alias(Alias { ref mut child, name: _, - } - | Expression::ExprInParentheses { ref mut child } - | Expression::Cast { + }) + | ExprOwned::ExprInParentheses(ExprInParentheses { ref mut child }) + | ExprOwned::Cast(Cast { ref mut child, to: _, - } - | Expression::Unary { + }) + | ExprOwned::Unary(UnaryExpr { ref mut child, op: _, - } => { + }) => { *child = self.get_new_id(*child)?; } - Expression::Case { + ExprOwned::Case(Case { ref mut search_expr, ref mut when_blocks, ref mut else_expr, - } => { + }) => { if let Some(search_expr) = search_expr { *search_expr = self.get_new_id(*search_expr)?; } @@ -486,40 +500,40 @@ impl SubtreeCloner { *else_expr = self.get_new_id(*else_expr)?; } } - Expression::Bool { + ExprOwned::Bool(BoolExpr { ref mut left, ref mut right, op: _, - } - | Expression::Arithmetic { + }) + | ExprOwned::Arithmetic(ArithmeticExpr { ref mut left, ref mut right, op: _, - } - | Expression::Concat { + }) + | ExprOwned::Concat(Concat { ref mut left, ref mut right, - } => { + }) => { *left = self.get_new_id(*left)?; *right = self.get_new_id(*right)?; } - Expression::Trim { + ExprOwned::Trim(Trim { ref mut pattern, ref mut target, .. - } => { + }) => { if let Some(pattern) = pattern { *pattern = self.get_new_id(*pattern)?; } *target = self.get_new_id(*target)?; } - Expression::Row { + ExprOwned::Row(Row { list: ref mut children, distribution: _, - } - | Expression::StableFunction { + }) + | ExprOwned::StableFunction(StableFunction { ref mut children, .. - } => { + }) => { *children = self.copy_list(&*children)?; } } @@ -532,8 +546,8 @@ impl SubtreeCloner { &mut self, old_relational: &Relational, id: NodeId, - ) -> Result<Relational, SbroadError> { - let mut copied = old_relational.clone(); + ) -> Result<RelOwned, SbroadError> { + let mut copied: RelOwned = old_relational.get_rel_owned(); // all relational nodes have output and children list, // which must be copied. @@ -549,101 +563,101 @@ impl SubtreeCloner { // when a new field is added to a struct, this match must // be updated, or compilation will fail. match &mut copied { - Relational::Values { + RelOwned::Values(Values { output: _, children: _, - } - | Relational::Projection { + }) + | RelOwned::Projection(Projection { children: _, output: _, is_distinct: _, - } - | Relational::Insert { + }) + | RelOwned::Insert(Insert { relation: _, columns: _, children: _, output: _, conflict_strategy: _, - } - | Relational::Update { + }) + | RelOwned::Update(Update { relation: _, children: _, update_columns_map: _, strategy: _, pk_positions: _, output: _, - } - | Relational::Delete { + }) + | RelOwned::Delete(Delete { relation: _, children: _, output: _, - } - | Relational::ScanRelation { + }) + | RelOwned::ScanRelation(ScanRelation { alias: _, output: _, relation: _, - } - | Relational::ScanCte { + }) + | RelOwned::ScanCte(ScanCte { alias: _, output: _, child: _, - } - | Relational::ScanSubQuery { + }) + | RelOwned::ScanSubQuery(ScanSubQuery { alias: _, children: _, output: _, - } - | Relational::Except { + }) + | RelOwned::Except(Except { left: _, right: _, output: _, - } - | Relational::Intersect { + }) + | RelOwned::Intersect(Intersect { left: _, right: _, output: _, - } - | Relational::Union { + }) + | RelOwned::Union(Union { left: _, right: _, output: _, - } - | Relational::UnionAll { + }) + | RelOwned::UnionAll(UnionAll { left: _, right: _, output: _, - } - | Relational::Limit { + }) + | RelOwned::Limit(Limit { limit: _, child: _, output: _, - } => {} - Relational::Having { + }) => {} + RelOwned::Having(Having { children: _, output: _, filter, - } - | Relational::Selection { + }) + | RelOwned::Selection(Selection { children: _, filter, output: _, - } - | Relational::Join { + }) + | RelOwned::Join(Join { children: _, condition: filter, output: _, kind: _, - } => { + }) => { *filter = self.get_new_id(*filter)?; } - Relational::Motion { + RelOwned::Motion(Motion { alias: _, children: _, policy: _, program, output: _, is_child_subquery: _, - } => { + }) => { for op in &mut program.0 { match op { MotionOpcode::RearrangeForShardedUpdate { @@ -667,19 +681,19 @@ impl SubtreeCloner { } } } - Relational::GroupBy { + RelOwned::GroupBy(GroupBy { children: _, gr_cols, output: _, is_final: _, - } => { + }) => { *gr_cols = self.copy_list(gr_cols)?; } - Relational::OrderBy { + RelOwned::OrderBy(OrderBy { child: _, order_by_elements, output: _, - } => { + }) => { let mut new_order_by_elements = Vec::with_capacity(order_by_elements.len()); for element in &mut *order_by_elements { let new_entity = match element.entity { @@ -695,11 +709,11 @@ impl SubtreeCloner { } *order_by_elements = new_order_by_elements; } - Relational::ValuesRow { + RelOwned::ValuesRow(ValuesRow { output: _, data, children: _, - } => { + }) => { *data = self.get_new_id(*data)?; } } @@ -711,7 +725,9 @@ impl SubtreeCloner { // This function replaces those references to new nodes. fn replace_backward_refs(&self, plan: &mut Plan) -> Result<(), SbroadError> { for old_id in &self.nodes_with_backward_references { - if let Node::Relational(Relational::Motion { program, .. }) = plan.get_node(*old_id)? { + if let Node::Relational(Relational::Motion(Motion { program, .. })) = + plan.get_node(*old_id)? + { let op_cnt = program.0.len(); for idx in 0..op_cnt { let op = plan.get_motion_opcode(*old_id, idx)?; @@ -719,10 +735,10 @@ impl SubtreeCloner { let new_motion_id = self.get_new_id(*old_id)?; let new_update_id = self.get_new_id(*update_id)?; - if let Relational::Motion { + if let MutRelational::Motion(Motion { program: new_program, .. - } = plan.get_mut_relation_node(new_motion_id)? + }) = plan.get_mut_relation_node(new_motion_id)? { if let Some(MotionOpcode::RearrangeForShardedUpdate { update_id: new_node_update_id, @@ -750,17 +766,16 @@ impl SubtreeCloner { dfs.populate_nodes(top_id); let nodes = dfs.take_nodes(); drop(dfs); - for level_node in nodes { - let id = level_node.1; + for LevelNode(_, id) in nodes { let node = plan.get_node(id)?; - let new_node = match node { - Node::Relational(rel) => Node::Relational(self.clone_relational(rel, id)?), - Node::Expression(expr) => Node::Expression(self.clone_expression(expr)?), + let new_node: SizeNode = match node { + Node::Relational(rel) => self.clone_relational(&rel, id)?.into(), + Node::Expression(expr) => self.clone_expression(&expr)?.into(), _ => { 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}" )), )) } @@ -771,7 +786,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}" )), )); } @@ -786,7 +801,7 @@ impl SubtreeCloner { SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( - "invalid subtree traversal with top: {top_id:?}" + "invalid subtree traversal with top: {top_id}" )), ) }) diff --git a/sbroad-core/src/frontend/sql/ir/tests.rs b/sbroad-core/src/frontend/sql/ir/tests.rs index a4a43cf03..861ee57cd 100644 --- a/sbroad-core/src/frontend/sql/ir/tests.rs +++ b/sbroad-core/src/frontend/sql/ir/tests.rs @@ -1,13 +1,13 @@ use crate::errors::SbroadError; +use crate::executor::engine::mock::RouterConfigurationMock; use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::frontend::Ast; -use crate::ir::expression::NodeId; -use crate::ir::operator::Relational; +use crate::ir::node::relational::Relational; +use crate::ir::node::NodeId; use crate::ir::transformation::helpers::{sql_to_ir, sql_to_optimized_ir}; use crate::ir::tree::traversal::PostOrder; use crate::ir::value::Value; -use crate::ir::Plan; -use crate::{executor::engine::mock::RouterConfigurationMock, ir::Positions}; +use crate::ir::{Plan, Positions}; use pretty_assertions::assert_eq; use time::{format_description, OffsetDateTime, Time}; @@ -827,10 +827,10 @@ fn front_order_by_over_single_distribution_must_not_add_motion() { scan projection ("id_count"::integer -> "id_count") scan - projection (sum(("count_13"::integer))::decimal -> "id_count") + projection (sum(("count_096"::integer))::decimal -> "id_count") motion [policy: full] scan - projection (count(("test_space"."id"::unsigned))::integer -> "count_13") + projection (count(("test_space"."id"::unsigned))::integer -> "count_096") scan "test_space" execution options: sql_vdbe_max_steps = 45000 @@ -964,10 +964,10 @@ fn track_shard_col_pos() { let node_id = level_node.1; let node = plan.get_relation_node(node_id).unwrap(); match node { - Relational::ScanRelation { .. } | Relational::Selection { .. } => { + Relational::ScanRelation(_) | Relational::Selection(_) => { assert_eq!([Some(4_usize), None], plan.get_positions(node_id).unwrap()) } - Relational::Projection { .. } => { + Relational::Projection(_) => { assert_eq!([Some(1_usize), None], plan.get_positions(node_id).unwrap()) } _ => {} @@ -985,7 +985,7 @@ fn track_shard_col_pos() { 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 { + if let Relational::Join(_) = node { assert_eq!( [Some(4_usize), Some(5_usize)], plan.get_positions(node_id).unwrap() @@ -1008,7 +1008,7 @@ fn track_shard_col_pos() { 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 { + if let Relational::Join(_) = node { assert_eq!([Some(4_usize), None], plan.get_positions(node_id).unwrap()); } } @@ -1263,11 +1263,11 @@ fn front_sql_groupby() { let plan = sql_to_optimized_ir(input, vec![]); println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( - r#"projection ("column_12"::integer -> "identification_number", "column_13"::string -> "product_code") - group by ("column_12"::integer, "column_13"::string) output: ("column_12"::integer -> "column_12", "column_13"::string -> "column_13") - motion [policy: segment([ref("column_12"), ref("column_13")])] + r#"projection ("column_764"::integer -> "identification_number", "column_864"::string -> "product_code") + group by ("column_764"::integer, "column_864"::string) output: ("column_764"::integer -> "column_764", "column_864"::string -> "column_864") + motion [policy: segment([ref("column_764"), ref("column_864")])] scan - projection ("hash_testing"."identification_number"::integer -> "column_12", "hash_testing"."product_code"::string -> "column_13") + projection ("hash_testing"."identification_number"::integer -> "column_764", "hash_testing"."product_code"::string -> "column_864") group by ("hash_testing"."identification_number"::integer, "hash_testing"."product_code"::string) output: ("hash_testing"."identification_number"::integer -> "identification_number", "hash_testing"."product_code"::string -> "product_code", "hash_testing"."product_units"::boolean -> "product_units", "hash_testing"."sys_op"::unsigned -> "sys_op", "hash_testing"."bucket_id"::unsigned -> "bucket_id") scan "hash_testing" execution options: @@ -1289,11 +1289,11 @@ fn front_sql_groupby_less_cols_in_proj() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection ("column_12"::integer -> "identification_number") - group by ("column_12"::integer, "column_13"::boolean) output: ("column_12"::integer -> "column_12", "column_13"::boolean -> "column_13") - motion [policy: segment([ref("column_12"), ref("column_13")])] + r#"projection ("column_764"::integer -> "identification_number") + group by ("column_764"::integer, "column_864"::boolean) output: ("column_764"::integer -> "column_764", "column_864"::boolean -> "column_864") + motion [policy: segment([ref("column_764"), ref("column_864")])] scan - projection ("hash_testing"."identification_number"::integer -> "column_12", "hash_testing"."product_units"::boolean -> "column_13") + projection ("hash_testing"."identification_number"::integer -> "column_764", "hash_testing"."product_units"::boolean -> "column_864") group by ("hash_testing"."identification_number"::integer, "hash_testing"."product_units"::boolean) output: ("hash_testing"."identification_number"::integer -> "identification_number", "hash_testing"."product_code"::string -> "product_code", "hash_testing"."product_units"::boolean -> "product_units", "hash_testing"."sys_op"::unsigned -> "sys_op", "hash_testing"."bucket_id"::unsigned -> "bucket_id") scan "hash_testing" execution options: @@ -1316,11 +1316,11 @@ fn front_sql_groupby_union_1() { let expected_explain = String::from( r#"union all - projection ("column_12"::integer -> "identification_number") - group by ("column_12"::integer) output: ("column_12"::integer -> "column_12") - motion [policy: segment([ref("column_12")])] + projection ("column_764"::integer -> "identification_number") + group by ("column_764"::integer) output: ("column_764"::integer -> "column_764") + motion [policy: segment([ref("column_764")])] scan - projection ("hash_testing"."identification_number"::integer -> "column_12") + projection ("hash_testing"."identification_number"::integer -> "column_764") group by ("hash_testing"."identification_number"::integer) output: ("hash_testing"."identification_number"::integer -> "identification_number", "hash_testing"."product_code"::string -> "product_code", "hash_testing"."product_units"::boolean -> "product_units", "hash_testing"."sys_op"::unsigned -> "sys_op", "hash_testing"."bucket_id"::unsigned -> "bucket_id") scan "hash_testing" projection ("hash_testing"."identification_number"::integer -> "identification_number") @@ -1351,11 +1351,11 @@ fn front_sql_groupby_union_2() { projection ("identification_number"::integer -> "identification_number") scan union all - projection ("column_28"::integer -> "identification_number") - group by ("column_28"::integer) output: ("column_28"::integer -> "column_28") - motion [policy: segment([ref("column_28")])] + projection ("column_1764"::integer -> "identification_number") + group by ("column_1764"::integer) output: ("column_1764"::integer -> "column_1764") + motion [policy: segment([ref("column_1764")])] scan - projection ("hash_testing"."identification_number"::integer -> "column_28") + projection ("hash_testing"."identification_number"::integer -> "column_1764") group by ("hash_testing"."identification_number"::integer) output: ("hash_testing"."identification_number"::integer -> "identification_number", "hash_testing"."product_code"::string -> "product_code", "hash_testing"."product_units"::boolean -> "product_units", "hash_testing"."sys_op"::unsigned -> "sys_op", "hash_testing"."bucket_id"::unsigned -> "bucket_id") scan "hash_testing" projection ("hash_testing"."identification_number"::integer -> "identification_number") @@ -1381,11 +1381,11 @@ fn front_sql_groupby_join_1() { let plan = sql_to_optimized_ir(input, vec![]); 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_63"::string -> "column_63", "column_64"::boolean -> "column_64") - motion [policy: segment([ref("column_63"), ref("column_64")])] + r#"projection ("column_4064"::string -> "product_code", "column_4164"::boolean -> "product_units") + group by ("column_4064"::string, "column_4164"::boolean) output: ("column_4064"::string -> "column_4064", "column_4164"::boolean -> "column_4164") + motion [policy: segment([ref("column_4064"), ref("column_4164")])] scan - projection ("t2"."product_code"::string -> "column_63", "t2"."product_units"::boolean -> "column_64") + projection ("t2"."product_code"::string -> "column_4064", "t2"."product_units"::boolean -> "column_4164") 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" @@ -1473,10 +1473,10 @@ vtable_max_rows = 5000 scan "hash_single_testing" motion [policy: full] scan "t2" - projection (sum(("sum_41"::decimal))::decimal -> "id") + projection (sum(("sum_096"::decimal))::decimal -> "id") motion [policy: full] scan - projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_41") + projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_096") scan "test_space" execution options: sql_vdbe_max_steps = 45000 @@ -1496,11 +1496,11 @@ fn front_sql_groupby_insert() { let expected_explain = String::from( 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_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12") - motion [policy: segment([ref("column_13"), ref("column_12")])] + projection ("column_764"::unsigned -> "b", "column_864"::unsigned -> "d") + group by ("column_864"::unsigned, "column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_864"::unsigned -> "column_864") + motion [policy: segment([ref("column_864"), ref("column_764")])] scan - projection ("t"."d"::unsigned -> "column_13", "t"."b"::unsigned -> "column_12") + projection ("t"."b"::unsigned -> "column_764", "t"."d"::unsigned -> "column_864") 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: @@ -1547,11 +1547,11 @@ fn front_sql_aggregates() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( - r#"projection ("column_12"::unsigned -> "b", ROW(sum(("count_29"::integer))::decimal) + ROW(sum(("count_31"::integer))::decimal) -> "col_1") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "count_31"::integer -> "count_31", "count_29"::integer -> "count_29") - motion [policy: segment([ref("column_12")])] + r#"projection ("column_764"::unsigned -> "b", ROW(sum(("count_096"::integer))::decimal) + ROW(sum(("count_196"::integer))::decimal) -> "col_1") + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "count_196"::integer -> "count_196", "count_096"::integer -> "count_096") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_12", count(("t"."b"::unsigned))::integer -> "count_31", count(("t"."a"::unsigned))::integer -> "count_29") + projection ("t"."b"::unsigned -> "column_764", count(("t"."b"::unsigned))::integer -> "count_196", count(("t"."a"::unsigned))::integer -> "count_096") group by ("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: @@ -1571,10 +1571,10 @@ fn front_sql_avg_aggregate() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( - r#"projection (sum(("sum_13"::decimal::double))::decimal / sum(("count_13"::decimal::double))::decimal -> "col_1", avg(distinct ("column_15"::decimal::double))::decimal -> "col_2", ROW(sum(("sum_13"::decimal::double))::decimal / sum(("count_13"::decimal::double))::decimal) * ROW(sum(("sum_13"::decimal::double))::decimal / sum(("count_13"::decimal::double))::decimal) -> "col_3") + r#"projection (sum(("sum_096"::decimal::double))::decimal / sum(("count_096"::decimal::double))::decimal -> "col_1", avg(distinct ("column_864"::decimal::double))::decimal -> "col_2", ROW(sum(("sum_096"::decimal::double))::decimal / sum(("count_096"::decimal::double))::decimal) * ROW(sum(("sum_096"::decimal::double))::decimal / sum(("count_096"::decimal::double))::decimal) -> "col_3") motion [policy: full] scan - projection ("t"."b"::unsigned -> "column_15", count(("t"."b"::unsigned))::integer -> "count_13", sum(("t"."b"::unsigned))::decimal -> "sum_13") + projection ("t"."b"::unsigned -> "column_864", count(("t"."b"::unsigned))::integer -> "count_096", sum(("t"."b"::unsigned))::decimal -> "sum_096") group by ("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: @@ -1593,10 +1593,10 @@ fn front_sql_total_aggregate() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (total(("total_13"::double))::double -> "col_1", total(distinct ("column_15"::double))::double -> "col_2") + r#"projection (total(("total_096"::double))::double -> "col_1", total(distinct ("column_864"::double))::double -> "col_2") motion [policy: full] scan - projection ("t"."b"::unsigned -> "column_15", total(("t"."b"::unsigned))::double -> "total_13") + projection ("t"."b"::unsigned -> "column_864", total(("t"."b"::unsigned))::double -> "total_096") group by ("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: @@ -1615,10 +1615,10 @@ fn front_sql_min_aggregate() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (min(("min_13"::unsigned))::scalar -> "col_1", min(distinct ("column_15"::unsigned))::scalar -> "col_2") + r#"projection (min(("min_096"::unsigned))::scalar -> "col_1", min(distinct ("column_864"::unsigned))::scalar -> "col_2") motion [policy: full] scan - projection ("t"."b"::unsigned -> "column_15", min(("t"."b"::unsigned))::scalar -> "min_13") + projection ("t"."b"::unsigned -> "column_864", min(("t"."b"::unsigned))::scalar -> "min_096") group by ("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: @@ -1637,10 +1637,10 @@ fn front_sql_max_aggregate() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (max(("max_13"::unsigned))::scalar -> "col_1", max(distinct ("column_15"::unsigned))::scalar -> "col_2") + r#"projection (max(("max_096"::unsigned))::scalar -> "col_1", max(distinct ("column_864"::unsigned))::scalar -> "col_2") motion [policy: full] scan - projection ("t"."b"::unsigned -> "column_15", max(("t"."b"::unsigned))::scalar -> "max_13") + projection ("t"."b"::unsigned -> "column_864", max(("t"."b"::unsigned))::scalar -> "max_096") group by ("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: @@ -1659,10 +1659,10 @@ fn front_sql_group_concat_aggregate() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (group_concat(("group_concat_13"::string))::string -> "col_1", group_concat(distinct ("column_15"::string))::string -> "col_2") + r#"projection (group_concat(("group_concat_096"::string))::string -> "col_1", group_concat(distinct ("column_864"::string))::string -> "col_2") motion [policy: full] scan - projection ("test_space"."FIRST_NAME"::string -> "column_15", group_concat(("test_space"."FIRST_NAME"::string))::string -> "group_concat_13") + projection ("test_space"."FIRST_NAME"::string -> "column_864", group_concat(("test_space"."FIRST_NAME"::string))::string -> "group_concat_096") group by ("test_space"."FIRST_NAME"::string) 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" execution options: @@ -1681,10 +1681,10 @@ fn front_sql_group_concat_aggregate2() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (group_concat(("group_concat_14"::string, ' '::string))::string -> "col_1", group_concat(distinct ("column_16"::string))::string -> "col_2") + r#"projection (group_concat(("group_concat_096"::string, ' '::string))::string -> "col_1", group_concat(distinct ("column_964"::string))::string -> "col_2") motion [policy: full] scan - projection ("test_space"."FIRST_NAME"::string -> "column_16", group_concat(("test_space"."FIRST_NAME"::string, ' '::string))::string -> "group_concat_14") + projection ("test_space"."FIRST_NAME"::string -> "column_964", group_concat(("test_space"."FIRST_NAME"::string, ' '::string))::string -> "group_concat_096") group by ("test_space"."FIRST_NAME"::string) 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" execution options: @@ -1703,10 +1703,10 @@ fn front_sql_count_asterisk1() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (sum(("count_13"::integer))::decimal -> "col_1", sum(("count_13"::integer))::decimal -> "col_2") + r#"projection (sum(("count_096"::integer))::decimal -> "col_1", sum(("count_096"::integer))::decimal -> "col_2") motion [policy: full] scan - projection (count((*::integer))::integer -> "count_13") + projection (count((*::integer))::integer -> "count_096") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -1724,11 +1724,11 @@ fn front_sql_count_asterisk2() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (sum(("count_26"::integer))::decimal -> "col_1", "column_12"::unsigned -> "b") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "count_26"::integer -> "count_26") - motion [policy: segment([ref("column_12")])] + r#"projection (sum(("count_096"::integer))::decimal -> "col_1", "column_764"::unsigned -> "b") + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "count_096"::integer -> "count_096") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_12", count((*::integer))::integer -> "count_26") + projection ("t"."b"::unsigned -> "column_764", count((*::integer))::integer -> "count_096") group by ("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: @@ -1764,11 +1764,11 @@ fn front_sql_aggregates_with_subexpressions() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( - r#"projection ("column_12"::unsigned -> "b", sum(("count_35"::integer))::decimal -> "col_1", sum(("count_39"::integer))::decimal -> "col_2") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "count_39"::integer -> "count_39", "count_35"::integer -> "count_35") - motion [policy: segment([ref("column_12")])] + r#"projection ("column_764"::unsigned -> "b", sum(("count_096"::integer))::decimal -> "col_1", sum(("count_296"::integer))::decimal -> "col_2") + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "count_296"::integer -> "count_296", "count_096"::integer -> "count_096") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_12", count(("func"(("t"."a"::unsigned))::integer))::integer -> "count_39", count((ROW("t"."a"::unsigned) * ROW("t"."b"::unsigned) + ROW(1::unsigned)))::integer -> "count_35") + projection ("t"."b"::unsigned -> "column_764", count(("func"(("t"."a"::unsigned))::integer))::integer -> "count_296", count((ROW("t"."a"::unsigned) * ROW("t"."b"::unsigned) + ROW(1::unsigned)))::integer -> "count_096") group by ("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: @@ -1787,11 +1787,11 @@ fn front_sql_aggregates_with_distinct1() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection ("column_12"::unsigned -> "b", count(distinct ("column_27"::integer))::integer -> "col_1", count(distinct ("column_12"::integer))::integer -> "col_2") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_27"::unsigned -> "column_27") - motion [policy: segment([ref("column_12")])] + r#"projection ("column_764"::unsigned -> "b", count(distinct ("column_1664"::integer))::integer -> "col_1", count(distinct ("column_764"::integer))::integer -> "col_2") + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_1664"::unsigned -> "column_1664") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_12", "t"."a"::unsigned -> "column_27") + projection ("t"."b"::unsigned -> "column_764", "t"."a"::unsigned -> "column_1664") 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" execution options: @@ -1811,11 +1811,11 @@ fn front_sql_aggregates_with_distinct2() { let plan = sql_to_optimized_ir(input, vec![]); 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_34"::unsigned -> "column_34", "column_12"::unsigned -> "column_12") - motion [policy: segment([ref("column_12")])] + r#"projection ("column_764"::unsigned -> "b", sum(distinct ("column_1232"::decimal))::decimal -> "col_1") + group by ("column_764"::unsigned) output: ("column_1232"::unsigned -> "column_1232", "column_764"::unsigned -> "column_764") + motion [policy: segment([ref("column_764")])] scan - projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) + ROW(3::unsigned) -> "column_34", "t"."b"::unsigned -> "column_12") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) + ROW(3::unsigned) -> "column_1232", "t"."b"::unsigned -> "column_764") 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: @@ -1834,10 +1834,10 @@ fn front_sql_aggregates_with_distinct3() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (sum(distinct ("column_19"::decimal))::decimal -> "col_1") + r#"projection (sum(distinct ("column_632"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) + ROW(3::unsigned) -> "column_19") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) + ROW(3::unsigned) -> "column_632") group by (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: @@ -1962,12 +1962,12 @@ fn front_sql_pg_style_params3() { let plan = sql_to_optimized_ir(input, vec![Value::Unsigned(42)]); let expected_explain = String::from( - r#"projection ("column_31"::unsigned -> "col_1") - having ROW(sum(("count_46"::integer))::decimal) > ROW(42::unsigned) - group by ("column_31"::unsigned) output: ("column_31"::unsigned -> "column_31", "count_46"::integer -> "count_46") - motion [policy: segment([ref("column_31")])] + r#"projection ("column_1132"::unsigned -> "col_1") + having ROW(sum(("count_096"::integer))::decimal) > ROW(42::unsigned) + group by ("column_1132"::unsigned) output: ("column_1132"::unsigned -> "column_1132", "count_096"::integer -> "count_096") + motion [policy: segment([ref("column_1132")])] scan - projection (ROW("t"."a"::unsigned) + ROW(42::unsigned) -> "column_31", count(("t"."b"::unsigned))::integer -> "count_46") + projection (ROW("t"."a"::unsigned) + ROW(42::unsigned) -> "column_1132", count(("t"."b"::unsigned))::integer -> "count_096") group by (ROW("t"."a"::unsigned) + ROW(42::unsigned)) output: ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d", "t"."bucket_id"::unsigned -> "bucket_id") selection ROW("t"."a"::unsigned) = ROW(42::unsigned) scan "t" @@ -2045,10 +2045,10 @@ fn front_sql_aggregate_without_groupby() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (sum(("sum_20"::decimal))::decimal -> "col_1") + r#"projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum((ROW("t"."a"::unsigned) * ROW("t"."b"::unsigned) + ROW(1::unsigned)))::decimal -> "sum_20") + projection (sum((ROW("t"."a"::unsigned) * ROW("t"."b"::unsigned) + ROW(1::unsigned)))::decimal -> "sum_096") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2068,10 +2068,10 @@ fn front_sql_aggregate_without_groupby2() { let expected_explain = String::from( r#"projection ("t1"."col_1"::integer -> "col_1") scan "t1" - projection (sum(("count_13"::integer))::decimal -> "col_1") + projection (sum(("count_096"::integer))::decimal -> "col_1") motion [policy: full] scan - projection (count(("test_space"."id"::unsigned))::integer -> "count_13") + projection (count(("test_space"."id"::unsigned))::integer -> "count_096") scan "test_space" execution options: sql_vdbe_max_steps = 45000 @@ -2092,10 +2092,10 @@ fn front_sql_aggregate_on_aggregate() { let expected_explain = String::from( r#"projection (max(("t1"."c"::integer))::scalar -> "col_1") scan "t1" - projection (sum(("count_13"::integer))::decimal -> "c") + projection (sum(("count_096"::integer))::decimal -> "c") motion [policy: full] scan - projection (count(("test_space"."id"::unsigned))::integer -> "count_13") + projection (count(("test_space"."id"::unsigned))::integer -> "count_096") scan "test_space" execution options: sql_vdbe_max_steps = 45000 @@ -2121,10 +2121,10 @@ fn front_sql_union_single_left() { projection ("t"."a"::unsigned -> "a") scan "t" motion [policy: segment([ref("col_1")])] - projection (sum(("sum_29"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_29") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2148,10 +2148,10 @@ fn front_sql_union_single_right() { let expected_explain = String::from( r#"union all motion [policy: segment([ref("col_1")])] - projection (sum(("sum_13"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_13") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096") scan "t" projection ("t"."a"::unsigned -> "a") scan "t" @@ -2177,16 +2177,16 @@ fn front_sql_union_single_both() { let expected_explain = String::from( r#"union all motion [policy: segment([ref("col_1")])] - projection (sum(("sum_13"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_13") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096") scan "t" motion [policy: segment([ref("col_1")])] - projection (sum(("sum_30"::decimal))::decimal -> "col_1") + projection (sum(("sum_196"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_30") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_196") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2206,10 +2206,10 @@ fn front_sql_insert_single() { let expected_explain = String::from( r#"insert "t" on conflict: fail motion [policy: segment([value(NULL), ref("col_2")])] - projection (sum(("sum_13"::decimal))::decimal -> "col_1", sum(("count_16"::integer))::decimal -> "col_2") + projection (sum(("sum_096"::decimal))::decimal -> "col_1", sum(("count_196"::integer))::decimal -> "col_2") motion [policy: full] scan - projection (count(("t"."d"::unsigned))::integer -> "count_16", sum(("t"."b"::unsigned))::decimal -> "sum_13") + projection (count(("t"."d"::unsigned))::integer -> "count_196", sum(("t"."b"::unsigned))::decimal -> "sum_096") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2233,10 +2233,10 @@ fn front_sql_except_single_right() { projection ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b") scan "t" motion [policy: segment([ref("col_1"), ref("col_2")])] - projection (sum(("sum_31"::decimal))::decimal -> "col_1", sum(("count_34"::integer))::decimal -> "col_2") + projection (sum(("sum_096"::decimal))::decimal -> "col_1", sum(("count_196"::integer))::decimal -> "col_2") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_31", count(("t"."b"::unsigned))::integer -> "count_34") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096", count(("t"."b"::unsigned))::integer -> "count_196") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2258,10 +2258,10 @@ vtable_max_rows = 5000 projection ("t"."b"::unsigned -> "b", "t"."a"::unsigned -> "a") scan "t" motion [policy: segment([ref("col_2"), ref("col_1")])] - projection (sum(("sum_31"::decimal))::decimal -> "col_1", sum(("count_34"::integer))::decimal -> "col_2") + projection (sum(("sum_096"::decimal))::decimal -> "col_1", sum(("count_196"::integer))::decimal -> "col_2") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_31", count(("t"."b"::unsigned))::integer -> "count_34") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096", count(("t"."b"::unsigned))::integer -> "count_196") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2283,10 +2283,10 @@ fn front_sql_except_single_left() { let expected_explain = String::from( r#"except motion [policy: segment([ref("col_1"), ref("col_2")])] - projection (sum(("sum_13"::decimal))::decimal -> "col_1", sum(("count_16"::integer))::decimal -> "col_2") + projection (sum(("sum_096"::decimal))::decimal -> "col_1", sum(("count_196"::integer))::decimal -> "col_2") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_13", count(("t"."b"::unsigned))::integer -> "count_16") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096", count(("t"."b"::unsigned))::integer -> "count_196") scan "t" projection ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b") scan "t" @@ -2311,16 +2311,16 @@ fn front_sql_except_single_both() { let expected_explain = String::from( r#"except motion [policy: segment([ref("col_1")])] - projection (sum(("sum_13"::decimal))::decimal -> "col_1", sum(("count_16"::integer))::decimal -> "col_2") + projection (sum(("sum_096"::decimal))::decimal -> "col_1", sum(("count_196"::integer))::decimal -> "col_2") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_13", count(("t"."b"::unsigned))::integer -> "count_16") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096", count(("t"."b"::unsigned))::integer -> "count_196") scan "t" motion [policy: segment([ref("col_1")])] - projection (sum(("sum_33"::decimal))::decimal -> "col_1", sum(("sum_36"::decimal))::decimal -> "col_2") + projection (sum(("sum_296"::decimal))::decimal -> "col_1", sum(("sum_396"::decimal))::decimal -> "col_2") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_33", sum(("t"."b"::unsigned))::decimal -> "sum_36") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_296", sum(("t"."b"::unsigned))::decimal -> "sum_396") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2339,11 +2339,11 @@ fn front_sql_groupby_expression() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection ("column_16"::unsigned -> "col_1") - group by ("column_16"::unsigned) output: ("column_16"::unsigned -> "column_16") - motion [policy: segment([ref("column_16")])] + r#"projection ("column_532"::unsigned -> "col_1") + group by ("column_532"::unsigned) output: ("column_532"::unsigned -> "column_532") + motion [policy: segment([ref("column_532")])] scan - projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_16") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_532") group by (ROW("t"."a"::unsigned) + ROW("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: @@ -2363,11 +2363,11 @@ fn front_sql_groupby_expression2() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection ("column_17"::unsigned + ROW(sum(("count_37"::integer))::decimal) -> "col_1") - group by ("column_17"::unsigned) output: ("column_17"::unsigned -> "column_17", "count_37"::integer -> "count_37") - motion [policy: segment([ref("column_17")])] + r#"projection ("column_632"::unsigned + ROW(sum(("count_096"::integer))::decimal) -> "col_1") + group by ("column_632"::unsigned) output: ("column_632"::unsigned -> "column_632", "count_096"::integer -> "count_096") + motion [policy: segment([ref("column_632")])] scan - projection ((ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned)) -> "column_17", count(("t"."a"::unsigned))::integer -> "count_37") + projection ((ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned)) -> "column_632", count(("t"."a"::unsigned))::integer -> "count_096") group by ((ROW("t"."a"::unsigned) + ROW("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: @@ -2387,11 +2387,11 @@ fn front_sql_groupby_expression3() { let plan = sql_to_optimized_ir(input, vec![]); 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_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")])] + r#"projection ("column_532"::unsigned -> "col_1", "column_832"::unsigned * ROW(sum(("sum_096"::decimal))::decimal) / ROW(sum(("count_196"::integer))::decimal) -> "col_2") + group by ("column_532"::unsigned, "column_832"::unsigned) output: ("column_532"::unsigned -> "column_532", "column_832"::unsigned -> "column_832", "count_196"::integer -> "count_196", "sum_096"::decimal -> "sum_096") + motion [policy: segment([ref("column_532"), ref("column_832")])] scan - 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") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_532", (ROW("t"."c"::unsigned) * ROW("t"."d"::unsigned)) -> "column_832", count((ROW("t"."a"::unsigned) * ROW("t"."b"::unsigned)))::integer -> "count_196", sum((ROW("t"."c"::unsigned) * ROW("t"."d"::unsigned)))::decimal -> "sum_096") 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: @@ -2411,11 +2411,11 @@ fn front_sql_groupby_expression4() { let plan = sql_to_optimized_ir(input, vec![]); 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_16"::unsigned -> "column_16", "column_17"::unsigned -> "column_17") - motion [policy: segment([ref("column_16"), ref("column_17")])] + r#"projection ("column_532"::unsigned -> "col_1", "column_1164"::unsigned -> "a") + group by ("column_532"::unsigned, "column_1164"::unsigned) output: ("column_1164"::unsigned -> "column_1164", "column_532"::unsigned -> "column_532") + motion [policy: segment([ref("column_532"), ref("column_1164")])] scan - projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_16", "t"."a"::unsigned -> "column_17") + projection ("t"."a"::unsigned -> "column_1164", ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_532") 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: @@ -2440,20 +2440,20 @@ fn front_sql_groupby_with_aggregates() { r#"projection ("t1"."a"::unsigned -> "a", "t1"."b"::unsigned -> "b", "t1"."c"::decimal -> "c", "t2"."g"::unsigned -> "g", "t2"."e"::unsigned -> "e", "t2"."f"::decimal -> "f") 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_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12", "sum_31"::decimal -> "sum_31") - motion [policy: segment([ref("column_13"), ref("column_12")])] + projection ("column_764"::unsigned -> "a", "column_864"::unsigned -> "b", sum(("sum_096"::decimal))::decimal -> "c") + group by ("column_864"::unsigned, "column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_864"::unsigned -> "column_864", "sum_096"::decimal -> "sum_096") + motion [policy: segment([ref("column_864"), ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_13", "t"."a"::unsigned -> "column_12", sum(("t"."c"::unsigned))::decimal -> "sum_31") + projection ("t"."a"::unsigned -> "column_764", "t"."b"::unsigned -> "column_864", sum(("t"."c"::unsigned))::decimal -> "sum_096") 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_55"::unsigned -> "column_55", "column_56"::unsigned -> "column_56", "sum_74"::decimal -> "sum_74") - motion [policy: segment([ref("column_55"), ref("column_56")])] + projection ("column_3364"::unsigned -> "g", "column_3464"::unsigned -> "e", sum(("sum_196"::decimal))::decimal -> "f") + group by ("column_3364"::unsigned, "column_3464"::unsigned) output: ("column_3464"::unsigned -> "column_3464", "column_3364"::unsigned -> "column_3364", "sum_196"::decimal -> "sum_196") + motion [policy: segment([ref("column_3364"), ref("column_3464")])] scan - projection ("t2"."g"::unsigned -> "column_55", "t2"."e"::unsigned -> "column_56", sum(("t2"."f"::unsigned))::decimal -> "sum_74") + projection ("t2"."e"::unsigned -> "column_3464", "t2"."g"::unsigned -> "column_3364", sum(("t2"."f"::unsigned))::decimal -> "sum_196") 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: @@ -2509,10 +2509,10 @@ fn front_sql_left_join_single_left() { left join on ROW("t1"."a"::decimal) = ROW("t2"."b"::unsigned) motion [policy: segment([ref("a")])] scan "t1" - projection (ROW(sum(("sum_14"::decimal))::decimal) / ROW(3::unsigned) -> "a") + projection (ROW(sum(("sum_096"::decimal))::decimal) / ROW(3::unsigned) -> "a") motion [policy: full] scan - projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_14") + projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_096") scan "test_space" motion [policy: full] scan "t2" @@ -2544,10 +2544,10 @@ fn front_sql_left_join_single_left2() { left join on ROW("t1"."a"::decimal) + ROW(3::unsigned) <> ROW("t2"."b"::unsigned) motion [policy: segment([ref("a")])] scan "t1" - projection (ROW(sum(("sum_14"::decimal))::decimal) / ROW(3::unsigned) -> "a") + projection (ROW(sum(("sum_096"::decimal))::decimal) / ROW(3::unsigned) -> "a") motion [policy: full] scan - projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_14") + projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_096") scan "test_space" motion [policy: full] scan "t2" @@ -2578,16 +2578,16 @@ fn front_sql_left_join_single_both() { r#"projection ("t1"."a"::decimal -> "a", "t2"."b"::integer -> "b") left join on ROW("t1"."a"::decimal) <> ROW("t2"."b"::integer) scan "t1" - projection (ROW(sum(("sum_14"::decimal))::decimal) / ROW(3::unsigned) -> "a") + projection (ROW(sum(("sum_096"::decimal))::decimal) / ROW(3::unsigned) -> "a") motion [policy: full] scan - projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_14") + projection (sum(("test_space"."id"::unsigned))::decimal -> "sum_096") scan "test_space" scan "t2" - projection (sum(("count_38"::integer))::decimal -> "b") + projection (sum(("count_196"::integer))::decimal -> "b") motion [policy: full] scan - projection (count(("test_space"."id"::unsigned))::integer -> "count_38") + projection (count(("test_space"."id"::unsigned))::integer -> "count_196") scan "test_space" execution options: sql_vdbe_max_steps = 45000 @@ -2638,12 +2638,12 @@ fn front_sql_having1() { let plan = sql_to_optimized_ir(input, vec![]); 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_27"::unsigned -> "column_27", "column_12"::unsigned -> "column_12", "sum_52"::decimal -> "sum_52") - motion [policy: segment([ref("column_12")])] + r#"projection ("column_764"::unsigned -> "a", sum(("sum_196"::decimal))::decimal -> "col_1") + having ROW("column_764"::unsigned) > ROW(1::unsigned) and ROW(sum(distinct ("column_1764"::decimal))::decimal) > ROW(1::unsigned) + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_1764"::unsigned -> "column_1764", "sum_196"::decimal -> "sum_196") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_27", "t"."a"::unsigned -> "column_12", sum(("t"."b"::unsigned))::decimal -> "sum_52") + projection ("t"."a"::unsigned -> "column_764", "t"."b"::unsigned -> "column_1764", sum(("t"."b"::unsigned))::decimal -> "sum_196") 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: @@ -2663,11 +2663,11 @@ fn front_sql_having2() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (ROW(sum(("sum_39"::decimal))::decimal) * ROW(count(distinct ("column_38"::integer))::integer) -> "col_1", sum(("sum_39"::decimal))::decimal -> "col_2") - having ROW(sum(distinct ("column_38"::decimal))::decimal) > ROW(1::unsigned) and ROW(sum(("sum_39"::decimal))::decimal) > ROW(1::unsigned) + r#"projection (ROW(sum(("sum_296"::decimal))::decimal) * ROW(count(distinct ("column_2364"::integer))::integer) -> "col_1", sum(("sum_296"::decimal))::decimal -> "col_2") + having ROW(sum(distinct ("column_2364"::decimal))::decimal) > ROW(1::unsigned) and ROW(sum(("sum_296"::decimal))::decimal) > ROW(1::unsigned) motion [policy: full] scan - projection ("t"."b"::unsigned -> "column_38", sum(("t"."a"::unsigned))::decimal -> "sum_39") + projection ("t"."b"::unsigned -> "column_2364", sum(("t"."a"::unsigned))::decimal -> "sum_296") group by ("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: @@ -2687,11 +2687,11 @@ fn front_sql_having3() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (sum(("sum_31"::decimal))::decimal -> "col_1") - having ROW(sum(("sum_31"::decimal))::decimal) > ROW(1::unsigned) + r#"projection (sum(("sum_196"::decimal))::decimal -> "col_1") + having ROW(sum(("sum_196"::decimal))::decimal) > ROW(1::unsigned) motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_31") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_196") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2728,12 +2728,12 @@ fn front_sql_having_with_sq() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection ("column_12"::unsigned -> "sysFrom", sum(distinct ("column_80"::decimal))::decimal -> "sum", count(distinct ("column_80"::integer))::integer -> "count") - having ROW($0) > ROW(count(distinct ("column_80"::integer))::integer) - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_80"::unsigned -> "column_80") - motion [policy: segment([ref("column_12")])] + r#"projection ("column_764"::unsigned -> "sysFrom", sum(distinct ("column_4964"::decimal))::decimal -> "sum", count(distinct ("column_4964"::integer))::integer -> "count") + having ROW($0) > ROW(count(distinct ("column_4964"::integer))::integer) + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_4964"::unsigned -> "column_4964") + motion [policy: segment([ref("column_764")])] scan - projection ("test_space"."sysFrom"::unsigned -> "column_12", "test_space"."id"::unsigned -> "column_80") + projection ("test_space"."sysFrom"::unsigned -> "column_764", "test_space"."id"::unsigned -> "column_4964") group by ("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: @@ -2780,12 +2780,12 @@ fn front_sql_having_with_sq_segment_motion() { println!("{}", plan.as_explain().unwrap()); 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_70"::unsigned -> "column_70", "column_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12") - motion [policy: segment([ref("column_13"), ref("column_12")])] + r#"projection ("column_764"::unsigned -> "sysFrom", "column_864"::unsigned -> "sys_op", sum(distinct ("column_4364"::decimal))::decimal -> "sum", count(distinct ("column_4364"::integer))::integer -> "count") + having ROW("column_764"::unsigned, "column_864"::unsigned) in ROW($0, $0) + group by ("column_864"::unsigned, "column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_4364"::unsigned -> "column_4364", "column_864"::unsigned -> "column_864") + motion [policy: segment([ref("column_864"), ref("column_764")])] scan - projection ("test_space"."id"::unsigned -> "column_70", "test_space"."sys_op"::unsigned -> "column_13", "test_space"."sysFrom"::unsigned -> "column_12") + projection ("test_space"."sysFrom"::unsigned -> "column_764", "test_space"."id"::unsigned -> "column_4364", "test_space"."sys_op"::unsigned -> "column_864") 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: @@ -2816,12 +2816,12 @@ fn front_sql_having_with_sq_segment_local_motion() { println!("{}", plan.as_explain().unwrap()); 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_70"::unsigned -> "column_70", "column_13"::unsigned -> "column_13", "column_12"::unsigned -> "column_12") - motion [policy: segment([ref("column_13"), ref("column_12")])] + r#"projection ("column_764"::unsigned -> "sysFrom", "column_864"::unsigned -> "sys_op", sum(distinct ("column_4364"::decimal))::decimal -> "sum", count(distinct ("column_4364"::integer))::integer -> "count") + having ROW("column_764"::unsigned, "column_864"::unsigned) in ROW($0, $0) + group by ("column_864"::unsigned, "column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_4364"::unsigned -> "column_4364", "column_864"::unsigned -> "column_864") + motion [policy: segment([ref("column_864"), ref("column_764")])] scan - projection ("test_space"."id"::unsigned -> "column_70", "test_space"."sys_op"::unsigned -> "column_13", "test_space"."sysFrom"::unsigned -> "column_12") + projection ("test_space"."sysFrom"::unsigned -> "column_764", "test_space"."id"::unsigned -> "column_4364", "test_space"."sys_op"::unsigned -> "column_864") 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: @@ -2847,10 +2847,10 @@ fn front_sql_unique_local_aggregates() { println!("{}", plan.as_explain().unwrap()); // here we must compute only two aggregates at local stage: sum(a), count(a) let expected_explain = String::from( - r#"projection (sum(("sum_13"::decimal))::decimal -> "col_1", sum(("count_16"::integer))::decimal -> "col_2", ROW(sum(("sum_13"::decimal))::decimal) + ROW(sum(("count_16"::integer))::decimal) -> "col_3") + r#"projection (sum(("sum_096"::decimal))::decimal -> "col_1", sum(("count_196"::integer))::decimal -> "col_2", ROW(sum(("sum_096"::decimal))::decimal) + ROW(sum(("count_196"::integer))::decimal) -> "col_3") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_13", count(("t"."a"::unsigned))::integer -> "count_16") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096", count(("t"."a"::unsigned))::integer -> "count_196") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -2871,11 +2871,11 @@ fn front_sql_unique_local_groupings() { let plan = sql_to_optimized_ir(input, vec![]); // here we must compute only two groupby columns at local stage: a, b let expected_explain = String::from( - r#"projection (sum(distinct ("column_25"::decimal))::decimal -> "col_1", count(distinct ("column_25"::integer))::integer -> "col_2", count(distinct ("column_12"::integer))::integer -> "col_3") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "column_25"::unsigned -> "column_25") - motion [policy: segment([ref("column_12")])] + r#"projection (sum(distinct ("column_1564"::decimal))::decimal -> "col_1", count(distinct ("column_1564"::integer))::integer -> "col_2", count(distinct ("column_764"::integer))::integer -> "col_3") + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "column_1564"::unsigned -> "column_1564") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_12", "t"."a"::unsigned -> "column_25") + projection ("t"."b"::unsigned -> "column_764", "t"."a"::unsigned -> "column_1564") 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" execution options: @@ -2936,11 +2936,11 @@ fn front_sql_select_distinct() { println!("{}", plan.as_explain().unwrap()); // 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_27"::unsigned -> "column_27", "column_22"::unsigned -> "column_22") - motion [policy: segment([ref("column_27"), ref("column_22")])] + r#"projection ("column_1464"::unsigned -> "a", "column_832"::unsigned -> "col_1") + group by ("column_832"::unsigned, "column_1464"::unsigned) output: ("column_832"::unsigned -> "column_832", "column_1464"::unsigned -> "column_1464") + motion [policy: segment([ref("column_832"), ref("column_1464")])] scan - projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_27", "t"."a"::unsigned -> "column_22") + projection (ROW("t"."a"::unsigned) + ROW("t"."b"::unsigned) -> "column_832", "t"."a"::unsigned -> "column_1464") 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: @@ -2959,11 +2959,11 @@ fn front_sql_select_distinct_asterisk() { let plan = sql_to_optimized_ir(input, vec![]); 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_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")])] + r#"projection ("column_1464"::unsigned -> "a", "column_1564"::unsigned -> "b", "column_1664"::unsigned -> "c", "column_1764"::unsigned -> "d") + group by ("column_1564"::unsigned, "column_1464"::unsigned, "column_1664"::unsigned, "column_1764"::unsigned) output: ("column_1464"::unsigned -> "column_1464", "column_1564"::unsigned -> "column_1564", "column_1664"::unsigned -> "column_1664", "column_1764"::unsigned -> "column_1764") + motion [policy: segment([ref("column_1564"), ref("column_1464"), ref("column_1664"), ref("column_1764")])] scan - projection ("t"."a"::unsigned -> "column_23", "t"."d"::unsigned -> "column_26", "t"."c"::unsigned -> "column_25", "t"."b"::unsigned -> "column_24") + projection ("t"."a"::unsigned -> "column_1464", "t"."b"::unsigned -> "column_1564", "t"."c"::unsigned -> "column_1664", "t"."d"::unsigned -> "column_1764") 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: @@ -2998,11 +2998,11 @@ fn front_sql_select_distinct_with_aggr() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (sum(("sum_26"::decimal))::decimal -> "col_1", "column_12"::unsigned -> "b") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "sum_26"::decimal -> "sum_26") - motion [policy: segment([ref("column_12")])] + r#"projection (sum(("sum_096"::decimal))::decimal -> "col_1", "column_764"::unsigned -> "b") + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "sum_096"::decimal -> "sum_096") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_12", sum(("t"."a"::unsigned))::decimal -> "sum_26") + projection ("t"."b"::unsigned -> "column_764", sum(("t"."a"::unsigned))::decimal -> "sum_096") group by ("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: @@ -3020,10 +3020,10 @@ fn front_sql_select_distinct_with_aggr2() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( - r#"projection (sum(("sum_13"::decimal))::decimal -> "col_1") + r#"projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_13") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -3380,10 +3380,10 @@ fn front_sql_update6() { subquery $0: motion [policy: full] scan - projection (sum(("sum_17"::decimal))::decimal -> "s") + projection (sum(("sum_096"::decimal))::decimal -> "s") motion [policy: full] scan - projection (sum(("t3"."b"::integer))::decimal -> "sum_17") + projection (sum(("t3"."b"::integer))::decimal -> "sum_096") scan "t3" execution options: sql_vdbe_max_steps = 45000 diff --git a/sbroad-core/src/frontend/sql/ir/tests/ddl.rs b/sbroad-core/src/frontend/sql/ir/tests/ddl.rs index 405e766d7..128101118 100644 --- a/sbroad-core/src/frontend/sql/ir/tests/ddl.rs +++ b/sbroad-core/src/frontend/sql/ir/tests/ddl.rs @@ -1,14 +1,14 @@ -use crate::frontend::Ast; +use crate::{ + frontend::Ast, + ir::node::{ddl::Ddl, CreateTable}, +}; use pretty_assertions::assert_eq; use smol_str::{SmolStr, ToSmolStr}; use crate::{ executor::engine::mock::RouterConfigurationMock, frontend::sql::ast::AbstractSyntaxTree, - ir::{ - ddl::{ColumnDef, Ddl}, - relation::Type, - }, + ir::{ddl::ColumnDef, relation::Type}, }; #[test] @@ -20,11 +20,11 @@ fn infer_not_null_on_pk1() { let top_id = plan.get_top().unwrap(); let top_node = plan.get_ddl_node(top_id).unwrap(); - let Ddl::CreateTable { + let Ddl::CreateTable(CreateTable { format, primary_key, .. - } = top_node + }) = top_node else { panic!("expected create table") }; @@ -51,11 +51,11 @@ fn infer_not_null_on_pk2() { let top_id = plan.get_top().unwrap(); let top_node = plan.get_ddl_node(top_id).unwrap(); - let Ddl::CreateTable { + let Ddl::CreateTable(CreateTable { format, primary_key, .. - } = top_node + }) = top_node else { panic!("expected create table") }; @@ -107,7 +107,7 @@ fn infer_sk_from_pk() { let top_id = plan.get_top().unwrap(); let top_node = plan.get_ddl_node(top_id).unwrap(); - let Ddl::CreateTable { sharding_key, .. } = top_node else { + let Ddl::CreateTable(CreateTable { sharding_key, .. }) = top_node else { panic!("expected create table") }; diff --git a/sbroad-core/src/frontend/sql/ir/tests/global.rs b/sbroad-core/src/frontend/sql/ir/tests/global.rs index e067aed43..ecae11c8a 100644 --- a/sbroad-core/src/frontend/sql/ir/tests/global.rs +++ b/sbroad-core/src/frontend/sql/ir/tests/global.rs @@ -1,10 +1,10 @@ use crate::ir::distribution::Distribution; -use crate::ir::expression::NodeId; -use crate::ir::operator::Relational; +use crate::ir::node::relational::Relational; +use crate::ir::node::{Node, NodeId}; use crate::ir::transformation::helpers::sql_to_optimized_ir; use crate::ir::tree::traversal::{FilterFn, LevelNode, PostOrderWithFilter, REL_CAPACITY}; use crate::ir::value::Value; -use crate::ir::{Node, Plan}; +use crate::ir::Plan; use pretty_assertions::assert_eq; #[derive(PartialEq, Eq, Debug)] @@ -48,10 +48,8 @@ fn check_distributions( nodes.len(), "different number of nodes" ); - 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(); + for (LevelNode(level, id), expected) in nodes.iter().zip(expected_distributions.iter()) { + let actual: DistMock = plan.get_rel_distribution(*id).unwrap().into(); assert_eq!( expected, &actual, "wrong distribution for node ({id:?}) at level {level}" @@ -63,7 +61,7 @@ fn check_selection_dist(plan: &Plan, expected_dist: DistMock) { let filter = |id: NodeId| -> bool { matches!( plan.get_node(id), - Ok(Node::Relational(Relational::Selection { .. })) + Ok(Node::Relational(Relational::Selection(_))) ) }; let nodes = collect_relational(plan, Box::new(filter)); @@ -93,10 +91,10 @@ motion [policy: full] scan "t" subquery $1: scan - projection (sum(("sum_39"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_39") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096") scan "t" execution options: sql_vdbe_max_steps = 45000 @@ -125,10 +123,10 @@ fn front_sql_global_tbl_multiple_sqs1() { scan "global_t" subquery $0: scan - projection (sum(("sum_43"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_43") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096") scan "t" subquery $1: scan @@ -163,10 +161,10 @@ fn front_sql_global_tbl_multiple_sqs2() { scan "global_t" subquery $0: scan - projection (sum(("sum_43"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t"."a"::unsigned))::decimal -> "sum_43") + projection (sum(("t"."a"::unsigned))::decimal -> "sum_096") scan "t" subquery $1: motion [policy: full] @@ -366,7 +364,7 @@ fn front_sql_global_tbl_sq7() { let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( r#"projection ("t"."a"::unsigned -> "a", "t2"."f"::unsigned -> "f") - join on ROW("t"."a"::unsigned, "t"."b"::unsigned) = ROW("t2"."e"::unsigned, "t2"."f"::unsigned) or ROW("t"."c"::unsigned) in ROW($1) or not ROW("t"."d"::unsigned) in ROW($0) + join on ROW("t"."a"::unsigned, "t"."b"::unsigned) = ROW("t2"."e"::unsigned, "t2"."f"::unsigned) or ROW("t"."c"::unsigned) in ROW($0) or not ROW("t"."d"::unsigned) in ROW($1) scan "t" projection ("t"."a"::unsigned -> "a", "t"."b"::unsigned -> "b", "t"."c"::unsigned -> "c", "t"."d"::unsigned -> "d") scan "t" @@ -392,10 +390,7 @@ vtable_max_rows = 5000 fn check_join_dist(plan: &Plan, expected_distributions: &[DistMock]) { let filter = |id: NodeId| -> bool { - matches!( - plan.get_node(id), - Ok(Node::Relational(Relational::Join { .. })) - ) + matches!(plan.get_node(id), Ok(Node::Relational(Relational::Join(_)))) }; let nodes = collect_relational(plan, Box::new(filter)); check_distributions(plan, &nodes, expected_distributions); @@ -500,10 +495,10 @@ fn front_sql_global_join4() { r#"projection ("s"."e"::decimal -> "e") left join on true::boolean scan "s" - projection (sum(("sum_13"::decimal))::decimal -> "e") + projection (sum(("sum_096"::decimal))::decimal -> "e") motion [policy: full] scan - projection (sum(("t2"."e"::unsigned))::decimal -> "sum_13") + projection (sum(("t2"."e"::unsigned))::decimal -> "sum_096") scan "t2" scan "global_t" projection ("global_t"."a"::integer -> "a", "global_t"."b"::integer -> "b") @@ -534,10 +529,10 @@ fn front_sql_global_join5() { projection ("global_t"."a"::integer -> "a", "global_t"."b"::integer -> "b") scan "global_t" scan "s" - projection (sum(("sum_19"::decimal))::decimal -> "e") + projection (sum(("sum_096"::decimal))::decimal -> "e") motion [policy: full] scan - projection (sum(("t2"."e"::unsigned))::decimal -> "sum_19") + projection (sum(("t2"."e"::unsigned))::decimal -> "sum_096") scan "t2" execution options: sql_vdbe_max_steps = 45000 @@ -819,12 +814,12 @@ fn front_sql_global_aggregate5() { println!("{}", plan.as_explain().unwrap()); let expected_explain = String::from( - r#"projection ("column_44"::integer -> "col_1", sum(("sum_70"::decimal))::decimal -> "col_2") - having ROW(sum(("sum_53"::decimal::double))::decimal / sum(("count_53"::decimal::double))::decimal) > ROW(3::unsigned) - group by ("column_44"::integer) output: ("column_44"::integer -> "column_44", "sum_70"::decimal -> "sum_70", "sum_53"::decimal -> "sum_53", "count_53"::integer -> "count_53") - motion [policy: segment([ref("column_44")])] + r#"projection ("column_1432"::integer -> "col_1", sum(("sum_196"::decimal))::decimal -> "col_2") + having ROW(sum(("sum_096"::decimal::double))::decimal / sum(("count_096"::decimal::double))::decimal) > ROW(3::unsigned) + group by ("column_1432"::integer) output: ("column_1432"::integer -> "column_1432", "sum_196"::decimal -> "sum_196", "sum_096"::decimal -> "sum_096", "count_096"::integer -> "count_096") + motion [policy: segment([ref("column_1432")])] scan - projection (ROW("global_t"."b"::integer) + ROW("global_t"."a"::integer) -> "column_44", sum(("global_t"."a"::integer))::decimal -> "sum_70", sum(("global_t"."b"::integer))::decimal -> "sum_53", count(("global_t"."b"::integer))::integer -> "count_53") + projection (ROW("global_t"."b"::integer) + ROW("global_t"."a"::integer) -> "column_1432", sum(("global_t"."a"::integer))::decimal -> "sum_196", sum(("global_t"."b"::integer))::decimal -> "sum_096", count(("global_t"."b"::integer))::integer -> "count_096") group by (ROW("global_t"."b"::integer) + ROW("global_t"."a"::integer)) output: ("global_t"."a"::integer -> "a", "global_t"."b"::integer -> "b") selection ROW("global_t"."a"::integer, "global_t"."b"::integer) in ROW($0, $0) scan "global_t" @@ -1072,10 +1067,10 @@ fn front_sql_global_union_all3() { projection ("global_t"."a"::integer -> "a") scan "global_t" motion [policy: segment([ref("col_1")])] - projection (sum(("sum_23"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t2"."e"::unsigned))::decimal -> "sum_23") + projection (sum(("t2"."e"::unsigned))::decimal -> "sum_096") scan "t2" motion [policy: local] projection ("global_t"."b"::integer -> "b") @@ -1182,10 +1177,10 @@ fn front_sql_global_union2() { projection ("global_t"."a"::integer -> "a") scan "global_t" motion [policy: segment([ref("col_1")])] - projection (sum(("sum_23"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t2"."e"::unsigned))::decimal -> "sum_23") + projection (sum(("t2"."e"::unsigned))::decimal -> "sum_096") scan "t2" execution options: sql_vdbe_max_steps = 45000 @@ -1332,10 +1327,10 @@ fn check_plan_except_global_vs_single() { r#"except projection ("global_t"."a"::integer -> "a") scan "global_t" - projection (sum(("sum_23"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t2"."e"::unsigned))::decimal -> "sum_23") + projection (sum(("t2"."e"::unsigned))::decimal -> "sum_096") scan "t2" execution options: sql_vdbe_max_steps = 45000 @@ -1357,10 +1352,10 @@ fn check_plan_except_single_vs_global() { let expected_explain = String::from( r#"except - projection (sum(("sum_13"::decimal))::decimal -> "col_1") + projection (sum(("sum_096"::decimal))::decimal -> "col_1") motion [policy: full] scan - projection (sum(("t2"."e"::unsigned))::decimal -> "sum_13") + projection (sum(("t2"."e"::unsigned))::decimal -> "sum_096") scan "t2" projection ("global_t"."a"::integer -> "a") scan "global_t" diff --git a/sbroad-core/src/frontend/sql/ir/tests/limit.rs b/sbroad-core/src/frontend/sql/ir/tests/limit.rs index 1787f244c..672ffadb6 100644 --- a/sbroad-core/src/frontend/sql/ir/tests/limit.rs +++ b/sbroad-core/src/frontend/sql/ir/tests/limit.rs @@ -48,17 +48,17 @@ vtable_max_rows = 5000 } #[test] -fn aggretage() { +fn aggregate() { let input = r#"SELECT min("b"), min(distinct "b") FROM "t" LIMIT 1"#; let plan = sql_to_optimized_ir(input, vec![]); let expected_explain = String::from( r#"limit 1 - projection (min(("min_13"::unsigned))::scalar -> "col_1", min(distinct ("column_15"::unsigned))::scalar -> "col_2") + projection (min(("min_096"::unsigned))::scalar -> "col_1", min(distinct ("column_864"::unsigned))::scalar -> "col_2") motion [policy: full] scan - projection ("t"."b"::unsigned -> "column_15", min(("t"."b"::unsigned))::scalar -> "min_13") + projection ("t"."b"::unsigned -> "column_864", min(("t"."b"::unsigned))::scalar -> "min_096") group by ("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: @@ -80,11 +80,11 @@ fn group_by() { r#"limit 555 motion [policy: full] limit 555 - projection (sum(("count_26"::integer))::decimal -> "col_1", "column_12"::unsigned -> "b") - group by ("column_12"::unsigned) output: ("column_12"::unsigned -> "column_12", "count_26"::integer -> "count_26") - motion [policy: segment([ref("column_12")])] + projection (sum(("count_096"::integer))::decimal -> "col_1", "column_764"::unsigned -> "b") + group by ("column_764"::unsigned) output: ("column_764"::unsigned -> "column_764", "count_096"::integer -> "count_096") + motion [policy: segment([ref("column_764")])] scan - projection ("t"."b"::unsigned -> "column_12", count((*::integer))::integer -> "count_26") + projection ("t"."b"::unsigned -> "column_764", count((*::integer))::integer -> "count_096") group by ("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: diff --git a/sbroad-core/src/frontend/sql/ir/tests/single.rs b/sbroad-core/src/frontend/sql/ir/tests/single.rs index 798f10e8b..df31f7c17 100644 --- a/sbroad-core/src/frontend/sql/ir/tests/single.rs +++ b/sbroad-core/src/frontend/sql/ir/tests/single.rs @@ -1,7 +1,7 @@ use smol_str::{SmolStr, ToSmolStr}; -use crate::ir::expression::NodeId; -use crate::ir::operator::Relational; +use crate::ir::node::relational::Relational; +use crate::ir::node::{Motion, NodeId}; use crate::ir::transformation::helpers::sql_to_optimized_ir; use crate::ir::transformation::redistribution::{MotionKey, MotionPolicy, Target}; use crate::ir::tree::traversal::{PostOrder, REL_CAPACITY}; @@ -35,7 +35,7 @@ impl Plan { let node = self.get_relation_node(node_id).unwrap(); match node { - Relational::Motion { policy, .. } => match policy { + Relational::Motion(Motion { policy, .. }) => match policy { MotionPolicy::None => Policy::None, MotionPolicy::Full => Policy::Full, MotionPolicy::Local => Policy::Local, @@ -81,7 +81,7 @@ fn check_join_motions( .iter(plan.get_top().unwrap()) .find(|level_node| -> bool { let rel = plan.get_relation_node(level_node.1).unwrap(); - matches!(rel, Relational::Join { .. }) + matches!(rel, Relational::Join(_)) }) .unwrap(); let join_id = level_node.1; diff --git a/sbroad-core/src/ir.rs b/sbroad-core/src/ir.rs index 10732d04a..9f1ad55fa 100644 --- a/sbroad-core/src/ir.rs +++ b/sbroad-core/src/ir.rs @@ -1,32 +1,37 @@ -//! Intermediate representation (IR) module. -//! //! Contains the logical plan tree and helpers. use base64ct::{Base64, Encoding}; +use expression::Position; +use node::acl::{Acl, MutAcl}; +use node::block::{Block, MutBlock}; +use node::ddl::{Ddl, MutDdl}; +use node::expression::{Expression, MutExpression}; +use node::relational::{MutRelational, Relational}; +use node::{Invalid, Parameter, SizeNode}; use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use std::cell::{RefCell, RefMut}; use std::collections::hash_map::IntoIter; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; +use std::slice::Iter; use tree::traversal::LevelNode; -use std::slice::Iter; use tarantool::tlua; -use acl::Acl; -use block::Block; -use ddl::Ddl; -use expression::Expression; -use operator::{Arithmetic, Relational}; +use operator::Arithmetic; use relation::{Table, Type}; use crate::errors::Entity::Query; use crate::errors::{Action, Entity, SbroadError, TypeError}; use crate::executor::engine::helpers::to_user; use crate::executor::engine::TableVersionMap; -use crate::ir::expression::Expression::StableFunction; use crate::ir::helpers::RepeatableState; +use crate::ir::node::{ + Alias, ArenaType, ArithmeticExpr, BoolExpr, Case, Cast, Concat, Constant, ExprInParentheses, + GroupBy, Insert, Motion, MutNode, Node, Node136, Node224, Node32, Node64, Node96, NodeId, + NodeOwned, Projection, Reference, Row, ScanRelation, StableFunction, Trim, UnaryExpr, Values, +}; use crate::ir::operator::Bool; use crate::ir::relation::Column; use crate::ir::tree::traversal::{ @@ -36,7 +41,6 @@ use crate::ir::undo::TransformationLog; use crate::ir::value::Value; use crate::{collection, error, warn}; -use self::expression::{NodeId, Position}; use self::parameters::Parameters; use self::relation::Relations; use self::transformation::redistribution::MotionPolicy; @@ -51,6 +55,7 @@ pub mod distribution; pub mod expression; pub mod function; pub mod helpers; +pub mod node; pub mod operator; pub mod parameters; pub mod relation; @@ -62,124 +67,388 @@ pub mod value; const DEFAULT_VTABLE_MAX_ROWS: u64 = 5000; const DEFAULT_VDBE_MAX_STEPS: u64 = 45000; -/// Plan tree node. -/// -/// There are two kinds of node variants: expressions and relational -/// operators. Both of them can easily refer each other in the -/// tree as they are stored in the same node arena. The reasons -/// to separate them are: -/// -/// - they should be treated with quite different logic -/// - we don't want to have a single huge enum -/// -/// Enum was chosen as we don't want to mess with dynamic -/// dispatching and its performance penalties. -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub enum Node { - Acl(Acl), - Block(Block), - Ddl(Ddl), - Expression(Expression), - Relational(Relational), - // The parameter type is inferred from the context. A typical value is None, i. e. any type. - // However, there is a special case where we can be more specific. According to Postgres, - // the parameter type can be specified by casting the parameter to a particular type. - // Thus, when we cast a parameter, we also assign it a type. - 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 { - /// We don't want to mess with the borrow checker and RefCell/Rc, - /// so all nodes are stored in the single arena ("nodes" array). - /// The positions in the array act like pointers, so it is possible + /// The positions in the arrays act like pointers, so it is possible /// only to add nodes to the plan, but never remove them. - arena: Vec<Node>, + arena32: Vec<Node32>, + arena64: Vec<Node64>, + arena96: Vec<Node96>, + arena136: Vec<Node136>, + arena224: Vec<Node224>, } impl Nodes { - pub(crate) fn get(&self, id: NodeId) -> Option<&Node> { - let offset = usize::try_from(id.offset).unwrap(); + pub(crate) fn get(&self, id: NodeId) -> Option<Node> { match id.arena_type { - ArenaType::Default => self.arena.get(offset), + ArenaType::Arena32 => self.arena32.get(id.offset as usize).map(|node| match node { + Node32::Alias(alias) => Node::Expression(Expression::Alias(alias)), + Node32::Arithmetic(arithm) => Node::Expression(Expression::Arithmetic(arithm)), + Node32::Bool(bool) => Node::Expression(Expression::Bool(bool)), + Node32::Concat(concat) => Node::Expression(Expression::Concat(concat)), + Node32::Cast(cast) => Node::Expression(Expression::Cast(cast)), + Node32::CountAsterisk(count) => Node::Expression(Expression::CountAsterisk(count)), + Node32::Except(except) => Node::Relational(Relational::Except(except)), + Node32::ExprInParentheses(expr) => { + Node::Expression(Expression::ExprInParentheses(expr)) + } + Node32::Intersect(intersect) => Node::Relational(Relational::Intersect(intersect)), + Node32::Invalid(inv) => Node::Invalid(inv), + Node32::Limit(limit) => Node::Relational(Relational::Limit(limit)), + Node32::Trim(trim) => Node::Expression(Expression::Trim(trim)), + Node32::Unary(unary) => Node::Expression(Expression::Unary(unary)), + Node32::Union(un) => Node::Relational(Relational::Union(un)), + Node32::UnionAll(union_all) => Node::Relational(Relational::UnionAll(union_all)), + Node32::Values(values) => Node::Relational(Relational::Values(values)), + }), + ArenaType::Arena64 => self.arena64.get(id.offset as usize).map(|node| match node { + Node64::Case(case) => Node::Expression(Expression::Case(case)), + Node64::Constant(constant) => Node::Expression(Expression::Constant(constant)), + Node64::CreateRole(create_role) => Node::Acl(Acl::CreateRole(create_role)), + Node64::Delete(delete) => Node::Relational(Relational::Delete(delete)), + Node64::DropIndex(drop_index) => Node::Ddl(Ddl::DropIndex(drop_index)), + Node64::DropRole(drop_role) => Node::Acl(Acl::DropRole(drop_role)), + Node64::DropTable(drop_table) => Node::Ddl(Ddl::DropTable(drop_table)), + Node64::Row(row) => Node::Expression(Expression::Row(row)), + Node64::DropUser(drop_user) => Node::Acl(Acl::DropUser(drop_user)), + Node64::GroupBy(group_by) => Node::Relational(Relational::GroupBy(group_by)), + Node64::Having(having) => Node::Relational(Relational::Having(having)), + Node64::Join(join) => Node::Relational(Relational::Join(join)), + Node64::OrderBy(order_by) => Node::Relational(Relational::OrderBy(order_by)), + Node64::Parameter(param) => Node::Parameter(param), + Node64::Procedure(proc) => Node::Block(Block::Procedure(proc)), + Node64::Projection(proj) => Node::Relational(Relational::Projection(proj)), + Node64::Reference(reference) => Node::Expression(Expression::Reference(reference)), + Node64::ScanCte(scan_cte) => Node::Relational(Relational::ScanCte(scan_cte)), + Node64::ScanRelation(scan_rel) => { + Node::Relational(Relational::ScanRelation(scan_rel)) + } + Node64::ScanSubQuery(scan_squery) => { + Node::Relational(Relational::ScanSubQuery(scan_squery)) + } + Node64::Selection(sel) => Node::Relational(Relational::Selection(sel)), + Node64::SetParam(set_param) => Node::Ddl(Ddl::SetParam(set_param)), + Node64::SetTransaction(set_trans) => Node::Ddl(Ddl::SetTransaction(set_trans)), + Node64::ValuesRow(values_row) => { + Node::Relational(Relational::ValuesRow(values_row)) + } + }), + ArenaType::Arena96 => self.arena96.get(id.offset as usize).map(|node| match node { + Node96::DropProc(drop_proc) => Node::Ddl(Ddl::DropProc(drop_proc)), + Node96::Insert(insert) => Node::Relational(Relational::Insert(insert)), + Node96::Invalid(inv) => Node::Invalid(inv), + Node96::StableFunction(stable_func) => { + Node::Expression(Expression::StableFunction(stable_func)) + } + }), + ArenaType::Arena136 => self + .arena136 + .get(id.offset as usize) + .map(|node| match node { + Node136::AlterUser(alter_user) => Node::Acl(Acl::AlterUser(alter_user)), + Node136::CreateProc(create_proc) => Node::Ddl(Ddl::CreateProc(create_proc)), + Node136::RevokePrivilege(revoke_priv) => { + Node::Acl(Acl::RevokePrivilege(revoke_priv)) + } + Node136::GrantPrivilege(grant_priv) => { + Node::Acl(Acl::GrantPrivilege(grant_priv)) + } + Node136::Update(update) => Node::Relational(Relational::Update(update)), + Node136::AlterSystem(alter_system) => Node::Ddl(Ddl::AlterSystem(alter_system)), + Node136::CreateUser(create_user) => Node::Acl(Acl::CreateUser(create_user)), + Node136::Invalid(inv) => Node::Invalid(inv), + Node136::Motion(motion) => Node::Relational(Relational::Motion(motion)), + Node136::RenameRoutine(rename_routine) => { + Node::Ddl(Ddl::RenameRoutine(rename_routine)) + } + }), + ArenaType::Arena224 => self + .arena224 + .get(id.offset as usize) + .map(|node| match node { + Node224::CreateIndex(create_index) => Node::Ddl(Ddl::CreateIndex(create_index)), + Node224::CreateTable(create_table) => Node::Ddl(Ddl::CreateTable(create_table)), + Node224::Invalid(inv) => Node::Invalid(inv), + }), } } - pub(crate) fn get_mut(&mut self, id: NodeId) -> Option<&mut Node> { - let offset = usize::try_from(id.offset).unwrap(); + #[allow(clippy::too_many_lines)] + pub(crate) fn get_mut(&mut self, id: NodeId) -> Option<MutNode> { match id.arena_type { - ArenaType::Default => self.arena.get_mut(offset), + ArenaType::Arena32 => self + .arena32 + .get_mut(id.offset as usize) + .map(|node| match node { + Node32::Alias(alias) => MutNode::Expression(MutExpression::Alias(alias)), + Node32::Arithmetic(arithm) => { + MutNode::Expression(MutExpression::Arithmetic(arithm)) + } + Node32::Bool(bool) => MutNode::Expression(MutExpression::Bool(bool)), + Node32::Limit(limit) => MutNode::Relational(MutRelational::Limit(limit)), + Node32::Concat(concat) => MutNode::Expression(MutExpression::Concat(concat)), + Node32::Cast(cast) => MutNode::Expression(MutExpression::Cast(cast)), + Node32::CountAsterisk(count) => { + MutNode::Expression(MutExpression::CountAsterisk(count)) + } + Node32::Except(except) => MutNode::Relational(MutRelational::Except(except)), + Node32::ExprInParentheses(expr) => { + MutNode::Expression(MutExpression::ExprInParentheses(expr)) + } + Node32::Intersect(intersect) => { + MutNode::Relational(MutRelational::Intersect(intersect)) + } + Node32::Invalid(inv) => MutNode::Invalid(inv), + Node32::Trim(trim) => MutNode::Expression(MutExpression::Trim(trim)), + Node32::Unary(unary) => MutNode::Expression(MutExpression::Unary(unary)), + Node32::Union(un) => MutNode::Relational(MutRelational::Union(un)), + Node32::UnionAll(union_all) => { + MutNode::Relational(MutRelational::UnionAll(union_all)) + } + Node32::Values(values) => MutNode::Relational(MutRelational::Values(values)), + }), + ArenaType::Arena64 => self + .arena64 + .get_mut(id.offset as usize) + .map(|node| match node { + Node64::Case(case) => MutNode::Expression(MutExpression::Case(case)), + Node64::Constant(constant) => { + MutNode::Expression(MutExpression::Constant(constant)) + } + Node64::CreateRole(create_role) => { + MutNode::Acl(MutAcl::CreateRole(create_role)) + } + Node64::Delete(delete) => MutNode::Relational(MutRelational::Delete(delete)), + Node64::DropIndex(drop_index) => MutNode::Ddl(MutDdl::DropIndex(drop_index)), + Node64::Row(row) => MutNode::Expression(MutExpression::Row(row)), + Node64::DropRole(drop_role) => MutNode::Acl(MutAcl::DropRole(drop_role)), + Node64::DropTable(drop_table) => MutNode::Ddl(MutDdl::DropTable(drop_table)), + Node64::DropUser(drop_user) => MutNode::Acl(MutAcl::DropUser(drop_user)), + Node64::GroupBy(group_by) => { + MutNode::Relational(MutRelational::GroupBy(group_by)) + } + Node64::Having(having) => MutNode::Relational(MutRelational::Having(having)), + Node64::Join(join) => MutNode::Relational(MutRelational::Join(join)), + Node64::OrderBy(order_by) => { + MutNode::Relational(MutRelational::OrderBy(order_by)) + } + Node64::Parameter(param) => MutNode::Parameter(param), + Node64::Procedure(proc) => MutNode::Block(MutBlock::Procedure(proc)), + Node64::Projection(proj) => { + MutNode::Relational(MutRelational::Projection(proj)) + } + Node64::Reference(reference) => { + MutNode::Expression(MutExpression::Reference(reference)) + } + Node64::ScanCte(scan_cte) => { + MutNode::Relational(MutRelational::ScanCte(scan_cte)) + } + Node64::ScanRelation(scan_rel) => { + MutNode::Relational(MutRelational::ScanRelation(scan_rel)) + } + Node64::ScanSubQuery(scan_squery) => { + MutNode::Relational(MutRelational::ScanSubQuery(scan_squery)) + } + Node64::Selection(sel) => MutNode::Relational(MutRelational::Selection(sel)), + Node64::SetParam(set_param) => MutNode::Ddl(MutDdl::SetParam(set_param)), + Node64::SetTransaction(set_trans) => { + MutNode::Ddl(MutDdl::SetTransaction(set_trans)) + } + Node64::ValuesRow(values_row) => { + MutNode::Relational(MutRelational::ValuesRow(values_row)) + } + }), + ArenaType::Arena96 => self + .arena96 + .get_mut(id.offset as usize) + .map(|node| match node { + Node96::DropProc(drop_proc) => MutNode::Ddl(MutDdl::DropProc(drop_proc)), + Node96::Insert(insert) => MutNode::Relational(MutRelational::Insert(insert)), + Node96::Invalid(inv) => MutNode::Invalid(inv), + Node96::StableFunction(stable_func) => { + MutNode::Expression(MutExpression::StableFunction(stable_func)) + } + }), + ArenaType::Arena136 => { + self.arena136 + .get_mut(id.offset as usize) + .map(|node| match node { + Node136::AlterUser(alter_user) => { + MutNode::Acl(MutAcl::AlterUser(alter_user)) + } + Node136::CreateProc(create_proc) => { + MutNode::Ddl(MutDdl::CreateProc(create_proc)) + } + Node136::GrantPrivilege(grant_priv) => { + MutNode::Acl(MutAcl::GrantPrivilege(grant_priv)) + } + Node136::CreateUser(create_user) => { + MutNode::Acl(MutAcl::CreateUser(create_user)) + } + Node136::RevokePrivilege(revoke_priv) => { + MutNode::Acl(MutAcl::RevokePrivilege(revoke_priv)) + } + Node136::Invalid(inv) => MutNode::Invalid(inv), + Node136::AlterSystem(alter_system) => { + MutNode::Ddl(MutDdl::AlterSystem(alter_system)) + } + Node136::Update(update) => { + MutNode::Relational(MutRelational::Update(update)) + } + Node136::Motion(motion) => { + MutNode::Relational(MutRelational::Motion(motion)) + } + Node136::RenameRoutine(rename_routine) => { + MutNode::Ddl(MutDdl::RenameRoutine(rename_routine)) + } + }) + } + ArenaType::Arena224 => { + self.arena224 + .get_mut(id.offset as usize) + .map(|node| match node { + Node224::CreateIndex(create_index) => { + MutNode::Ddl(MutDdl::CreateIndex(create_index)) + } + Node224::Invalid(inv) => MutNode::Invalid(inv), + Node224::CreateTable(create_table) => { + MutNode::Ddl(MutDdl::CreateTable(create_table)) + } + }) + } } } - /// Get the amount of relational nodes in the plan. + /// Returns the next node position + /// # Panics #[must_use] - pub fn relation_node_amount(&self) -> usize { - self.arena - .iter() - .filter(|node| matches!(node, Node::Relational(_))) - .count() + pub fn next_id(&self, arena_type: ArenaType) -> NodeId { + match arena_type { + ArenaType::Arena32 => NodeId { + offset: u32::try_from(self.arena32.len()).unwrap(), + arena_type: ArenaType::Arena32, + }, + ArenaType::Arena64 => NodeId { + offset: u32::try_from(self.arena64.len()).unwrap(), + arena_type: ArenaType::Arena64, + }, + ArenaType::Arena96 => NodeId { + offset: u32::try_from(self.arena96.len()).unwrap(), + arena_type: ArenaType::Arena96, + }, + ArenaType::Arena136 => NodeId { + offset: u32::try_from(self.arena136.len()).unwrap(), + arena_type: ArenaType::Arena136, + }, + ArenaType::Arena224 => NodeId { + offset: u32::try_from(self.arena224.len()).unwrap(), + arena_type: ArenaType::Arena224, + }, + } } - /// Get the amount of expression nodes in the plan. #[must_use] - pub fn expression_node_amount(&self) -> usize { - self.arena - .iter() - .filter(|node| matches!(node, Node::Expression(_))) - .count() + pub fn len(&self) -> usize { + self.arena32.len() + + self.arena64.len() + + self.arena96.len() + + self.arena136.len() + + self.arena224.len() } #[must_use] pub fn is_empty(&self) -> bool { - self.arena.is_empty() + self.arena32.is_empty() + && self.arena64.is_empty() + && self.arena96.is_empty() + && self.arena136.is_empty() + && self.arena224.is_empty() } - #[must_use] - pub fn len(&self) -> usize { - self.arena.len() + // #[must_use] + // pub fn len(&self) -> usize { + // self.arena.len() + // } + + pub fn iter32(&self) -> Iter<'_, Node32> { + self.arena32.iter() + } + + pub fn iter64(&self) -> Iter<'_, Node64> { + self.arena64.iter() + } + + pub fn iter96(&self) -> Iter<'_, Node96> { + self.arena96.iter() + } + + pub fn iter136(&self) -> Iter<'_, Node136> { + self.arena136.iter() } - pub fn iter(&self) -> Iter<'_, Node> { - self.arena.iter() + pub fn iter224(&self) -> Iter<'_, Node224> { + self.arena224.iter() } /// Add new node to arena. + /// # Panics /// /// # 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) -> NodeId { - let position = self.arena.len(); - self.arena.push(node); + pub fn push(&mut self, node: SizeNode) -> NodeId { + match node { + SizeNode::Node32(node32) => { + let new_node_id = NodeId { + offset: u32::try_from(self.arena32.len()).unwrap(), + arena_type: ArenaType::Arena32, + }; - NodeId { - offset: u32::try_from(position).unwrap(), - arena_type: ArenaType::Default, - } - } + self.arena32.push(node32); - /// # Panics - /// Returns the next node position - #[must_use] - 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, - }, + new_node_id + } + SizeNode::Node64(node64) => { + let new_node_id = NodeId { + offset: u32::try_from(self.arena64.len()).unwrap(), + arena_type: ArenaType::Arena64, + }; + + self.arena64.push(node64); + + new_node_id + } + SizeNode::Node96(node96) => { + let new_node_id = NodeId { + offset: u32::try_from(self.arena96.len()).unwrap(), + arena_type: ArenaType::Arena96, + }; + + self.arena96.push(node96); + + new_node_id + } + SizeNode::Node136(node136) => { + let new_node_id = NodeId { + offset: u32::try_from(self.arena136.len()).unwrap(), + arena_type: ArenaType::Arena136, + }; + + self.arena136.push(node136); + + new_node_id + } + SizeNode::Node224(node224) => { + let new_node_id = NodeId { + offset: u32::try_from(self.arena224.len()).unwrap(), + arena_type: ArenaType::Arena224, + }; + + self.arena224.push(node224); + + new_node_id + } } } @@ -187,37 +456,37 @@ impl Nodes { /// /// # Errors /// - The node with the given position doesn't exist. - pub fn replace(&mut self, id: NodeId, node: Node) -> Result<Node, SbroadError> { + pub fn replace(&mut self, id: NodeId, node: Node64) -> Result<Node64, SbroadError> { + let offset = id.offset as usize; + match id.arena_type { - ArenaType::Default => { - if id.offset as usize >= self.arena.len() { + ArenaType::Arena64 => { + if offset >= self.arena64.len() { return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!( "can't replace node with id {id:?} as it is out of arena bounds" ))); } } + _ => { + return Err(SbroadError::Invalid( + Entity::Node, + Some(format_smolstr!("node {:?} is invalid", node)), + )); + } }; - let old_node = std::mem::replace(&mut self.arena[id.offset as usize], node); + let old_node = std::mem::replace(&mut self.arena64[offset], node); Ok(old_node) } - - pub fn reserve(&mut self, capacity: usize) { - self.arena.reserve(capacity); - } - - pub fn shrink_to_fit(&mut self) { - self.arena.shrink_to_fit(); - } } -impl<'nodes> IntoIterator for &'nodes Nodes { - type Item = &'nodes Node; - type IntoIter = Iter<'nodes, Node>; - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} +// impl<'nodes> IntoIterator for &'nodes Nodes { +// type Item = &'nodes Node; +// type IntoIter = Iter<'nodes, Node>; +// fn into_iter(self) -> Self::IntoIter { +// self.iter() +// } +// } /// One level of `Slices`. /// Element of `slice` vec is a `motion_id` to execute. @@ -543,20 +812,62 @@ impl Plan { /// # Errors /// Returns `SbroadError` when the plan tree check fails. pub fn check(&self) -> Result<(), SbroadError> { - match self.top { + let _ = match self.top { None => { return Err(SbroadError::Invalid( Entity::Plan, Some("plan tree top is None".into()), - )); + )) } Some(top) => match top.arena_type { - ArenaType::Default => { - if self.nodes.get(top).is_none() { - return Err(SbroadError::Invalid( + ArenaType::Arena32 => { + let top_node = self.nodes.arena32.get(top.offset as usize); + match top_node { + Some(_) => Ok(()), + None => Err(SbroadError::Invalid( Entity::Plan, - Some("plan tree top index is out of bouns".into()), - )); + Some("plan tree top index is out of bounds".into()), + )), + } + } + ArenaType::Arena64 => { + let top_node = self.nodes.arena64.get(top.offset as usize); + match top_node { + Some(_) => Ok(()), + None => Err(SbroadError::Invalid( + Entity::Plan, + Some("plan tree top index is out of bounds".into()), + )), + } + } + ArenaType::Arena96 => { + let top_node = self.nodes.arena96.get(top.offset as usize); + match top_node { + Some(_) => Ok(()), + None => Err(SbroadError::Invalid( + Entity::Plan, + Some("plan tree top index is out of bounds".into()), + )), + } + } + ArenaType::Arena136 => { + let top_node = self.nodes.arena136.get(top.offset as usize); + match top_node { + Some(_) => Ok(()), + None => Err(SbroadError::Invalid( + Entity::Plan, + Some("plan tree top index is out of bounds".into()), + )), + } + } + ArenaType::Arena224 => { + let top_node = self.nodes.arena224.get(top.offset as usize); + match top_node { + Some(_) => Ok(()), + None => Err(SbroadError::Invalid( + Entity::Plan, + Some("plan tree top index is out of bounds".into()), + )), } } }, @@ -566,11 +877,74 @@ impl Plan { //TODO: additional consistency checks } + /// # Panics + #[must_use] + pub fn replace_with_stub(&mut self, dst_id: NodeId) -> NodeOwned { + match dst_id.arena_type { + ArenaType::Arena32 => { + let node32 = self + .nodes + .arena32 + .get_mut(usize::try_from(dst_id.offset).unwrap()) + .unwrap(); + let stub = Node32::Invalid(Invalid {}); + let node32 = std::mem::replace(node32, stub); + node32.into_common_node() + } + ArenaType::Arena64 => { + let node64 = self + .nodes + .arena64 + .get_mut(usize::try_from(dst_id.offset).unwrap()) + .unwrap(); + let stub = Node64::Parameter(Parameter { param_type: None }); + let node64 = std::mem::replace(node64, stub); + node64.into_common_node() + } + ArenaType::Arena96 => { + let node96 = self + .nodes + .arena96 + .get_mut(usize::try_from(dst_id.offset).unwrap()) + .unwrap(); + let stub = Node96::Invalid(Invalid {}); + let node96 = std::mem::replace(node96, stub); + node96.into_common_node() + } + ArenaType::Arena136 => { + let node136 = self + .nodes + .arena136 + .get_mut(usize::try_from(dst_id.offset).unwrap()) + .unwrap(); + let stub = Node136::Invalid(Invalid {}); + let node136 = std::mem::replace(node136, stub); + node136.into_common_node() + } + ArenaType::Arena224 => { + let node224 = self + .nodes + .arena224 + .get_mut(usize::try_from(dst_id.offset).unwrap()) + .unwrap(); + let stub = Node224::Invalid(Invalid {}); + let node224 = std::mem::replace(node224, stub); + node224.into_common_node() + } + } + } + /// Constructor for an empty plan structure. #[must_use] pub fn new() -> Self { Plan { - nodes: Nodes { arena: Vec::new() }, + nodes: Nodes { + arena32: Vec::new(), + arena64: Vec::new(), + arena96: Vec::new(), + arena136: Vec::new(), + arena224: Vec::new(), + }, relations: Relations::new(), slices: Slices { slices: vec![] }, top: None, @@ -606,9 +980,11 @@ impl Plan { let nodes = bfs.take_nodes(); for level_node in nodes { let id = level_node.1; - if let Relational::Insert { .. } = self.get_relation_node(id)? { + 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)? { + if let Relational::Values(Values { children, .. }) = + self.get_relation_node(child_id)? + { values_count = Some(children.len()); } } @@ -677,7 +1053,7 @@ impl Plan { /// Check if the plan arena is empty. #[must_use] pub fn is_empty(&self) -> bool { - self.nodes.arena.is_empty() + self.nodes.is_empty() } /// Get a node by its pointer (position in the node arena). @@ -685,15 +1061,13 @@ impl Plan { /// # Errors /// Returns `SbroadError` when the node with requested index /// doesn't exist. - 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), - }, + pub fn get_node(&self, id: NodeId) -> Result<Node, SbroadError> { + match self.nodes.get(id) { + None => Err(SbroadError::NotFound( + Entity::Node, + format_smolstr!("from {:?} with index {}", id.arena_type, id.offset), + )), + Some(node) => Ok(node), } } @@ -702,19 +1076,13 @@ impl Plan { /// # Errors /// Returns `SbroadError` when the node with requested index /// doesn't exist. - 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), - }, + pub fn get_mut_node(&mut self, id: NodeId) -> Result<MutNode, SbroadError> { + match self.nodes.get_mut(id) { + None => Err(SbroadError::NotFound( + Entity::Node, + format_smolstr!("from {:?} with index {}", id.arena_type, id.offset), + )), + Some(node) => Ok(node), } } @@ -752,7 +1120,7 @@ impl Plan { /// - Given node is not a scan 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 { + if let Relational::ScanRelation(ScanRelation { relation, .. }) = node { return Ok(relation.as_str()); } Err(SbroadError::Invalid( @@ -799,7 +1167,7 @@ impl Plan { let filter = |id: NodeId| -> bool { matches!( self.get_node(id), - Ok(Node::Expression(Expression::StableFunction { .. })) + Ok(Node::Expression(Expression::StableFunction(_))) ) }; let mut dfs = PostOrderWithFilter::with_capacity( @@ -812,7 +1180,9 @@ impl Plan { if !check_top && id == expr_id { continue; } - if let Node::Expression(Expression::StableFunction { name, .. }) = self.get_node(id)? { + if let Node::Expression(Expression::StableFunction(StableFunction { name, .. })) = + self.get_node(id)? + { if Expression::is_aggregate_name(name) { return Ok(true); } @@ -822,19 +1192,6 @@ impl Plan { Ok(false) } - /// Construct a plan from the YAML file. - /// - /// # Errors - /// Returns `SbroadError` when the YAML plan is invalid. - pub fn from_yaml(s: &str) -> Result<Self, SbroadError> { - let plan: Plan = match serde_yaml::from_str(s) { - Ok(p) => p, - Err(e) => return Err(SbroadError::Invalid(Entity::Plan, Some(e.to_smolstr()))), - }; - plan.check()?; - Ok(plan) - } - /// Helper function for writing tests with yaml /// /// # Errors @@ -849,16 +1206,19 @@ impl Plan { /// Get relational node and produce a new row without aliases from its output (row with aliases). /// + /// # Panics /// # Errors /// - node is not relational /// - node's output is not a row of aliases 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())? { + if let Node::Relational(ref rel) = n { + if let Node::Expression(Expression::Row(Row { list, .. })) = + self.get_node(rel.output())? + { let mut cols: Vec<NodeId> = Vec::with_capacity(list.len()); for alias in list { - if let Node::Expression(Expression::Alias { child, .. }) = + if let Node::Expression(Expression::Alias(Alias { child, .. })) = self.get_node(*alias)? { cols.push(*child); @@ -878,11 +1238,6 @@ impl Plan { )) } - #[must_use] - pub fn next_id(&self, arena_type: ArenaType) -> NodeId { - self.nodes.next_id(arena_type) - } - /// Add condition node to the plan. /// /// # Errors @@ -932,11 +1287,14 @@ impl Plan { when_blocks: Vec<(NodeId, NodeId)>, else_expr: Option<NodeId>, ) -> NodeId { - self.nodes.push(Node::Expression(Expression::Case { - search_expr, - else_expr, - when_blocks, - })) + self.nodes.push( + Case { + search_expr, + when_blocks, + else_expr, + } + .into(), + ) } /// Add bool operator node to the plan. @@ -969,7 +1327,8 @@ impl Plan { /// - top node doesn't exist in the plan or is invalid. pub fn is_block(&self) -> Result<bool, SbroadError> { let top_id = self.get_top()?; - Ok(matches!(self.get_node(top_id)?, Node::Block(..))) + let top = self.get_node(top_id)?; + Ok(matches!(top, Node::Block(_))) } /// Checks that plan is a dml query on global table. @@ -990,7 +1349,8 @@ impl Plan { /// - top node doesn't exist in the plan or is invalid. pub fn is_ddl(&self) -> Result<bool, SbroadError> { let top_id = self.get_top()?; - Ok(matches!(self.get_node(top_id)?, Node::Ddl(..))) + let top = self.get_node(top_id)?; + Ok(matches!(top, Node::Ddl(_))) } /// Checks that plan is ACL query. @@ -999,7 +1359,8 @@ impl Plan { /// - top node doesn't exist in the plan or is invalid. pub fn is_acl(&self) -> Result<bool, SbroadError> { let top_id = self.get_top()?; - Ok(matches!(self.get_node(top_id)?, Node::Acl(..))) + let top = self.get_node(top_id)?; + Ok(matches!(top, Node::Acl(_))) } /// Set top node of plan @@ -1016,13 +1377,14 @@ impl Plan { /// # Errors /// - node doesn't exist in the plan /// - node is not a relational type - pub fn get_relation_node(&self, node_id: NodeId) -> 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), Node::Expression(_) | Node::Parameter(..) | Node::Ddl(..) + | Node::Invalid(..) | Node::Acl(..) | Node::Block(..) => Err(SbroadError::Invalid( Entity::Node, @@ -1036,17 +1398,15 @@ impl Plan { /// # Errors /// - node doesn't exist in the plan /// - node is not a relational type - pub fn get_mut_relation_node( - &mut self, - node_id: NodeId, - ) -> Result<&mut Relational, SbroadError> { + pub fn get_mut_relation_node(&mut self, node_id: NodeId) -> Result<MutRelational, SbroadError> { match self.get_mut_node(node_id)? { - Node::Relational(rel) => Ok(rel), - Node::Expression(_) - | Node::Parameter(..) - | Node::Ddl(..) - | Node::Acl(..) - | Node::Block(..) => Err(SbroadError::Invalid( + MutNode::Relational(rel) => Ok(rel), + MutNode::Expression(_) + | MutNode::Parameter(..) + | MutNode::Ddl(..) + | MutNode::Invalid(..) + | MutNode::Acl(..) + | MutNode::Block(..) => Err(SbroadError::Invalid( Entity::Node, Some("Node is not relational".into()), )), @@ -1058,23 +1418,23 @@ impl Plan { /// # Errors /// - node doesn't exist in the plan /// - node is not expression type - pub fn get_expression_node(&self, node_id: NodeId) -> 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(..) => { - let node = self.constants.get(node_id); - if let Some(Node::Expression(exp)) = node { - Ok(exp) - } else { - Err(SbroadError::Invalid( - Entity::Node, - Some("parameter node does not refer to an expression".into()), - )) + if let Some(Node64::Constant(constant)) = self.constants.get(node_id) { + return Ok(Expression::Constant(constant)); } + + Err(SbroadError::Invalid( + Entity::Node, + Some("parameter node does not refer to an expression".into()), + )) } - Node::Relational(_) | Node::Ddl(..) | Node::Acl(..) | Node::Block(..) => Err( - SbroadError::Invalid(Entity::Node, Some("node is not Expression type".into())), - ), + _ => Err(SbroadError::Invalid( + Entity::Node, + Some("node is not Expression type".into()), + )), } } @@ -1086,18 +1446,19 @@ impl Plan { pub fn get_mut_expression_node( &mut self, node_id: NodeId, - ) -> Result<&mut Expression, SbroadError> { + ) -> Result<MutExpression, SbroadError> { let node = self.get_mut_node(node_id)?; match node { - Node::Expression(exp) => Ok(exp), - Node::Relational(_) - | Node::Parameter(..) - | Node::Ddl(..) - | Node::Acl(..) - | Node::Block(..) => Err(SbroadError::Invalid( + MutNode::Expression(exp) => Ok(exp), + MutNode::Relational(_) + | MutNode::Parameter(..) + | MutNode::Ddl(..) + | MutNode::Invalid(..) + | MutNode::Acl(..) + | MutNode::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:?}" )), )), } @@ -1107,8 +1468,15 @@ impl Plan { /// /// # Errors /// - supplied id does not correspond to `Row` node - pub fn get_row_list(&self, row_id: NodeId) -> Result<&[NodeId], SbroadError> { - self.get_expression_node(row_id)?.get_row_list() + pub fn get_row_list(&self, row_id: NodeId) -> Result<&Vec<NodeId>, SbroadError> { + if let Expression::Row(Row { list, .. }) = self.get_expression_node(row_id)? { + return Ok(list); + } + + Err(SbroadError::Invalid( + Entity::Expression, + Some("node is not Row".into()), + )) } /// Helper function to get id of node under alias node, @@ -1117,12 +1485,11 @@ impl Plan { /// # Errors /// - node is not an expression node 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, .. - } => Ok(*alias_child), - _ => Ok(child_id), + if let Expression::Alias(Alias { child, .. }) = self.get_expression_node(child_id)? { + return Ok(*child); } + + Ok(child_id) } /// Gets mut list of `Row` children ids @@ -1130,7 +1497,14 @@ impl Plan { /// # Errors /// - supplied id does not correspond to `Row` node 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() + if let MutExpression::Row(Row { list, .. }) = self.get_mut_expression_node(row_id)? { + return Ok(list); + } + + Err(SbroadError::Invalid( + Entity::Expression, + Some("node is not Row".into()), + )) } /// Replace expression that is not root of the tree (== has parent) @@ -1154,20 +1528,20 @@ impl Plan { new_id: NodeId, ) -> Result<(), SbroadError> { match self.get_mut_expression_node(parent_id)? { - Expression::Unary { child, .. } - | Expression::ExprInParentheses { child } - | Expression::Alias { child, .. } - | Expression::Cast { child, .. } => { + MutExpression::Unary(UnaryExpr { child, .. }) + | MutExpression::ExprInParentheses(ExprInParentheses { child }) + | MutExpression::Alias(Alias { child, .. }) + | MutExpression::Cast(Cast { child, .. }) => { if *child == old_id { *child = new_id; return Ok(()); } } - Expression::Case { + MutExpression::Case(Case { search_expr, when_blocks, else_expr, - } => { + }) => { if let Some(search_expr) = search_expr { if *search_expr == old_id { *search_expr = new_id; @@ -1191,9 +1565,9 @@ impl Plan { } } } - Expression::Bool { left, right, .. } - | Expression::Arithmetic { left, right, .. } - | Expression::Concat { left, right, .. } => { + MutExpression::Bool(BoolExpr { left, right, .. }) + | MutExpression::Arithmetic(ArithmeticExpr { left, right, .. }) + | MutExpression::Concat(Concat { left, right, .. }) => { if *left == old_id { *left = new_id; return Ok(()); @@ -1203,9 +1577,9 @@ impl Plan { return Ok(()); } } - Expression::Trim { + MutExpression::Trim(Trim { pattern, target, .. - } => { + }) => { if let Some(pattern_id) = pattern { if *pattern_id == old_id { *pattern_id = new_id; @@ -1217,7 +1591,8 @@ impl Plan { return Ok(()); } } - Expression::Row { list: arr, .. } | StableFunction { children: arr, .. } => { + MutExpression::Row(Row { list: arr, .. }) + | MutExpression::StableFunction(StableFunction { children: arr, .. }) => { for child in arr.iter_mut() { if *child == old_id { *child = new_id; @@ -1225,14 +1600,14 @@ impl Plan { } } } - Expression::Constant { .. } - | Expression::Reference { .. } - | Expression::CountAsterisk => {} + MutExpression::Constant { .. } + | MutExpression::Reference { .. } + | MutExpression::CountAsterisk { .. } => {} } 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}"), )) } @@ -1247,7 +1622,7 @@ impl Plan { col_idx: usize, ) -> Result<NodeId, SbroadError> { let node = self.get_relation_node(groupby_id)?; - if let Relational::GroupBy { gr_cols, .. } = node { + if let Relational::GroupBy(GroupBy { gr_cols, .. }) = node { let col_id = gr_cols.get(col_idx).ok_or_else(|| { SbroadError::UnexpectedNumberOfValues(format_smolstr!( "groupby column index out of range. Node: {node:?}" @@ -1268,7 +1643,7 @@ impl Plan { /// - node is not `Projection` 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 { + if let Relational::Projection(Projection { output, .. }) = node { let col_id = self.get_row_list(*output)?.get(col_idx).ok_or_else(|| { SbroadError::UnexpectedNumberOfValues(format_smolstr!( "projection column index out of range. Node: {node:?}" @@ -1288,7 +1663,7 @@ impl Plan { /// - node is not `GroupBy` 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 { + if let Relational::GroupBy(GroupBy { gr_cols, .. }) = node { return Ok(gr_cols); } Err(SbroadError::Invalid( @@ -1307,7 +1682,7 @@ impl Plan { new_cols: Vec<NodeId>, ) -> Result<(), SbroadError> { let node = self.get_mut_relation_node(groupby_id)?; - if let Relational::GroupBy { gr_cols, .. } = node { + if let MutRelational::GroupBy(GroupBy { gr_cols, .. }) = node { *gr_cols = new_cols; return Ok(()); } @@ -1327,12 +1702,12 @@ impl Plan { /// # Panics /// - Plan is in invalid state pub fn get_alias_from_reference_node(&self, node: &Expression) -> Result<&str, SbroadError> { - let Expression::Reference { + let Expression::Reference(Reference { targets, position, parent, .. - } = node + }) = node else { unreachable!("get_alias_from_reference_node: Node is not of a reference type"); }; @@ -1345,7 +1720,7 @@ impl Plan { // In a case of insert we don't inspect children output tuple // but rather use target relation columns. - if let Relational::Insert { ref relation, .. } = ref_node { + if let Relational::Insert(Insert { ref relation, .. }) = ref_node { let rel = self .relations .get(relation) @@ -1380,8 +1755,22 @@ impl Plan { .get(*position) .unwrap_or_else(|| panic!("Column not found at position {position} in row list")); - let col_alias_node = self.get_expression_node(*col_alias_id)?; - col_alias_node.get_alias_name() + self.get_alias_name(*col_alias_id) + } + + /// Gets alias node name. + /// + /// # Errors + /// - node isn't `Alias` + pub fn get_alias_name(&self, alias_id: NodeId) -> Result<&str, SbroadError> { + if let Expression::Alias(Alias { name, .. }) = self.get_expression_node(alias_id)? { + return Ok(name); + } + + Err(SbroadError::Invalid( + Entity::Expression, + Some("node is not Alias".into()), + )) } /// Set slices of the plan. @@ -1395,11 +1784,12 @@ impl Plan { 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()); + let mut plan_nodes: Vec<Node> = Vec::with_capacity(nodes.len()); for level_node in nodes { - let id = level_node.1; - plan_nodes.push(self.get_node(id)?); + let node = self.get_node(level_node.1)?; + plan_nodes.push(node); } + let bytes: Vec<u8> = bincode::serialize(&plan_nodes).map_err(|e| { SbroadError::FailedTo( Action::Serialize, @@ -1407,6 +1797,7 @@ impl Plan { format_smolstr!("plan nodes to binary: {e:?}"), ) })?; + let hash = Base64::encode_string(blake3::hash(&bytes).to_hex().as_bytes()).to_smolstr(); Ok(hash) } @@ -1416,7 +1807,7 @@ impl Plan { fn get_param_type(&self, param_id: NodeId) -> Result<Option<Type>, SbroadError> { let node = self.get_node(param_id)?; if let Node::Parameter(ty) = node { - return Ok(ty.clone()); + return Ok(ty.param_type.clone()); } Err(SbroadError::Invalid( Entity::Node, @@ -1426,8 +1817,8 @@ impl Plan { fn set_param_type(&mut self, param_id: NodeId, ty: &Type) -> Result<(), SbroadError> { let node = self.get_mut_node(param_id)?; - if let Node::Parameter(..) = node { - *node = Node::Parameter(Some(ty.clone())); + if let MutNode::Parameter(param) = node { + param.param_type = Some(ty.clone()); Ok(()) } else { Err(SbroadError::Invalid( @@ -1545,14 +1936,14 @@ impl ShardColumnsMap { pub fn update_node(&mut self, node_id: NodeId, plan: &Plan) -> Result<(), SbroadError> { let node = plan.get_relation_node(node_id)?; match node { - Relational::ScanRelation { relation, .. } => { + Relational::ScanRelation(ScanRelation { relation, .. }) => { let table = plan.get_relation_or_error(relation)?; if let Ok(Some(pos)) = table.get_bucket_id_position() { self.memo.insert(node_id, [Some(pos), None]); } return Ok(()); } - Relational::Motion { policy, .. } => { + Relational::Motion(Motion { policy, .. }) => { // Any motion node that moves data invalidates // bucket_id column selected from that space. // Even Segment policy is no help, because it only @@ -1586,9 +1977,9 @@ impl ShardColumnsMap { // If there is a parameter under alias // and we haven't bound parameters yet, // we will get an error. - let Ok(Expression::Reference { + let Ok(Expression::Reference(Reference { targets, position, .. - }) = plan.get_expression_node(ref_id) + })) = plan.get_expression_node(ref_id) else { continue; }; @@ -1651,9 +2042,9 @@ impl ShardColumnsMap { plan: &Plan, ) -> Result<(), SbroadError> { let node = plan.get_relation_node(node_id)?; - if let Relational::Motion { + if let Relational::Motion(Motion { policy, children, .. - } = node + }) = node { if matches!(policy, MotionPolicy::Local | MotionPolicy::LocalSegment(_)) { return Ok(()); diff --git a/sbroad-core/src/ir/acl.rs b/sbroad-core/src/ir/acl.rs index 54cf1e420..3e1555afe 100644 --- a/sbroad-core/src/ir/acl.rs +++ b/sbroad-core/src/ir/acl.rs @@ -1,9 +1,14 @@ -use crate::ir::{Entity, Node, Plan, SbroadError}; +use crate::{ + ir::node::{MutNode, NodeId}, + ir::{Entity, Node, Plan, SbroadError}, +}; use serde::{Deserialize, Serialize}; -use smol_str::{format_smolstr, SmolStr, ToSmolStr}; -use tarantool::decimal::Decimal; +use smol_str::{format_smolstr, SmolStr}; -use super::{ddl::ParamDef, expression::NodeId}; +use super::{ + ddl::ParamDef, + node::acl::{Acl, MutAcl}, +}; ::tarantool::define_str_enum! { /// Revoked or granted privilege. @@ -187,76 +192,13 @@ pub enum AlterOption { }, } -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -pub enum Acl { - DropRole { - name: SmolStr, - timeout: Decimal, - }, - DropUser { - name: SmolStr, - timeout: Decimal, - }, - CreateRole { - name: SmolStr, - timeout: Decimal, - }, - CreateUser { - name: SmolStr, - password: SmolStr, - auth_method: SmolStr, - timeout: Decimal, - }, - AlterUser { - name: SmolStr, - alter_option: AlterOption, - timeout: Decimal, - }, - GrantPrivilege { - grant_type: GrantRevokeType, - grantee_name: SmolStr, - timeout: Decimal, - }, - RevokePrivilege { - revoke_type: GrantRevokeType, - grantee_name: SmolStr, - timeout: Decimal, - }, -} - -impl Acl { - /// Return ACL node timeout. - /// - /// # Errors - /// - timeout parsing error - pub fn timeout(&self) -> Result<f64, SbroadError> { - match self { - Acl::DropRole { ref timeout, .. } - | Acl::DropUser { ref timeout, .. } - | Acl::CreateRole { ref timeout, .. } - | Acl::AlterUser { ref timeout, .. } - | Acl::CreateUser { ref timeout, .. } - | Acl::RevokePrivilege { ref timeout, .. } - | Acl::GrantPrivilege { ref timeout, .. } => timeout, - } - .to_smolstr() - .parse() - .map_err(|e| { - SbroadError::Invalid( - Entity::SpaceMetadata, - Some(format_smolstr!("timeout parsing error {e:?}")), - ) - }) - } -} - impl Plan { /// Get ACL node from the plan arena. /// /// # Errors /// - the node index is absent in arena /// - current node is not of ACL type - pub fn get_acl_node(&self, node_id: NodeId) -> 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,28 +214,10 @@ 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: NodeId) -> Result<&mut Acl, SbroadError> { + pub fn get_mut_acl_node(&mut self, node_id: NodeId) -> Result<MutAcl, SbroadError> { let node = self.get_mut_node(node_id)?; match node { - Node::Acl(acl) => Ok(acl), - _ => Err(SbroadError::Invalid( - Entity::Node, - Some(format_smolstr!("node is not ACL type: {node:?}")), - )), - } - } - - /// Take ACL node from the plan arena and replace it with parameter node. - /// - /// # Errors - /// - current node is not of ACL type - 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. - let node = std::mem::replace(self.get_mut_node(node_id)?, Node::Parameter(None)); - match node { - Node::Acl(acl) => Ok(acl), + MutNode::Acl(acl) => Ok(acl), _ => Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!("node is not ACL type: {node:?}")), diff --git a/sbroad-core/src/ir/aggregates.rs b/sbroad-core/src/ir/aggregates.rs index 7db5a343e..d06ba2240 100644 --- a/sbroad-core/src/ir/aggregates.rs +++ b/sbroad-core/src/ir/aggregates.rs @@ -2,15 +2,16 @@ use smol_str::{format_smolstr, ToSmolStr}; use crate::errors::{Entity, SbroadError}; use crate::ir::expression::cast::Type; -use crate::ir::expression::Expression; +use crate::ir::node::{NodeId, Reference, StableFunction}; use crate::ir::operator::Arithmetic; use crate::ir::relation::Type as RelType; -use crate::ir::{Node, Plan, Position}; +use crate::ir::Plan; use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::rc::Rc; -use super::expression::{ColumnPositionMap, FunctionFeature, NodeId}; +use super::expression::{ColumnPositionMap, FunctionFeature, Position}; +use super::node::expression::Expression; /// The kind of aggregate function /// @@ -309,18 +310,18 @@ impl SimpleAggregate { local_kind: AggregateKind, final_func: AggregateKind| -> Result<(), SbroadError> { - let ref_node = Expression::Reference { + let ref_node = Reference { parent: Some(parent), // projection has only one child targets: Some(vec![0]), position, col_type: fun_type.clone(), }; - let ref_id = plan.nodes.push(Node::Expression(ref_node)); + let ref_id = plan.nodes.push(ref_node.into()); let children = match self.kind { AggregateKind::AVG => vec![plan.add_cast(ref_id, Type::Double)?], AggregateKind::GRCONCAT => { - if let Expression::StableFunction { children, .. } = + if let Expression::StableFunction(StableFunction { children, .. }) = plan.get_expression_node(self.fun_id)? { if children.len() > 1 { @@ -351,14 +352,14 @@ impl SimpleAggregate { } else { None }; - let final_aggr = Expression::StableFunction { + let final_aggr = StableFunction { name: final_func.to_smolstr(), children, feature, func_type: RelType::from(final_func), is_system: true, }; - let aggr_id = plan.nodes.push(Node::Expression(final_aggr)); + let aggr_id = plan.nodes.push(final_aggr.into()); final_aggregates.insert(local_kind, aggr_id); Ok(()) }; diff --git a/sbroad-core/src/ir/api/children.rs b/sbroad-core/src/ir/api/children.rs index 2b004eac7..3cd2f250f 100644 --- a/sbroad-core/src/ir/api/children.rs +++ b/sbroad-core/src/ir/api/children.rs @@ -1,8 +1,8 @@ use std::ops::{Index, Range, RangeFrom, RangeFull}; -use crate::ir::expression::NodeId; +use crate::ir::node::NodeId; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Children<'r> { None, Single(&'r NodeId), @@ -223,9 +223,7 @@ impl<'r> MutChildren<'r> { MutChildren::Single(i) => (i, MutChildren::None), MutChildren::Couple(l, r) => (l, MutChildren::Single(r)), MutChildren::Many(i) => { - let Some((elem, next)) = i.split_first_mut() else { - return None; - }; + let (elem, next) = i.split_first_mut()?; (elem, MutChildren::Many(next)) } }; @@ -244,9 +242,7 @@ impl<'c> Iterator for MutChildrenIter<'c> { fn next(&mut self) -> Option<Self::Item> { let inner = std::mem::take(&mut self.inner); if let Some(inner) = inner { - let Some((elem, next)) = inner.split_first() else { - return None; - }; + let (elem, next) = inner.split_first()?; self.inner = Some(next); Some(elem) } else { diff --git a/sbroad-core/src/ir/api/constant.rs b/sbroad-core/src/ir/api/constant.rs index 50d841a0c..4fd7c5746 100644 --- a/sbroad-core/src/ir/api/constant.rs +++ b/sbroad-core/src/ir/api/constant.rs @@ -1,33 +1,19 @@ use smol_str::format_smolstr; use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::{Expression, NodeId}; +use crate::ir::node::expression::Expression; +use crate::ir::node::{Constant, Node64, NodeId, Parameter}; use crate::ir::value::Value; -use crate::ir::{ArenaType, Node, Nodes, Plan}; +use crate::ir::{ArenaType, Nodes, Plan}; -impl Expression { +impl Expression<'_> { /// Gets value from const node /// /// # Errors /// - node isn't constant type pub fn as_const_value(&self) -> Result<Value, SbroadError> { - if let Expression::Constant { value } = self.clone() { - return Ok(value); - } - - Err(SbroadError::Invalid( - Entity::Node, - Some("node is not Const type".into()), - )) - } - - /// Gets reference to value from const node - /// - /// # Errors - /// - node isn't constant type - pub fn as_const_value_ref(&self) -> Result<&Value, SbroadError> { - if let Expression::Constant { value } = self { - return Ok(value); + if let Expression::Constant(Constant { value }) = self { + return Ok(value.clone()); } Err(SbroadError::Invalid( @@ -39,35 +25,51 @@ impl Expression { /// Check whether the node is a constant expression. #[must_use] pub fn is_const(&self) -> bool { - matches!(self, Expression::Constant { .. }) + matches!(self, Expression::Constant(_)) } } impl Nodes { /// Adds constant node. pub fn add_const(&mut self, value: Value) -> NodeId { - self.push(Node::Expression(Expression::Constant { value })) + self.push(Constant { value }.into()) } } impl Plan { + /// Gets reference to value from const node + /// + /// # Errors + /// - node isn't constant type + pub fn as_const_value_ref(&self, const_id: NodeId) -> Result<&Value, SbroadError> { + if let Expression::Constant(Constant { value }) = self.get_expression_node(const_id)? { + return Ok(value); + } + + Err(SbroadError::Invalid( + Entity::Node, + Some("node is not Const type".into()), + )) + } + /// Add constant value to the plan. pub fn add_const(&mut self, v: Value) -> NodeId { self.nodes.add_const(v) } + /// # Panics #[must_use] /// # Panics pub fn get_const_list(&self) -> Vec<NodeId> { self.nodes - .arena + .arena64 .iter() .enumerate() .filter_map(|(id, node)| { - if let Node::Expression(Expression::Constant { .. }) = node { + if let Node64::Constant(_) = node { Some(NodeId { offset: u32::try_from(id).unwrap(), - arena_type: ArenaType::Default, + arena_type: ArenaType::Arena64, }) } else { None @@ -82,7 +84,7 @@ impl Plan { /// - The parameters map is corrupted (parameters map points to invalid nodes). pub fn restore_constants(&mut self) -> Result<(), SbroadError> { for (id, const_node) in self.constants.drain() { - if let Node::Expression(Expression::Constant { .. }) = const_node { + if let Node64::Constant(_) = const_node { } else { return Err(SbroadError::Invalid( Entity::Expression, @@ -103,7 +105,9 @@ impl Plan { pub fn stash_constants(&mut self) -> Result<(), SbroadError> { let constants = self.get_const_list(); for const_id in constants { - let const_node = self.nodes.replace(const_id, Node::Parameter(None))?; + let const_node = self + .nodes + .replace(const_id, Node64::Parameter(Parameter { param_type: None }))?; self.constants.insert(const_id, const_node); } Ok(()) diff --git a/sbroad-core/src/ir/api/parameter.rs b/sbroad-core/src/ir/api/parameter.rs index 9875e3028..2a16c6b89 100644 --- a/sbroad-core/src/ir/api/parameter.rs +++ b/sbroad-core/src/ir/api/parameter.rs @@ -1,7 +1,12 @@ use crate::errors::SbroadError; -use crate::ir::block::Block; -use crate::ir::expression::{Expression, NodeId}; -use crate::ir::operator::Relational; +use crate::ir::node::block::{Block, MutBlock}; +use crate::ir::node::expression::{Expression, MutExpression}; +use crate::ir::node::relational::{MutRelational, Relational}; +use crate::ir::node::{ + Alias, ArithmeticExpr, BoolExpr, Case, Cast, Concat, ExprInParentheses, Having, Join, MutNode, + Node64, NodeId, Parameter, Procedure, Row, Selection, StableFunction, Trim, UnaryExpr, + ValuesRow, +}; use crate::ir::tree::traversal::{LevelNode, PostOrder}; use crate::ir::value::Value; use crate::ir::{ArenaType, Node, OptionParamValue, Plan, ValueIdx}; @@ -205,54 +210,54 @@ impl<'binder> ParamsBinder<'binder> { // trees such as OrderBy and GroupBy, because it won't influence ordering and // grouping correspondingly. These cases are handled during parsing stage. Node::Relational(rel) => match rel { - Relational::Having { + Relational::Having(Having { filter: ref param_id, .. - } - | Relational::Selection { + }) + | Relational::Selection(Selection { filter: ref param_id, .. - } - | Relational::Join { + }) + | Relational::Join(Join { condition: ref param_id, .. - } => { + }) => { self.cover_param_with_row(*param_id, true, &mut param_index, &mut row_ids); } _ => {} }, Node::Expression(expr) => match expr { - Expression::Alias { + Expression::Alias(Alias { child: ref param_id, .. - } - | Expression::ExprInParentheses { + }) + | Expression::ExprInParentheses(ExprInParentheses { child: ref param_id, - } - | Expression::Cast { + }) + | Expression::Cast(Cast { child: ref param_id, .. - } - | Expression::Unary { + }) + | Expression::Unary(UnaryExpr { child: ref param_id, .. - } => { + }) => { self.cover_param_with_row(*param_id, false, &mut param_index, &mut row_ids); } - Expression::Bool { + Expression::Bool(BoolExpr { ref left, ref right, .. - } - | Expression::Arithmetic { + }) + | Expression::Arithmetic(ArithmeticExpr { ref left, ref right, .. - } - | Expression::Concat { + }) + | Expression::Concat(Concat { ref left, ref right, - } => { + }) => { for param_id in &[*left, *right] { self.cover_param_with_row( *param_id, @@ -262,11 +267,11 @@ impl<'binder> ParamsBinder<'binder> { ); } } - Expression::Trim { + Expression::Trim(Trim { ref pattern, ref target, .. - } => { + }) => { let params = match pattern { Some(p) => [Some(*p), Some(*target)], None => [None, Some(*target)], @@ -280,10 +285,10 @@ impl<'binder> ParamsBinder<'binder> { ); } } - Expression::Row { ref list, .. } - | Expression::StableFunction { + Expression::Row(Row { ref list, .. }) + | Expression::StableFunction(StableFunction { children: ref list, .. - } => { + }) => { for param_id in list { // Parameter is already under row/function so that we don't // have to cover it with `add_row` call. @@ -295,11 +300,11 @@ impl<'binder> ParamsBinder<'binder> { ); } } - Expression::Case { + Expression::Case(Case { ref search_expr, ref when_blocks, ref else_expr, - } => { + }) => { if let Some(search_expr) = search_expr { self.cover_param_with_row( *search_expr, @@ -333,10 +338,10 @@ impl<'binder> ParamsBinder<'binder> { } Expression::Reference { .. } | Expression::Constant { .. } - | Expression::CountAsterisk => {} + | Expression::CountAsterisk { .. } => {} }, Node::Block(block) => match block { - Block::Procedure { ref values, .. } => { + Block::Procedure(Procedure { ref values, .. }) => { for param_id in values { // We don't need to wrap arguments, passed into the // procedure call, into the rows. @@ -349,7 +354,7 @@ impl<'binder> ParamsBinder<'binder> { } } }, - Node::Parameter(..) | Node::Ddl(..) | Node::Acl(..) => {} + Node::Invalid(..) | Node::Parameter(..) | Node::Ddl(..) | Node::Acl(..) => {} } } @@ -382,7 +387,7 @@ impl<'binder> ParamsBinder<'binder> { } } for (id, new_type) in exprs_to_set_ref_type { - let expr = self.plan.get_mut_expression_node(id)?; + let mut expr = self.plan.get_mut_expression_node(id)?; expr.set_ref_type(new_type); } @@ -400,7 +405,7 @@ impl<'binder> ParamsBinder<'binder> { 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, @@ -419,64 +424,64 @@ impl<'binder> ParamsBinder<'binder> { for LevelNode(_, id) in &self.nodes { let node = self.plan.get_mut_node(*id)?; match node { - Node::Relational(rel) => match rel { - Relational::Having { + MutNode::Relational(rel) => match rel { + MutRelational::Having(Having { filter: ref mut param_id, .. - } - | Relational::Selection { + }) + | MutRelational::Selection(Selection { filter: ref mut param_id, .. - } - | Relational::Join { + }) + | MutRelational::Join(Join { condition: ref mut param_id, .. - } => { + }) => { bind_param(param_id, true, &mut param_index); } _ => {} }, - Node::Expression(expr) => match expr { - Expression::Alias { + MutNode::Expression(expr) => match expr { + MutExpression::Alias(Alias { child: ref mut param_id, .. - } - | Expression::ExprInParentheses { + }) + | MutExpression::ExprInParentheses(ExprInParentheses { child: ref mut param_id, - } - | Expression::Cast { + }) + | MutExpression::Cast(Cast { child: ref mut param_id, .. - } - | Expression::Unary { + }) + | MutExpression::Unary(UnaryExpr { child: ref mut param_id, .. - } => { + }) => { bind_param(param_id, false, &mut param_index); } - Expression::Bool { + MutExpression::Bool(BoolExpr { ref mut left, ref mut right, .. - } - | Expression::Arithmetic { + }) + | MutExpression::Arithmetic(ArithmeticExpr { ref mut left, ref mut right, .. - } - | Expression::Concat { + }) + | MutExpression::Concat(Concat { ref mut left, ref mut right, - } => { + }) => { for param_id in [left, right] { bind_param(param_id, true, &mut param_index); } } - Expression::Trim { + MutExpression::Trim(Trim { ref mut pattern, ref mut target, .. - } => { + }) => { let params = match pattern { Some(p) => [Some(p), Some(target)], None => [None, Some(target)], @@ -485,20 +490,20 @@ impl<'binder> ParamsBinder<'binder> { bind_param(param_id, true, &mut param_index); } } - Expression::Row { ref mut list, .. } - | Expression::StableFunction { + MutExpression::Row(Row { ref mut list, .. }) + | MutExpression::StableFunction(StableFunction { children: ref mut list, .. - } => { + }) => { for param_id in list { bind_param(param_id, false, &mut param_index); } } - Expression::Case { + MutExpression::Case(Case { ref mut search_expr, ref mut when_blocks, ref mut else_expr, - } => { + }) => { if let Some(param_id) = search_expr { bind_param(param_id, false, &mut param_index); } @@ -510,18 +515,21 @@ impl<'binder> ParamsBinder<'binder> { bind_param(param_id, false, &mut param_index); } } - Expression::Reference { .. } - | Expression::Constant { .. } - | Expression::CountAsterisk => {} + MutExpression::Reference { .. } + | MutExpression::Constant { .. } + | MutExpression::CountAsterisk { .. } => {} }, - Node::Block(block) => match block { - Block::Procedure { ref mut values, .. } => { + MutNode::Block(block) => match block { + MutBlock::Procedure(Procedure { ref mut values, .. }) => { for param_id in values { bind_param(param_id, false, &mut param_index); } } }, - Node::Parameter(..) | Node::Ddl(..) | Node::Acl(..) => {} + MutNode::Invalid(..) + | MutNode::Parameter(..) + | MutNode::Ddl(..) + | MutNode::Acl(..) => {} } } @@ -530,7 +538,7 @@ impl<'binder> ParamsBinder<'binder> { fn update_value_rows(&mut self) -> Result<(), SbroadError> { for LevelNode(_, id) in &self.nodes { - if let Ok(Node::Relational(Relational::ValuesRow { .. })) = self.plan.get_node(*id) { + if let Ok(Node::Relational(Relational::ValuesRow(_))) = self.plan.get_node(*id) { self.plan.update_values_row(*id)?; } } @@ -540,7 +548,7 @@ impl<'binder> ParamsBinder<'binder> { impl Plan { pub fn add_param(&mut self) -> NodeId { - self.nodes.push(Node::Parameter(None)) + self.nodes.push(Parameter { param_type: None }.into()) } /// Bind params related to `Option` clause. @@ -579,19 +587,20 @@ impl Plan { } // Gather all parameter nodes from the tree to a hash set. + /// # Panics #[must_use] /// # Panics pub fn get_param_set(&self) -> AHashSet<NodeId> { let param_set: AHashSet<NodeId> = self .nodes - .arena + .arena64 .iter() .enumerate() .filter_map(|(id, node)| { - if let Node::Parameter(..) = node { + if let Node64::Parameter(_) = node { Some(NodeId { offset: u32::try_from(id).unwrap(), - arena_type: ArenaType::Default, + arena_type: ArenaType::Arena64, }) } else { None @@ -613,7 +622,9 @@ impl Plan { 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 { + if let Node::Relational(Relational::ValuesRow(ValuesRow { output, data, .. })) = + values_row + { (*output, *data) } else { panic!("Expected a values row: {values_row:?}") @@ -627,7 +638,7 @@ impl Plan { .get(pos) .unwrap_or_else(|| panic!("Node not found at position {pos}")); let alias = self.get_mut_expression_node(*alias_id)?; - if let Expression::Alias { ref mut child, .. } = alias { + if let MutExpression::Alias(Alias { ref mut child, .. }) = alias { *child = new_child_id; } else { panic!("Expected an alias: {alias:?}") diff --git a/sbroad-core/src/ir/block.rs b/sbroad-core/src/ir/block.rs index 5dbd9ce97..e1d0c3d11 100644 --- a/sbroad-core/src/ir/block.rs +++ b/sbroad-core/src/ir/block.rs @@ -1,38 +1,18 @@ //! IR nodes representing blocks of commands. use crate::errors::{Entity, SbroadError}; +use crate::ir::node::{MutNode, NodeId}; use crate::ir::{Node, Plan}; -use serde::{Deserialize, Serialize}; -use smol_str::{format_smolstr, SmolStr}; +use smol_str::format_smolstr; -use super::expression::NodeId; - -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub enum Block { - /// Procedure body. - Procedure { - /// The name of the procedure. - name: SmolStr, - /// Passed values to the procedure. - values: Vec<NodeId>, - }, -} - -impl Default for Block { - fn default() -> Self { - Block::Procedure { - name: SmolStr::default(), - values: vec![], - } - } -} +use super::node::block::{Block, MutBlock}; impl Plan { /// Get a reference to a block node. /// /// # Errors /// - the node is not a block node. - pub fn get_block_node(&self, node_id: NodeId) -> Result<&Block, SbroadError> { + pub fn get_block_node(&self, node_id: NodeId) -> Result<Block, SbroadError> { let node = self.get_node(node_id)?; match node { Node::Block(block) => Ok(block), @@ -40,10 +20,11 @@ impl Plan { | Node::Relational(_) | Node::Ddl(..) | Node::Acl(..) + | Node::Invalid(..) | 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" )), )), } @@ -53,18 +34,19 @@ impl Plan { /// /// # Errors /// - the node is not a block node. - pub fn get_mut_block_node(&mut self, node_id: NodeId) -> Result<&mut Block, SbroadError> { + pub fn get_mut_block_node(&mut self, node_id: NodeId) -> Result<MutBlock, SbroadError> { let node = self.get_mut_node(node_id)?; match node { - Node::Block(block) => Ok(block), - Node::Expression(_) - | Node::Relational(_) - | Node::Ddl(..) - | Node::Acl(..) - | Node::Parameter(..) => Err(SbroadError::Invalid( + MutNode::Block(block) => Ok(block), + MutNode::Expression(_) + | MutNode::Relational(_) + | MutNode::Ddl(..) + | MutNode::Acl(..) + | MutNode::Invalid(..) + | MutNode::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 5932af5fb..b7b78eda7 100644 --- a/sbroad-core/src/ir/ddl.rs +++ b/sbroad-core/src/ir/ddl.rs @@ -1,17 +1,13 @@ use crate::ir::value::Value; use crate::{ errors::{Entity, SbroadError}, + ir::node::{MutNode, NodeId}, ir::{relation::Type as RelationType, Node, Plan}, }; use serde::{Deserialize, Serialize}; -use smol_str::{format_smolstr, SmolStr, ToSmolStr}; -use tarantool::space::SpaceEngineType; -use tarantool::{ - decimal::Decimal, - index::{IndexType, RtreeIndexDistanceType}, -}; +use smol_str::{format_smolstr, SmolStr}; -use super::expression::NodeId; +use super::node::ddl::{Ddl, MutDdl}; #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] pub struct ColumnDef { @@ -76,120 +72,13 @@ pub enum AlterSystemType { }, } -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -pub enum Ddl { - CreateTable { - name: SmolStr, - format: Vec<ColumnDef>, - primary_key: Vec<SmolStr>, - /// If `None`, create global table. - sharding_key: Option<Vec<SmolStr>>, - /// Vinyl is supported only for sharded tables. - engine_type: SpaceEngineType, - timeout: Decimal, - /// Shows which tier the sharded table belongs to. - /// Field has value, only if it was specified in [ON TIER] part of CREATE TABLE statement. - /// Field is None, if: - /// 1) Global table. - /// 2) Sharded table without [ON TIER] part. In this case picodata will use default tier. - tier: Option<SmolStr>, - }, - DropTable { - name: SmolStr, - timeout: Decimal, - }, - AlterSystem { - ty: AlterSystemType, - /// In case of None, ALTER is supposed - /// to be executed on all tiers. - tier_name: Option<SmolStr>, - timeout: Decimal, - }, - CreateProc { - name: SmolStr, - params: Vec<ParamDef>, - body: SmolStr, - language: Language, - timeout: Decimal, - }, - DropProc { - name: SmolStr, - params: Option<Vec<ParamDef>>, - timeout: Decimal, - }, - RenameRoutine { - old_name: SmolStr, - new_name: SmolStr, - params: Option<Vec<ParamDef>>, - timeout: Decimal, - }, - CreateIndex { - name: SmolStr, - table_name: SmolStr, - columns: Vec<SmolStr>, - unique: bool, - index_type: IndexType, - bloom_fpr: Option<Decimal>, - page_size: Option<u32>, - range_size: Option<u32>, - run_count_per_level: Option<u32>, - run_size_ratio: Option<Decimal>, - dimension: Option<u32>, - distance: Option<RtreeIndexDistanceType>, - hint: Option<bool>, - timeout: Decimal, - }, - DropIndex { - name: SmolStr, - timeout: Decimal, - }, - SetParam { - scope_type: SetParamScopeType, - param_value: SetParamValue, - timeout: Decimal, - }, - // TODO: Fill with actual values. - SetTransaction { - timeout: Decimal, - }, -} - -impl Ddl { - /// Return DDL node timeout. - /// - /// # Errors - /// - timeout parsing error - pub fn timeout(&self) -> Result<f64, SbroadError> { - match self { - Ddl::CreateTable { ref timeout, .. } - | Ddl::DropTable { ref timeout, .. } - | Ddl::CreateIndex { ref timeout, .. } - | Ddl::DropIndex { ref timeout, .. } - | Ddl::AlterSystem { ref timeout, .. } - | Ddl::SetParam { ref timeout, .. } - | Ddl::SetTransaction { ref timeout, .. } - | Ddl::CreateProc { ref timeout, .. } - | Ddl::DropProc { ref timeout, .. } - | Ddl::RenameRoutine { ref timeout, .. } => timeout, - } - .to_smolstr() - .parse() - .map_err(|e| { - SbroadError::Invalid( - Entity::SpaceMetadata, - Some(format_smolstr!("timeout parsing error {e:?}")), - ) - }) - } -} - impl Plan { /// Get DDL node from the plan arena. /// /// # Errors /// - the node index is absent in arena /// - current node is not of DDL type - pub fn get_ddl_node(&self, node_id: NodeId) -> 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), @@ -205,28 +94,10 @@ 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: NodeId) -> Result<&mut Ddl, SbroadError> { + pub fn get_mut_ddl_node(&mut self, node_id: NodeId) -> Result<MutDdl, SbroadError> { let node = self.get_mut_node(node_id)?; match node { - Node::Ddl(ddl) => Ok(ddl), - _ => Err(SbroadError::Invalid( - Entity::Node, - Some(format_smolstr!("node is not DDL type: {node:?}")), - )), - } - } - - /// Take DDL node from the plan arena and replace it with parameter node. - /// - /// # Errors - /// - current node is not of DDL type - 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. - let node = std::mem::replace(self.get_mut_node(node_id)?, Node::Parameter(None)); - match node { - Node::Ddl(ddl) => Ok(ddl), + MutNode::Ddl(ddl) => Ok(ddl), _ => Err(SbroadError::Invalid( Entity::Node, Some(format_smolstr!("node is not DDL type: {node:?}")), diff --git a/sbroad-core/src/ir/distribution.rs b/sbroad-core/src/ir/distribution.rs index 6a20a724b..ac2168c8b 100644 --- a/sbroad-core/src/ir/distribution.rs +++ b/sbroad-core/src/ir/distribution.rs @@ -9,11 +9,12 @@ use serde::{Deserialize, Serialize}; use crate::collection; use crate::errors::{Action, Entity, SbroadError}; use crate::ir::helpers::RepeatableState; +use crate::ir::node::{NodeId, Reference, Row}; use crate::ir::transformation::redistribution::{MotionKey, Target}; use super::api::children::Children; -use super::expression::{Expression, NodeId}; -use super::operator::Relational; +use super::node::expression::{Expression, MutExpression}; +use super::node::relational::Relational; use super::relation::{Column, ColumnPositions}; use super::{Node, Plan}; @@ -332,9 +333,9 @@ impl ReferenceInfo { let mut ref_map: AHashMap<ChildColumnReference, ParentColumnPosition> = AHashMap::new(); for (parent_column_pos, id) in ir.get_row_list(row_id)?.iter().enumerate() { let child_id = ir.get_child_under_alias(*id)?; - if let Expression::Reference { + if let Expression::Reference(Reference { targets, position, .. - } = ir.get_expression_node(child_id)? + }) = ir.get_expression_node(child_id)? { // As the row is located in the branch relational node, the targets should be non-empty. let targets = targets.as_ref().ok_or_else(|| { @@ -420,10 +421,7 @@ impl Plan { /// - invalid projection node (e.g. no children) /// - failed to get child distribution pub fn set_projection_distribution(&mut self, proj_id: NodeId) -> Result<(), SbroadError> { - if !matches!( - self.get_relation_node(proj_id)?, - Relational::Projection { .. } - ) { + 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:?}")), @@ -441,7 +439,7 @@ impl Plan { let mut only_compound_exprs = true; for id in self.get_row_list(output_id)? { let child_id = self.get_child_under_alias(*id)?; - if let Expression::Reference { .. } = self.get_expression_node(child_id)? { + if let Expression::Reference(_) = self.get_expression_node(child_id)? { only_compound_exprs = false; break; } @@ -479,12 +477,14 @@ impl Plan { /// - reference has invalid targets #[allow(clippy::too_many_lines)] pub fn set_distribution(&mut self, row_id: NodeId) -> Result<(), SbroadError> { - let row_children = self.get_expression_node(row_id)?.get_row_list()?; + let row_children = self.get_row_list(row_id)?; let mut parent_node = None; for id in row_children { let child_id = self.get_child_under_alias(*id)?; - if let Expression::Reference { parent, .. } = self.get_expression_node(child_id)? { + if let Expression::Reference(Reference { parent, .. }) = + self.get_expression_node(child_id)? + { parent_node = *parent; break; } @@ -511,9 +511,9 @@ impl Plan { HashMap::with_capacity_and_hasher(row_children.len(), RandomState::new()); for (pos, id) in row_children.iter().enumerate() { let child_id = self.get_child_under_alias(*id)?; - if let Expression::Reference { + if let Expression::Reference(Reference { targets, position, .. - } = self.get_expression_node(child_id)? + }) = self.get_expression_node(child_id)? { if targets.is_some() { return Err(SbroadError::Invalid( @@ -535,10 +535,10 @@ impl Plan { }) }); if all_found { - if let Expression::Row { + if let MutExpression::Row(Row { ref mut distribution, .. - } = self.get_mut_expression_node(row_id)? + }) = self.get_mut_expression_node(row_id)? { let keys: HashSet<Key, RepeatableState> = collection! { new_key }; *distribution = Some(Distribution::Segment { keys: keys.into() }); @@ -557,10 +557,10 @@ impl Plan { let suggested_dist = self.dist_from_child(child_id, &ref_info.child_column_to_parent_col)?; let output = self.get_mut_expression_node(row_id)?; - if let Expression::Row { + if let MutExpression::Row(Row { ref mut distribution, .. - } = output + }) = output { if distribution.is_none() { *distribution = Some(suggested_dist); @@ -614,7 +614,7 @@ impl Plan { if !matches!( node, - Relational::Join { .. } | Relational::Having { .. } | Relational::Selection { .. } + Relational::Join(_) | Relational::Having(_) | Relational::Selection(_) ) { return Ok(None); } @@ -664,10 +664,10 @@ impl Plan { ) -> Result<Distribution, SbroadError> { if let Node::Relational(relational_op) = self.get_node(child_rel_node)? { let node = self.get_node(relational_op.output())?; - if let Node::Expression(Expression::Row { + if let Node::Expression(Expression::Row(Row { distribution: child_dist, .. - }) = node + })) = node { match child_dist { None => { @@ -725,10 +725,10 @@ impl Plan { /// # Errors /// - supplied node is `Row` pub fn set_dist(&mut self, row_id: NodeId, dist: Distribution) -> Result<(), SbroadError> { - if let Expression::Row { + if let MutExpression::Row(Row { ref mut distribution, .. - } = self.get_mut_expression_node(row_id)? + }) = self.get_mut_expression_node(row_id)? { *distribution = Some(dist); return Ok(()); @@ -765,10 +765,10 @@ impl Plan { } }; let expr = self.get_mut_expression_node(row_id)?; - if let Expression::Row { + if let MutExpression::Row(Row { ref mut distribution, .. - } = expr + }) = expr { *distribution = Some(new_dist); } else { @@ -781,13 +781,31 @@ impl Plan { Ok(()) } + /// Gets current row distribution. + /// + /// # Errors + /// Returns `SbroadError` when the function is called on expression + /// other than `Row` or a node doesn't know its distribution yet. + pub fn distribution(&self, id: NodeId) -> Result<&Distribution, SbroadError> { + if let Expression::Row(Row { distribution, .. }) = self.get_expression_node(id)? { + let Some(dist) = distribution else { + return Err(SbroadError::Invalid( + Entity::Distribution, + Some("distribution is uninitialized".into()), + )); + }; + return Ok(dist); + } + Err(SbroadError::Invalid(Entity::Expression, None)) + } + /// Gets distribution of the output row. /// /// # Errors /// - Node is not of a row type. pub fn get_distribution(&self, row_id: NodeId) -> Result<&Distribution, SbroadError> { match self.get_node(row_id)? { - Node::Expression(expr) => expr.distribution(), + Node::Expression(_) => self.distribution(row_id), Node::Relational(_) => Err(SbroadError::Invalid( Entity::Distribution, Some( @@ -811,6 +829,10 @@ impl Plan { Entity::Distribution, Some("Failed to get distribution for a code block node.".to_smolstr()), )), + Node::Invalid(_) => Err(SbroadError::Invalid( + Entity::Distribution, + Some("Failed to get distribution for an invalid node.".to_smolstr()), + )), } } diff --git a/sbroad-core/src/ir/distribution/tests.rs b/sbroad-core/src/ir/distribution/tests.rs index 342a394e7..6b63c09a7 100644 --- a/sbroad-core/src/ir/distribution/tests.rs +++ b/sbroad-core/src/ir/distribution/tests.rs @@ -31,31 +31,27 @@ fn proj_preserve_dist_key() { plan.top = Some(proj_id); - let scan_output: NodeId = if let Node::Relational(scan) = plan.get_node(scan_id).unwrap() { - scan.output() - } else { - panic!("Invalid plan!"); - }; + let rel_node = plan.get_relation_node(scan_id).unwrap(); + let scan_output = rel_node.output(); + 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() - ); - } + let expr_node = plan.get_expression_node(scan_output).unwrap(); + let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1, 0]) }; + assert_eq!( + &Distribution::Segment { keys: keys.into() }, + expr_node.distribution().unwrap() + ); + + let rel_node = plan.get_relation_node(proj_id).unwrap(); + let proj_output: NodeId = rel_node.output(); - let proj_output: NodeId = if let Node::Relational(proj) = plan.get_node(proj_id).unwrap() { - proj.output() - } else { - panic!("Invalid plan!"); - }; plan.set_distribution(proj_output).unwrap(); - if let Node::Expression(proj_row) = plan.get_node(proj_output).unwrap() { + let expr_node = plan.get_node(proj_output).unwrap(); + if let Node::Expression(expr) = expr_node { let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1, 0]) }; assert_eq!( &Distribution::Segment { keys: keys.into() }, - proj_row.distribution().unwrap() + expr.distribution().unwrap() ); } } @@ -68,10 +64,10 @@ fn projection_any_dist_for_expr() { // check explain first let expected_explain = SmolStr::from( - r#"projection (sum(("count_13"::integer))::decimal -> "col_1") + r#"projection (sum(("count_096"::integer))::decimal -> "col_1") motion [policy: full] scan - projection (count(("test_space"."id"::unsigned))::integer -> "count_13") + projection (count(("test_space"."id"::unsigned))::integer -> "count_096") scan "test_space" execution options: sql_vdbe_max_steps = 45000 @@ -88,7 +84,7 @@ vtable_max_rows = 5000 .find(|level_node| { matches!( plan.get_relation_node(level_node.1).unwrap(), - Relational::Projection { .. } + Relational::Projection(_) ) }) .unwrap() diff --git a/sbroad-core/src/ir/explain.rs b/sbroad-core/src/ir/explain.rs index 60c010450..9e94e18c1 100644 --- a/sbroad-core/src/ir/explain.rs +++ b/sbroad-core/src/ir/explain.rs @@ -9,19 +9,26 @@ use smol_str::{format_smolstr, SmolStr, ToSmolStr}; use crate::errors::{Entity, SbroadError}; use crate::executor::engine::helpers::to_user; use crate::ir::expression::cast::Type as CastType; -use crate::ir::expression::{Expression, TrimKind}; -use crate::ir::operator::{ - ConflictStrategy, JoinKind, OrderByElement, OrderByEntity, OrderByType, Relational, +use crate::ir::expression::TrimKind; +use crate::ir::node::{ + Alias, ArithmeticExpr, BoolExpr, Case, Cast, Constant, Delete, GroupBy as GroupByRel, Having, + Insert, Join, Motion as MotionRel, NodeId, OrderBy as OrderByRel, Projection as ProjectionRel, + Reference, Row as RowExpr, ScanCte, ScanRelation, ScanSubQuery, Selection, StableFunction, + Trim, UnaryExpr, Update as UpdateRel, Values, ValuesRow, }; +use crate::ir::operator::{ConflictStrategy, JoinKind, OrderByElement, OrderByEntity, OrderByType}; use crate::ir::relation::Type; use crate::ir::transformation::redistribution::{ MotionKey as IrMotionKey, MotionPolicy as IrMotionPolicy, Target as IrTarget, }; use crate::ir::{OptionKind, Plan}; -use super::expression::{FunctionFeature, NodeId}; +use super::expression::FunctionFeature; +use super::node::expression::Expression; +use super::node::relational::Relational; +use super::node::Limit; use super::operator::{Arithmetic, Bool, Unary}; -use super::tree::traversal::{PostOrder, EXPR_CAPACITY, REL_CAPACITY}; +use super::tree::traversal::{LevelNode, PostOrder, EXPR_CAPACITY, REL_CAPACITY}; use super::value::Value; #[derive(Debug, PartialEq, Serialize)] @@ -130,12 +137,11 @@ impl ColExpr { let mut dft_post = PostOrder::with_capacity(|node| plan.nodes.expr_iter(node, false), EXPR_CAPACITY); - for level_node in dft_post.iter(subtree_top) { - let id = level_node.1; + for LevelNode(_, id) in dft_post.iter(subtree_top) { let current_node = plan.get_expression_node(id)?; match ¤t_node { - Expression::Cast { to, .. } => { + Expression::Cast(Cast { to, .. }) => { let (expr, _) = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "stack is empty while processing CAST expression".to_smolstr(), @@ -144,11 +150,11 @@ impl ColExpr { let cast_expr = ColExpr::Cast(Box::new(expr), *to); stack.push((cast_expr, id)); } - Expression::Case { + Expression::Case(Case { search_expr, when_blocks, else_expr, - } => { + }) => { let else_expr_col = if else_expr.is_some() { let (expr, _) = stack .pop() @@ -185,25 +191,24 @@ impl ColExpr { let cast_expr = ColExpr::Case(search_expr_col, match_expr_cols, else_expr_col); stack.push((cast_expr, id)); } - Expression::CountAsterisk => { + Expression::CountAsterisk(_) => { let count_asterisk_expr = ColExpr::Column("*".to_string(), current_node.calculate_type(plan)?); stack.push((count_asterisk_expr, id)); } - Expression::Reference { position, .. } => { + Expression::Reference(Reference { position, .. }) => { let mut col_name = String::new(); - let rel_id = *plan.get_relational_from_reference_node(id)?; - let rel_node = plan.get_relation_node(rel_id)?; + let rel_id: NodeId = *plan.get_relational_from_reference_node(id)?; - if let Some(name) = rel_node.scan_name(plan, *position)? { + if let Some(name) = plan.scan_name(rel_id, *position)? { col_name.push('"'); col_name.push_str(name); col_name.push('"'); col_name.push('.'); } - let alias = plan.get_alias_from_reference_node(current_node)?; + let alias = plan.get_alias_from_reference_node(¤t_node)?; col_name.push('"'); col_name.push_str(alias); col_name.push('"'); @@ -211,7 +216,7 @@ impl ColExpr { let ref_expr = ColExpr::Column(col_name, current_node.calculate_type(plan)?); stack.push((ref_expr, id)); } - Expression::Concat { .. } => { + Expression::Concat(_) => { let (right, _) = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "stack is empty while processing CONCAT expression".to_smolstr(), @@ -225,12 +230,12 @@ impl ColExpr { let concat_expr = ColExpr::Concat(Box::new(left), Box::new(right)); stack.push((concat_expr, id)); } - Expression::Constant { value } => { + Expression::Constant(Constant { value }) => { let expr = ColExpr::Column(value.to_string(), current_node.calculate_type(plan)?); stack.push((expr, id)); } - Expression::Trim { kind, .. } => { + Expression::Trim(Trim { kind, .. }) => { let (target, _) = stack .pop() .expect("stack is empty while processing TRIM expression"); @@ -238,14 +243,14 @@ impl ColExpr { let trim_expr = ColExpr::Trim(kind.clone(), pattern, Box::new(target)); stack.push((trim_expr, id)); } - Expression::StableFunction { + Expression::StableFunction(StableFunction { name, children, feature, func_type, is_system: is_aggr, .. - } => { + }) => { let mut len = children.len(); let mut args: Vec<ColExpr> = Vec::with_capacity(len); while len > 0 { @@ -267,7 +272,7 @@ impl ColExpr { ); stack.push((func_expr, id)); } - Expression::Row { list, .. } => { + Expression::Row(RowExpr { list, .. }) => { let mut len = list.len(); let mut row: Vec<(ColExpr, NodeId)> = Vec::with_capacity(len); while len > 0 { @@ -284,11 +289,11 @@ impl ColExpr { let row_expr = ColExpr::Row(row); stack.push((row_expr, id)); } - Expression::Arithmetic { + Expression::Arithmetic(ArithmeticExpr { left: _, op, right: _, - } => { + }) => { let (right, _) = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "stack is empty while processing ARITHMETIC expression".to_smolstr(), @@ -314,7 +319,7 @@ impl ColExpr { let parentheses_expr = ColExpr::Parentheses(Box::new(child_expr)); stack.push((parentheses_expr, id)); } - Expression::Alias { name, .. } => { + Expression::Alias(Alias { name, .. }) => { let (expr, _) = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "stack is empty while processing ALIAS expression".to_smolstr(), @@ -323,7 +328,7 @@ impl ColExpr { let alias_expr = ColExpr::Alias(Box::new(expr), name.clone()); stack.push((alias_expr, id)); } - Expression::Bool { op, .. } => { + Expression::Bool(BoolExpr { op, .. }) => { let (right, _) = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "stack is empty while processing BOOL expression".to_smolstr(), @@ -340,7 +345,7 @@ impl ColExpr { stack.push((bool_expr, id)); } - Expression::Unary { op, .. } => { + Expression::Unary(UnaryExpr { op, .. }) => { let (expr, _) = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "stack is empty while processing UNARY expression".to_smolstr(), @@ -549,12 +554,12 @@ struct Update { impl Update { #[allow(dead_code)] fn new(plan: &Plan, update_id: NodeId) -> Result<Self, SbroadError> { - if let Relational::Update { + if let Relational::Update(UpdateRel { relation: ref rel, update_columns_map, output: ref output_id, .. - } = plan.get_relation_node(update_id)? + }) = plan.get_relation_node(update_id)? { let mut update_statements: Vec<(SmolStr, SmolStr)> = Vec::with_capacity(update_columns_map.len()); @@ -588,7 +593,7 @@ impl Update { ) })?; let node = plan.get_expression_node(alias_id)?; - if let Expression::Alias { name, .. } = node { + if let Expression::Alias(Alias { name, .. }) = node { to_user(name) } else { return Err(SbroadError::Invalid( @@ -610,7 +615,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}" )), )) } @@ -712,7 +717,6 @@ impl Row { fn add_col(&mut self, row: RowVal) { self.cols.push(row); } - fn from_col_exprs_with_ids( plan: &Plan, exprs_with_ids: &mut Vec<(ColExpr, NodeId)>, @@ -725,7 +729,7 @@ impl Row { match ¤t_node { Expression::Reference { .. } => { - let rel_id = *plan.get_relational_from_reference_node(expr_id)?; + let rel_id: NodeId = *plan.get_relational_from_reference_node(expr_id)?; let rel_node = plan.get_relation_node(rel_id)?; if plan.is_additional_child(rel_id)? { @@ -735,7 +739,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))); @@ -743,7 +747,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:?}" )), )); } @@ -1032,7 +1036,7 @@ impl FullExplain { #[allow(dead_code)] #[allow(clippy::too_many_lines)] 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 stack: Vec<ExplainTreePart> = Vec::new(); let mut result = FullExplain::default(); result .exec_options @@ -1043,9 +1047,7 @@ impl FullExplain { )); let mut dft_post = PostOrder::with_capacity(|node| ir.nodes.rel_iter(node), REL_CAPACITY); - for level_node in dft_post.iter(top_id) { - let level = level_node.0; - let id = level_node.1; + for LevelNode(level, id) in dft_post.iter(top_id) { let mut current_node = ExplainTreePart::with_level(level); let node = ir.get_relation_node(id)?; current_node.current = match &node { @@ -1071,9 +1073,9 @@ impl FullExplain { } Some(ExplainNode::Except) } - Relational::GroupBy { + Relational::GroupBy(GroupByRel { gr_cols, output, .. - } => { + }) => { let child = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "Groupby node must have at least one child".into(), @@ -1083,9 +1085,9 @@ impl FullExplain { let p = GroupBy::new(ir, gr_cols, *output, &HashMap::new())?; Some(ExplainNode::GroupBy(p)) } - Relational::OrderBy { + Relational::OrderBy(OrderByRel { order_by_elements, .. - } => { + }) => { let child = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "OrderBy node must have at least one child".into(), @@ -1095,7 +1097,7 @@ impl FullExplain { let o_b = OrderBy::new(ir, order_by_elements, &HashMap::new())?; Some(ExplainNode::OrderBy(o_b)) } - Relational::Projection { output, .. } => { + Relational::Projection(ProjectionRel { output, .. }) => { // TODO: change this logic when we'll enable sub-queries in projection let child = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( @@ -1106,16 +1108,16 @@ impl FullExplain { let p = Projection::new(ir, *output, &HashMap::new())?; Some(ExplainNode::Projection(p)) } - Relational::ScanRelation { + Relational::ScanRelation(ScanRelation { relation, alias, .. - } => { + }) => { let s = Scan::new( relation.to_smolstr(), alias.as_ref().map(ToSmolStr::to_smolstr), ); Some(ExplainNode::Scan(s)) } - Relational::ScanCte { alias, .. } => { + Relational::ScanCte(ScanCte { alias, .. }) => { let child = stack.pop().expect("CTE node must have exactly one child"); let existing_pos = result.subqueries.iter().position(|sq| *sq == child); let pos = existing_pos.unwrap_or_else(|| { @@ -1124,12 +1126,12 @@ impl FullExplain { }); Some(ExplainNode::Cte(alias.clone(), Ref::new(pos))) } - Relational::Selection { + Relational::Selection(Selection { children, filter, .. - } - | Relational::Having { + }) + | Relational::Having(Having { children, filter, .. - } => { + }) => { let mut sq_ref_map: SubQueryRefMap = HashMap::with_capacity(children.len() - 1); if let Some((_, other)) = children.split_first() { for sq_id in other.iter().rev() { @@ -1177,7 +1179,7 @@ impl FullExplain { Some(ExplainNode::UnionAll) } } - Relational::ScanSubQuery { alias, .. } => { + Relational::ScanSubQuery(ScanSubQuery { alias, .. }) => { let child = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "ScanSubQuery node must have exactly one child".into(), @@ -1187,9 +1189,9 @@ impl FullExplain { let s = SubQuery::new(alias.as_ref().map(ToString::to_string)); Some(ExplainNode::SubQuery(s)) } - Relational::Motion { + Relational::Motion(MotionRel { children, policy, .. - } => { + }) => { let child = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "Motion node must have exactly one child".into(), @@ -1205,7 +1207,8 @@ impl FullExplain { })?; let child_output_id = ir.get_relation_node(*child_id)?.output(); - let col_list = ir.get_expression_node(child_output_id)?.get_row_list()?; + let child_node = ir.get_expression_node(child_output_id)?; + let col_list = child_node.get_row_list()?; let targets = (s.targets) .iter() @@ -1247,12 +1250,12 @@ impl FullExplain { Some(ExplainNode::Motion(m)) } - Relational::Join { + Relational::Join(Join { children, condition, kind, .. - } => { + }) => { if children.len() < 2 { return Err(SbroadError::UnexpectedNumberOfValues( "Join must have at least two children".into(), @@ -1287,7 +1290,7 @@ impl FullExplain { kind: kind.clone(), })) } - Relational::ValuesRow { data, children, .. } => { + Relational::ValuesRow(ValuesRow { data, children, .. }) => { let mut sq_ref_map: SubQueryRefMap = HashMap::with_capacity(children.len()); for sq_id in children.iter().rev() { @@ -1306,7 +1309,7 @@ impl FullExplain { Some(ExplainNode::ValueRow(row)) } - Relational::Values { children, .. } => { + Relational::Values(Values { children, .. }) => { let mut amount_values = children.len(); while amount_values > 0 { @@ -1321,11 +1324,11 @@ impl FullExplain { } Some(ExplainNode::Value) } - Relational::Insert { + Relational::Insert(Insert { relation, conflict_strategy, .. - } => { + }) => { let values = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "Insert node failed to pop a value row.".into(), @@ -1350,7 +1353,7 @@ impl FullExplain { Some(ExplainNode::Update(Update::new(ir, id)?)) } - Relational::Delete { relation, .. } => { + Relational::Delete(Delete { relation, .. }) => { let values = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "Delete node failed to pop a value row.".into(), @@ -1361,7 +1364,7 @@ impl FullExplain { Some(ExplainNode::Delete(relation.to_smolstr())) } - Relational::Limit { limit, .. } => { + Relational::Limit(Limit { limit, .. }) => { let child = stack.pop().ok_or_else(|| { SbroadError::UnexpectedNumberOfValues( "Limit node must have exactly one child".into(), diff --git a/sbroad-core/src/ir/expression.rs b/sbroad-core/src/ir/expression.rs index df68c1940..14ef78224 100644 --- a/sbroad-core/src/ir/expression.rs +++ b/sbroad-core/src/ir/expression.rs @@ -7,24 +7,24 @@ //! - distribution of the data in the tuple use ahash::RandomState; +use distribution::Distribution; 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; +use super::{ + distribution, operator, Alias, ArithmeticExpr, BoolExpr, Case, Cast, Concat, Constant, + ExprInParentheses, Expression, LevelNode, MutExpression, MutNode, Node, NodeId, Reference, + Relational, Row, StableFunction, Trim, UnaryExpr, Value, +}; use crate::errors::{Entity, SbroadError}; use crate::executor::engine::helpers::to_user; -use crate::ir::aggregates::AggregateKind; -use crate::ir::operator::{Bool, Relational}; +use crate::ir::operator::Bool; use crate::ir::relation::Type; -use crate::ir::Positions as Targets; - -use super::distribution::Distribution; -use super::tree::traversal::{PostOrderWithFilter, EXPR_CAPACITY}; -use super::value::Value; -use super::{operator, ArenaType, Node, Nodes, Plan}; +use crate::ir::tree::traversal::{PostOrderWithFilter, EXPR_CAPACITY}; +use crate::ir::{Nodes, Plan, Positions as Targets}; pub mod cast; pub mod concat; @@ -32,181 +32,6 @@ pub mod types; 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. -/// -/// A tuple describes a single portion of data moved among cluster nodes. -/// It consists of the ordered, strictly typed expressions with names -/// (columns) and additional information about data distribution policy. -/// -/// Tuple is a tree with a `Row` top (level 0) and a list of the named -/// `Alias` columns (level 1). This convention is used across the code -/// and should not be changed. It ensures that we always know the -/// name of any column in the tuple and therefore simplifies AST -/// deserialization. -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -pub enum Expression { - /// Expression name. - /// - /// Example: `42 as a`. - Alias { - /// Alias name. - name: SmolStr, - /// Child expression node index in the plan node arena. - 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: NodeId, - /// Boolean operator. - op: operator::Bool, - /// Right branch expression node index in the plan node arena. - right: NodeId, - }, - /// Binary expression returning row result. - /// - /// Example: `a + b > 42`, `a + b < c + 1`, `1 + 2 != 2 * 2`. - /// - /// TODO: always cover children with parentheses (in to_sql). - Arithmetic { - /// Left branch expression node index in the plan node arena. - left: NodeId, - /// Arithmetic operator. - op: operator::Arithmetic, - /// Right branch expression node index in the plan node arena. - right: NodeId, - }, - /// Type cast expression. - /// - /// Example: `cast(a as text)`. - Cast { - /// Target expression that must be casted to another type. - child: NodeId, - /// Cast type. - to: cast::Type, - }, - /// String concatenation expression. - /// - /// Example: `a || 'hello'`. - Concat { - /// Left expression node id. - left: NodeId, - /// Right expression node id. - right: NodeId, - }, - /// Constant expressions. - /// - /// Example: `42`. - Constant { - /// Contained value (boolean, number, string or null) - value: Value, - }, - /// Reference to the position in the incoming tuple(s). - /// Uses a relative pointer as a coordinate system: - /// - relational node (containing this reference) - /// - target(s) in the relational nodes list of children - /// - column position in the child(ren) output tuple - Reference { - /// Relational node ID that contains current reference. - parent: Option<NodeId>, - /// Targets in the relational node children list. - /// - Leaf nodes (relation scans): None. - /// - Union nodes: two elements (left and right). - /// - Other: single element. - targets: Option<Vec<usize>>, - /// Expression position in the input tuple (i.e. `Alias` column). - position: usize, - /// Referred column type in the input tuple. - col_type: Type, - }, - /// Top of the tuple tree. - /// - /// If the current tuple is the output for some relational operator, it should - /// consist of the list of aliases. Otherwise (rows in selection filter - /// or in join condition) we don't require aliases in the list. - /// - /// - /// Example: (a, b, 1). - Row { - /// A list of the alias expression node indexes in the plan node arena. - list: Vec<NodeId>, - /// Resulting data distribution of the tuple. Should be filled as a part - /// of the last "add Motion" transformation. - distribution: Option<Distribution>, - }, - /// Stable function cannot modify the database and - /// is guaranteed to return the same results given - /// the same arguments for all rows within a single - /// statement. - /// - /// Example: `bucket_id("1")` (the number of buckets can be - /// changed only after restarting the cluster). - StableFunction { - /// Function name. - name: SmolStr, - /// Function arguments. - children: Vec<NodeId>, - /// Optional function feature. - feature: Option<FunctionFeature>, - /// Function return type. - func_type: Type, - /// Whether function is provided by tarantool, - /// when referencing these funcs from local - /// sql we must not use quotes. - /// Examples: aggregates, substr - is_system: bool, - }, - /// Trim expression. - Trim { - /// Trim kind. - kind: Option<TrimKind>, - /// Trim string pattern to remove (it can be an expression). - pattern: Option<NodeId>, - /// Target expression to trim. - target: NodeId, - }, - /// Unary expression returning boolean result. - Unary { - /// Unary operator. - op: operator::Unary, - /// Child expression node index in the plan node arena. - child: NodeId, - }, - /// Argument of `count` aggregate in `count(*)` expression - CountAsterisk, - ExprInParentheses { - child: NodeId, - }, - Case { - search_expr: Option<NodeId>, - when_blocks: Vec<(NodeId, NodeId)>, - else_expr: Option<NodeId>, - }, -} - #[derive(Clone, Debug, Hash, Deserialize, PartialEq, Eq, Serialize)] pub enum FunctionFeature { /// Current function is an aggregate function and is marked as DISTINCT. @@ -234,171 +59,14 @@ impl TrimKind { } } -#[allow(dead_code)] -impl Expression { - /// Gets current row distribution. - /// - /// # Errors - /// Returns `SbroadError` when the function is called on expression - /// other than `Row` or a node doesn't know its distribution yet. - pub fn distribution(&self) -> Result<&Distribution, SbroadError> { - if let Expression::Row { distribution, .. } = self { - let Some(dist) = distribution else { - return Err(SbroadError::Invalid( - Entity::Distribution, - Some("distribution is uninitialized".into()), - )); - }; - return Ok(dist); - } - Err(SbroadError::Invalid(Entity::Expression, None)) - } - - /// Clone the row children list. - /// - /// # Errors - /// - node isn't `Row` - pub fn clone_row_list(&self) -> Result<Vec<NodeId>, SbroadError> { - match self { - Expression::Row { list, .. } => Ok(list.clone()), - _ => Err(SbroadError::Invalid( - Entity::Expression, - Some("node isn't Row type".into()), - )), - } - } - - #[must_use] - pub fn is_aggregate_name(name: &str) -> bool { - // currently we support only simple aggregates - AggregateKind::new(name).is_some() - } - - #[must_use] - pub fn is_aggregate_fun(&self) -> bool { - match self { - Expression::StableFunction { name, .. } => Expression::is_aggregate_name(name), - _ => false, - } - } - - /// Get a reference to the row children list. - /// - /// # Errors - /// - node isn't `Row` - pub fn get_row_list(&self) -> Result<&[NodeId], SbroadError> { - match self { - Expression::Row { ref list, .. } => Ok(list), - _ => Err(SbroadError::Invalid( - Entity::Expression, - Some("node isn't Row type".into()), - )), - } - } - - /// Get a mut reference to the row children list. - /// - /// # Errors - /// - node isn't `Row` - 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( - Entity::Expression, - Some("node isn't Row type".into()), - )), - } - } - - /// Get a mutable reference to the row children list. - /// - /// # Errors - /// - node isn't `Row` - 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( - Entity::Expression, - Some("node isn't Row type".into()), - )), - } - } - - /// Gets alias node name. - /// - /// # Errors - /// - node isn't `Alias` - pub fn get_alias_name(&self) -> Result<&str, SbroadError> { - match self { - Expression::Alias { name, .. } => Ok(name.as_str()), - _ => Err(SbroadError::Invalid( - Entity::Node, - Some("node is not Alias type".into()), - )), - } - } - - /// Checks for distribution determination - /// - /// # Errors - /// - distribution isn't set - pub fn has_unknown_distribution(&self) -> Result<bool, SbroadError> { - let d = self.distribution()?; - Ok(d.is_unknown()) - } - - /// Gets relational node id containing the reference. - /// - /// # Errors - /// - node isn't reference type - /// - reference doesn't have a parent - 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())) - }); - } - Err(SbroadError::Invalid( - Entity::Expression, - Some("node is not Reference type".into()), - )) - } - - /// The node is a row expression. - #[must_use] - pub fn is_row(&self) -> bool { - matches!(self, Expression::Row { .. }) - } - #[must_use] - pub fn is_arithmetic(&self) -> bool { - matches!(self, Expression::Arithmetic { .. }) - } - - /// Replaces parent in the reference node with the new one. - 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; - } - } - } - - /// Flushes parent in the reference node. - pub fn flush_parent_in_reference(&mut self) { - if let Expression::Reference { parent, .. } = self { - *parent = None; - } - } -} - impl Nodes { /// Adds exression covered with parentheses node. /// /// # Errors /// - child node is invalid 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)) + let covered_with_parentheses = ExprInParentheses { child }; + self.push(covered_with_parentheses.into()) } /// Adds alias node. @@ -407,11 +75,11 @@ impl Nodes { /// - child node is invalid /// - name is empty pub fn add_alias(&mut self, name: &str, child: NodeId) -> Result<NodeId, SbroadError> { - let alias = Expression::Alias { + let alias = Alias { name: SmolStr::from(name), child, }; - Ok(self.push(Node::Expression(alias))) + Ok(self.push(alias.into())) } /// Adds boolean node. @@ -436,7 +104,7 @@ impl Nodes { format_smolstr!("(right child of boolean node) from arena with index {right}"), ) })?; - Ok(self.push(Node::Expression(Expression::Bool { left, op, right }))) + Ok(self.push(BoolExpr { left, op, right }.into())) } /// Adds arithmetic node. @@ -461,7 +129,7 @@ impl Nodes { format_smolstr!("(right child of Arithmetic node) from arena with index {right:?}"), ) })?; - Ok(self.push(Node::Expression(Expression::Arithmetic { left, op, right }))) + Ok(self.push(ArithmeticExpr { left, op, right }.into())) } /// Adds reference node. @@ -472,18 +140,18 @@ impl Nodes { position: usize, col_type: Type, ) -> NodeId { - let r = Expression::Reference { + let r = Reference { parent, targets, position, col_type, }; - self.push(Node::Expression(r)) + self.push(r.into()) } /// Adds row node. pub fn add_row(&mut self, list: Vec<NodeId>, distribution: Option<Distribution>) -> NodeId { - self.push(Node::Expression(Expression::Row { list, distribution })) + self.push(Row { list, distribution }.into()) } /// Adds unary boolean node. @@ -501,7 +169,7 @@ impl Nodes { format_smolstr!("from arena with index {child}"), ) })?; - Ok(self.push(Node::Expression(Expression::Unary { op, child }))) + Ok(self.push(UnaryExpr { op, child }.into())) } } @@ -592,41 +260,43 @@ impl<'plan> Comparator<'plan> { if let Node::Expression(left) = l { if let Node::Expression(right) = r { match left { - Expression::Alias { .. } => {} - Expression::CountAsterisk => { - return Ok(matches!(right, Expression::CountAsterisk)) + Expression::Alias(_) => {} + Expression::CountAsterisk(_) => { + return Ok(matches!(right, Expression::CountAsterisk(_))) } - Expression::ExprInParentheses { child: l_child } => { - if let Expression::ExprInParentheses { child: r_child } = right { + Expression::ExprInParentheses(ExprInParentheses { child: l_child }) => { + if let Expression::ExprInParentheses(ExprInParentheses { child: r_child }) = + right + { return self.are_subtrees_equal(*l_child, *r_child); } } - Expression::Bool { + Expression::Bool(BoolExpr { left: left_left, op: op_left, right: right_left, - } => { - if let Expression::Bool { + }) => { + if let Expression::Bool(BoolExpr { left: left_right, op: op_right, right: right_right, - } = right + }) = right { return Ok(*op_left == *op_right && self.are_subtrees_equal(*left_left, *left_right)? && self.are_subtrees_equal(*right_left, *right_right)?); } } - Expression::Case { + Expression::Case(Case { search_expr: search_expr_left, when_blocks: when_blocks_left, else_expr: else_expr_left, - } => { - if let Expression::Case { + }) => { + if let Expression::Case(Case { search_expr: search_expr_right, when_blocks: when_blocks_right, else_expr: else_expr_right, - } = right + }) = right { let mut search_expr_equal = false; if let (Some(search_expr_left), Some(search_expr_right)) = @@ -654,58 +324,58 @@ impl<'plan> Comparator<'plan> { return Ok(search_expr_equal && when_blocks_equal && else_expr_equal); } } - Expression::Arithmetic { + Expression::Arithmetic(ArithmeticExpr { op: op_left, left: l_left, right: r_left, - } => { - if let Expression::Arithmetic { + }) => { + if let Expression::Arithmetic(ArithmeticExpr { op: op_right, left: l_right, right: r_right, - } = right + }) = right { return Ok(*op_left == *op_right && self.are_subtrees_equal(*l_left, *l_right)? && self.are_subtrees_equal(*r_left, *r_right)?); } } - Expression::Cast { + Expression::Cast(Cast { child: child_left, to: to_left, - } => { - if let Expression::Cast { + }) => { + if let Expression::Cast(Cast { child: child_right, to: to_right, - } = right + }) = right { return Ok(*to_left == *to_right && self.are_subtrees_equal(*child_left, *child_right)?); } } - Expression::Concat { + Expression::Concat(Concat { left: left_left, right: right_left, - } => { - if let Expression::Concat { + }) => { + if let Expression::Concat(Concat { left: left_right, right: right_right, - } = right + }) = right { return Ok(self.are_subtrees_equal(*left_left, *left_right)? && self.are_subtrees_equal(*right_left, *right_right)?); } } - Expression::Trim { + Expression::Trim(Trim { kind: kind_left, pattern: pattern_left, target: target_left, - } => { - if let Expression::Trim { + }) => { + if let Expression::Trim(Trim { kind: kind_right, pattern: pattern_right, target: target_right, - } = right + }) = right { match (pattern_left, pattern_right) { (Some(p_left), Some(p_right)) => { @@ -723,31 +393,31 @@ impl<'plan> Comparator<'plan> { } } } - Expression::Constant { value: value_left } => { - if let Expression::Constant { value: value_right } = right { + Expression::Constant(Constant { value: value_left }) => { + if let Expression::Constant(Constant { value: value_right }) = right { return Ok(*value_left == *value_right); } } - Expression::Reference { .. } => { - if let Expression::Reference { .. } = right { + Expression::Reference(_) => { + if let Expression::Reference(_) = right { return match self.policy { ReferencePolicy::ByAliases => { let alias_left = - self.plan.get_alias_from_reference_node(left)?; + self.plan.get_alias_from_reference_node(&left)?; let alias_right = - self.plan.get_alias_from_reference_node(right)?; + self.plan.get_alias_from_reference_node(&right)?; Ok(alias_left == alias_right) } ReferencePolicy::ByFields => Ok(left == right), }; } } - Expression::Row { + Expression::Row(Row { list: list_left, .. - } => { - if let Expression::Row { + }) => { + if let Expression::Row(Row { list: list_right, .. - } = right + }) = right { return Ok(list_left .iter() @@ -755,20 +425,20 @@ impl<'plan> Comparator<'plan> { .all(|(l, r)| self.are_subtrees_equal(*l, *r).unwrap_or(false))); } } - Expression::StableFunction { + Expression::StableFunction(StableFunction { name: name_left, children: children_left, feature: feature_left, func_type: func_type_left, is_system: is_aggr_left, - } => { - if let Expression::StableFunction { + }) => { + if let Expression::StableFunction(StableFunction { name: name_right, children: children_right, feature: feature_right, func_type: func_type_right, is_system: is_aggr_right, - } = right + }) = right { return Ok(name_left == name_right && feature_left == feature_right @@ -779,14 +449,14 @@ impl<'plan> Comparator<'plan> { )); } } - Expression::Unary { + Expression::Unary(UnaryExpr { op: op_left, child: child_left, - } => { - if let Expression::Unary { + }) => { + if let Expression::Unary(UnaryExpr { op: op_right, child: child_right, - } = right + }) = right { return Ok(*op_left == *op_right && self.are_subtrees_equal(*child_left, *child_right)?); @@ -819,18 +489,18 @@ impl<'plan> Comparator<'plan> { panic!("Hasher should have been set previously"); }; match node { - Expression::ExprInParentheses { child } => { + Expression::ExprInParentheses(ExprInParentheses { child }) => { self.hash_for_child_expr(*child, depth); } - Expression::Alias { child, name } => { + Expression::Alias(Alias { child, name }) => { name.hash(state); self.hash_for_child_expr(*child, depth); } - Expression::Case { + Expression::Case(Case { search_expr, when_blocks, else_expr, - } => { + }) => { if let Some(search_expr) = search_expr { self.hash_for_child_expr(*search_expr, depth); } @@ -842,47 +512,47 @@ impl<'plan> Comparator<'plan> { self.hash_for_child_expr(*else_expr, depth); } } - Expression::Bool { op, left, right } => { + Expression::Bool(BoolExpr { op, left, right }) => { op.hash(state); self.hash_for_child_expr(*left, depth); self.hash_for_child_expr(*right, depth); } - Expression::Arithmetic { op, left, right } => { + Expression::Arithmetic(ArithmeticExpr { op, left, right }) => { op.hash(state); self.hash_for_child_expr(*left, depth); self.hash_for_child_expr(*right, depth); } - Expression::Cast { child, to } => { + Expression::Cast(Cast { child, to }) => { to.hash(state); self.hash_for_child_expr(*child, depth); } - Expression::Concat { left, right } => { + Expression::Concat(Concat { left, right }) => { self.hash_for_child_expr(*left, depth); self.hash_for_child_expr(*right, depth); } - Expression::Trim { + Expression::Trim(Trim { kind, pattern, target, - } => { + }) => { kind.hash(state); if let Some(pattern) = pattern { self.hash_for_child_expr(*pattern, depth); } self.hash_for_child_expr(*target, depth); } - Expression::Constant { value } => { + Expression::Constant(Constant { value }) => { value.hash(state); } - Expression::Reference { + Expression::Reference(Reference { parent, position, targets, col_type, - } => match self.policy { + }) => match self.policy { ReferencePolicy::ByAliases => { self.plan - .get_alias_from_reference_node(node) + .get_alias_from_reference_node(&node) .unwrap_or("") .hash(state); } @@ -893,18 +563,18 @@ impl<'plan> Comparator<'plan> { col_type.hash(state); } }, - Expression::Row { list, .. } => { + Expression::Row(Row { list, .. }) => { for child in list { self.hash_for_child_expr(*child, depth); } } - Expression::StableFunction { + Expression::StableFunction(StableFunction { name, children, func_type, feature, is_system: is_aggr, - } => { + }) => { feature.hash(state); func_type.hash(state); name.hash(state); @@ -913,11 +583,11 @@ impl<'plan> Comparator<'plan> { self.hash_for_child_expr(*child, depth); } } - Expression::Unary { child, op } => { + Expression::Unary(UnaryExpr { child, op }) => { op.hash(state); self.hash_for_child_expr(*child, depth); } - Expression::CountAsterisk => { + Expression::CountAsterisk(_) => { "CountAsterisk".hash(state); } } @@ -980,7 +650,7 @@ impl ColumnPositionMap { for (pos, alias_id) in alias_ids.iter().enumerate() { let alias = plan.get_expression_node(*alias_id)?; let alias_name = SmolStr::from(alias.get_alias_name()?); - let scan_name = rel_node.scan_name(plan, pos)?.map(SmolStr::from); + let scan_name = plan.scan_name(rel_id, pos)?.map(SmolStr::from); // For query `select "a", "b" as "a" from (select "a", "b" from t)` // column entry "a" will have `Position::Multiple` so that if parent operator will // reference "a" we won't be able to identify which of these two columns @@ -1296,7 +966,7 @@ impl Plan { let relational_op = self.get_relation_node(rel_child)?; let output_id = relational_op.output(); - let child_node_row_list = self.get_row_list(output_id)?.to_vec(); + let child_node_row_list = self.get_row_list(output_id)?.clone(); let mut indices: Vec<usize> = Vec::new(); match columns_spec { @@ -1312,7 +982,7 @@ impl Plan { indices.push(index); } } - ColumnsRetrievalSpec::Indices(idx) => indices = idx.clone(), + ColumnsRetrievalSpec::Indices(idx) => indices.clone_from(&idx), }; let exclude_positions = column_positions_to_exclude(rel_child)?; @@ -1359,7 +1029,6 @@ impl Plan { let alias_expr = self.get_expression_node(alias_node_id)?; let alias_name = SmolStr::from(alias_expr.get_alias_name()?); let col_type = alias_expr.calculate_type(self)?; - let r_id = self.nodes.add_ref(None, Some(new_targets), pos, col_type); if need_aliases { let a_id = self.nodes.add_alias(&alias_name, r_id)?; @@ -1607,21 +1276,21 @@ impl Plan { &self, ref_id: NodeId, ) -> Result<&NodeId, SbroadError> { - if let Node::Expression(Expression::Reference { + if let Node::Expression(Expression::Reference(Reference { targets, parent, .. - }) = self.get_node(ref_id)? + })) = self.get_node(ref_id)? { 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)?; if let Relational::Insert { .. } = rel { return Ok(referred_rel_id); } - let children = rel.children(); + let children = self.children(*referred_rel_id); match targets { None => { return Err(SbroadError::UnexpectedNumberOfValues( @@ -1667,7 +1336,7 @@ impl Plan { row_id: NodeId, ) -> Result<HashSet<NodeId, RandomState>, SbroadError> { let row = self.get_expression_node(row_id)?; - let capacity = if let Expression::Row { list, .. } = row { + let capacity = if let Expression::Row(Row { list, .. }) = row { list.len() } else { return Err(SbroadError::Invalid( @@ -1691,17 +1360,16 @@ impl Plan { // We don't expect much relational references in a row (5 is a reasonable number). let mut rel_nodes: HashSet<NodeId, RandomState> = HashSet::with_capacity_and_hasher(5, RandomState::new()); - for level_node in nodes { - let id = level_node.1; + for LevelNode(_, id) in nodes { let reference = self.get_expression_node(id)?; - if let Expression::Reference { + if let Expression::Reference(Reference { targets, parent, .. - } = reference + }) = reference { 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)?; @@ -1724,7 +1392,7 @@ impl Plan { let Ok(node) = self.get_expression_node(node_id) else { return false; }; - if let Expression::Bool { left, op, right } = node { + if let Expression::Bool(BoolExpr { left, op, right }) = node { if *op != Bool::Eq { return false; } @@ -1752,15 +1420,17 @@ impl Plan { pub fn is_trivalent(&self, expr_id: NodeId) -> Result<bool, SbroadError> { let expr = self.get_expression_node(expr_id)?; match expr { - Expression::Bool { .. } - | Expression::Arithmetic { .. } - | Expression::Unary { .. } - | Expression::Constant { + Expression::Bool(_) + | Expression::Arithmetic(_) + | Expression::Unary(_) + | Expression::Constant(Constant { value: Value::Boolean(_) | Value::Null, .. - } => return Ok(true), - Expression::ExprInParentheses { child } => return self.is_trivalent(*child), - Expression::Row { list, .. } => { + }) => return Ok(true), + Expression::ExprInParentheses(ExprInParentheses { child }) => { + return self.is_trivalent(*child) + } + Expression::Row(Row { list, .. }) => { if let (Some(inner_id), None) = (list.first(), list.get(1)) { return self.is_trivalent(*inner_id); } @@ -1778,7 +1448,7 @@ impl Plan { let expr = self.get_expression_node(expr_id)?; match expr { Expression::Reference { .. } => return Ok(true), - Expression::Row { list, .. } => { + Expression::Row(Row { list, .. }) => { if let (Some(inner_id), None) = (list.first(), list.get(1)) { return self.is_ref(*inner_id); } @@ -1801,7 +1471,7 @@ impl Plan { child_num: usize, ) -> Result<Value, SbroadError> { let node = self.get_expression_node(row_id)?; - if let Expression::Row { list, .. } = node { + if let Expression::Row(Row { list, .. }) = node { let const_node_id = list.get(child_num).ok_or_else(|| { SbroadError::NotFound(Entity::Node, format_smolstr!("{child_num}")) })?; @@ -1841,9 +1511,8 @@ impl Plan { subtree.populate_nodes(node_id); let references = subtree.take_nodes(); drop(subtree); - for level_node in references { - let id = level_node.1; - let node = self.get_mut_expression_node(id)?; + for LevelNode(_, id) in references { + let mut node = self.get_mut_expression_node(id)?; node.replace_parent_in_reference(from_id, to_id); } Ok(()) @@ -1869,14 +1538,43 @@ impl Plan { subtree.populate_nodes(node_id); let references = subtree.take_nodes(); drop(subtree); - for level_node in references { - let id = level_node.1; - let node = self.get_mut_expression_node(id)?; + for LevelNode(_, id) in references { + let mut node = self.get_mut_expression_node(id)?; node.flush_parent_in_reference(); } Ok(()) } } +impl Expression<'_> { + /// Get a reference to the row children list. + /// + /// # Errors + /// - node isn't `Row` + pub fn get_row_list(&self) -> Result<&Vec<NodeId>, SbroadError> { + match self { + Expression::Row(Row { ref list, .. }) => Ok(list), + _ => Err(SbroadError::Invalid( + Entity::Expression, + Some("node isn't Row type".into()), + )), + } + } + + /// Gets alias node name. + /// + /// # Errors + /// - node isn't `Alias` + pub fn get_alias_name(&self) -> Result<&str, SbroadError> { + match self { + Expression::Alias(Alias { name, .. }) => Ok(name.as_str()), + _ => Err(SbroadError::Invalid( + Entity::Node, + Some("node is not Alias type".into()), + )), + } + } +} + #[cfg(test)] mod tests; diff --git a/sbroad-core/src/ir/expression/cast.rs b/sbroad-core/src/ir/expression/cast.rs index d4a07d55b..92a5da90e 100644 --- a/sbroad-core/src/ir/expression/cast.rs +++ b/sbroad-core/src/ir/expression/cast.rs @@ -2,13 +2,13 @@ use std::fmt::{Display, Formatter}; use crate::errors::{Entity, SbroadError}; use crate::frontend::sql::ast::Rule; -use crate::ir::expression::Expression; +use crate::ir::node::Cast; use crate::ir::relation::Type as RelationType; -use crate::ir::{Node, Plan}; +use crate::ir::Plan; use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; -use super::NodeId; +use super::{MutNode, NodeId}; #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)] pub enum Type { @@ -133,15 +133,15 @@ impl Plan { /// # Errors /// - Child node is not of the expression type. pub fn add_cast(&mut self, expr_id: NodeId, to_type: Type) -> Result<NodeId, SbroadError> { - let cast_expr = Expression::Cast { + let cast_expr = Cast { child: expr_id, to: to_type, }; - let cast_id = self.nodes.push(Node::Expression(cast_expr)); + let cast_id = self.nodes.push(cast_expr.into()); let child_plan_node = self.get_mut_node(expr_id)?; - if let Node::Parameter(ref mut ty) = child_plan_node { - *ty = Some(to_type.as_relation_type()); + if let MutNode::Parameter(ty) = child_plan_node { + ty.param_type = Some(to_type.as_relation_type()); } Ok(cast_id) diff --git a/sbroad-core/src/ir/expression/concat.rs b/sbroad-core/src/ir/expression/concat.rs index 09e637988..c469fee91 100644 --- a/sbroad-core/src/ir/expression/concat.rs +++ b/sbroad-core/src/ir/expression/concat.rs @@ -1,6 +1,6 @@ use crate::errors::SbroadError; -use crate::ir::expression::Expression; -use crate::ir::{Node, Plan}; +use crate::ir::node::Concat; +use crate::ir::Plan; use super::NodeId; @@ -14,10 +14,13 @@ impl Plan { for child_id in &[left_id, right_id] { self.get_expression_node(*child_id)?; } - let concat_id = self.nodes.push(Node::Expression(Expression::Concat { - left: left_id, - right: right_id, - })); + let concat_id = self.nodes.push( + Concat { + left: left_id, + right: right_id, + } + .into(), + ); Ok(concat_id) } } diff --git a/sbroad-core/src/ir/expression/types.rs b/sbroad-core/src/ir/expression/types.rs index 0122fe56c..cd0c8e71a 100644 --- a/sbroad-core/src/ir/expression/types.rs +++ b/sbroad-core/src/ir/expression/types.rs @@ -2,10 +2,13 @@ use smol_str::{format_smolstr, ToSmolStr}; use crate::{ errors::{Entity, SbroadError}, - ir::{expression::Expression, relation::Type, Node, Plan}, + ir::{relation::Type, Plan}, }; -use super::NodeId; +use super::{ + Alias, ArithmeticExpr, Case, Cast, Constant, ExprInParentheses, Expression, MutExpression, + Node, NodeId, Reference, Row, StableFunction, +}; impl Plan { fn get_node_type(&self, node_id: NodeId) -> Result<Type, SbroadError> { @@ -19,7 +22,7 @@ impl Plan { )), // Parameter nodes must recalculate their type during // binding (see `bind_params` function). - Node::Parameter(ty) => Ok(ty.clone().unwrap_or(Type::Scalar)), + Node::Parameter(ty) => Ok(ty.param_type.clone().unwrap_or(Type::Scalar)), Node::Ddl(_) => Err(SbroadError::Invalid( Entity::Node, Some("DDL node has no type".to_smolstr()), @@ -28,6 +31,10 @@ impl Plan { Entity::Node, Some("ACL node has no type".to_smolstr()), )), + Node::Invalid(_) => Err(SbroadError::Invalid( + Entity::Node, + Some("Invalid node has no type".to_smolstr()), + )), Node::Block(_) => Err(SbroadError::Invalid( Entity::Node, Some("code block node has no type".to_smolstr()), @@ -36,7 +43,7 @@ impl Plan { } } -impl Expression { +impl Expression<'_> { /// Calculate the type of the expression. /// /// # Errors @@ -46,11 +53,11 @@ impl Expression { /// - Plan is in inconsistent state pub fn calculate_type(&self, plan: &Plan) -> Result<Type, SbroadError> { match self { - Expression::Case { + Expression::Case(Case { when_blocks, else_expr, .. - } => { + }) => { let mut case_type = None; let check_types_corresponds = |case_type: &Type, ret_expr_type: &Type| { if case_type != ret_expr_type { @@ -86,13 +93,14 @@ impl Expression { } Ok(case_type_unwrapped) } - Expression::Alias { child, .. } | Expression::ExprInParentheses { child } => { + Expression::Alias(Alias { child, .. }) + | Expression::ExprInParentheses(ExprInParentheses { child }) => { plan.get_node_type(*child) } - Expression::Bool { .. } | Expression::Unary { .. } => Ok(Type::Boolean), - Expression::Arithmetic { + Expression::Bool(_) | Expression::Unary(_) => Ok(Type::Boolean), + Expression::Arithmetic(ArithmeticExpr { left, right, op, .. - } => { + }) => { let left_type = plan.get_node_type(*left)?; let right_type = plan.get_node_type(*right)?; match (&left_type, &right_type) { @@ -112,11 +120,11 @@ impl Expression { )), } } - Expression::Cast { to, .. } => Ok(to.as_relation_type()), - Expression::Trim { .. } | Expression::Concat { .. } => Ok(Type::String), - Expression::Constant { value, .. } => Ok(value.get_type()), - Expression::Reference { col_type, .. } => Ok(col_type.clone()), - Expression::Row { list, .. } => { + Expression::Cast(Cast { to, .. }) => Ok(to.as_relation_type()), + Expression::Trim(_) | Expression::Concat(_) => Ok(Type::String), + Expression::Constant(Constant { value, .. }) => Ok(value.get_type()), + Expression::Reference(Reference { col_type, .. }) => Ok(col_type.clone()), + Expression::Row(Row { list, .. }) => { if let (Some(expr_id), None) = (list.first(), list.get(1)) { let expr = plan.get_expression_node(*expr_id)?; expr.calculate_type(plan) @@ -124,12 +132,12 @@ impl Expression { Ok(Type::Array) } } - Expression::StableFunction { + Expression::StableFunction(StableFunction { name, func_type, children, .. - } => { + }) => { // min/max functions have a scalar type, which means that their actual type can be // inferred from the arguments. if let "max" | "min" = name.as_str() { @@ -142,7 +150,7 @@ impl Expression { Ok(func_type.clone()) } } - Expression::CountAsterisk => Ok(Type::Integer), + Expression::CountAsterisk(_) => Ok(Type::Integer), } } @@ -163,12 +171,12 @@ impl Expression { /// # Errors /// - if the reference is invalid; pub fn recalculate_type(&self, plan: &Plan) -> Result<Type, SbroadError> { - if let Expression::Reference { + if let Expression::Reference(Reference { parent, targets, position, .. - } = self + }) = self { let parent_id = parent.ok_or_else(|| { SbroadError::Invalid( @@ -206,9 +214,11 @@ impl Expression { } self.calculate_type(plan) } +} +impl MutExpression<'_> { pub fn set_ref_type(&mut self, new_type: Type) { - if let Expression::Reference { col_type, .. } = self { + if let MutExpression::Reference(Reference { col_type, .. }) = self { *col_type = new_type; } } diff --git a/sbroad-core/src/ir/function.rs b/sbroad-core/src/ir/function.rs index 5732bef6d..0e31fadb5 100644 --- a/sbroad-core/src/ir/function.rs +++ b/sbroad-core/src/ir/function.rs @@ -1,13 +1,13 @@ use crate::errors::{Entity, SbroadError}; use crate::executor::engine::helpers::to_user; use crate::ir::aggregates::AggregateKind; -use crate::ir::expression::Expression; +use crate::ir::node::{NodeId, StableFunction}; use crate::ir::relation::Type; -use crate::ir::{Node, Plan}; +use crate::ir::Plan; use serde::{Deserialize, Serialize}; use smol_str::{format_smolstr, SmolStr, ToSmolStr}; -use super::expression::{FunctionFeature, NodeId}; +use super::expression::FunctionFeature; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub enum Behavior { @@ -70,14 +70,14 @@ impl Plan { Some(format_smolstr!("function {} is not stable", function.name)), )); } - let func_expr = Expression::StableFunction { + let func_expr = StableFunction { name: function.name.to_smolstr(), children, feature, func_type: function.func_type.clone(), is_system: function.is_system, }; - let func_id = self.nodes.push(Node::Expression(func_expr)); + let func_id = self.nodes.push(func_expr.into()); Ok(func_id) } @@ -132,14 +132,14 @@ impl Plan { } else { None }; - let func_expr = Expression::StableFunction { + let func_expr = StableFunction { name: function.to_lowercase().to_smolstr(), children, feature, func_type: Type::from(kind), is_system: true, }; - let id = self.nodes.push(Node::Expression(func_expr)); + let id = self.nodes.push(func_expr.into()); Ok(id) } } diff --git a/sbroad-core/src/ir/helpers.rs b/sbroad-core/src/ir/helpers.rs index 7c59ef618..68a239594 100644 --- a/sbroad-core/src/ir/helpers.rs +++ b/sbroad-core/src/ir/helpers.rs @@ -4,15 +4,21 @@ use smol_str::{SmolStr, ToSmolStr}; use crate::backend::sql::tree::{SyntaxData, SyntaxPlan}; use crate::errors::{Action, Entity, SbroadError}; -use crate::ir::expression::Expression; -use crate::ir::operator::{OrderByEntity, Relational}; +use crate::ir::node::{ + Alias, BoolExpr, Case, Constant, Delete, Except, ExprInParentheses, GroupBy, Having, Insert, + Intersect, Join, Motion, NodeId, OrderBy, Projection, Reference, Row, ScanCte, ScanRelation, + ScanSubQuery, Selection, UnaryExpr, Union, UnionAll, Update, Values, ValuesRow, +}; +use crate::ir::operator::OrderByEntity; use crate::ir::tree::traversal::{PostOrder, EXPR_CAPACITY}; use crate::ir::{Node, Plan}; use std::collections::hash_map::DefaultHasher; use std::fmt::Write; use std::hash::BuildHasher; -use super::expression::NodeId; +use super::node::expression::Expression; +use super::node::relational::Relational; +use super::node::Limit; /// Helper macros to build a hash map or set /// from the list of arguments. @@ -83,7 +89,7 @@ impl Plan { if let Ok(expr) = expr_try { write!(buf, "expression: ")?; match expr { - Expression::Alias { name, child } => { + Expression::Alias(Alias { name, child }) => { let child_node = self.get_node(*child).expect("Alias must have a child node"); let child = match child_node { Node::Expression(child_expr) => format!("{child_expr:?}"), @@ -94,16 +100,16 @@ impl Plan { }; writeln!(buf, "Alias [name = {name}, child = {child}]")?; } - Expression::ExprInParentheses { child } => { + Expression::ExprInParentheses(ExprInParentheses { child }) => { writeln!(buf, "Parentheses")?; writeln_with_tabulation(buf, tabulation_number + 1, "Child")?; self.formatted_arena_node(buf, tabulation_number + 1, *child)?; } - Expression::Case { + Expression::Case(Case { search_expr, when_blocks, else_expr, - } => { + }) => { writeln!(buf, "Case")?; if let Some(search_expr) = search_expr { writeln_with_tabulation(buf, tabulation_number + 1, "Search_expr")?; @@ -120,24 +126,24 @@ impl Plan { self.formatted_arena_node(buf, tabulation_number + 1, *else_expr)?; } } - Expression::Bool { op, left, right } => { + Expression::Bool(BoolExpr { op, left, right }) => { writeln!(buf, "Bool [op: {op}]")?; writeln_with_tabulation(buf, tabulation_number + 1, "Left child")?; self.formatted_arena_node(buf, tabulation_number + 1, *left)?; writeln_with_tabulation(buf, tabulation_number + 1, "Right child")?; self.formatted_arena_node(buf, tabulation_number + 1, *right)?; } - Expression::Constant { value } => { + Expression::Constant(Constant { value }) => { writeln!(buf, "Constant [value = {value}]")?; } - Expression::CountAsterisk => writeln!(buf, "CountAsterisk")?, - Expression::Reference { + Expression::CountAsterisk(_) => writeln!(buf, "CountAsterisk")?, + Expression::Reference(Reference { targets, position, parent, col_type, - } => { - let alias_name = self.get_alias_from_reference_node(expr).unwrap(); + }) => { + let alias_name = self.get_alias_from_reference_node(&expr).unwrap(); writeln!(buf, "Reference")?; writeln_with_tabulation( @@ -150,8 +156,8 @@ impl Plan { let rel_id = self.get_relational_from_reference_node(node_id); if let Ok(rel_id) = rel_id { let rel_node = self.get_relation_node(*rel_id); - if let Ok(rel_node) = rel_node { - if let Ok(Some(name)) = rel_node.scan_name(self, *position) { + if rel_node.is_ok() { + if let Ok(Some(name)) = self.scan_name(*rel_id, *position) { writeln_with_tabulation( buf, tabulation_number + 1, @@ -185,23 +191,23 @@ impl Plan { format!("Column type: {col_type}").as_str(), )?; } - Expression::Row { list, distribution } => { + Expression::Row(Row { list, distribution }) => { writeln!(buf, "Row [distribution = {distribution:?}]")?; writeln_with_tabulation(buf, tabulation_number + 1, "List:")?; for value in list { self.formatted_arena_node(buf, tabulation_number + 2, *value)?; } } - Expression::Cast { .. } => writeln!(buf, "Cast")?, - Expression::Trim { .. } => writeln!(buf, "Trim")?, - Expression::Concat { .. } => writeln!(buf, "Concat")?, - Expression::StableFunction { .. } => writeln!(buf, "StableFunction")?, - Expression::Unary { op, child } => { + Expression::Cast(_) => writeln!(buf, "Cast")?, + Expression::Trim(_) => writeln!(buf, "Trim")?, + Expression::Concat(_) => writeln!(buf, "Concat")?, + Expression::StableFunction(_) => writeln!(buf, "StableFunction")?, + Expression::Unary(UnaryExpr { op, child }) => { writeln!(buf, "Unary [op: {op}]")?; writeln_with_tabulation(buf, tabulation_number + 1, "Child")?; self.formatted_arena_node(buf, tabulation_number + 1, *child)?; } - Expression::Arithmetic { .. } => writeln!(buf, "Arithmetic")?, + Expression::Arithmetic(_) => writeln!(buf, "Arithmetic")?, }; } Ok(()) @@ -224,9 +230,9 @@ impl Plan { write!(buf, "relation: ")?; // Print relation name and specific info. match relation { - Relational::ScanRelation { + Relational::ScanRelation(ScanRelation { alias, relation, .. - } => { + }) => { writeln!(buf, "ScanRelation")?; writeln_with_tabulation( buf, @@ -241,15 +247,15 @@ impl Plan { )?; } } - Relational::Join { condition, .. } => { + Relational::Join(Join { condition, .. }) => { writeln!(buf, "InnerJoin")?; writeln_with_tabulation(buf, tabulation_number + 1, "Condition:")?; self.formatted_arena_node(buf, tabulation_number + 2, *condition)?; } - Relational::Projection { .. } => { + Relational::Projection(_) => { writeln!(buf, "Projection")?; } - Relational::ScanCte { alias, .. } => { + Relational::ScanCte(ScanCte { alias, .. }) => { writeln!(buf, "ScanCte")?; if !alias.is_empty() { writeln_with_tabulation( @@ -259,7 +265,7 @@ impl Plan { )?; } } - Relational::ScanSubQuery { alias, .. } => { + Relational::ScanSubQuery(ScanSubQuery { alias, .. }) => { writeln!(buf, "ScanSubQuery")?; if let Some(alias) = alias { if !alias.is_empty() { @@ -271,23 +277,23 @@ impl Plan { } } } - Relational::Selection { + Relational::Selection(Selection { children: _, filter, output: _, - } => { + }) => { writeln!(buf, "Selection")?; writeln_with_tabulation(buf, tabulation_number + 1, "Filter")?; self.formatted_arena_node(buf, tabulation_number + 1, *filter)?; } - Relational::Having { filter, .. } => { + Relational::Having(Having { filter, .. }) => { writeln!(buf, "Having")?; writeln_with_tabulation(buf, tabulation_number + 1, "Filter")?; self.formatted_arena_node(buf, tabulation_number + 1, *filter)?; } - Relational::GroupBy { + Relational::GroupBy(GroupBy { gr_cols, is_final, .. - } => { + }) => { writeln!(buf, "GroupBy [is_final = {is_final}]")?; writeln_with_tabulation(buf, tabulation_number + 1, "Gr_cols:")?; for gr_col in gr_cols { @@ -295,14 +301,14 @@ 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())?; } } - Relational::OrderBy { + Relational::OrderBy(OrderBy { order_by_elements, .. - } => { + }) => { writeln!(buf, "OrderBy")?; writeln_with_tabulation(buf, tabulation_number + 1, "Order_by_elements:")?; for element in order_by_elements { @@ -322,52 +328,51 @@ impl Plan { } } Relational::Values { .. } => writeln!(buf, "Values")?, - Relational::ValuesRow { data, .. } => { + Relational::ValuesRow(ValuesRow { data, .. }) => { writeln!(buf, "ValuesRow")?; writeln_with_tabulation(buf, tabulation_number + 1, "Data")?; self.formatted_arena_node(buf, tabulation_number + 1, *data)?; } - Relational::Motion { policy, .. } => { + Relational::Motion(Motion { policy, .. }) => { writeln!(buf, "Motion [policy = {policy:?}]")?; } Relational::Union { .. } => writeln!(buf, "Union")?, Relational::UnionAll { .. } => writeln!(buf, "UnionAll")?, - Relational::Update { + Relational::Update(Update { relation, update_columns_map, .. - } => { + }) => { writeln!(buf, "Update")?; writeln_with_tabulation(buf, tabulation_number + 1, "Update columns map:")?; for (rel_pos, proj_pos) in update_columns_map { writeln_with_tabulation(buf, tabulation_number + 2, format!("Update {relation} column on pos {rel_pos} to child projection column on pos {proj_pos}").as_str())?; } } - Relational::Delete { .. } => writeln!(buf, "Delete")?, - Relational::Insert { .. } => writeln!(buf, "Insert")?, - Relational::Intersect { .. } => writeln!(buf, "Intersect")?, - Relational::Except { .. } => writeln!(buf, "Except")?, - Relational::Limit { limit, .. } => writeln!(buf, "Limit {limit}")?, + Relational::Delete(_) => writeln!(buf, "Delete")?, + Relational::Insert(_) => writeln!(buf, "Insert")?, + Relational::Intersect(_) => writeln!(buf, "Intersect")?, + Relational::Except(_) => writeln!(buf, "Except")?, + Relational::Limit(Limit { limit, .. }) => writeln!(buf, "Limit {limit}")?, } // Print children. match relation { - node @ (Relational::Join { .. } - | Relational::Projection { .. } - | Relational::Except { .. } - | Relational::Delete { .. } - | Relational::Insert { .. } - | Relational::Intersect { .. } - | Relational::ScanSubQuery { .. } - | Relational::Selection { .. } - | Relational::Values { .. } - | Relational::Motion { .. } - | Relational::Union { .. } - | Relational::UnionAll { .. } - | Relational::Update { .. } - | Relational::Having { .. } - | Relational::GroupBy { .. } - | Relational::ValuesRow { .. } - | Relational::Limit { .. }) => { + ref node @ (Relational::Join(_) + | Relational::Projection(_) + | Relational::Except(_) + | Relational::Delete(_) + | Relational::Insert(_) + | Relational::Intersect(_) + | Relational::ScanSubQuery(_) + | Relational::Selection(_) + | Relational::Values(_) + | Relational::Motion(_) + | Relational::Union(_) + | Relational::UnionAll(_) + | Relational::Update(_) + | Relational::Having(_) + | Relational::GroupBy(_) + | Relational::ValuesRow(_)) => { writeln_with_tabulation(buf, tabulation_number + 1, "Children:")?; for child in &node.children() { writeln_with_tabulation( @@ -377,7 +382,9 @@ impl Plan { )?; } } - Relational::OrderBy { child, .. } | Relational::ScanCte { child, .. } => { + Relational::Limit(Limit { child, .. }) + | Relational::OrderBy(OrderBy { child, .. }) + | Relational::ScanCte(ScanCte { child, .. }) => { writeln_with_tabulation(buf, tabulation_number + 1, "Children:")?; writeln_with_tabulation( buf, @@ -391,26 +398,26 @@ impl Plan { } // Print output. match relation { - Relational::ScanRelation { output, .. } - | Relational::Join { output, .. } - | Relational::Except { output, .. } - | Relational::Delete { output, .. } - | Relational::Insert { output, .. } - | Relational::Intersect { output, .. } - | Relational::Projection { output, .. } - | Relational::ScanCte { output, .. } - | Relational::ScanSubQuery { output, .. } - | Relational::GroupBy { output, .. } - | Relational::OrderBy { output, .. } - | Relational::Selection { output, .. } - | Relational::Having { output, .. } - | Relational::Values { output, .. } - | Relational::Motion { output, .. } - | Relational::Union { output, .. } - | Relational::UnionAll { output, .. } - | Relational::Update { output, .. } - | Relational::ValuesRow { output, .. } - | Relational::Limit { output, .. } => { + Relational::ScanRelation(ScanRelation { output, .. }) + | Relational::Join(Join { output, .. }) + | Relational::Except(Except { output, .. }) + | Relational::Delete(Delete { output, .. }) + | Relational::Insert(Insert { output, .. }) + | Relational::Intersect(Intersect { output, .. }) + | Relational::Projection(Projection { output, .. }) + | Relational::ScanCte(ScanCte { output, .. }) + | Relational::ScanSubQuery(ScanSubQuery { output, .. }) + | Relational::GroupBy(GroupBy { output, .. }) + | Relational::OrderBy(OrderBy { output, .. }) + | Relational::Selection(Selection { output, .. }) + | Relational::Having(Having { output, .. }) + | Relational::Values(Values { output, .. }) + | Relational::Motion(Motion { output, .. }) + | Relational::Union(Union { output, .. }) + | Relational::UnionAll(UnionAll { output, .. }) + | Relational::Update(Update { output, .. }) + | Relational::ValuesRow(ValuesRow { output, .. }) + | Relational::Limit(Limit { output, .. }) => { writeln_with_tabulation( buf, tabulation_number + 1, diff --git a/sbroad-core/src/ir/helpers/tests.rs b/sbroad-core/src/ir/helpers/tests.rs index a910c1fa6..dea18673e 100644 --- a/sbroad-core/src/ir/helpers/tests.rs +++ b/sbroad-core/src/ir/helpers/tests.rs @@ -1,4 +1,7 @@ -use crate::ir::{expression::NodeId, transformation::helpers::sql_to_optimized_ir, ArenaType}; +use crate::{ + ir::node::NodeId, + ir::{transformation::helpers::sql_to_optimized_ir, ArenaType}, +}; use pretty_assertions::assert_eq; #[test] @@ -11,26 +14,26 @@ fn simple_select() { let mut expected_arena = String::new(); expected_arena.push_str( r#"--------------------------------------------- -[id: 11] relation: ScanRelation +[id: 664] relation: ScanRelation Relation: hash_testing [No children] - Output_id: 10 - [id: 10] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] + Output_id: 564 + [id: 564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [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: 032] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })] + [id: 132] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: String })] + [id: 232] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })] + [id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })] + [id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 15] relation: Projection +[id: 964] relation: Projection Children: - Child_id = 11 - Output_id: 14 - [id: 14] expression: Row [distribution = Some(Any)] + Child_id = 664 + Output_id: 864 + [id: 864] expression: Row [distribution = Some(Any)] List: - [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 }] + [id: 532] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 9, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String })] --------------------------------------------- "#); @@ -50,117 +53,117 @@ fn simple_join() { let mut expected_arena = String::new(); expected_arena.push_str( r#"--------------------------------------------- -[id: 11] relation: ScanRelation +[id: 664] relation: ScanRelation Relation: test_space [No children] - Output_id: 10 - [id: 10] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Output_id: 564 + [id: 564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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: 032] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Unsigned })] + [id: 132] expression: Alias [name = sysFrom, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: Unsigned })] + [id: 232] expression: Alias [name = FIRST_NAME, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: String })] + [id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })] + [id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 15] relation: Projection +[id: 964] relation: Projection Children: - Child_id = 11 - Output_id: 14 - [id: 14] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Child_id = 664 + Output_id: 864 + [id: 864] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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: 532] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 9, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 19] relation: ScanSubQuery +[id: 1264] relation: ScanSubQuery Alias: t1 Children: - Child_id = 15 - Output_id: 18 - [id: 18] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Child_id = 964 + Output_id: 1164 + [id: 1164] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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: 632] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 12, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 31] relation: ScanRelation +[id: 1964] relation: ScanRelation Relation: hash_testing [No children] - Output_id: 30 - [id: 30] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] + Output_id: 1864 + [id: 1864] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [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: 732] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })] + [id: 832] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 1, col_type: String })] + [id: 932] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })] + [id: 1032] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })] + [id: 1132] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 35] relation: Projection +[id: 2264] relation: Projection Children: - Child_id = 31 - Output_id: 34 - [id: 34] expression: Row [distribution = Some(Any)] + Child_id = 1964 + Output_id: 2164 + [id: 2164] expression: Row [distribution = Some(Any)] List: - [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: 1232] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 22, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })] --------------------------------------------- --------------------------------------------- -[id: 39] relation: ScanSubQuery +[id: 2564] relation: ScanSubQuery Alias: t2 Children: - Child_id = 35 - Output_id: 38 - [id: 38] expression: Row [distribution = Some(Any)] + Child_id = 2264 + Output_id: 2464 + [id: 2464] expression: Row [distribution = Some(Any)] List: - [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: 1332] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 25, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })] --------------------------------------------- --------------------------------------------- -[id: 61] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] +[id: 0136] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] Children: - Child_id = 39 - Output_id: 60 - [id: 60] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Child_id = 2564 + Output_id: 4064 + [id: 4064] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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: 1932] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 0, arena_type: Arena136 }), targets: Some([0]), position: 0, col_type: Integer })] --------------------------------------------- --------------------------------------------- -[id: 50] relation: InnerJoin +[id: 3364] relation: InnerJoin Condition: - [id: 57] expression: Bool [op: =] + [id: 1832] expression: Bool [op: =] Left child - [id: 55] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + [id: 3764] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 40] expression: Reference + [id: 2664] expression: Reference Alias: id Referenced table name (or alias): t1 - Parent: Some(NodeId { offset: 50, arena_type: Default }) + Parent: Some(NodeId { offset: 33, arena_type: Arena64 }) target_id: 0 Column type: unsigned Right child - [id: 56] expression: Row [distribution = Some(Any)] + [id: 3864] expression: Row [distribution = Some(Any)] List: - [id: 42] expression: Reference + [id: 2864] expression: Reference Alias: identification_number Referenced table name (or alias): t2 - Parent: Some(NodeId { offset: 50, arena_type: Default }) + Parent: Some(NodeId { offset: 33, arena_type: Arena64 }) target_id: 1 Column type: integer Children: - Child_id = 19 - Child_id = 61 - Output_id: 49 - [id: 49] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [1] }, Key { positions: [0] }}) })] + Child_id = 1264 + Child_id = 0136 + Output_id: 3264 + [id: 3264] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [1] }, Key { positions: [0] }}) })] List: - [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: 1532] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 33, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })] + [id: 1632] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 33, arena_type: Arena64 }), targets: Some([1]), position: 0, col_type: Integer })] --------------------------------------------- --------------------------------------------- -[id: 54] relation: Projection +[id: 3664] relation: Projection Children: - Child_id = 50 - Output_id: 53 - [id: 53] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Child_id = 3364 + Output_id: 3564 + [id: 3564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [id: 52] expression: Alias [name = id, child = Reference { parent: Some(NodeId { offset: 54, arena_type: Default }), targets: Some([0]), position: 0, col_type: Unsigned }] + [id: 1732] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 36, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })] --------------------------------------------- "#); @@ -178,56 +181,55 @@ fn simple_join_subtree() { // Taken from the expected arena output in the `simple_join` test. let inner_join_inner_child_id = NodeId { - offset: 61, - arena_type: ArenaType::Default, + offset: 0, + arena_type: ArenaType::Arena136, }; let actual_arena_subtree = plan .formatted_arena_subtree(inner_join_inner_child_id) .unwrap(); - let mut expected_arena_subtree = String::new(); expected_arena_subtree.push_str( - r#"--------------------------------------------- -[id: 31] relation: ScanRelation + r#"--------------------------------------------- +[id: 1964] relation: ScanRelation Relation: hash_testing [No children] - Output_id: 30 - [id: 30] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] + Output_id: 1864 + [id: 1864] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [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: 732] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })] + [id: 832] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 1, col_type: String })] + [id: 932] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })] + [id: 1032] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })] + [id: 1132] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 35] relation: Projection +[id: 2264] relation: Projection Children: - Child_id = 31 - Output_id: 34 - [id: 34] expression: Row [distribution = Some(Any)] + Child_id = 1964 + Output_id: 2164 + [id: 2164] expression: Row [distribution = Some(Any)] List: - [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: 1232] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 22, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })] --------------------------------------------- --------------------------------------------- -[id: 39] relation: ScanSubQuery +[id: 2564] relation: ScanSubQuery Alias: t2 Children: - Child_id = 35 - Output_id: 38 - [id: 38] expression: Row [distribution = Some(Any)] + Child_id = 2264 + Output_id: 2464 + [id: 2464] expression: Row [distribution = Some(Any)] List: - [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: 1332] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 25, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })] --------------------------------------------- --------------------------------------------- -[id: 61] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] +[id: 0136] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] Children: - Child_id = 39 - Output_id: 60 - [id: 60] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Child_id = 2564 + Output_id: 4064 + [id: 4064] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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: 1932] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 0, arena_type: Arena136 }), targets: Some([0]), position: 0, col_type: Integer })] --------------------------------------------- "# ); @@ -244,79 +246,79 @@ fn simple_aggregation_with_group_by() { let mut expected_arena = String::new(); expected_arena.push_str( r#"--------------------------------------------- -[id: 11] relation: ScanRelation +[id: 664] relation: ScanRelation Relation: hash_testing [No children] - Output_id: 10 - [id: 10] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] + Output_id: 564 + [id: 564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [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: 032] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })] + [id: 132] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: String })] + [id: 232] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })] + [id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })] + [id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 24] relation: GroupBy [is_final = false] +[id: 1464] relation: GroupBy [is_final = false] Gr_cols: - Gr_col: Reference { parent: Some(NodeId { offset: 24, arena_type: Default }), targets: Some([0]), position: 1, col_type: String } + Gr_col: Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), 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] }}) })] + Child_id = 664 + Output_id: 1364 + [id: 1364] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })] List: - [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: 532] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })] + [id: 632] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String })] + [id: 732] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 2, col_type: Boolean })] + [id: 832] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 3, col_type: Unsigned })] + [id: 932] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 4, col_type: Unsigned })] --------------------------------------------- --------------------------------------------- -[id: 31] relation: Projection +[id: 1964] relation: Projection Children: - Child_id = 24 - Output_id: 30 - [id: 30] expression: Row [distribution = Some(Any)] + Child_id = 1464 + Output_id: 1864 + [id: 1864] expression: Row [distribution = Some(Any)] List: - [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: 1132] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String })] --------------------------------------------- --------------------------------------------- -[id: 35] relation: ScanSubQuery +[id: 2264] relation: ScanSubQuery Children: - Child_id = 31 - Output_id: 34 - [id: 34] expression: Row [distribution = Some(Any)] + Child_id = 1964 + Output_id: 2164 + [id: 2164] expression: Row [distribution = Some(Any)] List: - [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: 1232] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 22, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String })] --------------------------------------------- --------------------------------------------- -[id: 45] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] +[id: 0136] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] })] Children: - Child_id = 35 - Output_id: 44 - [id: 44] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Child_id = 2264 + Output_id: 2964 + [id: 2964] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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: 1432] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 0, arena_type: Arena136 }), targets: Some([0]), position: 0, col_type: String })] --------------------------------------------- --------------------------------------------- -[id: 40] relation: GroupBy [is_final = true] +[id: 2664] relation: GroupBy [is_final = true] Gr_cols: - Gr_col: Reference { parent: Some(NodeId { offset: 40, arena_type: Default }), targets: Some([0]), position: 0, col_type: String } + Gr_col: Reference(Reference { parent: Some(NodeId { offset: 26, arena_type: Arena64 }), 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] }}) })] + Child_id = 0136 + Output_id: 2564 + [id: 2564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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: 1332] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 26, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String })] --------------------------------------------- --------------------------------------------- -[id: 28] relation: Projection +[id: 1764] relation: Projection Children: - Child_id = 40 - Output_id: 27 - [id: 27] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] + Child_id = 2664 + Output_id: 1664 + [id: 1664] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })] List: - [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 }] + [id: 1032] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 17, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String })] --------------------------------------------- "#); diff --git a/sbroad-core/src/ir/node.rs b/sbroad-core/src/ir/node.rs new file mode 100644 index 000000000..fd93c2aeb --- /dev/null +++ b/sbroad-core/src/ir/node.rs @@ -0,0 +1,1310 @@ +use std::{collections::HashMap, fmt::Display}; + +use acl::{Acl, AclOwned, MutAcl}; +use block::{Block, BlockOwned, MutBlock}; +use ddl::{Ddl, DdlOwned, MutDdl}; +use expression::{ExprOwned, Expression, MutExpression}; +use relational::{MutRelational, RelOwned, Relational}; +use serde::{Deserialize, Serialize}; +use smol_str::SmolStr; +use tarantool::{ + decimal::Decimal, + index::{IndexType, RtreeIndexDistanceType}, + space::SpaceEngineType, +}; + +use crate::{ + errors::SbroadError, + ir::{ + acl::{AlterOption, GrantRevokeType}, + ddl::{ColumnDef, Language, ParamDef, SetParamScopeType, SetParamValue}, + distribution::Distribution, + helpers::RepeatableState, + relation::Type, + transformation::redistribution::{ColumnPosition, MotionPolicy, Program}, + value::Value, + }, +}; + +use super::{ + ddl::AlterSystemType, + expression::{cast, FunctionFeature, TrimKind}, + operator::{self, ConflictStrategy, JoinKind, OrderByElement, UpdateStrategy}, +}; + +pub mod acl; +pub mod block; +pub mod ddl; +pub mod expression; +pub mod relational; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Hash, Copy)] +pub enum ArenaType { + Arena32, + Arena64, + Arena96, + Arena136, + Arena224, +} + +impl Display for ArenaType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ArenaType::Arena32 => { + write!(f, "32") + } + ArenaType::Arena64 => { + write!(f, "64") + } + ArenaType::Arena96 => { + write!(f, "96") + } + ArenaType::Arena136 => { + write!(f, "136") + } + ArenaType::Arena224 => { + write!(f, "224") + } + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[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 std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.offset, self.arena_type) + } +} + +impl Default for NodeId { + fn default() -> Self { + NodeId { + offset: 0, + arena_type: ArenaType::Arena32, + } + } +} + +/// Expression name. +/// +/// Example: `42 as a`. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Alias { + /// Alias name. + pub name: SmolStr, + /// Child expression node index in the plan node arena. + pub child: NodeId, +} + +impl From<Alias> for SizeNode { + fn from(value: Alias) -> Self { + Self::Node32(Node32::Alias(value)) + } +} + +/// Binary expression returning boolean result. +/// +/// Example: `a > 42`, `b in (select c from ...)`. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct BoolExpr { + /// Left branch expression node index in the plan node arena. + pub left: NodeId, + /// Boolean operator. + pub op: operator::Bool, + /// Right branch expression node index in the plan node arena. + pub right: NodeId, +} + +impl From<BoolExpr> for SizeNode { + fn from(value: BoolExpr) -> Self { + Self::Node32(Node32::Bool(value)) + } +} + +/// Binary expression returning row result. +/// +/// Example: `a + b > 42`, `a + b < c + 1`, `1 + 2 != 2 * 2`. +/// +/// TODO: always cover children with parentheses (in `to_sql`). +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct ArithmeticExpr { + /// Left branch expression node index in the plan node arena. + pub left: NodeId, + /// Arithmetic operator. + pub op: operator::Arithmetic, + /// Right branch expression node index in the plan node arena. + pub right: NodeId, +} + +impl From<ArithmeticExpr> for SizeNode { + fn from(value: ArithmeticExpr) -> Self { + Self::Node32(Node32::Arithmetic(value)) + } +} + +/// Type cast expression. +/// +/// Example: `cast(a as text)`. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Cast { + /// Target expression that must be casted to another type. + pub child: NodeId, + /// Cast type. + pub to: cast::Type, +} + +impl From<Cast> for SizeNode { + fn from(value: Cast) -> Self { + Self::Node32(Node32::Cast(value)) + } +} + +/// String concatenation expression. +/// +/// Example: `a || 'hello'`. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Concat { + /// Left expression node id. + pub left: NodeId, + /// Right expression node id. + pub right: NodeId, +} + +impl From<Concat> for SizeNode { + fn from(value: Concat) -> Self { + Self::Node32(Node32::Concat(value)) + } +} + +/// Constant expressions. +/// +/// Example: `42`. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Constant { + /// Contained value (boolean, number, string or null) + pub value: Value, +} + +impl From<Constant> for SizeNode { + fn from(value: Constant) -> Self { + Self::Node64(Node64::Constant(value)) + } +} + +/// Reference to the position in the incoming tuple(s). +/// Uses a relative pointer as a coordinate system: +/// - relational node (containing this reference) +/// - target(s) in the relational nodes list of children +/// - column position in the child(ren) output tuple +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Reference { + /// Relational node ID that contains current reference. + pub parent: Option<NodeId>, + /// Targets in the relational node children list. + /// - Leaf nodes (relation scans): None. + /// - Union nodes: two elements (left and right). + /// - Other: single element. + pub targets: Option<Vec<usize>>, + /// Expression position in the input tuple (i.e. `Alias` column). + pub position: usize, + /// Referred column type in the input tuple. + pub col_type: Type, +} + +impl From<Reference> for SizeNode { + fn from(value: Reference) -> Self { + Self::Node64(Node64::Reference(value)) + } +} + +/// Top of the tuple tree. +/// +/// If the current tuple is the output for some relational operator, it should +/// consist of the list of aliases. Otherwise (rows in selection filter +/// or in join condition) we don't require aliases in the list. +/// +/// +/// Example: (a, b, 1). +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Row { + /// A list of the alias expression node indexes in the plan node arena. + pub list: Vec<NodeId>, + /// Resulting data distribution of the tuple. Should be filled as a part + /// of the last "add Motion" transformation. + pub distribution: Option<Distribution>, +} + +impl From<Row> for SizeNode { + fn from(value: Row) -> Self { + Self::Node64(Node64::Row(value)) + } +} + +/// Stable function cannot modify the database and +/// is guaranteed to return the same results given +/// the same arguments for all rows within a single +/// statement. +/// +/// Example: `bucket_id("1")` (the number of buckets can be +/// changed only after restarting the cluster). +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct StableFunction { + /// Function name. + pub name: SmolStr, + /// Function arguments. + pub children: Vec<NodeId>, + /// Optional function feature. + pub feature: Option<FunctionFeature>, + /// Function return type. + pub func_type: Type, + /// Whether function is provided by tarantool, + /// when referencing these funcs from local + /// sql we must not use quotes. + /// Examples: aggregates, substr + pub is_system: bool, +} + +impl From<StableFunction> for SizeNode { + fn from(value: StableFunction) -> Self { + Self::Node96(Node96::StableFunction(value)) + } +} + +/// Trim expression. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Trim { + /// Trim kind. + pub kind: Option<TrimKind>, + /// Trim string pattern to remove (it can be an expression). + pub pattern: Option<NodeId>, + /// Target expression to trim. + pub target: NodeId, +} + +impl From<Trim> for SizeNode { + fn from(value: Trim) -> Self { + Self::Node32(Node32::Trim(value)) + } +} + +/// Unary expression returning boolean result. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct UnaryExpr { + /// Unary operator. + pub op: operator::Unary, + /// Child expression node index in the plan node arena. + pub child: NodeId, +} + +impl From<UnaryExpr> for SizeNode { + fn from(value: UnaryExpr) -> Self { + Self::Node32(Node32::Unary(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct ExprInParentheses { + pub child: NodeId, +} + +impl From<ExprInParentheses> for SizeNode { + fn from(value: ExprInParentheses) -> Self { + Self::Node32(Node32::ExprInParentheses(value)) + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct Case { + pub search_expr: Option<NodeId>, + pub when_blocks: Vec<(NodeId, NodeId)>, + pub else_expr: Option<NodeId>, +} + +impl From<Case> for SizeNode { + fn from(value: Case) -> Self { + Self::Node64(Node64::Case(value)) + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct Parameter { + pub param_type: Option<Type>, +} + +impl From<Parameter> for SizeNode { + fn from(value: Parameter) -> Self { + Self::Node64(Node64::Parameter(value)) + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct CountAsterisk {} + +impl From<CountAsterisk> for SizeNode { + fn from(value: CountAsterisk) -> Self { + Self::Node32(Node32::CountAsterisk(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct ScanCte { + /// CTE's name. + pub alias: SmolStr, + /// Contains exactly one single element (projection node index). + pub child: NodeId, + /// An output tuple with aliases. + pub output: NodeId, +} + +impl From<ScanCte> for SizeNode { + fn from(value: ScanCte) -> Self { + Self::Node64(Node64::ScanCte(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Except { + /// Left child id + pub left: NodeId, + /// Right child id + pub right: NodeId, + /// Outputs tuple node index in the plan node arena. + pub output: NodeId, +} + +impl From<Except> for SizeNode { + fn from(value: Except) -> Self { + Self::Node32(Node32::Except(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Delete { + /// Relation name. + pub relation: SmolStr, + /// Contains exactly one single element. + pub children: Vec<NodeId>, + /// The output tuple (reserved for `delete returning`). + pub output: NodeId, +} + +impl From<Delete> for SizeNode { + fn from(value: Delete) -> Self { + Self::Node64(Node64::Delete(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Insert { + /// Relation name. + pub relation: SmolStr, + /// Target column positions for data insertion from + /// the child's tuple. + pub columns: Vec<usize>, + /// Contains exactly one single element. + pub children: Vec<NodeId>, + /// The output tuple (reserved for `insert returning`). + pub output: NodeId, + /// What to do in case there is a conflict during insert on storage + pub conflict_strategy: ConflictStrategy, +} + +impl From<Insert> for SizeNode { + fn from(value: Insert) -> Self { + Self::Node96(Node96::Insert(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Intersect { + pub left: NodeId, + pub right: NodeId, + // id of the output tuple + pub output: NodeId, +} + +impl From<Intersect> for SizeNode { + fn from(value: Intersect) -> Self { + Self::Node32(Node32::Intersect(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Update { + /// Relation name. + pub relation: SmolStr, + /// Children ids. Update has exactly one child. + pub children: Vec<NodeId>, + /// Maps position of column being updated in table to corresponding position + /// in `Projection` below `Update`. + /// + /// For sharded `Update`, it will contain every table column except `bucket_id` + /// column. For local `Update` it will contain only update table columns. + pub update_columns_map: HashMap<ColumnPosition, ColumnPosition, RepeatableState>, + /// How this update must be executed. + pub strategy: UpdateStrategy, + /// Positions of primary columns in `Projection` + /// below `Update`. + pub pk_positions: Vec<ColumnPosition>, + /// Output id. + pub output: NodeId, +} + +impl From<Update> for SizeNode { + fn from(value: Update) -> Self { + Self::Node136(Node136::Update(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct 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. + pub children: Vec<NodeId>, + /// Left and right tuple comparison condition. + /// In fact it is an expression tree top index from the plan node arena. + pub condition: NodeId, + /// Outputs tuple node index from the plan node arena. + pub output: NodeId, + /// inner or left + pub kind: JoinKind, +} + +impl From<Join> for SizeNode { + fn from(value: Join) -> Self { + Self::Node64(Node64::Join(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Limit { + /// Output tuple. + pub output: NodeId, + // The limit value constant that comes after LIMIT keyword. + pub 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. + pub child: NodeId, +} + +impl From<Limit> for SizeNode { + fn from(value: Limit) -> Self { + Self::Node32(Node32::Limit(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Motion { + // Scan name. + pub alias: Option<SmolStr>, + /// Contains exactly one single element: child node index + /// from the plan node arena. + pub children: Vec<NodeId>, + /// Motion policy - the amount of data to be moved. + pub policy: MotionPolicy, + /// A sequence of opcodes that transform the data. + pub program: Program, + /// Outputs tuple node index in the plan node arena. + pub 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 + /// by that moment we've already erased `children` information using + /// `unlink_motion_subtree` function. + pub is_child_subquery: bool, +} + +impl From<Motion> for SizeNode { + fn from(value: Motion) -> Self { + Self::Node136(Node136::Motion(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Projection { + /// 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 output tree. + pub children: Vec<NodeId>, + /// Outputs tuple node index in the plan node arena. + pub output: NodeId, + /// Wheter the select was marked with `distinct` keyword + pub is_distinct: bool, +} + +impl From<Projection> for SizeNode { + fn from(value: Projection) -> Self { + Self::Node64(Node64::Projection(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct ScanRelation { + // Scan name. + pub alias: Option<SmolStr>, + /// Outputs tuple node index in the plan node arena. + pub output: NodeId, + /// Relation name. + pub relation: SmolStr, +} + +impl From<ScanRelation> for SizeNode { + fn from(value: ScanRelation) -> Self { + Self::Node64(Node64::ScanRelation(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct ScanSubQuery { + /// SubQuery name. + pub alias: Option<SmolStr>, + /// Contains exactly one single element: child node index + /// from the plan node arena. + pub children: Vec<NodeId>, + /// Outputs tuple node index in the plan node arena. + pub output: NodeId, +} + +impl From<ScanSubQuery> for SizeNode { + fn from(value: ScanSubQuery) -> Self { + Self::Node64(Node64::ScanSubQuery(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct 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. + pub children: Vec<NodeId>, + /// Filters expression node index in the plan node arena. + pub filter: NodeId, + /// Outputs tuple node index in the plan node arena. + pub output: NodeId, +} + +impl From<Selection> for SizeNode { + fn from(value: Selection) -> Self { + Self::Node64(Node64::Selection(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct GroupBy { + /// The first child is a relational operator before group by + pub children: Vec<NodeId>, + pub gr_cols: Vec<NodeId>, + pub output: NodeId, + pub is_final: bool, +} + +impl From<GroupBy> for SizeNode { + fn from(value: GroupBy) -> Self { + Self::Node64(Node64::GroupBy(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Having { + pub children: Vec<NodeId>, + pub output: NodeId, + pub filter: NodeId, +} + +impl From<Having> for SizeNode { + fn from(value: Having) -> Self { + Self::Node64(Node64::Having(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct OrderBy { + pub child: NodeId, + pub output: NodeId, + pub order_by_elements: Vec<OrderByElement>, +} + +impl From<OrderBy> for SizeNode { + fn from(value: OrderBy) -> Self { + Self::Node64(Node64::OrderBy(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct UnionAll { + /// Left child id + pub left: NodeId, + /// Right child id + pub right: NodeId, + /// Outputs tuple node index in the plan node arena. + pub output: NodeId, +} + +impl From<UnionAll> for SizeNode { + fn from(value: UnionAll) -> Self { + Self::Node32(Node32::UnionAll(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Values { + /// Output tuple. + pub output: NodeId, + /// Non-empty list of value rows. + pub children: Vec<NodeId>, +} + +impl From<Values> for SizeNode { + fn from(value: Values) -> Self { + Self::Node32(Node32::Values(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct ValuesRow { + /// Output tuple of aliases. + pub output: NodeId, + /// The data tuple. + pub 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. + pub children: Vec<NodeId>, +} + +impl From<ValuesRow> for SizeNode { + fn from(value: ValuesRow) -> Self { + Self::Node64(Node64::ValuesRow(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct DropRole { + pub name: SmolStr, + pub timeout: Decimal, +} + +impl From<DropRole> for SizeNode { + fn from(value: DropRole) -> Self { + Self::Node64(Node64::DropRole(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct DropUser { + pub name: SmolStr, + pub timeout: Decimal, +} + +impl From<DropUser> for SizeNode { + fn from(value: DropUser) -> Self { + Self::Node64(Node64::DropUser(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct CreateRole { + pub name: SmolStr, + pub timeout: Decimal, +} + +impl From<CreateRole> for SizeNode { + fn from(value: CreateRole) -> Self { + Self::Node64(Node64::CreateRole(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct CreateUser { + pub name: SmolStr, + pub password: SmolStr, + pub auth_method: SmolStr, + pub timeout: Decimal, +} + +impl From<CreateUser> for SizeNode { + fn from(value: CreateUser) -> Self { + Self::Node136(Node136::CreateUser(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct AlterUser { + pub name: SmolStr, + pub alter_option: AlterOption, + pub timeout: Decimal, +} + +impl From<AlterUser> for SizeNode { + fn from(value: AlterUser) -> Self { + Self::Node136(Node136::AlterUser(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct GrantPrivilege { + pub grant_type: GrantRevokeType, + pub grantee_name: SmolStr, + pub timeout: Decimal, +} + +impl From<GrantPrivilege> for SizeNode { + fn from(value: GrantPrivilege) -> Self { + Self::Node136(Node136::GrantPrivilege(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct RevokePrivilege { + pub revoke_type: GrantRevokeType, + pub grantee_name: SmolStr, + pub timeout: Decimal, +} + +impl From<RevokePrivilege> for SizeNode { + fn from(value: RevokePrivilege) -> Self { + Self::Node136(Node136::RevokePrivilege(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct CreateTable { + pub name: SmolStr, + pub format: Vec<ColumnDef>, + pub primary_key: Vec<SmolStr>, + /// If `None`, create global table. + pub sharding_key: Option<Vec<SmolStr>>, + /// Vinyl is supported only for sharded tables. + pub engine_type: SpaceEngineType, + pub timeout: Decimal, + /// Shows which tier the sharded table belongs to. + /// Field has value, only if it was specified in [ON TIER] part of CREATE TABLE statement. + /// Field is None, if: + /// 1) Global table. + /// 2) Sharded table without [ON TIER] part. In this case picodata will use default tier. + pub tier: Option<SmolStr>, +} + +impl From<CreateTable> for SizeNode { + fn from(value: CreateTable) -> Self { + Self::Node224(Node224::CreateTable(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct DropTable { + pub name: SmolStr, + pub timeout: Decimal, +} + +impl From<DropTable> for SizeNode { + fn from(value: DropTable) -> Self { + Self::Node64(Node64::DropTable(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct CreateProc { + pub name: SmolStr, + pub params: Vec<ParamDef>, + pub body: SmolStr, + pub language: Language, + pub timeout: Decimal, +} + +impl From<CreateProc> for SizeNode { + fn from(value: CreateProc) -> Self { + Self::Node136(Node136::CreateProc(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct DropProc { + pub name: SmolStr, + pub params: Option<Vec<ParamDef>>, + pub timeout: Decimal, +} + +impl From<DropProc> for SizeNode { + fn from(value: DropProc) -> Self { + Self::Node96(Node96::DropProc(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct RenameRoutine { + pub old_name: SmolStr, + pub new_name: SmolStr, + pub params: Option<Vec<ParamDef>>, + pub timeout: Decimal, +} + +impl From<RenameRoutine> for SizeNode { + fn from(value: RenameRoutine) -> Self { + Self::Node136(Node136::RenameRoutine(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct CreateIndex { + pub name: SmolStr, + pub table_name: SmolStr, + pub columns: Vec<SmolStr>, + pub unique: bool, + pub index_type: IndexType, + pub bloom_fpr: Option<Decimal>, + pub page_size: Option<u32>, + pub range_size: Option<u32>, + pub run_count_per_level: Option<u32>, + pub run_size_ratio: Option<Decimal>, + pub dimension: Option<u32>, + pub distance: Option<RtreeIndexDistanceType>, + pub hint: Option<bool>, + pub timeout: Decimal, +} + +impl From<CreateIndex> for SizeNode { + fn from(value: CreateIndex) -> Self { + Self::Node224(Node224::CreateIndex(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct DropIndex { + pub name: SmolStr, + pub timeout: Decimal, +} + +impl From<DropIndex> for SizeNode { + fn from(value: DropIndex) -> Self { + Self::Node64(Node64::DropIndex(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct SetParam { + pub scope_type: SetParamScopeType, + pub param_value: SetParamValue, + pub timeout: Decimal, +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct AlterSystem { + pub ty: AlterSystemType, + /// In case of None, ALTER is supposed + /// to be executed on all tiers. + pub tier_name: Option<SmolStr>, + pub timeout: Decimal, +} + +impl From<AlterSystem> for SizeNode { + fn from(value: AlterSystem) -> Self { + Self::Node136(Node136::AlterSystem(value)) + } +} + +impl From<SetParam> for SizeNode { + fn from(value: SetParam) -> Self { + Self::Node64(Node64::SetParam(value)) + } +} + +// TODO: Fill with actual values. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct SetTransaction { + pub timeout: Decimal, +} + +impl From<SetTransaction> for SizeNode { + fn from(value: SetTransaction) -> Self { + Self::Node64(Node64::SetTransaction(value)) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct Invalid; + +impl From<Invalid> for SizeNode { + fn from(value: Invalid) -> Self { + Self::Node32(Node32::Invalid(value)) + } +} + +/// Procedure body. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct Procedure { + /// The name of the procedure. + pub name: SmolStr, + /// Passed values to the procedure. + pub values: Vec<NodeId>, +} + +impl From<Procedure> for SizeNode { + fn from(value: Procedure) -> Self { + Self::Node64(Node64::Procedure(value)) + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct Union { + /// Left child id + pub left: NodeId, + /// Right child id + pub right: NodeId, + /// Outputs tuple node index in the plan node arena. + pub output: NodeId, +} + +impl From<Union> for SizeNode { + fn from(value: Union) -> Self { + Self::Node32(Node32::Union(value)) + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub enum Node32 { + Invalid(Invalid), + Union(Union), + CountAsterisk(CountAsterisk), + ExprInParentheses(ExprInParentheses), + Unary(UnaryExpr), + Concat(Concat), + Bool(BoolExpr), + Limit(Limit), + Arithmetic(ArithmeticExpr), + Trim(Trim), + Cast(Cast), + Alias(Alias), + Except(Except), + Intersect(Intersect), + UnionAll(UnionAll), + Values(Values), +} + +const _: () = { + assert!(std::mem::size_of::<Node32>() == 40); + assert!(std::mem::size_of::<Node64>() == 72); + assert!(std::mem::size_of::<Node96>() == 96); + assert!(std::mem::size_of::<Node136>() == 136); + assert!(std::mem::size_of::<Node224>() == 224); +}; +impl Node32 { + #[must_use] + pub fn into_common_node(self) -> NodeOwned { + match self { + Node32::Alias(alias) => NodeOwned::Expression(ExprOwned::Alias(alias)), + Node32::Arithmetic(arithm) => NodeOwned::Expression(ExprOwned::Arithmetic(arithm)), + Node32::Bool(bool) => NodeOwned::Expression(ExprOwned::Bool(bool)), + Node32::Limit(limit) => NodeOwned::Relational(RelOwned::Limit(limit)), + Node32::Cast(cast) => NodeOwned::Expression(ExprOwned::Cast(cast)), + Node32::Concat(concat) => NodeOwned::Expression(ExprOwned::Concat(concat)), + Node32::CountAsterisk(count) => NodeOwned::Expression(ExprOwned::CountAsterisk(count)), + Node32::Except(except) => NodeOwned::Relational(RelOwned::Except(except)), + Node32::ExprInParentheses(expr_in_par) => { + NodeOwned::Expression(ExprOwned::ExprInParentheses(expr_in_par)) + } + Node32::Intersect(intersect) => NodeOwned::Relational(RelOwned::Intersect(intersect)), + Node32::Invalid(inv) => NodeOwned::Invalid(inv), + Node32::Trim(trim) => NodeOwned::Expression(ExprOwned::Trim(trim)), + Node32::Unary(unary) => NodeOwned::Expression(ExprOwned::Unary(unary)), + Node32::Union(un) => NodeOwned::Relational(RelOwned::Union(un)), + Node32::UnionAll(union_all) => NodeOwned::Relational(RelOwned::UnionAll(union_all)), + Node32::Values(values) => NodeOwned::Relational(RelOwned::Values(values)), + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub enum Node64 { + ScanCte(ScanCte), + Case(Case), + Parameter(Parameter), + Constant(Constant), + Projection(Projection), + Selection(Selection), + Having(Having), + ValuesRow(ValuesRow), + OrderBy(OrderBy), + Procedure(Procedure), + Join(Join), + Row(Row), // move to Node64 + Reference(Reference), + Delete(Delete), + ScanRelation(ScanRelation), + ScanSubQuery(ScanSubQuery), + DropRole(DropRole), + DropUser(DropUser), + CreateRole(CreateRole), + DropTable(DropTable), + DropIndex(DropIndex), + GroupBy(GroupBy), + SetParam(SetParam), + SetTransaction(SetTransaction), +} + +impl Node64 { + /// # Errors + pub fn into_expr_node(&self) -> Result<Expression<'_>, SbroadError> { + match self { + Node64::Case(case) => Ok(Expression::Case(case)), + Node64::Constant(constant) => Ok(Expression::Constant(constant)), + _ => Err(SbroadError::Invalid(crate::errors::Entity::Node, None)), + } + } + + #[must_use] + pub fn into_common_node(self) -> NodeOwned { + match self { + Node64::Case(case) => NodeOwned::Expression(ExprOwned::Case(case)), + Node64::Constant(constant) => NodeOwned::Expression(ExprOwned::Constant(constant)), + Node64::CreateRole(create_role) => NodeOwned::Acl(AclOwned::CreateRole(create_role)), + Node64::Delete(delete) => NodeOwned::Relational(RelOwned::Delete(delete)), + Node64::DropIndex(drop_index) => NodeOwned::Ddl(DdlOwned::DropIndex(drop_index)), + Node64::DropRole(drop_role) => NodeOwned::Acl(AclOwned::DropRole(drop_role)), + Node64::DropTable(drop_table) => NodeOwned::Ddl(DdlOwned::DropTable(drop_table)), + Node64::DropUser(drop_user) => NodeOwned::Acl(AclOwned::DropUser(drop_user)), + Node64::GroupBy(group_by) => NodeOwned::Relational(RelOwned::GroupBy(group_by)), + Node64::Having(having) => NodeOwned::Relational(RelOwned::Having(having)), + Node64::Join(join) => NodeOwned::Relational(RelOwned::Join(join)), + Node64::OrderBy(order_by) => NodeOwned::Relational(RelOwned::OrderBy(order_by)), + Node64::Parameter(param) => NodeOwned::Parameter(param), + Node64::Row(row) => NodeOwned::Expression(ExprOwned::Row(row)), + Node64::Procedure(proc) => NodeOwned::Block(BlockOwned::Procedure(proc)), + Node64::Projection(proj) => NodeOwned::Relational(RelOwned::Projection(proj)), + Node64::Reference(reference) => NodeOwned::Expression(ExprOwned::Reference(reference)), + Node64::ScanCte(scan_cte) => NodeOwned::Relational(RelOwned::ScanCte(scan_cte)), + Node64::ScanRelation(scan_rel) => { + NodeOwned::Relational(RelOwned::ScanRelation(scan_rel)) + } + Node64::ScanSubQuery(scan_squery) => { + NodeOwned::Relational(RelOwned::ScanSubQuery(scan_squery)) + } + Node64::Selection(sel) => NodeOwned::Relational(RelOwned::Selection(sel)), + Node64::SetParam(set_param) => NodeOwned::Ddl(DdlOwned::SetParam(set_param)), + Node64::SetTransaction(set_trans) => { + NodeOwned::Ddl(DdlOwned::SetTransaction(set_trans)) + } + Node64::ValuesRow(values_row) => NodeOwned::Relational(RelOwned::ValuesRow(values_row)), + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub enum Node96 { + Invalid(Invalid), + StableFunction(StableFunction), + DropProc(DropProc), + Insert(Insert), +} + +impl Node96 { + #[must_use] + pub fn into_common_node(self) -> NodeOwned { + match self { + Node96::DropProc(drop_proc) => NodeOwned::Ddl(DdlOwned::DropProc(drop_proc)), + Node96::Insert(insert) => NodeOwned::Relational(RelOwned::Insert(insert)), + Node96::Invalid(inv) => NodeOwned::Invalid(inv), + Node96::StableFunction(stable_func) => { + NodeOwned::Expression(ExprOwned::StableFunction(stable_func)) + } + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub enum Node136 { + Invalid(Invalid), + CreateUser(CreateUser), + AlterUser(AlterUser), + AlterSystem(AlterSystem), + CreateProc(CreateProc), + RenameRoutine(RenameRoutine), + Motion(Motion), + GrantPrivilege(GrantPrivilege), + RevokePrivilege(RevokePrivilege), + Update(Update), +} + +impl Node136 { + #[must_use] + pub fn into_common_node(self) -> NodeOwned { + match self { + Node136::AlterUser(alter_user) => NodeOwned::Acl(AclOwned::AlterUser(alter_user)), + Node136::AlterSystem(alter_system) => { + NodeOwned::Ddl(DdlOwned::AlterSystem(alter_system)) + } + Node136::CreateProc(create_proc) => NodeOwned::Ddl(DdlOwned::CreateProc(create_proc)), + Node136::GrantPrivilege(grant_privelege) => { + NodeOwned::Acl(AclOwned::GrantPrivilege(grant_privelege)) + } + Node136::CreateUser(create_user) => NodeOwned::Acl(AclOwned::CreateUser(create_user)), + Node136::RevokePrivilege(revoke_privelege) => { + NodeOwned::Acl(AclOwned::RevokePrivilege(revoke_privelege)) + } + Node136::Invalid(inv) => NodeOwned::Invalid(inv), + Node136::Motion(motion) => NodeOwned::Relational(RelOwned::Motion(motion)), + Node136::Update(update) => NodeOwned::Relational(RelOwned::Update(update)), + Node136::RenameRoutine(rename_routine) => { + NodeOwned::Ddl(DdlOwned::RenameRoutine(rename_routine)) + } + } + } +} + +#[allow(clippy::module_name_repetitions, clippy::large_enum_variant)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub enum Node224 { + Invalid(Invalid), + CreateTable(CreateTable), + CreateIndex(CreateIndex), +} + +impl Node224 { + #[must_use] + pub fn into_common_node(self) -> NodeOwned { + match self { + Node224::CreateTable(create_table) => { + NodeOwned::Ddl(DdlOwned::CreateTable(create_table)) + } + Node224::CreateIndex(create_index) => { + NodeOwned::Ddl(DdlOwned::CreateIndex(create_index)) + } + Node224::Invalid(inv) => NodeOwned::Invalid(inv), + } + } +} + +#[allow(clippy::module_name_repetitions)] +pub enum SizeNode { + Node32(Node32), + Node64(Node64), + Node96(Node96), + Node136(Node136), + Node224(Node224), +} + +impl From<Node32> for SizeNode { + fn from(value: Node32) -> Self { + Self::Node32(value) + } +} + +impl From<Node64> for SizeNode { + fn from(value: Node64) -> Self { + Self::Node64(value) + } +} + +impl From<Node96> for SizeNode { + fn from(value: Node96) -> Self { + Self::Node96(value) + } +} + +impl From<Node136> for SizeNode { + fn from(value: Node136) -> Self { + Self::Node136(value) + } +} + +impl From<Node224> for SizeNode { + fn from(value: Node224) -> Self { + Self::Node224(value) + } +} +// parameter to avoid multiple enums +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub enum Node<'nodes> { + Expression(Expression<'nodes>), + Relational(Relational<'nodes>), + Acl(Acl<'nodes>), + Ddl(Ddl<'nodes>), + Block(Block<'nodes>), + Parameter(&'nodes Parameter), + Invalid(&'nodes Invalid), +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Debug, PartialEq, Eq)] +pub enum MutNode<'nodes> { + Expression(MutExpression<'nodes>), + Relational(MutRelational<'nodes>), + Acl(MutAcl<'nodes>), + Ddl(MutDdl<'nodes>), + Block(MutBlock<'nodes>), + Parameter(&'nodes mut Parameter), + Invalid(&'nodes mut Invalid), +} + +impl MutNode<'_> { + #[must_use] + pub fn get_common_node(self) -> NodeOwned { + match self { + MutNode::Expression(expr) => NodeOwned::Expression(expr.get_expr_owned()), + MutNode::Relational(rel) => NodeOwned::Relational(rel.get_rel_owned()), + MutNode::Ddl(ddl) => NodeOwned::Ddl(ddl.get_ddl_owned()), + MutNode::Acl(acl) => NodeOwned::Acl(acl.get_acl_owned()), + MutNode::Block(block) => NodeOwned::Block(block.get_block_owned()), + MutNode::Parameter(param) => NodeOwned::Parameter((*param).clone()), + MutNode::Invalid(inv) => NodeOwned::Invalid((*inv).clone()), + } + } +} + +impl Node<'_> { + #[must_use] + pub fn get_common_node(self) -> NodeOwned { + match self { + Node::Expression(expr) => NodeOwned::Expression(expr.get_expr_owned()), + Node::Relational(rel) => NodeOwned::Relational(rel.get_rel_owned()), + Node::Ddl(ddl) => NodeOwned::Ddl(ddl.get_ddl_owned()), + Node::Acl(acl) => NodeOwned::Acl(acl.get_acl_owned()), + Node::Block(block) => NodeOwned::Block(block.get_block_owned()), + Node::Parameter(param) => NodeOwned::Parameter((*param).clone()), + Node::Invalid(inv) => NodeOwned::Invalid((*inv).clone()), + } + } +} + +// rename to NodeOwned +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum NodeOwned { + Expression(ExprOwned), + Relational(RelOwned), + Ddl(DdlOwned), + Acl(AclOwned), + Block(BlockOwned), + Parameter(Parameter), + Invalid(Invalid), +} + +impl From<NodeOwned> for SizeNode { + fn from(value: NodeOwned) -> Self { + match value { + NodeOwned::Acl(acl) => acl.into(), + NodeOwned::Block(block) => block.into(), + NodeOwned::Ddl(ddl) => ddl.into(), + NodeOwned::Expression(expr) => expr.into(), + NodeOwned::Invalid(inv) => inv.into(), + NodeOwned::Parameter(param) => param.into(), + NodeOwned::Relational(rel) => rel.into(), + } + } +} diff --git a/sbroad-core/src/ir/node/acl.rs b/sbroad-core/src/ir/node/acl.rs new file mode 100644 index 000000000..b75a9bc81 --- /dev/null +++ b/sbroad-core/src/ir/node/acl.rs @@ -0,0 +1,121 @@ +use serde::Serialize; +use smol_str::{format_smolstr, ToSmolStr}; + +use crate::errors::{Entity, SbroadError}; + +use super::{ + AlterUser, CreateRole, CreateUser, DropRole, DropUser, GrantPrivilege, RevokePrivilege, + SizeNode, +}; + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum AclOwned { + DropRole(DropRole), + DropUser(DropUser), + CreateRole(CreateRole), + CreateUser(CreateUser), + AlterUser(AlterUser), + GrantPrivilege(GrantPrivilege), + RevokePrivilege(RevokePrivilege), +} + +impl From<AclOwned> for SizeNode { + fn from(value: AclOwned) -> Self { + match value { + AclOwned::AlterUser(alter_user) => alter_user.into(), + AclOwned::CreateRole(create_role) => create_role.into(), + AclOwned::CreateUser(create_user) => create_user.into(), + AclOwned::DropRole(drop_role) => drop_role.into(), + AclOwned::DropUser(drop_user) => drop_user.into(), + AclOwned::GrantPrivilege(grant_privilege) => grant_privilege.into(), + AclOwned::RevokePrivilege(revoke_privilege) => revoke_privilege.into(), + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Debug, PartialEq, Eq, Serialize)] +pub enum MutAcl<'a> { + DropRole(&'a mut DropRole), + DropUser(&'a mut DropUser), + CreateRole(&'a mut CreateRole), + CreateUser(&'a mut CreateUser), + AlterUser(&'a mut AlterUser), + GrantPrivilege(&'a mut GrantPrivilege), + RevokePrivilege(&'a mut RevokePrivilege), +} + +impl MutAcl<'_> { + #[must_use] + pub fn get_acl_owned(&self) -> AclOwned { + match self { + MutAcl::AlterUser(alter_user) => AclOwned::AlterUser((*alter_user).clone()), + MutAcl::CreateRole(create_role) => AclOwned::CreateRole((*create_role).clone()), + MutAcl::CreateUser(create_user) => AclOwned::CreateUser((*create_user).clone()), + MutAcl::DropRole(drop_role) => AclOwned::DropRole((*drop_role).clone()), + MutAcl::DropUser(drop_user) => AclOwned::DropUser((*drop_user).clone()), + MutAcl::GrantPrivilege(grant_privelege) => { + AclOwned::GrantPrivilege((*grant_privelege).clone()) + } + MutAcl::RevokePrivilege(revoke_privelege) => { + AclOwned::RevokePrivilege((*revoke_privelege).clone()) + } + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum Acl<'a> { + DropRole(&'a DropRole), + DropUser(&'a DropUser), + CreateRole(&'a CreateRole), + CreateUser(&'a CreateUser), + AlterUser(&'a AlterUser), + GrantPrivilege(&'a GrantPrivilege), + RevokePrivilege(&'a RevokePrivilege), +} + +impl Acl<'_> { + /// Return ACL node timeout. + /// + /// # Errors + /// - timeout parsing error + pub fn timeout(&self) -> Result<f64, SbroadError> { + match self { + Acl::DropRole(DropRole { ref timeout, .. }) + | Acl::DropUser(DropUser { ref timeout, .. }) + | Acl::CreateRole(CreateRole { ref timeout, .. }) + | Acl::AlterUser(AlterUser { ref timeout, .. }) + | Acl::CreateUser(CreateUser { ref timeout, .. }) + | Acl::RevokePrivilege(RevokePrivilege { ref timeout, .. }) + | Acl::GrantPrivilege(GrantPrivilege { ref timeout, .. }) => timeout, + } + .to_smolstr() + .parse() + .map_err(|e| { + SbroadError::Invalid( + Entity::SpaceMetadata, + Some(format_smolstr!("timeout parsing error {e:?}")), + ) + }) + } + + #[must_use] + pub fn get_acl_owned(&self) -> AclOwned { + match self { + Acl::AlterUser(alter_user) => AclOwned::AlterUser((*alter_user).clone()), + Acl::CreateRole(create_role) => AclOwned::CreateRole((*create_role).clone()), + Acl::CreateUser(create_user) => AclOwned::CreateUser((*create_user).clone()), + Acl::DropRole(drop_role) => AclOwned::DropRole((*drop_role).clone()), + Acl::DropUser(drop_user) => AclOwned::DropUser((*drop_user).clone()), + Acl::GrantPrivilege(grant_privelege) => { + AclOwned::GrantPrivilege((*grant_privelege).clone()) + } + Acl::RevokePrivilege(revoke_privelege) => { + AclOwned::RevokePrivilege((*revoke_privelege).clone()) + } + } + } +} diff --git a/sbroad-core/src/ir/node/block.rs b/sbroad-core/src/ir/node/block.rs new file mode 100644 index 000000000..e36f164c1 --- /dev/null +++ b/sbroad-core/src/ir/node/block.rs @@ -0,0 +1,50 @@ +use serde::Serialize; + +use super::{Procedure, SizeNode}; + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum BlockOwned { + /// Procedure body. + Procedure(Procedure), +} + +impl From<BlockOwned> for SizeNode { + fn from(value: BlockOwned) -> Self { + match value { + BlockOwned::Procedure(proc) => proc.into(), + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Debug, Eq, PartialEq, Serialize)] +pub enum MutBlock<'a> { + /// Procedure body. + Procedure(&'a mut Procedure), +} + +impl MutBlock<'_> { + #[must_use] + pub fn get_block_owned(&self) -> BlockOwned { + match self { + MutBlock::Procedure(proc) => BlockOwned::Procedure((*proc).clone()), + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum Block<'a> { + /// Procedure body. + Procedure(&'a Procedure), +} + +impl Block<'_> { + #[must_use] + pub fn get_block_owned(&self) -> BlockOwned { + match self { + Block::Procedure(proc) => BlockOwned::Procedure((*proc).clone()), + } + } +} diff --git a/sbroad-core/src/ir/node/ddl.rs b/sbroad-core/src/ir/node/ddl.rs new file mode 100644 index 000000000..53f2b058b --- /dev/null +++ b/sbroad-core/src/ir/node/ddl.rs @@ -0,0 +1,134 @@ +use serde::Serialize; +use smol_str::{format_smolstr, ToSmolStr}; + +use crate::errors::{Entity, SbroadError}; + +use super::{ + AlterSystem, CreateIndex, CreateProc, CreateTable, DropIndex, DropProc, DropTable, + RenameRoutine, SetParam, SetTransaction, SizeNode, +}; + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum DdlOwned { + CreateTable(CreateTable), + DropTable(DropTable), + CreateProc(CreateProc), + DropProc(DropProc), + RenameRoutine(RenameRoutine), + AlterSystem(AlterSystem), + CreateIndex(CreateIndex), + DropIndex(DropIndex), + SetParam(SetParam), + SetTransaction(SetTransaction), +} + +impl From<DdlOwned> for SizeNode { + fn from(value: DdlOwned) -> Self { + match value { + DdlOwned::CreateIndex(create_index) => create_index.into(), + DdlOwned::CreateProc(create_proc) => create_proc.into(), + DdlOwned::CreateTable(create_table) => create_table.into(), + DdlOwned::DropIndex(drop_index) => drop_index.into(), + DdlOwned::DropProc(drop_proc) => drop_proc.into(), + DdlOwned::DropTable(drop_table) => drop_table.into(), + DdlOwned::AlterSystem(alter_system) => alter_system.into(), + DdlOwned::RenameRoutine(rename) => rename.into(), + DdlOwned::SetParam(set_param) => set_param.into(), + DdlOwned::SetTransaction(set_trans) => set_trans.into(), + } + } +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Debug, PartialEq, Eq, Serialize)] +pub enum MutDdl<'a> { + CreateTable(&'a mut CreateTable), + DropTable(&'a mut DropTable), + CreateProc(&'a mut CreateProc), + DropProc(&'a mut DropProc), + RenameRoutine(&'a mut RenameRoutine), + AlterSystem(&'a mut AlterSystem), + CreateIndex(&'a mut CreateIndex), + DropIndex(&'a mut DropIndex), + SetParam(&'a mut SetParam), + SetTransaction(&'a mut SetTransaction), +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum Ddl<'a> { + CreateTable(&'a CreateTable), + DropTable(&'a DropTable), + CreateProc(&'a CreateProc), + DropProc(&'a DropProc), + RenameRoutine(&'a RenameRoutine), + AlterSystem(&'a AlterSystem), + CreateIndex(&'a CreateIndex), + DropIndex(&'a DropIndex), + SetParam(&'a SetParam), + SetTransaction(&'a SetTransaction), +} + +impl MutDdl<'_> { + #[must_use] + pub fn get_ddl_owned(&self) -> DdlOwned { + match self { + MutDdl::CreateIndex(create_index) => DdlOwned::CreateIndex((*create_index).clone()), + MutDdl::CreateProc(create_proc) => DdlOwned::CreateProc((*create_proc).clone()), + MutDdl::CreateTable(create_table) => DdlOwned::CreateTable((*create_table).clone()), + MutDdl::DropIndex(drop_index) => DdlOwned::DropIndex((*drop_index).clone()), + MutDdl::DropProc(drop_proc) => DdlOwned::DropProc((*drop_proc).clone()), + MutDdl::DropTable(drop_table) => DdlOwned::DropTable((*drop_table).clone()), + MutDdl::RenameRoutine(rename) => DdlOwned::RenameRoutine((*rename).clone()), + MutDdl::AlterSystem(alter_system) => DdlOwned::AlterSystem((*alter_system).clone()), + MutDdl::SetParam(set_param) => DdlOwned::SetParam((*set_param).clone()), + MutDdl::SetTransaction(set_trans) => DdlOwned::SetTransaction((*set_trans).clone()), + } + } +} + +impl Ddl<'_> { + /// Return DDL node timeout. + /// + /// # Errors + /// - timeout parsing error + pub fn timeout(&self) -> Result<f64, SbroadError> { + match self { + Ddl::CreateTable(CreateTable { ref timeout, .. }) + | Ddl::DropTable(DropTable { ref timeout, .. }) + | Ddl::CreateIndex(CreateIndex { ref timeout, .. }) + | Ddl::DropIndex(DropIndex { ref timeout, .. }) + | Ddl::SetParam(SetParam { ref timeout, .. }) + | Ddl::SetTransaction(SetTransaction { ref timeout, .. }) + | Ddl::AlterSystem(AlterSystem { ref timeout, .. }) + | Ddl::CreateProc(CreateProc { ref timeout, .. }) + | Ddl::DropProc(DropProc { ref timeout, .. }) + | Ddl::RenameRoutine(RenameRoutine { ref timeout, .. }) => timeout, + } + .to_smolstr() + .parse() + .map_err(|e| { + SbroadError::Invalid( + Entity::SpaceMetadata, + Some(format_smolstr!("timeout parsing error {e:?}")), + ) + }) + } + + #[must_use] + pub fn get_ddl_owned(&self) -> DdlOwned { + match self { + Ddl::CreateIndex(create_index) => DdlOwned::CreateIndex((*create_index).clone()), + Ddl::CreateProc(create_proc) => DdlOwned::CreateProc((*create_proc).clone()), + Ddl::CreateTable(create_table) => DdlOwned::CreateTable((*create_table).clone()), + Ddl::DropIndex(drop_index) => DdlOwned::DropIndex((*drop_index).clone()), + Ddl::DropProc(drop_proc) => DdlOwned::DropProc((*drop_proc).clone()), + Ddl::DropTable(drop_table) => DdlOwned::DropTable((*drop_table).clone()), + Ddl::AlterSystem(alter_system) => DdlOwned::AlterSystem((*alter_system).clone()), + Ddl::RenameRoutine(rename) => DdlOwned::RenameRoutine((*rename).clone()), + Ddl::SetParam(set_param) => DdlOwned::SetParam((*set_param).clone()), + Ddl::SetTransaction(set_trans) => DdlOwned::SetTransaction((*set_trans).clone()), + } + } +} diff --git a/sbroad-core/src/ir/node/expression.rs b/sbroad-core/src/ir/node/expression.rs new file mode 100644 index 000000000..e748a01bc --- /dev/null +++ b/sbroad-core/src/ir/node/expression.rs @@ -0,0 +1,263 @@ +use serde::Serialize; + +use crate::{ + errors::{Entity, SbroadError}, + ir::{aggregates::AggregateKind, distribution::Distribution}, +}; + +use super::{ + Alias, ArithmeticExpr, BoolExpr, Case, Cast, Concat, Constant, CountAsterisk, + ExprInParentheses, NodeId, Reference, Row, SizeNode, StableFunction, Trim, UnaryExpr, +}; + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum ExprOwned { + Alias(Alias), + Bool(BoolExpr), + Arithmetic(ArithmeticExpr), + Cast(Cast), + Concat(Concat), + Constant(Constant), + Reference(Reference), + Row(Row), + StableFunction(StableFunction), + Trim(Trim), + Unary(UnaryExpr), + CountAsterisk(CountAsterisk), + Case(Case), + ExprInParentheses(ExprInParentheses), +} + +impl From<ExprOwned> for SizeNode { + fn from(value: ExprOwned) -> Self { + match value { + ExprOwned::Alias(alias) => alias.into(), + ExprOwned::Arithmetic(arithm) => arithm.into(), + ExprOwned::Bool(bool) => bool.into(), + ExprOwned::Case(case) => case.into(), + ExprOwned::Cast(cast) => cast.into(), + ExprOwned::Concat(concat) => concat.into(), + ExprOwned::Constant(constant) => constant.into(), + ExprOwned::CountAsterisk(count) => count.into(), + ExprOwned::ExprInParentheses(expr) => expr.into(), + ExprOwned::Reference(reference) => reference.into(), + ExprOwned::Row(row) => row.into(), + ExprOwned::StableFunction(stable_func) => stable_func.into(), + ExprOwned::Trim(trim) => trim.into(), + ExprOwned::Unary(unary) => unary.into(), + } + } +} + +/// Tuple tree build blocks. +/// +/// A tuple describes a single portion of data moved among cluster nodes. +/// It consists of the ordered, strictly typed expressions with names +/// (columns) and additional information about data distribution policy. +/// +/// Tuple is a tree with a `Row` top (level 0) and a list of the named +/// `Alias` columns (level 1). This convention is used across the code +/// and should not be changed. It ensures that we always know the +/// name of any column in the tuple and therefore simplifies AST +/// deserialization. +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum Expression<'a> { + Alias(&'a Alias), + Bool(&'a BoolExpr), + Arithmetic(&'a ArithmeticExpr), + Cast(&'a Cast), + Concat(&'a Concat), + Constant(&'a Constant), + Reference(&'a Reference), + Row(&'a Row), + StableFunction(&'a StableFunction), + Trim(&'a Trim), + Unary(&'a UnaryExpr), + CountAsterisk(&'a CountAsterisk), + Case(&'a Case), + ExprInParentheses(&'a ExprInParentheses), +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Debug, PartialEq, Eq)] +pub enum MutExpression<'a> { + Alias(&'a mut Alias), + Bool(&'a mut BoolExpr), + Arithmetic(&'a mut ArithmeticExpr), + Cast(&'a mut Cast), + Concat(&'a mut Concat), + Constant(&'a mut Constant), + Reference(&'a mut Reference), + Row(&'a mut Row), + StableFunction(&'a mut StableFunction), + Trim(&'a mut Trim), + Unary(&'a mut UnaryExpr), + CountAsterisk(&'a mut CountAsterisk), + Case(&'a mut Case), + ExprInParentheses(&'a mut ExprInParentheses), +} + +#[allow(dead_code)] +impl Expression<'_> { + /// Gets current row distribution. + /// + /// # Errors + /// Returns `SbroadError` when the function is called on expression + /// other than `Row` or a node doesn't know its distribution yet. + pub fn distribution(&self) -> Result<&Distribution, SbroadError> { + if let Expression::Row(Row { distribution, .. }) = self { + let Some(dist) = distribution else { + return Err(SbroadError::Invalid( + Entity::Distribution, + Some("distribution is uninitialized".into()), + )); + }; + return Ok(dist); + } + Err(SbroadError::Invalid(Entity::Expression, None)) + } + + /// Clone the row children list. + /// + /// # Errors + /// - node isn't `Row` + pub fn clone_row_list(&self) -> Result<Vec<NodeId>, SbroadError> { + match self { + Expression::Row(Row { list, .. }) => Ok(list.clone()), + _ => Err(SbroadError::Invalid( + Entity::Expression, + Some("node isn't Row type".into()), + )), + } + } + + #[must_use] + pub fn is_aggregate_name(name: &str) -> bool { + // currently we support only simple aggregates + AggregateKind::new(name).is_some() + } + + #[must_use] + pub fn is_aggregate_fun(&self) -> bool { + match self { + Expression::StableFunction(StableFunction { name, .. }) => { + Expression::is_aggregate_name(name) + } + _ => false, + } + } + + /// Checks for distribution determination + /// + /// # Errors + /// - distribution isn't set + pub fn has_unknown_distribution(&self) -> Result<bool, SbroadError> { + let d = self.distribution()?; + Ok(d.is_unknown()) + } + + /// Gets relational node id containing the reference. + /// + /// # Errors + /// - node isn't reference type + /// - reference doesn't have a parent + pub fn get_parent(&self) -> Result<NodeId, SbroadError> { + if let Expression::Reference(Reference { parent, .. }) = self { + return parent.ok_or_else(|| { + SbroadError::Invalid(Entity::Expression, Some("Reference has no parent".into())) + }); + } + Err(SbroadError::Invalid( + Entity::Expression, + Some("node is not Reference type".into()), + )) + } + + /// The node is a row expression. + #[must_use] + pub fn is_row(&self) -> bool { + matches!(self, Expression::Row(_)) + } + #[must_use] + pub fn is_arithmetic(&self) -> bool { + matches!(self, Expression::Arithmetic(_)) + } + + #[must_use] + pub fn get_expr_owned(&self) -> ExprOwned { + match self { + Expression::Alias(alias) => ExprOwned::Alias((*alias).clone()), + Expression::Arithmetic(arithm) => ExprOwned::Arithmetic((*arithm).clone()), + Expression::Bool(bool) => ExprOwned::Bool((*bool).clone()), + Expression::Case(case) => ExprOwned::Case((*case).clone()), + Expression::Cast(cast) => ExprOwned::Cast((*cast).clone()), + Expression::Concat(con) => ExprOwned::Concat((*con).clone()), + Expression::Constant(constant) => ExprOwned::Constant((*constant).clone()), + Expression::CountAsterisk(count) => ExprOwned::CountAsterisk((*count).clone()), + Expression::ExprInParentheses(expr_par) => { + ExprOwned::ExprInParentheses((*expr_par).clone()) + } + Expression::Reference(reference) => ExprOwned::Reference((*reference).clone()), + Expression::Row(row) => ExprOwned::Row((*row).clone()), + Expression::StableFunction(sfunc) => ExprOwned::StableFunction((*sfunc).clone()), + Expression::Trim(trim) => ExprOwned::Trim((*trim).clone()), + Expression::Unary(unary) => ExprOwned::Unary((*unary).clone()), + } + } +} + +impl MutExpression<'_> { + /// Get a mutable reference to the row children list. + /// + /// # Errors + /// - node isn't `Row` + pub fn get_row_list_mut(&mut self) -> Result<&mut Vec<NodeId>, SbroadError> { + match self { + MutExpression::Row(Row { ref mut list, .. }) => Ok(list), + _ => Err(SbroadError::Invalid( + Entity::Expression, + Some("node isn't Row type".into()), + )), + } + } + + /// Replaces parent in the reference node with the new one. + pub fn replace_parent_in_reference(&mut self, from_id: Option<NodeId>, to_id: Option<NodeId>) { + if let MutExpression::Reference(Reference { parent, .. }) = self { + if *parent == from_id { + *parent = to_id; + } + } + } + + /// Flushes parent in the reference node. + pub fn flush_parent_in_reference(&mut self) { + if let MutExpression::Reference(Reference { parent, .. }) = self { + *parent = None; + } + } + + #[must_use] + pub fn get_expr_owned(&self) -> ExprOwned { + match self { + MutExpression::Alias(alias) => ExprOwned::Alias((*alias).clone()), + MutExpression::Arithmetic(arithm) => ExprOwned::Arithmetic((*arithm).clone()), + MutExpression::Bool(bool) => ExprOwned::Bool((*bool).clone()), + MutExpression::Case(case) => ExprOwned::Case((*case).clone()), + MutExpression::Cast(cast) => ExprOwned::Cast((*cast).clone()), + MutExpression::Concat(con) => ExprOwned::Concat((*con).clone()), + MutExpression::Constant(constant) => ExprOwned::Constant((*constant).clone()), + MutExpression::CountAsterisk(count) => ExprOwned::CountAsterisk((*count).clone()), + MutExpression::ExprInParentheses(expr_par) => { + ExprOwned::ExprInParentheses((*expr_par).clone()) + } + MutExpression::Reference(reference) => ExprOwned::Reference((*reference).clone()), + MutExpression::Row(row) => ExprOwned::Row((*row).clone()), + MutExpression::StableFunction(sfunc) => ExprOwned::StableFunction((*sfunc).clone()), + MutExpression::Trim(trim) => ExprOwned::Trim((*trim).clone()), + MutExpression::Unary(unary) => ExprOwned::Unary((*unary).clone()), + } + } +} diff --git a/sbroad-core/src/ir/node/relational.rs b/sbroad-core/src/ir/node/relational.rs new file mode 100644 index 000000000..c580db51f --- /dev/null +++ b/sbroad-core/src/ir/node/relational.rs @@ -0,0 +1,704 @@ +use serde::Serialize; +use smol_str::SmolStr; + +use crate::{ + errors::{Entity, SbroadError}, + ir::api::children::{Children, MutChildren}, +}; + +use super::{ + Delete, Except, GroupBy, Having, Insert, Intersect, Join, Limit, Motion, NodeId, OrderBy, + Projection, ScanCte, ScanRelation, ScanSubQuery, Selection, SizeNode, Union, UnionAll, Update, + Values, ValuesRow, +}; + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum RelOwned { + ScanCte(ScanCte), + Except(Except), + Delete(Delete), + Insert(Insert), + Intersect(Intersect), + Update(Update), + Join(Join), + Limit(Limit), + Motion(Motion), + Projection(Projection), + ScanRelation(ScanRelation), + ScanSubQuery(ScanSubQuery), + Selection(Selection), + GroupBy(GroupBy), + Having(Having), + OrderBy(OrderBy), + UnionAll(UnionAll), + Union(Union), + Values(Values), + ValuesRow(ValuesRow), +} + +impl From<RelOwned> for SizeNode { + fn from(value: RelOwned) -> Self { + match value { + RelOwned::ScanCte(scan_cte) => scan_cte.into(), + RelOwned::Delete(delete) => delete.into(), + RelOwned::Except(except) => except.into(), + RelOwned::GroupBy(group_by) => group_by.into(), + RelOwned::Having(having) => having.into(), + RelOwned::Insert(insert) => insert.into(), + RelOwned::Intersect(intersect) => intersect.into(), + RelOwned::Join(join) => join.into(), + RelOwned::Limit(limit) => limit.into(), + RelOwned::Motion(motion) => motion.into(), + RelOwned::OrderBy(order_by) => order_by.into(), + RelOwned::Projection(proj) => proj.into(), + RelOwned::ScanRelation(scan_rel) => scan_rel.into(), + RelOwned::ScanSubQuery(scan_squery) => scan_squery.into(), + RelOwned::Selection(selection) => selection.into(), + RelOwned::Union(un) => un.into(), + RelOwned::UnionAll(union_all) => union_all.into(), + RelOwned::Update(update) => update.into(), + RelOwned::Values(values) => values.into(), + RelOwned::ValuesRow(values_row) => values_row.into(), + } + } +} + +impl RelOwned { + /// Sets new children to relational node. + /// + /// # Panics + /// - wrong number of children for the given node + pub fn set_children(&mut self, children: Vec<NodeId>) { + match self { + RelOwned::Join(Join { + children: ref mut old, + .. + }) + | RelOwned::Delete(Delete { + children: ref mut old, + .. + }) + | RelOwned::Update(Update { + children: ref mut old, + .. + }) + | RelOwned::Insert(Insert { + children: ref mut old, + .. + }) + | RelOwned::Motion(Motion { + children: ref mut old, + .. + }) + | RelOwned::Projection(Projection { + children: ref mut old, + .. + }) + | RelOwned::ScanSubQuery(ScanSubQuery { + children: ref mut old, + .. + }) + | RelOwned::Selection(Selection { + children: ref mut old, + .. + }) + | RelOwned::Values(Values { + children: ref mut old, + .. + }) + | RelOwned::GroupBy(GroupBy { + children: ref mut old, + .. + }) + | RelOwned::Having(Having { + children: ref mut old, + .. + }) + | RelOwned::ValuesRow(ValuesRow { + children: ref mut old, + .. + }) => { + *old = children; + } + RelOwned::Except(Except { left, right, .. }) + | RelOwned::UnionAll(UnionAll { left, right, .. }) + | RelOwned::Intersect(Intersect { left, right, .. }) + | RelOwned::Union(Union { left, right, .. }) => { + if children.len() != 2 { + unreachable!("Node has only two children!"); + } + *left = children[0]; + *right = children[1]; + } + RelOwned::OrderBy(OrderBy { ref mut child, .. }) => { + if children.len() != 1 { + unreachable!("ORDER BY may have only a single relational child"); + } + // It is safe to unwrap here, because the length is already checked above. + *child = children[0]; + } + RelOwned::ScanCte(ScanCte { ref mut child, .. }) => { + if children.len() != 1 { + unreachable!("CTE may have only a single relational child"); + } + // It is safe to unwrap here, because the length is already checked above. + *child = children[0]; + } + RelOwned::Limit(Limit { ref mut child, .. }) => { + if children.len() != 1 { + unreachable!("LIMIT may have only a single relational child"); + } + // It is safe to unwrap here, because the length is already checked above. + *child = children[0]; + } + RelOwned::ScanRelation(ScanRelation { .. }) => { + assert!(children.is_empty(), "scan must have no children!"); + } + } + } + + // Gets an immutable reference to the children nodes. + #[must_use] + pub fn children(&self) -> Children<'_> { + match self { + RelOwned::Limit(Limit { child, .. }) + | RelOwned::OrderBy(OrderBy { child, .. }) + | RelOwned::ScanCte(ScanCte { child, .. }) => Children::Single(child), + RelOwned::Except(Except { left, right, .. }) + | RelOwned::Intersect(Intersect { left, right, .. }) + | RelOwned::UnionAll(UnionAll { left, right, .. }) + | RelOwned::Union(Union { left, right, .. }) => Children::Couple(left, right), + RelOwned::GroupBy(GroupBy { children, .. }) + | RelOwned::Update(Update { children, .. }) + | RelOwned::Join(Join { children, .. }) + | RelOwned::Having(Having { children, .. }) + | RelOwned::Delete(Delete { children, .. }) + | RelOwned::Insert(Insert { children, .. }) + | RelOwned::Motion(Motion { children, .. }) + | RelOwned::Projection(Projection { children, .. }) + | RelOwned::ScanSubQuery(ScanSubQuery { children, .. }) + | RelOwned::Selection(Selection { children, .. }) + | RelOwned::ValuesRow(ValuesRow { children, .. }) + | RelOwned::Values(Values { children, .. }) => Children::Many(children), + RelOwned::ScanRelation(_) => Children::None, + } + } + + #[must_use] + pub fn mut_children(&mut self) -> MutChildren<'_> { + match self { + RelOwned::Limit(Limit { ref mut child, .. }) + | RelOwned::OrderBy(OrderBy { ref mut child, .. }) + | RelOwned::ScanCte(ScanCte { ref mut child, .. }) => MutChildren::Single(child), + RelOwned::Except(Except { + ref mut left, + ref mut right, + .. + }) + | RelOwned::Intersect(Intersect { + ref mut left, + ref mut right, + .. + }) + | RelOwned::UnionAll(UnionAll { + ref mut left, + ref mut right, + .. + }) + | RelOwned::Union(Union { + ref mut left, + ref mut right, + .. + }) => MutChildren::Couple(left, right), + RelOwned::GroupBy(GroupBy { + ref mut children, .. + }) + | RelOwned::Update(Update { + ref mut children, .. + }) + | RelOwned::Join(Join { + ref mut children, .. + }) + | RelOwned::Having(Having { + ref mut children, .. + }) + | RelOwned::Delete(Delete { + ref mut children, .. + }) + | RelOwned::Insert(Insert { + ref mut children, .. + }) + | RelOwned::Motion(Motion { + ref mut children, .. + }) + | RelOwned::Projection(Projection { + ref mut children, .. + }) + | RelOwned::ScanSubQuery(ScanSubQuery { + ref mut children, .. + }) + | RelOwned::Selection(Selection { + ref mut children, .. + }) + | RelOwned::ValuesRow(ValuesRow { + ref mut children, .. + }) + | RelOwned::Values(Values { + ref mut children, .. + }) => MutChildren::Many(children), + RelOwned::ScanRelation(_) => MutChildren::None, + } + } + + /// Gets an mutable reference to the output tuple node id. + #[must_use] + pub fn mut_output(&mut self) -> &mut NodeId { + match self { + RelOwned::ScanCte(ScanCte { output, .. }) + | RelOwned::Except(Except { output, .. }) + | RelOwned::GroupBy(GroupBy { output, .. }) + | RelOwned::OrderBy(OrderBy { output, .. }) + | RelOwned::Update(Update { output, .. }) + | RelOwned::Having(Having { output, .. }) + | RelOwned::Join(Join { output, .. }) + | RelOwned::Limit(Limit { output, .. }) + | RelOwned::Delete(Delete { output, .. }) + | RelOwned::Insert(Insert { output, .. }) + | RelOwned::Intersect(Intersect { output, .. }) + | RelOwned::Motion(Motion { output, .. }) + | RelOwned::Projection(Projection { output, .. }) + | RelOwned::ScanRelation(ScanRelation { output, .. }) + | RelOwned::ScanSubQuery(ScanSubQuery { output, .. }) + | RelOwned::Selection(Selection { output, .. }) + | RelOwned::Union(Union { output, .. }) + | RelOwned::UnionAll(UnionAll { output, .. }) + | RelOwned::Values(Values { output, .. }) + | RelOwned::ValuesRow(ValuesRow { output, .. }) => output, + } + } +} + +/// Relational algebra operator returning a new tuple. +/// +/// Transforms input tuple(s) into the output one using the +/// relation algebra logic. +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub enum Relational<'a> { + ScanCte(&'a ScanCte), + Except(&'a Except), + Delete(&'a Delete), + Insert(&'a Insert), + Intersect(&'a Intersect), + Update(&'a Update), + Join(&'a Join), + Limit(&'a Limit), + Motion(&'a Motion), + Projection(&'a Projection), + ScanRelation(&'a ScanRelation), + ScanSubQuery(&'a ScanSubQuery), + Selection(&'a Selection), + GroupBy(&'a GroupBy), + Having(&'a Having), + OrderBy(&'a OrderBy), + UnionAll(&'a UnionAll), + Union(&'a Union), + Values(&'a Values), + ValuesRow(&'a ValuesRow), +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Debug, PartialEq, Eq, Serialize)] +pub enum MutRelational<'a> { + ScanCte(&'a mut ScanCte), + Except(&'a mut Except), + Delete(&'a mut Delete), + Insert(&'a mut Insert), + Intersect(&'a mut Intersect), + Update(&'a mut Update), + Join(&'a mut Join), + Limit(&'a mut Limit), + Motion(&'a mut Motion), + Projection(&'a mut Projection), + ScanRelation(&'a mut ScanRelation), + ScanSubQuery(&'a mut ScanSubQuery), + Selection(&'a mut Selection), + GroupBy(&'a mut GroupBy), + Having(&'a mut Having), + OrderBy(&'a mut OrderBy), + UnionAll(&'a mut UnionAll), + Union(&'a mut Union), + Values(&'a mut Values), + ValuesRow(&'a mut ValuesRow), +} + +impl MutRelational<'_> { + /// Gets an mutable reference to the output tuple node id. + #[must_use] + pub fn mut_output(&mut self) -> &mut NodeId { + match self { + MutRelational::ScanCte(ScanCte { output, .. }) + | MutRelational::Except(Except { output, .. }) + | MutRelational::GroupBy(GroupBy { output, .. }) + | MutRelational::OrderBy(OrderBy { output, .. }) + | MutRelational::Update(Update { output, .. }) + | MutRelational::Having(Having { output, .. }) + | MutRelational::Join(Join { output, .. }) + | MutRelational::Limit(Limit { output, .. }) + | MutRelational::Delete(Delete { output, .. }) + | MutRelational::Insert(Insert { output, .. }) + | MutRelational::Intersect(Intersect { output, .. }) + | MutRelational::Motion(Motion { output, .. }) + | MutRelational::Projection(Projection { output, .. }) + | MutRelational::ScanRelation(ScanRelation { output, .. }) + | MutRelational::ScanSubQuery(ScanSubQuery { output, .. }) + | MutRelational::Selection(Selection { output, .. }) + | MutRelational::Union(Union { output, .. }) + | MutRelational::UnionAll(UnionAll { output, .. }) + | MutRelational::Values(Values { output, .. }) + | MutRelational::ValuesRow(ValuesRow { output, .. }) => output, + } + } + + // Gets a mutable reference to the children nodes. + #[must_use] + pub fn mut_children(&mut self) -> MutChildren<'_> { + // return MutChildren { node: self }; + match self { + MutRelational::Limit(Limit { child, .. }) + | MutRelational::OrderBy(OrderBy { child, .. }) + | MutRelational::ScanCte(ScanCte { child, .. }) => MutChildren::Single(child), + MutRelational::Except(Except { left, right, .. }) + | MutRelational::Intersect(Intersect { left, right, .. }) + | MutRelational::UnionAll(UnionAll { left, right, .. }) + | MutRelational::Union(Union { left, right, .. }) => MutChildren::Couple(left, right), + MutRelational::GroupBy(GroupBy { + ref mut children, .. + }) + | MutRelational::Update(Update { + ref mut children, .. + }) + | MutRelational::Having(Having { + ref mut children, .. + }) + | MutRelational::Join(Join { + ref mut children, .. + }) + | MutRelational::Delete(Delete { + ref mut children, .. + }) + | MutRelational::Insert(Insert { + ref mut children, .. + }) + | MutRelational::Motion(Motion { + ref mut children, .. + }) + | MutRelational::Projection(Projection { + ref mut children, .. + }) + | MutRelational::ScanSubQuery(ScanSubQuery { + ref mut children, .. + }) + | MutRelational::Selection(Selection { + ref mut children, .. + }) + | MutRelational::ValuesRow(ValuesRow { + ref mut children, .. + }) + | MutRelational::Values(Values { + ref mut children, .. + }) => MutChildren::Many(children), + MutRelational::ScanRelation(_) => MutChildren::None, + } + } + + /// Sets new children to relational node. + /// + /// # Panics + /// - wrong number of children for the given node + pub fn set_children(&mut self, children: Vec<NodeId>) { + match self { + MutRelational::Join(Join { + children: ref mut old, + .. + }) + | MutRelational::Delete(Delete { + children: ref mut old, + .. + }) + | MutRelational::Update(Update { + children: ref mut old, + .. + }) + | MutRelational::Insert(Insert { + children: ref mut old, + .. + }) + | MutRelational::Motion(Motion { + children: ref mut old, + .. + }) + | MutRelational::Projection(Projection { + children: ref mut old, + .. + }) + | MutRelational::ScanSubQuery(ScanSubQuery { + children: ref mut old, + .. + }) + | MutRelational::Selection(Selection { + children: ref mut old, + .. + }) + | MutRelational::Values(Values { + children: ref mut old, + .. + }) + | MutRelational::GroupBy(GroupBy { + children: ref mut old, + .. + }) + | MutRelational::Having(Having { + children: ref mut old, + .. + }) + | MutRelational::ValuesRow(ValuesRow { + children: ref mut old, + .. + }) => { + *old = children; + } + MutRelational::Except(Except { left, right, .. }) + | MutRelational::UnionAll(UnionAll { left, right, .. }) + | MutRelational::Intersect(Intersect { left, right, .. }) + | MutRelational::Union(Union { left, right, .. }) => { + if children.len() != 2 { + unreachable!("Node has only two children!"); + } + *left = children[0]; + *right = children[1]; + } + MutRelational::OrderBy(OrderBy { ref mut child, .. }) => { + if children.len() != 1 { + unreachable!("ORDER BY may have only a single relational child"); + } + // It is safe to unwrap here, because the length is already checked above. + *child = children[0]; + } + MutRelational::ScanCte(ScanCte { ref mut child, .. }) => { + if children.len() != 1 { + unreachable!("CTE may have only a single relational child"); + } + // It is safe to unwrap here, because the length is already checked above. + *child = children[0]; + } + MutRelational::Limit(Limit { ref mut child, .. }) => { + if children.len() != 1 { + unreachable!("LIMIT may have only a single relational child"); + } + // It is safe to unwrap here, because the length is already checked above. + *child = children[0]; + } + MutRelational::ScanRelation(ScanRelation { .. }) => { + assert!(children.is_empty(), "scan must have no children!"); + } + } + } + + /// Sets new scan name to relational node. + /// + /// # Errors + /// - relational node is not a scan. + /// + /// # Panics + /// - CTE must have a name. + pub fn set_scan_name(&mut self, name: Option<SmolStr>) -> Result<(), SbroadError> { + match self { + MutRelational::ScanRelation(ScanRelation { ref mut alias, .. }) + | MutRelational::ScanSubQuery(ScanSubQuery { ref mut alias, .. }) => { + *alias = name; + Ok(()) + } + MutRelational::ScanCte(ScanCte { ref mut alias, .. }) => { + let name = name.expect("CTE must have a name"); + *alias = name; + Ok(()) + } + _ => Err(SbroadError::Invalid( + Entity::Relational, + Some("Relational node is not a Scan.".into()), + )), + } + } + + #[must_use] + pub fn get_rel_owned(&self) -> RelOwned { + match self { + MutRelational::Delete(del) => RelOwned::Delete((*del).clone()), + MutRelational::Except(except) => RelOwned::Except((*except).clone()), + MutRelational::GroupBy(group_by) => RelOwned::GroupBy((*group_by).clone()), + MutRelational::Having(having) => RelOwned::Having((*having).clone()), + MutRelational::Insert(insert) => RelOwned::Insert((*insert).clone()), + MutRelational::Intersect(intersect) => RelOwned::Intersect((*intersect).clone()), + MutRelational::Join(join) => RelOwned::Join((*join).clone()), + MutRelational::Limit(limit) => RelOwned::Limit((*limit).clone()), + MutRelational::Motion(motion) => RelOwned::Motion((*motion).clone()), + MutRelational::OrderBy(order_by) => RelOwned::OrderBy((*order_by).clone()), + MutRelational::Projection(proj) => RelOwned::Projection((*proj).clone()), + MutRelational::ScanCte(scan_cte) => RelOwned::ScanCte((*scan_cte).clone()), + MutRelational::ScanRelation(scan_rel) => RelOwned::ScanRelation((*scan_rel).clone()), + MutRelational::ScanSubQuery(ssubquery) => RelOwned::ScanSubQuery((*ssubquery).clone()), + MutRelational::Selection(sel) => RelOwned::Selection((*sel).clone()), + MutRelational::Union(un) => RelOwned::Union((*un).clone()), + MutRelational::UnionAll(union_all) => RelOwned::UnionAll((*union_all).clone()), + MutRelational::Update(upd) => RelOwned::Update((*upd).clone()), + MutRelational::Values(values) => RelOwned::Values((*values).clone()), + MutRelational::ValuesRow(values_row) => RelOwned::ValuesRow((*values_row).clone()), + } + } +} + +#[allow(dead_code)] +impl Relational<'_> { + /// Gets an immutable id of the output tuple node of the plan's arena. + #[must_use] + pub fn output(&self) -> NodeId { + match self { + Relational::ScanCte(ScanCte { output, .. }) + | Relational::Except(Except { output, .. }) + | Relational::GroupBy(GroupBy { output, .. }) + | Relational::OrderBy(OrderBy { output, .. }) + | Relational::Having(Having { output, .. }) + | Relational::Update(Update { output, .. }) + | Relational::Limit(Limit { output, .. }) + | Relational::Join(Join { output, .. }) + | Relational::Delete(Delete { output, .. }) + | Relational::Insert(Insert { output, .. }) + | Relational::Intersect(Intersect { output, .. }) + | Relational::Motion(Motion { output, .. }) + | Relational::Projection(Projection { output, .. }) + | Relational::ScanRelation(ScanRelation { output, .. }) + | Relational::ScanSubQuery(ScanSubQuery { output, .. }) + | Relational::Selection(Selection { output, .. }) + | Relational::Union(Union { output, .. }) + | Relational::UnionAll(UnionAll { output, .. }) + | Relational::Values(Values { output, .. }) + | Relational::ValuesRow(ValuesRow { output, .. }) => *output, + } + } + + // Gets an immutable reference to the children nodes. + #[must_use] + pub fn children(&self) -> Children<'_> { + match self { + Relational::Limit(Limit { child, .. }) + | Relational::OrderBy(OrderBy { child, .. }) + | Relational::ScanCte(ScanCte { child, .. }) => Children::Single(child), + Relational::Except(Except { left, right, .. }) + | Relational::Intersect(Intersect { left, right, .. }) + | Relational::UnionAll(UnionAll { left, right, .. }) + | Relational::Union(Union { left, right, .. }) => Children::Couple(left, right), + Relational::GroupBy(GroupBy { children, .. }) + | Relational::Update(Update { children, .. }) + | Relational::Join(Join { children, .. }) + | Relational::Having(Having { children, .. }) + | Relational::Delete(Delete { children, .. }) + | Relational::Insert(Insert { children, .. }) + | Relational::Motion(Motion { children, .. }) + | Relational::Projection(Projection { children, .. }) + | Relational::ScanSubQuery(ScanSubQuery { children, .. }) + | Relational::Selection(Selection { children, .. }) + | Relational::ValuesRow(ValuesRow { children, .. }) + | Relational::Values(Values { children, .. }) => Children::Many(children), + Relational::ScanRelation(_) => Children::None, + } + } + + /// Checks if the node is deletion. + #[must_use] + pub fn is_delete(&self) -> bool { + matches!(self, Relational::Delete { .. }) + } + /// Checks if the node is an insertion. + #[must_use] + pub fn is_insert(&self) -> bool { + matches!(self, Relational::Insert { .. }) + } + + /// Checks if the node is dml node + #[must_use] + pub fn is_dml(&self) -> bool { + matches!( + self, + Relational::Insert { .. } | Relational::Update { .. } | Relational::Delete { .. } + ) + } + + /// Checks that the node is a motion. + #[must_use] + pub fn is_motion(&self) -> bool { + matches!(self, &Relational::Motion { .. }) + } + + /// Checks that the node is a sub-query or CTE scan. + #[must_use] + pub fn is_subquery_or_cte(&self) -> bool { + matches!( + self, + &Relational::ScanSubQuery { .. } | &Relational::ScanCte { .. } + ) + } + + #[must_use] + pub fn name(&self) -> &str { + match self { + Relational::Except { .. } => "Except", + Relational::Delete { .. } => "Delete", + Relational::Insert { .. } => "Insert", + Relational::Intersect { .. } => "Intersect", + Relational::Update { .. } => "Update", + Relational::Join { .. } => "Join", + Relational::Limit { .. } => "Limit", + Relational::Motion { .. } => "Motion", + Relational::Projection { .. } => "Projection", + Relational::ScanCte { .. } => "CTE", + Relational::ScanRelation { .. } => "Scan", + Relational::ScanSubQuery { .. } => "Subquery", + Relational::Selection { .. } => "Selection", + Relational::GroupBy { .. } => "GroupBy", + Relational::OrderBy { .. } => "OrderBy", + Relational::Having { .. } => "Having", + Relational::Union { .. } => "Union", + Relational::UnionAll { .. } => "UnionAll", + Relational::Values { .. } => "Values", + Relational::ValuesRow { .. } => "ValuesRow", + } + } + + #[must_use] + pub fn get_rel_owned(&self) -> RelOwned { + match self { + Relational::Delete(del) => RelOwned::Delete((*del).clone()), + Relational::Except(except) => RelOwned::Except((*except).clone()), + Relational::GroupBy(group_by) => RelOwned::GroupBy((*group_by).clone()), + Relational::Having(having) => RelOwned::Having((*having).clone()), + Relational::Insert(insert) => RelOwned::Insert((*insert).clone()), + Relational::Intersect(intersect) => RelOwned::Intersect((*intersect).clone()), + Relational::Join(join) => RelOwned::Join((*join).clone()), + Relational::Limit(join) => RelOwned::Limit((*join).clone()), + Relational::Motion(motion) => RelOwned::Motion((*motion).clone()), + Relational::OrderBy(order_by) => RelOwned::OrderBy((*order_by).clone()), + Relational::Projection(proj) => RelOwned::Projection((*proj).clone()), + Relational::ScanCte(scan_cte) => RelOwned::ScanCte((*scan_cte).clone()), + Relational::ScanRelation(scan_rel) => RelOwned::ScanRelation((*scan_rel).clone()), + Relational::ScanSubQuery(ssubquery) => RelOwned::ScanSubQuery((*ssubquery).clone()), + Relational::Selection(sel) => RelOwned::Selection((*sel).clone()), + Relational::Union(un) => RelOwned::Union((*un).clone()), + Relational::UnionAll(union_all) => RelOwned::UnionAll((*union_all).clone()), + Relational::Update(upd) => RelOwned::Update((*upd).clone()), + Relational::Values(values) => RelOwned::Values((*values).clone()), + Relational::ValuesRow(values_row) => RelOwned::ValuesRow((*values_row).clone()), + } + } +} diff --git a/sbroad-core/src/ir/node/util.rs b/sbroad-core/src/ir/node/util.rs new file mode 100644 index 000000000..a97b82604 --- /dev/null +++ b/sbroad-core/src/ir/node/util.rs @@ -0,0 +1,14 @@ +use serde::Serialize; +use crate::ir::node::{Invalid as Inv, Parameter as Param}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum Invalid<'a> { + /// Procedure body. + Invalid(&'a Inv), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum Parameter<'a> { + /// Procedure body. + Parameter(&'a Param), +} \ No newline at end of file diff --git a/sbroad-core/src/ir/operator.rs b/sbroad-core/src/ir/operator.rs index 44728f3ed..ed65415f0 100644 --- a/sbroad-core/src/ir/operator.rs +++ b/sbroad-core/src/ir/operator.rs @@ -4,6 +4,14 @@ use crate::executor::engine::helpers::to_user; use crate::frontend::sql::get_unnamed_column_alias; +use crate::ir::api::children::Children; +use crate::ir::expression::PlanExpr; +use crate::ir::node::{ + Alias, Delete, Except, GroupBy, Having, Insert, Intersect, Join, Motion, MutNode, Node64, + NodeId, OrderBy, Projection, Reference, Row, ScanCte, ScanRelation, ScanSubQuery, Selection, + Union, UnionAll, Update, Values, ValuesRow, +}; +use crate::ir::Plan; use ahash::RandomState; use crate::collection; @@ -16,13 +24,13 @@ use std::fmt::{Display, Formatter}; use crate::errors::{Action, Entity, SbroadError}; -use super::api::children::{Children, MutChildren}; -use super::expression::{ColumnPositionMap, Expression, NodeId}; +use super::expression::{ColumnPositionMap, ExpressionId}; +use super::node::expression::{Expression, MutExpression}; +use super::node::relational::Relational; +use super::node::{ArenaType, Limit, Node, SizeNode}; use super::transformation::redistribution::{MotionPolicy, Program}; 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; use crate::ir::relation::{Column, ColumnRole}; use crate::ir::transformation::redistribution::{ColumnPosition, JoinChild}; @@ -312,605 +320,13 @@ pub struct OrderByElement { pub order_type: Option<OrderByType>, } -/// Relational algebra operator returning a new tuple. -/// -/// Transforms input tuple(s) into the output one using the -/// relation algebra logic. -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -pub enum Relational { - ScanCte { - /// CTE's name. - alias: SmolStr, - /// Contains exactly one single element (projection node index). - child: NodeId, - /// An output tuple with aliases. - output: NodeId, - }, - Except { - /// Left child id - left: NodeId, - /// Right child id - right: NodeId, - /// Outputs tuple node index in the plan node arena. - output: NodeId, - }, - Delete { - /// Relation name. - relation: SmolStr, - /// Contains exactly one single element. - children: Vec<NodeId>, - /// The output tuple (reserved for `delete returning`). - output: NodeId, - }, - Insert { - /// Relation name. - relation: SmolStr, - /// Target column positions for data insertion from - /// the child's tuple. - columns: Vec<usize>, - /// Contains exactly one single element. - children: Vec<NodeId>, - /// The output tuple (reserved for `insert returning`). - output: NodeId, - /// What to do in case there is a conflict during insert on storage - conflict_strategy: ConflictStrategy, - }, - Intersect { - left: NodeId, - right: NodeId, - // id of the output tuple - output: NodeId, - }, - Update { - /// Relation name. - relation: SmolStr, - /// Children ids. Update has exactly one child. - children: Vec<NodeId>, - /// Maps position of column being updated in table to corresponding position - /// in `Projection` below `Update`. - /// - /// For sharded `Update`, it will contain every table column except `bucket_id` - /// column. For local `Update` it will contain only update table columns. - update_columns_map: HashMap<ColumnPosition, ColumnPosition, RepeatableState>, - /// How this update must be executed. - strategy: UpdateStrategy, - /// Positions of primary columns in `Projection` - /// below `Update`. - pk_positions: Vec<ColumnPosition>, - /// Output id. - 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<NodeId>, - /// Left and right tuple comparison condition. - /// In fact it is an expression tree top index from the plan node arena. - condition: NodeId, - /// Outputs tuple node index from the plan node arena. - output: NodeId, - /// inner or left - kind: JoinKind, - }, - Motion { - // Scan name. - alias: Option<SmolStr>, - /// Contains exactly one single element: child node index - /// from the plan node arena. - 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: 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 - /// by that moment we've already erased `children` information using - /// `unlink_motion_subtree` function. - is_child_subquery: bool, - }, - Projection { - /// 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 output tree. - children: Vec<NodeId>, - /// Outputs tuple node index in the plan node arena. - output: NodeId, - /// Wheter the select was marked with `distinct` keyword - is_distinct: bool, - }, - ScanRelation { - // Scan name. - alias: Option<SmolStr>, - /// Outputs tuple node index in the plan node arena. - output: NodeId, - /// Relation name. - relation: SmolStr, - }, - ScanSubQuery { - /// SubQuery name. - alias: Option<SmolStr>, - /// Contains exactly one single element: child node index - /// from the plan node arena. - children: Vec<NodeId>, - /// Outputs tuple node index in the plan node arena. - 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<NodeId>, - /// Filters expression node index in the plan node arena. - filter: NodeId, - /// Outputs tuple node index in the plan node arena. - output: NodeId, - }, - GroupBy { - /// The first child is a relational operator before group by - children: Vec<NodeId>, - gr_cols: Vec<NodeId>, - output: NodeId, - is_final: bool, - }, - Having { - children: Vec<NodeId>, - output: NodeId, - filter: NodeId, - }, - OrderBy { - child: NodeId, - output: NodeId, - order_by_elements: Vec<OrderByElement>, - }, - UnionAll { - /// Left child id - left: NodeId, - /// Right child id - right: NodeId, - /// Outputs tuple node index in the plan node arena. - output: NodeId, - }, - Union { - /// Left child id - left: NodeId, - /// Right child id - right: NodeId, - /// Outputs tuple node index in the plan node arena. - output: NodeId, - }, - Values { - /// Output tuple. - output: NodeId, - /// Non-empty list of value rows. - children: Vec<NodeId>, - }, - ValuesRow { - /// Output tuple of aliases. - output: NodeId, - /// The data tuple. - 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<NodeId>, - }, - Limit { - /// Output tuple. - 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: NodeId, - }, -} - -#[allow(dead_code)] -impl Relational { - /// Gets an immutable id of the output tuple node of the plan's arena. - #[must_use] - pub fn output(&self) -> NodeId { - match self { - Relational::ScanCte { output, .. } - | Relational::Except { output, .. } - | Relational::GroupBy { output, .. } - | Relational::OrderBy { output, .. } - | Relational::Having { output, .. } - | Relational::Update { output, .. } - | Relational::Join { output, .. } - | Relational::Delete { output, .. } - | Relational::Insert { output, .. } - | Relational::Intersect { output, .. } - | Relational::Motion { output, .. } - | Relational::Projection { output, .. } - | Relational::ScanRelation { output, .. } - | Relational::ScanSubQuery { output, .. } - | Relational::Selection { output, .. } - | Relational::Union { output, .. } - | Relational::UnionAll { output, .. } - | Relational::Values { output, .. } - | Relational::ValuesRow { output, .. } - | Relational::Limit { output, .. } => *output, - } - } - - /// Gets an immutable reference to the output tuple node id. - #[must_use] - pub fn mut_output(&mut self) -> &mut NodeId { - match self { - Relational::ScanCte { output, .. } - | Relational::Except { output, .. } - | Relational::GroupBy { output, .. } - | Relational::OrderBy { output, .. } - | Relational::Update { output, .. } - | Relational::Having { output, .. } - | Relational::Join { output, .. } - | Relational::Delete { output, .. } - | Relational::Insert { output, .. } - | Relational::Intersect { output, .. } - | Relational::Motion { output, .. } - | Relational::Projection { output, .. } - | Relational::ScanRelation { output, .. } - | Relational::ScanSubQuery { output, .. } - | Relational::Selection { output, .. } - | Relational::Union { output, .. } - | Relational::UnionAll { output, .. } - | Relational::Values { output, .. } - | Relational::ValuesRow { output, .. } - | Relational::Limit { output, .. } => output, - } - } - - // Gets an immutable reference to the children nodes. - #[must_use] - pub fn children(&self) -> Children<'_> { - match self { - Relational::OrderBy { child, .. } - | Relational::ScanCte { child, .. } - | Relational::Limit { child, .. } => Children::Single(child), - Relational::Except { left, right, .. } - | Relational::Intersect { left, right, .. } - | Relational::UnionAll { left, right, .. } - | Relational::Union { left, right, .. } => Children::Couple(left, right), - Relational::GroupBy { children, .. } - | Relational::Update { children, .. } - | Relational::Join { children, .. } - | Relational::Having { children, .. } - | Relational::Delete { children, .. } - | Relational::Insert { children, .. } - | Relational::Motion { children, .. } - | Relational::Projection { children, .. } - | Relational::ScanSubQuery { children, .. } - | Relational::Selection { children, .. } - | Relational::ValuesRow { children, .. } - | Relational::Values { children, .. } => Children::Many(children), - Relational::ScanRelation { .. } => Children::None, - } - } - - // Gets a mutable reference to the children nodes. - #[must_use] - pub fn mut_children(&mut self) -> MutChildren<'_> { - // return MutChildren { node: self }; - match self { - Relational::OrderBy { child, .. } - | Relational::ScanCte { child, .. } - | Relational::Limit { child, .. } => MutChildren::Single(child), - Relational::Except { left, right, .. } - | Relational::Intersect { left, right, .. } - | Relational::UnionAll { left, right, .. } - | Relational::Union { left, right, .. } => MutChildren::Couple(left, right), - Relational::GroupBy { - ref mut children, .. - } - | Relational::Update { - ref mut children, .. - } - | Relational::Having { - ref mut children, .. - } - | Relational::Join { - ref mut children, .. - } - | Relational::Delete { - ref mut children, .. - } - | Relational::Insert { - ref mut children, .. - } - | Relational::Motion { - ref mut children, .. - } - | Relational::Projection { - ref mut children, .. - } - | Relational::ScanSubQuery { - ref mut children, .. - } - | Relational::Selection { - ref mut children, .. - } - | Relational::ValuesRow { - ref mut children, .. - } - | Relational::Values { - ref mut children, .. - } => MutChildren::Many(children), - Relational::ScanRelation { .. } => MutChildren::None, - } - } - - /// Checks if the node is deletion. - #[must_use] - pub fn is_delete(&self) -> bool { - matches!(self, Relational::Delete { .. }) - } - /// Checks if the node is an insertion. - #[must_use] - pub fn is_insert(&self) -> bool { - matches!(self, Relational::Insert { .. }) - } - - /// Checks if the node is dml node - #[must_use] - pub fn is_dml(&self) -> bool { - matches!( - self, - Relational::Insert { .. } | Relational::Update { .. } | Relational::Delete { .. } - ) - } - - /// Checks that the node is a motion. - #[must_use] - pub fn is_motion(&self) -> bool { - matches!(self, &Relational::Motion { .. }) - } - - /// Checks that the node is a sub-query or CTE scan. - #[must_use] - pub fn is_subquery_or_cte(&self) -> bool { - matches!( - self, - &Relational::ScanSubQuery { .. } | &Relational::ScanCte { .. } - ) - } - - /// Sets new children to relational node. - /// - /// # Panics - /// - wrong number of children for the given node - pub fn set_children(&mut self, children: Vec<NodeId>) { - match self { - Relational::Join { - children: ref mut old, - .. - } - | Relational::Delete { - children: ref mut old, - .. - } - | Relational::Update { - children: ref mut old, - .. - } - | Relational::Insert { - children: ref mut old, - .. - } - | Relational::Motion { - children: ref mut old, - .. - } - | Relational::Projection { - children: ref mut old, - .. - } - | Relational::ScanSubQuery { - children: ref mut old, - .. - } - | Relational::Selection { - children: ref mut old, - .. - } - | Relational::Values { - children: ref mut old, - .. - } - | Relational::GroupBy { - children: ref mut old, - .. - } - | Relational::Having { - children: ref mut old, - .. - } - | Relational::ValuesRow { - children: ref mut old, - .. - } => { - *old = children; - } - Relational::Except { left, right, .. } - | Relational::UnionAll { left, right, .. } - | Relational::Intersect { left, right, .. } - | Relational::Union { left, right, .. } => { - if children.len() != 2 { - unreachable!("Node has only two children!"); - } - *left = children[0]; - *right = children[1]; - } - Relational::OrderBy { ref mut child, .. } => { - if children.len() != 1 { - unreachable!("ORDER BY may have only a single relational child"); - } - // It is safe to unwrap here, because the length is already checked above. - *child = children[0]; - } - Relational::ScanCte { ref mut child, .. } => { - if children.len() != 1 { - unreachable!("CTE may have only a single relational child"); - } - // It is safe to unwrap here, because the length is already checked above. - *child = children[0]; - } - Relational::Limit { ref mut child, .. } => { - if children.len() != 1 { - unreachable!("LIMIT may have only a single relational child"); - } - // It is safe to unwrap here, because the length is already checked above. - *child = children[0]; - } - Relational::ScanRelation { .. } => { - assert!(children.is_empty(), "scan must have no children!"); - } - } - } - - /// Get relational Scan name that given `output_alias_position` (`Expression::Alias`) - /// references to. - /// - /// # Errors - /// - plan tree is invalid (failed to retrieve child nodes) - pub fn scan_name<'n>( - &'n self, - plan: &'n Plan, - output_alias_position: usize, - ) -> Result<Option<&'n str>, SbroadError> { - match self { - Relational::Insert { relation, .. } | Relational::Delete { relation, .. } => { - Ok(Some(relation.as_str())) - } - Relational::ScanRelation { - alias, relation, .. - } => Ok(alias.as_deref().or(Some(relation.as_str()))), - Relational::Projection { .. } - | Relational::GroupBy { .. } - | Relational::OrderBy { .. } - | Relational::Intersect { .. } - | Relational::Having { .. } - | Relational::Selection { .. } - | Relational::Update { .. } - | Relational::Join { .. } => { - let output_row = plan.get_expression_node(self.output())?; - let list = output_row.get_row_list()?; - let col_id = *list.get(output_alias_position).ok_or_else(|| { - SbroadError::NotFound( - Entity::Column, - format_smolstr!( - "at position {output_alias_position} of Row, {self:?}, {output_row:?}" - ), - ) - })?; - let col_node = plan.get_expression_node(col_id)?; - if let Expression::Alias { child, .. } = col_node { - let child_node = plan.get_expression_node(*child)?; - if let Expression::Reference { position: pos, .. } = child_node { - let rel_id = *plan.get_relational_from_reference_node(*child)?; - let rel_node = plan.get_relation_node(rel_id)?; - if rel_node == self { - return Err(SbroadError::DuplicatedValue(format_smolstr!( - "Reference to the same node {rel_node:?} at position {output_alias_position}" - ))); - } - return rel_node.scan_name(plan, *pos); - } - } else { - return Err(SbroadError::Invalid( - Entity::Expression, - Some("expected an alias in the output row".into()), - )); - } - Ok(None) - } - Relational::ScanCte { alias, .. } => Ok(Some(alias)), - Relational::ScanSubQuery { alias, .. } | Relational::Motion { alias, .. } => { - if let Some(name) = alias.as_ref() { - if !name.is_empty() { - return Ok(alias.as_deref()); - } - } - Ok(None) - } - Relational::Except { .. } - | Relational::Union { .. } - | Relational::UnionAll { .. } - | Relational::Values { .. } - | Relational::ValuesRow { .. } - | Relational::Limit { .. } => Ok(None), - } - } - - #[must_use] - pub fn name(&self) -> &str { - match self { - Relational::Except { .. } => "Except", - Relational::Delete { .. } => "Delete", - Relational::Insert { .. } => "Insert", - Relational::Intersect { .. } => "Intersect", - Relational::Update { .. } => "Update", - Relational::Join { .. } => "Join", - Relational::Motion { .. } => "Motion", - Relational::Projection { .. } => "Projection", - Relational::ScanCte { .. } => "CTE", - Relational::ScanRelation { .. } => "Scan", - Relational::ScanSubQuery { .. } => "Subquery", - Relational::Selection { .. } => "Selection", - Relational::GroupBy { .. } => "GroupBy", - Relational::OrderBy { .. } => "OrderBy", - Relational::Having { .. } => "Having", - Relational::Union { .. } => "Union", - Relational::UnionAll { .. } => "UnionAll", - Relational::Values { .. } => "Values", - Relational::ValuesRow { .. } => "ValuesRow", - Relational::Limit { .. } => "Limit", - } - } - - /// Sets new scan name to relational node. - /// - /// # Errors - /// - relational node is not a scan. - /// - /// # Panics - /// - CTE must have a name. - pub fn set_scan_name(&mut self, name: Option<SmolStr>) -> Result<(), SbroadError> { - match self { - Relational::ScanRelation { ref mut alias, .. } - | Relational::ScanSubQuery { ref mut alias, .. } => { - *alias = name; - Ok(()) - } - Relational::ScanCte { ref mut alias, .. } => { - let name = name.expect("CTE must have a name"); - *alias = name; - Ok(()) - } - _ => Err(SbroadError::Invalid( - Entity::Relational, - Some("Relational node is not a Scan.".into()), - )), - } - } -} - impl Plan { /// Add relational node to plan arena and update shard columns info. /// /// # Errors /// - failed to oupdate shard columns info due to invalid plan subtree - pub fn add_relational(&mut self, node: Relational) -> Result<NodeId, SbroadError> { - let rel_id = self.nodes.push(Node::Relational(node)); + pub fn add_relational(&mut self, node: SizeNode) -> Result<NodeId, SbroadError> { + let rel_id = self.nodes.push(node); let mut context = self.context_mut(); context.shard_col_info.update_node(rel_id, self)?; Ok(rel_id) @@ -922,12 +338,12 @@ impl Plan { /// - child id pointes to non-existing or non-relational node. 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 { + let delete = Delete { relation: table, children: vec![child_id], output, }; - let delete_id = self.add_relational(delete)?; + let delete_id = self.add_relational(delete.into())?; self.replace_parent_in_subtree(output, None, Some(delete_id))?; Ok(delete_id) } @@ -956,13 +372,13 @@ impl Plan { } let output = self.add_row_for_union_except(left, right)?; - let except = Relational::Except { + let except = Except { left, right, output, }; - let except_id = self.add_relational(except)?; + let except_id = self.add_relational(except.into())?; self.replace_parent_in_subtree(output, None, Some(except_id))?; Ok(except_id) } @@ -1056,7 +472,7 @@ impl Plan { ) })?; let col_type = col.r#type.clone(); - let node = Expression::Reference { + let node = Reference { // It will be updated using `replace_parent_in_subtree` // in the end of the function. parent: None, @@ -1064,7 +480,7 @@ impl Plan { position: output_pos, col_type, }; - let id = plan.nodes.push(Node::Expression(node)); + let id = plan.nodes.push(node.into()); Ok(id) } @@ -1201,22 +617,25 @@ impl Plan { // it is assumed that any projection column always has an alias. for (pos, expr_id) in projection_cols.iter_mut().enumerate() { let alias = get_unnamed_column_alias(pos); - let alias_id = self.nodes.push(Node::Expression(Expression::Alias { - child: *expr_id, - name: alias, - })); + let alias_id = self.nodes.push( + Alias { + child: *expr_id, + name: alias, + } + .into(), + ); *expr_id = alias_id; } let proj_output = self.nodes.add_row(projection_cols, None); - let proj_node = Relational::Projection { + let proj_node = Projection { children: vec![rel_child_id], output: proj_output, is_distinct: false, }; - let proj_id = self.add_relational(proj_node)?; + let proj_id = self.add_relational(proj_node.into())?; self.replace_parent_in_subtree(proj_output, None, Some(proj_id))?; let upd_output = self.add_row_for_output(proj_id, &[], false)?; - let update_node = Relational::Update { + let update_node = Update { relation: relation.to_smolstr(), pk_positions: primary_key_positions, children: vec![proj_id], @@ -1224,7 +643,7 @@ impl Plan { output: upd_output, strategy: update_kind, }; - let update_id = self.add_relational(update_node)?; + let update_id = self.add_relational(update_node.into())?; self.replace_parent_in_subtree(upd_output, None, Some(update_id))?; Ok(update_id) @@ -1280,7 +699,7 @@ impl Plan { }; let child_rel = self.get_relation_node(child)?; let child_output = self.get_expression_node(child_rel.output())?; - let child_output_list_len = if let Expression::Row { list, .. } = child_output { + let child_output_list_len = if let Expression::Row(Row { list, .. }) = child_output { list.len() } else { return Err(SbroadError::Invalid( @@ -1313,14 +732,14 @@ impl Plan { } }; let output = self.nodes.add_row(refs, Some(dist)); - let insert = Node::Relational(Relational::Insert { + let insert = Insert { relation: relation.into(), columns, children: vec![child], output, conflict_strategy, - }); - let insert_id = self.nodes.push(insert); + }; + let insert_id = self.nodes.push(insert.into()); self.replace_parent_in_subtree(output, None, Some(insert_id))?; Ok(insert_id) } @@ -1341,13 +760,13 @@ impl Plan { } let output_id = nodes.add_row(refs, None); - let scan = Relational::ScanRelation { + let scan = ScanRelation { output: output_id, relation: SmolStr::from(table), alias: alias.map(SmolStr::from), }; - let scan_id = self.add_relational(scan)?; + let scan_id = self.add_relational(scan.into())?; self.replace_parent_in_subtree(output_id, None, Some(scan_id))?; return Ok(scan_id); } @@ -1387,9 +806,9 @@ impl Plan { 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 { + if let Relational::ScanRelation(ScanRelation { relation, alias, .. - } = child_node + }) = child_node { // We'll need it later to update the condition expression (borrow checker). let table = self.get_relation_or_error(relation)?; @@ -1399,10 +818,7 @@ impl Plan { // Update references to the sub-query's output in the condition. let condition_nodes = { let filter = |id| -> bool { - matches!( - self.get_expression_node(id), - Ok(Expression::Reference { .. }) - ) + matches!(self.get_expression_node(id), Ok(Expression::Reference(_))) }; let mut condition_tree = PostOrderWithFilter::with_capacity( |node| self.nodes.expr_iter(node, false), @@ -1420,9 +836,9 @@ impl Plan { let mut refs = Vec::with_capacity(condition_nodes.len()); for LevelNode(_, id) in condition_nodes { let expr = self.get_expression_node(id)?; - if let Expression::Reference { + if let Expression::Reference(Reference { position, targets, .. - } = expr + }) = expr { if *targets == current_target { if Some(*position) == sharding_column_pos { @@ -1450,9 +866,9 @@ impl Plan { if let Some(sharding_column_pos) = sharding_column_pos { for ref_id in refs { let expr = self.get_mut_expression_node(ref_id)?; - if let Expression::Reference { + if let MutExpression::Reference(Reference { position, targets, .. - } = expr + }) = expr { if current_target == *targets && *position > sharding_column_pos { *position -= 1; @@ -1466,14 +882,14 @@ impl Plan { } if let (Some(left_id), Some(right_id)) = (children.first(), children.get(1)) { let output = self.add_row_for_join(*left_id, *right_id)?; - let join = Relational::Join { + let join = Join { children: vec![*left_id, *right_id], condition, output, kind, }; - let join_id = self.add_relational(join)?; + let join_id = self.add_relational(join.into())?; self.replace_parent_in_subtree(condition, None, Some(join_id))?; self.replace_parent_in_subtree(output, None, Some(join_id))?; return Ok(join_id); @@ -1495,8 +911,9 @@ impl Plan { policy: &MotionPolicy, program: Program, ) -> Result<NodeId, SbroadError> { - let alias = if let Node::Relational(rel) = self.get_node(child_id)? { - rel.scan_name(self, 0)?.map(SmolStr::from) + let rel_node = self.get_node(child_id)?; + let alias = if let Node::Relational(_) = rel_node { + self.scan_name(child_id, 0)?.map(SmolStr::from) } else { return Err(SbroadError::Invalid(Entity::Relational, None)); }; @@ -1527,9 +944,9 @@ impl Plan { } let child = self.get_relation_node(child_id)?; - let is_child_subquery = matches!(child, Relational::ScanSubQuery { .. }); + let is_child_subquery = matches!(child, Relational::ScanSubQuery(_)); - let motion = Relational::Motion { + let motion = Motion { alias, children: vec![child_id], policy: policy.clone(), @@ -1537,7 +954,7 @@ impl Plan { output, is_child_subquery, }; - let motion_id = self.add_relational(motion)?; + let motion_id = self.add_relational(motion.into())?; self.replace_parent_in_subtree(output, None, Some(motion_id))?; let mut context = self.context_mut(); context @@ -1563,13 +980,13 @@ impl Plan { needs_shard_col: bool, ) -> Result<NodeId, SbroadError> { let output = self.add_row_for_output(child, col_names, needs_shard_col)?; - let proj = Relational::Projection { + let proj = Projection { children: vec![child], output, is_distinct, }; - let proj_id = self.add_relational(proj)?; + let proj_id = self.add_relational(proj.into())?; self.replace_parent_in_subtree(output, None, Some(proj_id))?; Ok(proj_id) } @@ -1587,13 +1004,13 @@ impl Plan { is_distinct: bool, ) -> Result<NodeId, SbroadError> { let output = self.nodes.add_row(columns.to_vec(), None); - let proj = Relational::Projection { + let proj = Projection { children: vec![child], output, is_distinct, }; - let proj_id = self.add_relational(proj)?; + let proj_id = self.add_relational(proj.into())?; self.replace_parent_in_subtree(output, None, Some(proj_id))?; Ok(proj_id) } @@ -1625,13 +1042,13 @@ impl Plan { } let output = self.add_row_for_output(first_child, &[], true)?; - let select = Relational::Selection { + let select = Selection { children: children.into(), filter, output, }; - let select_id = self.add_relational(select)?; + let select_id = self.add_relational(select.into())?; self.replace_parent_in_subtree(filter, None, Some(select_id))?; self.replace_parent_in_subtree(output, None, Some(select_id))?; Ok(select_id) @@ -1673,13 +1090,13 @@ impl Plan { } let output = self.add_row_for_output(first_child, &[], true)?; - let having = Relational::Having { + let having = Having { children: children.into(), filter, output, }; - let having_id = self.add_relational(having)?; + let having_id = self.add_relational(having.into())?; self.replace_parent_in_subtree(filter, None, Some(having_id))?; self.replace_parent_in_subtree(output, None, Some(having_id))?; Ok(having_id) @@ -1699,13 +1116,13 @@ impl Plan { order_by_elements: Vec<OrderByElement>, ) -> Result<NodeId, SbroadError> { let output = self.add_row_for_output(child, &[], true)?; - let order_by = Relational::OrderBy { + let order_by = OrderBy { child, output, order_by_elements: order_by_elements.clone(), }; - let plan_order_by_id = self.add_relational(order_by)?; + let plan_order_by_id = self.add_relational(order_by.into())?; for order_by_element in order_by_elements { if let OrderByElement { entity: OrderByEntity::Expression { expr_id }, @@ -1733,13 +1150,13 @@ impl Plan { let name: Option<SmolStr> = alias.map(SmolStr::from); let output = self.add_row_for_output(child, &[], true)?; - let sq = Relational::ScanSubQuery { + let sq = ScanSubQuery { alias: name, children: vec![child], output, }; - let sq_id = self.add_relational(sq)?; + let sq_id = self.add_relational(sq.into())?; self.replace_parent_in_subtree(output, None, Some(sq_id))?; Ok(sq_id) } @@ -1795,7 +1212,7 @@ impl Plan { let col_alias = self .get_mut_expression_node(col_id) .expect("column expression"); - if let Expression::Alias { name, .. } = col_alias { + if let MutExpression::Alias(Alias { name, .. }) = col_alias { *name = col_name; } else { panic!("Expected a row of aliases in the output tuple"); @@ -1806,12 +1223,12 @@ impl Plan { let output = self .add_row_for_output(child_id, &[], true) .expect("output row for CTE"); - let cte = Relational::ScanCte { + let cte = ScanCte { alias, child: child_id, output, }; - let cte_id = self.add_relational(cte)?; + let cte_id = self.add_relational(cte.into())?; Ok(cte_id) } @@ -1844,18 +1261,20 @@ impl Plan { } let output = self.add_row_for_union_except(left, right)?; - let union_all = if remove_duplicates { - Relational::Union { + let union_all: SizeNode = if remove_duplicates { + Union { left, right, output, } + .into() } else { - Relational::UnionAll { + UnionAll { left, right, output, } + .into() }; let union_id = self.add_relational(union_all)?; @@ -1869,13 +1288,13 @@ impl Plan { /// - Row node is not of a row type 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 { + let limit = Limit { output, limit, child: select, }; - let limit_id = self.add_relational(limit)?; + let limit_id = self.add_relational(limit.into())?; self.replace_parent_in_subtree(output, None, Some(limit_id))?; Ok(limit_id) } @@ -1902,12 +1321,12 @@ impl Plan { } let output = self.nodes.add_row(aliases, None); - let values_row = Relational::ValuesRow { + let values_row = ValuesRow { output, data: row_id, children: vec![], }; - let values_row_id = self.add_relational(values_row)?; + let values_row_id = self.add_relational(values_row.into())?; self.replace_parent_in_subtree(row_id, None, Some(values_row_id))?; Ok(values_row_id) } @@ -1933,7 +1352,8 @@ impl Plan { )); }; let value_row_last = self.get_relation_node(last_id)?; - let last_output_id = if let Relational::ValuesRow { output, .. } = value_row_last { + let last_output_id = if let Relational::ValuesRow(ValuesRow { output, .. }) = value_row_last + { *output } else { return Err(SbroadError::UnexpectedNumberOfValues( @@ -1941,11 +1361,11 @@ impl Plan { )); }; let last_output = self.get_expression_node(last_output_id)?; - let names = if let Expression::Row { list, .. } = last_output { + let names = if let Expression::Row(Row { list, .. }) = last_output { let mut aliases: Vec<SmolStr> = Vec::with_capacity(list.len()); for alias_id in list { let alias = self.get_expression_node(*alias_id)?; - if let Expression::Alias { name, .. } = alias { + if let Expression::Alias(Alias { name, .. }) = alias { aliases.push(name.clone()); } else { return Err(SbroadError::Invalid( @@ -1983,11 +1403,11 @@ impl Plan { } let output = self.nodes.add_row(aliases, None); - let values = Relational::Values { + let values = Values { output, children: value_rows, }; - let values_id = self.add_relational(values)?; + let values_id = self.add_relational(values.into())?; self.replace_parent_in_subtree(output, None, Some(values_id))?; Ok(values_id) } @@ -2012,7 +1432,7 @@ impl Plan { /// - any node in the output tuple is not `Expression::Alias` 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)? { + if let Expression::Row(Row { list, .. }) = self.get_expression_node(output)? { return list .iter() .map(|alias_id| { @@ -2035,8 +1455,8 @@ impl Plan { /// # Errors /// - node is not relational 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()) + if let Node::Relational(_) = self.get_node(rel_id)? { + Ok(self.children(rel_id)) } else { Err(SbroadError::Invalid( Entity::Node, @@ -2067,7 +1487,7 @@ impl Plan { } Err(SbroadError::NotFound( Entity::Relational, - format_smolstr!("with id ({rel_id:?})"), + format_smolstr!("with id ({rel_id})"), )) } @@ -2086,7 +1506,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})" )), )) } @@ -2095,29 +1515,96 @@ 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: NodeId) -> Result<Option<NodeId>, SbroadError> { - for (id, node) in self.nodes.iter().enumerate() { - if !matches!(node, Node::Relational(_)) { + for (id, _) in self.nodes.arena32.iter().enumerate() { + let parent_id = NodeId { + offset: u32::try_from(id).unwrap(), + arena_type: ArenaType::Arena32, + }; + + if !matches!(self.get_node(parent_id)?, Node::Relational(_)) { + continue; + } + + for child_id in self.nodes.rel_iter(parent_id) { + if child_id == target_id { + return Ok(Some(parent_id)); + } + } + } + + for (id, _) in self.nodes.arena64.iter().enumerate() { + let parent_id = NodeId { + offset: u32::try_from(id).unwrap(), + arena_type: ArenaType::Arena64, + }; + + if !matches!(self.get_node(parent_id)?, Node::Relational(_)) { + continue; + } + + for child_id in self.nodes.rel_iter(parent_id) { + if child_id == target_id { + return Ok(Some(parent_id)); + } + } + } + + for (id, _) in self.nodes.arena96.iter().enumerate() { + let parent_id = NodeId { + offset: u32::try_from(id).unwrap(), + arena_type: ArenaType::Arena96, + }; + + if !matches!(self.get_node(parent_id)?, Node::Relational(_)) { + continue; + } + + for child_id in self.nodes.rel_iter(parent_id) { + if child_id == target_id { + return Ok(Some(parent_id)); + } + } + } + + for (id, _) in self.nodes.arena136.iter().enumerate() { + let parent_id = NodeId { + offset: u32::try_from(id).unwrap(), + arena_type: ArenaType::Arena136, + }; + + if !matches!(self.get_node(parent_id)?, Node::Relational(_)) { continue; } - let rel_id = NodeId { + for child_id in self.nodes.rel_iter(parent_id) { + if child_id == target_id { + return Ok(Some(parent_id)); + } + } + } + + for (id, _) in self.nodes.arena224.iter().enumerate() { + let parent_id = NodeId { offset: u32::try_from(id).unwrap(), - arena_type: ArenaType::Default, + arena_type: ArenaType::Arena224, }; - // 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 !matches!(self.get_node(parent_id)?, Node::Relational(_)) { + continue; + } + + for child_id in self.nodes.rel_iter(parent_id) { if child_id == target_id { - return Ok(Some(rel_id)); + return Ok(Some(parent_id)); } } } + Ok(None) } @@ -2132,7 +1619,7 @@ impl Plan { old_child_id: NodeId, new_child_id: NodeId, ) -> Result<(), SbroadError> { - let node = self.get_mut_relation_node(parent_id)?; + let mut node = self.get_mut_relation_node(parent_id)?; let children = node.mut_children(); for child_id in children { if *child_id == old_child_id { @@ -2187,13 +1674,88 @@ impl Plan { rel_id: NodeId, children: Vec<NodeId>, ) -> Result<(), SbroadError> { - if let Some(Node::Relational(ref mut rel)) = self.nodes.get_mut(rel_id) { + if let MutNode::Relational(ref mut rel) = self.get_mut_node(rel_id)? { rel.set_children(children); return Ok(()); } Err(SbroadError::Invalid(Entity::Relational, None)) } + /// Get relational Scan name that given `output_alias_position` (`Expression::Alias`) + /// references to. + /// + /// # Errors + /// - plan tree is invalid (failed to retrieve child nodes) + pub fn scan_name( + &self, + id: NodeId, + output_alias_position: usize, + ) -> Result<Option<&str>, SbroadError> { + let node = self.get_relation_node(id)?; + match node { + Relational::Insert(Insert { relation, .. }) + | Relational::Delete(Delete { relation, .. }) => Ok(Some(relation.as_str())), + Relational::ScanRelation(ScanRelation { + alias, relation, .. + }) => Ok(alias.as_deref().or(Some(relation.as_str()))), + Relational::Projection { .. } + | Relational::GroupBy { .. } + | Relational::OrderBy { .. } + | Relational::Intersect { .. } + | Relational::Having { .. } + | Relational::Selection { .. } + | Relational::Update { .. } + | Relational::Join { .. } => { + let output_row = self.get_expression_node(node.output())?; + let list = output_row.get_row_list()?; + let col_id = *list.get(output_alias_position).ok_or_else(|| { + SbroadError::NotFound( + Entity::Column, + format_smolstr!( + "at position {output_alias_position} of Row, {self:?}, {output_row:?}" + ), + ) + })?; + let col_node = self.get_expression_node(col_id)?; + if let Expression::Alias(Alias { child, .. }) = col_node { + let child_node = self.get_expression_node(*child)?; + if let Expression::Reference(Reference { position: pos, .. }) = child_node { + let rel_id = *self.get_relational_from_reference_node(*child)?; + let rel_node = self.get_relation_node(rel_id)?; + if rel_node == node { + return Err(SbroadError::DuplicatedValue(format_smolstr!( + "Reference to the same node {rel_node:?} at position {output_alias_position}" + ))); + } + return self.scan_name(rel_id, *pos); + } + } else { + return Err(SbroadError::Invalid( + Entity::Expression, + Some("expected an alias in the output row".into()), + )); + } + Ok(None) + } + Relational::ScanCte(ScanCte { alias, .. }) => Ok(Some(alias)), + Relational::ScanSubQuery(ScanSubQuery { alias, .. }) + | Relational::Motion(Motion { alias, .. }) => { + if let Some(name) = alias.as_ref() { + if !name.is_empty() { + return Ok(alias.as_deref()); + } + } + Ok(None) + } + Relational::Except { .. } + | Relational::Union { .. } + | Relational::UnionAll { .. } + | Relational::Values { .. } + | Relational::Limit { .. } + | Relational::ValuesRow { .. } => Ok(None), + } + } + /// Checks if the node is an additional child of some relational node. /// We can use a simple node scan instead of the tree traversal as we are interested /// only in relational nodes that can't be unlinked from the tree by our transformations. @@ -2203,16 +1765,15 @@ impl Plan { /// - Failed to get plan top /// - Node returned by the relational iterator is not relational (bug) pub fn is_additional_child(&self, node_id: NodeId) -> Result<bool, SbroadError> { - for node in &self.nodes { + for node in &self.nodes.arena64 { match node { - Node::Relational( - Relational::Selection { children, .. } | Relational::Having { children, .. }, - ) => { + Node64::Selection(Selection { children, .. }) + | Node64::Having(Having { children, .. }) => { if children.iter().skip(1).any(|&c| c == node_id) { return Ok(true); } } - Node::Relational(Relational::Join { children, .. }) => { + Node64::Join(Join { children, .. }) => { if children.iter().skip(2).any(|&c| c == node_id) { return Ok(true); } @@ -2250,7 +1811,7 @@ impl Plan { /// - node is not motion 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 { + if let Relational::Motion(Motion { policy, .. }) = node { return Ok(policy); } Err(SbroadError::Invalid( @@ -2258,6 +1819,35 @@ impl Plan { Some(format_smolstr!("expected Motion, got: {node:?}")), )) } + + // Gets an immutable reference to the children nodes. + /// # Panics + #[must_use] + pub fn children(&self, rel_id: NodeId) -> Children<'_> { + let node = self.get_relation_node(rel_id).unwrap(); + match node { + Relational::Limit(Limit { child, .. }) + | Relational::OrderBy(OrderBy { child, .. }) + | Relational::ScanCte(ScanCte { child, .. }) => Children::Single(child), + Relational::Except(Except { left, right, .. }) + | Relational::Intersect(Intersect { left, right, .. }) + | Relational::UnionAll(UnionAll { left, right, .. }) + | Relational::Union(Union { left, right, .. }) => Children::Couple(left, right), + Relational::GroupBy(GroupBy { children, .. }) + | Relational::Update(Update { children, .. }) + | Relational::Join(Join { children, .. }) + | Relational::Having(Having { children, .. }) + | Relational::Delete(Delete { children, .. }) + | Relational::Insert(Insert { children, .. }) + | Relational::Motion(Motion { children, .. }) + | Relational::Projection(Projection { children, .. }) + | Relational::ScanSubQuery(ScanSubQuery { children, .. }) + | Relational::Selection(Selection { children, .. }) + | Relational::ValuesRow(ValuesRow { children, .. }) + | Relational::Values(Values { children, .. }) => Children::Many(children), + Relational::ScanRelation(_) => Children::None, + } + } } #[cfg(test)] diff --git a/sbroad-core/src/ir/operator/tests.rs b/sbroad-core/src/ir/operator/tests.rs index 6bc322422..f3a2f6859 100644 --- a/sbroad-core/src/ir/operator/tests.rs +++ b/sbroad-core/src/ir/operator/tests.rs @@ -7,7 +7,7 @@ use crate::ir::expression::ColumnWithScan; use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type}; use crate::ir::tests::{column_user_non_null, sharding_column}; use crate::ir::value::Value; -use crate::ir::{Node, Plan}; +use crate::ir::Plan; use super::*; @@ -31,12 +31,12 @@ fn scan_rel() { plan.add_rel(t); let scan_output = NodeId { - offset: 8, - arena_type: ArenaType::Default, + offset: 4, + arena_type: ArenaType::Arena64, }; let scan_node = NodeId { - offset: 9, - arena_type: ArenaType::Default, + offset: 5, + arena_type: ArenaType::Arena64, }; let scan_id = plan.add_scan("t", None).unwrap(); @@ -44,10 +44,11 @@ fn scan_rel() { plan.top = Some(scan_node); plan.set_distribution(scan_output).unwrap(); - if let Node::Expression(row) = plan.get_node(scan_output).unwrap() { + let row = plan.get_node(scan_output).unwrap(); + if let Node::Expression(expr) = row { let keys: HashSet<_, RepeatableState> = collection! { Key::new(vec![1, 0]) }; assert_eq!( - row.distribution().unwrap(), + expr.distribution().unwrap(), &Distribution::Segment { keys: keys.into() } ); } else { @@ -84,15 +85,17 @@ fn projection() { ); let mut test_node = NodeId { - offset: 1, - arena_type: ArenaType::Default, + offset: 0, + arena_type: ArenaType::Arena32, }; // Expression node instead of relational one assert_eq!( SbroadError::Invalid( Entity::Node, - Some("node is not Relational type: Expression(Alias { name: \"a\", child: NodeId { offset: 0, arena_type: Default } })".into()) + Some( + "node is not Relational type: Expression(Alias(Alias { name: \"a\", child: NodeId { offset: 0, arena_type: Arena64 } }))".into() + ) ), plan.add_proj(test_node, &["a"], false, false).unwrap_err() ); @@ -101,10 +104,7 @@ fn projection() { // Try to build projection from the non-existing node assert_eq!( - SbroadError::NotFound( - Entity::Node, - "from Default arena with index 42".to_smolstr() - ), + SbroadError::NotFound(Entity::Node, "from Arena32 with index 42".to_smolstr()), plan.add_proj(test_node, &["a"], false, false).unwrap_err() ); } @@ -368,13 +368,13 @@ fn sub_query() { // Non-relational child node let a = NodeId { - offset: 1, - arena_type: ArenaType::Default, + offset: 0, + arena_type: ArenaType::Arena32, }; assert_eq!( SbroadError::Invalid( Entity::Node, - Some("node is not Relational type: Expression(Alias { name: \"a\", child: NodeId { offset: 0, arena_type: Default } })".into()) + Some("node is not Relational type: Expression(Alias(Alias { name: \"a\", child: NodeId { offset: 0, arena_type: Arena64 } }))".into()) ), plan.add_sub_query(a, Some("sq")).unwrap_err() ); diff --git a/sbroad-core/src/ir/parameters.rs b/sbroad-core/src/ir/parameters.rs index eb5e001fc..d1f5da754 100644 --- a/sbroad-core/src/ir/parameters.rs +++ b/sbroad-core/src/ir/parameters.rs @@ -3,12 +3,10 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use crate::ir::Node; - -use super::expression::NodeId; +use crate::ir::node::{Node64, NodeId}; #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct Parameters(HashMap<NodeId, Node>); +pub struct Parameters(HashMap<NodeId, Node64>); impl Default for Parameters { fn default() -> Self { @@ -22,16 +20,16 @@ impl Parameters { Self(HashMap::new()) } - pub fn insert(&mut self, index: NodeId, node: Node) { + pub fn insert(&mut self, index: NodeId, node: Node64) { self.0.insert(index, node); } #[must_use] - pub fn get(&self, index: NodeId) -> Option<&Node> { + pub fn get(&self, index: NodeId) -> Option<&Node64> { self.0.get(&index) } - pub fn drain(&mut self) -> HashMap<NodeId, Node> { + pub fn drain(&mut self) -> HashMap<NodeId, Node64> { std::mem::take(&mut self.0) } } diff --git a/sbroad-core/src/ir/tests.rs b/sbroad-core/src/ir/tests.rs index b807ac665..15166202d 100644 --- a/sbroad-core/src/ir/tests.rs +++ b/sbroad-core/src/ir/tests.rs @@ -67,7 +67,7 @@ fn get_node() { let scan_id = plan.add_scan("t", None).unwrap(); - if let Node::Relational(Relational::ScanRelation { relation, .. }) = + if let Node::Relational(Relational::ScanRelation(ScanRelation { relation, .. })) = plan.get_node(scan_id).unwrap() { assert_eq!(relation, "t"); @@ -80,10 +80,10 @@ fn get_node() { fn get_node_oor() { let plan = Plan::default(); assert_eq!( - SbroadError::NotFound(Entity::Node, "from Default arena with index 42".into()), + SbroadError::NotFound(Entity::Node, "from Arena32 with index 42".into()), plan.get_node(NodeId { offset: 42, - arena_type: ArenaType::Default + arena_type: ArenaType::Arena32 }) .unwrap_err() ); diff --git a/sbroad-core/src/ir/transformation.rs b/sbroad-core/src/ir/transformation.rs index b7779f0e2..cf7e9142b 100644 --- a/sbroad-core/src/ir/transformation.rs +++ b/sbroad-core/src/ir/transformation.rs @@ -12,11 +12,15 @@ pub mod split_columns; use smol_str::format_smolstr; -use super::expression::NodeId; +use super::node::expression::{Expression, MutExpression}; +use super::node::relational::{MutRelational, Relational}; use super::tree::traversal::{PostOrder, PostOrderWithFilter, EXPR_CAPACITY}; use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::Expression; -use crate::ir::operator::{Bool, Relational}; +use crate::ir::node::{ + Alias, ArithmeticExpr, BoolExpr, Case, Cast, ExprInParentheses, Join, NodeId, Row, Selection, + StableFunction, Trim, UnaryExpr, +}; +use crate::ir::operator::Bool; use crate::ir::{Node, Plan}; use std::collections::HashMap; @@ -142,12 +146,12 @@ impl Plan { let id = level_node.1; let rel = self.get_relation_node(id)?; let (old_tree_id, new_tree_id) = match rel { - Relational::Selection { + Relational::Selection(Selection { filter: tree_id, .. - } - | Relational::Join { + }) + | Relational::Join(Join { condition: tree_id, .. - } => f(self, *tree_id)?, + }) => f(self, *tree_id)?, _ => continue, }; if old_tree_id != new_tree_id { @@ -155,12 +159,12 @@ impl Plan { } let rel = self.get_mut_relation_node(id)?; match rel { - Relational::Selection { + MutRelational::Selection(Selection { filter: tree_id, .. - } - | Relational::Join { + }) + | MutRelational::Join(Join { condition: tree_id, .. - } => { + }) => { *tree_id = new_tree_id; } _ => continue, @@ -187,15 +191,15 @@ impl Plan { // * That will contain transformed nodes as children let filter = |node_id: NodeId| -> bool { if let Ok(Node::Expression( - Expression::Bool { .. } - | Expression::ExprInParentheses { .. } - | Expression::Arithmetic { .. } - | Expression::Alias { .. } - | Expression::Row { .. } - | Expression::Cast { .. } - | Expression::Case { .. } - | Expression::StableFunction { .. } - | Expression::Unary { .. }, + Expression::Bool(_) + | Expression::ExprInParentheses(_) + | Expression::Arithmetic(_) + | Expression::Alias(_) + | Expression::Row(_) + | Expression::Cast(_) + | Expression::Case(_) + | Expression::StableFunction(_) + | Expression::Unary(_), )) = self.get_node(node_id) { return true; @@ -213,7 +217,7 @@ impl Plan { for level_node in &nodes { let id = level_node.1; let expr = self.get_expression_node(id)?; - if let Expression::Bool { op, .. } = expr { + if let Expression::Bool(BoolExpr { op, .. }) = expr { if ops.contains(op) || ops.is_empty() { let (old_top_id, new_top_id) = f(self, id)?; if old_top_id != new_top_id { @@ -240,17 +244,17 @@ impl Plan { // XXX: If you add a new expression type to the match, make sure to // add it to the filter above. match expr { - Expression::Alias { child, .. } - | Expression::ExprInParentheses { child, .. } - | Expression::Cast { child, .. } - | Expression::Unary { child, .. } => { + MutExpression::Alias(Alias { child, .. }) + | MutExpression::ExprInParentheses(ExprInParentheses { child, .. }) + | MutExpression::Cast(Cast { child, .. }) + | MutExpression::Unary(UnaryExpr { child, .. }) => { map.replace(child); } - Expression::Case { + MutExpression::Case(Case { search_expr, when_blocks, else_expr, - } => { + }) => { if let Some(search_expr) = search_expr { map.replace(search_expr); } @@ -262,29 +266,29 @@ impl Plan { map.replace(else_expr); } } - Expression::Bool { left, right, .. } - | Expression::Arithmetic { left, right, .. } => { + MutExpression::Bool(BoolExpr { left, right, .. }) + | MutExpression::Arithmetic(ArithmeticExpr { left, right, .. }) => { map.replace(left); map.replace(right); } - Expression::Trim { + MutExpression::Trim(Trim { pattern, target, .. - } => { + }) => { if let Some(pattern) = pattern { map.replace(pattern); } map.replace(target); } - Expression::Row { list, .. } - | Expression::StableFunction { children: list, .. } => { + MutExpression::Row(Row { list, .. }) + | MutExpression::StableFunction(StableFunction { children: list, .. }) => { for id in list { map.replace(id); } } - Expression::Concat { .. } - | Expression::Constant { .. } - | Expression::Reference { .. } - | Expression::CountAsterisk => {} + MutExpression::Concat(_) + | MutExpression::Constant(_) + | MutExpression::Reference(_) + | MutExpression::CountAsterisk(_) => {} } } // Checks if the top node is a new node. diff --git a/sbroad-core/src/ir/transformation/bool_in.rs b/sbroad-core/src/ir/transformation/bool_in.rs index be1bb8c5b..9fa275082 100644 --- a/sbroad-core/src/ir/transformation/bool_in.rs +++ b/sbroad-core/src/ir/transformation/bool_in.rs @@ -11,7 +11,8 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::{Expression, NodeId}; +use crate::ir::node::expression::Expression; +use crate::ir::node::{BoolExpr, NodeId}; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; use crate::ir::Plan; @@ -36,12 +37,12 @@ impl Plan { 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 { + Expression::Bool(BoolExpr { left, op: Bool::In, right, .. - } => (*left, *right), + }) => (*left, *right), _ => { return Err(SbroadError::Invalid( Entity::Expression, diff --git a/sbroad-core/src/ir/transformation/dnf.rs b/sbroad-core/src/ir/transformation/dnf.rs index 0cc77cedd..0e4944b9b 100644 --- a/sbroad-core/src/ir/transformation/dnf.rs +++ b/sbroad-core/src/ir/transformation/dnf.rs @@ -71,10 +71,11 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::{Expression, NodeId}; +use crate::ir::node::expression::Expression; +use crate::ir::node::{BoolExpr, ExprInParentheses, Node32, NodeId}; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; -use crate::ir::{Node, Plan}; +use crate::ir::Plan; use crate::otm::child_span; use sbroad_proc::otm_child_span; use std::collections::VecDeque; @@ -90,14 +91,16 @@ pub struct Chain { 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, .. } => { + Expression::Bool(BoolExpr { op, .. }) => { if matches!(op, Bool::And) || matches!(op, Bool::Or) { Some(expr_id) } else { None } } - Expression::ExprInParentheses { child } => optionally_covered_and_or(*child, plan)?, + Expression::ExprInParentheses(ExprInParentheses { child }) => { + optionally_covered_and_or(*child, plan)? + } _ => None, }; Ok(and_or) @@ -134,10 +137,10 @@ impl Chain { 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 { + if let Expression::Bool(BoolExpr { op: Bool::And | Bool::Or, .. - } = expr + }) = expr { return Ok(self.nodes.pop_back()); } @@ -186,9 +189,9 @@ impl Plan { /// - 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: NodeId) -> Result<VecDeque<Chain>, SbroadError> { - let capacity: usize = self.nodes.arena.iter().fold(0_usize, |acc, node| { + let capacity: usize = self.nodes.arena32.iter().fold(0_usize, |acc, node| { acc + match node { - Node::Expression(Expression::Bool { + Node32::Bool(BoolExpr { op: Bool::And | Bool::Or, .. }) => 1, @@ -208,9 +211,9 @@ impl Plan { continue; }; let expr = self.get_expression_node(expr_id)?; - if let Expression::Bool { + if let Expression::Bool(BoolExpr { op, left, right, .. - } = expr + }) = expr { match *op { Bool::And => { diff --git a/sbroad-core/src/ir/transformation/equality_propagation.rs b/sbroad-core/src/ir/transformation/equality_propagation.rs index dc7132d93..b4917ad65 100644 --- a/sbroad-core/src/ir/transformation/equality_propagation.rs +++ b/sbroad-core/src/ir/transformation/equality_propagation.rs @@ -90,8 +90,9 @@ //! to the plan tree. use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::{Expression, NodeId}; use crate::ir::helpers::RepeatableState; +use crate::ir::node::expression::Expression; +use crate::ir::node::{Constant, NodeId, Reference, Row}; use crate::ir::operator::Bool; use crate::ir::relation::Type; use crate::ir::transformation::merge_tuples::Chain; @@ -115,12 +116,12 @@ struct EqClassRef { impl EqClassRef { fn from_ref(expr: &Expression) -> Result<Self, SbroadError> { - if let Expression::Reference { + if let Expression::Reference(Reference { targets: expr_tgt, position: expr_pos, parent: expr_prt, col_type: expr_type, - } = expr + }) = expr { return Ok(EqClassRef { targets: expr_tgt.clone(), @@ -157,7 +158,7 @@ impl Eq for EqClassConst {} impl EqClassConst { fn from_const(expr: &Expression) -> Result<Self, SbroadError> { - if let Expression::Constant { value: expr_value } = expr { + if let Expression::Constant(Constant { value: expr_value }) = expr { return Ok(EqClassConst { value: expr_value.clone(), }); @@ -251,7 +252,7 @@ impl EqClassChain { // If one of the sides doesn't satisfy self equivalence, produce // a new equality class. for class in &mut self.list { - if (class.set.get(left).is_some() || class.set.get(right).is_some()) + if (class.set.contains(left) || class.set.contains(right)) && left.is_self_equivalent() && right.is_self_equivalent() { @@ -281,14 +282,14 @@ impl EqClassChain { /// as `NULL != NULL` (the result is "NULL" itself). fn merge(&self) -> Self { let mut result = EqClassChain::new(); - result.pairs = self.pairs.clone(); + result.pairs.clone_from(&self.pairs); // A set of indexes of the equality classes in the chain // that contain common elements and should not be reinspected. let mut matched: HashSet<usize> = HashSet::new(); for i in 0..self.list.len() { - if matched.get(&i).is_some() { + if matched.contains(&i) { continue; } @@ -297,7 +298,7 @@ impl EqClassChain { matched.insert(i); for j in i..self.list.len() { - if matched.get(&j).is_some() { + if matched.contains(&j) { continue; } @@ -333,7 +334,7 @@ impl EqClassChain { fn subtract_pairs(&self) -> Self { let mut result = EqClassChain::new(); - result.pairs = self.pairs.clone(); + result.pairs.clone_from(&self.pairs); for class in &self.list { let ec_ref = class.ref_copy(); @@ -484,13 +485,11 @@ impl Plan { 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 { .. } => { - Ok(EqClassExpr::EqClassConst(EqClassConst::from_const(expr)?)) + Expression::Constant(_) => { + Ok(EqClassExpr::EqClassConst(EqClassConst::from_const(&expr)?)) } - Expression::Reference { .. } => { - Ok(EqClassExpr::EqClassRef(EqClassRef::from_ref(expr)?)) - } - Expression::Row { list, .. } => { + Expression::Reference(_) => Ok(EqClassExpr::EqClassRef(EqClassRef::from_ref(&expr)?)), + Expression::Row(Row { list, .. }) => { if let (Some(col_id), None) = (list.first(), list.get(1)) { self.try_to_eq_class_expr(*col_id) } else { diff --git a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs index 83f6bfa30..696ce4b30 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"."a") = ("t"."c") or ("t"."d") = (?)"#, + r#"and ("t"."c") = ("t"."a") or ("t"."d") = (?)"#, ), vec![ Value::from(1_u64), @@ -80,7 +80,7 @@ fn equality_propagation4() { "{} {} {}", r#"SELECT "t"."a" FROM "t""#, r#"WHERE ("t"."b") = (?) and ("t"."a") = (?) and ("t"."a") = (?)"#, - r#"and ("t"."b") = (?) and ("t"."a") = ("t"."b")"#, + r#"and ("t"."b") = (?) and ("t"."b") = ("t"."a")"#, ), 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"."a") = ("t"."b") and ("t"."b") = ("t"."c")"#, - r#"and ("t"."c") = ("t"."d")"#, + r#"and ("t"."b") = ("t"."c") and ("t"."c") = ("t"."d")"#, + r#"and ("t"."d") = ("t"."a")"#, ), 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 30f76a9de..2aa1bf30a 100644 --- a/sbroad-core/src/ir/transformation/merge_tuples.rs +++ b/sbroad-core/src/ir/transformation/merge_tuples.rs @@ -11,8 +11,9 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::{Expression, NodeId}; use crate::ir::helpers::RepeatableState; +use crate::ir::node::expression::{Expression, MutExpression}; +use crate::ir::node::{Alias, ArithmeticExpr, BoolExpr, NodeId, Row}; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; use crate::ir::tree::traversal::BreadthFirst; @@ -69,7 +70,7 @@ impl Chain { /// - There is something wrong with our sub-queries. 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 Expression::Bool(BoolExpr { left, op, right }) = bool_expr { if let Bool::And | Bool::Or = op { // We don't expect nested AND/OR expressions in DNF. return Err(SbroadError::Unsupported( @@ -89,12 +90,12 @@ impl Chain { _ => (*left, *right, op.clone()), }; - if let Ok(Expression::Arithmetic { .. }) = plan.get_expression_node(left_id) { + if let Ok(Expression::Arithmetic(_)) = plan.get_expression_node(left_id) { self.other.push(expr_id); return Ok(()); } - if let Ok(Expression::Arithmetic { .. }) = plan.get_expression_node(right_id) { + if let Ok(Expression::Arithmetic(_)) = plan.get_expression_node(right_id) { self.other.push(expr_id); return Ok(()); } @@ -208,7 +209,7 @@ impl Plan { 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()), + Expression::Row(Row { list, .. }) => Ok(list.clone()), _ => Ok(vec![expr_id]), } } @@ -242,21 +243,21 @@ impl Plan { 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 { + if let Expression::Bool(BoolExpr { left, op: Bool::And, right, .. - } = expr + }) = expr { let children = vec![*left, *right]; for child_id in children { visited.insert(child_id); let child_expr = self.get_expression_node(child_id)?; - if let Expression::Bool { + if let Expression::Bool(BoolExpr { op: Bool::And | Bool::Or, .. - } = child_expr + }) = child_expr { continue; } @@ -306,15 +307,15 @@ impl Plan { for id in nodes { let expr = self.get_expression_node(id)?; match expr { - Expression::Alias { child, .. } => { + Expression::Alias(Alias { child, .. }) => { let chain = chains.get(child); if let Some(chain) = chain { let new_child_id = f_to_plan(chain, self)?; let expr_mut = self.get_mut_expression_node(id)?; - if let Expression::Alias { + if let MutExpression::Alias(Alias { child: ref mut child_id, .. - } = expr_mut + }) = expr_mut { *child_id = new_child_id; } else { @@ -325,18 +326,18 @@ impl Plan { } } } - Expression::Bool { left, right, .. } => { + Expression::Bool(BoolExpr { left, right, .. }) => { let children = [*left, *right]; for (pos, child) in children.iter().enumerate() { let chain = chains.get(child); if let Some(chain) = chain { let new_child_id = f_to_plan(chain, self)?; let expr_mut = self.get_mut_expression_node(id)?; - if let Expression::Bool { + if let MutExpression::Bool(BoolExpr { left: ref mut left_id, right: ref mut right_id, .. - } = expr_mut + }) = expr_mut { if pos == 0 { *left_id = new_child_id; @@ -354,18 +355,18 @@ impl Plan { } } } - Expression::Arithmetic { left, right, .. } => { + Expression::Arithmetic(ArithmeticExpr { left, right, .. }) => { let children = [*left, *right]; for (pos, child) in children.iter().enumerate() { let chain = chains.get(child); if let Some(chain) = chain { let new_child_id = f_to_plan(chain, self)?; let expr_mut = self.get_mut_expression_node(id)?; - if let Expression::Arithmetic { + if let MutExpression::Arithmetic(ArithmeticExpr { left: ref mut left_id, right: ref mut right_id, .. - } = expr_mut + }) = expr_mut { if pos == 0 { *left_id = new_child_id; @@ -383,14 +384,14 @@ impl Plan { } } } - Expression::Row { list, .. } => { + Expression::Row(Row { list, .. }) => { let children = list.clone(); for (pos, child) in children.iter().enumerate() { let chain = chains.get(child); if let Some(chain) = chain { let new_child_id = f_to_plan(chain, self)?; let expr_mut = self.get_mut_expression_node(id)?; - if let Expression::Row { ref mut list, .. } = expr_mut { + if let MutExpression::Row(Row { ref mut list, .. }) = expr_mut { if let Some(child_id) = list.get_mut(pos) { *child_id = new_child_id; } else { diff --git a/sbroad-core/src/ir/transformation/not_push_down.rs b/sbroad-core/src/ir/transformation/not_push_down.rs index 06a672118..04ae44833 100644 --- a/sbroad-core/src/ir/transformation/not_push_down.rs +++ b/sbroad-core/src/ir/transformation/not_push_down.rs @@ -5,7 +5,8 @@ //! * To: `select * from "t" where "a" = 1 and "b" = 2` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::{Expression, NodeId}; +use crate::ir::node::expression::{Expression, MutExpression}; +use crate::ir::node::{BoolExpr, Constant, ExprInParentheses, NodeId, Row, UnaryExpr}; use crate::ir::operator::{Bool, Unary}; use crate::ir::transformation::{OldNewExpressionMap, OldNewTopIdPair}; use crate::ir::tree::traversal::{PostOrderWithFilter, EXPR_CAPACITY}; @@ -55,7 +56,6 @@ fn call_expr_tree_not_push_down( let mut old_new_expression_map = OldNewExpressionMap::new(); let new_top_id = plan.push_down_not_for_expression(top_id, NotState::Off, &mut old_new_expression_map)?; - let (old_top_id, new_top_id) = if new_top_id == top_id && old_new_expression_map.is_empty() { (top_id, top_id) } else { @@ -64,9 +64,7 @@ fn call_expr_tree_not_push_down( matches!( plan.get_node(node_id), Ok(Node::Expression( - Expression::ExprInParentheses { .. } - | Expression::Bool { .. } - | Expression::Row { .. } + Expression::ExprInParentheses(_) | Expression::Bool(_) | Expression::Row(_) )) ) }; @@ -82,14 +80,14 @@ fn call_expr_tree_not_push_down( let id = level_node.1; let expr = plan.get_mut_expression_node(id)?; match expr { - Expression::ExprInParentheses { child } => { + MutExpression::ExprInParentheses(ExprInParentheses { child }) => { old_new_expression_map.replace(child); } - Expression::Bool { left, right, .. } => { + MutExpression::Bool(BoolExpr { left, right, .. }) => { old_new_expression_map.replace(left); old_new_expression_map.replace(right); } - Expression::Row { list, .. } => { + MutExpression::Row(Row { list, .. }) => { for id in list { old_new_expression_map.replace(id); } @@ -138,10 +136,10 @@ impl Plan { 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)?; - if let Expression::Unary { + if let MutExpression::Unary(UnaryExpr { op: Unary::Not, child, - } = parent_not_expr + }) = parent_not_expr { *child = expr_id; Ok(*parent_not_op) @@ -173,7 +171,7 @@ impl Plan { ) -> Result<NodeId, SbroadError> { let expr = self.get_expression_node(expr_id)?; let new_expr_id = match expr { - Expression::ExprInParentheses { child } => { + Expression::ExprInParentheses(ExprInParentheses { child }) => { // In case we have expression `true and not (true and false)` we would like to // save parentheses over not child: // `true and false or true` != `true and (false or true)`. @@ -184,7 +182,7 @@ impl Plan { } expr_id } - Expression::Constant { value } => { + Expression::Constant(Constant { value }) => { if let NotState::Off = not_state { expr_id } else { @@ -205,7 +203,7 @@ impl Plan { } } } - Expression::Bool { op, left, right } => { + Expression::Bool(BoolExpr { op, left, right }) => { let (remember_left, remember_right) = (*left, *right); if let NotState::On { .. } = not_state { @@ -235,10 +233,10 @@ impl Plan { expr_id } } - Expression::StableFunction { .. } - | Expression::Cast { .. } - | Expression::Reference { .. } => self.cover_with_not(expr_id, ¬_state)?, - Expression::Row { list, .. } => { + Expression::StableFunction(_) | Expression::Cast(_) | Expression::Reference(_) => { + self.cover_with_not(expr_id, ¬_state)? + } + Expression::Row(Row { list, .. }) => { let list_len = list.len(); if list_len == 1 { let child_id = *list.first().ok_or_else(|| { @@ -256,7 +254,7 @@ impl Plan { self.cover_with_not(expr_id, ¬_state)? } } - Expression::Unary { op, child } => match op { + Expression::Unary(UnaryExpr { op, child }) => match op { Unary::Not => { if let NotState::On { .. } = not_state { self.push_down_not_for_expression(*child, NotState::Off, map)? diff --git a/sbroad-core/src/ir/transformation/redistribution.rs b/sbroad-core/src/ir/transformation/redistribution.rs index 1832013da..0085a99be 100644 --- a/sbroad-core/src/ir/transformation/redistribution.rs +++ b/sbroad-core/src/ir/transformation/redistribution.rs @@ -10,10 +10,16 @@ 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::Expression; -use crate::ir::expression::{ColumnPositionMap, NodeId}; -use crate::ir::operator::{Bool, JoinKind, Relational, Unary, UpdateStrategy}; - +use crate::ir::expression::ColumnPositionMap; +use crate::ir::node::expression::Expression; +use crate::ir::node::relational::{RelOwned, Relational}; +use crate::ir::operator::{Bool, JoinKind, Unary, UpdateStrategy}; + +use crate::ir::node::{ + BoolExpr, Except, GroupBy, Having, Intersect, Join, Limit, NodeId, OrderBy, Projection, + Reference, ScanCte, ScanRelation, ScanSubQuery, Selection, UnaryExpr, Union, UnionAll, Update, + Values, ValuesRow, +}; use crate::ir::transformation::redistribution::eq_cols::EqualityCols; use crate::ir::tree::traversal::{ BreadthFirst, LevelNode, PostOrder, PostOrderWithFilter, EXPR_CAPACITY, REL_CAPACITY, @@ -161,9 +167,9 @@ struct BoolOp { impl BoolOp { fn from_expr(plan: &Plan, expr_id: NodeId) -> Result<Self, SbroadError> { - if let Expression::Bool { + if let Expression::Bool(BoolExpr { left, op, right, .. - } = plan.get_expression_node(expr_id)? + }) = plan.get_expression_node(expr_id)? { Ok(BoolOp { left: *left, @@ -277,7 +283,10 @@ impl Plan { let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), - Ok(Node::Expression(Expression::Unary { op: Unary::Not, .. })) + Ok(Node::Expression(Expression::Unary(UnaryExpr { + op: Unary::Not, + .. + }))) ) }; let mut post_tree = PostOrderWithFilter::with_capacity( @@ -299,16 +308,16 @@ impl Plan { 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, .. })) = + if let Ok(Node::Expression(Expression::Bool(BoolExpr { left, right, .. }))) = self.get_node(node_id) { let left_is_row = matches!( self.get_node(*left), - Ok(Node::Expression(Expression::Row { .. })) + Ok(Node::Expression(Expression::Row(_))) ); let right_is_row = matches!( self.get_node(*right), - Ok(Node::Expression(Expression::Row { .. })) + Ok(Node::Expression(Expression::Row(_))) ); if left_is_row && right_is_row { return true; @@ -335,10 +344,12 @@ impl Plan { 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) { + if let Ok(Node::Expression(Expression::Unary(UnaryExpr { child, .. }))) = + self.get_node(node_id) + { let child_is_row = matches!( self.get_node(*child), - Ok(Node::Expression(Expression::Row { .. })) + Ok(Node::Expression(Expression::Row(_))) ); if child_is_row { return true; @@ -379,7 +390,7 @@ impl Plan { ) -> 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)? { + if let Node::Relational(Relational::ScanSubQuery(_)) = self.get_node(*rel_id)? { sq_set.insert(*rel_id); } } @@ -468,11 +479,11 @@ impl Plan { 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 { + let ref node @ Expression::Reference(Reference { targets, position: ref_pos, .. - } = self.get_expression_node(*ref_id)? + }) = self.get_expression_node(*ref_id)? else { continue; }; @@ -581,7 +592,7 @@ impl Plan { if !strategy .children_policy .iter() - .all(|(node, _)| children_set.get(node).is_some()) + .all(|(node, _)| children_set.contains(node)) { return Err(SbroadError::FailedTo( Action::Add, @@ -700,7 +711,7 @@ impl Plan { 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 { + let Expression::Unary(UnaryExpr { child, op }) = unary_op_expr else { return Err(SbroadError::Invalid( Entity::Expression, Some(format_smolstr!( @@ -735,7 +746,7 @@ impl Plan { 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 { + if let Expression::Unary(UnaryExpr { child, .. }) = not_node { not_nodes_children.insert(*child); } else { return Err(SbroadError::Invalid( @@ -789,15 +800,14 @@ impl Plan { /// - If the node is not a join node. /// - Join node has no children. fn get_join_children(&self, join_id: NodeId) -> Result<Children<'_>, SbroadError> { - let join = self.get_relation_node(join_id)?; - if let Relational::Join { .. } = join { + if let Ok(children) = self.get_relational_children(join_id) { + Ok(children) } else { - return Err(SbroadError::Invalid( + Err(SbroadError::Invalid( Entity::Relational, Some("Join node is not an inner join.".into()), - )); + )) } - Ok(join.children()) } /// Detect join child from the position map corresponding to the distribution key. @@ -815,7 +825,9 @@ impl Plan { format_smolstr!("{pos} in row map {row_map:?}"), ) })?; - if let Expression::Reference { targets, .. } = self.get_expression_node(column_id)? { + if let Expression::Reference(Reference { targets, .. }) = + self.get_expression_node(column_id)? + { if let Some(targets) = targets { for target in targets { let child_id = *join_children.get(*target).ok_or_else(|| { @@ -851,7 +863,7 @@ impl Plan { /// # Errors /// - If the node is not a row node. 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 columns = self.get_row_list(row_id)?; let mut map: HashMap<usize, NodeId> = HashMap::new(); for (pos, col) in columns.iter().enumerate() { map.insert(pos, *col); @@ -913,10 +925,10 @@ impl Plan { let mut inner_positions: AHashSet<usize> = AHashSet::with_capacity(row_map.len()); for (pos, col) in row_map { let expression = self.get_expression_node(*col)?; - if let Expression::Reference { + if let Expression::Reference(Reference { targets: Some(targets), .. - } = expression + }) = expression { // Inner child of the join node is always the second one. if targets == &[1; 1] { @@ -942,9 +954,9 @@ impl Plan { format_smolstr!("{pos} in row map {condition_row_map:?}"), ) })?; - if let Expression::Reference { + if let Expression::Reference(Reference { targets, position, .. - } = self.get_expression_node(column_id)? + }) = self.get_expression_node(column_id)? { if let Some(targets) = targets { // Inner child of the join node is always the second one. @@ -1166,7 +1178,7 @@ impl Plan { matches!( self.get_node(node_id), Ok(Node::Expression( - Expression::Bool { .. } | Expression::Unary { op: Unary::Not, .. } + Expression::Bool(_) | Expression::Unary(UnaryExpr { op: Unary::Not, .. }) )) ) }; @@ -1183,13 +1195,13 @@ impl Plan { let expr = self.get_expression_node(node_id)?; // Under `not ... in ...` we should change the policy to `Full` - if let Expression::Unary { + if let Expression::Unary(UnaryExpr { op: Unary::Not, child, - } = expr + }) = expr { let child_expr = self.get_expression_node(*child)?; - if let Expression::Bool { op: Bool::In, .. } = child_expr { + if let Expression::Bool(BoolExpr { op: Bool::In, .. }) = child_expr { new_inner_policy = MotionPolicy::Full; inner_map.insert(node_id, new_inner_policy.clone()); continue; @@ -1224,12 +1236,12 @@ impl Plan { let left_expr = self.get_expression_node(bool_op.left)?; let right_expr = self.get_expression_node(bool_op.right)?; new_inner_policy = match (left_expr, right_expr) { - (Expression::Arithmetic { .. }, _) | (_, Expression::Arithmetic { .. }) => { + (Expression::Arithmetic(_), _) | (_, Expression::Arithmetic(_)) => { MotionPolicy::Full } ( - Expression::Bool { .. } | Expression::Unary { .. }, - Expression::Bool { .. } | Expression::Unary { .. }, + Expression::Bool(_) | Expression::Unary(_), + Expression::Bool(_) | Expression::Unary(_), ) => { let left_policy = inner_map .get(&bool_op.left) @@ -1250,7 +1262,7 @@ impl Plan { } } } - (Expression::Row { .. }, Expression::Row { .. }) => { + (Expression::Row(_), Expression::Row(_)) => { match bool_op.op { Bool::Between => { unreachable!("Between in redistribution") @@ -1270,17 +1282,11 @@ impl Plan { } } } - ( - Expression::Constant { .. }, - Expression::Bool { .. } | Expression::Unary { .. }, - ) => inner_map + (Expression::Constant(_), Expression::Bool(_) | Expression::Unary(_)) => inner_map .get(&bool_op.right) .cloned() .unwrap_or(MotionPolicy::Full), - ( - Expression::Bool { .. } | Expression::Unary { .. }, - Expression::Constant { .. }, - ) => inner_map + (Expression::Bool(_) | Expression::Unary(_), Expression::Constant(_)) => inner_map .get(&bool_op.left) .cloned() .unwrap_or(MotionPolicy::Full), @@ -1368,9 +1374,9 @@ impl Plan { // Otherwise, if they read some sharded table (Segment or Any), // then they always have Motion, which was set before this function // was called in `get_sq_node_strategy_for_unary_op`. - if let Expression::Bool { + if let Expression::Bool(BoolExpr { op, left, right, .. - } = self.get_expression_node(node_id)? + }) = self.get_expression_node(node_id)? { // If some other operator is used, then the corresponding subquery // already must have a Motion (in case it is reading non-global table), @@ -1593,14 +1599,13 @@ impl Plan { return self.resolve_dml_node_conflict_for_global_table(update_id); } - if let Relational::Update { strategy: kind, .. } = self.get_relation_node(update_id)? { + if let Relational::Update(Update { strategy: kind, .. }) = + self.get_relation_node(update_id)? + { let mut map = Strategy::new(update_id); let table = self.dml_node_table(update_id)?; let child_id = self.get_relational_child(update_id, 0)?; - if !matches!( - self.get_relation_node(child_id)?, - Relational::Projection { .. } - ) { + if !matches!(self.get_relation_node(child_id)?, Relational::Projection(_)) { return Err(SbroadError::Invalid( Entity::Update, Some(format_smolstr!( @@ -1778,7 +1783,7 @@ impl Plan { let mut map = Strategy::new(rel_id); let child_id = self.dml_child_id(rel_id)?; let child_node = self.get_relation_node(child_id)?; - if !matches!(child_node, Relational::Motion { .. }) { + if !matches!(child_node, Relational::Motion(_)) { map.add_child(child_id, MotionPolicy::Full, Program::default()); } Ok(map) @@ -1886,7 +1891,7 @@ impl Plan { #[allow(clippy::too_many_lines)] fn resolve_except_conflicts(&mut self, rel_id: NodeId) -> Result<Strategy, SbroadError> { - if !matches!(self.get_relation_node(rel_id)?, Relational::Except { .. }) { + if !matches!(self.get_relation_node(rel_id)?, Relational::Except(_)) { return Err(SbroadError::Invalid( Entity::Relational, Some("expected Except node".into()), @@ -2027,12 +2032,12 @@ impl Plan { 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 { + let intersect = Intersect { left: right_id, right: cloned_left_id, output: intersect_output_id, }; - let intersect_id = self.add_relational(intersect)?; + let intersect_id = self.add_relational(intersect.into())?; self.change_child(except_id, right_id, intersect_id)?; @@ -2046,7 +2051,7 @@ impl Plan { fn resolve_union_conflicts(&mut self, rel_id: NodeId) -> Result<Strategy, SbroadError> { if !matches!( self.get_relation_node(rel_id)?, - Relational::UnionAll { .. } | Relational::Union { .. } + Relational::UnionAll(_) | Relational::Union(_) ) { return Err(SbroadError::Invalid( Entity::Relational, @@ -2060,8 +2065,8 @@ impl Plan { let right_output_id = self.get_relation_node(right_id)?.output(); { - let left_output_row = self.get_expression_node(left_output_id)?.get_row_list()?; - let right_output_row = self.get_expression_node(right_output_id)?.get_row_list()?; + let left_output_row = self.get_row_list(left_output_id)?; + let right_output_row = self.get_row_list(right_output_id)?; if left_output_row.len() != right_output_row.len() { return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!( "Except node children have different row lengths: left {}, right {}", @@ -2152,7 +2157,7 @@ impl Plan { continue; } - let node = self.get_relation_node(id)?.clone(); + let node = self.get_relation_node(id)?.get_rel_owned(); // Some transformations (Union) need to add new nodes above // themselves, because we don't store parent references, @@ -2172,15 +2177,15 @@ impl Plan { // At the moment our grammar and IR constructors // don't allow projection and values row with // sub queries. - Relational::ScanRelation { output, .. } - | Relational::ScanSubQuery { output, .. } - | Relational::GroupBy { output, .. } - | Relational::Intersect { output, .. } - | Relational::Having { output, .. } - | Relational::ValuesRow { output, .. } => { + RelOwned::ScanRelation(ScanRelation { output, .. }) + | RelOwned::ScanSubQuery(ScanSubQuery { output, .. }) + | RelOwned::GroupBy(GroupBy { output, .. }) + | RelOwned::Intersect(Intersect { output, .. }) + | RelOwned::Having(Having { output, .. }) + | RelOwned::ValuesRow(ValuesRow { output, .. }) => { self.set_distribution(output)?; } - Relational::Limit { output, limit, .. } => { + RelOwned::Limit(Limit { output, limit, .. }) => { let rel_child_id = self.get_relational_child(id, 0)?; let child_dist = self.get_distribution(self.get_relational_output(rel_child_id)?)?; @@ -2209,7 +2214,7 @@ impl Plan { } } } - Relational::OrderBy { output, .. } => { + RelOwned::OrderBy(OrderBy { output, .. }) => { let rel_child_id = self.get_relational_child(id, 0)?; let child_dist = @@ -2225,13 +2230,13 @@ impl Plan { } self.set_dist(output, Distribution::Single)?; } - Relational::Values { output, .. } => { + RelOwned::Values(Values { output, .. }) => { self.set_dist(output, Distribution::Global)?; } - Relational::Projection { + RelOwned::Projection(Projection { output: proj_output_id, .. - } => { + }) => { let child_dist = self.get_distribution( self.get_relational_output(self.get_relational_child(id, 0)?)?, )?; @@ -2248,14 +2253,14 @@ impl Plan { self.set_projection_distribution(id)?; } } - Relational::Motion { .. } => { + RelOwned::Motion { .. } => { // We can apply this transformation only once, // i.e. to the plan without any motion nodes. return Err(SbroadError::DuplicatedValue(SmolStr::from( "IR already has Motion nodes.", ))); } - Relational::Selection { output, filter, .. } => { + RelOwned::Selection(Selection { output, filter, .. }) => { let strategy = self.resolve_sub_query_conflicts(id, filter)?; self.create_motion_nodes(strategy)?; if let Some(dist) = self.dist_from_subqueries(id)? { @@ -2264,12 +2269,12 @@ impl Plan { self.set_distribution(output)?; } } - Relational::Join { + RelOwned::Join(Join { output, condition, kind, .. - } => { + }) => { self.resolve_join_conflicts(id, condition, &kind)?; if let Some(dist) = self.dist_from_subqueries(id)? { self.set_dist(output, dist)?; @@ -2277,26 +2282,26 @@ impl Plan { self.set_distribution(output)?; } } - Relational::Delete { .. } => { + RelOwned::Delete { .. } => { let strategy = self.resolve_delete_conflicts(id)?; self.create_motion_nodes(strategy)?; } - Relational::Insert { .. } => { + RelOwned::Insert { .. } => { // Insert output tuple already has relation's distribution. let strategy = self.resolve_insert_conflicts(id)?; self.create_motion_nodes(strategy)?; } - Relational::Update { output, .. } => { + RelOwned::Update(Update { output, .. }) => { let strategy = self.resolve_update_conflicts(id)?; self.create_motion_nodes(strategy)?; self.set_distribution(output)?; } - Relational::Except { output, .. } => { + RelOwned::Except(Except { output, .. }) => { let strategy = self.resolve_except_conflicts(id)?; self.create_motion_nodes(strategy)?; self.set_distribution(output)?; } - Relational::Union { output, .. } => { + RelOwned::Union(Union { output, .. }) => { let strategy = self.resolve_union_conflicts(id)?; self.create_motion_nodes(strategy)?; self.set_distribution(output)?; @@ -2307,12 +2312,12 @@ impl Plan { )?; old_new.insert(id, new_top_id); } - Relational::UnionAll { output, .. } => { + RelOwned::UnionAll(UnionAll { output, .. }) => { let strategy = self.resolve_union_conflicts(id)?; self.create_motion_nodes(strategy)?; self.set_distribution(output)?; } - Relational::ScanCte { output, child, .. } => { + RelOwned::ScanCte(ScanCte { output, child, .. }) => { // Possible, current CTE subtree has already been resolved and we // can just copy the corresponding motion node. if let Some(motion_id) = cte_motions.get(&child) { @@ -2339,6 +2344,7 @@ impl Plan { } } } + visited.insert(id); } @@ -2353,7 +2359,6 @@ impl Plan { let top_id = self.get_top()?; let slices = self.calculate_slices(top_id)?; self.set_slices(slices); - Ok(()) } @@ -2371,7 +2376,7 @@ impl Plan { let mut map: HashMap<usize, usize> = HashMap::new(); let mut max_level: usize = 0; for LevelNode(level, id) in bft_tree.iter(top_id) { - if let Node::Relational(Relational::Motion { .. }) = self.get_node(id)? { + if let Node::Relational(Relational::Motion(_)) = self.get_node(id)? { let key: usize = match map.entry(level) { Entry::Occupied(o) => *o.into_mut(), Entry::Vacant(v) => { diff --git a/sbroad-core/src/ir/transformation/redistribution/dml.rs b/sbroad-core/src/ir/transformation/redistribution/dml.rs index b29de812b..96a901a73 100644 --- a/sbroad-core/src/ir/transformation/redistribution/dml.rs +++ b/sbroad-core/src/ir/transformation/redistribution/dml.rs @@ -1,6 +1,7 @@ use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::NodeId; -use crate::ir::operator::{ConflictStrategy, Relational, UpdateStrategy}; +use crate::ir::node::relational::{MutRelational, Relational}; +use crate::ir::node::{Delete, Insert, Motion, NodeId, Update}; +use crate::ir::operator::{ConflictStrategy, UpdateStrategy}; use crate::ir::relation::{Column, Table}; use crate::ir::transformation::redistribution::MotionOpcode; use crate::ir::Plan; @@ -17,9 +18,9 @@ impl Plan { /// - `Insert` has 0 or more than 1 child 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, .. } - | Relational::Delete { children, .. } = dml_node + if let Relational::Insert(Insert { children, .. }) + | Relational::Update(Update { children, .. }) + | Relational::Delete(Delete { children, .. }) = dml_node { if let (Some(child), None) = (children.first(), children.get(1)) { return Ok(*child); @@ -44,9 +45,9 @@ impl Plan { insert_id: NodeId, ) -> Result<&ConflictStrategy, SbroadError> { let insert = self.get_relation_node(insert_id)?; - if let Relational::Insert { + if let Relational::Insert(Insert { conflict_strategy, .. - } = insert + }) = insert { return Ok(conflict_strategy); } @@ -72,7 +73,7 @@ impl Plan { // output columns. let child_id = self.dml_child_id(insert_id)?; let child_output_id = self.get_relation_node(child_id)?.output(); - let child_row = self.get_expression_node(child_output_id)?.get_row_list()?; + let child_row = self.get_row_list(child_output_id)?; if columns.len() != child_row.len() { return Err(SbroadError::Invalid( Entity::Node, @@ -117,7 +118,7 @@ impl Plan { /// - node is not `Insert` 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 { + if let Relational::Insert(Insert { ref columns, .. }) = insert { return Ok(columns); } Err(SbroadError::Invalid( @@ -132,9 +133,9 @@ impl Plan { /// - Node is not an `Insert` 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, .. } - | Relational::Delete { relation, .. } = node + if let Relational::Insert(Insert { relation, .. }) + | Relational::Update(Update { relation, .. }) + | Relational::Delete(Delete { relation, .. }) = node { return self.get_relation_or_error(relation); } @@ -155,13 +156,13 @@ impl Plan { len: usize, ) -> Result<(), SbroadError> { let node = self.get_mut_relation_node(update_id)?; - if let Relational::Update { + if let MutRelational::Update(Update { strategy: UpdateStrategy::ShardedUpdate { delete_tuple_len, .. }, .. - } = node + }) = node { *delete_tuple_len = Some(len); } else { @@ -181,14 +182,14 @@ impl Plan { /// - length not set on current `Update` node 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 { + if let Relational::Update(Update { strategy: UpdateStrategy::ShardedUpdate { delete_tuple_len: Some(len), .. }, .. - } = node + }) = node { return Ok(*len); } @@ -211,7 +212,7 @@ impl Plan { opcode_idx: usize, ) -> Result<&MotionOpcode, SbroadError> { let node = self.get_relation_node(motion_id)?; - if let Relational::Motion { program, .. } = node { + if let Relational::Motion(Motion { program, .. }) = node { if let Some(op) = program.0.get(opcode_idx) { return Ok(op); } @@ -232,7 +233,7 @@ impl Plan { /// - Node is not an `Update` 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 { + if let Relational::Update(Update { strategy, .. }) = node { return Ok(matches!(strategy, UpdateStrategy::ShardedUpdate { .. })); } Err(SbroadError::Invalid( diff --git a/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs b/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs index 67e531528..82541cf4f 100644 --- a/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs +++ b/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs @@ -1,8 +1,13 @@ use crate::errors::SbroadError; -use crate::ir::expression::{Expression, ExpressionId, NodeId}; +use crate::ir::expression::ExpressionId; +use crate::ir::node::expression::Expression; +use crate::ir::node::{ + Alias, ArithmeticExpr, BoolExpr, Case, Cast, Concat, ExprInParentheses, NodeId, Reference, Row, + StableFunction, Trim, UnaryExpr, +}; use crate::ir::operator::Bool; use crate::ir::transformation::redistribution::BoolOp; -use crate::ir::tree::traversal::{PostOrder, PostOrderWithFilter, EXPR_CAPACITY}; +use crate::ir::tree::traversal::{LevelNode, PostOrder, PostOrderWithFilter, EXPR_CAPACITY}; use crate::ir::{Node, Plan}; use std::collections::{HashMap, HashSet}; use std::slice::Iter; @@ -71,20 +76,19 @@ impl ReferredMap { 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 level_node in expr_tree.iter(condition_id) { - let node_id = level_node.1; + for LevelNode(_, node_id) in expr_tree.iter(condition_id) { let expr = plan.get_expression_node(node_id)?; let res = match expr { - Expression::Bool { left, right, .. } - | Expression::Arithmetic { left, right, .. } - | Expression::Concat { left, right, .. } => referred + Expression::Bool(BoolExpr { left, right, .. }) + | Expression::Arithmetic(ArithmeticExpr { left, right, .. }) + | Expression::Concat(Concat { left, right, .. }) => referred .get_or_none(*left) .add(referred.get_or_none(*right)), - Expression::Case { + Expression::Case(Case { search_expr, when_blocks, else_expr, - } => { + }) => { let mut res = Referred::None; if let Some(search_expr) = search_expr { res = res.add(referred.get_or_none(*search_expr)); @@ -98,18 +102,18 @@ impl ReferredMap { } res } - Expression::Trim { + Expression::Trim(Trim { pattern, target, .. - } => match pattern { + }) => match pattern { Some(pattern) => referred .get_or_none(*pattern) .add(referred.get_or_none(*target)), None => referred.get_or_none(*target).clone(), }, - Expression::Constant { .. } | Expression::CountAsterisk => Referred::None, - Expression::Reference { + Expression::Constant { .. } | Expression::CountAsterisk { .. } => Referred::None, + Expression::Reference(Reference { targets, parent, .. - } => { + }) => { if *parent == Some(join_id) && *targets == Some(vec![1]) { Referred::Inner } else if *parent == Some(join_id) && *targets == Some(vec![0]) { @@ -118,16 +122,16 @@ impl ReferredMap { Referred::None } } - Expression::Row { list: children, .. } - | Expression::StableFunction { children, .. } => { + Expression::Row(Row { list: children, .. }) + | Expression::StableFunction(StableFunction { children, .. }) => { children.iter().fold(Referred::None, |acc, x| { acc.add(referred.get(*x).unwrap_or(&Referred::None)) }) } - Expression::Alias { child, .. } - | Expression::ExprInParentheses { child } - | Expression::Cast { child, .. } - | Expression::Unary { child, .. } => { + Expression::Alias(Alias { child, .. }) + | Expression::ExprInParentheses(ExprInParentheses { child }) + | Expression::Cast(Cast { child, .. }) + | Expression::Unary(UnaryExpr { child, .. }) => { referred.get(*child).unwrap_or(&Referred::None).clone() } }; @@ -291,18 +295,18 @@ impl EqualityCols { let right_node = plan.get_expression_node(*right_id)?; match (left_node, right_node) { ( - Expression::Reference { + Expression::Reference(Reference { targets: targets_left, position: pos_left, parent: parent_left, col_type: col_type_left, - }, - Expression::Reference { + }), + Expression::Reference(Reference { targets: targets_right, position: pos_right, parent: parent_right, col_type: col_type_right, - }, + }), ) => { // TODO: compare types only if the runtime requires it. @@ -322,7 +326,7 @@ impl EqualityCols { new_eq_cols.add_equality_pair(inner_pos, outer_pos); }; } - (Expression::Constant { .. }, _) | (_, Expression::Constant { .. }) => {} + (Expression::Constant(_), _) | (_, Expression::Constant(_)) => {} (_, _) => { // if some kind of transformation is applied to another side of equality // operator, we can't do repartition join, for example: @@ -360,12 +364,12 @@ impl EqualityCols { let right_expr = plan.get_expression_node(op.right)?; let res = match (left_expr, right_expr) { ( - Expression::Row { + Expression::Row(Row { list: list_left, .. - }, - Expression::Row { + }), + Expression::Row(Row { list: list_right, .. - }, + }), ) => match op.op { Bool::Eq | Bool::In => EqualityCols::eq_cols_for_eq( list_left, list_right, node_id, inner_id, plan, refers_to, @@ -489,7 +493,7 @@ impl EqualityCols { 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: NodeId| -> bool { - if let Ok(Node::Expression(Expression::Bool { .. })) = plan.get_node(node_id) { + if let Ok(Node::Expression(Expression::Bool(_))) = plan.get_node(node_id) { return true; } false @@ -505,7 +509,7 @@ impl EqualityCols { let left_expr = plan.get_expression_node(bool_op.left)?; let right_expr = plan.get_expression_node(bool_op.right)?; let new_eq_cols = match (left_expr, right_expr) { - (Expression::Row { .. }, Expression::Row { .. }) => { + (Expression::Row(_), Expression::Row(_)) => { EqualityCols::eq_cols_for_rows(&bool_op, node_id, &refers_to, inner_id, plan)? } (_, _) => { diff --git a/sbroad-core/src/ir/transformation/redistribution/groupby.rs b/sbroad-core/src/ir/transformation/redistribution/groupby.rs index ac587a759..132b9857c 100644 --- a/sbroad-core/src/ir/transformation/redistribution/groupby.rs +++ b/sbroad-core/src/ir/transformation/redistribution/groupby.rs @@ -4,18 +4,21 @@ use crate::errors::{Entity, SbroadError}; use crate::executor::engine::helpers::to_user; use crate::ir::aggregates::{generate_local_alias_for_aggr, AggregateKind, SimpleAggregate}; use crate::ir::distribution::Distribution; -use crate::ir::expression::Expression::StableFunction; use crate::ir::expression::{ - ColumnPositionMap, Comparator, Expression, FunctionFeature, NodeId, ReferencePolicy, - EXPR_HASH_DEPTH, + ColumnPositionMap, Comparator, FunctionFeature, ReferencePolicy, EXPR_HASH_DEPTH, +}; +use crate::ir::node::expression::Expression; +use crate::ir::node::relational::{MutRelational, Relational}; +use crate::ir::node::{ + Alias, ArenaType, ArithmeticExpr, BoolExpr, Case, Cast, Concat, Constant, ExprInParentheses, + GroupBy, Having, NodeId, Projection, Reference, Row, StableFunction, Trim, UnaryExpr, }; -use crate::ir::operator::Relational; use crate::ir::relation::Type; use crate::ir::transformation::redistribution::{ MotionKey, MotionPolicy, Program, Strategy, Target, }; use crate::ir::tree::traversal::{BreadthFirst, PostOrderWithFilter, EXPR_CAPACITY}; -use crate::ir::{ArenaType, Node, Plan}; +use crate::ir::{Node, Plan}; use std::collections::{HashMap, HashSet}; use crate::ir::function::{Behavior, Function}; @@ -131,6 +134,7 @@ impl<'plan, 'args> PartialEq<Self> for AggregateSignature<'plan, 'args> { impl<'plan, 'args> Eq for AggregateSignature<'plan, 'args> {} +#[derive(Debug)] struct GroupingExpression<'plan> { pub id: NodeId, pub plan: &'plan Plan, @@ -194,7 +198,7 @@ impl<'plan> AggrCollector<'plan> { 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 { + if let Expression::StableFunction(StableFunction { name, feature, .. }) = expr { let is_distinct = matches!(feature, Some(FunctionFeature::Distinct)); if let Some(aggr) = SimpleAggregate::new(name, current) { let Some(parent_rel) = self.parent_rel else { @@ -290,7 +294,7 @@ impl<'plan> ExpressionMapper<'plan> { }; let is_ref = matches!( self.plan.get_expression_node(current), - Ok(Expression::Reference { .. }) + Ok(Expression::Reference(_)) ); let is_sq_ref = is_ref && self.plan.is_additional_child_of_rel( @@ -327,7 +331,7 @@ impl<'plan> ExpressionMapper<'plan> { let column_name = { let node = self.plan.get_expression_node(current)?; self.plan - .get_alias_from_reference_node(node) + .get_alias_from_reference_node(&node) .unwrap_or("'failed to get column name'") }; return Err(SbroadError::Invalid( @@ -393,25 +397,27 @@ impl Plan { if let Node::Expression(right) = r { match left { Expression::Alias { .. } => {} - Expression::ExprInParentheses { child: l_child } => { + Expression::ExprInParentheses(ExprInParentheses { child: l_child }) => { // TODO: Should we compare expressions ignoring parentheses? - if let Expression::ExprInParentheses { child: r_child } = right { + if let Expression::ExprInParentheses(ExprInParentheses { child: r_child }) = + right + { return self.are_aggregate_subtrees_equal(*l_child, *r_child); } } - Expression::CountAsterisk => { - return Ok(matches!(right, Expression::CountAsterisk)) + Expression::CountAsterisk(_) => { + return Ok(matches!(right, Expression::CountAsterisk(_))) } - Expression::Bool { + Expression::Bool(BoolExpr { left: left_left, op: op_left, right: right_left, - } => { - if let Expression::Bool { + }) => { + if let Expression::Bool(BoolExpr { left: left_right, op: op_right, right: right_right, - } = right + }) = right { return Ok(*op_left == *op_right && self.are_aggregate_subtrees_equal(*left_left, *left_right)? @@ -419,16 +425,16 @@ impl Plan { .are_aggregate_subtrees_equal(*right_left, *right_right)?); } } - Expression::Case { + Expression::Case(Case { search_expr: search_expr_left, when_blocks: when_blocks_left, else_expr: else_expr_left, - } => { - if let Expression::Case { + }) => { + if let Expression::Case(Case { search_expr: search_expr_right, when_blocks: when_blocks_right, else_expr: else_expr_right, - } = right + }) = right { let mut search_expr_equal = false; if let (Some(search_expr_left), Some(search_expr_right)) = @@ -463,46 +469,46 @@ impl Plan { return Ok(search_expr_equal && when_blocks_equal && else_expr_equal); } } - Expression::Arithmetic { + Expression::Arithmetic(ArithmeticExpr { op: op_left, left: l_left, right: r_left, - } => { - if let Expression::Arithmetic { + }) => { + if let Expression::Arithmetic(ArithmeticExpr { op: op_right, left: l_right, right: r_right, - } = right + }) = right { return Ok(*op_left == *op_right && self.are_aggregate_subtrees_equal(*l_left, *l_right)? && self.are_aggregate_subtrees_equal(*r_left, *r_right)?); } } - Expression::Cast { + Expression::Cast(Cast { child: child_left, to: to_left, - } => { - if let Expression::Cast { + }) => { + if let Expression::Cast(Cast { child: child_right, to: to_right, - } = right + }) = right { return Ok(*to_left == *to_right && self .are_aggregate_subtrees_equal(*child_left, *child_right)?); } } - Expression::Trim { + Expression::Trim(Trim { kind: kind_left, pattern: pattern_left, target: target_left, - } => { - if let Expression::Trim { + }) => { + if let Expression::Trim(Trim { kind: kind_right, pattern: pattern_right, target: target_right, - } = right + }) = right { match (pattern_left, pattern_right) { (Some(p_left), Some(p_right)) => { @@ -525,14 +531,14 @@ impl Plan { } } } - Expression::Concat { + Expression::Concat(Concat { left: left_left, right: right_left, - } => { - if let Expression::Concat { + }) => { + if let Expression::Concat(Concat { left: left_right, right: right_right, - } = right + }) = right { return Ok(self .are_aggregate_subtrees_equal(*left_left, *left_right)? @@ -540,44 +546,44 @@ impl Plan { .are_aggregate_subtrees_equal(*right_left, *right_right)?); } } - Expression::Constant { value: value_left } => { - if let Expression::Constant { value: value_right } = right { + Expression::Constant(Constant { value: value_left }) => { + if let Expression::Constant(Constant { value: value_right }) = right { return Ok(*value_left == *value_right); } } Expression::Reference { .. } => { if let Expression::Reference { .. } = right { - let alias_left = self.get_alias_from_reference_node(left)?; - let alias_right = self.get_alias_from_reference_node(right)?; + let alias_left = self.get_alias_from_reference_node(&left)?; + let alias_right = self.get_alias_from_reference_node(&right)?; return Ok(alias_left == alias_right); } } - Expression::Row { + Expression::Row(Row { list: list_left, .. - } => { - if let Expression::Row { + }) => { + if let Expression::Row(Row { list: list_right, .. - } = right + }) = right { return Ok(list_left.iter().zip(list_right.iter()).all(|(l, r)| { self.are_aggregate_subtrees_equal(*l, *r).unwrap_or(false) })); } } - Expression::StableFunction { + Expression::StableFunction(StableFunction { name: name_left, children: children_left, feature: feature_left, func_type: func_type_left, is_system: is_aggr_left, - } => { - if let Expression::StableFunction { + }) => { + if let Expression::StableFunction(StableFunction { name: name_right, children: children_right, feature: feature_right, func_type: func_type_right, is_system: is_aggr_right, - } = right + }) = right { return Ok(name_left == name_right && feature_left == feature_right @@ -590,14 +596,14 @@ impl Plan { )); } } - Expression::Unary { + Expression::Unary(UnaryExpr { op: op_left, child: child_left, - } => { - if let Expression::Unary { + }) => { + if let Expression::Unary(UnaryExpr { op: op_right, child: child_right, - } = right + }) = right { return Ok(*op_left == *op_right && self @@ -636,7 +642,7 @@ impl Plan { matches!( self.get_node(node_id), Ok(Node::Expression( - Expression::StableFunction { .. } | Expression::Reference { .. } + Expression::StableFunction(_) | Expression::Reference(_) )) ) }; @@ -650,10 +656,12 @@ impl Plan { let node_id = level_node.1; let node = self.get_node(node_id)?; match node { - Node::Expression(Expression::Reference { .. }) => { + Node::Expression(Expression::Reference(_)) => { contains_at_least_one_col = true; } - Node::Expression(Expression::StableFunction { name, .. }) => { + Node::Expression(Expression::StableFunction(StableFunction { + name, .. + })) => { if Expression::is_aggregate_name(name) { return Err(SbroadError::Invalid( Entity::Query, @@ -689,14 +697,14 @@ impl Plan { expr_parent: Option<NodeId>, ) -> Result<NodeId, SbroadError> { let final_output = self.add_row_for_output(child_id, &[], true)?; - let groupby = Relational::GroupBy { + let groupby = GroupBy { children: [child_id].to_vec(), gr_cols: grouping_exprs.to_vec(), output: final_output, is_final, }; - let groupby_id = self.add_relational(groupby)?; + let groupby_id = self.add_relational(groupby.into())?; self.replace_parent_in_subtree(final_output, None, Some(groupby_id))?; for expr in grouping_exprs { @@ -719,12 +727,12 @@ impl Plan { for node_id in finals { let node = self.get_relation_node(*node_id)?; match node { - Relational::Projection { output, .. } => { + Relational::Projection(Projection { output, .. }) => { for col in self.get_row_list(*output)? { collector.collect_aggregates(*col, *node_id)?; } } - Relational::Having { filter, .. } => { + Relational::Having(Having { filter, .. }) => { collector.collect_aggregates(*filter, *node_id)?; } _ => { @@ -795,7 +803,7 @@ impl Plan { let max_reduce_nodes = 2; for _ in 0..=max_reduce_nodes { match self.get_relation_node(next)? { - Relational::Projection { .. } | Relational::Having { .. } => { + Relational::Projection(_) | Relational::Having(_) => { finals.push(next); next = get_first_child(next)?; } @@ -849,22 +857,22 @@ impl Plan { let mut gr_expr_map: GroupbyExpressionsMap = HashMap::new(); let mut upper = upper; - let mut has_groupby = matches!(self.get_relation_node(upper)?, Relational::GroupBy { .. }); + let mut has_groupby = matches!(self.get_relation_node(upper)?, Relational::GroupBy(_)); if !has_groupby && !has_aggregates { if let Some(proj_id) = finals.first() { - if let Relational::Projection { + if let Relational::Projection(Projection { is_distinct, output, .. - } = self.get_relation_node(*proj_id)? + }) = self.get_relation_node(*proj_id)? { if *is_distinct { let proj_cols_len = self.get_row_list(*output)?.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, .. } = + let proj_col_id = if let Expression::Alias(Alias { child, .. }) = self.get_expression_node(aliased_col)? { *child @@ -901,12 +909,12 @@ impl Plan { let mut mapper = ExpressionMapper::new(&grouping_expr, self); for node_id in finals { match self.get_relation_node(*node_id)? { - Relational::Projection { output, .. } => { + Relational::Projection(Projection { output, .. }) => { for col in self.get_row_list(*output)? { mapper.find_matches(*col, *node_id)?; } } - Relational::Having { filter, .. } => { + Relational::Having(Having { filter, .. }) => { mapper.find_matches(*filter, *node_id)?; } _ => {} @@ -920,12 +928,12 @@ impl Plan { for id in finals { let node = self.get_relation_node(*id)?; match node { - Relational::Projection { output, .. } => { + Relational::Projection(Projection { output, .. }) => { for col in self.get_row_list(*output)? { let filter = |node_id: NodeId| -> bool { matches!( self.get_node(node_id), - Ok(Node::Expression(Expression::Reference { .. })) + Ok(Node::Expression(Expression::Reference(_))) ) }; let mut dfs = PostOrderWithFilter::with_capacity( @@ -938,8 +946,8 @@ impl Plan { 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) { + if let Expression::Reference(_) = n { + let alias = match self.get_alias_from_reference_node(&n) { Ok(v) => v.to_smolstr(), Err(e) => e.to_smolstr(), }; @@ -949,7 +957,7 @@ impl Plan { } } } - Relational::Having { filter, .. } => { + Relational::Having(Having { filter, .. }) => { let mut bfs = BreadthFirst::with_capacity( |x| self.nodes.aggregate_iter(x, false), EXPR_CAPACITY, @@ -959,7 +967,7 @@ impl Plan { let nodes = bfs.take_nodes(); for level_node in nodes { let id = level_node.1; - if let Expression::Reference { .. } = self.get_expression_node(id)? { + if let Expression::Reference(_) = self.get_expression_node(id)? { return Err(SbroadError::Invalid( Entity::Query, Some("HAVING argument must appear in the GROUP BY clause or be used in an aggregate function".into()) @@ -988,7 +996,7 @@ impl Plan { ) -> Result<NodeId, SbroadError> { let mut local_proj_child_id = upper; if !additional_grouping_exprs.is_empty() { - if let Relational::GroupBy { gr_cols, .. } = + if let MutRelational::GroupBy(GroupBy { gr_cols, .. }) = self.get_mut_relation_node(local_proj_child_id)? { gr_cols.extend(additional_grouping_exprs); @@ -1068,12 +1076,13 @@ impl Plan { 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); - let proj = Relational::Projection { + let proj = Projection { output: proj_output, children: vec![child_id], is_distinct: false, }; - let proj_id = self.add_relational(proj)?; + let proj_id = self.add_relational(proj.into())?; + for info in aggr_infos { // We take expressions inside aggregate functions from Final projection, // so we need to update parent @@ -1216,6 +1225,7 @@ impl Plan { let mut alias_to_pos: HashMap<Rc<String>, usize> = HashMap::new(); // add grouping expressions to local projection + for (pos, (gr_expr, local_alias)) in unique_grouping_exprs_for_local_stage.iter().enumerate() { @@ -1282,7 +1292,7 @@ impl Plan { continue; } let arguments = { - if let StableFunction { children, .. } = + if let Expression::StableFunction(StableFunction { children, .. }) = self.get_expression_node(info.aggr.fun_id)? { children @@ -1395,31 +1405,31 @@ impl Plan { )), )); } - let new_col = Expression::Reference { + let new_col = Reference { position, parent: None, targets: Some(vec![0]), col_type, }; - nodes.push(Node::Expression(new_col)); + nodes.push(new_col); } for node in nodes { - let new_col_id = self.nodes.push(node); + let new_col_id = self.nodes.push(node.into()); gr_cols.push(new_col_id); } let output = self.add_row_for_output(child_id, &[], true)?; - let final_id = self.nodes.next_id(ArenaType::Default); + let final_id = self.nodes.next_id(ArenaType::Arena64); for col in &gr_cols { self.replace_parent_in_subtree(*col, None, Some(final_id))?; } - let final_groupby = Relational::GroupBy { + let final_groupby = GroupBy { gr_cols, children: vec![child_id], is_final: true, output, }; self.replace_parent_in_subtree(output, None, Some(final_id))?; - self.add_relational(final_groupby)?; + self.add_relational(final_groupby.into())?; Ok(final_id) } @@ -1488,21 +1498,21 @@ impl Plan { )), )); }; - let new_ref = Expression::Reference { + let new_ref = Reference { parent: Some(rel_id), targets: Some(vec![0]), position, col_type, }; - nodes.push((parent, expr_id, gr_expr_id, Node::Expression(new_ref))); + nodes.push((parent, expr_id, gr_expr_id, new_ref)); } for (parent, expr_id, gr_expr_id, node) in nodes { - let ref_id = self.nodes.push(node); + let ref_id = self.nodes.push(node.into()); if let Some(parent_expr_id) = parent { self.replace_expression(parent_expr_id, expr_id, ref_id)?; } else { match self.get_mut_relation_node(rel_id)? { - Relational::Projection { .. } => { + MutRelational::Projection(_) => { return Err(SbroadError::Invalid( Entity::Plan, Some(format_smolstr!( @@ -1513,7 +1523,7 @@ impl Plan { )), )) } - Relational::Having { filter, .. } => { + MutRelational::Having(Having { filter, .. }) => { *filter = ref_id; } _ => { @@ -1575,8 +1585,8 @@ impl Plan { // Projection node is the top node in finals: its aliases // must not be changed (because those are user aliases), so // nothing to do here - Relational::Projection { .. } => {} - Relational::Having { children, .. } => { + Relational::Projection(_) => {} + Relational::Having(Having { children, .. }) => { let child_id = *children.first().ok_or_else(|| { SbroadError::Invalid( Entity::Node, @@ -1608,7 +1618,7 @@ impl Plan { } for (parent, infos) in parent_to_infos { let child_id = { - let children = self.get_relation_node(parent)?.children(); + let children = self.get_relational_children(parent)?; *children.get(0).ok_or_else(|| { SbroadError::Invalid( Entity::Node, @@ -1661,7 +1671,7 @@ impl Plan { let proj_id = *finals.first().ok_or_else(|| { SbroadError::Invalid(Entity::Plan, Some("no nodes in Reduce stage!".into())) })?; - if let Relational::Projection { .. } = self.get_relation_node(proj_id)? { + if let Relational::Projection(_) = self.get_relation_node(proj_id)? { } else { return Err(SbroadError::Invalid( Entity::Plan, @@ -1680,7 +1690,7 @@ impl Plan { self.set_dist(self.get_relational_output(proj_id)?, Distribution::Single)?; } else { // we have GroupBy, then finals_child_id is final GroupBy - let child_id = if let Relational::GroupBy { children, .. } = + let child_id = if let Relational::GroupBy(GroupBy { children, .. }) = self.get_relation_node(motion_parent)? { *children.first().ok_or_else(|| { @@ -1747,7 +1757,8 @@ impl Plan { if !grouping_exprs.is_empty() { // let shard_col_info = self.track_shard_column_pos(final_proj_id)?; for expr_id in &grouping_exprs { - let Expression::Reference { position, .. } = self.get_expression_node(*expr_id)? + let Expression::Reference(Reference { position, .. }) = + self.get_expression_node(*expr_id)? else { continue; }; @@ -1783,14 +1794,14 @@ impl Plan { // skip Projection for node_id in finals.iter().skip(1).rev() { self.set_distribution(self.get_relational_output(*node_id)?)?; - if let Relational::Having { .. } = self.get_relation_node(*node_id)? { + if let Relational::Having(_) = self.get_relation_node(*node_id)? { having_id = Some(*node_id); } } if matches!( self.get_relation_node(finals_child_id)?, - Relational::GroupBy { .. } + Relational::GroupBy(_) ) { self.set_distribution(self.get_relational_output(final_proj_id)?)?; } else { @@ -1802,7 +1813,7 @@ impl Plan { // resolve subquery conflicts in HAVING if let Some(having_id) = having_id { - if let Relational::Having { filter, .. } = self.get_relation_node(having_id)? { + if let Relational::Having(Having { filter, .. }) = self.get_relation_node(having_id)? { let strategy = self.resolve_sub_query_conflicts(having_id, *filter)?; self.create_motion_nodes(strategy)?; } diff --git a/sbroad-core/src/ir/transformation/redistribution/left_join.rs b/sbroad-core/src/ir/transformation/redistribution/left_join.rs index 546f72040..358ec9874 100644 --- a/sbroad-core/src/ir/transformation/redistribution/left_join.rs +++ b/sbroad-core/src/ir/transformation/redistribution/left_join.rs @@ -7,8 +7,8 @@ use crate::{ errors::{Entity, SbroadError}, ir::{ distribution::Distribution, - expression::NodeId, - operator::{JoinKind, Relational}, + node::{relational::MutRelational, Join, NodeId}, + operator::JoinKind, Plan, }, }; @@ -34,7 +34,7 @@ impl Plan { return Ok(None); } - if let Relational::Join { kind, .. } = self.get_mut_relation_node(join_id)? { + if let MutRelational::Join(Join { kind, .. }) = self.get_mut_relation_node(join_id)? { *kind = JoinKind::Inner; } self.set_distribution(self.get_relational_output(join_id)?)?; @@ -58,7 +58,6 @@ impl Plan { let outer_child_motion_id = { let child = self.get_relation_node(outer_id)?; let mut motion_child_id = None; - // Check if there is already motion under outer child if child.is_subquery_or_cte() { let sq_child = self.get_relational_child(outer_id, 0)?; diff --git a/sbroad-core/src/ir/transformation/redistribution/tests.rs b/sbroad-core/src/ir/transformation/redistribution/tests.rs index 9a5ef710d..ce8c407b1 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests.rs @@ -1,5 +1,5 @@ use super::*; -use crate::ir::operator::Relational; +use crate::ir::node::Motion; use crate::ir::transformation::helpers::sql_to_ir; use crate::ir::Plan; use crate::ir::Slices; @@ -69,7 +69,7 @@ fn join_inner_sq_less_for_keys() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -87,7 +87,7 @@ fn join_inner_sq_eq_no_keys() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -105,7 +105,7 @@ fn join_inner_sq_eq_no_outer_keys() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -124,7 +124,7 @@ fn inner_join_full_policy_sq_in_filter() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -184,7 +184,7 @@ fn join_inner_or_local_full_policies() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); diff --git a/sbroad-core/src/ir/transformation/redistribution/tests/between.rs b/sbroad-core/src/ir/transformation/redistribution/tests/between.rs index 895f6ed26..da8f98d56 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests/between.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests/between.rs @@ -1,4 +1,5 @@ -use crate::ir::operator::Relational; +use crate::ir::node::relational::Relational; +use crate::ir::node::Motion; use crate::ir::transformation::helpers::sql_to_ir; use crate::ir::transformation::redistribution::tests::get_motion_id; use crate::ir::transformation::redistribution::MotionPolicy; @@ -16,7 +17,7 @@ fn between1() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -46,7 +47,7 @@ fn between3() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); diff --git a/sbroad-core/src/ir/transformation/redistribution/tests/except.rs b/sbroad-core/src/ir/transformation/redistribution/tests/except.rs index ae827e239..07529547f 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests/except.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests/except.rs @@ -1,10 +1,11 @@ -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::{Key, MotionPolicy}; use crate::ir::Slices; use pretty_assertions::assert_eq; +use super::{Motion, Relational}; + #[test] fn except1() { let query = r#"SELECT 1, 2 FROM "hash_testing" AS "t" @@ -15,7 +16,7 @@ fn except1() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -43,7 +44,7 @@ fn except3() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( @@ -72,7 +73,7 @@ fn except4() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( @@ -101,7 +102,7 @@ fn except5() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( 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 8593501b9..c77a9b11b 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests/not_in.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests/not_in.rs @@ -1,10 +1,11 @@ -use crate::ir::operator::Relational; use crate::ir::transformation::helpers::sql_to_ir; use crate::ir::transformation::redistribution::tests::{get_motion_id, NodeId}; use crate::ir::transformation::redistribution::MotionPolicy; use crate::ir::{ArenaType, Slice, Slices}; use pretty_assertions::assert_eq; +use super::{Motion, Relational}; + #[test] fn not_in1() { let query = r#"SELECT 1 FROM "hash_testing" AS "t" WHERE "product_code" NOT IN ( @@ -14,7 +15,7 @@ fn not_in1() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -31,8 +32,8 @@ fn not_in2() { assert_eq!( Slices::from(vec![Slice { slice: vec![NodeId { - offset: 65, - arena_type: ArenaType::Default, + offset: 0, + arena_type: ArenaType::Arena136, }] }]), plan.slices @@ -48,7 +49,7 @@ fn not_in3() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -64,7 +65,7 @@ fn not_in4() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); @@ -80,7 +81,7 @@ fn not_in5() { plan.add_motions().unwrap(); let motion_id = *get_motion_id(&plan, 0, 0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!(*policy, MotionPolicy::Full); } else { panic!("Expected a motion node"); diff --git a/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs b/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs index a42085758..a1819b234 100644 --- a/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs +++ b/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs @@ -1,14 +1,15 @@ use crate::collection; use crate::ir::distribution::{Distribution, Key}; use crate::ir::helpers::RepeatableState; -use crate::ir::operator::Relational; +use crate::ir::node::{Node64, NodeId}; 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; use pretty_assertions::assert_eq; use std::collections::HashSet; +use super::{Motion, Relational}; + #[test] fn inner_join1() { let query = r#"SELECT * FROM "hash_testing" AS "t1" @@ -20,7 +21,7 @@ fn inner_join1() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( @@ -49,7 +50,7 @@ fn inner_join2() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( @@ -105,7 +106,7 @@ fn inner_join3() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment((Key { positions: vec![0] }).into()) @@ -115,13 +116,17 @@ fn inner_join3() { } // Check distribution of the join output tuple. - let mut join_node: Option<&Relational> = None; - for node in &plan.nodes.arena { - if let Node::Relational(rel) = node { - if matches!(rel, Relational::Join { .. }) { - join_node = Some(rel); - break; - } + let mut join_node = None; + for node in plan.nodes.arena64.iter().enumerate() { + if let Node64::Join(_) = node.1 { + join_node = Some( + plan.get_relation_node(NodeId { + offset: u32::try_from(node.0).unwrap(), + arena_type: crate::ir::node::ArenaType::Arena64, + }) + .unwrap(), + ); + break; } } let join = join_node.unwrap(); @@ -140,7 +145,7 @@ fn inner_join4() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( @@ -163,7 +168,7 @@ fn insert1() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( @@ -186,7 +191,7 @@ fn insert2() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::LocalSegment( @@ -209,7 +214,7 @@ fn insert3() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::LocalSegment( @@ -232,7 +237,7 @@ fn insert4() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment( @@ -255,7 +260,7 @@ fn insert5() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment(MotionKey { @@ -275,7 +280,7 @@ fn insert6() { plan.add_motions().unwrap(); let motion_id = *plan.slices.slice(0).unwrap().position(0).unwrap(); let motion = plan.get_relation_node(motion_id).unwrap(); - if let Relational::Motion { policy, .. } = motion { + if let Relational::Motion(Motion { policy, .. }) = motion { assert_eq!( *policy, MotionPolicy::Segment(MotionKey { diff --git a/sbroad-core/src/ir/transformation/split_columns.rs b/sbroad-core/src/ir/transformation/split_columns.rs index 4b9cfe655..b0281fc28 100644 --- a/sbroad-core/src/ir/transformation/split_columns.rs +++ b/sbroad-core/src/ir/transformation/split_columns.rs @@ -13,7 +13,8 @@ //! ``` use crate::errors::{Entity, SbroadError}; -use crate::ir::expression::{Expression, NodeId}; +use crate::ir::node::expression::Expression; +use crate::ir::node::{BoolExpr, NodeId, Row}; use crate::ir::operator::Bool; use crate::ir::transformation::OldNewTopIdPair; use crate::ir::Plan; @@ -54,9 +55,9 @@ impl Plan { 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 { + Expression::Bool(BoolExpr { left, op, right, .. - } => (*left, *right, op.clone()), + }) => (*left, *right, op.clone()), _ => { return Err(SbroadError::Invalid( Entity::Expression, @@ -66,15 +67,15 @@ impl Plan { )); } }; - let left_expr = self.get_expression_node(left_id)?; - let right_expr = self.get_expression_node(right_id)?; + let left_expr = &self.get_expression_node(left_id)?; + let right_expr = &self.get_expression_node(right_id)?; if let ( - Expression::Row { + Expression::Row(Row { list: left_list, .. - }, - Expression::Row { + }), + Expression::Row(Row { list: right_list, .. - }, + }), ) = (left_expr, right_expr) { if left_list.len() != right_list.len() { diff --git a/sbroad-core/src/ir/transformation/split_columns/tests.rs b/sbroad-core/src/ir/transformation/split_columns/tests.rs index 0c038731c..2bc461321 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: [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 }"#, + r#"Row(Row { list: [NodeId { offset: 7, arena_type: Arena64 }, NodeId { offset: 8, arena_type: Arena64 }, NodeId { offset: 9, arena_type: Arena64 }], distribution: None }),"#, + r#"Row(Row { list: [NodeId { offset: 10, arena_type: Arena64 }, NodeId { offset: 11, arena_type: Arena64 }], distribution: None })"#, ), format!("{plan_err}") ); diff --git a/sbroad-core/src/ir/tree.rs b/sbroad-core/src/ir/tree.rs index 761135770..245de3521 100644 --- a/sbroad-core/src/ir/tree.rs +++ b/sbroad-core/src/ir/tree.rs @@ -1,8 +1,8 @@ //! IR tree traversal module. -use super::{ - expression::{Expression, NodeId}, - Nodes, Plan, +use super::{node::expression::Expression, Nodes, Plan}; +use crate::ir::node::{ + Alias, ArithmeticExpr, BoolExpr, Case, Cast, Concat, ExprInParentheses, NodeId, Trim, UnaryExpr, }; use std::cell::RefCell; @@ -11,10 +11,10 @@ trait TreeIterator<'nodes> { fn get_child(&self) -> &RefCell<usize>; fn get_nodes(&self) -> &'nodes Nodes; - fn handle_trim(&mut self, expr: &'nodes Expression) -> Option<&'nodes NodeId> { - let Expression::Trim { + fn handle_trim(&mut self, expr: Expression) -> Option<NodeId> { + let Expression::Trim(Trim { pattern, target, .. - } = expr + }) = expr else { panic!("Trim expected") }; @@ -23,61 +23,58 @@ trait TreeIterator<'nodes> { 0 => { *self.get_child().borrow_mut() += 1; match pattern { - Some(_) => pattern.as_ref(), - None => Some(target), + Some(_) => *pattern, + None => Some(*target), } } 1 => { *self.get_child().borrow_mut() += 1; - match pattern { - Some(_) => Some(target), - None => None, - } + pattern.as_ref().map(|_| *target) } _ => None, } } - 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 + fn handle_left_right_children(&mut self, expr: Expression) -> Option<NodeId> { + let (Expression::Bool(BoolExpr { left, right, .. }) + | Expression::Arithmetic(ArithmeticExpr { left, right, .. }) + | Expression::Concat(Concat { left, right, .. })) = expr else { panic!("Expected expression with left and right children") }; let child_step = *self.get_child().borrow(); if child_step == 0 { *self.get_child().borrow_mut() += 1; - return Some(left); + return Some(*left); } else if child_step == 1 { *self.get_child().borrow_mut() += 1; - return Some(right); + return Some(*right); } None } - fn handle_single_child(&mut self, expr: &'nodes Expression) -> Option<&'nodes NodeId> { - let (Expression::Alias { child, .. } - | Expression::ExprInParentheses { child } - | Expression::Cast { child, .. } - | Expression::Unary { child, .. }) = expr + fn handle_single_child(&mut self, expr: Expression) -> Option<NodeId> { + let (Expression::Alias(Alias { child, .. }) + | Expression::ExprInParentheses(ExprInParentheses { child }) + | Expression::Cast(Cast { child, .. }) + | Expression::Unary(UnaryExpr { child, .. })) = expr else { panic!("Expected expression with single child") }; let step = *self.get_child().borrow(); *self.get_child().borrow_mut() += 1; if step == 0 { - return Some(child); + return Some(*child); } None } - fn handle_case_iter(&mut self, expr: &'nodes Expression) -> Option<&'nodes NodeId> { - let Expression::Case { + fn handle_case_iter(&mut self, expr: Expression) -> Option<NodeId> { + let Expression::Case(Case { search_expr, when_blocks, else_expr, - } = expr + }) = expr else { panic!("Case expression expected"); }; @@ -85,7 +82,7 @@ trait TreeIterator<'nodes> { *self.get_child().borrow_mut() += 1; if let Some(search_expr) = search_expr { if child_step == 0 { - return Some(search_expr); + return Some(*search_expr); } child_step -= 1; } @@ -97,16 +94,12 @@ trait TreeIterator<'nodes> { .get(when_blocks_index) .expect("When block must have been found."); return match index_reminder { - 0 => Some(cond_expr), - 1 => Some(res_expr), + 0 => Some(*cond_expr), + 1 => Some(*res_expr), _ => unreachable!("Impossible reminder"), }; } else if when_blocks_index == when_blocks.len() && index_reminder == 0 { - if let Some(else_expr) = else_expr { - Some(else_expr) - } else { - None - } + else_expr.as_ref().copied() } else { None }; diff --git a/sbroad-core/src/ir/tree/and.rs b/sbroad-core/src/ir/tree/and.rs index c3cfc3167..58940707d 100644 --- a/sbroad-core/src/ir/tree/and.rs +++ b/sbroad-core/src/ir/tree/and.rs @@ -1,7 +1,8 @@ use std::cell::RefCell; use super::TreeIterator; -use crate::ir::expression::{Expression, NodeId}; +use crate::ir::node::expression::Expression; +use crate::ir::node::{BoolExpr, NodeId}; use crate::ir::operator::Bool; use crate::ir::{Node, Nodes}; @@ -55,9 +56,9 @@ impl<'n> Iterator for AndIterator<'n> { 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 { + if let Some(Node::Expression(Expression::Bool(BoolExpr { left, op, right, .. - })) = node + }))) = node { if *op != Bool::And { return None; diff --git a/sbroad-core/src/ir/tree/expression.rs b/sbroad-core/src/ir/tree/expression.rs index faaac377a..5d708111b 100644 --- a/sbroad-core/src/ir/tree/expression.rs +++ b/sbroad-core/src/ir/tree/expression.rs @@ -1,7 +1,8 @@ use std::cell::RefCell; use super::TreeIterator; -use crate::ir::expression::{Expression, NodeId}; +use crate::ir::node::expression::Expression; +use crate::ir::node::{NodeId, Row, StableFunction}; use crate::ir::{Node, Nodes}; trait ExpressionTreeIterator<'nodes>: TreeIterator<'nodes> { @@ -39,13 +40,15 @@ impl<'n> Nodes { #[must_use] 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.get(current) - { - Expression::is_aggregate_name(name) - } else { - false - }; + let must_stop = + if let Some(Node::Expression(Expression::StableFunction(StableFunction { + name, .. + }))) = self.get(current) + { + Expression::is_aggregate_name(name) + } else { + false + }; AggregateIterator { inner: ExpressionIterator { current, @@ -82,7 +85,7 @@ impl<'n> Iterator for ExpressionIterator<'n> { type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { - expression_next(self).copied() + expression_next(self) } } @@ -93,14 +96,12 @@ impl<'n> Iterator for AggregateIterator<'n> { if self.must_stop { return None; } - expression_next(&mut self.inner).copied() + expression_next(&mut self.inner) } } #[allow(clippy::too_many_lines)] -fn expression_next<'nodes>( - iter: &mut impl ExpressionTreeIterator<'nodes>, -) -> Option<&'nodes NodeId> { +fn expression_next<'nodes>(iter: &mut impl ExpressionTreeIterator<'nodes>) -> Option<NodeId> { let node = iter.get_nodes().get(iter.get_current()); match node { Some(node) => { @@ -114,7 +115,7 @@ fn expression_next<'nodes>( Expression::Bool { .. } | Expression::Arithmetic { .. } | Expression::Concat { .. } => iter.handle_left_right_children(expr), - Expression::Row { list, .. } => { + Expression::Row(Row { list, .. }) => { let child_step = *iter.get_child().borrow(); let mut is_leaf = false; @@ -142,20 +143,20 @@ fn expression_next<'nodes>( None => return None, Some(child) => { *iter.get_child().borrow_mut() += 1; - return Some(child); + return Some(*child); } } } None } - Expression::StableFunction { children, .. } => { + Expression::StableFunction(StableFunction { children, .. }) => { let child_step = *iter.get_child().borrow(); match children.get(child_step) { None => None, Some(child) => { *iter.get_child().borrow_mut() += 1; - Some(child) + Some(*child) } } } @@ -163,14 +164,15 @@ fn expression_next<'nodes>( Expression::Case { .. } => iter.handle_case_iter(expr), Expression::Constant { .. } | Expression::Reference { .. } - | Expression::CountAsterisk => None, + | Expression::CountAsterisk { .. } => None, } } Node::Acl(_) | Node::Block(_) | Node::Ddl(_) | Node::Relational(_) - | Node::Parameter(..) => None, + | Node::Invalid(_) + | Node::Parameter(_) => None, } } None => None, diff --git a/sbroad-core/src/ir/tree/relation.rs b/sbroad-core/src/ir/tree/relation.rs index cc14584d1..6399b3097 100644 --- a/sbroad-core/src/ir/tree/relation.rs +++ b/sbroad-core/src/ir/tree/relation.rs @@ -1,9 +1,9 @@ use std::cell::RefCell; use super::TreeIterator; -use crate::ir::expression::NodeId; -use crate::ir::operator::Relational; -use crate::ir::{ArenaType, Node, Nodes}; +use crate::ir::node::relational::Relational; +use crate::ir::node::{ArenaType, GroupBy, Limit, NodeId, OrderBy, ScanCte}; +use crate::ir::{Node, Nodes}; trait RelationalTreeIterator<'nodes>: TreeIterator<'nodes> {} @@ -30,7 +30,7 @@ impl<'n> Nodes { #[must_use] pub fn empty_rel_iter(&'n self) -> RelationalIterator<'n> { RelationalIterator { - current: self.next_id(ArenaType::Default), + current: self.next_id(ArenaType::Arena64), child: RefCell::new(0), nodes: self, } @@ -57,13 +57,11 @@ impl<'n> Iterator for RelationalIterator<'n> { type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { - relational_next(self).copied() + relational_next(self) } } -fn relational_next<'nodes>( - iter: &mut impl RelationalTreeIterator<'nodes>, -) -> Option<&'nodes NodeId> { +fn relational_next<'nodes>(iter: &mut impl RelationalTreeIterator<'nodes>) -> Option<NodeId> { match iter.get_nodes().get(iter.get_current()) { Some(Node::Relational( node @ (Relational::Except { .. } @@ -86,27 +84,27 @@ fn relational_next<'nodes>( let children = node.children(); if step < children.len() { *iter.get_child().borrow_mut() += 1; - return children.get(step); + return children.get(step).copied(); } None } - Some(Node::Relational(Relational::GroupBy { children, .. })) => { + Some(Node::Relational(Relational::GroupBy(GroupBy { children, .. }))) => { let step = *iter.get_child().borrow(); if step == 0 { *iter.get_child().borrow_mut() += 1; - return children.get(step); + return children.get(step).copied(); } None } Some(Node::Relational( - Relational::OrderBy { child, .. } - | Relational::ScanCte { child, .. } - | Relational::Limit { child, .. }, + Relational::OrderBy(OrderBy { child, .. }) + | Relational::ScanCte(ScanCte { child, .. }) + | Relational::Limit(Limit { child, .. }), )) => { let step = *iter.get_child().borrow(); if step == 0 { *iter.get_child().borrow_mut() += 1; - return Some(child); + return Some(*child); } None } @@ -114,6 +112,7 @@ fn relational_next<'nodes>( Node::Relational(Relational::ScanRelation { .. }) | Node::Expression(_) | Node::Parameter(_) + | Node::Invalid(_) | Node::Ddl(_) | Node::Acl(_) | Node::Block(_), diff --git a/sbroad-core/src/ir/tree/subtree.rs b/sbroad-core/src/ir/tree/subtree.rs index 4612eae7d..fa3421862 100644 --- a/sbroad-core/src/ir/tree/subtree.rs +++ b/sbroad-core/src/ir/tree/subtree.rs @@ -2,8 +2,14 @@ use std::cell::RefCell; use std::cmp::Ordering; use super::{PlanTreeIterator, Snapshot, TreeIterator}; -use crate::ir::expression::{Expression, NodeId}; -use crate::ir::operator::{OrderByElement, OrderByEntity, Relational}; +use crate::ir::node::expression::Expression; +use crate::ir::node::relational::Relational; +use crate::ir::node::{ + Delete, Except, GroupBy, Having, Insert, Intersect, Join, Limit, Motion, NodeId, OrderBy, + Projection, Row, ScanCte, ScanRelation, ScanSubQuery, Selection, StableFunction, Union, + UnionAll, Update, Values, ValuesRow, +}; +use crate::ir::operator::{OrderByElement, OrderByEntity}; use crate::ir::{Node, Nodes, Plan}; trait SubtreePlanIterator<'plan>: PlanTreeIterator<'plan> { @@ -55,7 +61,7 @@ impl<'plan> Iterator for SubtreeIterator<'plan> { type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { - subtree_next(self, &Snapshot::Latest).copied() + subtree_next(self, &Snapshot::Latest) } } @@ -116,7 +122,7 @@ impl<'plan> Iterator for FlashbackSubtreeIterator<'plan> { type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { - subtree_next(self, &Snapshot::Oldest).copied() + subtree_next(self, &Snapshot::Oldest) } } @@ -173,7 +179,7 @@ impl<'plan> Iterator for ExecPlanSubtreeIterator<'plan> { type Item = NodeId; fn next(&mut self) -> Option<Self::Item> { - subtree_next(self, &Snapshot::Oldest).copied() + subtree_next(self, &Snapshot::Oldest) } } @@ -192,10 +198,14 @@ impl<'plan> Plan { fn subtree_next<'plan>( iter: &mut impl SubtreePlanIterator<'plan>, snapshot: &Snapshot, -) -> Option<&'plan NodeId> { +) -> Option<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::Invalid(..) + | Node::Parameter(..) + | Node::Ddl(..) + | Node::Acl(..) + | Node::Block(..) => None, Node::Expression(expr) => match expr { Expression::Alias { .. } | Expression::ExprInParentheses { .. } @@ -206,18 +216,18 @@ fn subtree_next<'plan>( | Expression::Arithmetic { .. } | Expression::Concat { .. } => iter.handle_left_right_children(expr), Expression::Trim { .. } => iter.handle_trim(expr), - Expression::Row { list, .. } - | Expression::StableFunction { children: list, .. } => { + Expression::Row(Row { list, .. }) + | Expression::StableFunction(StableFunction { children: list, .. }) => { let child_step = *iter.get_child().borrow(); return match list.get(child_step) { None => None, Some(child) => { *iter.get_child().borrow_mut() += 1; - Some(child) + Some(*child) } }; } - Expression::Constant { .. } | Expression::CountAsterisk => None, + Expression::Constant { .. } | Expression::CountAsterisk { .. } => None, Expression::Reference { .. } => { let step = *iter.get_child().borrow(); if step == 0 { @@ -242,21 +252,21 @@ fn subtree_next<'plan>( let parent = iter.get_plan().get_relation_node(parent_id); let mut is_additional = false; if let Ok( - Relational::Selection { children, .. } - | Relational::Having { children, .. }, + Relational::Selection(Selection { children, .. }) + | Relational::Having(Having { children, .. }), ) = parent { if children.iter().skip(1).any(|&c| c == *rel_id) { is_additional = true; } } - if let Ok(Relational::Join { children, .. }) = parent { + if let Ok(Relational::Join(Join { children, .. })) = parent { if children.iter().skip(2).any(|&c| c == *rel_id) { is_additional = true; } } if is_additional { - return Some(rel_id); + return Some(*rel_id); } } _ => {} @@ -267,24 +277,25 @@ fn subtree_next<'plan>( } }, Node::Relational(r) => match r { - Relational::Join { + Relational::Join(Join { children, condition, output, .. - } => { + }) => { let step = *iter.get_child().borrow(); *iter.get_child().borrow_mut() += 1; match step.cmp(&2) { Ordering::Less => { - return children.get(step); + return children.get(step).copied(); } Ordering::Equal => match snapshot { - Snapshot::Latest => Some(condition), + Snapshot::Latest => Some(*condition), Snapshot::Oldest => { return Some( - iter.get_plan() + *iter + .get_plan() .undo .get_oldest(condition) .map_or_else(|| condition, |id| id), @@ -293,76 +304,76 @@ fn subtree_next<'plan>( }, Ordering::Greater => { if step == 3 && iter.need_output() { - return Some(output); + return Some(*output); } None } } } - node @ (Relational::Except { output, .. } - | Relational::Insert { output, .. } - | Relational::Intersect { output, .. } - | Relational::Delete { output, .. } - | Relational::ScanSubQuery { output, .. } - | Relational::Union { output, .. } - | Relational::UnionAll { output, .. }) => { + ref node @ (Relational::Except(Except { output, .. }) + | Relational::Insert(Insert { output, .. }) + | Relational::Intersect(Intersect { output, .. }) + | Relational::Delete(Delete { output, .. }) + | Relational::ScanSubQuery(ScanSubQuery { output, .. }) + | Relational::Union(Union { output, .. }) + | Relational::UnionAll(UnionAll { output, .. })) => { let step = *iter.get_child().borrow(); let children = node.children(); if step < children.len() { *iter.get_child().borrow_mut() += 1; - return children.get(step); + return children.get(step).copied(); } if iter.need_output() && step == children.len() { *iter.get_child().borrow_mut() += 1; - return Some(output); + return Some(*output); } None } - Relational::ScanCte { child, output, .. } - | Relational::Limit { child, output, .. } => { + Relational::ScanCte(ScanCte { child, output, .. }) + | Relational::Limit(Limit { child, output, .. }) => { let step = *iter.get_child().borrow(); if step == 0 { *iter.get_child().borrow_mut() += 1; - return Some(child); + return Some(*child); } if iter.need_output() && step == 1 { *iter.get_child().borrow_mut() += 1; - return Some(output); + return Some(*output); } None } - Relational::GroupBy { + Relational::GroupBy(GroupBy { children, output, gr_cols, .. - } => { + }) => { let step = *iter.get_child().borrow(); if step == 0 { *iter.get_child().borrow_mut() += 1; - return children.get(step); + return children.get(step).copied(); } let col_idx = step - 1; if col_idx < gr_cols.len() { *iter.get_child().borrow_mut() += 1; - return gr_cols.get(col_idx); + return gr_cols.get(col_idx).copied(); } if iter.need_output() && col_idx == gr_cols.len() { *iter.get_child().borrow_mut() += 1; - return Some(output); + return Some(*output); } None } - Relational::OrderBy { + Relational::OrderBy(OrderBy { child, output, order_by_elements, - } => { + }) => { let step = *iter.get_child().borrow(); if step == 0 { *iter.get_child().borrow_mut() += 1; - return Some(child); + return Some(*child); } let mut col_idx = step - 1; while col_idx < order_by_elements.len() { @@ -375,83 +386,84 @@ fn subtree_next<'plan>( .. } = current_element { - return Some(expr_id); + return Some(*expr_id); } col_idx += 1; } if iter.need_output() && col_idx == order_by_elements.len() { *iter.get_child().borrow_mut() += 1; - return Some(output); + return Some(*output); } None } - Relational::Motion { + Relational::Motion(Motion { children, output, policy, .. - } => { + }) => { if policy.is_local() || iter.need_motion_subtree() { let step = *iter.get_child().borrow(); if step < children.len() { *iter.get_child().borrow_mut() += 1; - return children.get(step); + return children.get(step).copied(); } if iter.need_output() && step == children.len() { *iter.get_child().borrow_mut() += 1; - return Some(output); + return Some(*output); } } else { let step = *iter.get_child().borrow(); if iter.need_output() && step == 0 { *iter.get_child().borrow_mut() += 1; - return Some(output); + return Some(*output); } } None } - Relational::Values { + Relational::Values(Values { output, children, .. - } - | Relational::Update { + }) + | Relational::Update(Update { output, children, .. - } - | Relational::Projection { + }) + | Relational::Projection(Projection { output, children, .. - } => { + }) => { let step = *iter.get_child().borrow(); *iter.get_child().borrow_mut() += 1; if step == 0 { - return Some(output); + return Some(*output); } if step <= children.len() { - return children.get(step - 1); + return children.get(step - 1).copied(); } None } - Relational::Selection { + Relational::Selection(Selection { children, filter, output, .. - } - | Relational::Having { + }) + | Relational::Having(Having { children, filter, output, - } => { + }) => { let step = *iter.get_child().borrow(); *iter.get_child().borrow_mut() += 1; match step.cmp(&1) { Ordering::Less => { - return children.get(step); + return children.get(step).copied(); } Ordering::Equal => match snapshot { - Snapshot::Latest => Some(filter), + Snapshot::Latest => Some(*filter), Snapshot::Oldest => { return Some( - iter.get_plan() + *iter + .get_plan() .undo .get_oldest(filter) .map_or_else(|| filter, |id| id), @@ -460,31 +472,31 @@ fn subtree_next<'plan>( }, Ordering::Greater => { if step == 2 && iter.need_output() { - return Some(output); + return Some(*output); } None } } } - Relational::ValuesRow { data, output, .. } => { + Relational::ValuesRow(ValuesRow { data, output, .. }) => { let step = *iter.get_child().borrow(); *iter.get_child().borrow_mut() += 1; if step == 0 { - return Some(data); + return Some(*data); } if iter.need_output() && step == 1 { - return Some(output); + return Some(*output); } None } - Relational::ScanRelation { output, .. } => { + Relational::ScanRelation(ScanRelation { output, .. }) => { if iter.need_output() { let step = *iter.get_child().borrow(); *iter.get_child().borrow_mut() += 1; if step == 0 { - return Some(output); + return Some(*output); } } None diff --git a/sbroad-core/src/ir/tree/tests.rs b/sbroad-core/src/ir/tree/tests.rs index c188bbcce..4ae29bf83 100644 --- a/sbroad-core/src/ir/tree/tests.rs +++ b/sbroad-core/src/ir/tree/tests.rs @@ -1,9 +1,11 @@ +use crate::ir::node::expression::Expression; +use crate::ir::node::{Alias, ArenaType}; 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, LevelNode, PostOrder, EXPR_CAPACITY, REL_CAPACITY}; use crate::ir::value::Value; -use crate::ir::{ArenaType, Expression, Plan}; +use crate::ir::Plan; use pretty_assertions::assert_eq; use smol_str::SmolStr; @@ -221,7 +223,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(ArenaType::Default); + let a_ref = plan.nodes.next_id(ArenaType::Arena64); 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(); @@ -240,9 +242,9 @@ fn subtree_dfs_post() { .clone_row_list() .unwrap(); let alias_id = row_children.first().unwrap(); - let Expression::Alias { + let Expression::Alias(Alias { child: c_ref_id, .. - } = plan.get_expression_node(*alias_id).unwrap() + }) = plan.get_expression_node(*alias_id).unwrap() else { panic!("invalid child in the row"); }; diff --git a/sbroad-core/src/ir/undo.rs b/sbroad-core/src/ir/undo.rs index 828f5d67c..76a03c955 100644 --- a/sbroad-core/src/ir/undo.rs +++ b/sbroad-core/src/ir/undo.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use super::expression::NodeId; +use crate::ir::node::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 -- GitLab