sqlparser/dialect/
mod.rs

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
13mod 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
50/// Convenience check if a [`Parser`] uses a certain dialect.
51///
52/// `dialect_of!(parser Is SQLiteDialect |  GenericDialect)` evaluates
53/// to `true` if `parser.dialect` is one of the [`Dialect`]s specified.
54macro_rules! dialect_of {
55    ( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
56        ($($parsed_dialect.dialect.is::<$dialect_type>())||+)
57    };
58}
59
60/// Encapsulates the differences between SQL implementations.
61///
62/// # SQL Dialects
63/// SQL implementations deviatiate from one another, either due to
64/// custom extensions or various historical reasons. This trait
65/// encapsulates the parsing differences between dialects.
66///
67/// [`GenericDialect`] is the most permissive dialect, and parses the union of
68/// all the other dialects, when there is no ambiguity. However, it does not
69/// currently allow `CREATE TABLE` statements without types specified for all
70/// columns; use [`SQLiteDialect`] if you require that.
71///
72/// # Examples
73/// Most users create a [`Dialect`] directly, as shown on the [module
74/// level documentation]:
75///
76/// ```
77/// # use sqlparser::dialect::AnsiDialect;
78/// let dialect = AnsiDialect {};
79/// ```
80///
81/// It is also possible to dynamically create a [`Dialect`] from its
82/// name. For example:
83///
84/// ```
85/// # use sqlparser::dialect::{AnsiDialect, dialect_from_str};
86/// let dialect = dialect_from_str("ansi").unwrap();
87///
88/// // Parsed dialect is an instance of `AnsiDialect`:
89/// assert!(dialect.is::<AnsiDialect>());
90/// ```
91///
92/// [module level documentation]: crate
93pub trait Dialect: Debug + Any {
94    /// Determine the [`TypeId`] of this dialect.
95    ///
96    /// By default, return the same [`TypeId`] as [`Any::type_id`]. Can be overriden
97    /// by dialects that behave like other dialects
98    /// (for example when wrapping a dialect).
99    fn dialect(&self) -> TypeId {
100        self.type_id()
101    }
102
103    /// Determine if a character starts a quoted identifier. The default
104    /// implementation, accepting "double quoted" ids is both ANSI-compliant
105    /// and appropriate for most dialects (with the notable exception of
106    /// MySQL, MS SQL, and sqlite). You can accept one of characters listed
107    /// in `Word::matching_end_quote` here
108    fn is_delimited_identifier_start(&self, ch: char) -> bool {
109        ch == '"' || ch == '`'
110    }
111    /// Determine if quoted characters are proper for identifier
112    fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
113        true
114    }
115    /// Determine if a character is a valid start character for an unquoted identifier
116    fn is_identifier_start(&self, ch: char) -> bool;
117    /// Determine if a character is a valid unquoted identifier character
118    fn is_identifier_part(&self, ch: char) -> bool;
119    /// Does the dialect support `FILTER (WHERE expr)` for aggregate queries?
120    fn supports_filter_during_aggregation(&self) -> bool {
121        false
122    }
123    /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions.
124    /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`]
125    ///
126    /// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function
127    fn supports_within_after_array_aggregation(&self) -> bool {
128        false
129    }
130    /// Returns true if the dialects supports `group sets, roll up, or cube` expressions.
131    fn supports_group_by_expr(&self) -> bool {
132        false
133    }
134    /// Returns true if the dialect supports `SUBSTRING(expr [FROM start] [FOR len])` expressions
135    fn supports_substring_from_for_expr(&self) -> bool {
136        true
137    }
138    /// Returns true if the dialect supports `(NOT) IN ()` expressions
139    fn supports_in_empty_list(&self) -> bool {
140        false
141    }
142    /// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE} [TRANSACTION]` statements
143    fn supports_start_transaction_modifier(&self) -> bool {
144        false
145    }
146    /// Returns true if the dialect has a CONVERT function which accepts a type first
147    /// and an expression second, e.g. `CONVERT(varchar, 1)`
148    fn convert_type_before_value(&self) -> bool {
149        false
150    }
151    /// Dialect-specific prefix parser override
152    fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
153        // return None to fall back to the default behavior
154        None
155    }
156    /// Dialect-specific infix parser override
157    fn parse_infix(
158        &self,
159        _parser: &mut Parser,
160        _expr: &Expr,
161        _precedence: u8,
162    ) -> Option<Result<Expr, ParserError>> {
163        // return None to fall back to the default behavior
164        None
165    }
166    /// Dialect-specific precedence override
167    fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
168        // return None to fall back to the default behavior
169        None
170    }
171    /// Dialect-specific statement parser override
172    fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
173        // return None to fall back to the default behavior
174        None
175    }
176}
177
178impl dyn Dialect {
179    #[inline]
180    pub fn is<T: Dialect>(&self) -> bool {
181        // borrowed from `Any` implementation
182        TypeId::of::<T>() == self.dialect()
183    }
184}
185
186/// Returns the built in [`Dialect`] corresponding to `dialect_name`.
187///
188/// See [`Dialect`] documentation for an example.
189pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
190    let dialect_name = dialect_name.as_ref();
191    match dialect_name.to_lowercase().as_str() {
192        "generic" => Some(Box::new(GenericDialect)),
193        "mysql" => Some(Box::new(MySqlDialect {})),
194        "postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
195        "hive" => Some(Box::new(HiveDialect {})),
196        "sqlite" => Some(Box::new(SQLiteDialect {})),
197        "snowflake" => Some(Box::new(SnowflakeDialect)),
198        "redshift" => Some(Box::new(RedshiftSqlDialect {})),
199        "mssql" => Some(Box::new(MsSqlDialect {})),
200        "clickhouse" => Some(Box::new(ClickHouseDialect {})),
201        "bigquery" => Some(Box::new(BigQueryDialect)),
202        "ansi" => Some(Box::new(AnsiDialect {})),
203        "duckdb" => Some(Box::new(DuckDbDialect {})),
204        _ => None,
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use super::ansi::AnsiDialect;
211    use super::generic::GenericDialect;
212    use super::*;
213
214    struct DialectHolder<'a> {
215        dialect: &'a dyn Dialect,
216    }
217
218    #[test]
219    fn test_is_dialect() {
220        let generic_dialect: &dyn Dialect = &GenericDialect {};
221        let ansi_dialect: &dyn Dialect = &AnsiDialect {};
222
223        let generic_holder = DialectHolder {
224            dialect: generic_dialect,
225        };
226        let ansi_holder = DialectHolder {
227            dialect: ansi_dialect,
228        };
229
230        assert!(dialect_of!(generic_holder is GenericDialect |  AnsiDialect),);
231        assert!(!dialect_of!(generic_holder is  AnsiDialect));
232        assert!(dialect_of!(ansi_holder is AnsiDialect));
233        assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
234        assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
235    }
236
237    #[test]
238    fn test_dialect_from_str() {
239        assert!(parse_dialect("generic").is::<GenericDialect>());
240        assert!(parse_dialect("mysql").is::<MySqlDialect>());
241        assert!(parse_dialect("MySql").is::<MySqlDialect>());
242        assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
243        assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
244        assert!(parse_dialect("hive").is::<HiveDialect>());
245        assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
246        assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
247        assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
248        assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
249        assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
250        assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
251        assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
252        assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
253        assert!(parse_dialect("ansi").is::<AnsiDialect>());
254        assert!(parse_dialect("ANSI").is::<AnsiDialect>());
255        assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
256        assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
257
258        // error cases
259        assert!(dialect_from_str("Unknown").is_none());
260        assert!(dialect_from_str("").is_none());
261    }
262
263    fn parse_dialect(v: &str) -> Box<dyn Dialect> {
264        dialect_from_str(v).unwrap()
265    }
266
267    #[test]
268    fn parse_with_wrapped_dialect() {
269        /// Wrapper for a dialect. In a real-world example, this wrapper
270        /// would tweak the behavior of the dialect. For the test case,
271        /// it wraps all methods unaltered.
272        #[derive(Debug)]
273        struct WrappedDialect(MySqlDialect);
274
275        impl Dialect for WrappedDialect {
276            fn dialect(&self) -> std::any::TypeId {
277                self.0.dialect()
278            }
279
280            fn is_identifier_start(&self, ch: char) -> bool {
281                self.0.is_identifier_start(ch)
282            }
283
284            fn is_delimited_identifier_start(&self, ch: char) -> bool {
285                self.0.is_delimited_identifier_start(ch)
286            }
287
288            fn is_proper_identifier_inside_quotes(
289                &self,
290                chars: std::iter::Peekable<std::str::Chars<'_>>,
291            ) -> bool {
292                self.0.is_proper_identifier_inside_quotes(chars)
293            }
294
295            fn supports_filter_during_aggregation(&self) -> bool {
296                self.0.supports_filter_during_aggregation()
297            }
298
299            fn supports_within_after_array_aggregation(&self) -> bool {
300                self.0.supports_within_after_array_aggregation()
301            }
302
303            fn supports_group_by_expr(&self) -> bool {
304                self.0.supports_group_by_expr()
305            }
306
307            fn supports_substring_from_for_expr(&self) -> bool {
308                self.0.supports_substring_from_for_expr()
309            }
310
311            fn supports_in_empty_list(&self) -> bool {
312                self.0.supports_in_empty_list()
313            }
314
315            fn convert_type_before_value(&self) -> bool {
316                self.0.convert_type_before_value()
317            }
318
319            fn parse_prefix(
320                &self,
321                parser: &mut sqlparser::parser::Parser,
322            ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
323                self.0.parse_prefix(parser)
324            }
325
326            fn parse_infix(
327                &self,
328                parser: &mut sqlparser::parser::Parser,
329                expr: &Expr,
330                precedence: u8,
331            ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
332                self.0.parse_infix(parser, expr, precedence)
333            }
334
335            fn get_next_precedence(
336                &self,
337                parser: &sqlparser::parser::Parser,
338            ) -> Option<Result<u8, sqlparser::parser::ParserError>> {
339                self.0.get_next_precedence(parser)
340            }
341
342            fn parse_statement(
343                &self,
344                parser: &mut sqlparser::parser::Parser,
345            ) -> Option<Result<Statement, sqlparser::parser::ParserError>> {
346                self.0.parse_statement(parser)
347            }
348
349            fn is_identifier_part(&self, ch: char) -> bool {
350                self.0.is_identifier_part(ch)
351            }
352        }
353
354        #[allow(clippy::needless_raw_string_hashes)]
355        let statement = r#"SELECT 'Wayne\'s World'"#;
356        let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
357        let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
358        assert!(res1.is_ok());
359        assert_eq!(res1, res2);
360    }
361}