Expand handling of `LIMIT 1, 2` handling to include sqlite (#1447)
diff --git a/src/dialect/clickhouse.rs b/src/dialect/clickhouse.rs
index ee8ee94..0c8f080 100644
--- a/src/dialect/clickhouse.rs
+++ b/src/dialect/clickhouse.rs
@@ -46,4 +46,8 @@
fn require_interval_qualifier(&self) -> bool {
true
}
+
+ fn supports_limit_comma(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/generic.rs b/src/dialect/generic.rs
index bea56d0..8bec45b 100644
--- a/src/dialect/generic.rs
+++ b/src/dialect/generic.rs
@@ -99,4 +99,8 @@
fn supports_explain_with_utility_options(&self) -> bool {
true
}
+
+ fn supports_limit_comma(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index 90dffe8..29ad0b9 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -67,7 +67,7 @@
/// 1. user defined [`Dialect`]s can customize the parsing behavior
/// 2. The differences between dialects can be clearly documented in the trait
///
-/// `dialect_of!(parser Is SQLiteDialect | GenericDialect)` evaluates
+/// `dialect_of!(parser is SQLiteDialect | GenericDialect)` evaluates
/// to `true` if `parser.dialect` is one of the [`Dialect`]s specified.
macro_rules! dialect_of {
( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
@@ -323,6 +323,11 @@
false
}
+ /// Does the dialect support parsing `LIMIT 1, 2` as `LIMIT 2 OFFSET 1`?
+ fn supports_limit_comma(&self) -> bool {
+ false
+ }
+
/// Does the dialect support trailing commas in the projection list?
fn supports_projection_trailing_commas(&self) -> bool {
self.supports_trailing_commas()
diff --git a/src/dialect/mysql.rs b/src/dialect/mysql.rs
index 2b5e42e..d1bf333 100644
--- a/src/dialect/mysql.rs
+++ b/src/dialect/mysql.rs
@@ -93,6 +93,10 @@
fn require_interval_qualifier(&self) -> bool {
true
}
+
+ fn supports_limit_comma(&self) -> bool {
+ true
+ }
}
/// `LOCK TABLES`
diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs
index d3813d9..5c563bf 100644
--- a/src/dialect/sqlite.rs
+++ b/src/dialect/sqlite.rs
@@ -73,4 +73,8 @@
fn supports_in_empty_list(&self) -> bool {
true
}
+
+ fn supports_limit_comma(&self) -> bool {
+ true
+ }
}
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index a60dea3..a4445e0 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -8739,7 +8739,7 @@
offset = Some(self.parse_offset()?)
}
- if dialect_of!(self is GenericDialect | MySqlDialect | ClickHouseDialect)
+ if self.dialect.supports_limit_comma()
&& limit.is_some()
&& offset.is_none()
&& self.consume_token(&Token::Comma)
diff --git a/src/test_utils.rs b/src/test_utils.rs
index eb03523..e588b35 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -47,6 +47,14 @@
}
impl TestedDialects {
+ /// Create a TestedDialects with default options and the given dialects.
+ pub fn new(dialects: Vec<Box<dyn Dialect>>) -> Self {
+ Self {
+ dialects,
+ options: None,
+ }
+ }
+
fn new_parser<'a>(&self, dialect: &'a dyn Dialect) -> Parser<'a> {
let parser = Parser::new(dialect);
if let Some(options) = &self.options {
@@ -211,24 +219,21 @@
/// Returns all available dialects.
pub fn all_dialects() -> TestedDialects {
- let all_dialects = vec![
- Box::new(GenericDialect {}) as Box<dyn Dialect>,
- Box::new(PostgreSqlDialect {}) as Box<dyn Dialect>,
- Box::new(MsSqlDialect {}) as Box<dyn Dialect>,
- Box::new(AnsiDialect {}) as Box<dyn Dialect>,
- Box::new(SnowflakeDialect {}) as Box<dyn Dialect>,
- Box::new(HiveDialect {}) as Box<dyn Dialect>,
- Box::new(RedshiftSqlDialect {}) as Box<dyn Dialect>,
- Box::new(MySqlDialect {}) as Box<dyn Dialect>,
- Box::new(BigQueryDialect {}) as Box<dyn Dialect>,
- Box::new(SQLiteDialect {}) as Box<dyn Dialect>,
- Box::new(DuckDbDialect {}) as Box<dyn Dialect>,
- Box::new(DatabricksDialect {}) as Box<dyn Dialect>,
- ];
- TestedDialects {
- dialects: all_dialects,
- options: None,
- }
+ TestedDialects::new(vec![
+ Box::new(GenericDialect {}),
+ Box::new(PostgreSqlDialect {}),
+ Box::new(MsSqlDialect {}),
+ Box::new(AnsiDialect {}),
+ Box::new(SnowflakeDialect {}),
+ Box::new(HiveDialect {}),
+ Box::new(RedshiftSqlDialect {}),
+ Box::new(MySqlDialect {}),
+ Box::new(BigQueryDialect {}),
+ Box::new(SQLiteDialect {}),
+ Box::new(DuckDbDialect {}),
+ Box::new(DatabricksDialect {}),
+ Box::new(ClickHouseDialect {}),
+ ])
}
/// Returns all dialects matching the given predicate.
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 2935298..2677c19 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -6832,7 +6832,9 @@
#[test]
fn parse_create_view_with_columns() {
let sql = "CREATE VIEW v (has, cols) AS SELECT 1, 2";
- match verified_stmt(sql) {
+ // TODO: why does this fail for ClickHouseDialect? (#1449)
+ // match all_dialects().verified_stmt(sql) {
+ match all_dialects_except(|d| d.is::<ClickHouseDialect>()).verified_stmt(sql) {
Statement::CreateView {
name,
columns,
@@ -8624,17 +8626,26 @@
#[test]
fn parse_offset_and_limit() {
- let sql = "SELECT foo FROM bar LIMIT 2 OFFSET 2";
+ let sql = "SELECT foo FROM bar LIMIT 1 OFFSET 2";
let expect = Some(Offset {
value: Expr::Value(number("2")),
rows: OffsetRows::None,
});
let ast = verified_query(sql);
assert_eq!(ast.offset, expect);
- assert_eq!(ast.limit, Some(Expr::Value(number("2"))));
+ assert_eq!(ast.limit, Some(Expr::Value(number("1"))));
// different order is OK
- one_statement_parses_to("SELECT foo FROM bar OFFSET 2 LIMIT 2", sql);
+ one_statement_parses_to("SELECT foo FROM bar OFFSET 2 LIMIT 1", sql);
+
+ // mysql syntax is ok for some dialects
+ TestedDialects::new(vec![
+ Box::new(GenericDialect {}),
+ Box::new(MySqlDialect {}),
+ Box::new(SQLiteDialect {}),
+ Box::new(ClickHouseDialect {}),
+ ])
+ .one_statement_parses_to("SELECT foo FROM bar LIMIT 2, 1", sql);
// expressions are allowed
let sql = "SELECT foo FROM bar LIMIT 1 + 2 OFFSET 3 * 4";