From de3cfc77879dd2a767ac9ed5d9a558b982dc6bc4 Mon Sep 17 00:00:00 2001 From: Denis Smirnov <sd@picodata.io> Date: Fri, 8 Apr 2022 16:43:23 +0700 Subject: [PATCH] refactoring: tests using sql transformations --- src/frontend/sql/ir/tests.rs | 379 +++++++----------- src/ir/transformation.rs | 2 +- src/ir/transformation/bool_in/tests.rs | 80 ++-- src/ir/transformation/dnf/tests.rs | 156 +++---- .../equality_propagation/tests.rs | 17 +- src/ir/transformation/helpers.rs | 17 +- src/ir/transformation/merge_tuples/tests.rs | 118 ++---- src/ir/transformation/redistribution/tests.rs | 233 +++++------ src/ir/transformation/split_columns/tests.rs | 100 ++--- 9 files changed, 419 insertions(+), 683 deletions(-) diff --git a/src/frontend/sql/ir/tests.rs b/src/frontend/sql/ir/tests.rs index b0388dcd1b..17adf6188c 100644 --- a/src/frontend/sql/ir/tests.rs +++ b/src/frontend/sql/ir/tests.rs @@ -1,190 +1,133 @@ -use pretty_assertions::assert_eq; - +use crate::errors::QueryPlannerError; use crate::executor::engine::mock::MetadataMock; -use crate::executor::ir::ExecutionPlan; +use crate::frontend::sql::ast::AbstractSyntaxTree; +use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::Plan; +use pretty_assertions::assert_eq; -use super::*; +fn no_transform(_plan: &mut Plan) {} #[test] -fn simple_query_to_ir() { - let query = r#"SELECT "identification_number", "product_code" FROM "hash_testing" - WHERE "identification_number" = 1"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - - assert_eq!( - format!( - "{} {}", - r#"SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, - r#"FROM "hash_testing" WHERE ("hash_testing"."identification_number") = (1)"#, - ), - sql +fn front_sql1() { + let input = r#"SELECT "identification_number", "product_code" FROM "hash_testing" + WHERE "identification_number" = 1"#; + let expected = format!( + "{} {}", + r#"SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, + r#"FROM "hash_testing" WHERE ("hash_testing"."identification_number") = (1)"#, ); -} -#[test] -fn complex_cond_query_transform() { - let query = r#"SELECT "identification_number", "product_code" - FROM "hash_testing" - WHERE "identification_number" = 1 AND "product_code" = '1' - OR "identification_number" = 2 AND "product_code" = '2'"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - - assert_eq!( - format!( - "{} {} {}", - r#"SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, - r#"FROM "hash_testing" WHERE (("hash_testing"."identification_number") = (1) and ("hash_testing"."product_code") = ('1')"#, - r#"or ("hash_testing"."identification_number") = (2) and ("hash_testing"."product_code") = ('2'))"#, - ), - sql - ); + assert_eq!(sql_to_sql(input, &no_transform), expected); } #[test] -fn simple_union_query_transform() { - let query = r#"SELECT * - FROM - (SELECT "identification_number", "product_code" +fn front_sql2() { + let input = r#"SELECT "identification_number", "product_code" FROM "hash_testing" - WHERE "sys_op" = 1 - UNION ALL - SELECT "identification_number", "product_code" - FROM "hash_testing_hist" - WHERE "sys_op" > 1) AS "t3" - WHERE "identification_number" = 1"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {} {} {} {} {} {}", - r#"SELECT "t3"."identification_number" as "identification_number", "t3"."product_code" as "product_code" FROM"#, - r#"(SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, - r#"FROM "hash_testing" WHERE ("hash_testing"."sys_op") = (1)"#, - r#"UNION ALL"#, - r#"SELECT "hash_testing_hist"."identification_number" as "identification_number", "hash_testing_hist"."product_code" as "product_code""#, - r#"FROM "hash_testing_hist" WHERE ("hash_testing_hist"."sys_op") > (1)) as "t3""#, - r#"WHERE ("t3"."identification_number") = (1)"#, - ), - sql + WHERE "identification_number" = 1 AND "product_code" = '1' + OR "identification_number" = 2 AND "product_code" = '2'"#; + let expected = format!( + "{} {} {}", + r#"SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, + r#"FROM "hash_testing" WHERE (("hash_testing"."identification_number") = (1) and ("hash_testing"."product_code") = ('1')"#, + r#"or ("hash_testing"."identification_number") = (2) and ("hash_testing"."product_code") = ('2'))"#, ); + + assert_eq!(sql_to_sql(input, &no_transform), expected); } #[test] -fn union_complex_cond_query_transform() { - let query = r#"SELECT * -FROM - (SELECT "identification_number", "product_code" - FROM "hash_testing" - WHERE "sys_op" = 1 - UNION ALL - SELECT "identification_number", "product_code" - FROM "hash_testing_hist" - WHERE "sys_op" > 1) AS "t3" -WHERE ("identification_number" = 1 - OR ("identification_number" = 2 - OR "identification_number" = 3)) - AND ("product_code" = '1' - OR "product_code" = '2')"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - - assert_eq!( - format!( - "{} {} {} {} {} {} {} {}", - r#"SELECT "t3"."identification_number" as "identification_number", "t3"."product_code" as "product_code" FROM"#, - r#"(SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, - r#"FROM "hash_testing" WHERE ("hash_testing"."sys_op") = (1)"#, - r#"UNION ALL"#, - r#"SELECT "hash_testing_hist"."identification_number" as "identification_number", "hash_testing_hist"."product_code" as "product_code""#, - r#"FROM "hash_testing_hist" WHERE ("hash_testing_hist"."sys_op") > (1)) as "t3""#, - r#"WHERE (("t3"."identification_number") = (1) or (("t3"."identification_number") = (2) or ("t3"."identification_number") = (3)))"#, - r#"and (("t3"."product_code") = ('1') or ("t3"."product_code") = ('2'))"#, - ), - sql +fn front_sql3() { + let input = r#"SELECT * + FROM + (SELECT "identification_number", "product_code" + FROM "hash_testing" + WHERE "sys_op" = 1 + UNION ALL + SELECT "identification_number", "product_code" + FROM "hash_testing_hist" + WHERE "sys_op" > 1) AS "t3" + WHERE "identification_number" = 1"#; + let expected = format!( + "{} {} {} {} {} {} {}", + r#"SELECT "t3"."identification_number" as "identification_number", "t3"."product_code" as "product_code" FROM"#, + r#"(SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, + r#"FROM "hash_testing" WHERE ("hash_testing"."sys_op") = (1)"#, + r#"UNION ALL"#, + r#"SELECT "hash_testing_hist"."identification_number" as "identification_number", "hash_testing_hist"."product_code" as "product_code""#, + r#"FROM "hash_testing_hist" WHERE ("hash_testing_hist"."sys_op") > (1)) as "t3""#, + r#"WHERE ("t3"."identification_number") = (1)"#, ); + + assert_eq!(sql_to_sql(input, &no_transform), expected); } #[test] -fn sub_query_in_selection() { - let query = r#"SELECT "identification_number", "product_code" FROM "hash_testing" - WHERE "identification_number" in ( - SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'a')"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); +fn front_sql4() { + let input = r#"SELECT * + FROM + (SELECT "identification_number", "product_code" + FROM "hash_testing" + WHERE "sys_op" = 1 + UNION ALL + SELECT "identification_number", "product_code" + FROM "hash_testing_hist" + WHERE "sys_op" > 1) AS "t3" + WHERE ("identification_number" = 1 + OR ("identification_number" = 2 + OR "identification_number" = 3)) + AND ("product_code" = '1' + OR "product_code" = '2')"#; + let expected = format!( + "{} {} {} {} {} {} {} {}", + r#"SELECT "t3"."identification_number" as "identification_number", "t3"."product_code" as "product_code" FROM"#, + r#"(SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, + r#"FROM "hash_testing" WHERE ("hash_testing"."sys_op") = (1)"#, + r#"UNION ALL"#, + r#"SELECT "hash_testing_hist"."identification_number" as "identification_number", "hash_testing_hist"."product_code" as "product_code""#, + r#"FROM "hash_testing_hist" WHERE ("hash_testing_hist"."sys_op") > (1)) as "t3""#, + r#"WHERE (("t3"."identification_number") = (1) or (("t3"."identification_number") = (2) or ("t3"."identification_number") = (3)))"#, + r#"and (("t3"."product_code") = ('1') or ("t3"."product_code") = ('2'))"#, + ); - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); + assert_eq!(sql_to_sql(input, &no_transform), expected); +} - assert_eq!( - format!( - "{} {} {} {}", - r#"SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, - r#"FROM "hash_testing" WHERE ("hash_testing"."identification_number") in"#, - r#"(SELECT "hash_testing_hist"."identification_number" as "identification_number" FROM "hash_testing_hist""#, - r#"WHERE ("hash_testing_hist"."product_code") = ('a'))"#, - ), - sql +#[test] +fn front_sql5() { + let input = r#"SELECT "identification_number", "product_code" FROM "hash_testing" + WHERE "identification_number" in ( + SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'a')"#; + let expected = format!( + "{} {} {} {}", + r#"SELECT "hash_testing"."identification_number" as "identification_number", "hash_testing"."product_code" as "product_code""#, + r#"FROM "hash_testing" WHERE ("hash_testing"."identification_number") in"#, + r#"(SELECT "hash_testing_hist"."identification_number" as "identification_number" FROM "hash_testing_hist""#, + r#"WHERE ("hash_testing_hist"."product_code") = ('a'))"#, ); + + assert_eq!(sql_to_sql(input, &no_transform), expected); } #[test] -fn inner_join() { - let query = r#"SELECT "id", "product_units" FROM "hash_testing" +fn front_sql6() { + let input = r#"SELECT "id", "product_units" FROM "hash_testing" INNER JOIN (SELECT "id" FROM "test_space") as t ON "hash_testing"."identification_number" = t."id" WHERE "hash_testing"."identification_number" = 5 and "hash_testing"."product_code" = '123'"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - - assert_eq!( - format!( - "{} {} {} {}", - r#"SELECT t."id" as "id", "hash_testing"."product_units" as "product_units""#, - r#"FROM "hash_testing" INNER JOIN (SELECT "test_space"."id" as "id" FROM "test_space") as t"#, - r#"ON ("hash_testing"."identification_number") = (t."id")"#, - r#"WHERE ("hash_testing"."identification_number") = (5) and ("hash_testing"."product_code") = ('123')"#, - ), - sql + let expected = format!( + "{} {} {} {}", + r#"SELECT t."id" as "id", "hash_testing"."product_units" as "product_units""#, + r#"FROM "hash_testing" INNER JOIN (SELECT "test_space"."id" as "id" FROM "test_space") as t"#, + r#"ON ("hash_testing"."identification_number") = (t."id")"#, + r#"WHERE ("hash_testing"."identification_number") = (5) and ("hash_testing"."product_code") = ('123')"#, ); + + assert_eq!(sql_to_sql(input, &no_transform), expected); } #[test] -fn inner_join_duplicate_columns() { +fn front_sql7() { // Tables "test_space" and "hash_testing" have the same columns "sys_op" and "bucket_id", // that cause a "duplicate column" error in the output tuple of the INNER JOIN node. // The error is handled by renaming the columns within a sub-query (inner_join test). @@ -208,81 +151,61 @@ fn inner_join_duplicate_columns() { } #[test] -fn simple_query_with_unquoted_aliases() { - let query = r#"SELECT t."identification_number", "product_code" FROM "hash_testing" as t - WHERE t."identification_number" = 1"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - - assert_eq!( - format!( - "{} {}", - r#"SELECT t."identification_number" as "identification_number", t."product_code" as "product_code""#, - r#"FROM "hash_testing" as t WHERE (t."identification_number") = (1)"#, - ), - sql +fn front_sql8() { + let input = r#"SELECT t."identification_number", "product_code" FROM "hash_testing" as t + WHERE t."identification_number" = 1"#; + let expected = format!( + "{} {}", + r#"SELECT t."identification_number" as "identification_number", t."product_code" as "product_code""#, + r#"FROM "hash_testing" as t WHERE (t."identification_number") = (1)"#, ); + + assert_eq!(sql_to_sql(input, &no_transform), expected); } #[test] -fn inner_join_1() { - let query = r#"SELECT * - FROM - (SELECT "id", "FIRST_NAME" - FROM "test_space" - WHERE "sys_op" < 0 - AND "sysFrom" >= 0 - UNION ALL - SELECT "id", "FIRST_NAME" - FROM "test_space_hist" - WHERE "sysFrom" <= 0) AS "t3" - INNER JOIN - (SELECT "identification_number", "product_code" - FROM "hash_testing_hist" - WHERE "sys_op" > 0 - UNION ALL - SELECT "identification_number", "product_code" - FROM "hash_single_testing_hist" - WHERE "sys_op" <= 0) AS "t8" - ON "t3"."id" = "t8"."identification_number" - WHERE "id" = 1 AND "t8"."identification_number" = 1 AND "product_code" = '123'"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let plan = ast.to_ir(metadata).unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - - assert_eq!( - format!( - "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", - r#"SELECT "t3"."id" as "id", "t3"."FIRST_NAME" as "FIRST_NAME","#, - r#""t8"."identification_number" as "identification_number","#, - r#""t8"."product_code" as "product_code" FROM"#, - r#"(SELECT "test_space"."id" as "id", "test_space"."FIRST_NAME" as "FIRST_NAME""#, - r#"FROM "test_space" WHERE ("test_space"."sys_op") < (0) and ("test_space"."sysFrom") >= (0)"#, - r#"UNION ALL"#, - r#"SELECT "test_space_hist"."id" as "id", "test_space_hist"."FIRST_NAME" as "FIRST_NAME""#, - r#"FROM "test_space_hist" WHERE ("test_space_hist"."sysFrom") <= (0))"#, - r#"as "t3""#, - r#"INNER JOIN"#, - r#"(SELECT "hash_testing_hist"."identification_number" as "identification_number","#, - r#""hash_testing_hist"."product_code" as "product_code" FROM "hash_testing_hist" WHERE ("hash_testing_hist"."sys_op") > (0)"#, - r#"UNION ALL"#, - r#"SELECT "hash_single_testing_hist"."identification_number" as "identification_number","#, - r#""hash_single_testing_hist"."product_code" as "product_code" FROM "hash_single_testing_hist""#, - r#"WHERE ("hash_single_testing_hist"."sys_op") <= (0))"#, - r#"as "t8" ON ("t3"."id") = ("t8"."identification_number")"#, - r#"WHERE ("t3"."id") = (1) and ("t8"."identification_number") = (1) and ("t8"."product_code") = ('123')"#, - ), - sql +fn front_sql9() { + let input = r#"SELECT * + FROM + (SELECT "id", "FIRST_NAME" + FROM "test_space" + WHERE "sys_op" < 0 + AND "sysFrom" >= 0 + UNION ALL + SELECT "id", "FIRST_NAME" + FROM "test_space_hist" + WHERE "sysFrom" <= 0) AS "t3" + INNER JOIN + (SELECT "identification_number", "product_code" + FROM "hash_testing_hist" + WHERE "sys_op" > 0 + UNION ALL + SELECT "identification_number", "product_code" + FROM "hash_single_testing_hist" + WHERE "sys_op" <= 0) AS "t8" + ON "t3"."id" = "t8"."identification_number" + WHERE "id" = 1 AND "t8"."identification_number" = 1 AND "product_code" = '123'"#; + let expected = format!( + "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", + r#"SELECT "t3"."id" as "id", "t3"."FIRST_NAME" as "FIRST_NAME","#, + r#""t8"."identification_number" as "identification_number","#, + r#""t8"."product_code" as "product_code" FROM"#, + r#"(SELECT "test_space"."id" as "id", "test_space"."FIRST_NAME" as "FIRST_NAME""#, + r#"FROM "test_space" WHERE ("test_space"."sys_op") < (0) and ("test_space"."sysFrom") >= (0)"#, + r#"UNION ALL"#, + r#"SELECT "test_space_hist"."id" as "id", "test_space_hist"."FIRST_NAME" as "FIRST_NAME""#, + r#"FROM "test_space_hist" WHERE ("test_space_hist"."sysFrom") <= (0))"#, + r#"as "t3""#, + r#"INNER JOIN"#, + r#"(SELECT "hash_testing_hist"."identification_number" as "identification_number","#, + r#""hash_testing_hist"."product_code" as "product_code" FROM "hash_testing_hist" WHERE ("hash_testing_hist"."sys_op") > (0)"#, + r#"UNION ALL"#, + r#"SELECT "hash_single_testing_hist"."identification_number" as "identification_number","#, + r#""hash_single_testing_hist"."product_code" as "product_code" FROM "hash_single_testing_hist""#, + r#"WHERE ("hash_single_testing_hist"."sys_op") <= (0))"#, + r#"as "t8" ON ("t3"."id") = ("t8"."identification_number")"#, + r#"WHERE ("t3"."id") = (1) and ("t8"."identification_number") = (1) and ("t8"."product_code") = ('123')"#, ); + + assert_eq!(sql_to_sql(input, &no_transform), expected); } diff --git a/src/ir/transformation.rs b/src/ir/transformation.rs index 6b2da0b5c4..50fa482fe3 100644 --- a/src/ir/transformation.rs +++ b/src/ir/transformation.rs @@ -183,4 +183,4 @@ impl Plan { } #[cfg(test)] -mod helpers; +pub mod helpers; diff --git a/src/ir/transformation/bool_in/tests.rs b/src/ir/transformation/bool_in/tests.rs index 0b415c6889..dc2c4b4e41 100644 --- a/src/ir/transformation/bool_in/tests.rs +++ b/src/ir/transformation/bool_in/tests.rs @@ -1,72 +1,44 @@ +use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::Plan; use pretty_assertions::assert_eq; -use crate::executor::engine::mock::MetadataMock; -use crate::executor::ir::ExecutionPlan; -use crate::frontend::sql::ast::AbstractSyntaxTree; +fn replace_in_operator(plan: &mut Plan) { + plan.replace_in_operator().unwrap(); +} #[test] fn bool_in1() { - let query = r#"SELECT "a" FROM "t" WHERE "a" IN (1, 2, 3)"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.replace_in_operator().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE ((("t"."a") = (1) or ("t"."a") = (2)) or ("t"."a") = (3))"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE "a" IN (1, 2, 3)"#; + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE ((("t"."a") = (1) or ("t"."a") = (2)) or ("t"."a") = (3))"#, ); + + assert_eq!(sql_to_sql(input, &replace_in_operator), expected); } #[test] fn bool_in2() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE ("a", "b") IN ((1, 10), (2, 20), (3, 30))"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.replace_in_operator().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE ((("t"."a", "t"."b") = (1, 10) or ("t"."a", "t"."b") = (2, 20)) or ("t"."a", "t"."b") = (3, 30))"#, - ), - sql + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE ((("t"."a", "t"."b") = (1, 10) or ("t"."a", "t"."b") = (2, 20)) or ("t"."a", "t"."b") = (3, 30))"#, ); + + assert_eq!(sql_to_sql(input, &replace_in_operator), expected); } #[test] fn bool_in3() { - let query = r#"SELECT "a" FROM "t" WHERE "a" IN (1, 2) AND "b" IN (3)"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.replace_in_operator().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (("t"."a") = (1) or ("t"."a") = (2)) and ("t"."b") = (3)"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE "a" IN (1, 2) AND "b" IN (3)"#; + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (("t"."a") = (1) or ("t"."a") = (2)) and ("t"."b") = (3)"#, ); + + assert_eq!(sql_to_sql(input, &replace_in_operator), expected); } diff --git a/src/ir/transformation/dnf/tests.rs b/src/ir/transformation/dnf/tests.rs index f6845843d6..4c71909596 100644 --- a/src/ir/transformation/dnf/tests.rs +++ b/src/ir/transformation/dnf/tests.rs @@ -1,145 +1,87 @@ +use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::Plan; use pretty_assertions::assert_eq; -use crate::executor::engine::mock::MetadataMock; -use crate::executor::ir::ExecutionPlan; -use crate::frontend::sql::ast::AbstractSyntaxTree; +fn set_dnf(plan: &mut Plan) { + plan.set_dnf().unwrap(); +} #[test] fn dnf1() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE ("a" = 1 AND "b" = 2 OR "a" = 3) AND "c" = 4"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.set_dnf().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (("t"."a") = (1) and ("t"."b") = (2) and ("t"."c") = (4)"#, - r#"or ("t"."a") = (3) and ("t"."c") = (4))"#, - ), - sql + let expected = format!( + "{} {} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (("t"."a") = (1) and ("t"."b") = (2) and ("t"."c") = (4)"#, + r#"or ("t"."a") = (3) and ("t"."c") = (4))"#, ); + + assert_eq!(sql_to_sql(input, &set_dnf), expected); } #[test] fn dnf2() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE ("a" = 1 OR "b" = 2) AND ("a" = 3 OR "c" = 4)"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.set_dnf().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (((("t"."a") = (3) and ("t"."a") = (1) or ("t"."c") = (4) and ("t"."a") = (1))"#, - r#"or ("t"."a") = (3) and ("t"."b") = (2)) or ("t"."c") = (4) and ("t"."b") = (2))"#, - ), - sql + let expected = format!( + "{} {} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (((("t"."a") = (3) and ("t"."a") = (1) or ("t"."c") = (4) and ("t"."a") = (1))"#, + r#"or ("t"."a") = (3) and ("t"."b") = (2)) or ("t"."c") = (4) and ("t"."b") = (2))"#, ); + + assert_eq!(sql_to_sql(input, &set_dnf), expected); } #[test] fn dnf3() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE ("a" = 1 OR "b" = 2) AND NULL"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.set_dnf().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (("t"."a") = (1) and (NULL) or ("t"."b") = (2) and (NULL))"#, - ), - sql + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (("t"."a") = (1) and (NULL) or ("t"."b") = (2) and (NULL))"#, ); + + assert_eq!(sql_to_sql(input, &set_dnf), expected); } #[test] fn dnf4() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE ("a" = 1 OR "b" = 2) AND true"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.set_dnf().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (("t"."a") = (1) and (true) or ("t"."b") = (2) and (true))"#, - ), - sql + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (("t"."a") = (1) and (true) or ("t"."b") = (2) and (true))"#, ); + + assert_eq!(sql_to_sql(input, &set_dnf), expected); } #[test] fn dnf5() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE ("a" = 1 OR "b" = 2) AND ((false))"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.set_dnf().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (("t"."a") = (1) and ((false)) or ("t"."b") = (2) and ((false)))"#, - ), - sql + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (("t"."a") = (1) and ((false)) or ("t"."b") = (2) and ((false)))"#, ); + + assert_eq!(sql_to_sql(input, &set_dnf), expected); } #[test] fn dnf6() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE "a" = 1 and "c" = 1 OR "b" = 2"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.set_dnf().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (("t"."a") = (1) and ("t"."c") = (1) or ("t"."b") = (2))"#, - ), - sql + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (("t"."a") = (1) and ("t"."c") = (1) or ("t"."b") = (2))"#, ); + + assert_eq!(sql_to_sql(input, &set_dnf), expected); } diff --git a/src/ir/transformation/equality_propagation/tests.rs b/src/ir/transformation/equality_propagation/tests.rs index 3661375ef2..494f0d3806 100644 --- a/src/ir/transformation/equality_propagation/tests.rs +++ b/src/ir/transformation/equality_propagation/tests.rs @@ -1,6 +1,11 @@ -use crate::ir::transformation::helpers::transform_sql; +use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::Plan; use pretty_assertions::assert_eq; +fn derive_equalities(plan: &mut Plan) { + plan.derive_equalities().unwrap(); +} + #[test] fn equality_propagation1() { let input = r#"SELECT "a" FROM "t" @@ -13,7 +18,7 @@ fn equality_propagation1() { r#"and ("t"."c") = ("t"."a") or ("t"."d") = (1))"#, ); - assert_eq!(transform_sql(input), expected); + assert_eq!(sql_to_sql(input, &derive_equalities), expected); } #[test] @@ -26,7 +31,7 @@ fn equality_propagation2() { r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") = (NULL) and ("t"."b") = (NULL)"#, ); - assert_eq!(transform_sql(input), expected); + assert_eq!(sql_to_sql(input, &derive_equalities), expected); } #[test] @@ -40,7 +45,7 @@ fn equality_propagation3() { r#"WHERE ("t"."a") = (1) and ("t"."b") = (NULL) and ("t"."a") = (NULL)"#, ); - assert_eq!(transform_sql(input), expected); + assert_eq!(sql_to_sql(input, &derive_equalities), expected); } #[test] @@ -55,7 +60,7 @@ fn equality_propagation4() { r#"and ("t"."b") = (1) and ("t"."a") = ("t"."b")"#, ); - assert_eq!(transform_sql(input), expected); + assert_eq!(sql_to_sql(input, &derive_equalities), expected); } #[test] @@ -72,5 +77,5 @@ fn equality_propagation5() { r#"and ("t"."d") = ("t"."b")"#, ); - assert_eq!(transform_sql(input), expected); + assert_eq!(sql_to_sql(input, &derive_equalities), expected); } diff --git a/src/ir/transformation/helpers.rs b/src/ir/transformation/helpers.rs index 11a0bc6836..9f76b45a8e 100644 --- a/src/ir/transformation/helpers.rs +++ b/src/ir/transformation/helpers.rs @@ -1,15 +1,24 @@ +//! IR test helpers. + use crate::executor::engine::mock::MetadataMock; use crate::executor::ir::ExecutionPlan; use crate::frontend::sql::ast::AbstractSyntaxTree; +use crate::ir::Plan; +/// Compile an SQL query to IR plan. #[allow(dead_code)] -pub fn transform_sql(input: &str) -> String { +pub fn sql_to_ir(input: &str) -> Plan { let metadata = &MetadataMock::new(); let ast = AbstractSyntaxTree::new(input).unwrap(); + let plan = ast.to_ir(metadata).unwrap(); + plan +} - let mut plan = ast.to_ir(metadata).unwrap(); - plan.derive_equalities().unwrap(); - +/// Compile and transform an SQL query to a new SQL. +#[allow(dead_code)] +pub fn sql_to_sql(input: &str, f_transform: &dyn Fn(&mut Plan)) -> String { + let mut plan = sql_to_ir(input); + f_transform(&mut plan); let ex_plan = ExecutionPlan::from(plan); let top_id = ex_plan.get_ir_plan().get_top().unwrap(); ex_plan.subtree_as_sql(top_id).unwrap() diff --git a/src/ir/transformation/merge_tuples/tests.rs b/src/ir/transformation/merge_tuples/tests.rs index 1ec3f7c0e8..53f9df5236 100644 --- a/src/ir/transformation/merge_tuples/tests.rs +++ b/src/ir/transformation/merge_tuples/tests.rs @@ -1,112 +1,64 @@ +use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::Plan; use pretty_assertions::assert_eq; -use crate::executor::engine::mock::MetadataMock; -use crate::executor::ir::ExecutionPlan; -use crate::frontend::sql::ast::AbstractSyntaxTree; +fn merge_tuples(plan: &mut Plan) { + plan.merge_tuples().unwrap(); +} #[test] fn merge_tuples1() { - let query = r#"SELECT "a" FROM "t" WHERE "a" = 1 and "b" = 2 and "c" < 3 and 4 < "a""#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.merge_tuples().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE ("t"."a", "t"."b") = (1, 2) and (3, "t"."a") > ("t"."c", 4)"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE "a" = 1 and "b" = 2 and "c" < 3 and 4 < "a""#; + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE ("t"."a", "t"."b") = (1, 2) and (3, "t"."a") > ("t"."c", 4)"#, ); + + assert_eq!(sql_to_sql(input, &merge_tuples), expected); } #[test] fn merge_tuples2() { - let query = r#"SELECT "a" FROM "t" + let input = r#"SELECT "a" FROM "t" WHERE "a" = 1 and null and "b" = 2 or true and "c" >= 3 and 4 <= "a""#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.merge_tuples().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, - r#"WHERE (("t"."a", "t"."b") = (1, 2) and (NULL)"#, - r#"or ("t"."c", "t"."a") >= (3, 4) and (true))"#, - ), - sql + let expected = format!( + "{} {} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, + r#"WHERE (("t"."a", "t"."b") = (1, 2) and (NULL)"#, + r#"or ("t"."c", "t"."a") >= (3, 4) and (true))"#, ); + + assert_eq!(sql_to_sql(input, &merge_tuples), expected); } #[test] fn merge_tuples3() { - let query = r#"SELECT "a" FROM "t" WHERE true"#; + let input = r#"SELECT "a" FROM "t" WHERE true"#; + let expected = format!("{}", r#"SELECT "t"."a" as "a" FROM "t" WHERE true"#); - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.merge_tuples().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!("{}", r#"SELECT "t"."a" as "a" FROM "t" WHERE true"#,), - sql - ); + assert_eq!(sql_to_sql(input, &merge_tuples), expected); } #[test] fn merge_tuples4() { - let query = r#"SELECT "a" FROM "t" WHERE ("a", "b") = (1, 2) and 3 = "c""#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.merge_tuples().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, r#"WHERE ("t"."a", "t"."b", "t"."c") = (1, 2, 3)"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE ("a", "b") = (1, 2) and 3 = "c""#; + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, r#"WHERE ("t"."a", "t"."b", "t"."c") = (1, 2, 3)"#, ); + + assert_eq!(sql_to_sql(input, &merge_tuples), expected); } #[test] fn merge_tuples5() { - let query = r#"SELECT "a" FROM "t" WHERE 3 < "c" and ("a", "b") > (1, 2)"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.merge_tuples().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t""#, r#"WHERE ("t"."c", "t"."a", "t"."b") > (3, 1, 2)"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE 3 < "c" and ("a", "b") > (1, 2)"#; + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t""#, r#"WHERE ("t"."c", "t"."a", "t"."b") > (3, 1, 2)"#, ); + + assert_eq!(sql_to_sql(input, &merge_tuples), expected); } diff --git a/src/ir/transformation/redistribution/tests.rs b/src/ir/transformation/redistribution/tests.rs index be0793b175..7de2daeefc 100644 --- a/src/ir/transformation/redistribution/tests.rs +++ b/src/ir/transformation/redistribution/tests.rs @@ -1,12 +1,11 @@ use super::*; use crate::collection; use crate::errors::QueryPlannerError; -use crate::executor::engine::mock::MetadataMock; -use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::ir::distribution::*; use crate::ir::operator::Relational; use crate::ir::relation::*; -use crate::ir::*; +use crate::ir::transformation::helpers::sql_to_ir; +use crate::ir::Plan; use pretty_assertions::assert_eq; use std::fs; use std::path::Path; @@ -304,19 +303,17 @@ fn multiple_sub_queries() { #[test] fn union_all_in_sq() { let query = r#"SELECT * - FROM - (SELECT "identification_number", "product_code" - FROM "hash_testing" - WHERE "sys_op" = 1 - UNION ALL - SELECT "identification_number", "product_code" - FROM "hash_testing_hist" - WHERE "sys_op" > 1) AS "t3" - WHERE "identification_number" = 1"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + FROM + (SELECT "identification_number", "product_code" + FROM "hash_testing" + WHERE "sys_op" = 1 + UNION ALL + SELECT "identification_number", "product_code" + FROM "hash_testing_hist" + WHERE "sys_op" > 1) AS "t3" + WHERE "identification_number" = 1"#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let expected: Option<Vec<Vec<usize>>> = None; assert_eq!(expected, plan.slices); @@ -325,12 +322,10 @@ fn union_all_in_sq() { #[test] fn inner_join_eq_for_keys() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN "t" - ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b")"#; + INNER JOIN "t" + ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b")"#; - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let expected: Option<Vec<Vec<usize>>> = None; assert_eq!(expected, plan.slices); @@ -339,13 +334,11 @@ fn inner_join_eq_for_keys() { #[test] fn join_inner_sq_eq_for_keys() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", "t1"."product_code") = ("t2"."id", "t2"."pc")"#; + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", "t1"."product_code") = ("t2"."id", "t2"."pc")"#; - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let expected: Option<Vec<Vec<usize>>> = None; assert_eq!(expected, plan.slices); @@ -354,13 +347,11 @@ fn join_inner_sq_eq_for_keys() { #[test] fn join_inner_eq_non_match_keys() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", "t1"."product_code") = ("t2"."pc", "t2"."id")"#; + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", "t1"."product_code") = ("t2"."pc", "t2"."id")"#; - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices @@ -386,13 +377,11 @@ fn join_inner_eq_non_match_keys() { #[test] fn join_inner_sq_eq_for_keys_with_const() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", 1, "t1"."product_code") = ("t2"."id", 1, "t2"."pc")"#; + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", 1, "t1"."product_code") = ("t2"."id", 1, "t2"."pc")"#; - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let expected: Option<Vec<Vec<usize>>> = None; assert_eq!(expected, plan.slices); @@ -401,13 +390,11 @@ fn join_inner_sq_eq_for_keys_with_const() { #[test] fn join_inner_sq_less_for_keys() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", "t1"."product_code") < ("t2"."id", "t2"."pc")"#; + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", "t1"."product_code") < ("t2"."id", "t2"."pc")"#; - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices @@ -428,13 +415,11 @@ fn join_inner_sq_less_for_keys() { #[test] fn join_inner_sq_eq_no_keys() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", 1) = (1, "t2"."pc")"#; + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", 1) = (1, "t2"."pc")"#; - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices @@ -455,13 +440,11 @@ fn join_inner_sq_eq_no_keys() { #[test] fn join_inner_sq_eq_no_outer_keys() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", 1) = ("t2"."id", "t2"."pc")"#; + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", 1) = ("t2"."id", "t2"."pc")"#; - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices @@ -482,14 +465,12 @@ fn join_inner_sq_eq_no_outer_keys() { #[test] fn inner_join_full_policy_sq_in_filter() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN "t" - ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") - AND ("t"."a", "t"."b") >= - (SELECT "hash_testing"."sys_op", "hash_testing"."bucket_id" FROM "hash_testing")"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + INNER JOIN "t" + ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") + AND ("t"."a", "t"."b") >= + (SELECT "hash_testing"."sys_op", "hash_testing"."bucket_id" FROM "hash_testing")"#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices @@ -510,14 +491,12 @@ fn inner_join_full_policy_sq_in_filter() { #[test] fn inner_join_local_policy_sq_in_filter() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN "t" - ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") - AND ("t"."a", "t"."b") = - (SELECT "hash_testing"."identification_number", "hash_testing"."product_code" FROM "hash_testing")"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + INNER JOIN "t" + ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") + AND ("t"."a", "t"."b") = + (SELECT "hash_testing"."identification_number", "hash_testing"."product_code" FROM "hash_testing")"#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let expected: Option<Vec<Vec<usize>>> = None; assert_eq!(expected, plan.slices); @@ -526,16 +505,14 @@ fn inner_join_local_policy_sq_in_filter() { #[test] fn inner_join_local_policy_sq_with_union_all_in_filter() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN "t" - ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") - AND ("t"."a", "t"."b") = - (SELECT "hash_testing"."identification_number", "hash_testing"."product_code" FROM "hash_testing" - UNION ALL - SELECT "hash_testing_hist"."identification_number", "hash_testing_hist"."product_code" FROM "hash_testing_hist")"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + INNER JOIN "t" + ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") + AND ("t"."a", "t"."b") = + (SELECT "hash_testing"."identification_number", "hash_testing"."product_code" FROM "hash_testing" + UNION ALL + SELECT "hash_testing_hist"."identification_number", "hash_testing_hist"."product_code" FROM "hash_testing_hist")"#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let expected: Option<Vec<Vec<usize>>> = None; assert_eq!(expected, plan.slices); @@ -544,16 +521,14 @@ fn inner_join_local_policy_sq_with_union_all_in_filter() { #[test] fn inner_join_full_policy_sq_with_union_all_in_filter() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN "t" - ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") - AND ("t"."a", "t"."b") = - (SELECT "hash_testing"."identification_number", "hash_testing"."product_code" FROM "hash_testing" - UNION ALL - SELECT "hash_testing_hist"."product_code", "hash_testing_hist"."identification_number" FROM "hash_testing_hist")"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + INNER JOIN "t" + ON ("t1"."identification_number", "t1"."product_code") = ("t"."a", "t"."b") + AND ("t"."a", "t"."b") = + (SELECT "hash_testing"."identification_number", "hash_testing"."product_code" FROM "hash_testing" + UNION ALL + SELECT "hash_testing_hist"."product_code", "hash_testing_hist"."identification_number" FROM "hash_testing_hist")"#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices @@ -579,14 +554,12 @@ fn inner_join_full_policy_sq_with_union_all_in_filter() { #[test] fn join_inner_and_local_full_policies() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", "t1"."product_code") = ("t2"."id", "t2"."pc") - AND "t1"."identification_number" = "t2"."pc""#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", "t1"."product_code") = ("t2"."id", "t2"."pc") + AND "t1"."identification_number" = "t2"."pc""#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let expected: Option<Vec<Vec<usize>>> = None; assert_eq!(expected, plan.slices); @@ -595,14 +568,12 @@ fn join_inner_and_local_full_policies() { #[test] fn join_inner_or_local_full_policies() { let query = r#"SELECT * FROM "hash_testing" AS "t1" - INNER JOIN - (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" - ON ("t1"."identification_number", "t1"."product_code") = ("t2"."id", "t2"."pc") - OR "t1"."identification_number" = "t2"."pc""#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + INNER JOIN + (SELECT "identification_number" as "id", "product_code" as "pc" FROM "hash_testing_hist") AS "t2" + ON ("t1"."identification_number", "t1"."product_code") = ("t2"."id", "t2"."pc") + OR "t1"."identification_number" = "t2"."pc""#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices @@ -623,29 +594,27 @@ fn join_inner_or_local_full_policies() { #[test] fn join1() { let query = r#"SELECT * - FROM - (SELECT "id", "FIRST_NAME" - FROM "test_space" - WHERE "sys_op" < 0 - AND "sysFrom" >= 0 - UNION ALL - SELECT "id", "FIRST_NAME" - FROM "test_space_hist" - WHERE "sysFrom" <= 0) AS "t3" - INNER JOIN - (SELECT "identification_number" - FROM "hash_testing_hist" - WHERE "sys_op" > 0 - UNION ALL - SELECT "identification_number" - FROM "hash_single_testing_hist" - WHERE "sys_op" <= 0) AS "t8" - ON "t3"."id" = "t8"."identification_number" - WHERE "t3"."id" = 1 AND "t8"."identification_number" = 1"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); + FROM + (SELECT "id", "FIRST_NAME" + FROM "test_space" + WHERE "sys_op" < 0 + AND "sysFrom" >= 0 + UNION ALL + SELECT "id", "FIRST_NAME" + FROM "test_space_hist" + WHERE "sysFrom" <= 0) AS "t3" + INNER JOIN + (SELECT "identification_number" + FROM "hash_testing_hist" + WHERE "sys_op" > 0 + UNION ALL + SELECT "identification_number" + FROM "hash_single_testing_hist" + WHERE "sys_op" <= 0) AS "t8" + ON "t3"."id" = "t8"."identification_number" + WHERE "t3"."id" = 1 AND "t8"."identification_number" = 1"#; + + let mut plan = sql_to_ir(query); plan.add_motions().unwrap(); let motion_id = *plan .slices diff --git a/src/ir/transformation/split_columns/tests.rs b/src/ir/transformation/split_columns/tests.rs index c1a552bc0d..aca3593d4e 100644 --- a/src/ir/transformation/split_columns/tests.rs +++ b/src/ir/transformation/split_columns/tests.rs @@ -1,49 +1,33 @@ -use pretty_assertions::assert_eq; - use crate::executor::engine::mock::MetadataMock; -use crate::executor::ir::ExecutionPlan; use crate::frontend::sql::ast::AbstractSyntaxTree; +use crate::ir::transformation::helpers::sql_to_sql; +use crate::ir::Plan; +use pretty_assertions::assert_eq; -#[test] -fn split_columns1() { - let query = r#"SELECT "a" FROM "t" WHERE ("a", 2) = (1, "b")"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); +fn split_columns(plan: &mut Plan) { plan.split_columns().unwrap(); - let ex_plan = ExecutionPlan::from(plan); +} - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{}", - r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") = (1) and (2) = ("t"."b")"#, - ), - sql +#[test] +fn split_columns1() { + let input = r#"SELECT "a" FROM "t" WHERE ("a", 2) = (1, "b")"#; + let expected = format!( + "{}", + r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") = (1) and (2) = ("t"."b")"#, ); + + assert_eq!(sql_to_sql(input, &split_columns), expected); } #[test] fn split_columns2() { - let query = r#"SELECT "a" FROM "t" WHERE "a" = 1"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.split_columns().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{}", - r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") = (1)"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE "a" = 1"#; + let expected = format!( + "{}", + r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") = (1)"#, ); + + assert_eq!(sql_to_sql(input, &split_columns), expected); } #[test] @@ -67,43 +51,23 @@ fn split_columns3() { #[test] fn split_columns4() { - let query = r#"SELECT "a" FROM "t" WHERE "a" in (1, 2)"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.split_columns().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{}", - r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") in (1, 2)"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE "a" in (1, 2)"#; + let expected = format!( + "{}", + r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") in (1, 2)"#, ); + + assert_eq!(sql_to_sql(input, &split_columns), expected); } #[test] fn split_columns5() { - let query = r#"SELECT "a" FROM "t" WHERE ("a", 2) < (1, "b") and "a" > 2"#; - - let metadata = &MetadataMock::new(); - let ast = AbstractSyntaxTree::new(query).unwrap(); - let mut plan = ast.to_ir(metadata).unwrap(); - plan.split_columns().unwrap(); - let ex_plan = ExecutionPlan::from(plan); - - let top_id = ex_plan.get_ir_plan().get_top().unwrap(); - let sql = ex_plan.subtree_as_sql(top_id).unwrap(); - assert_eq!( - format!( - "{} {}", - r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") < (1) and (2) < ("t"."b")"#, - r#"and ("t"."a") > (2)"#, - ), - sql + let input = r#"SELECT "a" FROM "t" WHERE ("a", 2) < (1, "b") and "a" > 2"#; + let expected = format!( + "{} {}", + r#"SELECT "t"."a" as "a" FROM "t" WHERE ("t"."a") < (1) and (2) < ("t"."b")"#, + r#"and ("t"."a") > (2)"#, ); + + assert_eq!(sql_to_sql(input, &split_columns), expected); } -- GitLab