diff --git a/examples/cli.rs b/examples/cli.rs index f019c520..98f6849b 100644 --- a/examples/cli.rs +++ b/examples/cli.rs @@ -39,6 +39,7 @@ $ cargo run --feature json_example --example cli FILENAME.sql [--dialectname] "--ansi" => Box::new(AnsiDialect {}), "--postgres" => Box::new(PostgreSqlDialect {}), "--ms" => Box::new(MsSqlDialect {}), + "--snowflake" => Box::new(SnowflakeDialect {}), "--generic" | "" => Box::new(GenericDialect {}), s => panic!("Unexpected parameter: {}", s), }; diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 91d69a33..e656ab26 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -16,6 +16,7 @@ pub mod keywords; mod mssql; mod mysql; mod postgresql; +mod snowflake; mod sqlite; use std::any::{Any, TypeId}; @@ -26,6 +27,7 @@ pub use self::generic::GenericDialect; pub use self::mssql::MsSqlDialect; pub use self::mysql::MySqlDialect; pub use self::postgresql::PostgreSqlDialect; +pub use self::snowflake::SnowflakeDialect; pub use self::sqlite::SQLiteDialect; /// `dialect_of!(parser is SQLiteDialect | GenericDialect)` evaluates diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs new file mode 100644 index 00000000..22fd55fa --- /dev/null +++ b/src/dialect/snowflake.rs @@ -0,0 +1,31 @@ +// 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, Default)] +pub struct SnowflakeDialect; + +impl Dialect for SnowflakeDialect { + // see https://docs.snowflake.com/en/sql-reference/identifiers-syntax.html + fn is_identifier_start(&self, ch: char) -> bool { + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' + } + + fn is_identifier_part(&self, ch: char) -> bool { + (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') + || (ch >= '0' && ch <= '9') + || ch == '$' + || ch == '_' + } +} diff --git a/src/test_utils.rs b/src/test_utils.rs index 848ea050..7d963606 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -119,6 +119,7 @@ pub fn all_dialects() -> TestedDialects { Box::new(PostgreSqlDialect {}), Box::new(MsSqlDialect {}), Box::new(AnsiDialect {}), + Box::new(SnowflakeDialect {}), ], } } diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs new file mode 100644 index 00000000..086d5726 --- /dev/null +++ b/tests/sqlparser_snowflake.rs @@ -0,0 +1,31 @@ +// 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 sqlparser::ast::*; +use sqlparser::dialect::{GenericDialect, SnowflakeDialect}; +use sqlparser::test_utils::*; + +#[test] +fn test_snowflake_create_table() { + let sql = "CREATE TABLE _my_$table (am00unt number)"; + match snowflake_and_generic().verified_stmt(sql) { + Statement::CreateTable { name, .. } => { + assert_eq!("_my_$table", name.to_string()); + } + _ => unreachable!(), + } +} + +fn snowflake_and_generic() -> TestedDialects { + TestedDialects { + dialects: vec![Box::new(SnowflakeDialect {}), Box::new(GenericDialect {})], + } +}