mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-22 05:32:29 +00:00
Allow to use the GLOBAL keyword before the join operator (#1353)
This commit is contained in:
parent
bc15f7b4ce
commit
f96658006f
9 changed files with 81 additions and 8 deletions
|
@ -1537,6 +1537,9 @@ impl Display for TableVersion {
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
pub struct Join {
|
pub struct Join {
|
||||||
pub relation: TableFactor,
|
pub relation: TableFactor,
|
||||||
|
/// ClickHouse supports the optional `GLOBAL` keyword before the join operator.
|
||||||
|
/// See [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/join)
|
||||||
|
pub global: bool,
|
||||||
pub join_operator: JoinOperator,
|
pub join_operator: JoinOperator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1563,6 +1566,10 @@ impl fmt::Display for Join {
|
||||||
}
|
}
|
||||||
Suffix(constraint)
|
Suffix(constraint)
|
||||||
}
|
}
|
||||||
|
if self.global {
|
||||||
|
write!(f, " GLOBAL")?;
|
||||||
|
}
|
||||||
|
|
||||||
match &self.join_operator {
|
match &self.join_operator {
|
||||||
JoinOperator::Inner(constraint) => write!(
|
JoinOperator::Inner(constraint) => write!(
|
||||||
f,
|
f,
|
||||||
|
|
|
@ -850,6 +850,7 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
|
||||||
Keyword::USING,
|
Keyword::USING,
|
||||||
Keyword::CLUSTER,
|
Keyword::CLUSTER,
|
||||||
Keyword::DISTRIBUTE,
|
Keyword::DISTRIBUTE,
|
||||||
|
Keyword::GLOBAL,
|
||||||
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
|
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
|
||||||
Keyword::OUTER,
|
Keyword::OUTER,
|
||||||
Keyword::SET,
|
Keyword::SET,
|
||||||
|
|
|
@ -9015,6 +9015,7 @@ impl<'a> Parser<'a> {
|
||||||
// a table alias.
|
// a table alias.
|
||||||
let mut joins = vec![];
|
let mut joins = vec![];
|
||||||
loop {
|
loop {
|
||||||
|
let global = self.parse_keyword(Keyword::GLOBAL);
|
||||||
let join = if self.parse_keyword(Keyword::CROSS) {
|
let join = if self.parse_keyword(Keyword::CROSS) {
|
||||||
let join_operator = if self.parse_keyword(Keyword::JOIN) {
|
let join_operator = if self.parse_keyword(Keyword::JOIN) {
|
||||||
JoinOperator::CrossJoin
|
JoinOperator::CrossJoin
|
||||||
|
@ -9026,6 +9027,7 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
Join {
|
Join {
|
||||||
relation: self.parse_table_factor()?,
|
relation: self.parse_table_factor()?,
|
||||||
|
global,
|
||||||
join_operator,
|
join_operator,
|
||||||
}
|
}
|
||||||
} else if self.parse_keyword(Keyword::OUTER) {
|
} else if self.parse_keyword(Keyword::OUTER) {
|
||||||
|
@ -9033,6 +9035,7 @@ impl<'a> Parser<'a> {
|
||||||
self.expect_keyword(Keyword::APPLY)?;
|
self.expect_keyword(Keyword::APPLY)?;
|
||||||
Join {
|
Join {
|
||||||
relation: self.parse_table_factor()?,
|
relation: self.parse_table_factor()?,
|
||||||
|
global,
|
||||||
join_operator: JoinOperator::OuterApply,
|
join_operator: JoinOperator::OuterApply,
|
||||||
}
|
}
|
||||||
} else if self.parse_keyword(Keyword::ASOF) {
|
} else if self.parse_keyword(Keyword::ASOF) {
|
||||||
|
@ -9042,6 +9045,7 @@ impl<'a> Parser<'a> {
|
||||||
let match_condition = self.parse_parenthesized(Self::parse_expr)?;
|
let match_condition = self.parse_parenthesized(Self::parse_expr)?;
|
||||||
Join {
|
Join {
|
||||||
relation,
|
relation,
|
||||||
|
global,
|
||||||
join_operator: JoinOperator::AsOf {
|
join_operator: JoinOperator::AsOf {
|
||||||
match_condition,
|
match_condition,
|
||||||
constraint: self.parse_join_constraint(false)?,
|
constraint: self.parse_join_constraint(false)?,
|
||||||
|
@ -9127,6 +9131,7 @@ impl<'a> Parser<'a> {
|
||||||
let join_constraint = self.parse_join_constraint(natural)?;
|
let join_constraint = self.parse_join_constraint(natural)?;
|
||||||
Join {
|
Join {
|
||||||
relation,
|
relation,
|
||||||
|
global,
|
||||||
join_operator: join_operator_type(join_constraint),
|
join_operator: join_operator_type(join_constraint),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -331,6 +331,7 @@ pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> Ta
|
||||||
pub fn join(relation: TableFactor) -> Join {
|
pub fn join(relation: TableFactor) -> Join {
|
||||||
Join {
|
Join {
|
||||||
relation,
|
relation,
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1557,6 +1557,7 @@ fn parse_join_constraint_unnest_alias() {
|
||||||
with_offset_alias: None,
|
with_offset_alias: None,
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
|
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
|
||||||
left: Box::new(Expr::Identifier("c1".into())),
|
left: Box::new(Expr::Identifier("c1".into())),
|
||||||
op: BinaryOperator::Eq,
|
op: BinaryOperator::Eq,
|
||||||
|
|
|
@ -5600,6 +5600,7 @@ fn parse_implicit_join() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
|
@ -5623,6 +5624,7 @@ fn parse_implicit_join() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
|
@ -5646,6 +5648,7 @@ fn parse_cross_join() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::CrossJoin,
|
join_operator: JoinOperator::CrossJoin,
|
||||||
},
|
},
|
||||||
only(only(select.from).joins),
|
only(only(select.from).joins),
|
||||||
|
@ -5657,6 +5660,7 @@ fn parse_joins_on() {
|
||||||
fn join_with_constraint(
|
fn join_with_constraint(
|
||||||
relation: impl Into<String>,
|
relation: impl Into<String>,
|
||||||
alias: Option<TableAlias>,
|
alias: Option<TableAlias>,
|
||||||
|
global: bool,
|
||||||
f: impl Fn(JoinConstraint) -> JoinOperator,
|
f: impl Fn(JoinConstraint) -> JoinOperator,
|
||||||
) -> Join {
|
) -> Join {
|
||||||
Join {
|
Join {
|
||||||
|
@ -5669,6 +5673,7 @@ fn parse_joins_on() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global,
|
||||||
join_operator: f(JoinConstraint::On(Expr::BinaryOp {
|
join_operator: f(JoinConstraint::On(Expr::BinaryOp {
|
||||||
left: Box::new(Expr::Identifier("c1".into())),
|
left: Box::new(Expr::Identifier("c1".into())),
|
||||||
op: BinaryOperator::Eq,
|
op: BinaryOperator::Eq,
|
||||||
|
@ -5682,6 +5687,7 @@ fn parse_joins_on() {
|
||||||
vec![join_with_constraint(
|
vec![join_with_constraint(
|
||||||
"t2",
|
"t2",
|
||||||
table_alias("foo"),
|
table_alias("foo"),
|
||||||
|
false,
|
||||||
JoinOperator::Inner,
|
JoinOperator::Inner,
|
||||||
)]
|
)]
|
||||||
);
|
);
|
||||||
|
@ -5692,35 +5698,80 @@ fn parse_joins_on() {
|
||||||
// Test parsing of different join operators
|
// Test parsing of different join operators
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::Inner)]
|
vec![join_with_constraint("t2", None, false, JoinOperator::Inner)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::LeftOuter)]
|
vec![join_with_constraint(
|
||||||
|
"t2",
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
JoinOperator::LeftOuter
|
||||||
|
)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
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,
|
||||||
|
false,
|
||||||
|
JoinOperator::RightOuter
|
||||||
|
)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 LEFT SEMI JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 LEFT SEMI JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::LeftSemi)]
|
vec![join_with_constraint(
|
||||||
|
"t2",
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
JoinOperator::LeftSemi
|
||||||
|
)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 RIGHT SEMI JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 RIGHT SEMI JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::RightSemi)]
|
vec![join_with_constraint(
|
||||||
|
"t2",
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
JoinOperator::RightSemi
|
||||||
|
)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 LEFT ANTI JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 LEFT ANTI JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::LeftAnti)]
|
vec![join_with_constraint(
|
||||||
|
"t2",
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
JoinOperator::LeftAnti
|
||||||
|
)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 RIGHT ANTI JOIN t2 ON c1 = c2").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 RIGHT ANTI JOIN t2 ON c1 = c2").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::RightAnti)]
|
vec![join_with_constraint(
|
||||||
|
"t2",
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
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,
|
||||||
|
false,
|
||||||
|
JoinOperator::FullOuter
|
||||||
|
)]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
only(&verified_only_select("SELECT * FROM t1 GLOBAL FULL JOIN t2 ON c1 = c2").from).joins,
|
||||||
|
vec![join_with_constraint(
|
||||||
|
"t2",
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
JoinOperator::FullOuter
|
||||||
|
)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5741,6 +5792,7 @@ fn parse_joins_using() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),
|
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5805,6 +5857,7 @@ fn parse_natural_join() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: f(JoinConstraint::Natural),
|
join_operator: f(JoinConstraint::Natural),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6073,6 +6126,7 @@ fn parse_derived_tables() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
|
@ -6983,6 +7037,7 @@ fn lateral_function() {
|
||||||
],
|
],
|
||||||
alias: None,
|
alias: None,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::LeftOuter(JoinConstraint::None),
|
join_operator: JoinOperator::LeftOuter(JoinConstraint::None),
|
||||||
}],
|
}],
|
||||||
}],
|
}],
|
||||||
|
|
|
@ -1891,6 +1891,7 @@ fn parse_update_with_joins() {
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
|
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
|
||||||
left: Box::new(Expr::CompoundIdentifier(vec![
|
left: Box::new(Expr::CompoundIdentifier(vec![
|
||||||
Ident::new("o"),
|
Ident::new("o"),
|
||||||
|
|
|
@ -4102,6 +4102,7 @@ fn parse_join_constraint_unnest_alias() {
|
||||||
with_offset_alias: None,
|
with_offset_alias: None,
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
},
|
},
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
|
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
|
||||||
left: Box::new(Expr::Identifier("c1".into())),
|
left: Box::new(Expr::Identifier("c1".into())),
|
||||||
op: BinaryOperator::Eq,
|
op: BinaryOperator::Eq,
|
||||||
|
|
|
@ -2206,6 +2206,7 @@ fn asof_joins() {
|
||||||
relation: table_with_alias("trades_unixtime", "tu"),
|
relation: table_with_alias("trades_unixtime", "tu"),
|
||||||
joins: vec![Join {
|
joins: vec![Join {
|
||||||
relation: table_with_alias("quotes_unixtime", "qu"),
|
relation: table_with_alias("quotes_unixtime", "qu"),
|
||||||
|
global: false,
|
||||||
join_operator: JoinOperator::AsOf {
|
join_operator: JoinOperator::AsOf {
|
||||||
match_condition: Expr::BinaryOp {
|
match_condition: Expr::BinaryOp {
|
||||||
left: Box::new(Expr::CompoundIdentifier(vec![
|
left: Box::new(Expr::CompoundIdentifier(vec![
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue