Skip to content

Commit 6e79ce0

Browse files
git-hulkayman-sigma
authored andcommitted
Add support of parsing ON CLUSTER in ALTER TABLE for ClickHouse (apache#1342)
1 parent c3ed0d5 commit 6e79ce0

File tree

8 files changed

+67
-21
lines changed

8 files changed

+67
-21
lines changed

src/ast/dml.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ pub struct CreateTable {
126126
pub on_commit: Option<OnCommit>,
127127
/// ClickHouse "ON CLUSTER" clause:
128128
/// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
129-
pub on_cluster: Option<String>,
129+
pub on_cluster: Option<Ident>,
130130
/// ClickHouse "PRIMARY KEY " clause.
131131
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
132132
pub primary_key: Option<Box<Expr>>,
@@ -206,11 +206,7 @@ impl Display for CreateTable {
206206
name = self.name,
207207
)?;
208208
if let Some(on_cluster) = &self.on_cluster {
209-
write!(
210-
f,
211-
" ON CLUSTER {}",
212-
on_cluster.replace('{', "'{").replace('}', "}'")
213-
)?;
209+
write!(f, " ON CLUSTER {}", on_cluster)?;
214210
}
215211
if !self.columns.is_empty() || !self.constraints.is_empty() {
216212
write!(f, " ({}", display_comma_separated(&self.columns))?;

src/ast/helpers/stmt_create_table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub struct CreateTableBuilder {
7373
pub default_charset: Option<String>,
7474
pub collation: Option<String>,
7575
pub on_commit: Option<OnCommit>,
76-
pub on_cluster: Option<String>,
76+
pub on_cluster: Option<Ident>,
7777
pub primary_key: Option<Box<Expr>>,
7878
pub order_by: Option<OneOrManyWithParens<Expr>>,
7979
pub partition_by: Option<Box<Expr>>,
@@ -261,7 +261,7 @@ impl CreateTableBuilder {
261261
self
262262
}
263263

264-
pub fn on_cluster(mut self, on_cluster: Option<String>) -> Self {
264+
pub fn on_cluster(mut self, on_cluster: Option<Ident>) -> Self {
265265
self.on_cluster = on_cluster;
266266
self
267267
}

src/ast/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,10 @@ pub enum Statement {
21832183
only: bool,
21842184
operations: Vec<AlterTableOperation>,
21852185
location: Option<HiveSetLocation>,
2186+
/// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
2187+
/// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
2188+
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
2189+
on_cluster: Option<Ident>,
21862190
},
21872191
/// ```sql
21882192
/// ALTER INDEX
@@ -3653,6 +3657,7 @@ impl fmt::Display for Statement {
36533657
only,
36543658
operations,
36553659
location,
3660+
on_cluster,
36563661
} => {
36573662
write!(f, "ALTER TABLE ")?;
36583663
if *if_exists {
@@ -3661,9 +3666,13 @@ impl fmt::Display for Statement {
36613666
if *only {
36623667
write!(f, "ONLY ")?;
36633668
}
3669+
write!(f, "{name} ", name = name)?;
3670+
if let Some(cluster) = on_cluster {
3671+
write!(f, "ON CLUSTER {cluster} ")?;
3672+
}
36643673
write!(
36653674
f,
3666-
"{name} {operations}",
3675+
"{operations}",
36673676
operations = display_comma_separated(operations)
36683677
)?;
36693678
if let Some(loc) = location {

src/parser/mod.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5393,6 +5393,14 @@ impl<'a> Parser<'a> {
53935393
}
53945394
}
53955395

5396+
fn parse_optional_on_cluster(&mut self) -> Result<Option<Ident>, ParserError> {
5397+
if self.parse_keywords(&[Keyword::ON, Keyword::CLUSTER]) {
5398+
Ok(Some(self.parse_identifier(false)?))
5399+
} else {
5400+
Ok(None)
5401+
}
5402+
}
5403+
53965404
pub fn parse_create_table(
53975405
&mut self,
53985406
or_replace: bool,
@@ -5405,16 +5413,7 @@ impl<'a> Parser<'a> {
54055413
let table_name = self.parse_object_name(allow_unquoted_hyphen)?;
54065414

54075415
// Clickhouse has `ON CLUSTER 'cluster'` syntax for DDLs
5408-
let on_cluster = if self.parse_keywords(&[Keyword::ON, Keyword::CLUSTER]) {
5409-
let next_token = self.next_token();
5410-
match next_token.token {
5411-
Token::SingleQuotedString(s) => Some(s),
5412-
Token::Word(s) => Some(s.to_string()),
5413-
_ => self.expected("identifier or cluster literal", next_token)?,
5414-
}
5415-
} else {
5416-
None
5417-
};
5416+
let on_cluster = self.parse_optional_on_cluster()?;
54185417

54195418
let like = if self.parse_keyword(Keyword::LIKE) || self.parse_keyword(Keyword::ILIKE) {
54205419
self.parse_object_name(allow_unquoted_hyphen).ok()
@@ -6597,6 +6596,7 @@ impl<'a> Parser<'a> {
65976596
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
65986597
let only = self.parse_keyword(Keyword::ONLY); // [ ONLY ]
65996598
let table_name = self.parse_object_name(false)?;
6599+
let on_cluster = self.parse_optional_on_cluster()?;
66006600
let operations = self.parse_comma_separated(Parser::parse_alter_table_operation)?;
66016601

66026602
let mut location = None;
@@ -6618,6 +6618,7 @@ impl<'a> Parser<'a> {
66186618
only,
66196619
operations,
66206620
location,
6621+
on_cluster,
66216622
})
66226623
}
66236624
Keyword::INDEX => {

src/test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTa
274274
if_exists,
275275
only: is_only,
276276
operations,
277+
on_cluster: _,
277278
location: _,
278279
} => {
279280
assert_eq!(name.to_string(), expected_name);

tests/sqlparser_common.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3507,7 +3507,7 @@ fn parse_create_table_on_cluster() {
35073507
let sql = "CREATE TABLE t ON CLUSTER '{cluster}' (a INT, b INT)";
35083508
match generic.verified_stmt(sql) {
35093509
Statement::CreateTable(CreateTable { on_cluster, .. }) => {
3510-
assert_eq!(on_cluster.unwrap(), "{cluster}".to_string());
3510+
assert_eq!(on_cluster.unwrap().to_string(), "'{cluster}'".to_string());
35113511
}
35123512
_ => unreachable!(),
35133513
}
@@ -3516,7 +3516,7 @@ fn parse_create_table_on_cluster() {
35163516
let sql = "CREATE TABLE t ON CLUSTER my_cluster (a INT, b INT)";
35173517
match generic.verified_stmt(sql) {
35183518
Statement::CreateTable(CreateTable { on_cluster, .. }) => {
3519-
assert_eq!(on_cluster.unwrap(), "my_cluster".to_string());
3519+
assert_eq!(on_cluster.unwrap().to_string(), "my_cluster".to_string());
35203520
}
35213521
_ => unreachable!(),
35223522
}
@@ -3823,6 +3823,40 @@ fn parse_alter_table() {
38233823
}
38243824
}
38253825

3826+
#[test]
3827+
fn test_alter_table_with_on_cluster() {
3828+
match all_dialects()
3829+
.verified_stmt("ALTER TABLE t ON CLUSTER 'cluster' ADD CONSTRAINT bar PRIMARY KEY (baz)")
3830+
{
3831+
Statement::AlterTable {
3832+
name, on_cluster, ..
3833+
} => {
3834+
std::assert_eq!(name.to_string(), "t");
3835+
std::assert_eq!(on_cluster, Some(Ident::with_quote('\'', "cluster")));
3836+
}
3837+
_ => unreachable!(),
3838+
}
3839+
3840+
match all_dialects()
3841+
.verified_stmt("ALTER TABLE t ON CLUSTER cluster_name ADD CONSTRAINT bar PRIMARY KEY (baz)")
3842+
{
3843+
Statement::AlterTable {
3844+
name, on_cluster, ..
3845+
} => {
3846+
std::assert_eq!(name.to_string(), "t");
3847+
std::assert_eq!(on_cluster, Some(Ident::new("cluster_name")));
3848+
}
3849+
_ => unreachable!(),
3850+
}
3851+
3852+
let res = all_dialects()
3853+
.parse_sql_statements("ALTER TABLE t ON CLUSTER 123 ADD CONSTRAINT bar PRIMARY KEY (baz)");
3854+
std::assert_eq!(
3855+
res.unwrap_err(),
3856+
ParserError::ParserError("Expected: identifier, found: 123".to_string())
3857+
)
3858+
}
3859+
38263860
#[test]
38273861
fn parse_alter_index() {
38283862
let rename_index = "ALTER INDEX idx RENAME TO new_idx";

tests/sqlparser_mysql.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,6 +1976,7 @@ fn parse_alter_table_add_column() {
19761976
only,
19771977
operations,
19781978
location: _,
1979+
on_cluster: _,
19791980
} => {
19801981
assert_eq!(name.to_string(), "tab");
19811982
assert!(!if_exists);
@@ -2005,6 +2006,7 @@ fn parse_alter_table_add_column() {
20052006
only,
20062007
operations,
20072008
location: _,
2009+
on_cluster: _,
20082010
} => {
20092011
assert_eq!(name.to_string(), "tab");
20102012
assert!(!if_exists);
@@ -2042,6 +2044,7 @@ fn parse_alter_table_add_columns() {
20422044
only,
20432045
operations,
20442046
location: _,
2047+
on_cluster: _,
20452048
} => {
20462049
assert_eq!(name.to_string(), "tab");
20472050
assert!(!if_exists);

tests/sqlparser_postgres.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ fn parse_alter_table_add_columns() {
677677
only,
678678
operations,
679679
location: _,
680+
on_cluster: _,
680681
} => {
681682
assert_eq!(name.to_string(), "tab");
682683
assert!(if_exists);
@@ -759,6 +760,7 @@ fn parse_alter_table_owner_to() {
759760
only: _,
760761
operations,
761762
location: _,
763+
on_cluster: _,
762764
} => {
763765
assert_eq!(name.to_string(), "tab");
764766
assert_eq!(

0 commit comments

Comments
 (0)