Skip to content

Commit 4b2ad47

Browse files
committed
Add the support of PREWHERE condition for ClickHouse dialect
For ClickHouse PREWHERE clause, please refer to: https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere
1 parent 44d7a20 commit 4b2ad47

File tree

9 files changed

+94
-0
lines changed

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
@@ -240,6 +240,11 @@ pub struct Select {
240240
pub from: Vec<TableWithJoins>,
241241
/// LATERAL VIEWs
242242
pub lateral_views: Vec<LateralView>,
243+
/// ClickHouse syntax: `PREWHERE a = 1 WHERE b = 2`,
244+
/// and it can be used together with WHERE selection.
245+
///
246+
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere)
247+
pub prewhere: Option<Expr>,
243248
/// WHERE
244249
pub selection: Option<Expr>,
245250
/// GROUP BY
@@ -295,6 +300,9 @@ impl fmt::Display for Select {
295300
write!(f, "{lv}")?;
296301
}
297302
}
303+
if let Some(ref prewhere) = self.prewhere {
304+
write!(f, " PREWHERE {prewhere}")?;
305+
}
298306
if let Some(ref selection) = self.selection {
299307
write!(f, " WHERE {selection}")?;
300308
}

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,
@@ -850,6 +851,8 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
850851
Keyword::FOR,
851852
// for MYSQL PARTITION SELECTION
852853
Keyword::PARTITION,
854+
// for Clickhouse PREWHERE
855+
Keyword::PREWHERE,
853856
// for Snowflake START WITH .. CONNECT BY
854857
Keyword::START,
855858
Keyword::CONNECT,

src/parser/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8312,6 +8312,14 @@ impl<'a> Parser<'a> {
83128312
}
83138313
}
83148314

8315+
let prewhere = if dialect_of!(self is ClickHouseDialect|GenericDialect)
8316+
&& self.parse_keyword(Keyword::PREWHERE)
8317+
{
8318+
Some(self.parse_expr()?)
8319+
} else {
8320+
None
8321+
};
8322+
83158323
let selection = if self.parse_keyword(Keyword::WHERE) {
83168324
Some(self.parse_expr()?)
83178325
} else {
@@ -8423,6 +8431,7 @@ impl<'a> Parser<'a> {
84238431
into,
84248432
from,
84258433
lateral_views,
8434+
prewhere,
84268435
selection,
84278436
group_by,
84288437
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"))),
@@ -681,6 +682,56 @@ fn parse_group_by_with_modifier() {
681682
}
682683
}
683684

685+
#[test]
686+
fn test_prewhere() {
687+
match clickhouse().verified_stmt("SELECT * FROM t PREWHERE x = 1 WHERE y = 2") {
688+
Statement::Query(query) => {
689+
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
690+
assert_eq!(
691+
prewhere,
692+
Some(&BinaryOp {
693+
left: Box::new(Identifier(Ident::new("x"))),
694+
op: BinaryOperator::Eq,
695+
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
696+
})
697+
);
698+
let selection = query.as_ref().body.as_select().unwrap().selection.as_ref();
699+
assert_eq!(
700+
selection,
701+
Some(&BinaryOp {
702+
left: Box::new(Identifier(Ident::new("y"))),
703+
op: BinaryOperator::Eq,
704+
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
705+
})
706+
);
707+
}
708+
_ => unreachable!(),
709+
}
710+
711+
match clickhouse().verified_stmt("SELECT * FROM t PREWHERE x = 1 AND y = 2") {
712+
Statement::Query(query) => {
713+
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
714+
assert_eq!(
715+
prewhere,
716+
Some(&BinaryOp {
717+
left: Box::new(BinaryOp {
718+
left: Box::new(Identifier(Ident::new("x"))),
719+
op: BinaryOperator::Eq,
720+
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
721+
}),
722+
op: BinaryOperator::And,
723+
right: Box::new(BinaryOp {
724+
left: Box::new(Identifier(Ident::new("y"))),
725+
op: BinaryOperator::Eq,
726+
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
727+
}),
728+
})
729+
);
730+
}
731+
_ => unreachable!(),
732+
}
733+
}
734+
684735
fn clickhouse() -> TestedDialects {
685736
TestedDialects {
686737
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"))],
@@ -4548,6 +4549,7 @@ fn test_parse_named_window() {
45484549
joins: vec![],
45494550
}],
45504551
lateral_views: vec![],
4552+
prewhere: None,
45514553
selection: None,
45524554
group_by: GroupByExpr::Expressions(vec![], vec![]),
45534555
cluster_by: vec![],
@@ -4929,6 +4931,7 @@ fn parse_interval_and_or_xor() {
49294931
joins: vec![],
49304932
}],
49314933
lateral_views: vec![],
4934+
prewhere: None,
49324935
selection: Some(Expr::BinaryOp {
49334936
left: Box::new(Expr::BinaryOp {
49344937
left: Box::new(Expr::Identifier(Ident {
@@ -6911,6 +6914,7 @@ fn lateral_function() {
69116914
}],
69126915
}],
69136916
lateral_views: vec![],
6917+
prewhere: None,
69146918
selection: None,
69156919
group_by: GroupByExpr::Expressions(vec![], vec![]),
69166920
cluster_by: vec![],
@@ -7630,6 +7634,7 @@ fn parse_merge() {
76307634
joins: vec![],
76317635
}],
76327636
lateral_views: vec![],
7637+
prewhere: None,
76337638
selection: None,
76347639
group_by: GroupByExpr::Expressions(vec![], vec![]),
76357640
cluster_by: vec![],
@@ -9136,6 +9141,7 @@ fn parse_unload() {
91369141
joins: vec![],
91379142
}],
91389143
lateral_views: vec![],
9144+
prewhere: None,
91399145
selection: None,
91409146
group_by: GroupByExpr::Expressions(vec![], vec![]),
91419147
cluster_by: vec![],
@@ -9279,6 +9285,7 @@ fn parse_connect_by() {
92799285
}],
92809286
into: None,
92819287
lateral_views: vec![],
9288+
prewhere: None,
92829289
selection: None,
92839290
group_by: GroupByExpr::Expressions(vec![], vec![]),
92849291
cluster_by: vec![],
@@ -9363,6 +9370,7 @@ fn parse_connect_by() {
93639370
}],
93649371
into: None,
93659372
lateral_views: vec![],
9373+
prewhere: None,
93669374
selection: Some(Expr::BinaryOp {
93679375
left: Box::new(Expr::Identifier(Ident::new("employee_id"))),
93689376
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
@@ -110,6 +110,7 @@ fn parse_create_procedure() {
110110
into: None,
111111
from: vec![],
112112
lateral_views: vec![],
113+
prewhere: None,
113114
selection: None,
114115
group_by: GroupByExpr::Expressions(vec![], vec![]),
115116
cluster_by: vec![],
@@ -527,6 +528,7 @@ fn parse_substring_in_select() {
527528
joins: vec![]
528529
}],
529530
lateral_views: vec![],
531+
prewhere: None,
530532
selection: None,
531533
group_by: GroupByExpr::Expressions(vec![], vec![]),
532534
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![],
@@ -953,6 +954,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
953954
into: None,
954955
from: vec![],
955956
lateral_views: vec![],
957+
prewhere: None,
956958
selection: None,
957959
group_by: GroupByExpr::Expressions(vec![], vec![]),
958960
cluster_by: vec![],
@@ -997,6 +999,7 @@ fn parse_escaped_backticks_with_escape() {
997999
into: None,
9981000
from: vec![],
9991001
lateral_views: vec![],
1002+
prewhere: None,
10001003
selection: None,
10011004
group_by: GroupByExpr::Expressions(vec![], vec![]),
10021005
cluster_by: vec![],
@@ -1041,6 +1044,7 @@ fn parse_escaped_backticks_with_no_escape() {
10411044
into: None,
10421045
from: vec![],
10431046
lateral_views: vec![],
1047+
prewhere: None,
10441048
selection: None,
10451049
group_by: GroupByExpr::Expressions(vec![], vec![]),
10461050
cluster_by: vec![],
@@ -1702,6 +1706,7 @@ fn parse_select_with_numeric_prefix_column_name() {
17021706
joins: vec![]
17031707
}],
17041708
lateral_views: vec![],
1709+
prewhere: None,
17051710
selection: None,
17061711
group_by: GroupByExpr::Expressions(vec![], vec![]),
17071712
cluster_by: vec![],
@@ -1755,6 +1760,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
17551760
joins: vec![]
17561761
}],
17571762
lateral_views: vec![],
1763+
prewhere: None,
17581764
selection: None,
17591765
group_by: GroupByExpr::Expressions(vec![], vec![]),
17601766
cluster_by: vec![],
@@ -2254,6 +2260,7 @@ fn parse_substring_in_select() {
22542260
joins: vec![]
22552261
}],
22562262
lateral_views: vec![],
2263+
prewhere: None,
22572264
selection: None,
22582265
group_by: GroupByExpr::Expressions(vec![], vec![]),
22592266
cluster_by: vec![],
@@ -2558,6 +2565,7 @@ fn parse_hex_string_introducer() {
25582565
})],
25592566
from: vec![],
25602567
lateral_views: vec![],
2568+
prewhere: None,
25612569
selection: None,
25622570
group_by: GroupByExpr::Expressions(vec![], vec![]),
25632571
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,
@@ -2382,6 +2383,7 @@ fn parse_array_subquery_expr() {
23822383
into: None,
23832384
from: vec![],
23842385
lateral_views: vec![],
2386+
prewhere: None,
23852387
selection: None,
23862388
group_by: GroupByExpr::Expressions(vec![], vec![]),
23872389
cluster_by: vec![],
@@ -2401,6 +2403,7 @@ fn parse_array_subquery_expr() {
24012403
into: None,
24022404
from: vec![],
24032405
lateral_views: vec![],
2406+
prewhere: None,
24042407
selection: None,
24052408
group_by: GroupByExpr::Expressions(vec![], vec![]),
24062409
cluster_by: vec![],

0 commit comments

Comments
 (0)