mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-26 08:54:06 +00:00
Support SEMI/ANTI JOIN syntax (#723)
This commit is contained in:
parent
1f22ea74ae
commit
96bca38fae
4 changed files with 118 additions and 7 deletions
|
@ -611,6 +611,34 @@ impl fmt::Display for Join {
|
||||||
suffix(constraint)
|
suffix(constraint)
|
||||||
),
|
),
|
||||||
JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
|
JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
|
||||||
|
JoinOperator::LeftSemi(constraint) => write!(
|
||||||
|
f,
|
||||||
|
" {}LEFT SEMI JOIN {}{}",
|
||||||
|
prefix(constraint),
|
||||||
|
self.relation,
|
||||||
|
suffix(constraint)
|
||||||
|
),
|
||||||
|
JoinOperator::RightSemi(constraint) => write!(
|
||||||
|
f,
|
||||||
|
" {}RIGHT SEMI JOIN {}{}",
|
||||||
|
prefix(constraint),
|
||||||
|
self.relation,
|
||||||
|
suffix(constraint)
|
||||||
|
),
|
||||||
|
JoinOperator::LeftAnti(constraint) => write!(
|
||||||
|
f,
|
||||||
|
" {}LEFT ANTI JOIN {}{}",
|
||||||
|
prefix(constraint),
|
||||||
|
self.relation,
|
||||||
|
suffix(constraint)
|
||||||
|
),
|
||||||
|
JoinOperator::RightAnti(constraint) => write!(
|
||||||
|
f,
|
||||||
|
" {}RIGHT ANTI JOIN {}{}",
|
||||||
|
prefix(constraint),
|
||||||
|
self.relation,
|
||||||
|
suffix(constraint)
|
||||||
|
),
|
||||||
JoinOperator::CrossApply => write!(f, " CROSS APPLY {}", self.relation),
|
JoinOperator::CrossApply => write!(f, " CROSS APPLY {}", self.relation),
|
||||||
JoinOperator::OuterApply => write!(f, " OUTER APPLY {}", self.relation),
|
JoinOperator::OuterApply => write!(f, " OUTER APPLY {}", self.relation),
|
||||||
}
|
}
|
||||||
|
@ -625,6 +653,14 @@ pub enum JoinOperator {
|
||||||
RightOuter(JoinConstraint),
|
RightOuter(JoinConstraint),
|
||||||
FullOuter(JoinConstraint),
|
FullOuter(JoinConstraint),
|
||||||
CrossJoin,
|
CrossJoin,
|
||||||
|
/// LEFT SEMI (non-standard)
|
||||||
|
LeftSemi(JoinConstraint),
|
||||||
|
/// RIGHT SEMI (non-standard)
|
||||||
|
RightSemi(JoinConstraint),
|
||||||
|
/// LEFT ANTI (non-standard)
|
||||||
|
LeftAnti(JoinConstraint),
|
||||||
|
/// RIGHT ANTI (non-standard)
|
||||||
|
RightAnti(JoinConstraint),
|
||||||
/// CROSS APPLY (non-standard)
|
/// CROSS APPLY (non-standard)
|
||||||
CrossApply,
|
CrossApply,
|
||||||
/// OUTER APPLY (non-standard)
|
/// OUTER APPLY (non-standard)
|
||||||
|
|
|
@ -77,6 +77,7 @@ define_keywords!(
|
||||||
ALTER,
|
ALTER,
|
||||||
ANALYZE,
|
ANALYZE,
|
||||||
AND,
|
AND,
|
||||||
|
ANTI,
|
||||||
ANY,
|
ANY,
|
||||||
APPLY,
|
APPLY,
|
||||||
ARCHIVE,
|
ARCHIVE,
|
||||||
|
@ -491,6 +492,7 @@ define_keywords!(
|
||||||
SEARCH,
|
SEARCH,
|
||||||
SECOND,
|
SECOND,
|
||||||
SELECT,
|
SELECT,
|
||||||
|
SEMI,
|
||||||
SENSITIVE,
|
SENSITIVE,
|
||||||
SEQUENCE,
|
SEQUENCE,
|
||||||
SEQUENCEFILE,
|
SEQUENCEFILE,
|
||||||
|
|
|
@ -4830,17 +4830,58 @@ impl<'a> Parser<'a> {
|
||||||
self.expect_keyword(Keyword::JOIN)?;
|
self.expect_keyword(Keyword::JOIN)?;
|
||||||
JoinOperator::Inner
|
JoinOperator::Inner
|
||||||
}
|
}
|
||||||
kw @ Keyword::LEFT | kw @ Keyword::RIGHT | kw @ Keyword::FULL => {
|
kw @ Keyword::LEFT | kw @ Keyword::RIGHT => {
|
||||||
let _ = self.next_token();
|
let _ = self.next_token();
|
||||||
let _ = self.parse_keyword(Keyword::OUTER);
|
let join_type = self.parse_one_of_keywords(&[
|
||||||
|
Keyword::OUTER,
|
||||||
|
Keyword::SEMI,
|
||||||
|
Keyword::ANTI,
|
||||||
|
Keyword::JOIN,
|
||||||
|
]);
|
||||||
|
match join_type {
|
||||||
|
Some(Keyword::OUTER) => {
|
||||||
self.expect_keyword(Keyword::JOIN)?;
|
self.expect_keyword(Keyword::JOIN)?;
|
||||||
match kw {
|
match kw {
|
||||||
Keyword::LEFT => JoinOperator::LeftOuter,
|
Keyword::LEFT => JoinOperator::LeftOuter,
|
||||||
Keyword::RIGHT => JoinOperator::RightOuter,
|
Keyword::RIGHT => JoinOperator::RightOuter,
|
||||||
Keyword::FULL => JoinOperator::FullOuter,
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(Keyword::SEMI) => {
|
||||||
|
self.expect_keyword(Keyword::JOIN)?;
|
||||||
|
match kw {
|
||||||
|
Keyword::LEFT => JoinOperator::LeftSemi,
|
||||||
|
Keyword::RIGHT => JoinOperator::RightSemi,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(Keyword::ANTI) => {
|
||||||
|
self.expect_keyword(Keyword::JOIN)?;
|
||||||
|
match kw {
|
||||||
|
Keyword::LEFT => JoinOperator::LeftAnti,
|
||||||
|
Keyword::RIGHT => JoinOperator::RightAnti,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(Keyword::JOIN) => match kw {
|
||||||
|
Keyword::LEFT => JoinOperator::LeftOuter,
|
||||||
|
Keyword::RIGHT => JoinOperator::RightOuter,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(ParserError::ParserError(format!(
|
||||||
|
"expected OUTER, SEMI, ANTI or JOIN after {:?}",
|
||||||
|
kw
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::FULL => {
|
||||||
|
let _ = self.next_token();
|
||||||
|
let _ = self.parse_keyword(Keyword::OUTER);
|
||||||
|
self.expect_keyword(Keyword::JOIN)?;
|
||||||
|
JoinOperator::FullOuter
|
||||||
|
}
|
||||||
Keyword::OUTER => {
|
Keyword::OUTER => {
|
||||||
return self.expected("LEFT, RIGHT, or FULL", self.peek_token());
|
return self.expected("LEFT, RIGHT, or FULL", self.peek_token());
|
||||||
}
|
}
|
||||||
|
|
|
@ -3868,6 +3868,22 @@ fn parse_joins_on() {
|
||||||
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::RightOuter)]
|
vec![join_with_constraint("t2", None, JoinOperator::RightOuter)]
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 LEFT SEMI JOIN t2 ON c1 = c2").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::LeftSemi)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 RIGHT SEMI JOIN t2 ON c1 = c2").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::RightSemi)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 LEFT ANTI JOIN t2 ON c1 = c2").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::LeftAnti)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 RIGHT ANTI JOIN t2 ON c1 = c2").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::RightAnti)]
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 FULL JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 FULL JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::FullOuter)]
|
vec![join_with_constraint("t2", None, JoinOperator::FullOuter)]
|
||||||
|
@ -3917,6 +3933,22 @@ fn parse_joins_using() {
|
||||||
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 USING(c1)").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 USING(c1)").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::RightOuter)]
|
vec![join_with_constraint("t2", None, JoinOperator::RightOuter)]
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 LEFT SEMI JOIN t2 USING(c1)").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::LeftSemi)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 RIGHT SEMI JOIN t2 USING(c1)").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::RightSemi)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 LEFT ANTI JOIN t2 USING(c1)").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::LeftAnti)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 RIGHT ANTI JOIN t2 USING(c1)").from).joins,
|
||||||
|
vec![join_with_constraint("t2", None, JoinOperator::RightAnti)]
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 FULL JOIN t2 USING(c1)").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 FULL JOIN t2 USING(c1)").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::FullOuter)]
|
vec![join_with_constraint("t2", None, JoinOperator::FullOuter)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue