Skip to content

Commit 8e86b4b

Browse files
committed
Correct handling of enum8 and enum16
1 parent 41a6b70 commit 8e86b4b

File tree

6 files changed

+103
-13
lines changed

6 files changed

+103
-13
lines changed

src/ast/data_type.rs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,12 @@ pub enum DataType {
294294
/// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/nested-data-structures/nested
295295
Nested(Vec<ColumnDef>),
296296
/// Enums
297-
Enum(Vec<String>),
297+
Enum(Vec<EnumTypeValue>),
298+
/// Enum8
299+
///
300+
/// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/enum
301+
Enum8(Vec<EnumTypeValue>),
302+
Enum16(Vec<EnumTypeValue>),
298303
/// Set
299304
Set(Vec<String>),
300305
/// Struct
@@ -497,15 +502,15 @@ impl fmt::Display for DataType {
497502
}
498503
}
499504
DataType::Enum(vals) => {
500-
write!(f, "ENUM(")?;
501-
for (i, v) in vals.iter().enumerate() {
502-
if i != 0 {
503-
write!(f, ", ")?;
504-
}
505-
write!(f, "'{}'", escape_single_quote_string(v))?;
506-
}
507-
write!(f, ")")
505+
write!(f, "ENUM({})", display_comma_separated(vals))
506+
}
507+
DataType::Enum8(vals) => {
508+
write!(f, "ENUM8({})", display_comma_separated(vals))
509+
}
510+
DataType::Enum16(vals) => {
511+
write!(f, "ENUM16({})", display_comma_separated(vals))
508512
}
513+
509514
DataType::Set(vals) => {
510515
write!(f, "SET(")?;
511516
for (i, v) in vals.iter().enumerate() {
@@ -786,3 +791,30 @@ pub enum ArrayElemTypeDef {
786791
/// `Array(Int64)`
787792
Parenthesis(Box<DataType>),
788793
}
794+
795+
796+
/// String enum values with optional integer value.
797+
///
798+
/// [1]: https://clickhouse.com/docs/en/sql-reference/data-types/enum
799+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
800+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
801+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
802+
pub enum EnumTypeValue {
803+
/// 'world'
804+
Name(String),
805+
/// 'hello'=1
806+
NameWithValue(String, i64),
807+
}
808+
809+
impl fmt::Display for EnumTypeValue {
810+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
811+
match self {
812+
Self::Name(n) => {
813+
write!(f, "'{}'", escape_single_quote_string(n))
814+
}
815+
Self::NameWithValue(n,v) => {
816+
write!(f, "'{}' = {}", escape_single_quote_string(n),v)
817+
}
818+
}
819+
}
820+
}

src/ast/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize};
2929
use sqlparser_derive::{Visit, VisitMut};
3030

3131
pub use self::data_type::{
32-
ArrayElemTypeDef, CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, TimezoneInfo,
32+
ArrayElemTypeDef, CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, TimezoneInfo, EnumTypeValue,
3333
};
3434
pub use self::dcl::{AlterRoleOperation, ResetConfig, RoleOption, SetConfigValue};
3535
pub use self::ddl::{

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ define_keywords!(
259259
ENFORCED,
260260
ENGINE,
261261
ENUM,
262+
ENUM16,
263+
ENUM8,
262264
EPHEMERAL,
263265
EPOCH,
264266
EQUALS,

src/parser/mod.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5900,6 +5900,18 @@ impl<'a> Parser<'a> {
59005900
}
59015901
}
59025902

5903+
/// Parse an literal integer/long
5904+
pub fn parse_literal_int(&mut self) -> Result<i64, ParserError> {
5905+
let neg = if self.consume_token(&Token::Minus) { -1 } else { 1 };
5906+
let next_token = self.next_token();
5907+
match next_token.token {
5908+
Token::Number(s, _) => s.parse::<i64>().map(|n| n*neg).map_err(|e| {
5909+
ParserError::ParserError(format!("Could not parse '{s}' as i64: {e}"))
5910+
}),
5911+
_ => self.expected("literal int", next_token),
5912+
}
5913+
}
5914+
59035915
pub fn parse_function_definition(&mut self) -> Result<FunctionDefinition, ParserError> {
59045916
let peek_token = self.peek_token();
59055917
match peek_token.token {
@@ -6184,7 +6196,9 @@ impl<'a> Parser<'a> {
61846196
Keyword::BIGDECIMAL => Ok(DataType::BigDecimal(
61856197
self.parse_exact_number_optional_precision_scale()?,
61866198
)),
6187-
Keyword::ENUM => Ok(DataType::Enum(self.parse_string_values()?)),
6199+
Keyword::ENUM => Ok(DataType::Enum(self.parse_enum_values()?)),
6200+
Keyword::ENUM8 => Ok(DataType::Enum8(self.parse_enum_values()?)),
6201+
Keyword::ENUM16 => Ok(DataType::Enum16(self.parse_enum_values()?)),
61886202
Keyword::SET => Ok(DataType::Set(self.parse_string_values()?)),
61896203
Keyword::ARRAY => {
61906204
if dialect_of!(self is SnowflakeDialect) {
@@ -6291,6 +6305,37 @@ impl<'a> Parser<'a> {
62916305
Ok(values)
62926306
}
62936307

6308+
pub fn parse_enum_values(&mut self) -> Result<Vec<EnumTypeValue>, ParserError> {
6309+
self.expect_token(&Token::LParen)?;
6310+
let mut values:Vec<EnumTypeValue> = Vec::new();
6311+
loop {
6312+
let next_token = self.next_token();
6313+
let name = match next_token.token {
6314+
Token::SingleQuotedString(value) => value,
6315+
_ => self.expected("a string", next_token)?,
6316+
};
6317+
let next_token = self.next_token();
6318+
match next_token.token {
6319+
Token::Eq => {
6320+
values.push(EnumTypeValue::NameWithValue(name, self.parse_literal_int()?));
6321+
if self.consume_token(&Token::RParen) {
6322+
break;
6323+
}
6324+
if self.consume_token(&Token::Comma) {
6325+
continue;
6326+
}
6327+
}
6328+
Token::Comma => values.push(EnumTypeValue::Name(name)),
6329+
Token::RParen => {
6330+
values.push(EnumTypeValue::Name(name));
6331+
break
6332+
},
6333+
_ => self.expected(", or }", next_token)?,
6334+
}
6335+
}
6336+
Ok(values)
6337+
}
6338+
62946339
/// Strictly parse `identifier AS identifier`
62956340
pub fn parse_identifier_with_alias(&mut self) -> Result<IdentWithAlias, ParserError> {
62966341
let ident = self.parse_identifier(false)?.unwrap();

tests/sqlparser_clickhouse.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,8 @@ fn parse_create_table_with_variant_default_expressions() {
603603
"a DATETIME MATERIALIZED now(),",
604604
" b DATETIME EPHEMERAL now(),",
605605
" c DATETIME EPHEMERAL,",
606-
" d STRING ALIAS toString(c)",
606+
" d STRING ALIAS toString(c),",
607+
" x ENUM8('hello' = 1, 'world', 'foo' = -3)",
607608
") ENGINE=MergeTree"
608609
);
609610
match clickhouse().verified_stmt(sql) {
@@ -697,6 +698,16 @@ fn parse_create_table_with_variant_default_expressions() {
697698
column_options: vec![],
698699
mask: None,
699700
column_location: None,
701+
},
702+
ColumnDef {
703+
name: Ident::new("x").empty_span(),
704+
data_type: DataType::Enum8(vec![EnumTypeValue::NameWithValue("hello".to_string(), 1), EnumTypeValue::Name("world".to_string()), EnumTypeValue::NameWithValue("foo".to_string(), -3)]),
705+
collation: None,
706+
codec: None,
707+
options: vec![],
708+
column_options: vec![],
709+
mask: None,
710+
column_location: None,
700711
}
701712
]
702713
)

tests/sqlparser_mysql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ fn parse_create_table_set_enum() {
433433
},
434434
ColumnDef {
435435
name: Ident::new("baz").empty_span(),
436-
data_type: DataType::Enum(vec!["a".to_string(), "b".to_string()]),
436+
data_type: DataType::Enum(vec![EnumTypeValue::Name("a".to_string()), EnumTypeValue::Name("b".to_string())]),
437437
collation: None,
438438
codec: None,
439439
options: vec![],

0 commit comments

Comments
 (0)