Skip to content

Commit 4b8c6fe

Browse files
committed
Merge branch 'main' of https://github.com/sqlparser-rs/sqlparser-rs into add-order-by-expr-with-fill
2 parents ec263d2 + 17e5c0c commit 4b8c6fe

File tree

11 files changed

+249
-18
lines changed

11 files changed

+249
-18
lines changed

derive/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl Visit for TableFactor {
9797
match self {
9898
Self::Table { name, alias } => {
9999
visitor.pre_visit_relation(name)?;
100-
alias.visit(name)?;
100+
name.visit(visitor)?;
101101
visitor.post_visit_relation(name)?;
102102
alias.visit(visitor)?;
103103
}

src/ast/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ pub use self::query::{
4949
MatchRecognizeSymbol, Measure, NamedWindowDefinition, NamedWindowExpr, NonBlock, Offset,
5050
OffsetRows, OrderByExpr, PivotValueSource, Query, RenameSelectItem, RepetitionQuantifier,
5151
ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select, SelectInto, SelectItem, SetExpr,
52-
SetOperator, SetQuantifier, SymbolDefinition, Table, TableAlias, TableFactor, TableVersion,
53-
TableWithJoins, Top, TopQuantity, ValueTableMode, Values, WildcardAdditionalOptions, With,
54-
WithFill,
52+
SetOperator, SetQuantifier, Setting, SymbolDefinition, Table, TableAlias, TableFactor,
53+
TableVersion, TableWithJoins, Top, TopQuantity, ValueTableMode, Values,
54+
WildcardAdditionalOptions, With, WithFill,
5555
};
5656
pub use self::value::{
5757
escape_double_quote_string, escape_quoted_string, DateTimeField, DollarQuotedString,

src/ast/query.rs

Lines changed: 29 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
}
@@ -240,6 +247,11 @@ pub struct Select {
240247
pub from: Vec<TableWithJoins>,
241248
/// LATERAL VIEWs
242249
pub lateral_views: Vec<LateralView>,
250+
/// ClickHouse syntax: `PREWHERE a = 1 WHERE b = 2`,
251+
/// and it can be used together with WHERE selection.
252+
///
253+
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere)
254+
pub prewhere: Option<Expr>,
243255
/// WHERE
244256
pub selection: Option<Expr>,
245257
/// GROUP BY
@@ -295,6 +307,9 @@ impl fmt::Display for Select {
295307
write!(f, "{lv}")?;
296308
}
297309
}
310+
if let Some(ref prewhere) = self.prewhere {
311+
write!(f, " PREWHERE {prewhere}")?;
312+
}
298313
if let Some(ref selection) = self.selection {
299314
write!(f, " WHERE {selection}")?;
300315
}
@@ -828,6 +843,20 @@ impl fmt::Display for ConnectBy {
828843
}
829844
}
830845

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+
831860
/// An expression optionally followed by an alias.
832861
///
833862
/// Example:

src/keywords.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ define_keywords!(
560560
PRECISION,
561561
PREPARE,
562562
PRESERVE,
563+
PREWHERE,
563564
PRIMARY,
564565
PRIOR,
565566
PRIVILEGES,
@@ -652,6 +653,7 @@ define_keywords!(
652653
SESSION_USER,
653654
SET,
654655
SETS,
656+
SETTINGS,
655657
SHARE,
656658
SHOW,
657659
SIMILAR,
@@ -853,6 +855,10 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
853855
Keyword::FOR,
854856
// for MYSQL PARTITION SELECTION
855857
Keyword::PARTITION,
858+
// for Clickhouse PREWHERE
859+
Keyword::PREWHERE,
860+
// for ClickHouse SELECT * FROM t SETTINGS ...
861+
Keyword::SETTINGS,
856862
// for Snowflake START WITH .. CONNECT BY
857863
Keyword::START,
858864
Keyword::CONNECT,

src/parser/mod.rs

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ pub enum ParserError {
4646
RecursionLimitExceeded,
4747
}
4848

49+
// avoid clippy type_complexity warnings
50+
type ParsedAction = (Keyword, Option<Vec<Ident>>);
51+
4952
// Use `Parser::expected` instead, if possible
5053
macro_rules! parser_err {
5154
($MSG:expr, $loc:expr) => {
@@ -3334,6 +3337,29 @@ impl<'a> Parser<'a> {
33343337
ret
33353338
}
33363339

3340+
pub fn parse_actions_list(&mut self) -> Result<Vec<ParsedAction>, ParserError> {
3341+
let mut values = vec![];
3342+
loop {
3343+
values.push(self.parse_grant_permission()?);
3344+
if !self.consume_token(&Token::Comma) {
3345+
break;
3346+
} else if self.options.trailing_commas {
3347+
match self.peek_token().token {
3348+
Token::Word(kw) if kw.keyword == Keyword::ON => {
3349+
break;
3350+
}
3351+
Token::RParen
3352+
| Token::SemiColon
3353+
| Token::EOF
3354+
| Token::RBracket
3355+
| Token::RBrace => break,
3356+
_ => continue,
3357+
}
3358+
}
3359+
}
3360+
Ok(values)
3361+
}
3362+
33373363
/// Parse a comma-separated list of 1+ items accepted by `F`
33383364
pub fn parse_comma_separated<T, F>(&mut self, mut f: F) -> Result<Vec<T>, ParserError>
33393365
where
@@ -3347,9 +3373,7 @@ impl<'a> Parser<'a> {
33473373
} else if self.options.trailing_commas {
33483374
match self.peek_token().token {
33493375
Token::Word(kw)
3350-
if keywords::RESERVED_FOR_COLUMN_ALIAS
3351-
.iter()
3352-
.any(|d| kw.keyword == *d) =>
3376+
if keywords::RESERVED_FOR_COLUMN_ALIAS.contains(&kw.keyword) =>
33533377
{
33543378
break;
33553379
}
@@ -7871,6 +7895,7 @@ impl<'a> Parser<'a> {
78717895
fetch: None,
78727896
locks: vec![],
78737897
for_clause: None,
7898+
settings: None,
78747899
})
78757900
} else if self.parse_keyword(Keyword::UPDATE) {
78767901
Ok(Query {
@@ -7883,6 +7908,7 @@ impl<'a> Parser<'a> {
78837908
fetch: None,
78847909
locks: vec![],
78857910
for_clause: None,
7911+
settings: None,
78867912
})
78877913
} else {
78887914
let body = self.parse_boxed_query_body(0)?;
@@ -7930,6 +7956,20 @@ impl<'a> Parser<'a> {
79307956
vec![]
79317957
};
79327958

7959+
let settings = if dialect_of!(self is ClickHouseDialect|GenericDialect)
7960+
&& self.parse_keyword(Keyword::SETTINGS)
7961+
{
7962+
let key_values = self.parse_comma_separated(|p| {
7963+
let key = p.parse_identifier(false)?;
7964+
p.expect_token(&Token::Eq)?;
7965+
let value = p.parse_value()?;
7966+
Ok(Setting { key, value })
7967+
})?;
7968+
Some(key_values)
7969+
} else {
7970+
None
7971+
};
7972+
79337973
let fetch = if self.parse_keyword(Keyword::FETCH) {
79347974
Some(self.parse_fetch()?)
79357975
} else {
@@ -7957,6 +7997,7 @@ impl<'a> Parser<'a> {
79577997
fetch,
79587998
locks,
79597999
for_clause,
8000+
settings,
79608001
})
79618002
}
79628003
}
@@ -8314,6 +8355,14 @@ impl<'a> Parser<'a> {
83148355
}
83158356
}
83168357

8358+
let prewhere = if dialect_of!(self is ClickHouseDialect|GenericDialect)
8359+
&& self.parse_keyword(Keyword::PREWHERE)
8360+
{
8361+
Some(self.parse_expr()?)
8362+
} else {
8363+
None
8364+
};
8365+
83178366
let selection = if self.parse_keyword(Keyword::WHERE) {
83188367
Some(self.parse_expr()?)
83198368
} else {
@@ -8425,6 +8474,7 @@ impl<'a> Parser<'a> {
84258474
into,
84268475
from,
84278476
lateral_views,
8477+
prewhere,
84288478
selection,
84298479
group_by,
84308480
cluster_by,
@@ -9093,6 +9143,7 @@ impl<'a> Parser<'a> {
90939143
fetch: None,
90949144
locks: vec![],
90959145
for_clause: None,
9146+
settings: None,
90969147
}),
90979148
alias,
90989149
})
@@ -9655,11 +9706,8 @@ impl<'a> Parser<'a> {
96559706
with_privileges_keyword: self.parse_keyword(Keyword::PRIVILEGES),
96569707
}
96579708
} else {
9658-
let old_value = self.options.trailing_commas;
9659-
self.options.trailing_commas = false;
9660-
96619709
let (actions, err): (Vec<_>, Vec<_>) = self
9662-
.parse_comma_separated(Parser::parse_grant_permission)?
9710+
.parse_actions_list()?
96639711
.into_iter()
96649712
.map(|(kw, columns)| match kw {
96659713
Keyword::DELETE => Ok(Action::Delete),
@@ -9681,8 +9729,6 @@ impl<'a> Parser<'a> {
96819729
})
96829730
.partition(Result::is_ok);
96839731

9684-
self.options.trailing_commas = old_value;
9685-
96869732
if !err.is_empty() {
96879733
let errors: Vec<Keyword> = err.into_iter().filter_map(|x| x.err()).collect();
96889734
return Err(ParserError::ParserError(format!(
@@ -9728,7 +9774,7 @@ impl<'a> Parser<'a> {
97289774
Ok((privileges, objects))
97299775
}
97309776

9731-
pub fn parse_grant_permission(&mut self) -> Result<(Keyword, Option<Vec<Ident>>), ParserError> {
9777+
pub fn parse_grant_permission(&mut self) -> Result<ParsedAction, ParserError> {
97329778
if let Some(kw) = self.parse_one_of_keywords(&[
97339779
Keyword::CONNECT,
97349780
Keyword::CREATE,

tests/sqlparser_clickhouse.rs

Lines changed: 88 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

@@ -63,6 +63,7 @@ fn parse_map_access_expr() {
6363
joins: vec![],
6464
}],
6565
lateral_views: vec![],
66+
prewhere: None,
6667
selection: Some(BinaryOp {
6768
left: Box::new(BinaryOp {
6869
left: Box::new(Identifier(Ident::new("id"))),
@@ -549,6 +550,42 @@ fn parse_limit_by() {
549550
);
550551
}
551552

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+
}
552589
#[test]
553590
fn parse_select_star_except() {
554591
clickhouse().verified_stmt("SELECT * EXCEPT (prev_status) FROM anomalies");
@@ -857,6 +894,56 @@ fn parse_interpolate_with_empty_body() {
857894
);
858895
}
859896

897+
#[test]
898+
fn test_prewhere() {
899+
match clickhouse_and_generic().verified_stmt("SELECT * FROM t PREWHERE x = 1 WHERE y = 2") {
900+
Statement::Query(query) => {
901+
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
902+
assert_eq!(
903+
prewhere,
904+
Some(&BinaryOp {
905+
left: Box::new(Identifier(Ident::new("x"))),
906+
op: BinaryOperator::Eq,
907+
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
908+
})
909+
);
910+
let selection = query.as_ref().body.as_select().unwrap().selection.as_ref();
911+
assert_eq!(
912+
selection,
913+
Some(&BinaryOp {
914+
left: Box::new(Identifier(Ident::new("y"))),
915+
op: BinaryOperator::Eq,
916+
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
917+
})
918+
);
919+
}
920+
_ => unreachable!(),
921+
}
922+
923+
match clickhouse_and_generic().verified_stmt("SELECT * FROM t PREWHERE x = 1 AND y = 2") {
924+
Statement::Query(query) => {
925+
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
926+
assert_eq!(
927+
prewhere,
928+
Some(&BinaryOp {
929+
left: Box::new(BinaryOp {
930+
left: Box::new(Identifier(Ident::new("x"))),
931+
op: BinaryOperator::Eq,
932+
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
933+
}),
934+
op: BinaryOperator::And,
935+
right: Box::new(BinaryOp {
936+
left: Box::new(Identifier(Ident::new("y"))),
937+
op: BinaryOperator::Eq,
938+
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
939+
}),
940+
})
941+
);
942+
}
943+
_ => unreachable!(),
944+
}
945+
}
946+
860947
fn clickhouse() -> TestedDialects {
861948
TestedDialects {
862949
dialects: vec![Box::new(ClickHouseDialect {})],

0 commit comments

Comments
 (0)