Skip to content

Commit a67a4f3

Browse files
authored
Support ANTI and SEMI joins without LEFT/RIGHT (#1528)
1 parent 4a5f20e commit a67a4f3

File tree

4 files changed

+46
-0
lines changed

4 files changed

+46
-0
lines changed

src/ast/query.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,13 @@ impl fmt::Display for Join {
16941694
suffix(constraint)
16951695
),
16961696
JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
1697+
JoinOperator::Semi(constraint) => write!(
1698+
f,
1699+
" {}SEMI JOIN {}{}",
1700+
prefix(constraint),
1701+
self.relation,
1702+
suffix(constraint)
1703+
),
16971704
JoinOperator::LeftSemi(constraint) => write!(
16981705
f,
16991706
" {}LEFT SEMI JOIN {}{}",
@@ -1708,6 +1715,13 @@ impl fmt::Display for Join {
17081715
self.relation,
17091716
suffix(constraint)
17101717
),
1718+
JoinOperator::Anti(constraint) => write!(
1719+
f,
1720+
" {}ANTI JOIN {}{}",
1721+
prefix(constraint),
1722+
self.relation,
1723+
suffix(constraint)
1724+
),
17111725
JoinOperator::LeftAnti(constraint) => write!(
17121726
f,
17131727
" {}LEFT ANTI JOIN {}{}",
@@ -1746,10 +1760,14 @@ pub enum JoinOperator {
17461760
RightOuter(JoinConstraint),
17471761
FullOuter(JoinConstraint),
17481762
CrossJoin,
1763+
/// SEMI (non-standard)
1764+
Semi(JoinConstraint),
17491765
/// LEFT SEMI (non-standard)
17501766
LeftSemi(JoinConstraint),
17511767
/// RIGHT SEMI (non-standard)
17521768
RightSemi(JoinConstraint),
1769+
/// ANTI (non-standard)
1770+
Anti(JoinConstraint),
17531771
/// LEFT ANTI (non-standard)
17541772
LeftAnti(JoinConstraint),
17551773
/// RIGHT ANTI (non-standard)

src/keywords.rs

+2
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,8 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
892892
Keyword::CLUSTER,
893893
Keyword::DISTRIBUTE,
894894
Keyword::GLOBAL,
895+
Keyword::ANTI,
896+
Keyword::SEMI,
895897
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
896898
Keyword::OUTER,
897899
Keyword::SET,

src/parser/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -10025,6 +10025,16 @@ impl<'a> Parser<'a> {
1002510025
}
1002610026
}
1002710027
}
10028+
Keyword::ANTI => {
10029+
let _ = self.next_token(); // consume ANTI
10030+
self.expect_keyword(Keyword::JOIN)?;
10031+
JoinOperator::Anti
10032+
}
10033+
Keyword::SEMI => {
10034+
let _ = self.next_token(); // consume SEMI
10035+
self.expect_keyword(Keyword::JOIN)?;
10036+
JoinOperator::Semi
10037+
}
1002810038
Keyword::FULL => {
1002910039
let _ = self.next_token(); // consume FULL
1003010040
let _ = self.parse_keyword(Keyword::OUTER); // [ OUTER ]

tests/sqlparser_common.rs

+16
Original file line numberDiff line numberDiff line change
@@ -6013,6 +6013,10 @@ fn parse_joins_on() {
60136013
JoinOperator::RightOuter
60146014
)]
60156015
);
6016+
assert_eq!(
6017+
only(&verified_only_select("SELECT * FROM t1 SEMI JOIN t2 ON c1 = c2").from).joins,
6018+
vec![join_with_constraint("t2", None, false, JoinOperator::Semi)]
6019+
);
60166020
assert_eq!(
60176021
only(&verified_only_select("SELECT * FROM t1 LEFT SEMI JOIN t2 ON c1 = c2").from).joins,
60186022
vec![join_with_constraint(
@@ -6031,6 +6035,10 @@ fn parse_joins_on() {
60316035
JoinOperator::RightSemi
60326036
)]
60336037
);
6038+
assert_eq!(
6039+
only(&verified_only_select("SELECT * FROM t1 ANTI JOIN t2 ON c1 = c2").from).joins,
6040+
vec![join_with_constraint("t2", None, false, JoinOperator::Anti)]
6041+
);
60346042
assert_eq!(
60356043
only(&verified_only_select("SELECT * FROM t1 LEFT ANTI JOIN t2 ON c1 = c2").from).joins,
60366044
vec![join_with_constraint(
@@ -6117,6 +6125,10 @@ fn parse_joins_using() {
61176125
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 USING(c1)").from).joins,
61186126
vec![join_with_constraint("t2", None, JoinOperator::RightOuter)]
61196127
);
6128+
assert_eq!(
6129+
only(&verified_only_select("SELECT * FROM t1 SEMI JOIN t2 USING(c1)").from).joins,
6130+
vec![join_with_constraint("t2", None, JoinOperator::Semi)]
6131+
);
61206132
assert_eq!(
61216133
only(&verified_only_select("SELECT * FROM t1 LEFT SEMI JOIN t2 USING(c1)").from).joins,
61226134
vec![join_with_constraint("t2", None, JoinOperator::LeftSemi)]
@@ -6125,6 +6137,10 @@ fn parse_joins_using() {
61256137
only(&verified_only_select("SELECT * FROM t1 RIGHT SEMI JOIN t2 USING(c1)").from).joins,
61266138
vec![join_with_constraint("t2", None, JoinOperator::RightSemi)]
61276139
);
6140+
assert_eq!(
6141+
only(&verified_only_select("SELECT * FROM t1 ANTI JOIN t2 USING(c1)").from).joins,
6142+
vec![join_with_constraint("t2", None, JoinOperator::Anti)]
6143+
);
61286144
assert_eq!(
61296145
only(&verified_only_select("SELECT * FROM t1 LEFT ANTI JOIN t2 USING(c1)").from).joins,
61306146
vec![join_with_constraint("t2", None, JoinOperator::LeftAnti)]

0 commit comments

Comments
 (0)