Allow to use the GLOBAL keyword before the join operator (#1353)

This commit is contained in:
hulk 2024-07-31 04:30:46 +08:00 committed by GitHub
parent bc15f7b4ce
commit f96658006f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 81 additions and 8 deletions

View file

@ -1537,6 +1537,9 @@ impl Display for TableVersion {
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Join {
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,
}
@ -1563,6 +1566,10 @@ impl fmt::Display for Join {
}
Suffix(constraint)
}
if self.global {
write!(f, " GLOBAL")?;
}
match &self.join_operator {
JoinOperator::Inner(constraint) => write!(
f,

View file

@ -850,6 +850,7 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
Keyword::USING,
Keyword::CLUSTER,
Keyword::DISTRIBUTE,
Keyword::GLOBAL,
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
Keyword::OUTER,
Keyword::SET,

View file

@ -9015,6 +9015,7 @@ impl<'a> Parser<'a> {
// a table alias.
let mut joins = vec![];
loop {
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
@ -9026,6 +9027,7 @@ impl<'a> Parser<'a> {
};
Join {
relation: self.parse_table_factor()?,
global,
join_operator,
}
} else if self.parse_keyword(Keyword::OUTER) {
@ -9033,6 +9035,7 @@ impl<'a> Parser<'a> {
self.expect_keyword(Keyword::APPLY)?;
Join {
relation: self.parse_table_factor()?,
global,
join_operator: JoinOperator::OuterApply,
}
} else if self.parse_keyword(Keyword::ASOF) {
@ -9042,6 +9045,7 @@ impl<'a> Parser<'a> {
let match_condition = self.parse_parenthesized(Self::parse_expr)?;
Join {
relation,
global,
join_operator: JoinOperator::AsOf {
match_condition,
constraint: self.parse_join_constraint(false)?,
@ -9127,6 +9131,7 @@ impl<'a> Parser<'a> {
let join_constraint = self.parse_join_constraint(natural)?;
Join {
relation,
global,
join_operator: join_operator_type(join_constraint),
}
};

View file

@ -331,6 +331,7 @@ pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> Ta
pub fn join(relation: TableFactor) -> Join {
Join {
relation,
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
}
}

View file

@ -1557,6 +1557,7 @@ fn parse_join_constraint_unnest_alias() {
with_offset_alias: None,
with_ordinality: false,
},
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
left: Box::new(Expr::Identifier("c1".into())),
op: BinaryOperator::Eq,

View file

@ -5600,6 +5600,7 @@ fn parse_implicit_join() {
partitions: vec![],
with_ordinality: false,
},
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
}],
},
@ -5623,6 +5624,7 @@ fn parse_implicit_join() {
partitions: vec![],
with_ordinality: false,
},
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
}],
},
@ -5646,6 +5648,7 @@ fn parse_cross_join() {
partitions: vec![],
with_ordinality: false,
},
global: false,
join_operator: JoinOperator::CrossJoin,
},
only(only(select.from).joins),
@ -5657,6 +5660,7 @@ fn parse_joins_on() {
fn join_with_constraint(
relation: impl Into<String>,
alias: Option<TableAlias>,
global: bool,
f: impl Fn(JoinConstraint) -> JoinOperator,
) -> Join {
Join {
@ -5669,6 +5673,7 @@ fn parse_joins_on() {
partitions: vec![],
with_ordinality: false,
},
global,
join_operator: f(JoinConstraint::On(Expr::BinaryOp {
left: Box::new(Expr::Identifier("c1".into())),
op: BinaryOperator::Eq,
@ -5682,6 +5687,7 @@ fn parse_joins_on() {
vec![join_with_constraint(
"t2",
table_alias("foo"),
false,
JoinOperator::Inner,
)]
);
@ -5692,35 +5698,80 @@ fn parse_joins_on() {
// Test parsing of different join operators
assert_eq!(
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!(
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!(
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!(
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!(
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!(
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!(
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!(
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![],
with_ordinality: false,
},
global: false,
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),
}
}
@ -5805,6 +5857,7 @@ fn parse_natural_join() {
partitions: vec![],
with_ordinality: false,
},
global: false,
join_operator: f(JoinConstraint::Natural),
}
}
@ -6073,6 +6126,7 @@ fn parse_derived_tables() {
partitions: vec![],
with_ordinality: false,
},
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
}],
}),
@ -6983,6 +7037,7 @@ fn lateral_function() {
],
alias: None,
},
global: false,
join_operator: JoinOperator::LeftOuter(JoinConstraint::None),
}],
}],

View file

@ -1891,6 +1891,7 @@ fn parse_update_with_joins() {
partitions: vec![],
with_ordinality: false,
},
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
left: Box::new(Expr::CompoundIdentifier(vec![
Ident::new("o"),

View file

@ -4102,6 +4102,7 @@ fn parse_join_constraint_unnest_alias() {
with_offset_alias: None,
with_ordinality: false,
},
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
left: Box::new(Expr::Identifier("c1".into())),
op: BinaryOperator::Eq,

View file

@ -2206,6 +2206,7 @@ fn asof_joins() {
relation: table_with_alias("trades_unixtime", "tu"),
joins: vec![Join {
relation: table_with_alias("quotes_unixtime", "qu"),
global: false,
join_operator: JoinOperator::AsOf {
match_condition: Expr::BinaryOp {
left: Box::new(Expr::CompoundIdentifier(vec![