sqltk_parser/dialect/
mod.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18mod ansi;
19mod bigquery;
20mod clickhouse;
21mod databricks;
22mod duckdb;
23mod generic;
24mod hive;
25mod mssql;
26mod mysql;
27mod postgresql;
28mod redshift;
29mod snowflake;
30mod sqlite;
31
32use core::any::{Any, TypeId};
33use core::fmt::Debug;
34use core::iter::Peekable;
35use core::str::Chars;
36
37use log::debug;
38
39pub use self::ansi::AnsiDialect;
40pub use self::bigquery::BigQueryDialect;
41pub use self::clickhouse::ClickHouseDialect;
42pub use self::databricks::DatabricksDialect;
43pub use self::duckdb::DuckDbDialect;
44pub use self::generic::GenericDialect;
45pub use self::hive::HiveDialect;
46pub use self::mssql::MsSqlDialect;
47pub use self::mysql::MySqlDialect;
48pub use self::postgresql::PostgreSqlDialect;
49pub use self::redshift::RedshiftSqlDialect;
50pub use self::snowflake::SnowflakeDialect;
51pub use self::sqlite::SQLiteDialect;
52use crate::ast::{ColumnOption, Expr, Statement};
53pub use crate::keywords;
54use crate::keywords::Keyword;
55use crate::parser::{Parser, ParserError};
56use crate::tokenizer::Token;
57
58#[cfg(not(feature = "std"))]
59use alloc::boxed::Box;
60
61/// Convenience check if a [`Parser`] uses a certain dialect.
62///
63/// Note: when possible please the new style, adding a method to the [`Dialect`]
64/// trait rather than using this macro.
65///
66/// The benefits of adding a method on `Dialect` over this macro are:
67/// 1. user defined [`Dialect`]s can customize the parsing behavior
68/// 2. The differences between dialects can be clearly documented in the trait
69///
70/// `dialect_of!(parser is SQLiteDialect |  GenericDialect)` evaluates
71/// to `true` if `parser.dialect` is one of the [`Dialect`]s specified.
72macro_rules! dialect_of {
73    ( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
74        ($($parsed_dialect.dialect.is::<$dialect_type>())||+)
75    };
76}
77
78/// Encapsulates the differences between SQL implementations.
79///
80/// # SQL Dialects
81///
82/// SQL implementations deviate from one another, either due to
83/// custom extensions or various historical reasons. This trait
84/// encapsulates the parsing differences between dialects.
85///
86/// [`GenericDialect`] is the most permissive dialect, and parses the union of
87/// all the other dialects, when there is no ambiguity. However, it does not
88/// currently allow `CREATE TABLE` statements without types specified for all
89/// columns; use [`SQLiteDialect`] if you require that.
90///
91/// # Examples
92/// Most users create a [`Dialect`] directly, as shown on the [module
93/// level documentation]:
94///
95/// ```
96/// # use sqltk_parser::dialect::AnsiDialect;
97/// let dialect = AnsiDialect {};
98/// ```
99///
100/// It is also possible to dynamically create a [`Dialect`] from its
101/// name. For example:
102///
103/// ```
104/// # use sqltk_parser::dialect::{AnsiDialect, dialect_from_str};
105/// let dialect = dialect_from_str("ansi").unwrap();
106///
107/// // Parsed dialect is an instance of `AnsiDialect`:
108/// assert!(dialect.is::<AnsiDialect>());
109/// ```
110///
111/// [module level documentation]: crate
112pub trait Dialect: Debug + Any {
113    /// Determine the [`TypeId`] of this dialect.
114    ///
115    /// By default, return the same [`TypeId`] as [`Any::type_id`]. Can be overridden
116    /// by dialects that behave like other dialects
117    /// (for example when wrapping a dialect).
118    fn dialect(&self) -> TypeId {
119        self.type_id()
120    }
121
122    /// Determine if a character starts a quoted identifier. The default
123    /// implementation, accepting "double quoted" ids is both ANSI-compliant
124    /// and appropriate for most dialects (with the notable exception of
125    /// MySQL, MS SQL, and sqlite). You can accept one of characters listed
126    /// in `Word::matching_end_quote` here
127    fn is_delimited_identifier_start(&self, ch: char) -> bool {
128        ch == '"' || ch == '`'
129    }
130
131    /// Return the character used to quote identifiers.
132    fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
133        None
134    }
135
136    /// Determine if quoted characters are proper for identifier
137    fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
138        true
139    }
140
141    /// Determine if a character is a valid start character for an unquoted identifier
142    fn is_identifier_start(&self, ch: char) -> bool;
143
144    /// Determine if a character is a valid unquoted identifier character
145    fn is_identifier_part(&self, ch: char) -> bool;
146
147    /// Most dialects do not have custom operators. Override this method to provide custom operators.
148    fn is_custom_operator_part(&self, _ch: char) -> bool {
149        false
150    }
151
152    /// Determine if the dialect supports escaping characters via '\' in string literals.
153    ///
154    /// Some dialects like BigQuery and Snowflake support this while others like
155    /// Postgres do not. Such that the following is accepted by the former but
156    /// rejected by the latter.
157    /// ```sql
158    /// SELECT 'ab\'cd';
159    /// ```
160    ///
161    /// Conversely, such dialects reject the following statement which
162    /// otherwise would be valid in the other dialects.
163    /// ```sql
164    /// SELECT '\';
165    /// ```
166    fn supports_string_literal_backslash_escape(&self) -> bool {
167        false
168    }
169
170    /// Determine if the dialect supports string literals with `U&` prefix.
171    /// This is used to specify Unicode code points in string literals.
172    /// For example, in PostgreSQL, the following is a valid string literal:
173    /// ```sql
174    /// SELECT U&'\0061\0062\0063';
175    /// ```
176    /// This is equivalent to the string literal `'abc'`.
177    /// See
178    ///  - [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
179    ///  - [H2 docs](http://www.h2database.com/html/grammar.html#string)
180    fn supports_unicode_string_literal(&self) -> bool {
181        false
182    }
183
184    /// Does the dialect support `FILTER (WHERE expr)` for aggregate queries?
185    fn supports_filter_during_aggregation(&self) -> bool {
186        false
187    }
188
189    /// Returns true if the dialect supports referencing another named window
190    /// within a window clause declaration.
191    ///
192    /// Example
193    /// ```sql
194    /// SELECT * FROM mytable
195    /// WINDOW mynamed_window AS another_named_window
196    /// ```
197    fn supports_window_clause_named_window_reference(&self) -> bool {
198        false
199    }
200
201    /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions.
202    /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`]
203    ///
204    /// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function
205    fn supports_within_after_array_aggregation(&self) -> bool {
206        false
207    }
208
209    /// Returns true if the dialects supports `group sets, roll up, or cube` expressions.
210    fn supports_group_by_expr(&self) -> bool {
211        false
212    }
213
214    /// Returns true if the dialect supports CONNECT BY.
215    fn supports_connect_by(&self) -> bool {
216        false
217    }
218
219    /// Returns true if the dialect supports the MATCH_RECOGNIZE operation.
220    fn supports_match_recognize(&self) -> bool {
221        false
222    }
223
224    /// Returns true if the dialect supports `(NOT) IN ()` expressions
225    fn supports_in_empty_list(&self) -> bool {
226        false
227    }
228
229    /// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE} [TRANSACTION]` statements
230    fn supports_start_transaction_modifier(&self) -> bool {
231        false
232    }
233
234    /// Returns true if the dialect supports named arguments of the form FUN(a = '1', b = '2').
235    fn supports_named_fn_args_with_eq_operator(&self) -> bool {
236        false
237    }
238
239    /// Returns true if the dialect supports identifiers starting with a numeric
240    /// prefix such as tables named `59901_user_login`
241    fn supports_numeric_prefix(&self) -> bool {
242        false
243    }
244
245    /// Returns true if the dialects supports specifying null treatment
246    /// as part of a window function's parameter list as opposed
247    /// to after the parameter list.
248    ///
249    /// i.e The following syntax returns true
250    /// ```sql
251    /// FIRST_VALUE(a IGNORE NULLS) OVER ()
252    /// ```
253    /// while the following syntax returns false
254    /// ```sql
255    /// FIRST_VALUE(a) IGNORE NULLS OVER ()
256    /// ```
257    fn supports_window_function_null_treatment_arg(&self) -> bool {
258        false
259    }
260
261    /// Returns true if the dialect supports defining structs or objects using a
262    /// syntax like `{'x': 1, 'y': 2, 'z': 3}`.
263    fn supports_dictionary_syntax(&self) -> bool {
264        false
265    }
266
267    /// Returns true if the dialect supports defining object using the
268    /// syntax like `Map {1: 10, 2: 20}`.
269    fn support_map_literal_syntax(&self) -> bool {
270        false
271    }
272
273    /// Returns true if the dialect supports lambda functions, for example:
274    ///
275    /// ```sql
276    /// SELECT transform(array(1, 2, 3), x -> x + 1); -- returns [2,3,4]
277    /// ```
278    fn supports_lambda_functions(&self) -> bool {
279        false
280    }
281
282    /// Returns true if the dialect supports multiple variable assignment
283    /// using parentheses in a `SET` variable declaration.
284    ///
285    /// ```sql
286    /// SET (variable[, ...]) = (expression[, ...]);
287    /// ```
288    fn supports_parenthesized_set_variables(&self) -> bool {
289        false
290    }
291
292    /// Returns true if the dialect supports an `EXCEPT` clause following a
293    /// wildcard in a select list.
294    ///
295    /// For example
296    /// ```sql
297    /// SELECT * EXCEPT order_id FROM orders;
298    /// ```
299    fn supports_select_wildcard_except(&self) -> bool {
300        false
301    }
302
303    /// Returns true if the dialect has a CONVERT function which accepts a type first
304    /// and an expression second, e.g. `CONVERT(varchar, 1)`
305    fn convert_type_before_value(&self) -> bool {
306        false
307    }
308
309    /// Returns true if the dialect supports triple quoted string
310    /// e.g. `"""abc"""`
311    fn supports_triple_quoted_string(&self) -> bool {
312        false
313    }
314
315    /// Dialect-specific prefix parser override
316    fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
317        // return None to fall back to the default behavior
318        None
319    }
320
321    /// Does the dialect support trailing commas around the query?
322    fn supports_trailing_commas(&self) -> bool {
323        false
324    }
325
326    /// Does the dialect support parsing `LIMIT 1, 2` as `LIMIT 2 OFFSET 1`?
327    fn supports_limit_comma(&self) -> bool {
328        false
329    }
330
331    /// Does the dialect support trailing commas in the projection list?
332    fn supports_projection_trailing_commas(&self) -> bool {
333        self.supports_trailing_commas()
334    }
335
336    /// Dialect-specific infix parser override
337    ///
338    /// This method is called to parse the next infix expression.
339    ///
340    /// If `None` is returned, falls back to the default behavior.
341    fn parse_infix(
342        &self,
343        _parser: &mut Parser,
344        _expr: &Expr,
345        _precedence: u8,
346    ) -> Option<Result<Expr, ParserError>> {
347        // return None to fall back to the default behavior
348        None
349    }
350
351    /// Dialect-specific precedence override
352    ///
353    /// This method is called to get the precedence of the next token.
354    ///
355    /// If `None` is returned, falls back to the default behavior.
356    fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
357        // return None to fall back to the default behavior
358        None
359    }
360
361    /// Get the precedence of the next token, looking at the full token stream.
362    ///
363    /// A higher number => higher precedence
364    ///
365    /// See [`Self::get_next_precedence`] to override the behavior for just the
366    /// next token.
367    ///
368    /// The default implementation is used for many dialects, but can be
369    /// overridden to provide dialect-specific behavior.
370    fn get_next_precedence_default(&self, parser: &Parser) -> Result<u8, ParserError> {
371        if let Some(precedence) = self.get_next_precedence(parser) {
372            return precedence;
373        }
374        macro_rules! p {
375            ($precedence:ident) => {
376                self.prec_value(Precedence::$precedence)
377            };
378        }
379
380        let token = parser.peek_token();
381        debug!("get_next_precedence_full() {:?}", token);
382        match token.token {
383            Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
384            Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
385            Token::Word(w) if w.keyword == Keyword::XOR => Ok(p!(Xor)),
386
387            Token::Word(w) if w.keyword == Keyword::AT => {
388                match (
389                    parser.peek_nth_token(1).token,
390                    parser.peek_nth_token(2).token,
391                ) {
392                    (Token::Word(w), Token::Word(w2))
393                        if w.keyword == Keyword::TIME && w2.keyword == Keyword::ZONE =>
394                    {
395                        Ok(p!(AtTz))
396                    }
397                    _ => Ok(self.prec_unknown()),
398                }
399            }
400
401            Token::Word(w) if w.keyword == Keyword::NOT => match parser.peek_nth_token(1).token {
402                // The precedence of NOT varies depending on keyword that
403                // follows it. If it is followed by IN, BETWEEN, or LIKE,
404                // it takes on the precedence of those tokens. Otherwise, it
405                // is not an infix operator, and therefore has zero
406                // precedence.
407                Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
408                Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
409                Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
410                Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
411                Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
412                Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
413                Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
414                _ => Ok(self.prec_unknown()),
415            },
416            Token::Word(w) if w.keyword == Keyword::IS => Ok(p!(Is)),
417            Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
418            Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
419            Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
420            Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
421            Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
422            Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
423            Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
424            Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(p!(Between)),
425            Token::Word(w) if w.keyword == Keyword::DIV => Ok(p!(MulDivModOp)),
426            Token::Eq
427            | Token::Lt
428            | Token::LtEq
429            | Token::Neq
430            | Token::Gt
431            | Token::GtEq
432            | Token::DoubleEq
433            | Token::Tilde
434            | Token::TildeAsterisk
435            | Token::ExclamationMarkTilde
436            | Token::ExclamationMarkTildeAsterisk
437            | Token::DoubleTilde
438            | Token::DoubleTildeAsterisk
439            | Token::ExclamationMarkDoubleTilde
440            | Token::ExclamationMarkDoubleTildeAsterisk
441            | Token::Spaceship => Ok(p!(Eq)),
442            Token::Pipe => Ok(p!(Pipe)),
443            Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
444            Token::Ampersand => Ok(p!(Ampersand)),
445            Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
446            Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
447                Ok(p!(MulDivModOp))
448            }
449            Token::DoubleColon
450            | Token::ExclamationMark
451            | Token::LBracket
452            | Token::Overlap
453            | Token::CaretAt => Ok(p!(DoubleColon)),
454            Token::Arrow
455            | Token::LongArrow
456            | Token::HashArrow
457            | Token::HashLongArrow
458            | Token::AtArrow
459            | Token::ArrowAt
460            | Token::HashMinus
461            | Token::AtQuestion
462            | Token::AtAt
463            | Token::Question
464            | Token::QuestionAnd
465            | Token::QuestionPipe
466            | Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
467            _ => Ok(self.prec_unknown()),
468        }
469    }
470
471    /// Dialect-specific statement parser override
472    ///
473    /// This method is called to parse the next statement.
474    ///
475    /// If `None` is returned, falls back to the default behavior.
476    fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
477        // return None to fall back to the default behavior
478        None
479    }
480
481    /// Dialect-specific column option parser override
482    ///
483    /// This method is called to parse the next column option.
484    ///
485    /// If `None` is returned, falls back to the default behavior.
486    fn parse_column_option(
487        &self,
488        _parser: &mut Parser,
489    ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
490        // return None to fall back to the default behavior
491        Ok(None)
492    }
493
494    /// Decide the lexical Precedence of operators.
495    ///
496    /// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
497    fn prec_value(&self, prec: Precedence) -> u8 {
498        match prec {
499            Precedence::DoubleColon => 50,
500            Precedence::AtTz => 41,
501            Precedence::MulDivModOp => 40,
502            Precedence::PlusMinus => 30,
503            Precedence::Xor => 24,
504            Precedence::Ampersand => 23,
505            Precedence::Caret => 22,
506            Precedence::Pipe => 21,
507            Precedence::Between => 20,
508            Precedence::Eq => 20,
509            Precedence::Like => 19,
510            Precedence::Is => 17,
511            Precedence::PgOther => 16,
512            Precedence::UnaryNot => 15,
513            Precedence::And => 10,
514            Precedence::Or => 5,
515        }
516    }
517
518    /// Returns the precedence when the precedence is otherwise unknown
519    fn prec_unknown(&self) -> u8 {
520        0
521    }
522
523    /// Returns true if this dialect requires the `TABLE` keyword after `DESCRIBE`
524    ///
525    /// Defaults to false.
526    ///
527    /// If true, the following statement is valid: `DESCRIBE TABLE my_table`
528    /// If false, the following statements are valid: `DESCRIBE my_table` and `DESCRIBE table`
529    fn describe_requires_table_keyword(&self) -> bool {
530        false
531    }
532
533    /// Returns true if this dialect allows the `EXTRACT` function to words other than [`Keyword`].
534    fn allow_extract_custom(&self) -> bool {
535        false
536    }
537
538    /// Returns true if this dialect allows the `EXTRACT` function to use single quotes in the part being extracted.
539    fn allow_extract_single_quotes(&self) -> bool {
540        false
541    }
542
543    /// Does the dialect support with clause in create index statement?
544    /// e.g. `CREATE INDEX idx ON t WITH (key = value, key2)`
545    fn supports_create_index_with_clause(&self) -> bool {
546        false
547    }
548
549    /// Whether `INTERVAL` expressions require units (called "qualifiers" in the ANSI SQL spec) to be specified,
550    /// e.g. `INTERVAL 1 DAY` vs `INTERVAL 1`.
551    ///
552    /// Expressions within intervals (e.g. `INTERVAL '1' + '1' DAY`) are only allowed when units are required.
553    ///
554    /// See <https://github.com/sqlparser-rs/sqlparser-rs/pull/1398> for more information.
555    ///
556    /// When `true`:
557    /// * `INTERVAL '1' DAY` is VALID
558    /// * `INTERVAL 1 + 1 DAY` is VALID
559    /// * `INTERVAL '1' + '1' DAY` is VALID
560    /// * `INTERVAL '1'` is INVALID
561    ///
562    /// When `false`:
563    /// * `INTERVAL '1'` is VALID
564    /// * `INTERVAL '1' DAY` is VALID — unit is not required, but still allowed
565    /// * `INTERVAL 1 + 1 DAY` is INVALID
566    fn require_interval_qualifier(&self) -> bool {
567        false
568    }
569
570    fn supports_explain_with_utility_options(&self) -> bool {
571        false
572    }
573
574    fn supports_asc_desc_in_column_definition(&self) -> bool {
575        false
576    }
577
578    /// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
579    /// as an alias assignment operator, rather than a boolean expression.
580    /// For example: the following statements are equivalent for such a dialect:
581    /// ```sql
582    ///  SELECT col_alias = col FROM tbl;
583    ///  SELECT col_alias AS col FROM tbl;
584    /// ```
585    fn supports_eq_alias_assignment(&self) -> bool {
586        false
587    }
588
589    /// Returns true if this dialect supports the `TRY_CONVERT` function
590    fn supports_try_convert(&self) -> bool {
591        false
592    }
593
594    /// Returns true if the dialect supports the `LISTEN` statement
595    fn supports_listen(&self) -> bool {
596        false
597    }
598
599    /// Returns true if the dialect supports the `NOTIFY` statement
600    fn supports_notify(&self) -> bool {
601        false
602    }
603
604    /// Returns true if this dialect expects the the `TOP` option
605    /// before the `ALL`/`DISTINCT` options in a `SELECT` statement.
606    fn supports_top_before_distinct(&self) -> bool {
607        false
608    }
609}
610
611/// This represents the operators for which precedence must be defined
612///
613/// higher number -> higher precedence
614#[derive(Debug, Clone, Copy)]
615pub enum Precedence {
616    DoubleColon,
617    AtTz,
618    MulDivModOp,
619    PlusMinus,
620    Xor,
621    Ampersand,
622    Caret,
623    Pipe,
624    Between,
625    Eq,
626    Like,
627    Is,
628    PgOther,
629    UnaryNot,
630    And,
631    Or,
632}
633
634impl dyn Dialect {
635    #[inline]
636    pub fn is<T: Dialect>(&self) -> bool {
637        // borrowed from `Any` implementation
638        TypeId::of::<T>() == self.dialect()
639    }
640}
641
642/// Returns the built in [`Dialect`] corresponding to `dialect_name`.
643///
644/// See [`Dialect`] documentation for an example.
645pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
646    let dialect_name = dialect_name.as_ref();
647    match dialect_name.to_lowercase().as_str() {
648        "generic" => Some(Box::new(GenericDialect)),
649        "mysql" => Some(Box::new(MySqlDialect {})),
650        "postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
651        "hive" => Some(Box::new(HiveDialect {})),
652        "sqlite" => Some(Box::new(SQLiteDialect {})),
653        "snowflake" => Some(Box::new(SnowflakeDialect)),
654        "redshift" => Some(Box::new(RedshiftSqlDialect {})),
655        "mssql" => Some(Box::new(MsSqlDialect {})),
656        "clickhouse" => Some(Box::new(ClickHouseDialect {})),
657        "bigquery" => Some(Box::new(BigQueryDialect)),
658        "ansi" => Some(Box::new(AnsiDialect {})),
659        "duckdb" => Some(Box::new(DuckDbDialect {})),
660        "databricks" => Some(Box::new(DatabricksDialect {})),
661        _ => None,
662    }
663}
664
665#[cfg(test)]
666mod tests {
667    use super::*;
668
669    struct DialectHolder<'a> {
670        dialect: &'a dyn Dialect,
671    }
672
673    #[test]
674    fn test_is_dialect() {
675        let generic_dialect: &dyn Dialect = &GenericDialect {};
676        let ansi_dialect: &dyn Dialect = &AnsiDialect {};
677
678        let generic_holder = DialectHolder {
679            dialect: generic_dialect,
680        };
681        let ansi_holder = DialectHolder {
682            dialect: ansi_dialect,
683        };
684
685        assert!(dialect_of!(generic_holder is GenericDialect |  AnsiDialect),);
686        assert!(!dialect_of!(generic_holder is  AnsiDialect));
687        assert!(dialect_of!(ansi_holder is AnsiDialect));
688        assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
689        assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
690    }
691
692    #[test]
693    fn test_dialect_from_str() {
694        assert!(parse_dialect("generic").is::<GenericDialect>());
695        assert!(parse_dialect("mysql").is::<MySqlDialect>());
696        assert!(parse_dialect("MySql").is::<MySqlDialect>());
697        assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
698        assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
699        assert!(parse_dialect("hive").is::<HiveDialect>());
700        assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
701        assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
702        assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
703        assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
704        assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
705        assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
706        assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
707        assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
708        assert!(parse_dialect("ansi").is::<AnsiDialect>());
709        assert!(parse_dialect("ANSI").is::<AnsiDialect>());
710        assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
711        assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
712        assert!(parse_dialect("DataBricks").is::<DatabricksDialect>());
713        assert!(parse_dialect("databricks").is::<DatabricksDialect>());
714
715        // error cases
716        assert!(dialect_from_str("Unknown").is_none());
717        assert!(dialect_from_str("").is_none());
718    }
719
720    fn parse_dialect(v: &str) -> Box<dyn Dialect> {
721        dialect_from_str(v).unwrap()
722    }
723
724    #[test]
725    fn identifier_quote_style() {
726        let tests: Vec<(&dyn Dialect, &str, Option<char>)> = vec![
727            (&GenericDialect {}, "id", None),
728            (&SQLiteDialect {}, "id", Some('`')),
729            (&PostgreSqlDialect {}, "id", Some('"')),
730        ];
731
732        for (dialect, ident, expected) in tests {
733            let actual = dialect.identifier_quote_style(ident);
734
735            assert_eq!(actual, expected);
736        }
737    }
738
739    #[test]
740    fn parse_with_wrapped_dialect() {
741        /// Wrapper for a dialect. In a real-world example, this wrapper
742        /// would tweak the behavior of the dialect. For the test case,
743        /// it wraps all methods unaltered.
744        #[derive(Debug)]
745        struct WrappedDialect(MySqlDialect);
746
747        impl Dialect for WrappedDialect {
748            fn dialect(&self) -> std::any::TypeId {
749                self.0.dialect()
750            }
751
752            fn is_identifier_start(&self, ch: char) -> bool {
753                self.0.is_identifier_start(ch)
754            }
755
756            fn is_delimited_identifier_start(&self, ch: char) -> bool {
757                self.0.is_delimited_identifier_start(ch)
758            }
759
760            fn identifier_quote_style(&self, identifier: &str) -> Option<char> {
761                self.0.identifier_quote_style(identifier)
762            }
763
764            fn supports_string_literal_backslash_escape(&self) -> bool {
765                self.0.supports_string_literal_backslash_escape()
766            }
767
768            fn is_proper_identifier_inside_quotes(
769                &self,
770                chars: std::iter::Peekable<std::str::Chars<'_>>,
771            ) -> bool {
772                self.0.is_proper_identifier_inside_quotes(chars)
773            }
774
775            fn supports_filter_during_aggregation(&self) -> bool {
776                self.0.supports_filter_during_aggregation()
777            }
778
779            fn supports_within_after_array_aggregation(&self) -> bool {
780                self.0.supports_within_after_array_aggregation()
781            }
782
783            fn supports_group_by_expr(&self) -> bool {
784                self.0.supports_group_by_expr()
785            }
786
787            fn supports_in_empty_list(&self) -> bool {
788                self.0.supports_in_empty_list()
789            }
790
791            fn convert_type_before_value(&self) -> bool {
792                self.0.convert_type_before_value()
793            }
794
795            fn parse_prefix(
796                &self,
797                parser: &mut sqltk_parser::parser::Parser,
798            ) -> Option<Result<Expr, sqltk_parser::parser::ParserError>> {
799                self.0.parse_prefix(parser)
800            }
801
802            fn parse_infix(
803                &self,
804                parser: &mut sqltk_parser::parser::Parser,
805                expr: &Expr,
806                precedence: u8,
807            ) -> Option<Result<Expr, sqltk_parser::parser::ParserError>> {
808                self.0.parse_infix(parser, expr, precedence)
809            }
810
811            fn get_next_precedence(
812                &self,
813                parser: &sqltk_parser::parser::Parser,
814            ) -> Option<Result<u8, sqltk_parser::parser::ParserError>> {
815                self.0.get_next_precedence(parser)
816            }
817
818            fn parse_statement(
819                &self,
820                parser: &mut sqltk_parser::parser::Parser,
821            ) -> Option<Result<Statement, sqltk_parser::parser::ParserError>> {
822                self.0.parse_statement(parser)
823            }
824
825            fn is_identifier_part(&self, ch: char) -> bool {
826                self.0.is_identifier_part(ch)
827            }
828        }
829
830        #[allow(clippy::needless_raw_string_hashes)]
831        let statement = r#"SELECT 'Wayne\'s World'"#;
832        let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
833        let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
834        assert!(res1.is_ok());
835        assert_eq!(res1, res2);
836    }
837}