Skip to content

Commit

Permalink
Differentiate LEFT JOIN from LEFT OUTER JOIN (#1726)
Browse files Browse the repository at this point in the history
  • Loading branch information
mvzink authored Feb 14, 2025
1 parent 1c0e5d3 commit 68c41a9
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 23 deletions.
20 changes: 18 additions & 2 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2077,20 +2077,34 @@ impl fmt::Display for Join {
self.relation,
suffix(constraint)
),
JoinOperator::LeftOuter(constraint) => write!(
JoinOperator::Left(constraint) => write!(
f,
" {}LEFT JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
),
JoinOperator::RightOuter(constraint) => write!(
JoinOperator::LeftOuter(constraint) => write!(
f,
" {}LEFT OUTER JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
),
JoinOperator::Right(constraint) => write!(
f,
" {}RIGHT JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
),
JoinOperator::RightOuter(constraint) => write!(
f,
" {}RIGHT OUTER JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
),
JoinOperator::FullOuter(constraint) => write!(
f,
" {}FULL JOIN {}{}",
Expand Down Expand Up @@ -2162,7 +2176,9 @@ impl fmt::Display for Join {
pub enum JoinOperator {
Join(JoinConstraint),
Inner(JoinConstraint),
Left(JoinConstraint),
LeftOuter(JoinConstraint),
Right(JoinConstraint),
RightOuter(JoinConstraint),
FullOuter(JoinConstraint),
CrossJoin,
Expand Down
2 changes: 2 additions & 0 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2010,7 +2010,9 @@ impl Spanned for JoinOperator {
match self {
JoinOperator::Join(join_constraint) => join_constraint.span(),
JoinOperator::Inner(join_constraint) => join_constraint.span(),
JoinOperator::Left(join_constraint) => join_constraint.span(),
JoinOperator::LeftOuter(join_constraint) => join_constraint.span(),
JoinOperator::Right(join_constraint) => join_constraint.span(),
JoinOperator::RightOuter(join_constraint) => join_constraint.span(),
JoinOperator::FullOuter(join_constraint) => join_constraint.span(),
JoinOperator::CrossJoin => Span::empty(),
Expand Down
6 changes: 3 additions & 3 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5740,7 +5740,7 @@ impl<'a> Parser<'a> {
drop_behavior,
})
}
/// ```sql
/// ```sql
/// DROP CONNECTOR [IF EXISTS] name
/// ```
///
Expand Down Expand Up @@ -11190,9 +11190,9 @@ impl<'a> Parser<'a> {
}
Some(Keyword::JOIN) => {
if is_left {
JoinOperator::LeftOuter
JoinOperator::Left
} else {
JoinOperator::RightOuter
JoinOperator::Right
}
}
_ => {
Expand Down
60 changes: 42 additions & 18 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6661,8 +6661,16 @@ fn parse_joins_on() {
only(&verified_only_select("SELECT * FROM t1 JOIN t2 ON c1 = c2").from).joins,
vec![join_with_constraint("t2", None, false, JoinOperator::Join)]
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 INNER JOIN t2 ON c1 = c2").from).joins,
vec![join_with_constraint("t2", None, false, JoinOperator::Inner)]
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2").from).joins,
vec![join_with_constraint("t2", None, false, JoinOperator::Left)]
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 LEFT OUTER JOIN t2 ON c1 = c2").from).joins,
vec![join_with_constraint(
"t2",
None,
Expand All @@ -6672,6 +6680,10 @@ fn parse_joins_on() {
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 ON c1 = c2").from).joins,
vec![join_with_constraint("t2", None, false, JoinOperator::Right)]
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 RIGHT OUTER JOIN t2 ON c1 = c2").from).joins,
vec![join_with_constraint(
"t2",
None,
Expand Down Expand Up @@ -6794,10 +6806,18 @@ fn parse_joins_using() {
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 LEFT JOIN t2 USING(c1)").from).joins,
vec![join_with_constraint("t2", None, JoinOperator::Left)]
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 LEFT OUTER JOIN t2 USING(c1)").from).joins,
vec![join_with_constraint("t2", None, JoinOperator::LeftOuter)]
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 USING(c1)").from).joins,
vec![join_with_constraint("t2", None, JoinOperator::Right)]
);
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 RIGHT OUTER JOIN t2 USING(c1)").from).joins,
vec![join_with_constraint("t2", None, JoinOperator::RightOuter)]
);
assert_eq!(
Expand Down Expand Up @@ -6857,20 +6877,34 @@ fn parse_natural_join() {
only(&verified_only_select("SELECT * FROM t1 NATURAL JOIN t2").from).joins,
vec![natural_join(JoinOperator::Join, None)]
);

// inner join explicitly
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 NATURAL INNER JOIN t2").from).joins,
vec![natural_join(JoinOperator::Inner, None)]
);

// left join explicitly
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 NATURAL LEFT JOIN t2").from).joins,
vec![natural_join(JoinOperator::Left, None)]
);

// left outer join explicitly
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 NATURAL LEFT OUTER JOIN t2").from).joins,
vec![natural_join(JoinOperator::LeftOuter, None)]
);

// right join explicitly
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 NATURAL RIGHT JOIN t2").from).joins,
vec![natural_join(JoinOperator::Right, None)]
);

// right outer join explicitly
assert_eq!(
only(&verified_only_select("SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2").from).joins,
vec![natural_join(JoinOperator::RightOuter, None)]
);

Expand Down Expand Up @@ -6950,22 +6984,12 @@ fn parse_join_nesting() {

#[test]
fn parse_join_syntax_variants() {
one_statement_parses_to(
"SELECT c1 FROM t1 JOIN t2 USING(c1)",
"SELECT c1 FROM t1 JOIN t2 USING(c1)",
);
one_statement_parses_to(
"SELECT c1 FROM t1 INNER JOIN t2 USING(c1)",
"SELECT c1 FROM t1 INNER JOIN t2 USING(c1)",
);
one_statement_parses_to(
"SELECT c1 FROM t1 LEFT OUTER JOIN t2 USING(c1)",
"SELECT c1 FROM t1 LEFT JOIN t2 USING(c1)",
);
one_statement_parses_to(
"SELECT c1 FROM t1 RIGHT OUTER JOIN t2 USING(c1)",
"SELECT c1 FROM t1 RIGHT JOIN t2 USING(c1)",
);
verified_stmt("SELECT c1 FROM t1 JOIN t2 USING(c1)");
verified_stmt("SELECT c1 FROM t1 INNER JOIN t2 USING(c1)");
verified_stmt("SELECT c1 FROM t1 LEFT JOIN t2 USING(c1)");
verified_stmt("SELECT c1 FROM t1 LEFT OUTER JOIN t2 USING(c1)");
verified_stmt("SELECT c1 FROM t1 RIGHT JOIN t2 USING(c1)");
verified_stmt("SELECT c1 FROM t1 RIGHT OUTER JOIN t2 USING(c1)");
one_statement_parses_to(
"SELECT c1 FROM t1 FULL OUTER JOIN t2 USING(c1)",
"SELECT c1 FROM t1 FULL JOIN t2 USING(c1)",
Expand Down Expand Up @@ -8027,7 +8051,7 @@ fn lateral_derived() {
let join = &from.joins[0];
assert_eq!(
join.join_operator,
JoinOperator::LeftOuter(JoinConstraint::On(Expr::Value(test_utils::number("1"))))
JoinOperator::Left(JoinConstraint::On(Expr::Value(test_utils::number("1"))))
);
if let TableFactor::Derived {
lateral,
Expand Down Expand Up @@ -8095,7 +8119,7 @@ fn lateral_function() {
alias: None,
},
global: false,
join_operator: JoinOperator::LeftOuter(JoinConstraint::None),
join_operator: JoinOperator::Left(JoinConstraint::None),
}],
}],
lateral_views: vec![],
Expand Down

0 comments on commit 68c41a9

Please sign in to comment.