1mod ansi;
14mod bigquery;
15mod clickhouse;
16mod duckdb;
17mod generic;
18mod hive;
19mod mssql;
20mod mysql;
21mod postgresql;
22mod redshift;
23mod snowflake;
24mod sqlite;
25
26use crate::ast::{Expr, Statement};
27use core::any::{Any, TypeId};
28use core::fmt::Debug;
29use core::iter::Peekable;
30use core::str::Chars;
31
32pub use self::ansi::AnsiDialect;
33pub use self::bigquery::BigQueryDialect;
34pub use self::clickhouse::ClickHouseDialect;
35pub use self::duckdb::DuckDbDialect;
36pub use self::generic::GenericDialect;
37pub use self::hive::HiveDialect;
38pub use self::mssql::MsSqlDialect;
39pub use self::mysql::MySqlDialect;
40pub use self::postgresql::PostgreSqlDialect;
41pub use self::redshift::RedshiftSqlDialect;
42pub use self::snowflake::SnowflakeDialect;
43pub use self::sqlite::SQLiteDialect;
44pub use crate::keywords;
45use crate::parser::{Parser, ParserError};
46
47#[cfg(not(feature = "std"))]
48use alloc::boxed::Box;
49
50macro_rules! dialect_of {
55 ( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
56 ($($parsed_dialect.dialect.is::<$dialect_type>())||+)
57 };
58}
59
60pub trait Dialect: Debug + Any {
92 fn is_delimited_identifier_start(&self, ch: char) -> bool {
98 ch == '"' || ch == '`'
99 }
100 fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
102 true
103 }
104 fn is_identifier_start(&self, ch: char) -> bool;
106 fn is_identifier_part(&self, ch: char) -> bool;
108 fn supports_filter_during_aggregation(&self) -> bool {
110 false
111 }
112 fn supports_within_after_array_aggregation(&self) -> bool {
117 false
118 }
119 fn supports_group_by_expr(&self) -> bool {
121 false
122 }
123 fn supports_substring_from_for_expr(&self) -> bool {
125 true
126 }
127 fn supports_in_empty_list(&self) -> bool {
129 false
130 }
131 fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
133 None
135 }
136 fn parse_infix(
138 &self,
139 _parser: &mut Parser,
140 _expr: &Expr,
141 _precedence: u8,
142 ) -> Option<Result<Expr, ParserError>> {
143 None
145 }
146 fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
148 None
150 }
151 fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
153 None
155 }
156}
157
158impl dyn Dialect {
159 #[inline]
160 pub fn is<T: Dialect>(&self) -> bool {
161 TypeId::of::<T>() == self.type_id()
163 }
164}
165
166pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
170 let dialect_name = dialect_name.as_ref();
171 match dialect_name.to_lowercase().as_str() {
172 "generic" => Some(Box::new(GenericDialect)),
173 "mysql" => Some(Box::new(MySqlDialect {})),
174 "postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
175 "hive" => Some(Box::new(HiveDialect {})),
176 "sqlite" => Some(Box::new(SQLiteDialect {})),
177 "snowflake" => Some(Box::new(SnowflakeDialect)),
178 "redshift" => Some(Box::new(RedshiftSqlDialect {})),
179 "mssql" => Some(Box::new(MsSqlDialect {})),
180 "clickhouse" => Some(Box::new(ClickHouseDialect {})),
181 "bigquery" => Some(Box::new(BigQueryDialect)),
182 "ansi" => Some(Box::new(AnsiDialect {})),
183 "duckdb" => Some(Box::new(DuckDbDialect {})),
184 _ => None,
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::ansi::AnsiDialect;
191 use super::generic::GenericDialect;
192 use super::*;
193
194 struct DialectHolder<'a> {
195 dialect: &'a dyn Dialect,
196 }
197
198 #[test]
199 fn test_is_dialect() {
200 let generic_dialect: &dyn Dialect = &GenericDialect {};
201 let ansi_dialect: &dyn Dialect = &AnsiDialect {};
202
203 let generic_holder = DialectHolder {
204 dialect: generic_dialect,
205 };
206 let ansi_holder = DialectHolder {
207 dialect: ansi_dialect,
208 };
209
210 assert!(dialect_of!(generic_holder is GenericDialect | AnsiDialect),);
211 assert!(!dialect_of!(generic_holder is AnsiDialect));
212 assert!(dialect_of!(ansi_holder is AnsiDialect));
213 assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
214 assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
215 }
216
217 #[test]
218 fn test_dialect_from_str() {
219 assert!(parse_dialect("generic").is::<GenericDialect>());
220 assert!(parse_dialect("mysql").is::<MySqlDialect>());
221 assert!(parse_dialect("MySql").is::<MySqlDialect>());
222 assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
223 assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
224 assert!(parse_dialect("hive").is::<HiveDialect>());
225 assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
226 assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
227 assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
228 assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
229 assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
230 assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
231 assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
232 assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
233 assert!(parse_dialect("ansi").is::<AnsiDialect>());
234 assert!(parse_dialect("ANSI").is::<AnsiDialect>());
235 assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
236 assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
237
238 assert!(dialect_from_str("Unknown").is_none());
240 assert!(dialect_from_str("").is_none());
241 }
242
243 fn parse_dialect(v: &str) -> Box<dyn Dialect> {
244 dialect_from_str(v).unwrap()
245 }
246}