From ffe9ba7db32a07cc492046dd8999b6ac55e22265 Mon Sep 17 00:00:00 2001 From: Arseniy Volynets <vol0ncar@yandex.ru> Date: Wed, 15 May 2024 00:14:58 +0000 Subject: [PATCH] fix: double motion under left join in case of cte --- sbroad-core/src/frontend/sql/ir/tests/cte.rs | 32 +++++++++++++++++++ .../redistribution/left_join.rs | 29 +++++++++++++++-- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/sbroad-core/src/frontend/sql/ir/tests/cte.rs b/sbroad-core/src/frontend/sql/ir/tests/cte.rs index 26c0b7a02a..ca97c9bb27 100644 --- a/sbroad-core/src/frontend/sql/ir/tests/cte.rs +++ b/sbroad-core/src/frontend/sql/ir/tests/cte.rs @@ -417,3 +417,35 @@ fn cte_column_mismatch() { )) ); } + +#[test] +fn cte_with_left_join() { + let sql = r#" + with cte as (select "e" as e from "t2") + select e from cte left join "t2" + on true + "#; + + let plan = sql_to_optimized_ir(sql, vec![]); + + let expected_explain = String::from( + r#"projection ("E"::unsigned -> "E") + motion [policy: full] + scan + projection ("CTE"."E"::unsigned -> "E", "t2"."e"::unsigned -> "e", "t2"."f"::unsigned -> "f", "t2"."g"::unsigned -> "g", "t2"."h"::unsigned -> "h") + join on true::boolean + scan cte "CTE"($0) + scan "t2" + projection ("t2"."e"::unsigned -> "e", "t2"."f"::unsigned -> "f", "t2"."g"::unsigned -> "g", "t2"."h"::unsigned -> "h") + scan "t2" +subquery $0: +motion [policy: full] + projection ("t2"."e"::unsigned -> "E") + scan "t2" +execution options: +sql_vdbe_max_steps = 45000 +vtable_max_rows = 5000 +"#, + ); + assert_eq!(expected_explain, plan.as_explain().unwrap()); +} diff --git a/sbroad-core/src/ir/transformation/redistribution/left_join.rs b/sbroad-core/src/ir/transformation/redistribution/left_join.rs index 0e6691ba14..064d3bb7ff 100644 --- a/sbroad-core/src/ir/transformation/redistribution/left_join.rs +++ b/sbroad-core/src/ir/transformation/redistribution/left_join.rs @@ -51,9 +51,32 @@ impl Plan { self.change_child(parent_id, join_id, sq_id)?; let outer_id = self.get_relational_child(join_id, 0)?; - let outer_child_motion_id = - self.add_motion(outer_id, &MotionPolicy::Full, Program::default())?; - self.change_child(join_id, outer_id, outer_child_motion_id)?; + + // In case there are no motions under outer child, + // we need to add one, because we need to materialize + // the subtree from which missing rows will be added. + let outer_child_motion_id = { + let child = self.get_relation_node(outer_id)?; + let mut motion_child_id = None; + + // Check if there is already motion under outer child + if child.is_subquery_or_cte() { + let sq_child = self.get_relational_child(outer_id, 0)?; + if self.get_relation_node(sq_child)?.is_motion() { + motion_child_id = Some(sq_child); + } + } else if child.is_motion() { + motion_child_id = Some(outer_id); + } + + if motion_child_id.is_none() { + let motion_id = + self.add_motion(outer_id, &MotionPolicy::Full, Program::default())?; + self.change_child(join_id, outer_id, motion_id)?; + motion_child_id = Some(motion_id); + } + motion_child_id.unwrap() + }; // Add motion which will do the reduce stage of joining: // adding missing rows. -- GitLab