Skip to content

Commit 972f46a

Browse files
committed
Add support for WITH FILL to OrderByExpr
ClickHouse supports the ORDER BY ... WITH FILL modifier: https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier WITH FILL itself supports a simple "from", "to", and "step" parameters, and a more sophisticated INTERPOLATE option.
1 parent 44d7a20 commit 972f46a

File tree

6 files changed

+229
-2
lines changed

6 files changed

+229
-2
lines changed

src/ast/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ pub use self::operator::{BinaryOperator, UnaryOperator};
4343
pub use self::query::{
4444
AfterMatchSkip, ConnectBy, Cte, CteAsMaterialized, Distinct, EmptyMatchesMode,
4545
ExceptSelectItem, ExcludeSelectItem, ExprWithAlias, Fetch, ForClause, ForJson, ForXml,
46-
GroupByExpr, GroupByWithModifier, IdentWithAlias, IlikeSelectItem, Join, JoinConstraint,
46+
GroupByExpr, GroupByWithModifier, IdentWithAlias, IlikeSelectItem, Interpolation, Join, JoinConstraint,
4747
JoinOperator, JsonTableColumn, JsonTableColumnErrorHandling, LateralView, LockClause, LockType,
4848
MatchRecognizePattern, MatchRecognizeSymbol, Measure, NamedWindowDefinition, NamedWindowExpr,
4949
NonBlock, Offset, OffsetRows, OrderByExpr, PivotValueSource, Query, RenameSelectItem,
5050
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,
5151
SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, SymbolDefinition, Table,
5252
TableAlias, TableFactor, TableVersion, TableWithJoins, Top, TopQuantity, ValueTableMode,
53-
Values, WildcardAdditionalOptions, With,
53+
Values, WildcardAdditionalOptions, With, WithFill,
5454
};
5555
pub use self::value::{
5656
escape_double_quote_string, escape_quoted_string, DateTimeField, DollarQuotedString,

src/ast/query.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,9 @@ pub struct OrderByExpr {
16271627
pub asc: Option<bool>,
16281628
/// Optional `NULLS FIRST` or `NULLS LAST`
16291629
pub nulls_first: Option<bool>,
1630+
/// Optional: `WITH FILL`
1631+
/// Supported by [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
1632+
pub with_fill: Option<WithFill>,
16301633
}
16311634

16321635
impl fmt::Display for OrderByExpr {
@@ -1642,6 +1645,58 @@ impl fmt::Display for OrderByExpr {
16421645
Some(false) => write!(f, " NULLS LAST")?,
16431646
None => (),
16441647
}
1648+
if let Some(ref with_fill) = self.with_fill {
1649+
write!(f, " {}", with_fill)?
1650+
}
1651+
Ok(())
1652+
}
1653+
}
1654+
1655+
/// ClickHouse `WITH FILL` modifier for `ORDER BY` clause.
1656+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1657+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1658+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1659+
pub struct WithFill {
1660+
pub from: Option<Expr>,
1661+
pub to: Option<Expr>,
1662+
pub step: Option<Expr>,
1663+
pub interpolate: Vec<Interpolation>,
1664+
}
1665+
1666+
impl fmt::Display for WithFill {
1667+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1668+
write!(f, "WITH FILL")?;
1669+
if let Some(ref from) = self.from {
1670+
write!(f, " FROM {}", from)?;
1671+
}
1672+
if let Some(ref to) = self.to {
1673+
write!(f, " TO {}", to)?;
1674+
}
1675+
if let Some(ref step) = self.step {
1676+
write!(f, " STEP {}", step)?;
1677+
}
1678+
if !self.interpolate.is_empty() {
1679+
write!(f, " INTERPOLATE ({})", display_comma_separated(&self.interpolate))?;
1680+
}
1681+
Ok(())
1682+
}
1683+
}
1684+
1685+
/// ClickHouse `INTERPOLATE` clause for use in `WITH FILL` modifier.
1686+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1687+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1688+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1689+
pub struct Interpolation {
1690+
pub column: Expr,
1691+
pub formula: Option<Expr>,
1692+
}
1693+
1694+
impl fmt::Display for Interpolation {
1695+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1696+
write!(f, "{}", self.column)?;
1697+
if let Some(ref formula) = self.formula {
1698+
write!(f, " AS {}", formula)?;
1699+
}
16451700
Ok(())
16461701
}
16471702
}

src/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ define_keywords!(
297297
FILE,
298298
FILES,
299299
FILE_FORMAT,
300+
FILL,
300301
FILTER,
301302
FIRST,
302303
FIRST_VALUE,
@@ -382,6 +383,7 @@ define_keywords!(
382383
INT64,
383384
INT8,
384385
INTEGER,
386+
INTERPOLATE,
385387
INTERSECT,
386388
INTERSECTION,
387389
INTERVAL,
@@ -678,6 +680,7 @@ define_keywords!(
678680
STDDEV_SAMP,
679681
STDIN,
680682
STDOUT,
683+
STEP,
681684
STORAGE_INTEGRATION,
682685
STORED,
683686
STRICT,

src/parser/mod.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10408,13 +10408,70 @@ impl<'a> Parser<'a> {
1040810408
None
1040910409
};
1041010410

10411+
let with_fill = if self.parse_keywords(&[Keyword::WITH, Keyword::FILL]) {
10412+
Some(self.parse_with_fill()?)
10413+
} else {
10414+
None
10415+
};
10416+
1041110417
Ok(OrderByExpr {
1041210418
expr,
1041310419
asc,
1041410420
nulls_first,
10421+
with_fill,
1041510422
})
1041610423
}
1041710424

10425+
// Parse a WITH FILL clause (ClickHouse dialect)
10426+
// that follow the WITH FILL keywords in a ORDER BY clause
10427+
pub fn parse_with_fill(&mut self) -> Result<WithFill, ParserError> {
10428+
let from = if self.parse_keyword(Keyword::FROM) {
10429+
Some(self.parse_expr()?)
10430+
} else {
10431+
None
10432+
};
10433+
10434+
let to = if self.parse_keyword(Keyword::TO) {
10435+
Some(self.parse_expr()?)
10436+
} else {
10437+
None
10438+
};
10439+
10440+
let step = if self.parse_keyword(Keyword::STEP) {
10441+
Some(self.parse_expr()?)
10442+
} else {
10443+
None
10444+
};
10445+
10446+
let interpolate = if self.parse_keyword(Keyword::INTERPOLATE) && self.consume_token(&Token::LParen) {
10447+
let interpolations = self.parse_interpolations()?;
10448+
self.expect_token(&Token::RParen)?;
10449+
interpolations
10450+
} else {
10451+
vec![]
10452+
};
10453+
10454+
Ok(WithFill { from, to, step, interpolate })
10455+
}
10456+
10457+
// Parse a set of comma seperated INTERPOLATE expressions (ClickHouse dialect)
10458+
// that follow the INTERPOLATE keyword in a WITH FILL clause
10459+
pub fn parse_interpolations(&mut self) -> Result<Vec<Interpolation>, ParserError> {
10460+
self.parse_comma_separated(|p| p.parse_interpolation())
10461+
}
10462+
10463+
10464+
// Parse a INTERPOLATE expression (ClickHouse dialect)
10465+
pub fn parse_interpolation(&mut self) -> Result<Interpolation, ParserError> {
10466+
let column = self.parse_expr()?;
10467+
let formula = if self.parse_keyword(Keyword::AS) {
10468+
Some(self.parse_expr()?)
10469+
} else {
10470+
None
10471+
};
10472+
Ok(Interpolation { column, formula })
10473+
}
10474+
1041810475
/// Parse a TOP clause, MSSQL equivalent of LIMIT,
1041910476
/// that follows after `SELECT [DISTINCT]`.
1042010477
pub fn parse_top(&mut self) -> Result<Top, ParserError> {

0 commit comments

Comments
 (0)