diff --git a/sbroad-core/src/frontend/sql/ir/tests.rs b/sbroad-core/src/frontend/sql/ir/tests.rs index aad71980fc7131caba5a620f189a14e880de7982..0a6629775ec72c644496cab70858c9f3a2a2263e 100644 --- a/sbroad-core/src/frontend/sql/ir/tests.rs +++ b/sbroad-core/src/frontend/sql/ir/tests.rs @@ -1359,6 +1359,44 @@ fn front_sql_unique_local_groupings() { assert_eq!(expected_explain, plan.as_explain().unwrap()); } + +#[test] +fn front_sql_join_table_with_bucket_id_as_first_col() { + // here we are joining t3 who has bucket_id as its first column, + // check that we correctly handle references in join condition, + // after inserting SQ with Projection under outer child + let input = r#" +SELECT * FROM + "t3" +INNER JOIN + (SELECT * FROM "hash_single_testing" INNER JOIN (SELECT "id" FROM "test_space") as "ts" + ON "hash_single_testing"."identification_number" = "ts"."id") as "ij" +ON "t3"."a" = "ij"."id" +"#; + + let plan = sql_to_optimized_ir(input, vec![]); + + let expected_explain = String::from( + r#"projection ("t3"."a" -> "a", "t3"."b" -> "b", "ij"."identification_number" -> "identification_number", "ij"."product_code" -> "product_code", "ij"."product_units" -> "product_units", "ij"."sys_op" -> "sys_op", "ij"."id" -> "id") + join on ROW("t3"."a") = ROW("ij"."id") + scan "t3" + projection ("t3"."a" -> "a", "t3"."b" -> "b") + scan "t3" + scan "ij" + projection ("hash_single_testing"."identification_number" -> "identification_number", "hash_single_testing"."product_code" -> "product_code", "hash_single_testing"."product_units" -> "product_units", "hash_single_testing"."sys_op" -> "sys_op", "ts"."id" -> "id") + join on ROW("hash_single_testing"."identification_number") = ROW("ts"."id") + scan "hash_single_testing" + projection ("hash_single_testing"."identification_number" -> "identification_number", "hash_single_testing"."product_code" -> "product_code", "hash_single_testing"."product_units" -> "product_units", "hash_single_testing"."sys_op" -> "sys_op") + scan "hash_single_testing" + scan "ts" + projection ("test_space"."id" -> "id") + scan "test_space" +"#, + ); + + assert_eq!(expected_explain, plan.as_explain().unwrap()); +} + #[cfg(test)] mod params; mod single; diff --git a/sbroad-core/src/ir/operator.rs b/sbroad-core/src/ir/operator.rs index 89220840e0abd9cfbcd28b5b93b5271586fbd46d..bbba4ed3c0ecd3bee7143047be727ba5074d4c6d 100644 --- a/sbroad-core/src/ir/operator.rs +++ b/sbroad-core/src/ir/operator.rs @@ -18,6 +18,7 @@ use crate::collection; use crate::ir::distribution::{Distribution, KeySet}; use crate::ir::helpers::RepeatableState; use crate::ir::relation::ColumnRole; +use crate::ir::transformation::redistribution::JoinChild; /// Binary operator returning Bool expression. #[derive(Serialize, Deserialize, PartialEq, Debug, Eq, Hash, Clone)] @@ -783,7 +784,7 @@ impl Plan { // to the child's output in the condition expression as // we have filtered out the sharding column. let mut children: Vec<usize> = Vec::with_capacity(2); - for child in &[left, right] { + for (child, join_child) in &[(left, JoinChild::Outer), (right, JoinChild::Inner)] { let child_node = self.get_relation_node(*child)?; if let Relational::ScanRelation { relation, alias, .. @@ -822,10 +823,18 @@ impl Plan { } }) .collect::<Vec<_>>(); + // we should update ONLY references that refer to current child (left, right) + let current_target = match join_child { + JoinChild::Inner => Some(vec![1_usize]), + JoinChild::Outer => Some(vec![0_usize]), + }; for ref_id in refs { let expr = self.get_mut_expression_node(ref_id)?; - if let Expression::Reference { position, .. } = expr { - if *position > sharding_column_pos { + if let Expression::Reference { + position, targets, .. + } = expr + { + if current_target == *targets && *position > sharding_column_pos { *position -= 1; } }