Skip to content

Commit

Permalink
ClickHouse CREATE TABLE Fixes: add ORDER BY and fix clause ordering (#…
Browse files Browse the repository at this point in the history
…824)

* Fix ClickHouse (add ORDER BY)

* Improve test case
  • Loading branch information
ankrgyl authored Mar 6, 2023
1 parent 1cf913e commit d69b875
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 11 deletions.
12 changes: 11 additions & 1 deletion src/ast/helpers/stmt_create_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use sqlparser_derive::{Visit, VisitMut};

use crate::ast::{
ColumnDef, FileFormat, HiveDistributionStyle, HiveFormat, ObjectName, OnCommit, Query,
ColumnDef, FileFormat, HiveDistributionStyle, HiveFormat, Ident, ObjectName, OnCommit, Query,
SqlOption, Statement, TableConstraint,
};
use crate::parser::ParserError;
Expand Down Expand Up @@ -69,6 +69,7 @@ pub struct CreateTableBuilder {
pub collation: Option<String>,
pub on_commit: Option<OnCommit>,
pub on_cluster: Option<String>,
pub order_by: Option<Vec<Ident>>,
}

impl CreateTableBuilder {
Expand Down Expand Up @@ -98,6 +99,7 @@ impl CreateTableBuilder {
collation: None,
on_commit: None,
on_cluster: None,
order_by: None,
}
}
pub fn or_replace(mut self, or_replace: bool) -> Self {
Expand Down Expand Up @@ -213,6 +215,11 @@ impl CreateTableBuilder {
self
}

pub fn order_by(mut self, order_by: Option<Vec<Ident>>) -> Self {
self.order_by = order_by;
self
}

pub fn build(self) -> Statement {
Statement::CreateTable {
or_replace: self.or_replace,
Expand All @@ -239,6 +246,7 @@ impl CreateTableBuilder {
collation: self.collation,
on_commit: self.on_commit,
on_cluster: self.on_cluster,
order_by: self.order_by,
}
}
}
Expand Down Expand Up @@ -275,6 +283,7 @@ impl TryFrom<Statement> for CreateTableBuilder {
collation,
on_commit,
on_cluster,
order_by,
} => Ok(Self {
or_replace,
temporary,
Expand All @@ -300,6 +309,7 @@ impl TryFrom<Statement> for CreateTableBuilder {
collation,
on_commit,
on_cluster,
order_by,
}),
_ => Err(ParserError::ParserError(format!(
"Expected create table statement, but received: {stmt}"
Expand Down
16 changes: 12 additions & 4 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1254,9 +1254,13 @@ pub enum Statement {
default_charset: Option<String>,
collation: Option<String>,
on_commit: Option<OnCommit>,
/// Click house "ON CLUSTER" clause:
/// ClickHouse "ON CLUSTER" clause:
/// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
on_cluster: Option<String>,
/// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
/// than empty (represented as ()), the latter meaning "no sorting".
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
order_by: Option<Vec<Ident>>,
},
/// SQLite's `CREATE VIRTUAL TABLE .. USING <module_name> (<module_args>)`
CreateVirtualTable {
Expand Down Expand Up @@ -2053,6 +2057,7 @@ impl fmt::Display for Statement {
collation,
on_commit,
on_cluster,
order_by,
} => {
// We want to allow the following options
// Empty column list, allowed by PostgreSQL:
Expand Down Expand Up @@ -2196,12 +2201,15 @@ impl fmt::Display for Statement {
if !with_options.is_empty() {
write!(f, " WITH ({})", display_comma_separated(with_options))?;
}
if let Some(query) = query {
write!(f, " AS {query}")?;
}
if let Some(engine) = engine {
write!(f, " ENGINE={engine}")?;
}
if let Some(order_by) = order_by {
write!(f, " ORDER BY ({})", display_comma_separated(order_by))?;
}
if let Some(query) = query {
write!(f, " AS {query}")?;
}
if let Some(default_charset) = default_charset {
write!(f, " DEFAULT CHARSET={default_charset}")?;
}
Expand Down
30 changes: 24 additions & 6 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3340,12 +3340,6 @@ impl<'a> Parser<'a> {
// PostgreSQL supports `WITH ( options )`, before `AS`
let with_options = self.parse_options(Keyword::WITH)?;
let table_properties = self.parse_options(Keyword::TBLPROPERTIES)?;
// Parse optional `AS ( query )`
let query = if self.parse_keyword(Keyword::AS) {
Some(Box::new(self.parse_query()?))
} else {
None
};

let engine = if self.parse_keyword(Keyword::ENGINE) {
self.expect_token(&Token::Eq)?;
Expand All @@ -3358,6 +3352,29 @@ impl<'a> Parser<'a> {
None
};

let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) {
if self.consume_token(&Token::LParen) {
let columns = if self.peek_token() != Token::RParen {
self.parse_comma_separated(Parser::parse_identifier)?
} else {
vec![]
};
self.expect_token(&Token::RParen)?;
Some(columns)
} else {
Some(vec![self.parse_identifier()?])
}
} else {
None
};

// Parse optional `AS ( query )`
let query = if self.parse_keyword(Keyword::AS) {
Some(Box::new(self.parse_query()?))
} else {
None
};

let default_charset = if self.parse_keywords(&[Keyword::DEFAULT, Keyword::CHARSET]) {
self.expect_token(&Token::Eq)?;
let next_token = self.next_token();
Expand Down Expand Up @@ -3414,6 +3431,7 @@ impl<'a> Parser<'a> {
.like(like)
.clone_clause(clone)
.engine(engine)
.order_by(order_by)
.default_charset(default_charset)
.collation(collation)
.on_commit(on_commit)
Expand Down
12 changes: 12 additions & 0 deletions tests/sqlparser_clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,18 @@ fn parse_similar_to() {
chk(true);
}

#[test]
fn parse_create_table() {
clickhouse().verified_stmt(r#"CREATE TABLE "x" ("a" "int") ENGINE=MergeTree ORDER BY ("x")"#);
clickhouse().one_statement_parses_to(
r#"CREATE TABLE "x" ("a" "int") ENGINE=MergeTree ORDER BY "x""#,
r#"CREATE TABLE "x" ("a" "int") ENGINE=MergeTree ORDER BY ("x")"#,
);
clickhouse().verified_stmt(
r#"CREATE TABLE "x" ("a" "int") ENGINE=MergeTree ORDER BY ("x") AS SELECT * FROM "t" WHERE true"#,
);
}

fn clickhouse() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(ClickHouseDialect {})],
Expand Down

0 comments on commit d69b875

Please sign in to comment.