diff --git a/sbroad-benches/benches/parse.rs b/sbroad-benches/benches/parse.rs index 7bc8e5f9b50b8a43f6316b5e9cf7ccdc162c596d..455221808298a99b03a1ccb047818ba8d75bd2ac 100644 --- a/sbroad-benches/benches/parse.rs +++ b/sbroad-benches/benches/parse.rs @@ -1,6 +1,7 @@ use criterion::{criterion_group, criterion_main, Criterion}; use sbroad::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan}; use sbroad::executor::Query; +use sbroad::ir::tree::Snapshot; use sbroad::ir::value::Value; use sbroad_benches::engine::RouterRuntimeMock; @@ -237,7 +238,7 @@ fn query1(pattern: &str, params: Vec<Value>, engine: &mut RouterRuntimeMock) { let top_id = query.get_exec_plan().get_ir_plan().get_top().unwrap(); let buckets = query.bucket_discovery(top_id).unwrap(); let plan = query.get_exec_plan(); - let sp = SyntaxPlan::new(plan, top_id).unwrap(); + let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest).unwrap(); let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); let nodes = ordered.to_syntax_data().unwrap(); plan.to_sql(&nodes, &buckets).unwrap(); diff --git a/sbroad-benches/src/engine.rs b/sbroad-benches/src/engine.rs index 47e5ff30a87682b14d20b3b41e6d694c82bf7df9..e87a52b35eb1c1e162d5aeb0900ac5f5c8d04256 100644 --- a/sbroad-benches/src/engine.rs +++ b/sbroad-benches/src/engine.rs @@ -17,6 +17,7 @@ use sbroad::executor::vtable::VirtualTable; use sbroad::frontend::sql::ast::AbstractSyntaxTree; use sbroad::ir::function::Function; use sbroad::ir::relation::{Column, ColumnRole, Table, Type}; +use sbroad::ir::tree::Snapshot; use sbroad::ir::value::Value; use sbroad::ir::Plan; @@ -431,7 +432,7 @@ impl Coordinator for RouterRuntimeMock { buckets: &Buckets, ) -> Result<Box<dyn Any>, QueryPlannerError> { let result = ProducerResult::new(); - let sp = SyntaxPlan::new(plan, top_id)?; + let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest)?; let ordered = OrderedSyntaxNodes::try_from(sp)?; let nodes = ordered.to_syntax_data()?; plan.to_sql(&nodes, buckets)?; diff --git a/sbroad-cartridge/src/cartridge/router.rs b/sbroad-cartridge/src/cartridge/router.rs index fd7ed9a2c0afe136eded9a96e62f10b5dc60d3cf..cdad68b649e297f142d638c6efd839ae9109ec40 100644 --- a/sbroad-cartridge/src/cartridge/router.rs +++ b/sbroad-cartridge/src/cartridge/router.rs @@ -30,6 +30,7 @@ use sbroad::executor::result::ProducerResult; use sbroad::executor::vtable::VirtualTable; use sbroad::frontend::sql::ast::AbstractSyntaxTree; use sbroad::ir::helpers::RepeatableState; +use sbroad::ir::tree::Snapshot; use sbroad::ir::value::Value; use sbroad::ir::Plan; use sbroad::otm::child_span; @@ -185,7 +186,7 @@ impl Coordinator for RouterRuntime { top_id: usize, buckets: &Buckets, ) -> Result<Box<dyn Any>, QueryPlannerError> { - let sp = SyntaxPlan::new(plan, top_id)?; + let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest)?; let ordered = OrderedSyntaxNodes::try_from(sp)?; let nodes = ordered.to_syntax_data()?; let is_data_modifier = plan.subtree_modifies_data(top_id)?; diff --git a/sbroad-cartridge/test_app/test/data/test_data.lua b/sbroad-cartridge/test_app/test/data/test_data.lua index 4770dfa22c3ddb56c68b1db114ce380296778420..f36b66d55cbe913d23af09d9687a35ecd57814bd 100644 --- a/sbroad-cartridge/test_app/test/data/test_data.lua +++ b/sbroad-cartridge/test_app/test/data/test_data.lua @@ -1,5 +1,15 @@ local vsa_proxy_records = { - { 6659253, -20191, 0, "111", box.NULL, "{\"inn\":1234567890\"\",\"name\":\"КÐПИБÐРРТЮЛЕÐЬ ВОМБÐТОВИЧ\"}", "", box.NULL, box.NULL }, + { + 6659253, + -20191, + 0, + "111", + box.NULL, + "{\"inn\":1234567890\"\",\"name\":\"КÐПИБÐРРТЮЛЕÐЬ ВОМБÐТОВИЧ\"}", + "", + box.NULL, + box.NULL + }, } return { diff --git a/sbroad-cartridge/test_app/test/integration/large_query_test.lua b/sbroad-cartridge/test_app/test/integration/large_query_test.lua index 3dfaa876746d5bdbce66c411dffa40ef8b0a9088..bbf9e530a8006d34d124f5349bacf69cd049c258 100644 --- a/sbroad-cartridge/test_app/test/integration/large_query_test.lua +++ b/sbroad-cartridge/test_app/test/integration/large_query_test.lua @@ -116,8 +116,12 @@ g.before_all( local _, err = api:call( "sbroad.execute", { - [[INSERT INTO "VSA_PROXY" - ("fid","date_start","date_end","common_id","exclude_id", "common_text", "common_detail", "typology_type", "typology_id") + [[INSERT INTO "VSA_PROXY" ( + "fid", "date_start", "date_end", + "common_id", "exclude_id", + "common_text", "common_detail", + "typology_type", "typology_id" + ) VALUES (?,?,?,?,?,?,?,?,?)]], rec } diff --git a/sbroad-core/src/backend/sql/ir/tests.rs b/sbroad-core/src/backend/sql/ir/tests.rs index 1c34f1f83e8baad40a94709562def36ae5df910f..27146258d47cd0818d0bf9f563f2532fa9330f18 100644 --- a/sbroad-core/src/backend/sql/ir/tests.rs +++ b/sbroad-core/src/backend/sql/ir/tests.rs @@ -6,337 +6,45 @@ use crate::executor::engine::mock::RouterConfigurationMock; use crate::executor::ir::ExecutionPlan; use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::frontend::Ast; -use crate::ir::value::Value; +use crate::ir::tree::Snapshot; use super::*; -#[test] -fn one_table_projection() { - let query = r#"SELECT "identification_number", "product_code" - FROM "hash_testing" - WHERE "identification_number" = 1"#; - - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {}", - r#"SELECT "hash_testing"."identification_number","#, - r#""hash_testing"."product_code""#, - r#"FROM "hash_testing""#, - r#"WHERE ("hash_testing"."identification_number") = (?)"#, - ), - vec![Value::from(1_u64)] - ), - sql - ); -} - -#[test] -fn one_table_with_asterisk() { - let query = r#"SELECT * - FROM "hash_testing" - WHERE "identification_number" = 1"#; - - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {} {}", - r#"SELECT "hash_testing"."identification_number","#, - r#""hash_testing"."product_code","#, - r#""hash_testing"."product_units", "hash_testing"."sys_op""#, - r#"FROM "hash_testing""#, - r#"WHERE ("hash_testing"."identification_number") = (?)"# - ), - vec![Value::from(1_u64)] - ), - sql - ); -} - -#[test] -fn union_all() { - let query = r#"SELECT "product_code" - FROM "hash_testing" - WHERE "identification_number" = 1 - UNION ALL - SELECT "product_code" - FROM "hash_testing_hist" - WHERE "product_code" = 'a' - "#; - - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {} {}", - r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, - r#"WHERE ("hash_testing"."identification_number") = (?)"#, - r#"UNION ALL"#, - r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#, - r#"WHERE ("hash_testing_hist"."product_code") = (?)"# - ), - vec![Value::from(1_u64), Value::from("a")], - ), - sql - ); -} - -#[test] -fn from_sub_query() { - let query = r#"SELECT "product_code" - FROM (SELECT "product_code" - FROM "hash_testing" - WHERE "identification_number" = 1) as t1 - WHERE "product_code" = 'a'"#; - - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {}", - r#"SELECT "T1"."product_code" FROM"#, - r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#, - r#"WHERE ("hash_testing"."identification_number") = (?)) as "T1""#, - r#"WHERE ("T1"."product_code") = (?)"# - ), - vec![Value::from(1_u64), Value::from("a")], - ), - sql - ); -} - -#[test] -fn from_sub_query_with_union() { - let query = r#"SELECT "product_code" - FROM (SELECT "product_code" - FROM "hash_testing" - WHERE "identification_number" = 1 - UNION ALL - SELECT "product_code" - FROM "hash_testing_hist" - WHERE "product_code" = 'a') as "t1" - WHERE "product_code" = 'a'"#; - +fn check_sql_with_snapshot(query: &str, expected: PatternWithParams, snapshot: Snapshot) { let metadata = &RouterConfigurationMock::new(); let ast = AbstractSyntaxTree::new(query).unwrap(); let mut plan = ast.resolve_metadata(metadata).unwrap(); plan.bind_params(vec![]).unwrap(); + plan.replace_in_operator().unwrap(); + plan.split_columns().unwrap(); + plan.set_dnf().unwrap(); + plan.derive_equalities().unwrap(); + plan.merge_tuples().unwrap(); let ex_plan = ExecutionPlan::from(plan); let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); + let sp = SyntaxPlan::new(&ex_plan, top_id, snapshot).unwrap(); let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); let nodes = ordered.to_syntax_data().unwrap(); let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {} {} {} {}", - r#"SELECT "t1"."product_code" FROM"#, - r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#, - r#"WHERE ("hash_testing"."identification_number") = (?)"#, - r#"UNION ALL"#, - r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#, - r#"WHERE ("hash_testing_hist"."product_code") = (?)) as "t1""#, - r#"WHERE ("t1"."product_code") = (?)"#, - ), - vec![Value::from(1_u64), Value::from("a"), Value::from("a")], - ), - sql - ); + assert_eq!(expected, sql,); } -#[test] -fn inner_join() { - let query = r#"SELECT "product_code" FROM "hash_testing" join "history" - on "hash_testing"."identification_number" = "history"."id" - WHERE "product_code" = 'a'"#; +#[cfg(test)] +mod except; - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); +#[cfg(test)] +mod projection; - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); +#[cfg(test)] +mod inner_join; - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {} {} {} {} {}", - r#"SELECT "hash_testing"."product_code""#, - r#"FROM (SELECT "hash_testing"."identification_number","#, - r#""hash_testing"."product_code","#, - r#""hash_testing"."product_units","#, - r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#, - r#"INNER JOIN (SELECT "history"."id" FROM "history") as "history""#, - r#"ON ("hash_testing"."identification_number") = ("history"."id")"#, - r#"WHERE ("hash_testing"."product_code") = (?)"#, - ), - vec![Value::from("a")], - ), - sql - ); -} +#[cfg(test)] +mod selection; -#[test] -fn inner_join_with_sq() { - let query = r#"SELECT "product_code" FROM "hash_testing" join - (SELECT * FROM "history" WHERE "id" = 1) as "t" - on "hash_testing"."identification_number" = "t"."id" - WHERE "product_code" = 'a'"#; - - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {} {} {} {} {} {}", - r#"SELECT "hash_testing"."product_code" FROM (SELECT"#, - r#""hash_testing"."identification_number","#, - r#""hash_testing"."product_code","#, - r#""hash_testing"."product_units","#, - r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#, - r#"INNER JOIN"#, - r#"(SELECT "history"."id" FROM "history" WHERE ("history"."id") = (?)) as "t""#, - r#"ON ("hash_testing"."identification_number") = ("t"."id")"#, - r#"WHERE ("hash_testing"."product_code") = (?)"#, - ), - vec![Value::from(1_u64), Value::from("a")], - ), - sql - ); -} +#[cfg(test)] +mod sub_query; -#[test] -fn selection_with_sq() { - let query = r#"SELECT "product_code" FROM "hash_testing" - WHERE "identification_number" in - (SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'b') and "product_code" < 'a'"#; - - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {} {}", - r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, - r#"WHERE ("hash_testing"."identification_number") in"#, - r#"(SELECT "hash_testing_hist"."identification_number" FROM "hash_testing_hist""#, - r#"WHERE ("hash_testing_hist"."product_code") = (?))"#, - r#"and ("hash_testing"."product_code") < (?)"#, - ), - vec![Value::from("b"), Value::from("a")], - ), - sql - ); -} - -#[test] -fn except() { - let query = r#"SELECT "id" - FROM "test_space" - WHERE "sysFrom" = 1 - EXCEPT DISTINCT - SELECT "id" - FROM "test_space" - WHERE "FIRST_NAME" = 'a' - "#; - - let metadata = &RouterConfigurationMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.resolve_metadata(metadata).unwrap(); - plan.bind_params(vec![]).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); - let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); - let nodes = ordered.to_syntax_data().unwrap(); - let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap(); - - assert_eq!( - PatternWithParams::new( - format!( - "{} {} {} {} {}", - r#"SELECT "test_space"."id" FROM "test_space""#, - r#"WHERE ("test_space"."sysFrom") = (?)"#, - r#"EXCEPT"#, - r#"SELECT "test_space"."id" FROM "test_space""#, - r#"WHERE ("test_space"."FIRST_NAME") = (?)"# - ), - vec![Value::from(1_u64), Value::from("a")], - ), - sql - ); -} +#[cfg(test)] +mod union_all; diff --git a/sbroad-core/src/backend/sql/ir/tests/except.rs b/sbroad-core/src/backend/sql/ir/tests/except.rs new file mode 100644 index 0000000000000000000000000000000000000000..b12eb3069619a6efcd267c2fe7a84dbc56e49561 --- /dev/null +++ b/sbroad-core/src/backend/sql/ir/tests/except.rs @@ -0,0 +1,51 @@ +use super::*; +use crate::ir::tree::Snapshot; +use crate::ir::value::Value; + +#[test] +fn except1_latest() { + let query = r#"SELECT "id" + FROM "test_space" + WHERE "sysFrom" = 1 + EXCEPT DISTINCT + SELECT "id" + FROM "test_space" + WHERE "FIRST_NAME" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "test_space"."id" FROM "test_space""#, + r#"WHERE ("test_space"."sysFrom") = (?)"#, + r#"EXCEPT"#, + r#"SELECT "test_space"."id" FROM "test_space""#, + r#"WHERE ("test_space"."FIRST_NAME") = (?)"# + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn except1_oldest() { + let query = r#"SELECT "id" + FROM "test_space" + WHERE "sysFrom" = 1 + EXCEPT DISTINCT + SELECT "id" + FROM "test_space" + WHERE "FIRST_NAME" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "test_space"."id" FROM "test_space""#, + r#"WHERE ("test_space"."sysFrom") = (?)"#, + r#"EXCEPT"#, + r#"SELECT "test_space"."id" FROM "test_space""#, + r#"WHERE ("test_space"."FIRST_NAME") = (?)"# + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} diff --git a/sbroad-core/src/backend/sql/ir/tests/inner_join.rs b/sbroad-core/src/backend/sql/ir/tests/inner_join.rs new file mode 100644 index 0000000000000000000000000000000000000000..2c714a7e85acae8e19b5c4c0fbe64313273a0e9d --- /dev/null +++ b/sbroad-core/src/backend/sql/ir/tests/inner_join.rs @@ -0,0 +1,99 @@ +use super::*; +use crate::ir::tree::Snapshot; +use crate::ir::value::Value; + +#[test] +fn inner_join1_latest() { + let query = r#"SELECT "product_code" FROM "hash_testing" join "history" + on "hash_testing"."identification_number" = "history"."id" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {} {} {} {}", + r#"SELECT "hash_testing"."product_code""#, + r#"FROM (SELECT "hash_testing"."identification_number","#, + r#""hash_testing"."product_code","#, + r#""hash_testing"."product_units","#, + r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#, + r#"INNER JOIN (SELECT "history"."id" FROM "history") as "history""#, + r#"ON ("hash_testing"."identification_number") = ("history"."id")"#, + r#"WHERE ("hash_testing"."product_code") = (?)"#, + ), + vec![Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn inner_join1_oldest() { + let query = r#"SELECT "product_code" FROM "hash_testing" join "history" + on "hash_testing"."identification_number" = "history"."id" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {} {} {} {}", + r#"SELECT "hash_testing"."product_code""#, + r#"FROM (SELECT "hash_testing"."identification_number","#, + r#""hash_testing"."product_code","#, + r#""hash_testing"."product_units","#, + r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#, + r#"INNER JOIN (SELECT "history"."id" FROM "history") as "history""#, + r#"ON ("hash_testing"."identification_number") = ("history"."id")"#, + r#"WHERE ("hash_testing"."product_code") = (?)"#, + ), + vec![Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} + +#[test] +fn inner_join2_latest() { + let query = r#"SELECT "product_code" FROM "hash_testing" join + (SELECT * FROM "history" WHERE "id" = 1) as "t" + on "hash_testing"."identification_number" = "t"."id" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {} {} {} {} {}", + r#"SELECT "hash_testing"."product_code" FROM (SELECT"#, + r#""hash_testing"."identification_number","#, + r#""hash_testing"."product_code","#, + r#""hash_testing"."product_units","#, + r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#, + r#"INNER JOIN"#, + r#"(SELECT "history"."id" FROM "history" WHERE ("history"."id") = (?)) as "t""#, + r#"ON ("hash_testing"."identification_number") = ("t"."id")"#, + r#"WHERE ("hash_testing"."product_code") = (?)"#, + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn inner_join2_oldest() { + let query = r#"SELECT "product_code" FROM "hash_testing" join + (SELECT * FROM "history" WHERE "id" = 1) as "t" + on "hash_testing"."identification_number" = "t"."id" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {} {} {} {} {}", + r#"SELECT "hash_testing"."product_code" FROM (SELECT"#, + r#""hash_testing"."identification_number","#, + r#""hash_testing"."product_code","#, + r#""hash_testing"."product_units","#, + r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#, + r#"INNER JOIN"#, + r#"(SELECT "history"."id" FROM "history" WHERE ("history"."id") = (?)) as "t""#, + r#"ON ("hash_testing"."identification_number") = ("t"."id")"#, + r#"WHERE ("hash_testing"."product_code") = (?)"#, + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} diff --git a/sbroad-core/src/backend/sql/ir/tests/projection.rs b/sbroad-core/src/backend/sql/ir/tests/projection.rs new file mode 100644 index 0000000000000000000000000000000000000000..57c1b248b20dc1591ac9a8193808891bab02e71a --- /dev/null +++ b/sbroad-core/src/backend/sql/ir/tests/projection.rs @@ -0,0 +1,79 @@ +use super::*; +use crate::ir::tree::Snapshot; +use crate::ir::value::Value; + +#[test] +fn projection1_latest() { + let query = r#"SELECT "identification_number", "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {}", + r#"SELECT "hash_testing"."identification_number","#, + r#""hash_testing"."product_code""#, + r#"FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"#, + ), + vec![Value::from(1_u64)], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn projection1_oldest() { + let query = r#"SELECT "identification_number", "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {}", + r#"SELECT "hash_testing"."identification_number","#, + r#""hash_testing"."product_code""#, + r#"FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"#, + ), + vec![Value::from(1_u64)], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} + +#[test] +fn projection2_latest() { + let query = r#"SELECT * + FROM "hash_testing" + WHERE "identification_number" = 1"#; + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "hash_testing"."identification_number","#, + r#""hash_testing"."product_code","#, + r#""hash_testing"."product_units", "hash_testing"."sys_op""#, + r#"FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"# + ), + vec![Value::from(1_u64)], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn projection2_oldest() { + let query = r#"SELECT * + FROM "hash_testing" + WHERE "identification_number" = 1"#; + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "hash_testing"."identification_number","#, + r#""hash_testing"."product_code","#, + r#""hash_testing"."product_units", "hash_testing"."sys_op""#, + r#"FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"# + ), + vec![Value::from(1_u64)], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} diff --git a/sbroad-core/src/backend/sql/ir/tests/selection.rs b/sbroad-core/src/backend/sql/ir/tests/selection.rs new file mode 100644 index 0000000000000000000000000000000000000000..0759275feeb8a00dfdd0f35b4d7baa400f64f331 --- /dev/null +++ b/sbroad-core/src/backend/sql/ir/tests/selection.rs @@ -0,0 +1,600 @@ +use super::*; +use crate::ir::tree::Snapshot; +use crate::ir::value::Value; + +#[test] +fn selection1_latest() { + let query = r#"SELECT "product_code" FROM "hash_testing" + WHERE "identification_number" in + (SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'b') and "product_code" < 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."product_code") < (?)"#, + r#"and ("hash_testing"."identification_number") in"#, + r#"(SELECT "hash_testing_hist"."identification_number" FROM "hash_testing_hist""#, + r#"WHERE ("hash_testing_hist"."product_code") = (?))"#, + ), + vec![Value::from("a"), Value::from("b")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn selection1_oldest() { + let query = r#"SELECT "product_code" FROM "hash_testing" + WHERE "identification_number" in + (SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'b') and "product_code" < 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") in"#, + r#"(SELECT "hash_testing_hist"."identification_number" FROM "hash_testing_hist""#, + r#"WHERE ("hash_testing_hist"."product_code") = (?))"#, + r#"and ("hash_testing"."product_code") < (?)"#, + ), + vec![Value::from("b"), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} + +#[test] +fn selection2_latest() { + let query = r#"SELECT "product_code" FROM "hash_testing" + WHERE "identification_number" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717) + AND "product_code" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717) + AND "identification_number" < "product_code" + AND ("product_units" <> "sys_op" OR "product_units" IS NULL)"#; + + let expected = PatternWithParams::new( + [ + r#"SELECT "hash_testing"."product_code" FROM "hash_testing" WHERE (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op")"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#, + r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and ("hash_testing"."product_units") is null)"#, + ].join(" "), + vec![ + Value::from(6659253_u64), + Value::from(6659253_u64), + Value::from(6659253_u64), + Value::from(6659253_u64), + Value::from(6659253_u64), + Value::from(-21_i64), + Value::from(6659253_u64), + Value::from(-21_i64), + Value::from(6659253_u64), + Value::from(5933116_u64), + Value::from(6659253_u64), + Value::from(5933116_u64), + Value::from(6659253_u64), + Value::from(8257405_u64), + Value::from(6659253_u64), + Value::from(8257405_u64), + Value::from(6659253_u64), + Value::from(3676468_u64), + Value::from(6659253_u64), + Value::from(3676468_u64), + Value::from(6659253_u64), + Value::from(6580234_u64), + Value::from(6659253_u64), + Value::from(6580234_u64), + Value::from(6659253_u64), + Value::from(9557717_u64), + Value::from(6659253_u64), + Value::from(9557717_u64), + Value::from(-21_i64), + Value::from(6659253_u64), + Value::from(-21_i64), + Value::from(6659253_u64), + Value::from(-21_i64), + Value::from(-21_i64), + Value::from(-21_i64), + Value::from(-21_i64), + Value::from(-21_i64), + Value::from(5933116_u64), + Value::from(-21_i64), + Value::from(5933116_u64), + Value::from(-21_i64), + Value::from(8257405_u64), + Value::from(-21_i64), + Value::from(8257405_u64), + Value::from(-21_i64), + Value::from(3676468_u64), + Value::from(-21_i64), + Value::from(3676468_u64), + Value::from(-21_i64), + Value::from(6580234_u64), + Value::from(-21_i64), + Value::from(6580234_u64), + Value::from(-21_i64), + Value::from(9557717_u64), + Value::from(-21_i64), + Value::from(9557717_u64), + Value::from(5933116_u64), + Value::from(6659253_u64), + Value::from(5933116_u64), + Value::from(6659253_u64), + Value::from(5933116_u64), + Value::from(-21_i64), + Value::from(5933116_u64), + Value::from(-21_i64), + Value::from(5933116_u64), + Value::from(5933116_u64), + Value::from(5933116_u64), + Value::from(5933116_u64), + Value::from(5933116_u64), + Value::from(8257405_u64), + Value::from(5933116_u64), + Value::from(8257405_u64), + Value::from(5933116_u64), + Value::from(3676468_u64), + Value::from(5933116_u64), + Value::from(3676468_u64), + Value::from(5933116_u64), + Value::from(6580234_u64), + Value::from(5933116_u64), + Value::from(6580234_u64), + Value::from(5933116_u64), + Value::from(9557717_u64), + Value::from(5933116_u64), + Value::from(9557717_u64), + Value::from(8257405_u64), + Value::from(6659253_u64), + Value::from(8257405_u64), + Value::from(6659253_u64), + Value::from(8257405_u64), + Value::from(-21_i64), + Value::from(8257405_u64), + Value::from(-21_i64), + Value::from(8257405_u64), + Value::from(5933116_u64), + Value::from(8257405_u64), + Value::from(5933116_u64), + Value::from(8257405_u64), + Value::from(8257405_u64), + Value::from(8257405_u64), + Value::from(8257405_u64), + Value::from(8257405_u64), + Value::from(3676468_u64), + Value::from(8257405_u64), + Value::from(3676468_u64), + Value::from(8257405_u64), + Value::from(6580234_u64), + Value::from(8257405_u64), + Value::from(6580234_u64), + Value::from(8257405_u64), + Value::from(9557717_u64), + Value::from(8257405_u64), + Value::from(9557717_u64), + Value::from(3676468_u64), + Value::from(6659253_u64), + Value::from(3676468_u64), + Value::from(6659253_u64), + Value::from(3676468_u64), + Value::from(-21_i64), + Value::from(3676468_u64), + Value::from(-21_i64), + Value::from(3676468_u64), + Value::from(5933116_u64), + Value::from(3676468_u64), + Value::from(5933116_u64), + Value::from(3676468_u64), + Value::from(8257405_u64), + Value::from(3676468_u64), + Value::from(8257405_u64), + Value::from(3676468_u64), + Value::from(3676468_u64), + Value::from(3676468_u64), + Value::from(3676468_u64), + Value::from(3676468_u64), + Value::from(6580234_u64), + Value::from(3676468_u64), + Value::from(6580234_u64), + Value::from(3676468_u64), + Value::from(9557717_u64), + Value::from(3676468_u64), + Value::from(9557717_u64), + Value::from(6580234_u64), + Value::from(6659253_u64), + Value::from(6580234_u64), + Value::from(6659253_u64), + Value::from(6580234_u64), + Value::from(-21_i64), + Value::from(6580234_u64), + Value::from(-21_i64), + Value::from(6580234_u64), + Value::from(5933116_u64), + Value::from(6580234_u64), + Value::from(5933116_u64), + Value::from(6580234_u64), + Value::from(8257405_u64), + Value::from(6580234_u64), + Value::from(8257405_u64), + Value::from(6580234_u64), + Value::from(3676468_u64), + Value::from(6580234_u64), + Value::from(3676468_u64), + Value::from(6580234_u64), + Value::from(6580234_u64), + Value::from(6580234_u64), + Value::from(6580234_u64), + Value::from(6580234_u64), + Value::from(9557717_u64), + Value::from(6580234_u64), + Value::from(9557717_u64), + Value::from(9557717_u64), + Value::from(6659253_u64), + Value::from(9557717_u64), + Value::from(6659253_u64), + Value::from(9557717_u64), + Value::from(-21_i64), + Value::from(9557717_u64), + Value::from(-21_i64), + Value::from(9557717_u64), + Value::from(5933116_u64), + Value::from(9557717_u64), + Value::from(5933116_u64), + Value::from(9557717_u64), + Value::from(8257405_u64), + Value::from(9557717_u64), + Value::from(8257405_u64), + Value::from(9557717_u64), + Value::from(3676468_u64), + Value::from(9557717_u64), + Value::from(3676468_u64), + Value::from(9557717_u64), + Value::from(6580234_u64), + Value::from(9557717_u64), + Value::from(6580234_u64), + Value::from(9557717_u64), + Value::from(9557717_u64), + Value::from(9557717_u64), + Value::from(9557717_u64), + ], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn selection2_oldest() { + let query = r#"SELECT "product_code" FROM "hash_testing" + WHERE "identification_number" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717) + AND "product_code" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717) + AND "identification_number" < "product_code" + AND ("product_units" <> "sys_op" OR "product_units" IS NULL)"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", + r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ((((((("hash_testing"."identification_number") = (?)"#, + r#"or ("hash_testing"."identification_number") = (?))"#, + r#"or ("hash_testing"."identification_number") = (?))"#, + r#"or ("hash_testing"."identification_number") = (?))"#, + r#"or ("hash_testing"."identification_number") = (?))"#, + r#"or ("hash_testing"."identification_number") = (?))"#, + r#"or ("hash_testing"."identification_number") = (?))"#, + r#"and ((((((("hash_testing"."product_code") = (?)"#, + r#"or ("hash_testing"."product_code") = (?))"#, + r#"or ("hash_testing"."product_code") = (?))"#, + r#"or ("hash_testing"."product_code") = (?))"#, + r#"or ("hash_testing"."product_code") = (?))"#, + r#"or ("hash_testing"."product_code") = (?))"#, + r#"or ("hash_testing"."product_code") = (?))"#, + r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#, + r#"and (("hash_testing"."product_units") <> ("hash_testing"."sys_op")"#, + r#"or ("hash_testing"."product_units") is null)"#, + ), + vec![ + Value::from(6659253_u64), + Value::from(-21_i64), + Value::from(5933116_u64), + Value::from(8257405_u64), + Value::from(3676468_u64), + Value::from(6580234_u64), + Value::from(9557717_u64), + Value::from(6659253_u64), + Value::from(-21_i64), + Value::from(5933116_u64), + Value::from(8257405_u64), + Value::from(3676468_u64), + Value::from(6580234_u64), + Value::from(9557717_u64), + ], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} diff --git a/sbroad-core/src/backend/sql/ir/tests/sub_query.rs b/sbroad-core/src/backend/sql/ir/tests/sub_query.rs new file mode 100644 index 0000000000000000000000000000000000000000..3b35a158fb097d2b501905236ccd44054a42d8da --- /dev/null +++ b/sbroad-core/src/backend/sql/ir/tests/sub_query.rs @@ -0,0 +1,101 @@ +use super::*; +use crate::ir::tree::Snapshot; +use crate::ir::value::Value; + +#[test] +fn sub_query1_latest() { + let query = r#"SELECT "product_code" + FROM (SELECT "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1) as t1 + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {}", + r#"SELECT "T1"."product_code" FROM"#, + r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)) as "T1""#, + r#"WHERE ("T1"."product_code") = (?)"# + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn sub_query1_oldest() { + let query = r#"SELECT "product_code" + FROM (SELECT "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1) as t1 + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {}", + r#"SELECT "T1"."product_code" FROM"#, + r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)) as "T1""#, + r#"WHERE ("T1"."product_code") = (?)"# + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} + +#[test] +fn sub_query2_latest() { + let query = r#"SELECT "product_code" + FROM (SELECT "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1 + UNION ALL + SELECT "product_code" + FROM "hash_testing_hist" + WHERE "product_code" = 'a') as "t1" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {} {} {}", + r#"SELECT "t1"."product_code" FROM"#, + r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"#, + r#"UNION ALL"#, + r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#, + r#"WHERE ("hash_testing_hist"."product_code") = (?)) as "t1""#, + r#"WHERE ("t1"."product_code") = (?)"#, + ), + vec![Value::from(1_u64), Value::from("a"), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn sub_query2_oldest() { + let query = r#"SELECT "product_code" + FROM (SELECT "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1 + UNION ALL + SELECT "product_code" + FROM "hash_testing_hist" + WHERE "product_code" = 'a') as "t1" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {} {} {}", + r#"SELECT "t1"."product_code" FROM"#, + r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"#, + r#"UNION ALL"#, + r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#, + r#"WHERE ("hash_testing_hist"."product_code") = (?)) as "t1""#, + r#"WHERE ("t1"."product_code") = (?)"#, + ), + vec![Value::from(1_u64), Value::from("a"), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} diff --git a/sbroad-core/src/backend/sql/ir/tests/union_all.rs b/sbroad-core/src/backend/sql/ir/tests/union_all.rs new file mode 100644 index 0000000000000000000000000000000000000000..008c27e87671a57031e6450d03b006ba57942cd9 --- /dev/null +++ b/sbroad-core/src/backend/sql/ir/tests/union_all.rs @@ -0,0 +1,51 @@ +use super::*; +use crate::ir::tree::Snapshot; +use crate::ir::value::Value; + +#[test] +fn union_all1_latest() { + let query = r#"SELECT "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1 + UNION ALL + SELECT "product_code" + FROM "hash_testing_hist" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"#, + r#"UNION ALL"#, + r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#, + r#"WHERE ("hash_testing_hist"."product_code") = (?)"# + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Latest); +} + +#[test] +fn union_all1_oldest() { + let query = r#"SELECT "product_code" + FROM "hash_testing" + WHERE "identification_number" = 1 + UNION ALL + SELECT "product_code" + FROM "hash_testing_hist" + WHERE "product_code" = 'a'"#; + + let expected = PatternWithParams::new( + format!( + "{} {} {} {} {}", + r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#, + r#"WHERE ("hash_testing"."identification_number") = (?)"#, + r#"UNION ALL"#, + r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#, + r#"WHERE ("hash_testing_hist"."product_code") = (?)"# + ), + vec![Value::from(1_u64), Value::from("a")], + ); + check_sql_with_snapshot(query, expected, Snapshot::Oldest); +} diff --git a/sbroad-core/src/backend/sql/tree.rs b/sbroad-core/src/backend/sql/tree.rs index a5b20f9aa6ca4824605ed7311fa5fb0173800056..8c1649d23d0b25c83d45dff5b4e21b7adef8bb31 100644 --- a/sbroad-core/src/backend/sql/tree.rs +++ b/sbroad-core/src/backend/sql/tree.rs @@ -11,6 +11,7 @@ use crate::executor::ir::ExecutionPlan; use crate::executor::vtable::VirtualTable; use crate::ir::expression::Expression; use crate::ir::operator::{Bool, Relational}; +use crate::ir::tree::Snapshot; use crate::ir::Node; use crate::otm::child_span; use sbroad_proc::otm_child_span; @@ -238,7 +239,10 @@ impl SyntaxNodes { /// - nothing was found fn get_syntax_node_id(&self, plan_id: usize) -> Result<usize, QueryPlannerError> { self.map.get(&plan_id).copied().ok_or_else(|| { - QueryPlannerError::CustomError("Current plan node is absent in the map".into()) + QueryPlannerError::CustomError(format!( + "Current plan node ({}) is absent in the map", + plan_id + )) }) } @@ -424,6 +428,7 @@ pub struct SyntaxPlan<'p> { pub(crate) nodes: SyntaxNodes, top: Option<usize>, plan: &'p ExecutionPlan, + snapshot: Snapshot, } #[allow(dead_code)] @@ -560,10 +565,17 @@ impl<'p> SyntaxPlan<'p> { let left_id = *children.first().ok_or_else(|| { QueryPlannerError::CustomError("Selection has no children.".into()) })?; + let filter_id = match self.snapshot { + Snapshot::Latest => *filter, + Snapshot::Oldest => *ir_plan + .undo + .get_oldest(filter) + .map_or_else(|| filter, |id| id), + }; let sn = SyntaxNode::new_pointer( id, Some(self.nodes.get_syntax_node_id(left_id)?), - vec![self.nodes.get_syntax_node_id(*filter)?], + vec![self.nodes.get_syntax_node_id(filter_id)?], ); Ok(self.nodes.push_syntax_node(sn)) } @@ -906,6 +918,7 @@ impl<'p> SyntaxPlan<'p> { nodes: SyntaxNodes::with_capacity(plan.get_ir_plan().next_id()), top: None, plan, + snapshot: Snapshot::Latest, } } @@ -916,17 +929,36 @@ impl<'p> SyntaxPlan<'p> { /// - Failed to get to the top of the syntax tree /// - Failed to move projection nodes under their scans #[otm_child_span("syntax.new")] - pub fn new(plan: &'p ExecutionPlan, top: usize) -> Result<Self, QueryPlannerError> { + pub fn new( + plan: &'p ExecutionPlan, + top: usize, + snapshot: Snapshot, + ) -> Result<Self, QueryPlannerError> { let mut sp = SyntaxPlan::empty(plan); + sp.snapshot = snapshot.clone(); let ir_plan = plan.get_ir_plan(); // Wrap plan's nodes and preserve their ids. - let dft_post = DftPost::new(&top, |node| ir_plan.subtree_iter(node)); - for (_, id) in dft_post { - // it works only for post-order traversal - let sn_id = sp.add_plan_node(*id)?; - if *id == top { - sp.set_top(sn_id)?; + match snapshot { + Snapshot::Latest => { + let dft_post = DftPost::new(&top, |node| ir_plan.subtree_iter(node)); + for (_, id) in dft_post { + // it works only for post-order traversal + let sn_id = sp.add_plan_node(*id)?; + if *id == top { + sp.set_top(sn_id)?; + } + } + } + Snapshot::Oldest => { + let dft_post = DftPost::new(&top, |node| ir_plan.flashback_subtree_iter(node)); + for (_, id) in dft_post { + // it works only for post-order traversal + let sn_id = sp.add_plan_node(*id)?; + if *id == top { + sp.set_top(sn_id)?; + } + } } } sp.move_proj_under_scan()?; diff --git a/sbroad-core/src/backend/sql/tree/tests.rs b/sbroad-core/src/backend/sql/tree/tests.rs index 14f59c512d482ae77bb909020e55f44887dbbcb4..efae9280b14f0824fec297b8d1ab44e9ab9a25a8 100644 --- a/sbroad-core/src/backend/sql/tree/tests.rs +++ b/sbroad-core/src/backend/sql/tree/tests.rs @@ -6,6 +6,7 @@ use pretty_assertions::assert_eq; use crate::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan}; use crate::ir::operator::Bool; use crate::ir::relation::{Column, ColumnRole, Table, Type}; +use crate::ir::tree::Snapshot; use crate::ir::value::Value; use crate::ir::Plan; @@ -49,7 +50,7 @@ fn sql_order_selection() { let top_id = exec_plan.get_ir_plan().get_top().unwrap(); // test the syntax plan - let sp = SyntaxPlan::new(&exec_plan, top_id).unwrap(); + let sp = SyntaxPlan::new(&exec_plan, top_id, Snapshot::Latest).unwrap(); let path = Path::new("") .join("tests") .join("artifactory") @@ -65,7 +66,7 @@ fn sql_order_selection() { 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).unwrap(); + 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(); diff --git a/sbroad-core/src/executor/engine/mock.rs b/sbroad-core/src/executor/engine/mock.rs index b49c677b77539ba3660ad12ab693484609bfe120..ed14cc3c04cb326c0dc82a47f71db1e70708139f 100644 --- a/sbroad-core/src/executor/engine/mock.rs +++ b/sbroad-core/src/executor/engine/mock.rs @@ -20,6 +20,7 @@ use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::ir::function::Function; use crate::ir::helpers::RepeatableState; use crate::ir::relation::{Column, ColumnRole, Table, Type}; +use crate::ir::tree::Snapshot; use crate::ir::value::Value; use crate::ir::Plan; @@ -318,7 +319,7 @@ impl Coordinator for RouterRuntimeMock { buckets: &Buckets, ) -> Result<Box<dyn Any>, QueryPlannerError> { let mut result = ProducerResult::new(); - let sp = SyntaxPlan::new(plan, top_id)?; + let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest)?; let ordered = OrderedSyntaxNodes::try_from(sp)?; let nodes = ordered.to_syntax_data()?; diff --git a/sbroad-core/src/executor/tests.rs b/sbroad-core/src/executor/tests.rs index 98f7167f86738ee04f451dbc1cc3880e4389665b..7554144cf4e4c1638d72ad4fcbbcdd49424cc380 100644 --- a/sbroad-core/src/executor/tests.rs +++ b/sbroad-core/src/executor/tests.rs @@ -114,7 +114,7 @@ fn map_reduce_query() { "{} {} {}", r#"SELECT "hash_testing"."product_code""#, r#"FROM "hash_testing""#, - r#"WHERE ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#, + r#"WHERE ("hash_testing"."identification_number") = (?) and ("hash_testing"."product_code") = (?)"#, ), vec![param1, param457], ) ) @@ -332,45 +332,39 @@ WHERE "t3"."id" = 2 AND "t8"."identification_number" = 2"#; let param2 = Value::from(2_u64); let bucket2 = query.coordinator.determine_bucket_id(&[¶m2]); - expected.rows.extend(vec![ - vec![ - Value::String(format!("Execute query on a bucket [{}]", bucket2)), - Value::String( - String::from( - PatternWithParams::new( - format!( - "{}, {}, {} {}{} {} {} {} {} {} {}{} {} {}{} {} {}", - r#"SELECT "t3"."id""#, - r#""t3"."FIRST_NAME""#, - r#""t8"."identification_number""#, - r#"FROM ("#, - r#"SELECT "test_space"."id", "test_space"."FIRST_NAME""#, - r#"FROM "test_space""#, - r#"WHERE ("test_space"."sysFrom") >= (?) and ("test_space"."sys_op") < (?)"#, - r#"UNION ALL"#, - r#"SELECT "test_space_hist"."id", "test_space_hist"."FIRST_NAME""#, - r#"FROM "test_space_hist""#, - r#"WHERE ("test_space_hist"."sysFrom") <= (?)"#, - r#") as "t3""#, - r#"INNER JOIN"#, - r#"(SELECT COLUMN_1 as "identification_number" FROM (VALUES (?))"#, - r#") as "t8""#, - r#"ON ("t3"."id") = ("t8"."identification_number")"#, - r#"WHERE ("t3"."id", "t3"."id", "t8"."identification_number") = ("t8"."identification_number", ?, ?)"# - ), - vec![ - Value::from(0_u64), - Value::from(0_u64), - Value::from(0_u64), - Value::from(2_u64), - Value::from(2_u64), - Value::from(2_u64) - ] - ) - ) - ) - ], - ]); + expected.rows.extend(vec![vec![ + Value::String(format!("Execute query on a bucket [{}]", bucket2)), + Value::String(String::from(PatternWithParams::new( + format!( + "{}, {}, {} {}{} {} {} {} {} {} {}{} {} {}{} {} {}", + r#"SELECT "t3"."id""#, + r#""t3"."FIRST_NAME""#, + r#""t8"."identification_number""#, + r#"FROM ("#, + r#"SELECT "test_space"."id", "test_space"."FIRST_NAME""#, + r#"FROM "test_space""#, + r#"WHERE ("test_space"."sys_op") < (?) and ("test_space"."sysFrom") >= (?)"#, + r#"UNION ALL"#, + r#"SELECT "test_space_hist"."id", "test_space_hist"."FIRST_NAME""#, + r#"FROM "test_space_hist""#, + r#"WHERE ("test_space_hist"."sysFrom") <= (?)"#, + r#") as "t3""#, + r#"INNER JOIN"#, + r#"(SELECT COLUMN_1 as "identification_number" FROM (VALUES (?))"#, + r#") as "t8""#, + r#"ON ("t3"."id") = ("t8"."identification_number")"#, + r#"WHERE ("t3"."id") = (?) and ("t8"."identification_number") = (?)"# + ), + vec![ + Value::from(0_u64), + Value::from(0_u64), + Value::from(0_u64), + Value::from(2_u64), + Value::from(2_u64), + Value::from(2_u64), + ], + ))), + ]]); assert_eq!(expected, result); } diff --git a/sbroad-core/src/executor/tests/between.rs b/sbroad-core/src/executor/tests/between.rs index 6514471781910d121a55ded6ba452d974eeae808..5be94415fe893f301f405070af6b5ccf96b7da94 100644 --- a/sbroad-core/src/executor/tests/between.rs +++ b/sbroad-core/src/executor/tests/between.rs @@ -57,12 +57,12 @@ fn between1_test() { format!( "{} {} {}", r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#, - r#"WHERE ("t"."identification_number") <= (SELECT COLUMN_1 as "id" FROM (VALUES (?)))"#, - r#"and ("t"."identification_number") >= (?)"#, + r#"WHERE ("t"."identification_number") >= (?)"#, + r#"and ("t"."identification_number") <= (SELECT COLUMN_1 as "id" FROM (VALUES (?)))"#, ), vec![ - Value::from(2_u64), Value::from(1_u64), + Value::from(2_u64), ], ))), ]]); @@ -123,14 +123,14 @@ fn between2_test() { format!( "{} {} {}", r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#, - r#"WHERE (SELECT COLUMN_1 as "id" FROM (VALUES (?))) <= (?)"#, - r#"and (SELECT COLUMN_2 as "id" FROM (VALUES (?))) >= (?)"#, + r#"WHERE (SELECT COLUMN_1 as "id" FROM (VALUES (?))) >= (?)"#, + r#"and (SELECT COLUMN_2 as "id" FROM (VALUES (?))) <= (?)"#, ), vec![ - Value::from(2_u64), - Value::from(3_u64), Value::from(2_u64), Value::from(1_u64), + Value::from(2_u64), + Value::from(3_u64), ], ))), ]]); diff --git a/sbroad-core/src/executor/tests/bucket_id.rs b/sbroad-core/src/executor/tests/bucket_id.rs index 17abd756186c1d7c1af9452436531204bdd0bd7c..6ea2280ddb363edea0c9e0367bc639bd8de1825c 100644 --- a/sbroad-core/src/executor/tests/bucket_id.rs +++ b/sbroad-core/src/executor/tests/bucket_id.rs @@ -55,7 +55,7 @@ fn bucket2_test() { format!( "{} {}", r#"SELECT "t1"."a", "t1"."bucket_id", "t1"."b" FROM "t1""#, - r#"WHERE ("t1"."a", "t1"."b") = (?, ?)"#, + r#"WHERE ("t1"."a") = (?) and ("t1"."b") = (?)"#, ), vec![param1, param2], ))), diff --git a/sbroad-core/src/executor/tests/not_eq.rs b/sbroad-core/src/executor/tests/not_eq.rs index f9d134de7cfca7afdbbc1f349fc4106bcf013295..a2f7ab4565622169e4f0428b9bcefda1cf8ec328 100644 --- a/sbroad-core/src/executor/tests/not_eq.rs +++ b/sbroad-core/src/executor/tests/not_eq.rs @@ -41,9 +41,9 @@ fn not_eq1_test() { format!( "{} {}", r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#, - r#"WHERE ("t"."product_code") <> (?) and ("t"."identification_number") <> (?)"#, + r#"WHERE ("t"."identification_number") <> (?) and ("t"."product_code") <> (?)"#, ), - vec![Value::from(2_u64), Value::from(1_u64)], + vec![Value::from(1_u64), Value::from(2_u64)], ))), ]]); assert_eq!(expected, result); diff --git a/sbroad-core/src/ir.rs b/sbroad-core/src/ir.rs index abdab500c92525b40b1944666e66b0c3a6e2c454..bb6a3f89c6620485ccc6d00dfa6912bca59ff052 100644 --- a/sbroad-core/src/ir.rs +++ b/sbroad-core/src/ir.rs @@ -28,7 +28,14 @@ pub mod value; #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] pub struct TreeMap(HashMap<usize, usize, RepeatableState>); +impl Default for TreeMap { + fn default() -> Self { + Self::new() + } +} + impl TreeMap { + #[must_use] pub fn new() -> Self { Self(HashMap::with_hasher(RepeatableState)) } @@ -37,16 +44,23 @@ impl TreeMap { self.0.insert(new_id, old_id); } - pub fn get(&self, new_id: usize) -> Option<usize> { - self.0.get(&new_id).copied() + #[must_use] + pub fn get(&self, new_id: &usize) -> Option<&usize> { + self.0.get(new_id) } - pub fn get_oldest(&self, new_id: usize) -> usize { - let mut id = new_id; - while let Some(old_id) = self.get(id) { - id = old_id; + #[must_use] + pub fn get_oldest(&self, new_id: &usize) -> Option<&usize> { + match self.0.get_key_value(new_id) { + None => None, + Some((id, _)) => { + let mut current = id; + while let Some(parent) = self.get(current) { + current = parent; + } + Some(current) + } } - id } } @@ -138,10 +152,9 @@ pub struct Plan { /// The flag is enabled if user wants to get a query plan only. /// In this case we don't need to execute query. is_explain: bool, - /// The undo log is used to track the changes in the plan tree - /// during the optimization process. It is used to restore the - /// original subtree after the optimization (if it is needed). - undo: TreeMap, + /// The undo log keeps the history of the plan transformations. It can + /// be used to revert the plan subtree to some previous snapshot if needed. + pub(crate) undo: TreeMap, } impl Default for Plan { diff --git a/sbroad-core/src/ir/transformation.rs b/sbroad-core/src/ir/transformation.rs index c5ffa20462030a1ca14a84295e1de164fdb73640..28cb3401a316d4044e1ea7f3b296b114e6e8ed97 100644 --- a/sbroad-core/src/ir/transformation.rs +++ b/sbroad-core/src/ir/transformation.rs @@ -95,7 +95,7 @@ impl Plan { _ => continue, }; if old_tree_id != new_tree_id { - self.undo.add(new_tree_id, old_tree_id); + self.undo.add(old_tree_id, new_tree_id); } let rel = self.get_mut_relation_node(*id)?; match rel { diff --git a/sbroad-core/src/ir/transformation/bool_in/tests.rs b/sbroad-core/src/ir/transformation/bool_in/tests.rs index feccf6b7426f411c67f51f1d2b64814c90690c18..6de0158fa38a0dd1d68935d5b50d5baddd5ba3d0 100644 --- a/sbroad-core/src/ir/transformation/bool_in/tests.rs +++ b/sbroad-core/src/ir/transformation/bool_in/tests.rs @@ -1,5 +1,5 @@ use crate::backend::sql::ir::PatternWithParams; -use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::transformation::helpers::check_transformation; use crate::ir::value::Value; use crate::ir::Plan; use pretty_assertions::assert_eq; @@ -20,7 +20,10 @@ fn bool_in1() { vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &replace_in_operator), expected); + assert_eq!( + check_transformation(input, vec![], &replace_in_operator), + expected + ); } #[test] @@ -43,7 +46,10 @@ fn bool_in2() { ], ); - assert_eq!(sql_to_sql(input, vec![], &replace_in_operator), expected); + assert_eq!( + check_transformation(input, vec![], &replace_in_operator), + expected + ); } #[test] @@ -58,5 +64,8 @@ fn bool_in3() { vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &replace_in_operator), expected); + assert_eq!( + check_transformation(input, vec![], &replace_in_operator), + expected + ); } diff --git a/sbroad-core/src/ir/transformation/dnf/tests.rs b/sbroad-core/src/ir/transformation/dnf/tests.rs index 37b671f120af0f140a3bd1668ea9434644fcd551..9943e953186cb4c5f2acf1989510cd84b95c9ffd 100644 --- a/sbroad-core/src/ir/transformation/dnf/tests.rs +++ b/sbroad-core/src/ir/transformation/dnf/tests.rs @@ -1,5 +1,5 @@ use crate::backend::sql::ir::PatternWithParams; -use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::transformation::helpers::check_transformation; use crate::ir::value::Value; use crate::ir::Plan; use pretty_assertions::assert_eq; @@ -28,7 +28,7 @@ fn dnf1() { ], ); - assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected); + assert_eq!(check_transformation(input, vec![], &set_dnf), expected); } #[test] @@ -54,7 +54,7 @@ fn dnf2() { ], ); - assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected); + assert_eq!(check_transformation(input, vec![], &set_dnf), expected); } #[test] @@ -75,7 +75,7 @@ fn dnf3() { ], ); - assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected); + assert_eq!(check_transformation(input, vec![], &set_dnf), expected); } #[test] @@ -96,7 +96,7 @@ fn dnf4() { ], ); - assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected); + assert_eq!(check_transformation(input, vec![], &set_dnf), expected); } #[test] @@ -117,7 +117,7 @@ fn dnf5() { ], ); - assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected); + assert_eq!(check_transformation(input, vec![], &set_dnf), expected); } #[test] @@ -133,5 +133,5 @@ fn dnf6() { vec![Value::from(1_u64), Value::from(1_u64), Value::from(2_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected); + assert_eq!(check_transformation(input, vec![], &set_dnf), expected); } diff --git a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs index 7f1b0fdb5f848c9945a55f0825c05534405069db..4a7f7ddcf830475d7ee49217baf41e0e939b91d2 100644 --- a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs +++ b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs @@ -1,5 +1,5 @@ use crate::backend::sql::ir::PatternWithParams; -use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::transformation::helpers::check_transformation; use crate::ir::value::Value; use crate::ir::Plan; use pretty_assertions::assert_eq; @@ -28,7 +28,10 @@ fn equality_propagation1() { ], ); - assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected); + assert_eq!( + check_transformation(input, vec![], &derive_equalities), + expected + ); } #[test] @@ -41,7 +44,10 @@ fn equality_propagation2() { vec![Value::Null, Value::Null], ); - assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected); + assert_eq!( + check_transformation(input, vec![], &derive_equalities), + expected + ); } #[test] @@ -58,7 +64,10 @@ fn equality_propagation3() { vec![Value::from(1_u64), Value::Null, Value::Null], ); - assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected); + assert_eq!( + check_transformation(input, vec![], &derive_equalities), + expected + ); } #[test] @@ -81,7 +90,10 @@ fn equality_propagation4() { ], ); - assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected); + assert_eq!( + check_transformation(input, vec![], &derive_equalities), + expected + ); } #[test] @@ -106,5 +118,8 @@ fn equality_propagation5() { ], ); - assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected); + assert_eq!( + check_transformation(input, vec![], &derive_equalities), + expected + ); } diff --git a/sbroad-core/src/ir/transformation/helpers.rs b/sbroad-core/src/ir/transformation/helpers.rs index 424d23287c7c82d8fbac967cbefa0cf858407008..41d921892f3442845765a648c30f06f24996bc31 100644 --- a/sbroad-core/src/ir/transformation/helpers.rs +++ b/sbroad-core/src/ir/transformation/helpers.rs @@ -7,6 +7,7 @@ use crate::executor::engine::mock::RouterConfigurationMock; use crate::executor::ir::ExecutionPlan; use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::frontend::Ast; +use crate::ir::tree::Snapshot; use crate::ir::value::Value; use crate::ir::Plan; @@ -40,7 +41,7 @@ pub fn sql_to_ir(query: &str, params: Vec<Value>) -> Plan { /// # Panics /// if query is not correct #[allow(dead_code)] -pub fn sql_to_sql( +pub fn check_transformation( query: &str, params: Vec<Value>, f_transform: &dyn Fn(&mut Plan), @@ -49,7 +50,7 @@ pub fn sql_to_sql( f_transform(&mut plan); let ex_plan = ExecutionPlan::from(plan); let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap(); + let sp = SyntaxPlan::new(&ex_plan, top_id, Snapshot::Latest).unwrap(); let ordered = OrderedSyntaxNodes::try_from(sp).unwrap(); let nodes = ordered.to_syntax_data().unwrap(); ex_plan.to_sql(&nodes, &Buckets::All).unwrap() diff --git a/sbroad-core/src/ir/transformation/merge_tuples/tests.rs b/sbroad-core/src/ir/transformation/merge_tuples/tests.rs index 22c8361e50f475194a0b054b47aecf5a80e79669..11e9c8ffdd9dec6dd5c7413dda7462f10fdd53b9 100644 --- a/sbroad-core/src/ir/transformation/merge_tuples/tests.rs +++ b/sbroad-core/src/ir/transformation/merge_tuples/tests.rs @@ -1,5 +1,5 @@ use crate::backend::sql::ir::PatternWithParams; -use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::transformation::helpers::check_transformation; use crate::ir::value::Value; use crate::ir::Plan; use pretty_assertions::assert_eq; @@ -25,7 +25,7 @@ fn merge_tuples1() { ], ); - assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected); + assert_eq!(check_transformation(input, vec![], &merge_tuples), expected); } #[test] @@ -50,7 +50,7 @@ fn merge_tuples2() { ], ); - assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected); + assert_eq!(check_transformation(input, vec![], &merge_tuples), expected); } #[test] @@ -61,7 +61,7 @@ fn merge_tuples3() { vec![Value::Boolean(true)], ); - assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected); + assert_eq!(check_transformation(input, vec![], &merge_tuples), expected); } #[test] @@ -75,7 +75,7 @@ fn merge_tuples4() { vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected); + assert_eq!(check_transformation(input, vec![], &merge_tuples), expected); } #[test] @@ -90,7 +90,7 @@ fn merge_tuples5() { vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected); + assert_eq!(check_transformation(input, vec![], &merge_tuples), expected); } #[test] @@ -104,5 +104,5 @@ fn merge_tuples6() { vec![Value::from(2_u64), Value::from(1_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected); + assert_eq!(check_transformation(input, vec![], &merge_tuples), expected); } diff --git a/sbroad-core/src/ir/transformation/split_columns/tests.rs b/sbroad-core/src/ir/transformation/split_columns/tests.rs index 7eaaf0a762323495506b8e1865f84a2ed3e8271e..02ad99fe980380a2a6c6597f3dd041bd18fcc9e2 100644 --- a/sbroad-core/src/ir/transformation/split_columns/tests.rs +++ b/sbroad-core/src/ir/transformation/split_columns/tests.rs @@ -2,7 +2,7 @@ use crate::backend::sql::ir::PatternWithParams; use crate::executor::engine::mock::RouterConfigurationMock; use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::frontend::Ast; -use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::transformation::helpers::check_transformation; use crate::ir::value::Value; use crate::ir::Plan; use pretty_assertions::assert_eq; @@ -19,7 +19,10 @@ fn split_columns1() { vec![Value::from(1_u64), Value::from(2_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &split_columns), expected); + assert_eq!( + check_transformation(input, vec![], &split_columns), + expected + ); } #[test] @@ -30,7 +33,10 @@ fn split_columns2() { vec![Value::from(1_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &split_columns), expected); + assert_eq!( + check_transformation(input, vec![], &split_columns), + expected + ); } #[test] @@ -61,7 +67,10 @@ fn split_columns4() { vec![Value::from(1_u64), Value::from(2_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &split_columns), expected); + assert_eq!( + check_transformation(input, vec![], &split_columns), + expected + ); } #[test] @@ -76,5 +85,8 @@ fn split_columns5() { vec![Value::from(1_u64), Value::from(2_u64), Value::from(2_u64)], ); - assert_eq!(sql_to_sql(input, vec![], &split_columns), expected); + assert_eq!( + check_transformation(input, vec![], &split_columns), + expected + ); } diff --git a/sbroad-core/src/ir/tree.rs b/sbroad-core/src/ir/tree.rs index ea174a34ae42facd6bd7a9f27c8ddf47487e005f..d0df786dc320a14ac97a4234b94ae3c62f654467 100644 --- a/sbroad-core/src/ir/tree.rs +++ b/sbroad-core/src/ir/tree.rs @@ -13,6 +13,14 @@ trait PlanTreeIterator<'plan>: TreeIterator<'plan> { fn get_plan(&self) -> &'plan Plan; } +/// A snapshot describes the version of the plan +/// subtree to iterate over. +#[derive(Debug, Clone)] +pub enum Snapshot { + Latest, + Oldest, +} + pub mod and; pub mod eq_class; pub mod expression; diff --git a/sbroad-core/src/ir/tree/and.rs b/sbroad-core/src/ir/tree/and.rs index f38259e07957ba52a258feaddf13603c06c27d71..1c6c8377f98fb2217f031f0352398089b220bbbe 100644 --- a/sbroad-core/src/ir/tree/and.rs +++ b/sbroad-core/src/ir/tree/and.rs @@ -10,6 +10,7 @@ trait AndTreeIterator<'nodes>: TreeIterator<'nodes> {} /// Children iterator for "and"-ed expression chains. /// /// The iterator returns the next child for the chained `Bool::And` nodes. +#[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct AndIterator<'n> { current: &'n usize, diff --git a/sbroad-core/src/ir/tree/eq_class.rs b/sbroad-core/src/ir/tree/eq_class.rs index a96ad63b8c1dc413ea42230196ed748c9ca5ce28..c8febae73d0f8fc8630c8ad0a48f3b7525cccae9 100644 --- a/sbroad-core/src/ir/tree/eq_class.rs +++ b/sbroad-core/src/ir/tree/eq_class.rs @@ -11,6 +11,7 @@ trait EqClassTreeIterator<'nodes>: TreeIterator<'nodes> {} /// /// The iterator returns the next child for the chained `Bool::And` /// and `Bool::Eq` nodes. +#[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct EqClassIterator<'n> { current: &'n usize, diff --git a/sbroad-core/src/ir/tree/expression.rs b/sbroad-core/src/ir/tree/expression.rs index aeafaebc88ee38e67f817e5fdcc689ba1ece51cf..f46e4ebb6958568c21c83df29891dc74e870cd37 100644 --- a/sbroad-core/src/ir/tree/expression.rs +++ b/sbroad-core/src/ir/tree/expression.rs @@ -12,6 +12,7 @@ trait ExpressionTreeIterator<'nodes>: TreeIterator<'nodes> { /// /// The iterator returns the next child for expression /// nodes. It is required to use `traversal` crate. +#[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct ExpressionIterator<'n> { current: &'n usize, diff --git a/sbroad-core/src/ir/tree/subtree.rs b/sbroad-core/src/ir/tree/subtree.rs index 0868168be519aace8af1ad4b2c1200612615d8d6..17845d033597707b0be8da3fa517020113b89f16 100644 --- a/sbroad-core/src/ir/tree/subtree.rs +++ b/sbroad-core/src/ir/tree/subtree.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::cmp::Ordering; -use super::{PlanTreeIterator, TreeIterator}; +use super::{PlanTreeIterator, Snapshot, TreeIterator}; use crate::ir::expression::Expression; use crate::ir::operator::Relational; use crate::ir::{Node, Nodes, Plan}; @@ -9,6 +9,7 @@ use crate::ir::{Node, Nodes, Plan}; trait SubtreePlanIterator<'plan>: PlanTreeIterator<'plan> {} /// Expression and relational nodes iterator. +#[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct SubtreeIterator<'plan> { current: &'plan usize, @@ -42,7 +43,7 @@ impl<'plan> Iterator for SubtreeIterator<'plan> { type Item = &'plan usize; fn next(&mut self) -> Option<Self::Item> { - subtree_next(self) + subtree_next(self, &Snapshot::Latest) } } @@ -57,8 +58,66 @@ impl<'plan> Plan { } } +/// Expression and relational nodes flashback iterator. +/// It uses the UNDO transformation log to go back to the +/// original state of some subtrees in the plan (selections +/// at the moment). +#[derive(Debug)] +pub struct FlashbackSubtreeIterator<'plan> { + current: &'plan usize, + child: RefCell<usize>, + plan: &'plan Plan, +} + +impl<'nodes> TreeIterator<'nodes> for FlashbackSubtreeIterator<'nodes> { + fn get_current(&self) -> &'nodes usize { + self.current + } + + fn get_child(&self) -> &RefCell<usize> { + &self.child + } + + fn get_nodes(&self) -> &'nodes Nodes { + &self.plan.nodes + } +} + +impl<'plan> PlanTreeIterator<'plan> for FlashbackSubtreeIterator<'plan> { + fn get_plan(&self) -> &'plan Plan { + self.plan + } +} + +impl<'plan> SubtreePlanIterator<'plan> for FlashbackSubtreeIterator<'plan> {} + +impl<'plan> Iterator for FlashbackSubtreeIterator<'plan> { + type Item = &'plan usize; + + fn next(&mut self) -> Option<Self::Item> { + subtree_next(self, &Snapshot::Oldest) + } +} + +impl<'plan> Plan { + #[must_use] + pub fn flashback_subtree_iter( + &'plan self, + current: &'plan usize, + ) -> FlashbackSubtreeIterator<'plan> { + FlashbackSubtreeIterator { + current, + child: RefCell::new(0), + plan: self, + } + } +} + #[allow(clippy::too_many_lines)] -fn subtree_next<'plan>(iter: &mut impl SubtreePlanIterator<'plan>) -> Option<&'plan usize> { +fn subtree_next<'plan>( + iter: &mut impl SubtreePlanIterator<'plan>, + snapshot: &Snapshot, +) -> Option<&'plan usize> { if let Some(child) = iter.get_nodes().arena.get(*iter.get_current()) { return match child { Node::Parameter => None, @@ -198,9 +257,17 @@ fn subtree_next<'plan>(iter: &mut impl SubtreePlanIterator<'plan>) -> Option<&'p Ordering::Less => { return children.get(step); } - Ordering::Equal => { - return Some(filter); - } + Ordering::Equal => match snapshot { + Snapshot::Latest => Some(filter), + Snapshot::Oldest => { + return Some( + iter.get_plan() + .undo + .get_oldest(filter) + .map_or_else(|| filter, |id| id), + ); + } + }, Ordering::Greater => None, } } diff --git a/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml b/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml index 19a2aa7daeef5e5f459f520980b57febe9a0e67e..a1125e3312af24be929694516442468785bbd1b1 100644 --- a/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml +++ b/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml @@ -113,3 +113,4 @@ relations: slices: ~ top: 16 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml b/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml index b1ac3d0077e06e447beb9e9321be7d4808625275..a5eec7cf424931e638648b6846f198ac3fd62e6a 100644 --- a/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml +++ b/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml @@ -171,3 +171,4 @@ relations: slices: ~ top: 28 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml index 0646bb3bf3b0e7ae4461aa47063be71e55f424af..2ff4e07729b9e5fb20635eedfab65719da3ab7d6 100644 --- a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml +++ b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml @@ -99,3 +99,4 @@ relations: slices: ~ top: 15 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml index 82494146138c4e242088b64d849b7fe0c2a4f3d0..8e1c4a050b0956d97a3027ef9a24527f2afa7806 100644 --- a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml +++ b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml @@ -88,3 +88,4 @@ relations: slices: ~ top: 13 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml b/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml index d2f81b5ca91593638c6e68dec69b5cc479a92d8f..2c3200dc93bb47274114e878f42253c5aa6f8b79 100644 --- a/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml +++ b/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml @@ -99,3 +99,4 @@ relations: slices: ~ top: 15 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml b/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml index e10eccccdd87bb494eb81b58493d4c58e4f71e7c..0365fd8300ca088ff0a9097c9c3a2daecafae7d1 100644 --- a/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml +++ b/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml @@ -115,3 +115,4 @@ relations: slices: ~ top: 17 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml b/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml index 60ae5e3b6af972c0226ca3c8a5f8f4670d53df0c..d5e530d7c0a2c1867dea0d1960a582ee0cdfc700 100644 --- a/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml +++ b/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml @@ -115,3 +115,4 @@ relations: slices: ~ top: 17 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/join.yaml b/sbroad-core/tests/artifactory/ir/operator/join.yaml index b1ac3d0077e06e447beb9e9321be7d4808625275..a5eec7cf424931e638648b6846f198ac3fd62e6a 100644 --- a/sbroad-core/tests/artifactory/ir/operator/join.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/join.yaml @@ -171,3 +171,4 @@ relations: slices: ~ top: 28 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml index 0e2235de84453c4796686c2cd13a3fe119d05160..fd3fa6fe03b65ab8538fe8df6f32f09592cca11e 100644 --- a/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml @@ -44,3 +44,4 @@ relations: name: t slices: ~ top: 5 +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml index febed528f0d0999cd93945c6f92d41b8a5de2092..1bbafd3ef94cad94a1f46da2a03f746a7027b56b 100644 --- a/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml @@ -44,3 +44,4 @@ relations: name: t slices: ~ top: 5 +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml index 33d04e1e732eba193e97b97e600e67c3dd2eb5e0..159ff0c773002338aeb8b50d3974f580b5ef5a46 100644 --- a/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml @@ -35,3 +35,4 @@ relations: name: t slices: ~ top: 3 +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml index a39463aae4caf3823b1713bb9541deba9ed7354a..30cc8279ce2605eaf63fbb797903610993b48c99 100644 --- a/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml @@ -40,3 +40,4 @@ relations: name: t slices: ~ top: 4 +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/projection.yaml b/sbroad-core/tests/artifactory/ir/operator/projection.yaml index 965a3d0c2aa87159fd07202d9a62364f74aab784..49e42253cf45f100e890f1ec1045655da0c410e0 100644 --- a/sbroad-core/tests/artifactory/ir/operator/projection.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/projection.yaml @@ -74,3 +74,4 @@ relations: slices: ~ top: 9 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml b/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml index 314dc8b09ff502dffb40b681445ee9107251a692..a46ea0c1f9da25f32e0cde903aad4a072820da15 100644 --- a/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml @@ -73,3 +73,4 @@ relations: slices: ~ top: 9 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/selection.yaml b/sbroad-core/tests/artifactory/ir/operator/selection.yaml index dafbec9d8d734b1b626725aece3f48c9c36a4e73..75090997341eebb1e00277c66bf0589fbecf8684 100644 --- a/sbroad-core/tests/artifactory/ir/operator/selection.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/selection.yaml @@ -149,3 +149,4 @@ relations: slices: ~ top: 23 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml b/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml index 323c7fce30f77a469b4c10495a0102a10974d3bd..5705e4195f6458347f0baebab825c601144be966 100644 --- a/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml @@ -150,3 +150,4 @@ relations: slices: ~ top: 24 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml b/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml index 60b9c0588381157959fe24af234ddb8b89d7ff11..a01aaf056611bad3491dbc68269c127236cf36f8 100644 --- a/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml +++ b/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml @@ -82,3 +82,4 @@ relations: slices: ~ top: 11 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/plan_no_top.yaml b/sbroad-core/tests/artifactory/ir/plan_no_top.yaml index bb091a3b4fc9658dc5e9e6f153f9f525c16baf48..d35a5a3d54b39a87b1020d1a407651d4e38a4bce 100644 --- a/sbroad-core/tests/artifactory/ir/plan_no_top.yaml +++ b/sbroad-core/tests/artifactory/ir/plan_no_top.yaml @@ -35,3 +35,4 @@ relations: slices: ~ top: ~ is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml b/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml index 652b2be063343c5c8f27efe54bf973fa22f8769a..c4bb1f225c7d9e69133787db0183b73476bd283d 100644 --- a/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml +++ b/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml @@ -35,3 +35,4 @@ relations: slices: ~ top: 42 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml index 7e7ab85177d06ec372c788ddda6e28355d725bcb..a24ad86786ff0c12fdb0ae31b3b4fd2f75559b1f 100644 --- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml +++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml @@ -199,3 +199,4 @@ slices: - 30 top: 26 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml index ddac69bf957cad7183dcb872d2e96e1e2191a874..a0b1102c93afbd5b0be45aaddbbaf5c69964a215 100644 --- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml +++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml @@ -218,3 +218,4 @@ slices: - 32 top: 28 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml index c7fda607c315f77c9d62b4b99687da451a6f4de9..19c59a6245bf0c93e68329612ad5ae7a7f8e56d2 100644 --- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml +++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml @@ -175,3 +175,4 @@ relations: slices: ~ top: 24 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml index 138593e3ab48c82b3034a71f736e78d4d36ec3c1..6f2aa7c28ea124859df233c1c103863e53be5f52 100644 --- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml +++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml @@ -347,3 +347,4 @@ slices: - 54 top: 46 is_explain: false +undo: {} diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml index bd8470931001d8df6445cf90379759c89869deb7..52c411d2368e9dae2bf77dc95147009e3b19f25d 100644 --- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml +++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml @@ -206,3 +206,4 @@ slices: - 30 top: 26 is_explain: false +undo: {}