From 300aa272177fe8a8e344b54511c72d74e37603a5 Mon Sep 17 00:00:00 2001 From: "ms.evilhat" <ms.evilhat@gmail.com> Date: Thu, 2 Feb 2023 09:21:11 +0300 Subject: [PATCH] test: add unit tests for arithmetic expessions --- sbroad-core/src/backend/sql/tree/tests.rs | 198 ++++++++- sbroad-core/src/frontend/sql/ast/tests.rs | 104 +++++ .../backend/sql/tree/arithmetic_plan.yaml | 383 ++++++++++++++++++ .../frontend/sql/arithmetic_ast.yaml | 90 ++++ 4 files changed, 774 insertions(+), 1 deletion(-) create mode 100644 sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_plan.yaml create mode 100644 sbroad-core/tests/artifactory/frontend/sql/arithmetic_ast.yaml diff --git a/sbroad-core/src/backend/sql/tree/tests.rs b/sbroad-core/src/backend/sql/tree/tests.rs index fc23af479b..49be7fcf1d 100644 --- a/sbroad-core/src/backend/sql/tree/tests.rs +++ b/sbroad-core/src/backend/sql/tree/tests.rs @@ -4,7 +4,7 @@ use std::path::Path; use pretty_assertions::assert_eq; use crate::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan}; -use crate::ir::operator::Bool; +use crate::ir::operator::{Arithmetic, Bool}; use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type}; use crate::ir::tree::Snapshot; use crate::ir::value::Value; @@ -89,3 +89,199 @@ fn sql_order_selection() { assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); // ) assert_eq!(None, nodes_iter.next()); } + +#[test] +fn sql_arithmetic_plan() { + // select a from t where a + (b/c + d*e) * f - b = 1 + let mut plan = Plan::default(); + let t = Table::new_seg( + "t", + vec![ + Column::new("a", Type::Integer, ColumnRole::User), + Column::new("b", Type::Integer, ColumnRole::User), + Column::new("c", Type::Integer, ColumnRole::User), + Column::new("d", Type::Integer, ColumnRole::User), + Column::new("e", Type::Integer, ColumnRole::User), + Column::new("f", Type::Integer, ColumnRole::User), + Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding), + ], + &["a"], + SpaceEngine::Memtx, + ) + .unwrap(); + plan.add_rel(t); + let scan_id = plan.add_scan("t", None).unwrap(); + let a_id = plan.add_row_from_child(scan_id, &["a"]).unwrap(); + let b_id = plan.add_row_from_child(scan_id, &["b"]).unwrap(); + let c_id = plan.add_row_from_child(scan_id, &["c"]).unwrap(); + let d_id = plan.add_row_from_child(scan_id, &["d"]).unwrap(); + let e_id = plan.add_row_from_child(scan_id, &["e"]).unwrap(); + let f_id = plan.add_row_from_child(scan_id, &["f"]).unwrap(); + let const_1 = plan.nodes.add_const(Value::from(1_u64)); + let const_row = plan.nodes.add_row(vec![const_1], None); + + // b/c + let arith_divide_id = plan + .add_arithmetic_to_plan(b_id, Arithmetic::Divide, c_id, false) + .unwrap(); + // d*e + let arith_multiply_id = plan + .add_arithmetic_to_plan(d_id, Arithmetic::Multiply, e_id, false) + .unwrap(); + // (b/c + d*e) + let arith_addition_id = plan + .add_arithmetic_to_plan(arith_divide_id, Arithmetic::Add, arith_multiply_id, true) + .unwrap(); + // (b/c + d*e) * f + let arith_multiply_id2 = plan + .add_arithmetic_to_plan(arith_addition_id, Arithmetic::Multiply, f_id, false) + .unwrap(); + // a + (b/c + d*e) * f + let arith_addition_id2 = plan + .add_arithmetic_to_plan(a_id, Arithmetic::Add, arith_multiply_id2, false) + .unwrap(); + // a + (b/c + d*e) * f - b + let arith_subract_id = plan + .add_arithmetic_to_plan(arith_addition_id2, Arithmetic::Subtract, b_id, false) + .unwrap(); + // a + (b/c + d*e) * f - b = 1 + let eq_id = plan + .nodes + .add_bool(arith_subract_id, Bool::Eq, const_row) + .unwrap(); + // where a + (b/c + d*e) * f - b = 1 + let select_id = plan.add_select(&[scan_id], eq_id).unwrap(); + + let proj_id = plan.add_proj(select_id, &["a"]).unwrap(); + plan.set_top(proj_id).unwrap(); + + // check the plan + let path = Path::new("") + .join("tests") + .join("artifactory") + .join("backend") + .join("sql") + .join("tree") + .join("arithmetic_plan.yaml"); + let s = fs::read_to_string(path).unwrap(); + let expected_plan = Plan::from_yaml(&s).unwrap(); + assert_eq!(expected_plan, plan); + + let exec_plan = ExecutionPlan::from(plan.clone()); + let top_id = exec_plan.get_ir_plan().get_top().unwrap(); + + // get nodes in the sql-convenient order + let sp = SyntaxPlan::new(&exec_plan, top_id, Snapshot::Latest).unwrap(); + let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); + let nodes = ordered.to_syntax_data().unwrap(); + let mut nodes_iter = nodes.into_iter(); + // projection + assert_eq!(Some(&SyntaxData::PlanId(56)), nodes_iter.next()); + // alias + assert_eq!(Some(&SyntaxData::PlanId(54)), nodes_iter.next()); + // ref + assert_eq!(Some(&SyntaxData::PlanId(53)), nodes_iter.next()); + // from + assert_eq!(Some(&SyntaxData::From), nodes_iter.next()); + // scan + assert_eq!(Some(&SyntaxData::PlanId(15)), nodes_iter.next()); + // selection + assert_eq!(Some(&SyntaxData::PlanId(52)), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(17)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // ref a + assert_eq!(Some(&SyntaxData::PlanId(16)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // arithmetic expression: [a] + [(b/c + d*e)] + assert_eq!(Some(&SyntaxData::PlanId(34)), nodes_iter.next()); + // arithmetic operator add (+) + assert_eq!(Some(&SyntaxData::Operator("+".into())), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // arithmetic expression add: ([b/c] + [d*e]) + assert_eq!(Some(&SyntaxData::PlanId(32)), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(19)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // ref b + assert_eq!(Some(&SyntaxData::PlanId(18)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // arithmetic expression divide: [b] / [c] + assert_eq!(Some(&SyntaxData::PlanId(30)), nodes_iter.next()); + // arithmetic operator divide (/) + assert_eq!(Some(&SyntaxData::Operator("/".into())), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(21)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // ref c + assert_eq!(Some(&SyntaxData::PlanId(20)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // arithmetic operator add (+) + assert_eq!(Some(&SyntaxData::Operator("+".into())), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(23)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // ref d + assert_eq!(Some(&SyntaxData::PlanId(22)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // arithmetic expression multiply: [d] * [e] + assert_eq!(Some(&SyntaxData::PlanId(31)), nodes_iter.next()); + // arithmetic operator multiply (*) + assert_eq!(Some(&SyntaxData::Operator("*".into())), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(25)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // ref e + assert_eq!(Some(&SyntaxData::PlanId(24)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // arithmetic expression multiply: [(b/c + d*e)] * f + assert_eq!(Some(&SyntaxData::PlanId(33)), nodes_iter.next()); + // arithmetic operator multiply (*) + assert_eq!(Some(&SyntaxData::Operator("*".into())), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(27)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // ref f + assert_eq!(Some(&SyntaxData::PlanId(26)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // arithmetic expression subtract: [a + (b/c + d*e) * f] - [b] + assert_eq!(Some(&SyntaxData::PlanId(35)), nodes_iter.next()); + // arithmetic operator subtract (-) + assert_eq!(Some(&SyntaxData::Operator("-".into())), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(19)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // ref b + assert_eq!(Some(&SyntaxData::PlanId(18)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + // bool expression eq: [a + (b/c + d*e) * f - b] = [1] + assert_eq!(Some(&SyntaxData::PlanId(36)), nodes_iter.next()); + // bool operator eq (=) + assert_eq!(Some(&SyntaxData::Operator("=".into())), nodes_iter.next()); + // row + assert_eq!(Some(&SyntaxData::PlanId(29)), nodes_iter.next()); + // ( + assert_eq!(Some(&SyntaxData::OpenParenthesis), nodes_iter.next()); + // parameter + assert_eq!(Some(&SyntaxData::Parameter(28)), nodes_iter.next()); + // ) + assert_eq!(Some(&SyntaxData::CloseParenthesis), nodes_iter.next()); + assert_eq!(None, nodes_iter.next()); +} diff --git a/sbroad-core/src/frontend/sql/ast/tests.rs b/sbroad-core/src/frontend/sql/ast/tests.rs index 2d46560c64..c1c2e1663a 100644 --- a/sbroad-core/src/frontend/sql/ast/tests.rs +++ b/sbroad-core/src/frontend/sql/ast/tests.rs @@ -182,3 +182,107 @@ fn invalid_condition() { format!("{ast}"), ) } + +#[test] +fn sql_arithmetic_ast() { + let ast = AbstractSyntaxTree::new("select a from t where a + b = 1").unwrap(); + + let path = Path::new("") + .join("tests") + .join("artifactory") + .join("frontend") + .join("sql") + .join("arithmetic_ast.yaml"); + + let s = fs::read_to_string(path).unwrap(); + let expected_ast = AbstractSyntaxTree::from_yaml(&s).unwrap(); + + assert_eq!(expected_ast, ast); + + let top = ast.top.unwrap(); + let mut dft_post = PostOrder::with_capacity(|node| ast.nodes.ast_iter(node), 64); + let mut iter = dft_post.iter(top); + + let (_, table_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(table_id).unwrap(); + assert_eq!(node.rule, Type::Table); + assert_eq!(node.value, Some("t".to_string())); + + let (_, scan_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(scan_id).unwrap(); + assert_eq!(node.rule, Type::Scan); + + let (_, sel_name_a_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(sel_name_a_id).unwrap(); + assert_eq!(node.rule, Type::ColumnName); + assert_eq!(node.value, Some("a".to_string())); + + let (_, a_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(a_id).unwrap(); + assert_eq!(node.rule, Type::Reference); + + let (_, col_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(col_id).unwrap(); + assert_eq!(node.rule, Type::Column); + + let (_, add_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(add_id).unwrap(); + assert_eq!(node.rule, Type::Add); + + let (_, sel_name_b_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(sel_name_b_id).unwrap(); + assert_eq!(node.rule, Type::ColumnName); + assert_eq!(node.value, Some("b".to_string())); + + let (_, b_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(b_id).unwrap(); + assert_eq!(node.rule, Type::Reference); + + let (_, col_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(col_id).unwrap(); + assert_eq!(node.rule, Type::Column); + + let (_, addition_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(addition_id).unwrap(); + assert_eq!(node.rule, Type::Addition); + + let (_, num_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(num_id).unwrap(); + assert_eq!(node.rule, Type::Unsigned); + assert_eq!(node.value, Some("1".to_string())); + + let (_, eq_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(eq_id).unwrap(); + assert_eq!(node.rule, Type::Eq); + + let (_, selection_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(selection_id).unwrap(); + assert_eq!(node.rule, Type::Selection); + + let (_, sel_name_a_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(sel_name_a_id).unwrap(); + assert_eq!(node.rule, Type::ColumnName); + assert_eq!(node.value, Some("a".to_string())); + + let (_, str_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(str_id).unwrap(); + assert_eq!(node.rule, Type::Reference); + + let (_, alias_name_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(alias_name_id).unwrap(); + assert_eq!(node.rule, Type::AliasName); + + let (_, alias_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(alias_id).unwrap(); + assert_eq!(node.rule, Type::Alias); + + let (_, col_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(col_id).unwrap(); + assert_eq!(node.rule, Type::Column); + + let (_, projection_id) = iter.next().unwrap(); + let node = ast.nodes.get_node(projection_id).unwrap(); + assert_eq!(node.rule, Type::Projection); + + assert_eq!(None, iter.next()); +} diff --git a/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_plan.yaml b/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_plan.yaml new file mode 100644 index 0000000000..111fee0449 --- /dev/null +++ b/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_plan.yaml @@ -0,0 +1,383 @@ +nodes: + arena: + # 0 + - Expression: + Reference: + parent: 15 + targets: ~ + position: 0 + # 1 + - Expression: + Alias: + name: a + child: 0 + # 2 + - Expression: + Reference: + parent: 15 + targets: ~ + position: 1 + # 3 + - Expression: + Alias: + name: b + child: 2 + # 4 + - Expression: + Reference: + parent: 15 + targets: ~ + position: 2 + # 5 + - Expression: + Alias: + name: c + child: 4 + # 6 + - Expression: + Reference: + parent: 15 + targets: ~ + position: 3 + # 7 + - Expression: + Alias: + name: d + child: 6 + # 8 + - Expression: + Reference: + parent: 15 + targets: ~ + position: 4 + # 9 + - Expression: + Alias: + name: e + child: 8 + # 10 + - Expression: + Reference: + parent: 15 + targets: ~ + position: 5 + # 11 + - Expression: + Alias: + name: f + child: 10 + # 12 + - Expression: + Reference: + parent: 15 + targets: ~ + position: 6 + # 13 + - Expression: + Alias: + name: bucket_id + child: 12 + # 14 + - Expression: + Row: + list: + - 1 + - 3 + - 5 + - 7 + - 9 + - 11 + - 13 + distribution: ~ + # 15 + - Relational: + ScanRelation: + output: 14 + relation: t + # 16 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 0 + # 17 + - Expression: + Row: + list: + - 16 + distribution: ~ + # 18 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 1 + # 19 + - Expression: + Row: + list: + - 18 + distribution: ~ + # 20 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 2 + # 21 + - Expression: + Row: + list: + - 20 + distribution: ~ + # 22 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 3 + # 23 + - Expression: + Row: + list: + - 22 + distribution: ~ + # 24 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 4 + # 25 + - Expression: + Row: + list: + - 24 + distribution: ~ + # 26 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 5 + # 27 + - Expression: + Row: + list: + - 26 + distribution: ~ + # 28 + - Expression: + Constant: + value: + Unsigned: 1 + # 29 + - Expression: + Row: + list: + - 28 + distribution: ~ + # 30 + - Expression: + Arithmetic: + left: 19 + op: divide + right: 21 + with_parentheses: false + # 31 + - Expression: + Arithmetic: + left: 23 + op: multiply + right: 25 + with_parentheses: false + # 32 + - Expression: + Arithmetic: + left: 30 + op: add + right: 31 + with_parentheses: true + # 33 + - Expression: + Arithmetic: + left: 32 + op: multiply + right: 27 + with_parentheses: false + # 34 + - Expression: + Arithmetic: + left: 17 + op: add + right: 33 + with_parentheses: false + # 35 + - Expression: + Arithmetic: + left: 34 + op: subtract + right: 19 + with_parentheses: false + # 36 + - Expression: + Bool: + left: 35 + op: eq + right: 29 + # 37 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 0 + # 38 + - Expression: + Alias: + name: a + child: 37 + # 39 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 1 + # 40 + - Expression: + Alias: + name: b + child: 39 + # 41 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 2 + # 42 + - Expression: + Alias: + name: c + child: 41 + # 43 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 3 + # 44 + - Expression: + Alias: + name: d + child: 43 + # 45 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 4 + # 46 + - Expression: + Alias: + name: e + child: 45 + # 47 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 5 + # 48 + - Expression: + Alias: + name: f + child: 47 + # 49 + - Expression: + Reference: + parent: 52 + targets: [0] + position: 6 + # 50 + - Expression: + Alias: + name: bucket_id + child: 49 + # 51 + - Expression: + Row: + list: + - 38 + - 40 + - 42 + - 44 + - 46 + - 48 + - 50 + distribution: ~ + # 52 + - Relational: + Selection: + children: + - 15 + filter: 36 + output: 51 + # 53 + - Expression: + Reference: + parent: 56 + targets: [0] + position: 0 + # 54 + - Expression: + Alias: + name: a + child: 53 + # 55 + - Expression: + Row: + list: + - 54 + distribution: ~ + # 56 + - Relational: + Projection: + children: + - 52 + output: 55 +relations: + tables: + t: + columns: + - name: a + type: Integer + role: User + - name: b + type: Integer + role: User + - name: c + type: Integer + role: User + - name: d + type: Integer + role: User + - name: e + type: Integer + role: User + - name: f + type: Integer + role: User + - name: bucket_id + type: Unsigned + role: Sharding + key: + positions: + - 0 + name: t + engine: Memtx +slices: + slices: [] +top: 56 +is_explain: false +undo: + log: {} +constants: {} diff --git a/sbroad-core/tests/artifactory/frontend/sql/arithmetic_ast.yaml b/sbroad-core/tests/artifactory/frontend/sql/arithmetic_ast.yaml new file mode 100644 index 0000000000..07d0be3fa2 --- /dev/null +++ b/sbroad-core/tests/artifactory/frontend/sql/arithmetic_ast.yaml @@ -0,0 +1,90 @@ +--- +nodes: + arena: + - children: + - 14 + rule: Select + value: ~ + - children: + - 12 + - 2 + rule: Selection + value: ~ + - children: + - 4 + - 3 + rule: Eq + value: ~ + - children: [] + rule: Unsigned + value: 1 + - children: + - 9 + - 8 + - 5 + rule: Addition + value: ~ + - children: + - 6 + rule: Column + value: ~ + - children: + - 7 + rule: Reference + value: ~ + - children: [] + rule: ColumnName + value: "b" + - children: [] + rule: Add + value: "+" + - children: + - 10 + rule: Column + value: ~ + - children: + - 11 + rule: Reference + value: ~ + - children: [] + rule: ColumnName + value: "a" + - children: + - 13 + rule: Scan + value: ~ + - children: [] + rule: Table + value: "t" + - children: + - 1 + - 15 + rule: Projection + value: ~ + - children: + - 19 + rule: Column + value: ~ + - children: + - 17 + rule: Reference + value: ~ + - children: [] + rule: ColumnName + value: "a" + - children: [] + rule: AliasName + value: "a" + - children: + - 16 + - 18 + rule: Alias + value: ~ +top: 14 +map: + 16: + - 1 + 6: + - 12 + 10: + - 12 \ No newline at end of file -- GitLab