Skip to content

Commit f8feff4

Browse files
authored
Add SQLite dialect (apache#248)
1 parent 4452f9b commit f8feff4

3 files changed

Lines changed: 76 additions & 2 deletions

File tree

src/dialect/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub mod keywords;
1616
mod mssql;
1717
mod mysql;
1818
mod postgresql;
19+
mod sqlite;
1920

2021
use std::fmt::Debug;
2122

@@ -24,6 +25,7 @@ pub use self::generic::GenericDialect;
2425
pub use self::mssql::MsSqlDialect;
2526
pub use self::mysql::MySqlDialect;
2627
pub use self::postgresql::PostgreSqlDialect;
28+
pub use self::sqlite::SQLiteDialect;
2729

2830
pub trait Dialect: Debug {
2931
/// Determine if a character starts a quoted identifier. The default

src/dialect/sqlite.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at
4+
//
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS,
9+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
// See the License for the specific language governing permissions and
11+
// limitations under the License.
12+
13+
use crate::dialect::Dialect;
14+
15+
#[derive(Debug)]
16+
pub struct SQLiteDialect {}
17+
18+
impl Dialect for SQLiteDialect {
19+
// see https://www.sqlite.org/lang_keywords.html
20+
// parse `...`, [...] and "..." as identifier
21+
// TODO: support depending on the context tread '...' as identifier too.
22+
fn is_delimited_identifier_start(&self, ch: char) -> bool {
23+
ch == '`' || ch == '"' || ch == '['
24+
}
25+
26+
fn is_identifier_start(&self, ch: char) -> bool {
27+
// See https://www.sqlite.org/draft/tokenreq.html
28+
(ch >= 'a' && ch <= 'z')
29+
|| (ch >= 'A' && ch <= 'Z')
30+
|| ch == '_'
31+
|| ch == '$'
32+
|| (ch >= '\u{007f}' && ch <= '\u{ffff}')
33+
}
34+
35+
fn is_identifier_part(&self, ch: char) -> bool {
36+
self.is_identifier_start(ch) || (ch >= '0' && ch <= '9')
37+
}
38+
}

tests/sqlparser_sqlite.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//! generic dialect is also tested (on the inputs it can handle).
1616
1717
use sqlparser::ast::*;
18-
use sqlparser::dialect::GenericDialect;
18+
use sqlparser::dialect::{GenericDialect, SQLiteDialect};
1919
use sqlparser::test_utils::*;
2020
use sqlparser::tokenizer::Token;
2121

@@ -87,9 +87,43 @@ fn parse_create_table_auto_increment() {
8787
}
8888
}
8989

90+
#[test]
91+
fn parse_create_sqlite_quote() {
92+
let sql = "CREATE TABLE `PRIMARY` (\"KEY\" INT, [INDEX] INT)";
93+
match sqlite().verified_stmt(sql) {
94+
Statement::CreateTable { name, columns, .. } => {
95+
assert_eq!(name.to_string(), "`PRIMARY`");
96+
assert_eq!(
97+
vec![
98+
ColumnDef {
99+
name: Ident::with_quote('"', "KEY"),
100+
data_type: DataType::Int,
101+
collation: None,
102+
options: vec![],
103+
},
104+
ColumnDef {
105+
name: Ident::with_quote('[', "INDEX"),
106+
data_type: DataType::Int,
107+
collation: None,
108+
options: vec![],
109+
},
110+
],
111+
columns
112+
);
113+
}
114+
_ => unreachable!(),
115+
}
116+
}
117+
118+
fn sqlite() -> TestedDialects {
119+
TestedDialects {
120+
dialects: vec![Box::new(SQLiteDialect {})],
121+
}
122+
}
123+
90124
fn sqlite_and_generic() -> TestedDialects {
91125
TestedDialects {
92126
// we don't have a separate SQLite dialect, so test only the generic dialect for now
93-
dialects: vec![Box::new(GenericDialect {})],
127+
dialects: vec![Box::new(SQLiteDialect {}), Box::new(GenericDialect {})],
94128
}
95129
}

0 commit comments

Comments
 (0)