Merge pull request #158 from mjibson/offset-rows

Add support for OFFSET without the ROWS keyword (a MySQL quirk, documented at https://dev.mysql.com/doc/refman/8.0/en/select.html)

Teach the parser to remember which variant it saw (ROWS/ROW/none).
This commit is contained in:
Nickolay Ponomarev 2020-04-20 05:38:04 +03:00 committed by GitHub
commit af852e78f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 25 deletions

View file

@ -26,8 +26,8 @@ pub use self::ddl::{
};
pub use self::operator::{BinaryOperator, UnaryOperator};
pub use self::query::{
Cte, Fetch, Join, JoinConstraint, JoinOperator, OrderByExpr, Query, Select, SelectItem,
SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top, Values,
Cte, Fetch, Join, JoinConstraint, JoinOperator, Offset, OffsetRows, OrderByExpr, Query, Select,
SelectItem, SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top, Values,
};
pub use self::value::{DateTimeField, Value};

View file

@ -24,8 +24,8 @@ pub struct Query {
pub order_by: Vec<OrderByExpr>,
/// `LIMIT { <N> | ALL }`
pub limit: Option<Expr>,
/// `OFFSET <N> { ROW | ROWS }`
pub offset: Option<Expr>,
/// `OFFSET <N> [ { ROW | ROWS } ]`
pub offset: Option<Offset>,
/// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
pub fetch: Option<Fetch>,
}
@ -43,7 +43,7 @@ impl fmt::Display for Query {
write!(f, " LIMIT {}", limit)?;
}
if let Some(ref offset) = self.offset {
write!(f, " OFFSET {} ROWS", offset)?;
write!(f, " {}", offset)?;
}
if let Some(ref fetch) = self.fetch {
write!(f, " {}", fetch)?;
@ -391,6 +391,35 @@ impl fmt::Display for OrderByExpr {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Offset {
pub value: Expr,
pub rows: OffsetRows,
}
impl fmt::Display for Offset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "OFFSET {}{}", self.value, self.rows)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum OffsetRows {
None,
Row,
Rows,
}
impl fmt::Display for OffsetRows {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OffsetRows::None => Ok(()),
OffsetRows::Row => write!(f, " ROW"),
OffsetRows::Rows => write!(f, " ROWS"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Fetch {
pub with_ties: bool,

View file

@ -1970,10 +1970,16 @@ impl Parser {
}
/// Parse an OFFSET clause
pub fn parse_offset(&mut self) -> Result<Expr, ParserError> {
pub fn parse_offset(&mut self) -> Result<Offset, ParserError> {
let value = Expr::Value(self.parse_number_value()?);
self.expect_one_of_keywords(&["ROW", "ROWS"])?;
Ok(value)
let rows = if self.parse_keyword("ROW") {
OffsetRows::Row
} else if self.parse_keyword("ROWS") {
OffsetRows::Rows
} else {
OffsetRows::None
};
Ok(Offset { value, rows })
}
/// Parse a FETCH clause