Skip to content

Commit e0d3f76

Browse files
git-hulklustefaniak
authored andcommitted
Add support of parsing OPTIMIZE TABLE statement for ClickHouse (apache#1359)
# Conflicts: # src/ast/ddl.rs # src/ast/mod.rs # src/parser/mod.rs # tests/sqlparser_clickhouse.rs
1 parent f6b8c3a commit e0d3f76

File tree

5 files changed

+372
-4
lines changed

5 files changed

+372
-4
lines changed

src/ast/ddl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
958958
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
959959
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
960960
pub enum Partition {
961-
Identifier(Ident),
961+
Identifier(WithSpan<Ident>),
962962
Expr(Expr),
963963
/// ClickHouse supports PART expr which represents physical partition in disk.
964964
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)

src/ast/mod.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,20 @@ pub enum Statement {
15111511
/// RETURNING
15121512
returning: Option<Vec<WithSpan<SelectItem>>>,
15131513
},
1514+
/// ```sql
1515+
/// INSTALL
1516+
/// ```
1517+
Install {
1518+
/// Only for DuckDB
1519+
extension_name: WithSpan<Ident>,
1520+
},
1521+
/// ```sql
1522+
/// LOAD
1523+
/// ```
1524+
Load {
1525+
/// Only for DuckDB
1526+
extension_name: WithSpan<Ident>,
1527+
},
15141528
// TODO: Support ROW FORMAT
15151529
Directory {
15161530
overwrite: bool,
@@ -2231,6 +2245,46 @@ pub enum Statement {
22312245
name: ObjectName,
22322246
representation: UserDefinedTypeRepresentation,
22332247
},
2248+
/// ```sql
2249+
/// PRAGMA <schema-name>.<pragma-name> = <pragma-value>
2250+
/// ```
2251+
Pragma {
2252+
name: ObjectName,
2253+
value: Option<Value>,
2254+
is_eq: bool,
2255+
},
2256+
/// ```sql
2257+
/// LOCK TABLES <table_name> [READ [LOCAL] | [LOW_PRIORITY] WRITE]
2258+
/// ```
2259+
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
2260+
LockTables { tables: Vec<LockTable> },
2261+
/// ```sql
2262+
/// UNLOCK TABLES
2263+
/// ```
2264+
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
2265+
UnlockTables,
2266+
/// ```sql
2267+
/// UNLOAD(statement) TO <destination> [ WITH options ]
2268+
/// ```
2269+
/// See Redshift <https://docs.aws.amazon.com/redshift/latest/dg/r_UNLOAD.html> and
2270+
// Athena <https://docs.aws.amazon.com/athena/latest/ug/unload.html>
2271+
Unload {
2272+
query: Box<Query>,
2273+
to: WithSpan<Ident>,
2274+
with: Vec<SqlOption>,
2275+
},
2276+
/// ```sql
2277+
/// OPTIMIZE TABLE [db.]name [ON CLUSTER cluster] [PARTITION partition | PARTITION ID 'partition_id'] [FINAL] [DEDUPLICATE [BY expression]]
2278+
/// ```
2279+
///
2280+
/// See ClickHouse <https://clickhouse.com/docs/en/sql-reference/statements/optimize>
2281+
OptimizeTable {
2282+
name: ObjectName,
2283+
on_cluster: Option<WithSpan<Ident>>,
2284+
partition: Option<Partition>,
2285+
include_final: bool,
2286+
deduplicate: Option<Deduplicate>,
2287+
},
22342288
}
22352289

22362290
impl fmt::Display for Statement {
@@ -2476,6 +2530,14 @@ impl fmt::Display for Statement {
24762530
Ok(())
24772531
}
24782532

2533+
Statement::Install {
2534+
extension_name: name,
2535+
} => write!(f, "INSTALL {name}"),
2536+
2537+
Statement::Load {
2538+
extension_name: name,
2539+
} => write!(f, "LOAD {name}"),
2540+
24792541
Statement::Call(function) => write!(f, "CALL {function}"),
24802542

24812543
Statement::Copy {
@@ -3710,6 +3772,55 @@ impl fmt::Display for Statement {
37103772
} => {
37113773
write!(f, "CREATE TYPE {name} AS {representation}")
37123774
}
3775+
Statement::Pragma { name, value, is_eq } => {
3776+
write!(f, "PRAGMA {name}")?;
3777+
if value.is_some() {
3778+
let val = value.as_ref().unwrap();
3779+
if *is_eq {
3780+
write!(f, " = {val}")?;
3781+
} else {
3782+
write!(f, "({val})")?;
3783+
}
3784+
}
3785+
Ok(())
3786+
}
3787+
Statement::LockTables { tables } => {
3788+
write!(f, "LOCK TABLES {}", display_comma_separated(tables))
3789+
}
3790+
Statement::UnlockTables => {
3791+
write!(f, "UNLOCK TABLES")
3792+
}
3793+
Statement::Unload { query, to, with } => {
3794+
write!(f, "UNLOAD({query}) TO {to}")?;
3795+
3796+
if !with.is_empty() {
3797+
write!(f, " WITH ({})", display_comma_separated(with))?;
3798+
}
3799+
3800+
Ok(())
3801+
}
3802+
Statement::OptimizeTable {
3803+
name,
3804+
on_cluster,
3805+
partition,
3806+
include_final,
3807+
deduplicate,
3808+
} => {
3809+
write!(f, "OPTIMIZE TABLE {name}")?;
3810+
if let Some(on_cluster) = on_cluster {
3811+
write!(f, " ON CLUSTER {on_cluster}", on_cluster = on_cluster)?;
3812+
}
3813+
if let Some(partition) = partition {
3814+
write!(f, " {partition}", partition = partition)?;
3815+
}
3816+
if *include_final {
3817+
write!(f, " FINAL")?;
3818+
}
3819+
if let Some(deduplicate) = deduplicate {
3820+
write!(f, " {deduplicate}")?;
3821+
}
3822+
Ok(())
3823+
}
37133824
}
37143825
}
37153826
}
@@ -5210,6 +5321,61 @@ impl fmt::Display for SearchModifier {
52105321
}
52115322
}
52125323

5324+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5325+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5326+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5327+
pub struct LockTable {
5328+
pub table: Ident,
5329+
pub alias: Option<Ident>,
5330+
pub lock_type: LockTableType,
5331+
}
5332+
5333+
impl fmt::Display for LockTable {
5334+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5335+
let Self {
5336+
table: tbl_name,
5337+
alias,
5338+
lock_type,
5339+
} = self;
5340+
5341+
write!(f, "{tbl_name} ")?;
5342+
if let Some(alias) = alias {
5343+
write!(f, "AS {alias} ")?;
5344+
}
5345+
write!(f, "{lock_type}")?;
5346+
Ok(())
5347+
}
5348+
}
5349+
5350+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5351+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5352+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5353+
pub enum LockTableType {
5354+
Read { local: bool },
5355+
Write { low_priority: bool },
5356+
}
5357+
5358+
impl fmt::Display for LockTableType {
5359+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5360+
match self {
5361+
Self::Read { local } => {
5362+
write!(f, "READ")?;
5363+
if *local {
5364+
write!(f, " LOCAL")?;
5365+
}
5366+
}
5367+
Self::Write { low_priority } => {
5368+
if *low_priority {
5369+
write!(f, "LOW_PRIORITY ")?;
5370+
}
5371+
write!(f, "WRITE")?;
5372+
}
5373+
}
5374+
5375+
Ok(())
5376+
}
5377+
}
5378+
52135379
#[cfg(test)]
52145380
mod tests {
52155381
use super::*;

src/keywords.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ define_keywords!(
213213
DECADE,
214214
DECIMAL,
215215
DECLARE,
216+
DEDUPLICATE,
216217
DEFAULT,
217218
DEFERRABLE,
218219
DEFERRED,
@@ -284,6 +285,7 @@ define_keywords!(
284285
FILES,
285286
FILE_FORMAT,
286287
FILTER,
288+
FINAL,
287289
FIRST,
288290
FIRST_VALUE,
289291
FLOAT,
@@ -330,6 +332,7 @@ define_keywords!(
330332
HOLD,
331333
HOUR,
332334
HOURS,
335+
ID,
333336
IDENTITY,
334337
IF,
335338
IGNORE,
@@ -348,6 +351,7 @@ define_keywords!(
348351
INPUTFORMAT,
349352
INSENSITIVE,
350353
INSERT,
354+
INSTALL,
351355
INT,
352356
INT2,
353357
INT4,
@@ -385,6 +389,7 @@ define_keywords!(
385389
LIMIT,
386390
LISTAGG,
387391
LN,
392+
LOAD,
388393
LOCAL,
389394
LOCALTIME,
390395
LOCALTIMESTAMP,
@@ -501,6 +506,7 @@ define_keywords!(
501506
POSITION,
502507
POSITION_REGEX,
503508
POWER,
509+
PRAGMA,
504510
PRECEDES,
505511
PRECEDING,
506512
PRECISION,
@@ -677,6 +683,7 @@ define_keywords!(
677683
UNION,
678684
UNIQUE,
679685
UNKNOWN,
686+
UNLOAD,
680687
UNLOGGED,
681688
UNNEST,
682689
UNPIVOT,

0 commit comments

Comments
 (0)