diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 6c851906c..4e3cbcdba 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2172,6 +2172,11 @@ pub enum Statement { /// Postgres-specific option /// [ CASCADE | RESTRICT ] cascade: Option, + /// ClickHouse-specific option + /// [ ON CLUSTER cluster_name ] + /// + /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/) + on_cluster: Option, }, /// ```sql /// MSCK @@ -3293,6 +3298,7 @@ impl fmt::Display for Statement { only, identity, cascade, + on_cluster, } => { let table = if *table { "TABLE " } else { "" }; let only = if *only { "ONLY " } else { "" }; @@ -3321,6 +3327,9 @@ impl fmt::Display for Statement { write!(f, " PARTITION ({})", display_comma_separated(parts))?; } } + if let Some(on_cluster) = on_cluster { + write!(f, " ON CLUSTER {on_cluster}")?; + } Ok(()) } Statement::AttachDatabase { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 8d920b2ce..d7dbf23d7 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -708,6 +708,8 @@ impl<'a> Parser<'a> { }; }; + let on_cluster = self.parse_optional_on_cluster()?; + Ok(Statement::Truncate { table_names, partitions, @@ -715,6 +717,7 @@ impl<'a> Parser<'a> { only, identity, cascade, + on_cluster, }) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index ff45d7b6e..4cc3776e1 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -10792,3 +10792,24 @@ fn test_extract_seconds_single_quote_err() { "sql parser error: Expected: date/time field, found: 'seconds'" ); } + +#[test] +fn test_truncate_table_with_on_cluster() { + let sql = "TRUNCATE TABLE t ON CLUSTER cluster_name"; + match all_dialects().verified_stmt(sql) { + Statement::Truncate { on_cluster, .. } => { + assert_eq!(on_cluster, Some(Ident::new("cluster_name"))); + } + _ => panic!("Expected: TRUNCATE TABLE statement"), + } + + // Omit ON CLUSTER is allowed + all_dialects().verified_stmt("TRUNCATE TABLE t"); + + assert_eq!( + ParserError::ParserError("Expected: identifier, found: EOF".to_string()), + all_dialects() + .parse_sql_statements("TRUNCATE TABLE t ON CLUSTER") + .unwrap_err() + ); +} diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index ec1311f2c..1ccc4d0af 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -3990,6 +3990,7 @@ fn parse_truncate() { only: false, identity: None, cascade: None, + on_cluster: None, }, truncate ); @@ -4012,7 +4013,8 @@ fn parse_truncate_with_options() { table: true, only: true, identity: Some(TruncateIdentityOption::Restart), - cascade: Some(TruncateCascadeOption::Cascade) + cascade: Some(TruncateCascadeOption::Cascade), + on_cluster: None, }, truncate ); @@ -4043,7 +4045,8 @@ fn parse_truncate_with_table_list() { table: true, only: false, identity: Some(TruncateIdentityOption::Restart), - cascade: Some(TruncateCascadeOption::Cascade) + cascade: Some(TruncateCascadeOption::Cascade), + on_cluster: None, }, truncate );