Skip to content

Commit 0884dd9

Browse files
authored
Support PREWHERE condition for ClickHouse dialect (#1328)
1 parent 700bd03 commit 0884dd9

9 files changed

+94
-0
lines changed

src/ast/query.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ pub struct Select {
247247
pub from: Vec<TableWithJoins>,
248248
/// LATERAL VIEWs
249249
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>,
250255
/// WHERE
251256
pub selection: Option<Expr>,
252257
/// GROUP BY
@@ -302,6 +307,9 @@ impl fmt::Display for Select {
302307
write!(f, "{lv}")?;
303308
}
304309
}
310+
if let Some(ref prewhere) = self.prewhere {
311+
write!(f, " PREWHERE {prewhere}")?;
312+
}
305313
if let Some(ref selection) = self.selection {
306314
write!(f, " WHERE {selection}")?;
307315
}

src/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ define_keywords!(
558558
PRECISION,
559559
PREPARE,
560560
PRESERVE,
561+
PREWHERE,
561562
PRIMARY,
562563
PRIOR,
563564
PRIVILEGES,
@@ -851,6 +852,8 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
851852
Keyword::FOR,
852853
// for MYSQL PARTITION SELECTION
853854
Keyword::PARTITION,
855+
// for Clickhouse PREWHERE
856+
Keyword::PREWHERE,
854857
// for ClickHouse SELECT * FROM t SETTINGS ...
855858
Keyword::SETTINGS,
856859
// for Snowflake START WITH .. CONNECT BY

src/parser/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8329,6 +8329,14 @@ impl<'a> Parser<'a> {
83298329
}
83308330
}
83318331

8332+
let prewhere = if dialect_of!(self is ClickHouseDialect|GenericDialect)
8333+
&& self.parse_keyword(Keyword::PREWHERE)
8334+
{
8335+
Some(self.parse_expr()?)
8336+
} else {
8337+
None
8338+
};
8339+
83328340
let selection = if self.parse_keyword(Keyword::WHERE) {
83338341
Some(self.parse_expr()?)
83348342
} else {
@@ -8440,6 +8448,7 @@ impl<'a> Parser<'a> {
84408448
into,
84418449
from,
84428450
lateral_views,
8451+
prewhere,
84438452
selection,
84448453
group_by,
84458454
cluster_by,

tests/sqlparser_clickhouse.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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"))),
@@ -717,6 +718,56 @@ fn parse_group_by_with_modifier() {
717718
}
718719
}
719720

721+
#[test]
722+
fn test_prewhere() {
723+
match clickhouse_and_generic().verified_stmt("SELECT * FROM t PREWHERE x = 1 WHERE y = 2") {
724+
Statement::Query(query) => {
725+
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
726+
assert_eq!(
727+
prewhere,
728+
Some(&BinaryOp {
729+
left: Box::new(Identifier(Ident::new("x"))),
730+
op: BinaryOperator::Eq,
731+
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
732+
})
733+
);
734+
let selection = query.as_ref().body.as_select().unwrap().selection.as_ref();
735+
assert_eq!(
736+
selection,
737+
Some(&BinaryOp {
738+
left: Box::new(Identifier(Ident::new("y"))),
739+
op: BinaryOperator::Eq,
740+
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
741+
})
742+
);
743+
}
744+
_ => unreachable!(),
745+
}
746+
747+
match clickhouse_and_generic().verified_stmt("SELECT * FROM t PREWHERE x = 1 AND y = 2") {
748+
Statement::Query(query) => {
749+
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
750+
assert_eq!(
751+
prewhere,
752+
Some(&BinaryOp {
753+
left: Box::new(BinaryOp {
754+
left: Box::new(Identifier(Ident::new("x"))),
755+
op: BinaryOperator::Eq,
756+
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
757+
}),
758+
op: BinaryOperator::And,
759+
right: Box::new(BinaryOp {
760+
left: Box::new(Identifier(Ident::new("y"))),
761+
op: BinaryOperator::Eq,
762+
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
763+
}),
764+
})
765+
);
766+
}
767+
_ => unreachable!(),
768+
}
769+
}
770+
720771
fn clickhouse() -> TestedDialects {
721772
TestedDialects {
722773
dialects: vec![Box::new(ClickHouseDialect {})],

tests/sqlparser_common.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ fn parse_update_set_from() {
391391
joins: vec![],
392392
}],
393393
lateral_views: vec![],
394+
prewhere: None,
394395
selection: None,
395396
group_by: GroupByExpr::Expressions(
396397
vec![Expr::Identifier(Ident::new("id"))],
@@ -4551,6 +4552,7 @@ fn test_parse_named_window() {
45514552
joins: vec![],
45524553
}],
45534554
lateral_views: vec![],
4555+
prewhere: None,
45544556
selection: None,
45554557
group_by: GroupByExpr::Expressions(vec![], vec![]),
45564558
cluster_by: vec![],
@@ -4932,6 +4934,7 @@ fn parse_interval_and_or_xor() {
49324934
joins: vec![],
49334935
}],
49344936
lateral_views: vec![],
4937+
prewhere: None,
49354938
selection: Some(Expr::BinaryOp {
49364939
left: Box::new(Expr::BinaryOp {
49374940
left: Box::new(Expr::Identifier(Ident {
@@ -6915,6 +6918,7 @@ fn lateral_function() {
69156918
}],
69166919
}],
69176920
lateral_views: vec![],
6921+
prewhere: None,
69186922
selection: None,
69196923
group_by: GroupByExpr::Expressions(vec![], vec![]),
69206924
cluster_by: vec![],
@@ -7634,6 +7638,7 @@ fn parse_merge() {
76347638
joins: vec![],
76357639
}],
76367640
lateral_views: vec![],
7641+
prewhere: None,
76377642
selection: None,
76387643
group_by: GroupByExpr::Expressions(vec![], vec![]),
76397644
cluster_by: vec![],
@@ -9141,6 +9146,7 @@ fn parse_unload() {
91419146
joins: vec![],
91429147
}],
91439148
lateral_views: vec![],
9149+
prewhere: None,
91449150
selection: None,
91459151
group_by: GroupByExpr::Expressions(vec![], vec![]),
91469152
cluster_by: vec![],
@@ -9285,6 +9291,7 @@ fn parse_connect_by() {
92859291
}],
92869292
into: None,
92879293
lateral_views: vec![],
9294+
prewhere: None,
92889295
selection: None,
92899296
group_by: GroupByExpr::Expressions(vec![], vec![]),
92909297
cluster_by: vec![],
@@ -9369,6 +9376,7 @@ fn parse_connect_by() {
93699376
}],
93709377
into: None,
93719378
lateral_views: vec![],
9379+
prewhere: None,
93729380
selection: Some(Expr::BinaryOp {
93739381
left: Box::new(Expr::Identifier(Ident::new("employee_id"))),
93749382
op: BinaryOperator::NotEq,

tests/sqlparser_duckdb.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ fn test_select_union_by_name() {
170170
joins: vec![],
171171
}],
172172
lateral_views: vec![],
173+
prewhere: None,
173174
selection: None,
174175
group_by: GroupByExpr::Expressions(vec![], vec![]),
175176
cluster_by: vec![],
@@ -208,6 +209,7 @@ fn test_select_union_by_name() {
208209
joins: vec![],
209210
}],
210211
lateral_views: vec![],
212+
prewhere: None,
211213
selection: None,
212214
group_by: GroupByExpr::Expressions(vec![], vec![]),
213215
cluster_by: vec![],

tests/sqlparser_mssql.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ fn parse_create_procedure() {
111111
into: None,
112112
from: vec![],
113113
lateral_views: vec![],
114+
prewhere: None,
114115
selection: None,
115116
group_by: GroupByExpr::Expressions(vec![], vec![]),
116117
cluster_by: vec![],
@@ -528,6 +529,7 @@ fn parse_substring_in_select() {
528529
joins: vec![]
529530
}],
530531
lateral_views: vec![],
532+
prewhere: None,
531533
selection: None,
532534
group_by: GroupByExpr::Expressions(vec![], vec![]),
533535
cluster_by: vec![],

tests/sqlparser_mysql.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,7 @@ fn parse_escaped_quote_identifiers_with_escape() {
906906
into: None,
907907
from: vec![],
908908
lateral_views: vec![],
909+
prewhere: None,
909910
selection: None,
910911
group_by: GroupByExpr::Expressions(vec![], vec![]),
911912
cluster_by: vec![],
@@ -954,6 +955,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
954955
into: None,
955956
from: vec![],
956957
lateral_views: vec![],
958+
prewhere: None,
957959
selection: None,
958960
group_by: GroupByExpr::Expressions(vec![], vec![]),
959961
cluster_by: vec![],
@@ -999,6 +1001,7 @@ fn parse_escaped_backticks_with_escape() {
9991001
into: None,
10001002
from: vec![],
10011003
lateral_views: vec![],
1004+
prewhere: None,
10021005
selection: None,
10031006
group_by: GroupByExpr::Expressions(vec![], vec![]),
10041007
cluster_by: vec![],
@@ -1044,6 +1047,7 @@ fn parse_escaped_backticks_with_no_escape() {
10441047
into: None,
10451048
from: vec![],
10461049
lateral_views: vec![],
1050+
prewhere: None,
10471051
selection: None,
10481052
group_by: GroupByExpr::Expressions(vec![], vec![]),
10491053
cluster_by: vec![],
@@ -1715,6 +1719,7 @@ fn parse_select_with_numeric_prefix_column_name() {
17151719
joins: vec![]
17161720
}],
17171721
lateral_views: vec![],
1722+
prewhere: None,
17181723
selection: None,
17191724
group_by: GroupByExpr::Expressions(vec![], vec![]),
17201725
cluster_by: vec![],
@@ -1768,6 +1773,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
17681773
joins: vec![]
17691774
}],
17701775
lateral_views: vec![],
1776+
prewhere: None,
17711777
selection: None,
17721778
group_by: GroupByExpr::Expressions(vec![], vec![]),
17731779
cluster_by: vec![],
@@ -2267,6 +2273,7 @@ fn parse_substring_in_select() {
22672273
joins: vec![]
22682274
}],
22692275
lateral_views: vec![],
2276+
prewhere: None,
22702277
selection: None,
22712278
group_by: GroupByExpr::Expressions(vec![], vec![]),
22722279
cluster_by: vec![],
@@ -2572,6 +2579,7 @@ fn parse_hex_string_introducer() {
25722579
})],
25732580
from: vec![],
25742581
lateral_views: vec![],
2582+
prewhere: None,
25752583
selection: None,
25762584
group_by: GroupByExpr::Expressions(vec![], vec![]),
25772585
cluster_by: vec![],

tests/sqlparser_postgres.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,7 @@ fn parse_copy_to() {
10741074
into: None,
10751075
from: vec![],
10761076
lateral_views: vec![],
1077+
prewhere: None,
10771078
selection: None,
10781079
group_by: GroupByExpr::Expressions(vec![], vec![]),
10791080
having: None,
@@ -2383,6 +2384,7 @@ fn parse_array_subquery_expr() {
23832384
into: None,
23842385
from: vec![],
23852386
lateral_views: vec![],
2387+
prewhere: None,
23862388
selection: None,
23872389
group_by: GroupByExpr::Expressions(vec![], vec![]),
23882390
cluster_by: vec![],
@@ -2402,6 +2404,7 @@ fn parse_array_subquery_expr() {
24022404
into: None,
24032405
from: vec![],
24042406
lateral_views: vec![],
2407+
prewhere: None,
24052408
selection: None,
24062409
group_by: GroupByExpr::Expressions(vec![], vec![]),
24072410
cluster_by: vec![],

0 commit comments

Comments
 (0)