diff --git a/logictests/weird_joins.test b/logictests/weird_joins.test index 07039c1efb..a020e9bf5e 100644 --- a/logictests/weird_joins.test +++ b/logictests/weird_joins.test @@ -79,3 +79,15 @@ ON t1.x = t2.x AND t2.y = 2 ---- 1 + +query II nosort +SELECT t1.x, t2.y +FROM t1 +LEFT OUTER JOIN t2 +ON t2.y = 2 +AND t1.x = t2.x +---- +1 +2 +2 +NULL diff --git a/readyset-server/src/controller/sql/mir/join.rs b/readyset-server/src/controller/sql/mir/join.rs index b0cd199a3b..4a1b9de578 100644 --- a/readyset-server/src/controller/sql/mir/join.rs +++ b/readyset-server/src/controller/sql/mir/join.rs @@ -45,25 +45,30 @@ pub(super) fn make_joins( let mut join_chains = Vec::new(); for jref in qg.join_order.iter() { - let (mut join_kind, jps) = match &qg.edges[&(jref.src.clone(), jref.dst.clone())] { - QueryGraphEdge::Join { on } => (JoinKind::Inner, on), - QueryGraphEdge::LeftJoin { - on, - left_local_preds, - right_local_preds, - global_preds, - params, - } => { - if !(left_local_preds.is_empty() - && right_local_preds.is_empty() - && global_preds.is_empty() - && params.is_empty()) - { - unsupported!("Non equal-join predicates not (yet) supported in left joins"); + let (mut join_kind, jps, left_preds, right_preds) = + match &qg.edges[&(jref.src.clone(), jref.dst.clone())] { + QueryGraphEdge::Join { on } => (JoinKind::Inner, on, None, None), + QueryGraphEdge::LeftJoin { + on, + left_local_preds, + right_local_preds, + global_preds, + params, + } => { + if !global_preds.is_empty() { + unsupported!("Global predicates not yet supported in left joins"); + } + if !params.is_empty() { + unsupported!("Parameters not yet supported in left joins"); + } + ( + JoinKind::Left, + on, + Some(left_local_preds), + Some(right_local_preds), + ) } - (JoinKind::Left, on) - } - }; + }; let (left_chain, right_chain) = pick_join_chains(&jref.src, &jref.dst, &mut join_chains, node_for_rel)?; @@ -80,12 +85,32 @@ pub(super) fn make_joins( } } + let mut left_parent = left_chain.last_node; + for (i, p) in left_preds.into_iter().flatten().enumerate() { + left_parent = mir_converter.make_predicate_nodes( + query_name, + mir_converter.generate_label(&format!("left_local_{i}").into()), + left_parent, + p, + )?; + } + + let mut right_parent = right_chain.last_node; + for (i, p) in right_preds.into_iter().flatten().enumerate() { + right_parent = mir_converter.make_predicate_nodes( + query_name, + mir_converter.generate_label(&format!("right_local_{i}").into()), + right_parent, + p, + )?; + } + let jn = mir_converter.make_join_node( query_name, mir_converter.generate_label(&name), jps, - left_chain.last_node, - right_chain.last_node, + left_parent, + right_parent, join_kind, )?;