-
Notifications
You must be signed in to change notification settings - Fork 627
[ClickHouse] Add support for WITH FILL to OrderByExpr #1330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
815ee5b
7022e42
47ba442
4068bb3
ec263d2
4b8c6fe
85fae63
4a7167b
7e745c3
44deb69
000e08d
9aaca38
6ee4257
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7914,7 +7914,9 @@ impl<'a> Parser<'a> { | |
let body = self.parse_boxed_query_body(0)?; | ||
|
||
let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) { | ||
self.parse_comma_separated(Parser::parse_order_by_expr)? | ||
let order_by_exprs = self.parse_comma_separated(Parser::parse_order_by_expr)?; | ||
self.validate_order_by_exprs_for_interpolate_and_with_fill(&order_by_exprs)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah so the parser generally doesn't do semantic validations explicitly except for maybe trivial cases, in this case it seems correct to have the invalid state non-representable in the AST, it does become a bit invasive of a change but that should be fine since it would leave us with a more accurate representation of the syntax There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can likely skip this validation function in any case. To clarify, I think the current approach having interpolate in the Query {
pub order_by: Vec<OrderByExpr>,
} to either struct Query {
pub order_by: Vec<OrderByExpr>,
interpolate: Option<Interpolate>
} or struct OrderBy {
exprs: Vec<OrderByExpr>,
interpolate: Option<Interpolate>
}
Query {
pub order_by: OrderBy,
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the structure of |
||
order_by_exprs | ||
} else { | ||
vec![] | ||
}; | ||
|
@@ -10454,13 +10456,111 @@ impl<'a> Parser<'a> { | |
None | ||
}; | ||
|
||
let with_fill = if dialect_of!(self is ClickHouseDialect | GenericDialect) | ||
&& self.parse_keywords(&[Keyword::WITH, Keyword::FILL]) | ||
{ | ||
Some(self.parse_with_fill()?) | ||
} else { | ||
None | ||
}; | ||
|
||
let interpolate = if dialect_of!(self is ClickHouseDialect | GenericDialect) | ||
&& self.parse_keyword(Keyword::INTERPOLATE) | ||
{ | ||
if self.consume_token(&Token::LParen) { | ||
let interpolations = self.parse_interpolations()?; | ||
self.expect_token(&Token::RParen)?; | ||
// INTERPOLATE () and INTERPOLATE ( ... ) variants | ||
Some(Interpolate { | ||
expr: Some(interpolations), | ||
}) | ||
} else { | ||
// INTERPOLATE | ||
Some(Interpolate { expr: None }) | ||
} | ||
} else { | ||
None | ||
}; | ||
|
||
Ok(OrderByExpr { | ||
expr, | ||
asc, | ||
nulls_first, | ||
with_fill, | ||
interpolate, | ||
}) | ||
} | ||
|
||
// Parse a WITH FILL clause (ClickHouse dialect) | ||
// that follow the WITH FILL keywords in a ORDER BY clause | ||
pub fn parse_with_fill(&mut self) -> Result<WithFill, ParserError> { | ||
let from = if self.parse_keyword(Keyword::FROM) { | ||
Some(self.parse_expr()?) | ||
} else { | ||
None | ||
}; | ||
|
||
let to = if self.parse_keyword(Keyword::TO) { | ||
Some(self.parse_expr()?) | ||
} else { | ||
None | ||
}; | ||
|
||
let step = if self.parse_keyword(Keyword::STEP) { | ||
Some(self.parse_expr()?) | ||
} else { | ||
None | ||
}; | ||
|
||
Ok(WithFill { from, to, step }) | ||
} | ||
|
||
pub fn validate_order_by_exprs_for_interpolate_and_with_fill( | ||
&mut self, | ||
order_by_exprs: &Vec<OrderByExpr>, | ||
) -> Result<(), ParserError> { | ||
if dialect_of!(self is ClickHouseDialect | GenericDialect) { | ||
let mut has_with_fill = false; | ||
let mut has_interpolate = false; | ||
for order_by_expr in order_by_exprs { | ||
if order_by_expr.with_fill.is_some() { | ||
has_with_fill = true; | ||
} | ||
if order_by_expr.interpolate.is_some() { | ||
if has_interpolate { | ||
return Err(ParserError::ParserError( | ||
"Only the last ORDER BY expression can contain interpolate".to_string(), | ||
)); | ||
} | ||
if !has_with_fill { | ||
return Err(ParserError::ParserError( | ||
"INTERPOLATE requires WITH FILL".to_string(), | ||
)); | ||
} | ||
has_interpolate = true; | ||
} | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
// Parse a set of comma seperated INTERPOLATE expressions (ClickHouse dialect) | ||
// that follow the INTERPOLATE keyword in an ORDER BY clause with the WITH FILL modifier | ||
pub fn parse_interpolations(&mut self) -> Result<Vec<InterpolateExpr>, ParserError> { | ||
self.parse_comma_separated0(|p| p.parse_interpolation()) | ||
} | ||
|
||
// Parse a INTERPOLATE expression (ClickHouse dialect) | ||
pub fn parse_interpolation(&mut self) -> Result<InterpolateExpr, ParserError> { | ||
let column = self.parse_identifier(false)?; | ||
let expr = if self.parse_keyword(Keyword::AS) { | ||
Some(self.parse_expr()?) | ||
} else { | ||
None | ||
}; | ||
Ok(InterpolateExpr { column, expr }) | ||
} | ||
|
||
/// Parse a TOP clause, MSSQL equivalent of LIMIT, | ||
/// that follows after `SELECT [DISTINCT]`. | ||
pub fn parse_top(&mut self) -> Result<Top, ParserError> { | ||
|
Uh oh!
There was an error while loading. Please reload this page.