Skip to content

Commit 73f7784

Browse files
committed
Support for Map values in ClickHouse settings
1 parent 84c3a1b commit 73f7784

5 files changed

Lines changed: 124 additions & 42 deletions

File tree

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)
@@ -3144,7 +3144,7 @@ impl<'a> Parser<'a> {
31443144
Ok(fields)
31453145
}
31463146

3147-
/// DuckDB specific: Parse a duckdb [dictionary]
3147+
/// DuckDB and ClickHouse specific: Parse a duckdb [dictionary] or a clickhouse [map] setting
31483148
///
31493149
/// Syntax:
31503150
///
@@ -3153,18 +3153,21 @@ impl<'a> Parser<'a> {
31533153
/// ```
31543154
///
31553155
/// [dictionary]: https://duckdb.org/docs/sql/data_types/struct#creating-structs
3156-
fn parse_duckdb_struct_literal(&mut self) -> Result<Expr, ParserError> {
3156+
/// [map]: https://clickhouse.com/docs/operations/settings/settings#additional_table_filters
3157+
fn parse_duckdb_and_clickhouse_struct_literal(&mut self) -> Result<Expr, ParserError> {
31573158
self.expect_token(&Token::LBrace)?;
31583159

3159-
let fields =
3160-
self.parse_comma_separated0(Self::parse_duckdb_dictionary_field, Token::RBrace)?;
3160+
let fields = self.parse_comma_separated0(
3161+
Self::parse_duckdb_and_clickhouse_struct_field,
3162+
Token::RBrace,
3163+
)?;
31613164

31623165
self.expect_token(&Token::RBrace)?;
31633166

31643167
Ok(Expr::Dictionary(fields))
31653168
}
31663169

3167-
/// Parse a field for a duckdb [dictionary]
3170+
/// Parse a field for a duckdb [dictionary] or a clickhouse [map] setting
31683171
///
31693172
/// Syntax
31703173
///
@@ -3173,7 +3176,8 @@ impl<'a> Parser<'a> {
31733176
/// ```
31743177
///
31753178
/// [dictionary]: https://duckdb.org/docs/sql/data_types/struct#creating-structs
3176-
fn parse_duckdb_dictionary_field(&mut self) -> Result<DictionaryField, ParserError> {
3179+
/// [map]: https://clickhouse.com/docs/operations/settings/settings#additional_table_filters
3180+
fn parse_duckdb_and_clickhouse_struct_field(&mut self) -> Result<DictionaryField, ParserError> {
31773181
let key = self.parse_identifier()?;
31783182

31793183
self.expect_token(&Token::Colon)?;
@@ -11177,7 +11181,12 @@ impl<'a> Parser<'a> {
1117711181
let key_values = self.parse_comma_separated(|p| {
1117811182
let key = p.parse_identifier()?;
1117911183
p.expect_token(&Token::Eq)?;
11180-
let value = p.parse_value()?.value;
11184+
11185+
let value = if p.peek_token_ref().token == Token::LBrace {
11186+
p.parse_duckdb_and_clickhouse_struct_literal()?
11187+
} else {
11188+
Expr::Value(p.parse_value()?)
11189+
};
1118111190
Ok(Setting { key, value })
1118211191
})?;
1118311192
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;
@@ -961,38 +961,107 @@ fn parse_limit_by() {
961961

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

9851014
let invalid_cases = vec![
986-
"SELECT * FROM t SETTINGS a",
987-
"SELECT * FROM t SETTINGS a=",
988-
"SELECT * FROM t SETTINGS a=1, b",
989-
"SELECT * FROM t SETTINGS a=1, b=",
990-
"SELECT * FROM t SETTINGS a=1, b=c",
1015+
("SELECT * FROM t SETTINGS a", "Expected: =, found: EOF"),
1016+
(
1017+
"SELECT * FROM t SETTINGS a=",
1018+
"Expected: a value, found: EOF",
1019+
),
1020+
("SELECT * FROM t SETTINGS a=1, b", "Expected: =, found: EOF"),
1021+
(
1022+
"SELECT * FROM t SETTINGS a=1, b=",
1023+
"Expected: a value, found: EOF",
1024+
),
1025+
(
1026+
"SELECT * FROM t SETTINGS a=1, b=c",
1027+
"Expected: a concrete value, found: c",
1028+
),
1029+
(
1030+
"SELECT * FROM t SETTINGS a = {",
1031+
"Expected: identifier, found: EOF",
1032+
),
1033+
(
1034+
"SELECT * FROM t SETTINGS a = {'b'",
1035+
"Expected: :, found: EOF",
1036+
),
1037+
(
1038+
"SELECT * FROM t SETTINGS a = {'b': ",
1039+
"Expected: an expression, found: EOF",
1040+
),
1041+
(
1042+
"SELECT * FROM t SETTINGS a = {'b': 'c',}",
1043+
"Expected: identifier, found: }",
1044+
),
1045+
(
1046+
"SELECT * FROM t SETTINGS a = {'b': 'c', 'd'}",
1047+
"Expected: :, found: }",
1048+
),
1049+
(
1050+
"SELECT * FROM t SETTINGS a = {'b': 'c', 'd': }",
1051+
"Expected: an expression, found: }",
1052+
),
1053+
(
1054+
"SELECT * FROM t SETTINGS a = {ANY(b)}",
1055+
"Expected: :, found: (",
1056+
),
9911057
];
992-
for sql in invalid_cases {
993-
clickhouse_and_generic()
994-
.parse_sql_statements(sql)
995-
.expect_err("Expected: SETTINGS key = value, found: ");
1058+
for (sql, error_msg) in invalid_cases {
1059+
assert_eq!(
1060+
clickhouse_and_generic()
1061+
.parse_sql_statements(sql)
1062+
.unwrap_err(),
1063+
ParserError(error_msg.to_string())
1064+
);
9961065
}
9971066
}
9981067
#[test]
@@ -1546,11 +1615,11 @@ fn parse_select_table_function_settings() {
15461615
settings: Some(vec![
15471616
Setting {
15481617
key: "s0".into(),
1549-
value: Value::Number("3".parse().unwrap(), false),
1618+
value: Expr::value(number("3")),
15501619
},
15511620
Setting {
15521621
key: "s1".into(),
1553-
value: Value::SingleQuotedString("s".into()),
1622+
value: Expr::value(single_quoted_string("s")),
15541623
},
15551624
]),
15561625
},
@@ -1571,11 +1640,11 @@ fn parse_select_table_function_settings() {
15711640
settings: Some(vec![
15721641
Setting {
15731642
key: "s0".into(),
1574-
value: Value::Number("3".parse().unwrap(), false),
1643+
value: Expr::value(number("3")),
15751644
},
15761645
Setting {
15771646
key: "s1".into(),
1578-
value: Value::SingleQuotedString("s".into()),
1647+
value: Expr::value(single_quoted_string("s")),
15791648
},
15801649
]),
15811650
},

0 commit comments

Comments
 (0)