Skip to content

Commit 1e0460a

Browse files
Expand handling of LIMIT 1, 2 handling to include sqlite (#1447)
1 parent ce2686a commit 1e0460a

File tree

8 files changed

+61
-24
lines changed

8 files changed

+61
-24
lines changed

src/dialect/clickhouse.rs

+4
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,8 @@ impl Dialect for ClickHouseDialect {
4646
fn require_interval_qualifier(&self) -> bool {
4747
true
4848
}
49+
50+
fn supports_limit_comma(&self) -> bool {
51+
true
52+
}
4953
}

src/dialect/generic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,8 @@ impl Dialect for GenericDialect {
9999
fn supports_explain_with_utility_options(&self) -> bool {
100100
true
101101
}
102+
103+
fn supports_limit_comma(&self) -> bool {
104+
true
105+
}
102106
}

src/dialect/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use alloc::boxed::Box;
6767
/// 1. user defined [`Dialect`]s can customize the parsing behavior
6868
/// 2. The differences between dialects can be clearly documented in the trait
6969
///
70-
/// `dialect_of!(parser Is SQLiteDialect | GenericDialect)` evaluates
70+
/// `dialect_of!(parser is SQLiteDialect | GenericDialect)` evaluates
7171
/// to `true` if `parser.dialect` is one of the [`Dialect`]s specified.
7272
macro_rules! dialect_of {
7373
( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
@@ -323,6 +323,11 @@ pub trait Dialect: Debug + Any {
323323
false
324324
}
325325

326+
/// Does the dialect support parsing `LIMIT 1, 2` as `LIMIT 2 OFFSET 1`?
327+
fn supports_limit_comma(&self) -> bool {
328+
false
329+
}
330+
326331
/// Does the dialect support trailing commas in the projection list?
327332
fn supports_projection_trailing_commas(&self) -> bool {
328333
self.supports_trailing_commas()

src/dialect/mysql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ impl Dialect for MySqlDialect {
9393
fn require_interval_qualifier(&self) -> bool {
9494
true
9595
}
96+
97+
fn supports_limit_comma(&self) -> bool {
98+
true
99+
}
96100
}
97101

98102
/// `LOCK TABLES`

src/dialect/sqlite.rs

+4
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,8 @@ impl Dialect for SQLiteDialect {
7373
fn supports_in_empty_list(&self) -> bool {
7474
true
7575
}
76+
77+
fn supports_limit_comma(&self) -> bool {
78+
true
79+
}
7680
}

src/parser/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8739,7 +8739,7 @@ impl<'a> Parser<'a> {
87398739
offset = Some(self.parse_offset()?)
87408740
}
87418741

8742-
if dialect_of!(self is GenericDialect | MySqlDialect | ClickHouseDialect)
8742+
if self.dialect.supports_limit_comma()
87438743
&& limit.is_some()
87448744
&& offset.is_none()
87458745
&& self.consume_token(&Token::Comma)

src/test_utils.rs

+23-18
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ pub struct TestedDialects {
4747
}
4848

4949
impl TestedDialects {
50+
/// Create a TestedDialects with default options and the given dialects.
51+
pub fn new(dialects: Vec<Box<dyn Dialect>>) -> Self {
52+
Self {
53+
dialects,
54+
options: None,
55+
}
56+
}
57+
5058
fn new_parser<'a>(&self, dialect: &'a dyn Dialect) -> Parser<'a> {
5159
let parser = Parser::new(dialect);
5260
if let Some(options) = &self.options {
@@ -211,24 +219,21 @@ impl TestedDialects {
211219

212220
/// Returns all available dialects.
213221
pub fn all_dialects() -> TestedDialects {
214-
let all_dialects = vec![
215-
Box::new(GenericDialect {}) as Box<dyn Dialect>,
216-
Box::new(PostgreSqlDialect {}) as Box<dyn Dialect>,
217-
Box::new(MsSqlDialect {}) as Box<dyn Dialect>,
218-
Box::new(AnsiDialect {}) as Box<dyn Dialect>,
219-
Box::new(SnowflakeDialect {}) as Box<dyn Dialect>,
220-
Box::new(HiveDialect {}) as Box<dyn Dialect>,
221-
Box::new(RedshiftSqlDialect {}) as Box<dyn Dialect>,
222-
Box::new(MySqlDialect {}) as Box<dyn Dialect>,
223-
Box::new(BigQueryDialect {}) as Box<dyn Dialect>,
224-
Box::new(SQLiteDialect {}) as Box<dyn Dialect>,
225-
Box::new(DuckDbDialect {}) as Box<dyn Dialect>,
226-
Box::new(DatabricksDialect {}) as Box<dyn Dialect>,
227-
];
228-
TestedDialects {
229-
dialects: all_dialects,
230-
options: None,
231-
}
222+
TestedDialects::new(vec![
223+
Box::new(GenericDialect {}),
224+
Box::new(PostgreSqlDialect {}),
225+
Box::new(MsSqlDialect {}),
226+
Box::new(AnsiDialect {}),
227+
Box::new(SnowflakeDialect {}),
228+
Box::new(HiveDialect {}),
229+
Box::new(RedshiftSqlDialect {}),
230+
Box::new(MySqlDialect {}),
231+
Box::new(BigQueryDialect {}),
232+
Box::new(SQLiteDialect {}),
233+
Box::new(DuckDbDialect {}),
234+
Box::new(DatabricksDialect {}),
235+
Box::new(ClickHouseDialect {}),
236+
])
232237
}
233238

234239
/// Returns all dialects matching the given predicate.

tests/sqlparser_common.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -6832,7 +6832,9 @@ fn parse_create_view_with_options() {
68326832
#[test]
68336833
fn parse_create_view_with_columns() {
68346834
let sql = "CREATE VIEW v (has, cols) AS SELECT 1, 2";
6835-
match verified_stmt(sql) {
6835+
// TODO: why does this fail for ClickHouseDialect? (#1449)
6836+
// match all_dialects().verified_stmt(sql) {
6837+
match all_dialects_except(|d| d.is::<ClickHouseDialect>()).verified_stmt(sql) {
68366838
Statement::CreateView {
68376839
name,
68386840
columns,
@@ -8624,17 +8626,26 @@ fn verified_expr(query: &str) -> Expr {
86248626

86258627
#[test]
86268628
fn parse_offset_and_limit() {
8627-
let sql = "SELECT foo FROM bar LIMIT 2 OFFSET 2";
8629+
let sql = "SELECT foo FROM bar LIMIT 1 OFFSET 2";
86288630
let expect = Some(Offset {
86298631
value: Expr::Value(number("2")),
86308632
rows: OffsetRows::None,
86318633
});
86328634
let ast = verified_query(sql);
86338635
assert_eq!(ast.offset, expect);
8634-
assert_eq!(ast.limit, Some(Expr::Value(number("2"))));
8636+
assert_eq!(ast.limit, Some(Expr::Value(number("1"))));
86358637

86368638
// different order is OK
8637-
one_statement_parses_to("SELECT foo FROM bar OFFSET 2 LIMIT 2", sql);
8639+
one_statement_parses_to("SELECT foo FROM bar OFFSET 2 LIMIT 1", sql);
8640+
8641+
// mysql syntax is ok for some dialects
8642+
TestedDialects::new(vec![
8643+
Box::new(GenericDialect {}),
8644+
Box::new(MySqlDialect {}),
8645+
Box::new(SQLiteDialect {}),
8646+
Box::new(ClickHouseDialect {}),
8647+
])
8648+
.one_statement_parses_to("SELECT foo FROM bar LIMIT 2, 1", sql);
86388649

86398650
// expressions are allowed
86408651
let sql = "SELECT foo FROM bar LIMIT 1 + 2 OFFSET 3 * 4";

0 commit comments

Comments
 (0)