Skip to content

Commit 625d0e6

Browse files
authored
Merge branch 'main' into feature/support-clickhouse-prewhere
2 parents 6ef8164 + 700bd03 commit 625d0e6

File tree

9 files changed

+111
-5
lines changed

9 files changed

+111
-5
lines changed

src/ast/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub use self::query::{
4848
MatchRecognizePattern, MatchRecognizeSymbol, Measure, NamedWindowDefinition, NamedWindowExpr,
4949
NonBlock, Offset, OffsetRows, OrderByExpr, PivotValueSource, Query, RenameSelectItem,
5050
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,
51-
SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, SymbolDefinition, Table,
51+
SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, Setting, SymbolDefinition, Table,
5252
TableAlias, TableFactor, TableVersion, TableWithJoins, Top, TopQuantity, ValueTableMode,
5353
Values, WildcardAdditionalOptions, With,
5454
};

src/ast/query.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ pub struct Query {
5050
/// `FOR JSON { AUTO | PATH } [ , INCLUDE_NULL_VALUES ]`
5151
/// (MSSQL-specific)
5252
pub for_clause: Option<ForClause>,
53+
/// ClickHouse syntax: `SELECT * FROM t SETTINGS key1 = value1, key2 = value2`
54+
///
55+
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select#settings-in-select-query)
56+
pub settings: Option<Vec<Setting>>,
5357
}
5458

5559
impl fmt::Display for Query {
@@ -70,6 +74,9 @@ impl fmt::Display for Query {
7074
if !self.limit_by.is_empty() {
7175
write!(f, " BY {}", display_separated(&self.limit_by, ", "))?;
7276
}
77+
if let Some(ref settings) = self.settings {
78+
write!(f, " SETTINGS {}", display_comma_separated(settings))?;
79+
}
7380
if let Some(ref fetch) = self.fetch {
7481
write!(f, " {fetch}")?;
7582
}
@@ -836,6 +843,20 @@ impl fmt::Display for ConnectBy {
836843
}
837844
}
838845

846+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
847+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
848+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
849+
pub struct Setting {
850+
pub key: Ident,
851+
pub value: Value,
852+
}
853+
854+
impl fmt::Display for Setting {
855+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
856+
write!(f, "{} = {}", self.key, self.value)
857+
}
858+
}
859+
839860
/// An expression optionally followed by an alias.
840861
///
841862
/// Example:

src/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ define_keywords!(
651651
SESSION_USER,
652652
SET,
653653
SETS,
654+
SETTINGS,
654655
SHARE,
655656
SHOW,
656657
SIMILAR,
@@ -853,6 +854,8 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
853854
Keyword::PARTITION,
854855
// for Clickhouse PREWHERE
855856
Keyword::PREWHERE,
857+
// for ClickHouse SELECT * FROM t SETTINGS ...
858+
Keyword::SETTINGS,
856859
// for Snowflake START WITH .. CONNECT BY
857860
Keyword::START,
858861
Keyword::CONNECT,

src/parser/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7871,6 +7871,7 @@ impl<'a> Parser<'a> {
78717871
fetch: None,
78727872
locks: vec![],
78737873
for_clause: None,
7874+
settings: None,
78747875
})
78757876
} else if self.parse_keyword(Keyword::UPDATE) {
78767877
Ok(Query {
@@ -7883,6 +7884,7 @@ impl<'a> Parser<'a> {
78837884
fetch: None,
78847885
locks: vec![],
78857886
for_clause: None,
7887+
settings: None,
78867888
})
78877889
} else {
78887890
let body = self.parse_boxed_query_body(0)?;
@@ -7928,6 +7930,20 @@ impl<'a> Parser<'a> {
79287930
vec![]
79297931
};
79307932

7933+
let settings = if dialect_of!(self is ClickHouseDialect|GenericDialect)
7934+
&& self.parse_keyword(Keyword::SETTINGS)
7935+
{
7936+
let key_values = self.parse_comma_separated(|p| {
7937+
let key = p.parse_identifier(false)?;
7938+
p.expect_token(&Token::Eq)?;
7939+
let value = p.parse_value()?;
7940+
Ok(Setting { key, value })
7941+
})?;
7942+
Some(key_values)
7943+
} else {
7944+
None
7945+
};
7946+
79317947
let fetch = if self.parse_keyword(Keyword::FETCH) {
79327948
Some(self.parse_fetch()?)
79337949
} else {
@@ -7955,6 +7971,7 @@ impl<'a> Parser<'a> {
79557971
fetch,
79567972
locks,
79577973
for_clause,
7974+
settings,
79587975
})
79597976
}
79607977
}
@@ -9100,6 +9117,7 @@ impl<'a> Parser<'a> {
91009117
fetch: None,
91019118
locks: vec![],
91029119
for_clause: None,
9120+
settings: None,
91039121
}),
91049122
alias,
91059123
})

tests/sqlparser_clickhouse.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use test_utils::*;
2121
use sqlparser::ast::Expr::{BinaryOp, Identifier, MapAccess};
2222
use sqlparser::ast::SelectItem::UnnamedExpr;
2323
use sqlparser::ast::TableFactor::Table;
24+
use sqlparser::ast::Value::Number;
2425
use sqlparser::ast::*;
25-
2626
use sqlparser::dialect::ClickHouseDialect;
2727
use sqlparser::dialect::GenericDialect;
2828

@@ -550,6 +550,42 @@ fn parse_limit_by() {
550550
);
551551
}
552552

553+
#[test]
554+
fn parse_settings_in_query() {
555+
match clickhouse_and_generic()
556+
.verified_stmt(r#"SELECT * FROM t SETTINGS max_threads = 1, max_block_size = 10000"#)
557+
{
558+
Statement::Query(query) => {
559+
assert_eq!(
560+
query.settings,
561+
Some(vec![
562+
Setting {
563+
key: Ident::new("max_threads"),
564+
value: Number("1".parse().unwrap(), false)
565+
},
566+
Setting {
567+
key: Ident::new("max_block_size"),
568+
value: Number("10000".parse().unwrap(), false)
569+
},
570+
])
571+
);
572+
}
573+
_ => unreachable!(),
574+
}
575+
576+
let invalid_cases = vec![
577+
"SELECT * FROM t SETTINGS a",
578+
"SELECT * FROM t SETTINGS a=",
579+
"SELECT * FROM t SETTINGS a=1, b",
580+
"SELECT * FROM t SETTINGS a=1, b=",
581+
"SELECT * FROM t SETTINGS a=1, b=c",
582+
];
583+
for sql in invalid_cases {
584+
clickhouse_and_generic()
585+
.parse_sql_statements(sql)
586+
.expect_err("Expected: SETTINGS key = value, found: ");
587+
}
588+
}
553589
#[test]
554590
fn parse_select_star_except() {
555591
clickhouse().verified_stmt("SELECT * EXCEPT (prev_status) FROM anomalies");

tests/sqlparser_common.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ fn parse_update_set_from() {
414414
fetch: None,
415415
locks: vec![],
416416
for_clause: None,
417+
settings: None,
417418
}),
418419
alias: Some(TableAlias {
419420
name: Ident::new("t2"),
@@ -3428,6 +3429,7 @@ fn parse_create_table_as_table() {
34283429
fetch: None,
34293430
locks: vec![],
34303431
for_clause: None,
3432+
settings: None,
34313433
});
34323434

34333435
match verified_stmt(sql1) {
@@ -3453,6 +3455,7 @@ fn parse_create_table_as_table() {
34533455
fetch: None,
34543456
locks: vec![],
34553457
for_clause: None,
3458+
settings: None,
34563459
});
34573460

34583461
match verified_stmt(sql2) {
@@ -4999,6 +5002,7 @@ fn parse_interval_and_or_xor() {
49995002
fetch: None,
50005003
locks: vec![],
50015004
for_clause: None,
5005+
settings: None,
50025006
}))];
50035007

50045008
assert_eq!(actual_ast, expected_ast);
@@ -7654,6 +7658,7 @@ fn parse_merge() {
76547658
fetch: None,
76557659
locks: vec![],
76567660
for_clause: None,
7661+
settings: None,
76577662
}),
76587663
alias: Some(TableAlias {
76597664
name: Ident {
@@ -9162,6 +9167,7 @@ fn parse_unload() {
91629167
locks: vec![],
91639168
for_clause: None,
91649169
order_by: vec![],
9170+
settings: None,
91659171
}),
91669172
to: Ident {
91679173
value: "s3://...".to_string(),

tests/sqlparser_mssql.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ fn parse_create_procedure() {
103103
locks: vec![],
104104
for_clause: None,
105105
order_by: vec![],
106+
settings: None,
106107
body: Box::new(SetExpr::Select(Box::new(Select {
107108
distinct: None,
108109
top: None,
@@ -548,6 +549,7 @@ fn parse_substring_in_select() {
548549
fetch: None,
549550
locks: vec![],
550551
for_clause: None,
552+
settings: None,
551553
}),
552554
query
553555
);

tests/sqlparser_mysql.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,7 @@ fn parse_escaped_quote_identifiers_with_escape() {
926926
fetch: None,
927927
locks: vec![],
928928
for_clause: None,
929+
settings: None,
929930
}))
930931
);
931932
}
@@ -974,6 +975,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
974975
fetch: None,
975976
locks: vec![],
976977
for_clause: None,
978+
settings: None,
977979
}))
978980
);
979981
}
@@ -1019,6 +1021,7 @@ fn parse_escaped_backticks_with_escape() {
10191021
fetch: None,
10201022
locks: vec![],
10211023
for_clause: None,
1024+
settings: None,
10221025
}))
10231026
);
10241027
}
@@ -1064,6 +1067,7 @@ fn parse_escaped_backticks_with_no_escape() {
10641067
fetch: None,
10651068
locks: vec![],
10661069
for_clause: None,
1070+
settings: None,
10671071
}))
10681072
);
10691073
}
@@ -1268,6 +1272,7 @@ fn parse_simple_insert() {
12681272
fetch: None,
12691273
locks: vec![],
12701274
for_clause: None,
1275+
settings: None,
12711276
})),
12721277
source
12731278
);
@@ -1310,6 +1315,7 @@ fn parse_ignore_insert() {
13101315
fetch: None,
13111316
locks: vec![],
13121317
for_clause: None,
1318+
settings: None,
13131319
})),
13141320
source
13151321
);
@@ -1352,6 +1358,7 @@ fn parse_priority_insert() {
13521358
fetch: None,
13531359
locks: vec![],
13541360
for_clause: None,
1361+
settings: None,
13551362
})),
13561363
source
13571364
);
@@ -1391,6 +1398,7 @@ fn parse_priority_insert() {
13911398
fetch: None,
13921399
locks: vec![],
13931400
for_clause: None,
1401+
settings: None,
13941402
})),
13951403
source
13961404
);
@@ -1438,6 +1446,7 @@ fn parse_insert_as() {
14381446
fetch: None,
14391447
locks: vec![],
14401448
for_clause: None,
1449+
settings: None,
14411450
})),
14421451
source
14431452
);
@@ -1497,6 +1506,7 @@ fn parse_insert_as() {
14971506
fetch: None,
14981507
locks: vec![],
14991508
for_clause: None,
1509+
settings: None,
15001510
})),
15011511
source
15021512
);
@@ -1540,6 +1550,7 @@ fn parse_replace_insert() {
15401550
fetch: None,
15411551
locks: vec![],
15421552
for_clause: None,
1553+
settings: None,
15431554
})),
15441555
source
15451556
);
@@ -1577,6 +1588,7 @@ fn parse_empty_row_insert() {
15771588
fetch: None,
15781589
locks: vec![],
15791590
for_clause: None,
1591+
settings: None,
15801592
})),
15811593
source
15821594
);
@@ -1637,6 +1649,7 @@ fn parse_insert_with_on_duplicate_update() {
16371649
fetch: None,
16381650
locks: vec![],
16391651
for_clause: None,
1652+
settings: None,
16401653
})),
16411654
source
16421655
);
@@ -2280,6 +2293,7 @@ fn parse_substring_in_select() {
22802293
fetch: None,
22812294
locks: vec![],
22822295
for_clause: None,
2296+
settings: None,
22832297
}),
22842298
query
22852299
);
@@ -2586,6 +2600,7 @@ fn parse_hex_string_introducer() {
25862600
fetch: None,
25872601
locks: vec![],
25882602
for_clause: None,
2603+
settings: None,
25892604
}))
25902605
)
25912606
}

0 commit comments

Comments
 (0)