Skip to content

Commit e0032ed

Browse files
committed
Allow to use the GLOBAL keyword before the join operator
ClickHouse supports the GLOBAL keyworld while joining the right table, for the syntax, please refer to: ```SQL SELECT <expr_list> FROM <left_table> [GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ALL|ASOF] JOIN <right_table> (ON <expr_list>)|(USING <column_list>) ``` Reference: https://clickhouse.com/docs/en/sql-reference/statements/select/join
1 parent 6c64d43 commit e0032ed

File tree

9 files changed

+81
-8
lines changed

9 files changed

+81
-8
lines changed

src/ast/query.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,9 @@ impl Display for TableVersion {
15371537
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
15381538
pub struct Join {
15391539
pub relation: TableFactor,
1540+
/// ClickHouse supports the optional `GLOBAL` keyword before the join operator.
1541+
/// See [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/join)
1542+
pub global: bool,
15401543
pub join_operator: JoinOperator,
15411544
}
15421545

@@ -1563,6 +1566,10 @@ impl fmt::Display for Join {
15631566
}
15641567
Suffix(constraint)
15651568
}
1569+
if self.global {
1570+
write!(f, " GLOBAL")?;
1571+
}
1572+
15661573
match &self.join_operator {
15671574
JoinOperator::Inner(constraint) => write!(
15681575
f,

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,7 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
850850
Keyword::USING,
851851
Keyword::CLUSTER,
852852
Keyword::DISTRIBUTE,
853+
Keyword::GLOBAL,
853854
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
854855
Keyword::OUTER,
855856
Keyword::SET,

src/parser/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9003,6 +9003,7 @@ impl<'a> Parser<'a> {
90039003
// a table alias.
90049004
let mut joins = vec![];
90059005
loop {
9006+
let global = self.parse_keyword(Keyword::GLOBAL);
90069007
let join = if self.parse_keyword(Keyword::CROSS) {
90079008
let join_operator = if self.parse_keyword(Keyword::JOIN) {
90089009
JoinOperator::CrossJoin
@@ -9014,13 +9015,15 @@ impl<'a> Parser<'a> {
90149015
};
90159016
Join {
90169017
relation: self.parse_table_factor()?,
9018+
global,
90179019
join_operator,
90189020
}
90199021
} else if self.parse_keyword(Keyword::OUTER) {
90209022
// MSSQL extension, similar to LEFT JOIN LATERAL .. ON 1=1
90219023
self.expect_keyword(Keyword::APPLY)?;
90229024
Join {
90239025
relation: self.parse_table_factor()?,
9026+
global,
90249027
join_operator: JoinOperator::OuterApply,
90259028
}
90269029
} else if self.parse_keyword(Keyword::ASOF) {
@@ -9030,6 +9033,7 @@ impl<'a> Parser<'a> {
90309033
let match_condition = self.parse_parenthesized(Self::parse_expr)?;
90319034
Join {
90329035
relation,
9036+
global,
90339037
join_operator: JoinOperator::AsOf {
90349038
match_condition,
90359039
constraint: self.parse_join_constraint(false)?,
@@ -9115,6 +9119,7 @@ impl<'a> Parser<'a> {
91159119
let join_constraint = self.parse_join_constraint(natural)?;
91169120
Join {
91179121
relation,
9122+
global,
91189123
join_operator: join_operator_type(join_constraint),
91199124
}
91209125
};

src/test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> Ta
331331
pub fn join(relation: TableFactor) -> Join {
332332
Join {
333333
relation,
334+
global: false,
334335
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
335336
}
336337
}

tests/sqlparser_bigquery.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,7 @@ fn parse_join_constraint_unnest_alias() {
15571557
with_offset_alias: None,
15581558
with_ordinality: false,
15591559
},
1560+
global: false,
15601561
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
15611562
left: Box::new(Expr::Identifier("c1".into())),
15621563
op: BinaryOperator::Eq,

tests/sqlparser_common.rs

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5582,6 +5582,7 @@ fn parse_implicit_join() {
55825582
partitions: vec![],
55835583
with_ordinality: false,
55845584
},
5585+
global: false,
55855586
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
55865587
}],
55875588
},
@@ -5605,6 +5606,7 @@ fn parse_implicit_join() {
56055606
partitions: vec![],
56065607
with_ordinality: false,
56075608
},
5609+
global: false,
56085610
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
56095611
}],
56105612
},
@@ -5628,6 +5630,7 @@ fn parse_cross_join() {
56285630
partitions: vec![],
56295631
with_ordinality: false,
56305632
},
5633+
global: false,
56315634
join_operator: JoinOperator::CrossJoin,
56325635
},
56335636
only(only(select.from).joins),
@@ -5639,6 +5642,7 @@ fn parse_joins_on() {
56395642
fn join_with_constraint(
56405643
relation: impl Into<String>,
56415644
alias: Option<TableAlias>,
5645+
global: bool,
56425646
f: impl Fn(JoinConstraint) -> JoinOperator,
56435647
) -> Join {
56445648
Join {
@@ -5651,6 +5655,7 @@ fn parse_joins_on() {
56515655
partitions: vec![],
56525656
with_ordinality: false,
56535657
},
5658+
global,
56545659
join_operator: f(JoinConstraint::On(Expr::BinaryOp {
56555660
left: Box::new(Expr::Identifier("c1".into())),
56565661
op: BinaryOperator::Eq,
@@ -5664,6 +5669,7 @@ fn parse_joins_on() {
56645669
vec![join_with_constraint(
56655670
"t2",
56665671
table_alias("foo"),
5672+
false,
56675673
JoinOperator::Inner,
56685674
)]
56695675
);
@@ -5674,35 +5680,80 @@ fn parse_joins_on() {
56745680
// Test parsing of different join operators
56755681
assert_eq!(
56765682
only(&verified_only_select("SELECT * FROM t1 JOIN t2 ON c1 = c2").from).joins,
5677-
vec![join_with_constraint("t2", None, JoinOperator::Inner)]
5683+
vec![join_with_constraint("t2", None, false, JoinOperator::Inner)]
56785684
);
56795685
assert_eq!(
56805686
only(&verified_only_select("SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2").from).joins,
5681-
vec![join_with_constraint("t2", None, JoinOperator::LeftOuter)]
5687+
vec![join_with_constraint(
5688+
"t2",
5689+
None,
5690+
false,
5691+
JoinOperator::LeftOuter
5692+
)]
56825693
);
56835694
assert_eq!(
56845695
only(&verified_only_select("SELECT * FROM t1 RIGHT JOIN t2 ON c1 = c2").from).joins,
5685-
vec![join_with_constraint("t2", None, JoinOperator::RightOuter)]
5696+
vec![join_with_constraint(
5697+
"t2",
5698+
None,
5699+
false,
5700+
JoinOperator::RightOuter
5701+
)]
56865702
);
56875703
assert_eq!(
56885704
only(&verified_only_select("SELECT * FROM t1 LEFT SEMI JOIN t2 ON c1 = c2").from).joins,
5689-
vec![join_with_constraint("t2", None, JoinOperator::LeftSemi)]
5705+
vec![join_with_constraint(
5706+
"t2",
5707+
None,
5708+
false,
5709+
JoinOperator::LeftSemi
5710+
)]
56905711
);
56915712
assert_eq!(
56925713
only(&verified_only_select("SELECT * FROM t1 RIGHT SEMI JOIN t2 ON c1 = c2").from).joins,
5693-
vec![join_with_constraint("t2", None, JoinOperator::RightSemi)]
5714+
vec![join_with_constraint(
5715+
"t2",
5716+
None,
5717+
false,
5718+
JoinOperator::RightSemi
5719+
)]
56945720
);
56955721
assert_eq!(
56965722
only(&verified_only_select("SELECT * FROM t1 LEFT ANTI JOIN t2 ON c1 = c2").from).joins,
5697-
vec![join_with_constraint("t2", None, JoinOperator::LeftAnti)]
5723+
vec![join_with_constraint(
5724+
"t2",
5725+
None,
5726+
false,
5727+
JoinOperator::LeftAnti
5728+
)]
56985729
);
56995730
assert_eq!(
57005731
only(&verified_only_select("SELECT * FROM t1 RIGHT ANTI JOIN t2 ON c1 = c2").from).joins,
5701-
vec![join_with_constraint("t2", None, JoinOperator::RightAnti)]
5732+
vec![join_with_constraint(
5733+
"t2",
5734+
None,
5735+
false,
5736+
JoinOperator::RightAnti
5737+
)]
57025738
);
57035739
assert_eq!(
57045740
only(&verified_only_select("SELECT * FROM t1 FULL JOIN t2 ON c1 = c2").from).joins,
5705-
vec![join_with_constraint("t2", None, JoinOperator::FullOuter)]
5741+
vec![join_with_constraint(
5742+
"t2",
5743+
None,
5744+
false,
5745+
JoinOperator::FullOuter
5746+
)]
5747+
);
5748+
5749+
assert_eq!(
5750+
only(&verified_only_select("SELECT * FROM t1 GLOBAL FULL JOIN t2 ON c1 = c2").from).joins,
5751+
vec![join_with_constraint(
5752+
"t2",
5753+
None,
5754+
true,
5755+
JoinOperator::FullOuter
5756+
)]
57065757
);
57075758
}
57085759

@@ -5723,6 +5774,7 @@ fn parse_joins_using() {
57235774
partitions: vec![],
57245775
with_ordinality: false,
57255776
},
5777+
global: false,
57265778
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),
57275779
}
57285780
}
@@ -5787,6 +5839,7 @@ fn parse_natural_join() {
57875839
partitions: vec![],
57885840
with_ordinality: false,
57895841
},
5842+
global: false,
57905843
join_operator: f(JoinConstraint::Natural),
57915844
}
57925845
}
@@ -6055,6 +6108,7 @@ fn parse_derived_tables() {
60556108
partitions: vec![],
60566109
with_ordinality: false,
60576110
},
6111+
global: false,
60586112
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
60596113
}],
60606114
}),
@@ -6965,6 +7019,7 @@ fn lateral_function() {
69657019
],
69667020
alias: None,
69677021
},
7022+
global: false,
69687023
join_operator: JoinOperator::LeftOuter(JoinConstraint::None),
69697024
}],
69707025
}],

tests/sqlparser_mysql.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,7 @@ fn parse_update_with_joins() {
18911891
partitions: vec![],
18921892
with_ordinality: false,
18931893
},
1894+
global: false,
18941895
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
18951896
left: Box::new(Expr::CompoundIdentifier(vec![
18961897
Ident::new("o"),

tests/sqlparser_postgres.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4102,6 +4102,7 @@ fn parse_join_constraint_unnest_alias() {
41024102
with_offset_alias: None,
41034103
with_ordinality: false,
41044104
},
4105+
global: false,
41054106
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
41064107
left: Box::new(Expr::Identifier("c1".into())),
41074108
op: BinaryOperator::Eq,

tests/sqlparser_snowflake.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,6 +2206,7 @@ fn asof_joins() {
22062206
relation: table_with_alias("trades_unixtime", "tu"),
22072207
joins: vec![Join {
22082208
relation: table_with_alias("quotes_unixtime", "qu"),
2209+
global: false,
22092210
join_operator: JoinOperator::AsOf {
22102211
match_condition: Expr::BinaryOp {
22112212
left: Box::new(Expr::CompoundIdentifier(vec![

0 commit comments

Comments
 (0)