Skip to content

Commit af852e7

Browse files
authored
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).
2 parents 5fe9060 + c0b0b59 commit af852e7

File tree

4 files changed

+96
-25
lines changed

4 files changed

+96
-25
lines changed

src/ast/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ pub use self::ddl::{
2626
};
2727
pub use self::operator::{BinaryOperator, UnaryOperator};
2828
pub use self::query::{
29-
Cte, Fetch, Join, JoinConstraint, JoinOperator, OrderByExpr, Query, Select, SelectItem,
30-
SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top, Values,
29+
Cte, Fetch, Join, JoinConstraint, JoinOperator, Offset, OffsetRows, OrderByExpr, Query, Select,
30+
SelectItem, SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top, Values,
3131
};
3232
pub use self::value::{DateTimeField, Value};
3333

src/ast/query.rs

+32-3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ pub struct Query {
2424
pub order_by: Vec<OrderByExpr>,
2525
/// `LIMIT { <N> | ALL }`
2626
pub limit: Option<Expr>,
27-
/// `OFFSET <N> { ROW | ROWS }`
28-
pub offset: Option<Expr>,
27+
/// `OFFSET <N> [ { ROW | ROWS } ]`
28+
pub offset: Option<Offset>,
2929
/// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
3030
pub fetch: Option<Fetch>,
3131
}
@@ -43,7 +43,7 @@ impl fmt::Display for Query {
4343
write!(f, " LIMIT {}", limit)?;
4444
}
4545
if let Some(ref offset) = self.offset {
46-
write!(f, " OFFSET {} ROWS", offset)?;
46+
write!(f, " {}", offset)?;
4747
}
4848
if let Some(ref fetch) = self.fetch {
4949
write!(f, " {}", fetch)?;
@@ -391,6 +391,35 @@ impl fmt::Display for OrderByExpr {
391391
}
392392
}
393393

394+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
395+
pub struct Offset {
396+
pub value: Expr,
397+
pub rows: OffsetRows,
398+
}
399+
400+
impl fmt::Display for Offset {
401+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
402+
write!(f, "OFFSET {}{}", self.value, self.rows)
403+
}
404+
}
405+
406+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
407+
pub enum OffsetRows {
408+
None,
409+
Row,
410+
Rows,
411+
}
412+
413+
impl fmt::Display for OffsetRows {
414+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415+
match self {
416+
OffsetRows::None => Ok(()),
417+
OffsetRows::Row => write!(f, " ROW"),
418+
OffsetRows::Rows => write!(f, " ROWS"),
419+
}
420+
}
421+
}
422+
394423
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
395424
pub struct Fetch {
396425
pub with_ties: bool,

src/parser.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1970,10 +1970,16 @@ impl Parser {
19701970
}
19711971

19721972
/// Parse an OFFSET clause
1973-
pub fn parse_offset(&mut self) -> Result<Expr, ParserError> {
1973+
pub fn parse_offset(&mut self) -> Result<Offset, ParserError> {
19741974
let value = Expr::Value(self.parse_number_value()?);
1975-
self.expect_one_of_keywords(&["ROW", "ROWS"])?;
1976-
Ok(value)
1975+
let rows = if self.parse_keyword("ROW") {
1976+
OffsetRows::Row
1977+
} else if self.parse_keyword("ROWS") {
1978+
OffsetRows::Rows
1979+
} else {
1980+
OffsetRows::None
1981+
};
1982+
Ok(Offset { value, rows })
19771983
}
19781984

19791985
/// Parse a FETCH clause

tests/sqlparser_common.rs

+53-17
Original file line numberDiff line numberDiff line change
@@ -2265,34 +2265,52 @@ fn parse_invalid_subquery_without_parens() {
22652265

22662266
#[test]
22672267
fn parse_offset() {
2268+
let expect = Some(Offset {
2269+
value: Expr::Value(number("2")),
2270+
rows: OffsetRows::Rows,
2271+
});
22682272
let ast = verified_query("SELECT foo FROM bar OFFSET 2 ROWS");
2269-
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
2273+
assert_eq!(ast.offset, expect);
22702274
let ast = verified_query("SELECT foo FROM bar WHERE foo = 4 OFFSET 2 ROWS");
2271-
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
2275+
assert_eq!(ast.offset, expect);
22722276
let ast = verified_query("SELECT foo FROM bar ORDER BY baz OFFSET 2 ROWS");
2273-
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
2277+
assert_eq!(ast.offset, expect);
22742278
let ast = verified_query("SELECT foo FROM bar WHERE foo = 4 ORDER BY baz OFFSET 2 ROWS");
2275-
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
2279+
assert_eq!(ast.offset, expect);
22762280
let ast = verified_query("SELECT foo FROM (SELECT * FROM bar OFFSET 2 ROWS) OFFSET 2 ROWS");
2277-
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
2281+
assert_eq!(ast.offset, expect);
22782282
match ast.body {
22792283
SetExpr::Select(s) => match only(s.from).relation {
22802284
TableFactor::Derived { subquery, .. } => {
2281-
assert_eq!(subquery.offset, Some(Expr::Value(number("2"))));
2285+
assert_eq!(subquery.offset, expect);
22822286
}
22832287
_ => panic!("Test broke"),
22842288
},
22852289
_ => panic!("Test broke"),
22862290
}
22872291
let ast = verified_query("SELECT 'foo' OFFSET 0 ROWS");
2288-
assert_eq!(ast.offset, Some(Expr::Value(number("0"))));
2289-
}
2290-
2291-
#[test]
2292-
fn parse_singular_row_offset() {
2293-
one_statement_parses_to(
2294-
"SELECT foo FROM bar OFFSET 1 ROW",
2295-
"SELECT foo FROM bar OFFSET 1 ROWS",
2292+
assert_eq!(
2293+
ast.offset,
2294+
Some(Offset {
2295+
value: Expr::Value(number("0")),
2296+
rows: OffsetRows::Rows,
2297+
})
2298+
);
2299+
let ast = verified_query("SELECT 'foo' OFFSET 1 ROW");
2300+
assert_eq!(
2301+
ast.offset,
2302+
Some(Offset {
2303+
value: Expr::Value(number("1")),
2304+
rows: OffsetRows::Row,
2305+
})
2306+
);
2307+
let ast = verified_query("SELECT 'foo' OFFSET 1");
2308+
assert_eq!(
2309+
ast.offset,
2310+
Some(Offset {
2311+
value: Expr::Value(number("1")),
2312+
rows: OffsetRows::None,
2313+
})
22962314
);
22972315
}
22982316

@@ -2343,7 +2361,13 @@ fn parse_fetch() {
23432361
let ast = verified_query(
23442362
"SELECT foo FROM bar WHERE foo = 4 ORDER BY baz OFFSET 2 ROWS FETCH FIRST 2 ROWS ONLY",
23452363
);
2346-
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
2364+
assert_eq!(
2365+
ast.offset,
2366+
Some(Offset {
2367+
value: Expr::Value(number("2")),
2368+
rows: OffsetRows::Rows,
2369+
})
2370+
);
23472371
assert_eq!(ast.fetch, fetch_first_two_rows_only);
23482372
let ast = verified_query(
23492373
"SELECT foo FROM (SELECT * FROM bar FETCH FIRST 2 ROWS ONLY) FETCH FIRST 2 ROWS ONLY",
@@ -2359,12 +2383,24 @@ fn parse_fetch() {
23592383
_ => panic!("Test broke"),
23602384
}
23612385
let ast = verified_query("SELECT foo FROM (SELECT * FROM bar OFFSET 2 ROWS FETCH FIRST 2 ROWS ONLY) OFFSET 2 ROWS FETCH FIRST 2 ROWS ONLY");
2362-
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
2386+
assert_eq!(
2387+
ast.offset,
2388+
Some(Offset {
2389+
value: Expr::Value(number("2")),
2390+
rows: OffsetRows::Rows,
2391+
})
2392+
);
23632393
assert_eq!(ast.fetch, fetch_first_two_rows_only);
23642394
match ast.body {
23652395
SetExpr::Select(s) => match only(s.from).relation {
23662396
TableFactor::Derived { subquery, .. } => {
2367-
assert_eq!(subquery.offset, Some(Expr::Value(number("2"))));
2397+
assert_eq!(
2398+
subquery.offset,
2399+
Some(Offset {
2400+
value: Expr::Value(number("2")),
2401+
rows: OffsetRows::Rows,
2402+
})
2403+
);
23682404
assert_eq!(subquery.fetch, fetch_first_two_rows_only);
23692405
}
23702406
_ => panic!("Test broke"),

0 commit comments

Comments
 (0)