Add SQLite dialect (#248)

This commit is contained in:
mz 2020-07-31 20:09:54 +08:00 committed by GitHub
parent 4452f9bad1
commit f8feff4ef2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 2 deletions

View file

@ -16,6 +16,7 @@ pub mod keywords;
mod mssql;
mod mysql;
mod postgresql;
mod sqlite;
use std::fmt::Debug;
@ -24,6 +25,7 @@ pub use self::generic::GenericDialect;
pub use self::mssql::MsSqlDialect;
pub use self::mysql::MySqlDialect;
pub use self::postgresql::PostgreSqlDialect;
pub use self::sqlite::SQLiteDialect;
pub trait Dialect: Debug {
/// Determine if a character starts a quoted identifier. The default

38
src/dialect/sqlite.rs Normal file
View file

@ -0,0 +1,38 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::dialect::Dialect;
#[derive(Debug)]
pub struct SQLiteDialect {}
impl Dialect for SQLiteDialect {
// see https://www.sqlite.org/lang_keywords.html
// parse `...`, [...] and "..." as identifier
// TODO: support depending on the context tread '...' as identifier too.
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '`' || ch == '"' || ch == '['
}
fn is_identifier_start(&self, ch: char) -> bool {
// See https://www.sqlite.org/draft/tokenreq.html
(ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| ch == '_'
|| ch == '$'
|| (ch >= '\u{007f}' && ch <= '\u{ffff}')
}
fn is_identifier_part(&self, ch: char) -> bool {
self.is_identifier_start(ch) || (ch >= '0' && ch <= '9')
}
}

View file

@ -15,7 +15,7 @@
//! generic dialect is also tested (on the inputs it can handle).
use sqlparser::ast::*;
use sqlparser::dialect::GenericDialect;
use sqlparser::dialect::{GenericDialect, SQLiteDialect};
use sqlparser::test_utils::*;
use sqlparser::tokenizer::Token;
@ -87,9 +87,43 @@ fn parse_create_table_auto_increment() {
}
}
#[test]
fn parse_create_sqlite_quote() {
let sql = "CREATE TABLE `PRIMARY` (\"KEY\" INT, [INDEX] INT)";
match sqlite().verified_stmt(sql) {
Statement::CreateTable { name, columns, .. } => {
assert_eq!(name.to_string(), "`PRIMARY`");
assert_eq!(
vec![
ColumnDef {
name: Ident::with_quote('"', "KEY"),
data_type: DataType::Int,
collation: None,
options: vec![],
},
ColumnDef {
name: Ident::with_quote('[', "INDEX"),
data_type: DataType::Int,
collation: None,
options: vec![],
},
],
columns
);
}
_ => unreachable!(),
}
}
fn sqlite() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(SQLiteDialect {})],
}
}
fn sqlite_and_generic() -> TestedDialects {
TestedDialects {
// we don't have a separate SQLite dialect, so test only the generic dialect for now
dialects: vec![Box::new(GenericDialect {})],
dialects: vec![Box::new(SQLiteDialect {}), Box::new(GenericDialect {})],
}
}