sqlparser/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, GranteesType, Ident, ObjectNamePart, 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// Similar to above, but for applying directly against an instance of dialect
79// instead of a struct member named dialect. This avoids lifetime issues when
80// mixing match guards and token references.
81macro_rules! dialect_is {
82    ($dialect:ident is $($dialect_type:ty)|+) => {
83        ($($dialect.is::<$dialect_type>())||+)
84    }
85}
86
87/// Encapsulates the differences between SQL implementations.
88///
89/// # SQL Dialects
90///
91/// SQL implementations deviate from one another, either due to
92/// custom extensions or various historical reasons. This trait
93/// encapsulates the parsing differences between dialects.
94///
95/// [`GenericDialect`] is the most permissive dialect, and parses the union of
96/// all the other dialects, when there is no ambiguity. However, it does not
97/// currently allow `CREATE TABLE` statements without types specified for all
98/// columns; use [`SQLiteDialect`] if you require that.
99///
100/// # Examples
101/// Most users create a [`Dialect`] directly, as shown on the [module
102/// level documentation]:
103///
104/// ```
105/// # use sqlparser::dialect::AnsiDialect;
106/// let dialect = AnsiDialect {};
107/// ```
108///
109/// It is also possible to dynamically create a [`Dialect`] from its
110/// name. For example:
111///
112/// ```
113/// # use sqlparser::dialect::{AnsiDialect, dialect_from_str};
114/// let dialect = dialect_from_str("ansi").unwrap();
115///
116/// // Parsed dialect is an instance of `AnsiDialect`:
117/// assert!(dialect.is::<AnsiDialect>());
118/// ```
119///
120/// [module level documentation]: crate
121pub trait Dialect: Debug + Any {
122    /// Determine the [`TypeId`] of this dialect.
123    ///
124    /// By default, return the same [`TypeId`] as [`Any::type_id`]. Can be overridden
125    /// by dialects that behave like other dialects
126    /// (for example when wrapping a dialect).
127    fn dialect(&self) -> TypeId {
128        self.type_id()
129    }
130
131    /// Determine if a character starts a quoted identifier. The default
132    /// implementation, accepting "double quoted" ids is both ANSI-compliant
133    /// and appropriate for most dialects (with the notable exception of
134    /// MySQL, MS SQL, and sqlite). You can accept one of characters listed
135    /// in `Word::matching_end_quote` here
136    fn is_delimited_identifier_start(&self, ch: char) -> bool {
137        ch == '"' || ch == '`'
138    }
139
140    /// Determine if a character starts a potential nested quoted identifier.
141    /// Example: RedShift supports the following quote styles to all mean the same thing:
142    /// ```sql
143    /// SELECT 1 AS foo;
144    /// SELECT 1 AS "foo";
145    /// SELECT 1 AS [foo];
146    /// SELECT 1 AS ["foo"];
147    /// ```
148    fn is_nested_delimited_identifier_start(&self, _ch: char) -> bool {
149        false
150    }
151
152    /// Only applicable whenever [`Self::is_nested_delimited_identifier_start`] returns true
153    /// If the next sequence of tokens potentially represent a nested identifier, then this method
154    /// returns a tuple containing the outer quote style, and if present, the inner (nested) quote style.
155    ///
156    /// Example (Redshift):
157    /// ```text
158    /// `["foo"]` => Some(`[`, Some(`"`))
159    /// `[foo]` => Some(`[`, None)
160    /// `[0]` => None
161    /// `"foo"` => None
162    /// ```
163    fn peek_nested_delimited_identifier_quotes(
164        &self,
165        mut _chars: Peekable<Chars<'_>>,
166    ) -> Option<(char, Option<char>)> {
167        None
168    }
169
170    /// Return the character used to quote identifiers.
171    fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
172        None
173    }
174
175    /// Determine if a character is a valid start character for an unquoted identifier
176    fn is_identifier_start(&self, ch: char) -> bool;
177
178    /// Determine if a character is a valid unquoted identifier character
179    fn is_identifier_part(&self, ch: char) -> bool;
180
181    /// Most dialects do not have custom operators. Override this method to provide custom operators.
182    fn is_custom_operator_part(&self, _ch: char) -> bool {
183        false
184    }
185
186    /// Determine if the dialect supports escaping characters via '\' in string literals.
187    ///
188    /// Some dialects like BigQuery and Snowflake support this while others like
189    /// Postgres do not. Such that the following is accepted by the former but
190    /// rejected by the latter.
191    /// ```sql
192    /// SELECT 'ab\'cd';
193    /// ```
194    ///
195    /// Conversely, such dialects reject the following statement which
196    /// otherwise would be valid in the other dialects.
197    /// ```sql
198    /// SELECT '\';
199    /// ```
200    fn supports_string_literal_backslash_escape(&self) -> bool {
201        false
202    }
203
204    /// Determine whether the dialect strips the backslash when escaping LIKE wildcards (%, _).
205    ///
206    /// [MySQL] has a special case when escaping single quoted strings which leaves these unescaped
207    /// so they can be used in LIKE patterns without double-escaping (as is necessary in other
208    /// escaping dialects, such as [Snowflake]). Generally, special characters have escaping rules
209    /// causing them to be replaced with a different byte sequences (e.g. `'\0'` becoming the zero
210    /// byte), and the default if an escaped character does not have a specific escaping rule is to
211    /// strip the backslash (e.g. there is no rule for `h`, so `'\h' = 'h'`). MySQL's special case
212    /// for ignoring LIKE wildcard escapes is to *not* strip the backslash, so that `'\%' = '\\%'`.
213    /// This applies to all string literals though, not just those used in LIKE patterns.
214    ///
215    /// ```text
216    /// mysql> select '\_', hex('\\'), hex('_'), hex('\_');
217    /// +----+-----------+----------+-----------+
218    /// | \_ | hex('\\') | hex('_') | hex('\_') |
219    /// +----+-----------+----------+-----------+
220    /// | \_ | 5C        | 5F       | 5C5F      |
221    /// +----+-----------+----------+-----------+
222    /// 1 row in set (0.00 sec)
223    /// ```
224    ///
225    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/string-literals.html
226    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/functions/like#usage-notes
227    fn ignores_wildcard_escapes(&self) -> bool {
228        false
229    }
230
231    /// Determine if the dialect supports string literals with `U&` prefix.
232    /// This is used to specify Unicode code points in string literals.
233    /// For example, in PostgreSQL, the following is a valid string literal:
234    /// ```sql
235    /// SELECT U&'\0061\0062\0063';
236    /// ```
237    /// This is equivalent to the string literal `'abc'`.
238    /// See
239    ///  - [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
240    ///  - [H2 docs](http://www.h2database.com/html/grammar.html#string)
241    fn supports_unicode_string_literal(&self) -> bool {
242        false
243    }
244
245    /// Does the dialect support `FILTER (WHERE expr)` for aggregate queries?
246    fn supports_filter_during_aggregation(&self) -> bool {
247        false
248    }
249
250    /// Returns true if the dialect supports referencing another named window
251    /// within a window clause declaration.
252    ///
253    /// Example
254    /// ```sql
255    /// SELECT * FROM mytable
256    /// WINDOW mynamed_window AS another_named_window
257    /// ```
258    fn supports_window_clause_named_window_reference(&self) -> bool {
259        false
260    }
261
262    /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions.
263    /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`]
264    ///
265    /// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function
266    fn supports_within_after_array_aggregation(&self) -> bool {
267        false
268    }
269
270    /// Returns true if the dialects supports `group sets, roll up, or cube` expressions.
271    fn supports_group_by_expr(&self) -> bool {
272        false
273    }
274
275    /// Returns true if the dialects supports `GROUP BY` modifiers prefixed by a `WITH` keyword.
276    /// Example: `GROUP BY value WITH ROLLUP`.
277    fn supports_group_by_with_modifier(&self) -> bool {
278        false
279    }
280
281    /// Indicates whether the dialect supports left-associative join parsing
282    /// by default when parentheses are omitted in nested joins.
283    ///
284    /// Most dialects (like MySQL or Postgres) assume **left-associative** precedence,
285    /// so a query like:
286    ///
287    /// ```sql
288    /// SELECT * FROM t1 NATURAL JOIN t5 INNER JOIN t0 ON ...
289    /// ```
290    /// is interpreted as:
291    /// ```sql
292    /// ((t1 NATURAL JOIN t5) INNER JOIN t0 ON ...)
293    /// ```
294    /// and internally represented as a **flat list** of joins.
295    ///
296    /// In contrast, some dialects (e.g. **Snowflake**) assume **right-associative**
297    /// precedence and interpret the same query as:
298    /// ```sql
299    /// (t1 NATURAL JOIN (t5 INNER JOIN t0 ON ...))
300    /// ```
301    /// which results in a **nested join** structure in the AST.
302    ///
303    /// If this method returns `false`, the parser must build nested join trees
304    /// even in the absence of parentheses to reflect the correct associativity
305    fn supports_left_associative_joins_without_parens(&self) -> bool {
306        true
307    }
308
309    /// Returns true if the dialect supports the `(+)` syntax for OUTER JOIN.
310    fn supports_outer_join_operator(&self) -> bool {
311        false
312    }
313
314    /// Returns true if the dialect supports CONNECT BY.
315    fn supports_connect_by(&self) -> bool {
316        false
317    }
318
319    /// Returns true if the dialect supports `EXECUTE IMMEDIATE` statements.
320    fn supports_execute_immediate(&self) -> bool {
321        false
322    }
323
324    /// Returns true if the dialect supports the MATCH_RECOGNIZE operation.
325    fn supports_match_recognize(&self) -> bool {
326        false
327    }
328
329    /// Returns true if the dialect supports `(NOT) IN ()` expressions
330    fn supports_in_empty_list(&self) -> bool {
331        false
332    }
333
334    /// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE | TRY | CATCH} [TRANSACTION]` statements
335    fn supports_start_transaction_modifier(&self) -> bool {
336        false
337    }
338
339    /// Returns true if the dialect supports `END {TRY | CATCH}` statements
340    fn supports_end_transaction_modifier(&self) -> bool {
341        false
342    }
343
344    /// Returns true if the dialect supports named arguments of the form `FUN(a = '1', b = '2')`.
345    fn supports_named_fn_args_with_eq_operator(&self) -> bool {
346        false
347    }
348
349    /// Returns true if the dialect supports named arguments of the form `FUN(a : '1', b : '2')`.
350    fn supports_named_fn_args_with_colon_operator(&self) -> bool {
351        false
352    }
353
354    /// Returns true if the dialect supports named arguments of the form `FUN(a := '1', b := '2')`.
355    fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
356        false
357    }
358
359    /// Returns true if the dialect supports named arguments of the form `FUN(a => '1', b => '2')`.
360    fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
361        true
362    }
363
364    /// Returns true if dialect supports argument name as arbitrary expression.
365    /// e.g. `FUN(LOWER('a'):'1',  b:'2')`
366    /// Such function arguments are represented in the AST by the `FunctionArg::ExprNamed` variant,
367    /// otherwise use the `FunctionArg::Named` variant (compatible reason).
368    fn supports_named_fn_args_with_expr_name(&self) -> bool {
369        false
370    }
371
372    /// Returns true if the dialect supports identifiers starting with a numeric
373    /// prefix such as tables named `59901_user_login`
374    fn supports_numeric_prefix(&self) -> bool {
375        false
376    }
377
378    /// Returns true if the dialect supports numbers containing underscores, e.g. `10_000_000`
379    fn supports_numeric_literal_underscores(&self) -> bool {
380        false
381    }
382
383    /// Returns true if the dialects supports specifying null treatment
384    /// as part of a window function's parameter list as opposed
385    /// to after the parameter list.
386    ///
387    /// i.e The following syntax returns true
388    /// ```sql
389    /// FIRST_VALUE(a IGNORE NULLS) OVER ()
390    /// ```
391    /// while the following syntax returns false
392    /// ```sql
393    /// FIRST_VALUE(a) IGNORE NULLS OVER ()
394    /// ```
395    fn supports_window_function_null_treatment_arg(&self) -> bool {
396        false
397    }
398
399    /// Returns true if the dialect supports defining structs or objects using a
400    /// syntax like `{'x': 1, 'y': 2, 'z': 3}`.
401    fn supports_dictionary_syntax(&self) -> bool {
402        false
403    }
404
405    /// Returns true if the dialect supports defining object using the
406    /// syntax like `Map {1: 10, 2: 20}`.
407    fn support_map_literal_syntax(&self) -> bool {
408        false
409    }
410
411    /// Returns true if the dialect supports lambda functions, for example:
412    ///
413    /// ```sql
414    /// SELECT transform(array(1, 2, 3), x -> x + 1); -- returns [2,3,4]
415    /// ```
416    fn supports_lambda_functions(&self) -> bool {
417        false
418    }
419
420    /// Returns true if the dialect supports multiple variable assignment
421    /// using parentheses in a `SET` variable declaration.
422    ///
423    /// ```sql
424    /// SET (variable[, ...]) = (expression[, ...]);
425    /// ```
426    fn supports_parenthesized_set_variables(&self) -> bool {
427        false
428    }
429
430    /// Returns true if the dialect supports multiple `SET` statements
431    /// in a single statement.
432    ///
433    /// ```sql
434    /// SET variable = expression [, variable = expression];
435    /// ```
436    fn supports_comma_separated_set_assignments(&self) -> bool {
437        false
438    }
439
440    /// Returns true if the dialect supports an `EXCEPT` clause following a
441    /// wildcard in a select list.
442    ///
443    /// For example
444    /// ```sql
445    /// SELECT * EXCEPT order_id FROM orders;
446    /// ```
447    fn supports_select_wildcard_except(&self) -> bool {
448        false
449    }
450
451    /// Returns true if the dialect has a CONVERT function which accepts a type first
452    /// and an expression second, e.g. `CONVERT(varchar, 1)`
453    fn convert_type_before_value(&self) -> bool {
454        false
455    }
456
457    /// Returns true if the dialect supports triple quoted string
458    /// e.g. `"""abc"""`
459    fn supports_triple_quoted_string(&self) -> bool {
460        false
461    }
462
463    /// Dialect-specific prefix parser override
464    fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
465        // return None to fall back to the default behavior
466        None
467    }
468
469    /// Does the dialect support trailing commas around the query?
470    fn supports_trailing_commas(&self) -> bool {
471        false
472    }
473
474    /// Does the dialect support parsing `LIMIT 1, 2` as `LIMIT 2 OFFSET 1`?
475    fn supports_limit_comma(&self) -> bool {
476        false
477    }
478
479    /// Does the dialect support trailing commas in the projection list?
480    fn supports_projection_trailing_commas(&self) -> bool {
481        self.supports_trailing_commas()
482    }
483
484    /// Returns true if the dialect supports trailing commas in the `FROM` clause of a `SELECT` statement.
485    /// Example: `SELECT 1 FROM T, U, LIMIT 1`
486    fn supports_from_trailing_commas(&self) -> bool {
487        false
488    }
489
490    /// Returns true if the dialect supports trailing commas in the
491    /// column definitions list of a `CREATE` statement.
492    /// Example: `CREATE TABLE T (x INT, y TEXT,)`
493    fn supports_column_definition_trailing_commas(&self) -> bool {
494        false
495    }
496
497    /// Returns true if the dialect supports double dot notation for object names
498    ///
499    /// Example
500    /// ```sql
501    /// SELECT * FROM db_name..table_name
502    /// ```
503    fn supports_object_name_double_dot_notation(&self) -> bool {
504        false
505    }
506
507    /// Return true if the dialect supports the STRUCT literal
508    ///
509    /// Example
510    /// ```sql
511    /// SELECT STRUCT(1 as one, 'foo' as foo, false)
512    /// ```
513    fn supports_struct_literal(&self) -> bool {
514        false
515    }
516
517    /// Return true if the dialect supports empty projections in SELECT statements
518    ///
519    /// Example
520    /// ```sql
521    /// SELECT from table_name
522    /// ```
523    fn supports_empty_projections(&self) -> bool {
524        false
525    }
526
527    /// Return true if the dialect supports wildcard expansion on
528    /// arbitrary expressions in projections.
529    ///
530    /// Example:
531    /// ```sql
532    /// SELECT STRUCT<STRING>('foo').* FROM T
533    /// ```
534    fn supports_select_expr_star(&self) -> bool {
535        false
536    }
537
538    /// Return true if the dialect supports "FROM-first" selects.
539    ///
540    /// Example:
541    /// ```sql
542    /// FROM table
543    /// SELECT *
544    /// ```
545    fn supports_from_first_select(&self) -> bool {
546        false
547    }
548
549    /// Return true if the dialect supports pipe operator.
550    ///
551    /// Example:
552    /// ```sql
553    /// SELECT *
554    /// FROM table
555    /// |> limit 1
556    /// ```
557    ///
558    /// See <https://cloud.google.com/bigquery/docs/pipe-syntax-guide#basic_syntax>
559    fn supports_pipe_operator(&self) -> bool {
560        false
561    }
562
563    /// Does the dialect support MySQL-style `'user'@'host'` grantee syntax?
564    fn supports_user_host_grantee(&self) -> bool {
565        false
566    }
567
568    /// Does the dialect support the `MATCH() AGAINST()` syntax?
569    fn supports_match_against(&self) -> bool {
570        false
571    }
572
573    /// Returns true if the dialect supports an exclude option
574    /// following a wildcard in the projection section. For example:
575    /// `SELECT * EXCLUDE col1 FROM tbl`.
576    ///
577    /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
578    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select)
579    fn supports_select_wildcard_exclude(&self) -> bool {
580        false
581    }
582
583    /// Returns true if the dialect supports an exclude option
584    /// as the last item in the projection section, not necessarily
585    /// after a wildcard. For example:
586    /// `SELECT *, c1, c2 EXCLUDE c3 FROM tbl`
587    ///
588    /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
589    fn supports_select_exclude(&self) -> bool {
590        false
591    }
592
593    /// Returne true if the dialect supports specifying multiple options
594    /// in a `CREATE TABLE` statement for the structure of the new table. For example:
595    /// `CREATE TABLE t (a INT, b INT) AS SELECT 1 AS b, 2 AS a`
596    fn supports_create_table_multi_schema_info_sources(&self) -> bool {
597        false
598    }
599
600    /// Dialect-specific infix parser override
601    ///
602    /// This method is called to parse the next infix expression.
603    ///
604    /// If `None` is returned, falls back to the default behavior.
605    fn parse_infix(
606        &self,
607        _parser: &mut Parser,
608        _expr: &Expr,
609        _precedence: u8,
610    ) -> Option<Result<Expr, ParserError>> {
611        // return None to fall back to the default behavior
612        None
613    }
614
615    /// Dialect-specific precedence override
616    ///
617    /// This method is called to get the precedence of the next token.
618    ///
619    /// If `None` is returned, falls back to the default behavior.
620    fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
621        // return None to fall back to the default behavior
622        None
623    }
624
625    /// Get the precedence of the next token, looking at the full token stream.
626    ///
627    /// A higher number => higher precedence
628    ///
629    /// See [`Self::get_next_precedence`] to override the behavior for just the
630    /// next token.
631    ///
632    /// The default implementation is used for many dialects, but can be
633    /// overridden to provide dialect-specific behavior.
634    fn get_next_precedence_default(&self, parser: &Parser) -> Result<u8, ParserError> {
635        if let Some(precedence) = self.get_next_precedence(parser) {
636            return precedence;
637        }
638        macro_rules! p {
639            ($precedence:ident) => {
640                self.prec_value(Precedence::$precedence)
641            };
642        }
643
644        let token = parser.peek_token();
645        debug!("get_next_precedence_full() {token:?}");
646        match token.token {
647            Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
648            Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
649            Token::Word(w) if w.keyword == Keyword::XOR => Ok(p!(Xor)),
650
651            Token::Word(w) if w.keyword == Keyword::AT => {
652                match (
653                    parser.peek_nth_token(1).token,
654                    parser.peek_nth_token(2).token,
655                ) {
656                    (Token::Word(w), Token::Word(w2))
657                        if w.keyword == Keyword::TIME && w2.keyword == Keyword::ZONE =>
658                    {
659                        Ok(p!(AtTz))
660                    }
661                    _ => Ok(self.prec_unknown()),
662                }
663            }
664
665            Token::Word(w) if w.keyword == Keyword::NOT => match parser.peek_nth_token(1).token {
666                // The precedence of NOT varies depending on keyword that
667                // follows it. If it is followed by IN, BETWEEN, or LIKE,
668                // it takes on the precedence of those tokens. Otherwise, it
669                // is not an infix operator, and therefore has zero
670                // precedence.
671                Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
672                Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
673                Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
674                Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
675                Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
676                Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
677                Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
678                Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
679                Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
680                _ => Ok(self.prec_unknown()),
681            },
682            Token::Word(w) if w.keyword == Keyword::IS => Ok(p!(Is)),
683            Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
684            Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
685            Token::Word(w) if w.keyword == Keyword::OVERLAPS => Ok(p!(Between)),
686            Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
687            Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
688            Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
689            Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
690            Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
691            Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
692            Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
693            Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(p!(Between)),
694            Token::Word(w) if w.keyword == Keyword::DIV => Ok(p!(MulDivModOp)),
695            Token::Period => Ok(p!(Period)),
696            Token::Assignment
697            | Token::Eq
698            | Token::Lt
699            | Token::LtEq
700            | Token::Neq
701            | Token::Gt
702            | Token::GtEq
703            | Token::DoubleEq
704            | Token::Tilde
705            | Token::TildeAsterisk
706            | Token::ExclamationMarkTilde
707            | Token::ExclamationMarkTildeAsterisk
708            | Token::DoubleTilde
709            | Token::DoubleTildeAsterisk
710            | Token::ExclamationMarkDoubleTilde
711            | Token::ExclamationMarkDoubleTildeAsterisk
712            | Token::Spaceship => Ok(p!(Eq)),
713            Token::Pipe
714            | Token::QuestionMarkDash
715            | Token::DoubleSharp
716            | Token::Overlap
717            | Token::AmpersandLeftAngleBracket
718            | Token::AmpersandRightAngleBracket
719            | Token::QuestionMarkDashVerticalBar
720            | Token::AmpersandLeftAngleBracketVerticalBar
721            | Token::VerticalBarAmpersandRightAngleBracket
722            | Token::TwoWayArrow
723            | Token::LeftAngleBracketCaret
724            | Token::RightAngleBracketCaret
725            | Token::QuestionMarkSharp
726            | Token::QuestionMarkDoubleVerticalBar
727            | Token::QuestionPipe
728            | Token::TildeEqual
729            | Token::AtSign
730            | Token::ShiftLeftVerticalBar
731            | Token::VerticalBarShiftRight => Ok(p!(Pipe)),
732            Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
733            Token::Ampersand => Ok(p!(Ampersand)),
734            Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
735            Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
736                Ok(p!(MulDivModOp))
737            }
738            Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
739                Ok(p!(DoubleColon))
740            }
741            Token::Arrow
742            | Token::LongArrow
743            | Token::HashArrow
744            | Token::HashLongArrow
745            | Token::AtArrow
746            | Token::ArrowAt
747            | Token::HashMinus
748            | Token::AtQuestion
749            | Token::AtAt
750            | Token::Question
751            | Token::QuestionAnd
752            | Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
753            _ => Ok(self.prec_unknown()),
754        }
755    }
756
757    /// Dialect-specific statement parser override
758    ///
759    /// This method is called to parse the next statement.
760    ///
761    /// If `None` is returned, falls back to the default behavior.
762    fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
763        // return None to fall back to the default behavior
764        None
765    }
766
767    /// Dialect-specific column option parser override
768    ///
769    /// This method is called to parse the next column option.
770    ///
771    /// If `None` is returned, falls back to the default behavior.
772    fn parse_column_option(
773        &self,
774        _parser: &mut Parser,
775    ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
776        // return None to fall back to the default behavior
777        Ok(None)
778    }
779
780    /// Decide the lexical Precedence of operators.
781    ///
782    /// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
783    fn prec_value(&self, prec: Precedence) -> u8 {
784        match prec {
785            Precedence::Period => 100,
786            Precedence::DoubleColon => 50,
787            Precedence::AtTz => 41,
788            Precedence::MulDivModOp => 40,
789            Precedence::PlusMinus => 30,
790            Precedence::Xor => 24,
791            Precedence::Ampersand => 23,
792            Precedence::Caret => 22,
793            Precedence::Pipe => 21,
794            Precedence::Between => 20,
795            Precedence::Eq => 20,
796            Precedence::Like => 19,
797            Precedence::Is => 17,
798            Precedence::PgOther => 16,
799            Precedence::UnaryNot => 15,
800            Precedence::And => 10,
801            Precedence::Or => 5,
802        }
803    }
804
805    /// Returns the precedence when the precedence is otherwise unknown
806    fn prec_unknown(&self) -> u8 {
807        0
808    }
809
810    /// Returns true if this dialect requires the `TABLE` keyword after `DESCRIBE`
811    ///
812    /// Defaults to false.
813    ///
814    /// If true, the following statement is valid: `DESCRIBE TABLE my_table`
815    /// If false, the following statements are valid: `DESCRIBE my_table` and `DESCRIBE table`
816    fn describe_requires_table_keyword(&self) -> bool {
817        false
818    }
819
820    /// Returns true if this dialect allows the `EXTRACT` function to words other than [`Keyword`].
821    fn allow_extract_custom(&self) -> bool {
822        false
823    }
824
825    /// Returns true if this dialect allows the `EXTRACT` function to use single quotes in the part being extracted.
826    fn allow_extract_single_quotes(&self) -> bool {
827        false
828    }
829
830    /// Returns true if this dialect allows dollar placeholders
831    /// e.g. `SELECT $var` (SQLite)
832    fn supports_dollar_placeholder(&self) -> bool {
833        false
834    }
835
836    /// Does the dialect support with clause in create index statement?
837    /// e.g. `CREATE INDEX idx ON t WITH (key = value, key2)`
838    fn supports_create_index_with_clause(&self) -> bool {
839        false
840    }
841
842    /// Whether `INTERVAL` expressions require units (called "qualifiers" in the ANSI SQL spec) to be specified,
843    /// e.g. `INTERVAL 1 DAY` vs `INTERVAL 1`.
844    ///
845    /// Expressions within intervals (e.g. `INTERVAL '1' + '1' DAY`) are only allowed when units are required.
846    ///
847    /// See <https://github.com/sqlparser-rs/sqlparser-rs/pull/1398> for more information.
848    ///
849    /// When `true`:
850    /// * `INTERVAL '1' DAY` is VALID
851    /// * `INTERVAL 1 + 1 DAY` is VALID
852    /// * `INTERVAL '1' + '1' DAY` is VALID
853    /// * `INTERVAL '1'` is INVALID
854    ///
855    /// When `false`:
856    /// * `INTERVAL '1'` is VALID
857    /// * `INTERVAL '1' DAY` is VALID — unit is not required, but still allowed
858    /// * `INTERVAL 1 + 1 DAY` is INVALID
859    fn require_interval_qualifier(&self) -> bool {
860        false
861    }
862
863    fn supports_explain_with_utility_options(&self) -> bool {
864        false
865    }
866
867    fn supports_asc_desc_in_column_definition(&self) -> bool {
868        false
869    }
870
871    /// Returns true if the dialect supports `a!` expressions
872    fn supports_factorial_operator(&self) -> bool {
873        false
874    }
875
876    /// Returns true if the dialect supports nested comments
877    /// e.g. `/* /* nested */ */`
878    fn supports_nested_comments(&self) -> bool {
879        false
880    }
881
882    /// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
883    /// as an alias assignment operator, rather than a boolean expression.
884    /// For example: the following statements are equivalent for such a dialect:
885    /// ```sql
886    ///  SELECT col_alias = col FROM tbl;
887    ///  SELECT col_alias AS col FROM tbl;
888    /// ```
889    fn supports_eq_alias_assignment(&self) -> bool {
890        false
891    }
892
893    /// Returns true if this dialect supports the `TRY_CONVERT` function
894    fn supports_try_convert(&self) -> bool {
895        false
896    }
897
898    /// Returns true if the dialect supports `!a` syntax for boolean `NOT` expressions.
899    fn supports_bang_not_operator(&self) -> bool {
900        false
901    }
902
903    /// Returns true if the dialect supports the `LISTEN`, `UNLISTEN` and `NOTIFY` statements
904    fn supports_listen_notify(&self) -> bool {
905        false
906    }
907
908    /// Returns true if the dialect supports the `LOAD DATA` statement
909    fn supports_load_data(&self) -> bool {
910        false
911    }
912
913    /// Returns true if the dialect supports the `LOAD extension` statement
914    fn supports_load_extension(&self) -> bool {
915        false
916    }
917
918    /// Returns true if this dialect expects the `TOP` option
919    /// before the `ALL`/`DISTINCT` options in a `SELECT` statement.
920    fn supports_top_before_distinct(&self) -> bool {
921        false
922    }
923
924    /// Returns true if the dialect supports boolean literals (`true` and `false`).
925    /// For example, in MSSQL these are treated as identifiers rather than boolean literals.
926    fn supports_boolean_literals(&self) -> bool {
927        true
928    }
929
930    /// Returns true if this dialect supports the `LIKE 'pattern'` option in
931    /// a `SHOW` statement before the `IN` option
932    fn supports_show_like_before_in(&self) -> bool {
933        false
934    }
935
936    /// Returns true if this dialect supports the `COMMENT` statement
937    fn supports_comment_on(&self) -> bool {
938        false
939    }
940
941    /// Returns true if the dialect supports the `CREATE TABLE SELECT` statement
942    fn supports_create_table_select(&self) -> bool {
943        false
944    }
945
946    /// Returns true if the dialect supports PartiQL for querying semi-structured data
947    /// <https://partiql.org/index.html>
948    fn supports_partiql(&self) -> bool {
949        false
950    }
951
952    /// Returns true if the specified keyword is reserved and cannot be
953    /// used as an identifier without special handling like quoting.
954    fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
955        keywords::RESERVED_FOR_IDENTIFIER.contains(&kw)
956    }
957
958    /// Returns reserved keywords when looking to parse a `TableFactor`.
959    /// See [Self::supports_from_trailing_commas]
960    fn get_reserved_keywords_for_table_factor(&self) -> &[Keyword] {
961        keywords::RESERVED_FOR_TABLE_FACTOR
962    }
963
964    /// Returns reserved keywords that may prefix a select item expression
965    /// e.g. `SELECT CONNECT_BY_ROOT name FROM Tbl2` (Snowflake)
966    fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
967        &[]
968    }
969
970    /// Returns grantee types that should be treated as identifiers
971    fn get_reserved_grantees_types(&self) -> &[GranteesType] {
972        &[]
973    }
974
975    /// Returns true if this dialect supports the `TABLESAMPLE` option
976    /// before the table alias option. For example:
977    ///
978    /// Table sample before alias: `SELECT * FROM tbl AS t TABLESAMPLE (10)`
979    /// Table sample after alias: `SELECT * FROM tbl TABLESAMPLE (10) AS t`
980    ///
981    /// <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#_7_6_table_reference>
982    fn supports_table_sample_before_alias(&self) -> bool {
983        false
984    }
985
986    /// Returns true if this dialect supports the `INSERT INTO ... SET col1 = 1, ...` syntax.
987    ///
988    /// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
989    fn supports_insert_set(&self) -> bool {
990        false
991    }
992
993    /// Does the dialect support table function in insertion?
994    fn supports_insert_table_function(&self) -> bool {
995        false
996    }
997
998    /// Does the dialect support insert formats, e.g. `INSERT INTO ... FORMAT <format>`
999    fn supports_insert_format(&self) -> bool {
1000        false
1001    }
1002
1003    /// Returns true if this dialect supports `SET` statements without an explicit
1004    /// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
1005    fn supports_set_stmt_without_operator(&self) -> bool {
1006        false
1007    }
1008
1009    /// Returns true if the specified keyword should be parsed as a column identifier.
1010    /// See [keywords::RESERVED_FOR_COLUMN_ALIAS]
1011    fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1012        !keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw)
1013    }
1014
1015    /// Returns true if the specified keyword should be parsed as a select item alias.
1016    /// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
1017    /// to enable looking ahead if needed.
1018    fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
1019        explicit || self.is_column_alias(kw, parser)
1020    }
1021
1022    /// Returns true if the specified keyword should be parsed as a table identifier.
1023    /// See [keywords::RESERVED_FOR_TABLE_ALIAS]
1024    fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1025        !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
1026    }
1027
1028    /// Returns true if the specified keyword should be parsed as a table factor alias.
1029    /// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
1030    /// to enable looking ahead if needed.
1031    fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
1032        explicit || self.is_table_alias(kw, parser)
1033    }
1034
1035    /// Returns true if this dialect supports querying historical table data
1036    /// by specifying which version of the data to query.
1037    fn supports_timestamp_versioning(&self) -> bool {
1038        false
1039    }
1040
1041    /// Returns true if this dialect supports the E'...' syntax for string literals
1042    ///
1043    /// Postgres: <https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE>
1044    fn supports_string_escape_constant(&self) -> bool {
1045        false
1046    }
1047
1048    /// Returns true if the dialect supports the table hints in the `FROM` clause.
1049    fn supports_table_hints(&self) -> bool {
1050        false
1051    }
1052
1053    /// Returns true if this dialect requires a whitespace character after `--` to start a single line comment.
1054    ///
1055    /// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/ansi-diff-comments.html>
1056    /// e.g. UPDATE account SET balance=balance--1
1057    //       WHERE account_id=5752             ^^^ will be interpreted as two minus signs instead of a comment
1058    fn requires_single_line_comment_whitespace(&self) -> bool {
1059        false
1060    }
1061
1062    /// Returns true if the dialect supports array type definition with brackets with
1063    /// an optional size. For example:
1064    /// ```CREATE TABLE my_table (arr1 INT[], arr2 INT[3])```
1065    /// ```SELECT x::INT[]```
1066    fn supports_array_typedef_with_brackets(&self) -> bool {
1067        false
1068    }
1069    /// Returns true if the dialect supports geometric types.
1070    ///
1071    /// Postgres: <https://www.postgresql.org/docs/9.5/functions-geometry.html>
1072    /// e.g. @@ circle '((0,0),10)'
1073    fn supports_geometric_types(&self) -> bool {
1074        false
1075    }
1076
1077    /// Returns true if the dialect supports `ORDER BY ALL`.
1078    /// `ALL` which means all columns of the SELECT clause.
1079    ///
1080    /// For example: ```SELECT * FROM addresses ORDER BY ALL;```.
1081    fn supports_order_by_all(&self) -> bool {
1082        false
1083    }
1084
1085    /// Returns true if the dialect supports `SET NAMES <charset_name> [COLLATE <collation_name>]`.
1086    ///
1087    /// - [MySQL](https://dev.mysql.com/doc/refman/8.4/en/set-names.html)
1088    /// - [PostgreSQL](https://www.postgresql.org/docs/17/sql-set.html)
1089    ///
1090    /// Note: Postgres doesn't support the `COLLATE` clause, but we permissively parse it anyway.
1091    fn supports_set_names(&self) -> bool {
1092        false
1093    }
1094
1095    fn supports_space_separated_column_options(&self) -> bool {
1096        false
1097    }
1098
1099    /// Returns true if the dialect supports the `USING` clause in an `ALTER COLUMN` statement.
1100    /// Example:
1101    ///  ```sql
1102    ///  ALTER TABLE tbl ALTER COLUMN col SET DATA TYPE <type> USING <exp>`
1103    /// ```
1104    fn supports_alter_column_type_using(&self) -> bool {
1105        false
1106    }
1107
1108    /// Returns true if the dialect supports `ALTER TABLE tbl DROP COLUMN c1, ..., cn`
1109    fn supports_comma_separated_drop_column_list(&self) -> bool {
1110        false
1111    }
1112
1113    /// Returns true if the dialect considers the specified ident as a function
1114    /// that returns an identifier. Typically used to generate identifiers
1115    /// programmatically.
1116    ///
1117    /// - [Snowflake](https://docs.snowflake.com/en/sql-reference/identifier-literal)
1118    fn is_identifier_generating_function_name(
1119        &self,
1120        _ident: &Ident,
1121        _name_parts: &[ObjectNamePart],
1122    ) -> bool {
1123        false
1124    }
1125}
1126
1127/// This represents the operators for which precedence must be defined
1128///
1129/// higher number -> higher precedence
1130#[derive(Debug, Clone, Copy)]
1131pub enum Precedence {
1132    Period,
1133    DoubleColon,
1134    AtTz,
1135    MulDivModOp,
1136    PlusMinus,
1137    Xor,
1138    Ampersand,
1139    Caret,
1140    Pipe,
1141    Between,
1142    Eq,
1143    Like,
1144    Is,
1145    PgOther,
1146    UnaryNot,
1147    And,
1148    Or,
1149}
1150
1151impl dyn Dialect {
1152    #[inline]
1153    pub fn is<T: Dialect>(&self) -> bool {
1154        // borrowed from `Any` implementation
1155        TypeId::of::<T>() == self.dialect()
1156    }
1157}
1158
1159/// Returns the built in [`Dialect`] corresponding to `dialect_name`.
1160///
1161/// See [`Dialect`] documentation for an example.
1162pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
1163    let dialect_name = dialect_name.as_ref();
1164    match dialect_name.to_lowercase().as_str() {
1165        "generic" => Some(Box::new(GenericDialect)),
1166        "mysql" => Some(Box::new(MySqlDialect {})),
1167        "postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
1168        "hive" => Some(Box::new(HiveDialect {})),
1169        "sqlite" => Some(Box::new(SQLiteDialect {})),
1170        "snowflake" => Some(Box::new(SnowflakeDialect)),
1171        "redshift" => Some(Box::new(RedshiftSqlDialect {})),
1172        "mssql" => Some(Box::new(MsSqlDialect {})),
1173        "clickhouse" => Some(Box::new(ClickHouseDialect {})),
1174        "bigquery" => Some(Box::new(BigQueryDialect)),
1175        "ansi" => Some(Box::new(AnsiDialect {})),
1176        "duckdb" => Some(Box::new(DuckDbDialect {})),
1177        "databricks" => Some(Box::new(DatabricksDialect {})),
1178        _ => None,
1179    }
1180}
1181
1182#[cfg(test)]
1183mod tests {
1184    use super::*;
1185
1186    struct DialectHolder<'a> {
1187        dialect: &'a dyn Dialect,
1188    }
1189
1190    #[test]
1191    fn test_is_dialect() {
1192        let generic_dialect: &dyn Dialect = &GenericDialect {};
1193        let ansi_dialect: &dyn Dialect = &AnsiDialect {};
1194
1195        let generic_holder = DialectHolder {
1196            dialect: generic_dialect,
1197        };
1198        let ansi_holder = DialectHolder {
1199            dialect: ansi_dialect,
1200        };
1201
1202        assert!(dialect_of!(generic_holder is GenericDialect |  AnsiDialect),);
1203        assert!(!dialect_of!(generic_holder is  AnsiDialect));
1204        assert!(dialect_of!(ansi_holder is AnsiDialect));
1205        assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
1206        assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
1207    }
1208
1209    #[test]
1210    fn test_dialect_from_str() {
1211        assert!(parse_dialect("generic").is::<GenericDialect>());
1212        assert!(parse_dialect("mysql").is::<MySqlDialect>());
1213        assert!(parse_dialect("MySql").is::<MySqlDialect>());
1214        assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
1215        assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
1216        assert!(parse_dialect("hive").is::<HiveDialect>());
1217        assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
1218        assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
1219        assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
1220        assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
1221        assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
1222        assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
1223        assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
1224        assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
1225        assert!(parse_dialect("ansi").is::<AnsiDialect>());
1226        assert!(parse_dialect("ANSI").is::<AnsiDialect>());
1227        assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
1228        assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
1229        assert!(parse_dialect("DataBricks").is::<DatabricksDialect>());
1230        assert!(parse_dialect("databricks").is::<DatabricksDialect>());
1231
1232        // error cases
1233        assert!(dialect_from_str("Unknown").is_none());
1234        assert!(dialect_from_str("").is_none());
1235    }
1236
1237    fn parse_dialect(v: &str) -> Box<dyn Dialect> {
1238        dialect_from_str(v).unwrap()
1239    }
1240
1241    #[test]
1242    fn identifier_quote_style() {
1243        let tests: Vec<(&dyn Dialect, &str, Option<char>)> = vec![
1244            (&GenericDialect {}, "id", None),
1245            (&SQLiteDialect {}, "id", Some('`')),
1246            (&PostgreSqlDialect {}, "id", Some('"')),
1247        ];
1248
1249        for (dialect, ident, expected) in tests {
1250            let actual = dialect.identifier_quote_style(ident);
1251
1252            assert_eq!(actual, expected);
1253        }
1254    }
1255
1256    #[test]
1257    fn parse_with_wrapped_dialect() {
1258        /// Wrapper for a dialect. In a real-world example, this wrapper
1259        /// would tweak the behavior of the dialect. For the test case,
1260        /// it wraps all methods unaltered.
1261        #[derive(Debug)]
1262        struct WrappedDialect(MySqlDialect);
1263
1264        impl Dialect for WrappedDialect {
1265            fn dialect(&self) -> std::any::TypeId {
1266                self.0.dialect()
1267            }
1268
1269            fn is_identifier_start(&self, ch: char) -> bool {
1270                self.0.is_identifier_start(ch)
1271            }
1272
1273            fn is_delimited_identifier_start(&self, ch: char) -> bool {
1274                self.0.is_delimited_identifier_start(ch)
1275            }
1276
1277            fn is_nested_delimited_identifier_start(&self, ch: char) -> bool {
1278                self.0.is_nested_delimited_identifier_start(ch)
1279            }
1280
1281            fn peek_nested_delimited_identifier_quotes(
1282                &self,
1283                chars: std::iter::Peekable<std::str::Chars<'_>>,
1284            ) -> Option<(char, Option<char>)> {
1285                self.0.peek_nested_delimited_identifier_quotes(chars)
1286            }
1287
1288            fn identifier_quote_style(&self, identifier: &str) -> Option<char> {
1289                self.0.identifier_quote_style(identifier)
1290            }
1291
1292            fn supports_string_literal_backslash_escape(&self) -> bool {
1293                self.0.supports_string_literal_backslash_escape()
1294            }
1295
1296            fn supports_filter_during_aggregation(&self) -> bool {
1297                self.0.supports_filter_during_aggregation()
1298            }
1299
1300            fn supports_within_after_array_aggregation(&self) -> bool {
1301                self.0.supports_within_after_array_aggregation()
1302            }
1303
1304            fn supports_group_by_expr(&self) -> bool {
1305                self.0.supports_group_by_expr()
1306            }
1307
1308            fn supports_in_empty_list(&self) -> bool {
1309                self.0.supports_in_empty_list()
1310            }
1311
1312            fn convert_type_before_value(&self) -> bool {
1313                self.0.convert_type_before_value()
1314            }
1315
1316            fn parse_prefix(
1317                &self,
1318                parser: &mut sqlparser::parser::Parser,
1319            ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
1320                self.0.parse_prefix(parser)
1321            }
1322
1323            fn parse_infix(
1324                &self,
1325                parser: &mut sqlparser::parser::Parser,
1326                expr: &Expr,
1327                precedence: u8,
1328            ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
1329                self.0.parse_infix(parser, expr, precedence)
1330            }
1331
1332            fn get_next_precedence(
1333                &self,
1334                parser: &sqlparser::parser::Parser,
1335            ) -> Option<Result<u8, sqlparser::parser::ParserError>> {
1336                self.0.get_next_precedence(parser)
1337            }
1338
1339            fn parse_statement(
1340                &self,
1341                parser: &mut sqlparser::parser::Parser,
1342            ) -> Option<Result<Statement, sqlparser::parser::ParserError>> {
1343                self.0.parse_statement(parser)
1344            }
1345
1346            fn is_identifier_part(&self, ch: char) -> bool {
1347                self.0.is_identifier_part(ch)
1348            }
1349        }
1350
1351        #[allow(clippy::needless_raw_string_hashes)]
1352        let statement = r#"SELECT 'Wayne\'s World'"#;
1353        let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
1354        let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
1355        assert!(res1.is_ok());
1356        assert_eq!(res1, res2);
1357    }
1358}