Skip to content

Commit c0b0b59

Browse files
committed
Add support for OFFSET with the ROWS keyword
MySQL doesn't support the ROWS part of OFFSET. Teach the parser to remember which variant it saw, including just ROW.
1 parent 05a2921 commit c0b0b59

File tree

4 files changed

+96
-25
lines changed

4 files changed

+96
-25
lines changed

src/ast/mod.rs

Lines changed: 2 additions & 2 deletions
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

Lines changed: 32 additions & 3 deletions
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

Lines changed: 9 additions & 3 deletions
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

Lines changed: 53 additions & 17 deletions
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)