Skip to content

Commit d27aeca

Browse files
Cristhian Lopez VidalCopilot
andcommitted
feat(clickhouse): add ARRAY JOIN, LEFT/INNER ARRAY JOIN support
ClickHouse supports ARRAY JOIN clauses for unnesting arrays inline. This adds JoinOperator variants for ARRAY JOIN, LEFT ARRAY JOIN, and INNER ARRAY JOIN. These joins take a table expression (the array to unnest) rather than a standard table reference, and do not use ON/USING constraints. Also adds Spanned impls for the new variants in spans.rs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1970fc9 commit d27aeca

File tree

4 files changed

+63
-0
lines changed

4 files changed

+63
-0
lines changed

src/ast/query.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,6 +2755,13 @@ impl fmt::Display for Join {
27552755
self.relation,
27562756
suffix(constraint)
27572757
)),
2758+
JoinOperator::ArrayJoin => f.write_fmt(format_args!("ARRAY JOIN {}", self.relation)),
2759+
JoinOperator::LeftArrayJoin => {
2760+
f.write_fmt(format_args!("LEFT ARRAY JOIN {}", self.relation))
2761+
}
2762+
JoinOperator::InnerArrayJoin => {
2763+
f.write_fmt(format_args!("INNER ARRAY JOIN {}", self.relation))
2764+
}
27582765
}
27592766
}
27602767
}
@@ -2809,6 +2816,14 @@ pub enum JoinOperator {
28092816
///
28102817
/// See <https://dev.mysql.com/doc/refman/8.4/en/join.html>.
28112818
StraightJoin(JoinConstraint),
2819+
/// ClickHouse: `ARRAY JOIN` for unnesting arrays inline.
2820+
///
2821+
/// See <https://clickhouse.com/docs/en/sql-reference/statements/select/array-join>.
2822+
ArrayJoin,
2823+
/// ClickHouse: `LEFT ARRAY JOIN` for unnesting arrays inline (preserves rows with empty arrays).
2824+
LeftArrayJoin,
2825+
/// ClickHouse: `INNER ARRAY JOIN` for unnesting arrays inline (filters rows with empty arrays).
2826+
InnerArrayJoin,
28122827
}
28132828

28142829
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]

src/ast/spans.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,6 +2234,9 @@ impl Spanned for JoinOperator {
22342234
JoinOperator::Anti(join_constraint) => join_constraint.span(),
22352235
JoinOperator::Semi(join_constraint) => join_constraint.span(),
22362236
JoinOperator::StraightJoin(join_constraint) => join_constraint.span(),
2237+
JoinOperator::ArrayJoin => Span::empty(),
2238+
JoinOperator::LeftArrayJoin => Span::empty(),
2239+
JoinOperator::InnerArrayJoin => Span::empty(),
22372240
}
22382241
}
22392242
}

src/parser/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15342,6 +15342,33 @@ impl<'a> Parser<'a> {
1534215342
constraint: self.parse_join_constraint(false)?,
1534315343
},
1534415344
}
15345+
} else if dialect_of!(self is ClickHouseDialect | GenericDialect)
15346+
&& self.parse_keywords(&[Keyword::INNER, Keyword::ARRAY, Keyword::JOIN])
15347+
{
15348+
// ClickHouse: INNER ARRAY JOIN
15349+
Join {
15350+
relation: self.parse_table_factor()?,
15351+
global,
15352+
join_operator: JoinOperator::InnerArrayJoin,
15353+
}
15354+
} else if dialect_of!(self is ClickHouseDialect | GenericDialect)
15355+
&& self.parse_keywords(&[Keyword::LEFT, Keyword::ARRAY, Keyword::JOIN])
15356+
{
15357+
// ClickHouse: LEFT ARRAY JOIN
15358+
Join {
15359+
relation: self.parse_table_factor()?,
15360+
global,
15361+
join_operator: JoinOperator::LeftArrayJoin,
15362+
}
15363+
} else if dialect_of!(self is ClickHouseDialect | GenericDialect)
15364+
&& self.parse_keywords(&[Keyword::ARRAY, Keyword::JOIN])
15365+
{
15366+
// ClickHouse: ARRAY JOIN
15367+
Join {
15368+
relation: self.parse_table_factor()?,
15369+
global,
15370+
join_operator: JoinOperator::ArrayJoin,
15371+
}
1534515372
} else {
1534615373
let natural = self.parse_keyword(Keyword::NATURAL);
1534715374
let peek_keyword = if let Token::Word(w) = &self.peek_token_ref().token {

tests/sqlparser_clickhouse.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,24 @@ fn test_parse_not_null_in_column_options() {
17511751
);
17521752
}
17531753

1754+
#[test]
1755+
fn parse_array_join() {
1756+
// ClickHouse: plain ARRAY JOIN for unnesting arrays
1757+
clickhouse().verified_stmt("SELECT x FROM t ARRAY JOIN arr AS x");
1758+
}
1759+
1760+
#[test]
1761+
fn parse_left_array_join() {
1762+
// ClickHouse: LEFT ARRAY JOIN preserves rows with empty/null arrays
1763+
clickhouse().verified_stmt("SELECT x FROM t LEFT ARRAY JOIN arr AS x");
1764+
}
1765+
1766+
#[test]
1767+
fn parse_inner_array_join() {
1768+
// ClickHouse: INNER ARRAY JOIN filters rows with empty/null arrays
1769+
clickhouse().verified_stmt("SELECT x FROM t INNER ARRAY JOIN arr AS x");
1770+
}
1771+
17541772
fn clickhouse() -> TestedDialects {
17551773
TestedDialects::new(vec![Box::new(ClickHouseDialect {})])
17561774
}

0 commit comments

Comments
 (0)