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