Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down
35 changes: 32 additions & 3 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}
Expand All @@ -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)?;
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 9 additions & 3 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 53 additions & 17 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2265,34 +2265,52 @@ fn parse_invalid_subquery_without_parens() {

#[test]
fn parse_offset() {
let expect = Some(Offset {
value: Expr::Value(number("2")),
rows: OffsetRows::Rows,
});
let ast = verified_query("SELECT foo FROM bar OFFSET 2 ROWS");
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
assert_eq!(ast.offset, expect);
let ast = verified_query("SELECT foo FROM bar WHERE foo = 4 OFFSET 2 ROWS");
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
assert_eq!(ast.offset, expect);
let ast = verified_query("SELECT foo FROM bar ORDER BY baz OFFSET 2 ROWS");
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
assert_eq!(ast.offset, expect);
let ast = verified_query("SELECT foo FROM bar WHERE foo = 4 ORDER BY baz OFFSET 2 ROWS");
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
assert_eq!(ast.offset, expect);
let ast = verified_query("SELECT foo FROM (SELECT * FROM bar OFFSET 2 ROWS) OFFSET 2 ROWS");
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
assert_eq!(ast.offset, expect);
match ast.body {
SetExpr::Select(s) => match only(s.from).relation {
TableFactor::Derived { subquery, .. } => {
assert_eq!(subquery.offset, Some(Expr::Value(number("2"))));
assert_eq!(subquery.offset, expect);
}
_ => panic!("Test broke"),
},
_ => panic!("Test broke"),
}
let ast = verified_query("SELECT 'foo' OFFSET 0 ROWS");
assert_eq!(ast.offset, Some(Expr::Value(number("0"))));
}

#[test]
fn parse_singular_row_offset() {
one_statement_parses_to(
"SELECT foo FROM bar OFFSET 1 ROW",
"SELECT foo FROM bar OFFSET 1 ROWS",
assert_eq!(
ast.offset,
Some(Offset {
value: Expr::Value(number("0")),
rows: OffsetRows::Rows,
})
);
let ast = verified_query("SELECT 'foo' OFFSET 1 ROW");
assert_eq!(
ast.offset,
Some(Offset {
value: Expr::Value(number("1")),
rows: OffsetRows::Row,
})
);
let ast = verified_query("SELECT 'foo' OFFSET 1");
assert_eq!(
ast.offset,
Some(Offset {
value: Expr::Value(number("1")),
rows: OffsetRows::None,
})
);
}

Expand Down Expand Up @@ -2343,7 +2361,13 @@ fn parse_fetch() {
let ast = verified_query(
"SELECT foo FROM bar WHERE foo = 4 ORDER BY baz OFFSET 2 ROWS FETCH FIRST 2 ROWS ONLY",
);
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
assert_eq!(
ast.offset,
Some(Offset {
value: Expr::Value(number("2")),
rows: OffsetRows::Rows,
})
);
assert_eq!(ast.fetch, fetch_first_two_rows_only);
let ast = verified_query(
"SELECT foo FROM (SELECT * FROM bar FETCH FIRST 2 ROWS ONLY) FETCH FIRST 2 ROWS ONLY",
Expand All @@ -2359,12 +2383,24 @@ fn parse_fetch() {
_ => panic!("Test broke"),
}
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");
assert_eq!(ast.offset, Some(Expr::Value(number("2"))));
assert_eq!(
ast.offset,
Some(Offset {
value: Expr::Value(number("2")),
rows: OffsetRows::Rows,
})
);
assert_eq!(ast.fetch, fetch_first_two_rows_only);
match ast.body {
SetExpr::Select(s) => match only(s.from).relation {
TableFactor::Derived { subquery, .. } => {
assert_eq!(subquery.offset, Some(Expr::Value(number("2"))));
assert_eq!(
subquery.offset,
Some(Offset {
value: Expr::Value(number("2")),
rows: OffsetRows::Rows,
})
);
assert_eq!(subquery.fetch, fetch_first_two_rows_only);
}
_ => panic!("Test broke"),
Expand Down