Skip to content

Commit 4e3b6c1

Browse files
committed
Support for Map values in ClickHouse settings
1 parent b1b379e commit 4e3b6c1

File tree

5 files changed

+124
-42
lines changed

5 files changed

+124
-42
lines changed

src/ast/query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ impl fmt::Display for ConnectBy {
10471047
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
10481048
pub struct Setting {
10491049
pub key: Ident,
1050-
pub value: Value,
1050+
pub value: Expr,
10511051
}
10521052

10531053
impl fmt::Display for Setting {

src/ast/value.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ impl From<ValueWithSpan> for Value {
116116
derive(Visit, VisitMut),
117117
visit(with = "visit_value")
118118
)]
119-
120119
pub enum Value {
121120
/// Numeric literal
122121
#[cfg(not(feature = "bigdecimal"))]

src/parser/mod.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,7 +2771,7 @@ impl<'a> Parser<'a> {
27712771

27722772
if self.dialect.supports_dictionary_syntax() {
27732773
self.prev_token(); // Put back the '{'
2774-
return self.parse_duckdb_struct_literal();
2774+
return self.parse_duckdb_and_clickhouse_struct_literal();
27752775
}
27762776

27772777
self.expected("an expression", token)
@@ -3147,7 +3147,7 @@ impl<'a> Parser<'a> {
31473147
Ok(fields)
31483148
}
31493149

3150-
/// DuckDB specific: Parse a duckdb [dictionary]
3150+
/// DuckDB and ClickHouse specific: Parse a duckdb [dictionary] or a clickhouse [map] setting
31513151
///
31523152
/// Syntax:
31533153
///
@@ -3156,18 +3156,21 @@ impl<'a> Parser<'a> {
31563156
/// ```
31573157
///
31583158
/// [dictionary]: https://duckdb.org/docs/sql/data_types/struct#creating-structs
3159-
fn parse_duckdb_struct_literal(&mut self) -> Result<Expr, ParserError> {
3159+
/// [map]: https://clickhouse.com/docs/operations/settings/settings#additional_table_filters
3160+
fn parse_duckdb_and_clickhouse_struct_literal(&mut self) -> Result<Expr, ParserError> {
31603161
self.expect_token(&Token::LBrace)?;
31613162

3162-
let fields =
3163-
self.parse_comma_separated0(Self::parse_duckdb_dictionary_field, Token::RBrace)?;
3163+
let fields = self.parse_comma_separated0(
3164+
Self::parse_duckdb_and_clickhouse_struct_field,
3165+
Token::RBrace,
3166+
)?;
31643167

31653168
self.expect_token(&Token::RBrace)?;
31663169

31673170
Ok(Expr::Dictionary(fields))
31683171
}
31693172

3170-
/// Parse a field for a duckdb [dictionary]
3173+
/// Parse a field for a duckdb [dictionary] or a clickhouse [map] setting
31713174
///
31723175
/// Syntax
31733176
///
@@ -3176,7 +3179,8 @@ impl<'a> Parser<'a> {
31763179
/// ```
31773180
///
31783181
/// [dictionary]: https://duckdb.org/docs/sql/data_types/struct#creating-structs
3179-
fn parse_duckdb_dictionary_field(&mut self) -> Result<DictionaryField, ParserError> {
3182+
/// [map]: https://clickhouse.com/docs/operations/settings/settings#additional_table_filters
3183+
fn parse_duckdb_and_clickhouse_struct_field(&mut self) -> Result<DictionaryField, ParserError> {
31803184
let key = self.parse_identifier()?;
31813185

31823186
self.expect_token(&Token::Colon)?;
@@ -11190,7 +11194,12 @@ impl<'a> Parser<'a> {
1119011194
let key_values = self.parse_comma_separated(|p| {
1119111195
let key = p.parse_identifier()?;
1119211196
p.expect_token(&Token::Eq)?;
11193-
let value = p.parse_value()?.value;
11197+
11198+
let value = if p.peek_token_ref().token == Token::LBrace {
11199+
p.parse_duckdb_and_clickhouse_struct_literal()?
11200+
} else {
11201+
Expr::Value(p.parse_value()?)
11202+
};
1119411203
Ok(Setting { key, value })
1119511204
})?;
1119611205
Some(key_values)

src/test_utils.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,11 @@ pub fn number(n: &str) -> Value {
366366
Value::Number(n.parse().unwrap(), false)
367367
}
368368

369+
/// Creates a `Value::SingleQuotedString`
370+
pub fn single_quoted_string(s: &str) -> Value {
371+
Value::SingleQuotedString(s.to_string())
372+
}
373+
369374
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
370375
Some(TableAlias {
371376
name: Ident::new(name),

tests/sqlparser_clickhouse.rs

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use test_utils::*;
2828
use sqlparser::ast::Expr::{BinaryOp, Identifier};
2929
use sqlparser::ast::SelectItem::UnnamedExpr;
3030
use sqlparser::ast::TableFactor::Table;
31-
use sqlparser::ast::Value::Number;
31+
use sqlparser::ast::Value::Boolean;
3232
use sqlparser::ast::*;
3333
use sqlparser::dialect::ClickHouseDialect;
3434
use sqlparser::dialect::GenericDialect;
@@ -965,38 +965,107 @@ fn parse_limit_by() {
965965

966966
#[test]
967967
fn parse_settings_in_query() {
968-
match clickhouse_and_generic()
969-
.verified_stmt(r#"SELECT * FROM t SETTINGS max_threads = 1, max_block_size = 10000"#)
970-
{
971-
Statement::Query(query) => {
972-
assert_eq!(
973-
query.settings,
974-
Some(vec![
975-
Setting {
976-
key: Ident::new("max_threads"),
977-
value: Number("1".parse().unwrap(), false)
978-
},
979-
Setting {
980-
key: Ident::new("max_block_size"),
981-
value: Number("10000".parse().unwrap(), false)
982-
},
983-
])
984-
);
968+
fn check_settings(sql: &str, expected: Vec<Setting>) {
969+
match clickhouse_and_generic().verified_stmt(sql) {
970+
Statement::Query(q) => {
971+
assert_eq!(q.settings, Some(expected));
972+
}
973+
_ => unreachable!(),
985974
}
986-
_ => unreachable!(),
975+
}
976+
977+
for (sql, expected_settings) in vec![
978+
(
979+
r#"SELECT * FROM t SETTINGS max_threads = 1, max_block_size = 10000"#,
980+
vec![
981+
Setting {
982+
key: Ident::new("max_threads"),
983+
value: Expr::value(number("1")),
984+
},
985+
Setting {
986+
key: Ident::new("max_block_size"),
987+
value: Expr::value(number("10000")),
988+
},
989+
],
990+
),
991+
(
992+
r#"SELECT * FROM t SETTINGS additional_table_filters = {'table_1': 'x != 2'}"#,
993+
vec![Setting {
994+
key: Ident::new("additional_table_filters"),
995+
value: Expr::Dictionary(vec![DictionaryField {
996+
key: Ident::with_quote('\'', "table_1"),
997+
value: Expr::value(single_quoted_string("x != 2")).into(),
998+
}]),
999+
}],
1000+
),
1001+
(
1002+
r#"SELECT * FROM t SETTINGS additional_result_filter = 'x != 2', query_plan_optimize_lazy_materialization = false"#,
1003+
vec![
1004+
Setting {
1005+
key: Ident::new("additional_result_filter"),
1006+
value: Expr::value(single_quoted_string("x != 2")),
1007+
},
1008+
Setting {
1009+
key: Ident::new("query_plan_optimize_lazy_materialization"),
1010+
value: Expr::value(Boolean(false)),
1011+
},
1012+
],
1013+
),
1014+
] {
1015+
check_settings(sql, expected_settings);
9871016
}
9881017

9891018
let invalid_cases = vec![
990-
"SELECT * FROM t SETTINGS a",
991-
"SELECT * FROM t SETTINGS a=",
992-
"SELECT * FROM t SETTINGS a=1, b",
993-
"SELECT * FROM t SETTINGS a=1, b=",
994-
"SELECT * FROM t SETTINGS a=1, b=c",
1019+
("SELECT * FROM t SETTINGS a", "Expected: =, found: EOF"),
1020+
(
1021+
"SELECT * FROM t SETTINGS a=",
1022+
"Expected: a value, found: EOF",
1023+
),
1024+
("SELECT * FROM t SETTINGS a=1, b", "Expected: =, found: EOF"),
1025+
(
1026+
"SELECT * FROM t SETTINGS a=1, b=",
1027+
"Expected: a value, found: EOF",
1028+
),
1029+
(
1030+
"SELECT * FROM t SETTINGS a=1, b=c",
1031+
"Expected: a concrete value, found: c",
1032+
),
1033+
(
1034+
"SELECT * FROM t SETTINGS a = {",
1035+
"Expected: identifier, found: EOF",
1036+
),
1037+
(
1038+
"SELECT * FROM t SETTINGS a = {'b'",
1039+
"Expected: :, found: EOF",
1040+
),
1041+
(
1042+
"SELECT * FROM t SETTINGS a = {'b': ",
1043+
"Expected: an expression, found: EOF",
1044+
),
1045+
(
1046+
"SELECT * FROM t SETTINGS a = {'b': 'c',}",
1047+
"Expected: identifier, found: }",
1048+
),
1049+
(
1050+
"SELECT * FROM t SETTINGS a = {'b': 'c', 'd'}",
1051+
"Expected: :, found: }",
1052+
),
1053+
(
1054+
"SELECT * FROM t SETTINGS a = {'b': 'c', 'd': }",
1055+
"Expected: an expression, found: }",
1056+
),
1057+
(
1058+
"SELECT * FROM t SETTINGS a = {ANY(b)}",
1059+
"Expected: :, found: (",
1060+
),
9951061
];
996-
for sql in invalid_cases {
997-
clickhouse_and_generic()
998-
.parse_sql_statements(sql)
999-
.expect_err("Expected: SETTINGS key = value, found: ");
1062+
for (sql, error_msg) in invalid_cases {
1063+
assert_eq!(
1064+
clickhouse_and_generic()
1065+
.parse_sql_statements(sql)
1066+
.unwrap_err(),
1067+
ParserError(error_msg.to_string())
1068+
);
10001069
}
10011070
}
10021071
#[test]
@@ -1550,11 +1619,11 @@ fn parse_select_table_function_settings() {
15501619
settings: Some(vec![
15511620
Setting {
15521621
key: "s0".into(),
1553-
value: Value::Number("3".parse().unwrap(), false),
1622+
value: Expr::value(number("3")),
15541623
},
15551624
Setting {
15561625
key: "s1".into(),
1557-
value: Value::SingleQuotedString("s".into()),
1626+
value: Expr::value(single_quoted_string("s")),
15581627
},
15591628
]),
15601629
},
@@ -1575,11 +1644,11 @@ fn parse_select_table_function_settings() {
15751644
settings: Some(vec![
15761645
Setting {
15771646
key: "s0".into(),
1578-
value: Value::Number("3".parse().unwrap(), false),
1647+
value: Expr::value(number("3")),
15791648
},
15801649
Setting {
15811650
key: "s1".into(),
1582-
value: Value::SingleQuotedString("s".into()),
1651+
value: Expr::value(single_quoted_string("s")),
15831652
},
15841653
]),
15851654
},

0 commit comments

Comments
 (0)