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