Support PREWHERE condition for ClickHouse dialect (#1328)

This commit is contained in:
hulk 2024-07-07 20:03:23 +08:00 committed by GitHub
parent 700bd03d6f
commit 0884dd920d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 94 additions and 0 deletions

View file

@ -247,6 +247,11 @@ pub struct Select {
pub from: Vec<TableWithJoins>,
/// LATERAL VIEWs
pub lateral_views: Vec<LateralView>,
/// ClickHouse syntax: `PREWHERE a = 1 WHERE b = 2`,
/// and it can be used together with WHERE selection.
///
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere)
pub prewhere: Option<Expr>,
/// WHERE
pub selection: Option<Expr>,
/// GROUP BY
@ -302,6 +307,9 @@ impl fmt::Display for Select {
write!(f, "{lv}")?;
}
}
if let Some(ref prewhere) = self.prewhere {
write!(f, " PREWHERE {prewhere}")?;
}
if let Some(ref selection) = self.selection {
write!(f, " WHERE {selection}")?;
}

View file

@ -558,6 +558,7 @@ define_keywords!(
PRECISION,
PREPARE,
PRESERVE,
PREWHERE,
PRIMARY,
PRIOR,
PRIVILEGES,
@ -851,6 +852,8 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
Keyword::FOR,
// for MYSQL PARTITION SELECTION
Keyword::PARTITION,
// for Clickhouse PREWHERE
Keyword::PREWHERE,
// for ClickHouse SELECT * FROM t SETTINGS ...
Keyword::SETTINGS,
// for Snowflake START WITH .. CONNECT BY

View file

@ -8329,6 +8329,14 @@ impl<'a> Parser<'a> {
}
}
let prewhere = if dialect_of!(self is ClickHouseDialect|GenericDialect)
&& self.parse_keyword(Keyword::PREWHERE)
{
Some(self.parse_expr()?)
} else {
None
};
let selection = if self.parse_keyword(Keyword::WHERE) {
Some(self.parse_expr()?)
} else {
@ -8440,6 +8448,7 @@ impl<'a> Parser<'a> {
into,
from,
lateral_views,
prewhere,
selection,
group_by,
cluster_by,

View file

@ -63,6 +63,7 @@ fn parse_map_access_expr() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: Some(BinaryOp {
left: Box::new(BinaryOp {
left: Box::new(Identifier(Ident::new("id"))),
@ -717,6 +718,56 @@ fn parse_group_by_with_modifier() {
}
}
#[test]
fn test_prewhere() {
match clickhouse_and_generic().verified_stmt("SELECT * FROM t PREWHERE x = 1 WHERE y = 2") {
Statement::Query(query) => {
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
assert_eq!(
prewhere,
Some(&BinaryOp {
left: Box::new(Identifier(Ident::new("x"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
})
);
let selection = query.as_ref().body.as_select().unwrap().selection.as_ref();
assert_eq!(
selection,
Some(&BinaryOp {
left: Box::new(Identifier(Ident::new("y"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
})
);
}
_ => unreachable!(),
}
match clickhouse_and_generic().verified_stmt("SELECT * FROM t PREWHERE x = 1 AND y = 2") {
Statement::Query(query) => {
let prewhere = query.body.as_select().unwrap().prewhere.as_ref();
assert_eq!(
prewhere,
Some(&BinaryOp {
left: Box::new(BinaryOp {
left: Box::new(Identifier(Ident::new("x"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
}),
op: BinaryOperator::And,
right: Box::new(BinaryOp {
left: Box::new(Identifier(Ident::new("y"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(Value::Number("2".parse().unwrap(), false))),
}),
})
);
}
_ => unreachable!(),
}
}
fn clickhouse() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(ClickHouseDialect {})],

View file

@ -391,6 +391,7 @@ fn parse_update_set_from() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(
vec![Expr::Identifier(Ident::new("id"))],
@ -4551,6 +4552,7 @@ fn test_parse_named_window() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -4932,6 +4934,7 @@ fn parse_interval_and_or_xor() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: Some(Expr::BinaryOp {
left: Box::new(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident {
@ -6915,6 +6918,7 @@ fn lateral_function() {
}],
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -7634,6 +7638,7 @@ fn parse_merge() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -9141,6 +9146,7 @@ fn parse_unload() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -9285,6 +9291,7 @@ fn parse_connect_by() {
}],
into: None,
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -9369,6 +9376,7 @@ fn parse_connect_by() {
}],
into: None,
lateral_views: vec![],
prewhere: None,
selection: Some(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("employee_id"))),
op: BinaryOperator::NotEq,

View file

@ -170,6 +170,7 @@ fn test_select_union_by_name() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -208,6 +209,7 @@ fn test_select_union_by_name() {
joins: vec![],
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],

View file

@ -111,6 +111,7 @@ fn parse_create_procedure() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -528,6 +529,7 @@ fn parse_substring_in_select() {
joins: vec![]
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],

View file

@ -906,6 +906,7 @@ fn parse_escaped_quote_identifiers_with_escape() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -954,6 +955,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -999,6 +1001,7 @@ fn parse_escaped_backticks_with_escape() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -1044,6 +1047,7 @@ fn parse_escaped_backticks_with_no_escape() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -1715,6 +1719,7 @@ fn parse_select_with_numeric_prefix_column_name() {
joins: vec![]
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -1768,6 +1773,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
joins: vec![]
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -2267,6 +2273,7 @@ fn parse_substring_in_select() {
joins: vec![]
}],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -2572,6 +2579,7 @@ fn parse_hex_string_introducer() {
})],
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],

View file

@ -1074,6 +1074,7 @@ fn parse_copy_to() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
having: None,
@ -2383,6 +2384,7 @@ fn parse_array_subquery_expr() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],
@ -2402,6 +2404,7 @@ fn parse_array_subquery_expr() {
into: None,
from: vec![],
lateral_views: vec![],
prewhere: None,
selection: None,
group_by: GroupByExpr::Expressions(vec![], vec![]),
cluster_by: vec![],