Amend WindowFrame docs

The note about WindowFrameBound::Following being only valid "in
WindowFrame::end_bound" was both

- confusing, as it was based on the ANSI SQL syntax the parser doesn't
  adhere to -- though it sounded like a promise about the AST one could
  expect to get from the parser
- and incomplete, as the reality is that the bounds validation the SQL
  engine might want to perform is more complex. For example Postgres
  documentation says <https://www.postgresql.org/docs/11/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS>:

> Restrictions are that frame_start cannot be UNBOUNDED FOLLOWING,
> frame_end cannot be UNBOUNDED PRECEDING, and the frame_end choice
> cannot appear earlier in the above list of frame_start and frame_end
> options than the frame_start choice does — for example RANGE BETWEEN
> CURRENT ROW AND offset PRECEDING is not allowed. But, for example,
> ROWS BETWEEN 7 PRECEDING AND 8 PRECEDING is allowed, even though it
> would never select any rows.
This commit is contained in:
Nickolay Ponomarev 2019-07-09 02:37:36 +03:00
parent f31636d339
commit 086ba1281c
2 changed files with 10 additions and 6 deletions

View file

@ -292,11 +292,16 @@ impl fmt::Display for WindowSpec {
/// Specifies the data processed by a window function, e.g.
/// `RANGE UNBOUNDED PRECEDING` or `ROWS BETWEEN 5 PRECEDING AND CURRENT ROW`.
///
/// Note: The parser does not validate the specified bounds; the caller should
/// reject invalid bounds like `ROWS UNBOUNDED FOLLOWING` before execution.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct WindowFrame {
pub units: WindowFrameUnits,
pub start_bound: WindowFrameBound,
/// The right bound of the `BETWEEN .. AND` clause.
/// The right bound of the `BETWEEN .. AND` clause. The end bound of `None`
/// indicates the shorthand form (e.g. `ROWS 1 PRECEDING`), which must
/// behave the same as `end_bound = WindowFrameBound::CurrentRow`.
pub end_bound: Option<WindowFrameBound>,
// TBD: EXCLUDE
}
@ -334,14 +339,14 @@ impl FromStr for WindowFrameUnits {
}
}
/// Specifies [WindowFrame]'s `start_bound` and `end_bound`
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WindowFrameBound {
/// `CURRENT ROW`
CurrentRow,
/// `<N> PRECEDING` or `UNBOUNDED PRECEDING`
Preceding(Option<u64>),
/// `<N> FOLLOWING` or `UNBOUNDED FOLLOWING`. This can only appear in
/// [WindowFrame::end_bound].
/// `<N> FOLLOWING` or `UNBOUNDED FOLLOWING`.
Following(Option<u64>),
}

View file

@ -339,7 +339,7 @@ impl Parser {
})
}
/// "CURRENT ROW" | ( (<positive number> | "UNBOUNDED") ("PRECEDING" | FOLLOWING) )
/// Parse `CURRENT ROW` or `{ <positive number> | UNBOUNDED } { PRECEDING | FOLLOWING }`
pub fn parse_window_frame_bound(&mut self) -> Result<WindowFrameBound, ParserError> {
if self.parse_keywords(vec!["CURRENT", "ROW"]) {
Ok(WindowFrameBound::CurrentRow)
@ -347,8 +347,7 @@ impl Parser {
let rows = if self.parse_keyword("UNBOUNDED") {
None
} else {
let rows = self.parse_literal_uint()?;
Some(rows)
Some(self.parse_literal_uint()?)
};
if self.parse_keyword("PRECEDING") {
Ok(WindowFrameBound::Preceding(rows))