mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-26 15:39:12 +00:00
MySQL: Support CROSS JOIN
constraint (#2025)
Some checks failed
Rust / test (beta) (push) Has been cancelled
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Some checks failed
Rust / test (beta) (push) Has been cancelled
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
This commit is contained in:
parent
280f51889f
commit
e3fbfd91b2
6 changed files with 62 additions and 6 deletions
|
@ -2333,7 +2333,11 @@ impl fmt::Display for Join {
|
|||
self.relation,
|
||||
suffix(constraint)
|
||||
)),
|
||||
JoinOperator::CrossJoin => f.write_fmt(format_args!("CROSS JOIN {}", self.relation)),
|
||||
JoinOperator::CrossJoin(constraint) => f.write_fmt(format_args!(
|
||||
"CROSS JOIN {}{}",
|
||||
self.relation,
|
||||
suffix(constraint)
|
||||
)),
|
||||
JoinOperator::Semi(constraint) => f.write_fmt(format_args!(
|
||||
"{}SEMI JOIN {}{}",
|
||||
prefix(constraint),
|
||||
|
@ -2400,7 +2404,8 @@ pub enum JoinOperator {
|
|||
Right(JoinConstraint),
|
||||
RightOuter(JoinConstraint),
|
||||
FullOuter(JoinConstraint),
|
||||
CrossJoin,
|
||||
/// CROSS (constraint is non-standard)
|
||||
CrossJoin(JoinConstraint),
|
||||
/// SEMI (non-standard)
|
||||
Semi(JoinConstraint),
|
||||
/// LEFT SEMI (non-standard)
|
||||
|
|
|
@ -2226,7 +2226,7 @@ impl Spanned for JoinOperator {
|
|||
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(),
|
||||
JoinOperator::CrossJoin(join_constraint) => join_constraint.span(),
|
||||
JoinOperator::LeftSemi(join_constraint) => join_constraint.span(),
|
||||
JoinOperator::RightSemi(join_constraint) => join_constraint.span(),
|
||||
JoinOperator::LeftAnti(join_constraint) => join_constraint.span(),
|
||||
|
|
|
@ -311,6 +311,11 @@ pub trait Dialect: Debug + Any {
|
|||
false
|
||||
}
|
||||
|
||||
/// Returns true if the dialect supports a join specification on CROSS JOIN.
|
||||
fn supports_cross_join_constraint(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns true if the dialect supports CONNECT BY.
|
||||
fn supports_connect_by(&self) -> bool {
|
||||
false
|
||||
|
|
|
@ -163,6 +163,10 @@ impl Dialect for MySqlDialect {
|
|||
fn supports_data_type_signed_suffix(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn supports_cross_join_constraint(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// `LOCK TABLES`
|
||||
|
|
|
@ -13317,15 +13317,24 @@ impl<'a> Parser<'a> {
|
|||
let global = self.parse_keyword(Keyword::GLOBAL);
|
||||
let join = if self.parse_keyword(Keyword::CROSS) {
|
||||
let join_operator = if self.parse_keyword(Keyword::JOIN) {
|
||||
JoinOperator::CrossJoin
|
||||
JoinOperator::CrossJoin(JoinConstraint::None)
|
||||
} else if self.parse_keyword(Keyword::APPLY) {
|
||||
// MSSQL extension, similar to CROSS JOIN LATERAL
|
||||
JoinOperator::CrossApply
|
||||
} else {
|
||||
return self.expected("JOIN or APPLY after CROSS", self.peek_token());
|
||||
};
|
||||
let relation = self.parse_table_factor()?;
|
||||
let join_operator = if matches!(join_operator, JoinOperator::CrossJoin(_))
|
||||
&& self.dialect.supports_cross_join_constraint()
|
||||
{
|
||||
let constraint = self.parse_join_constraint(false)?;
|
||||
JoinOperator::CrossJoin(constraint)
|
||||
} else {
|
||||
join_operator
|
||||
};
|
||||
Join {
|
||||
relation: self.parse_table_factor()?,
|
||||
relation,
|
||||
global,
|
||||
join_operator,
|
||||
}
|
||||
|
|
|
@ -7131,12 +7131,45 @@ fn parse_cross_join() {
|
|||
Join {
|
||||
relation: table_from_name(ObjectName::from(vec![Ident::new("t2")])),
|
||||
global: false,
|
||||
join_operator: JoinOperator::CrossJoin,
|
||||
join_operator: JoinOperator::CrossJoin(JoinConstraint::None),
|
||||
},
|
||||
only(only(select.from).joins),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_cross_join_constraint() {
|
||||
fn join_with_constraint(constraint: JoinConstraint) -> Join {
|
||||
Join {
|
||||
relation: table_from_name(ObjectName::from(vec![Ident::new("t2")])),
|
||||
global: false,
|
||||
join_operator: JoinOperator::CrossJoin(constraint),
|
||||
}
|
||||
}
|
||||
|
||||
fn test_constraint(sql: &str, constraint: JoinConstraint) {
|
||||
let dialect = all_dialects_where(|d| d.supports_cross_join_constraint());
|
||||
let select = dialect.verified_only_select(sql);
|
||||
assert_eq!(
|
||||
join_with_constraint(constraint),
|
||||
only(only(select.from).joins),
|
||||
);
|
||||
}
|
||||
|
||||
test_constraint(
|
||||
"SELECT * FROM t1 CROSS JOIN t2 ON a = b",
|
||||
JoinConstraint::On(Expr::BinaryOp {
|
||||
left: Box::new(Expr::Identifier(Ident::new("a"))),
|
||||
op: BinaryOperator::Eq,
|
||||
right: Box::new(Expr::Identifier(Ident::new("b"))),
|
||||
}),
|
||||
);
|
||||
test_constraint(
|
||||
"SELECT * FROM t1 CROSS JOIN t2 USING(a)",
|
||||
JoinConstraint::Using(vec![ObjectName::from(vec![Ident::new("a")])]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_joins_on() {
|
||||
fn join_with_constraint(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue