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::parse_snowflake_stage_name;
53pub use self::snowflake::SnowflakeDialect;
54pub use self::sqlite::SQLiteDialect;
55
56/// Macro for streamlining the creation of derived `Dialect` objects.
57/// The generated struct includes `new()` and `default()` constructors.
58/// Requires the `derive-dialect` feature.
59///
60/// # Syntax
61///
62/// ```text
63/// derive_dialect!(NewDialect, BaseDialect);
64/// derive_dialect!(NewDialect, BaseDialect, overrides = { method = value, ... });
65/// derive_dialect!(NewDialect, BaseDialect, preserve_type_id = true);
66/// derive_dialect!(NewDialect, BaseDialect, preserve_type_id = true, overrides = { ... });
67/// ```
68///
69/// # Example
70///
71/// ```
72/// use sqlparser::derive_dialect;
73/// use sqlparser::dialect::{Dialect, GenericDialect};
74///
75/// // Override boolean methods (supports_*, allow_*, etc.)
76/// derive_dialect!(CustomDialect, GenericDialect, overrides = {
77/// supports_order_by_all = true,
78/// supports_nested_comments = true,
79/// });
80///
81/// let dialect = CustomDialect::new();
82/// assert!(dialect.supports_order_by_all());
83/// assert!(dialect.supports_nested_comments());
84/// ```
85///
86/// # Overriding `identifier_quote_style`
87///
88/// Use a char literal or `None`:
89/// ```
90/// use sqlparser::derive_dialect;
91/// use sqlparser::dialect::{Dialect, PostgreSqlDialect};
92///
93/// derive_dialect!(BacktickPostgreSqlDialect, PostgreSqlDialect,
94/// preserve_type_id = true,
95/// overrides = { identifier_quote_style = '`' }
96/// );
97/// let d: &dyn Dialect = &BacktickPostgreSqlDialect::new();
98/// assert_eq!(d.identifier_quote_style("foo"), Some('`'));
99///
100/// derive_dialect!(QuotelessPostgreSqlDialect, PostgreSqlDialect,
101/// preserve_type_id = true,
102/// overrides = { identifier_quote_style = None }
103/// );
104/// let d: &dyn Dialect = &QuotelessPostgreSqlDialect::new();
105/// assert_eq!(d.identifier_quote_style("foo"), None);
106/// ```
107///
108/// # Type Identity
109///
110/// By default, derived dialects have their own `TypeId`. Set `preserve_type_id = true` to
111/// retain the base dialect's identity with respect to the parser's `dialect.is::<T>()` checks:
112/// ```
113/// use sqlparser::derive_dialect;
114/// use sqlparser::dialect::{Dialect, GenericDialect};
115///
116/// derive_dialect!(EnhancedGenericDialect, GenericDialect,
117/// preserve_type_id = true,
118/// overrides = {
119/// supports_order_by_all = true,
120/// supports_nested_comments = true,
121/// }
122/// );
123/// let d: &dyn Dialect = &EnhancedGenericDialect::new();
124/// assert!(d.is::<GenericDialect>()); // still recognized as a GenericDialect
125/// assert!(d.supports_nested_comments());
126/// assert!(d.supports_order_by_all());
127/// ```
128#[cfg(feature = "derive-dialect")]
129pub use sqlparser_derive::derive_dialect;
130
131use crate::ast::{ColumnOption, Expr, GranteesType, Ident, ObjectNamePart, Statement};
132pub use crate::keywords;
133use crate::keywords::Keyword;
134use crate::parser::{Parser, ParserError};
135use crate::tokenizer::Token;
136
137#[cfg(not(feature = "std"))]
138use alloc::boxed::Box;
139
140/// Convenience check if a [`Parser`] uses a certain dialect.
141///
142/// Note: when possible, please use the new style, adding a method to
143/// the [`Dialect`] trait rather than using this macro.
144///
145/// The benefits of adding a method on `Dialect` over this macro are:
146/// 1. user defined [`Dialect`]s can customize the parsing behavior
147/// 2. The differences between dialects can be clearly documented in the trait
148///
149/// `dialect_of!(parser is SQLiteDialect | GenericDialect)` evaluates
150/// to `true` if `parser.dialect` is one of the [`Dialect`]s specified.
151macro_rules! dialect_of {
152 ( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
153 ($($parsed_dialect.dialect.is::<$dialect_type>())||+)
154 };
155}
156
157// Similar to above, but for applying directly against an instance of dialect
158// instead of a struct member named dialect. This avoids lifetime issues when
159// mixing match guards and token references.
160macro_rules! dialect_is {
161 ($dialect:ident is $($dialect_type:ty)|+) => {
162 ($($dialect.is::<$dialect_type>())||+)
163 }
164}
165
166/// Encapsulates the differences between SQL implementations.
167///
168/// # SQL Dialects
169///
170/// SQL implementations deviate from one another, either due to
171/// custom extensions or various historical reasons. This trait
172/// encapsulates the parsing differences between dialects.
173///
174/// [`GenericDialect`] is the most permissive dialect, and parses the union of
175/// all the other dialects, when there is no ambiguity. However, it does not
176/// currently allow `CREATE TABLE` statements without types specified for all
177/// columns; use [`SQLiteDialect`] if you require that.
178///
179/// # Examples
180/// Most users create a [`Dialect`] directly, as shown on the [module
181/// level documentation]:
182///
183/// ```
184/// # use sqlparser::dialect::AnsiDialect;
185/// let dialect = AnsiDialect {};
186/// ```
187///
188/// It is also possible to dynamically create a [`Dialect`] from its
189/// name. For example:
190///
191/// ```
192/// # use sqlparser::dialect::{AnsiDialect, dialect_from_str};
193/// let dialect = dialect_from_str("ansi").unwrap();
194///
195/// // Parsed dialect is an instance of `AnsiDialect`:
196/// assert!(dialect.is::<AnsiDialect>());
197/// ```
198///
199/// [module level documentation]: crate
200pub trait Dialect: Debug + Any {
201 /// Determine the [`TypeId`] of this dialect.
202 ///
203 /// By default, return the same [`TypeId`] as [`Any::type_id`]. Can be overridden by
204 /// dialects that behave like other dialects (for example, when wrapping a dialect).
205 fn dialect(&self) -> TypeId {
206 self.type_id()
207 }
208
209 /// Determine if a character starts a quoted identifier. The default
210 /// implementation, accepting "double quoted" ids is both ANSI-compliant
211 /// and appropriate for most dialects (with the notable exception of
212 /// MySQL, MS SQL, and sqlite). You can accept one of characters listed
213 /// in `Word::matching_end_quote` here
214 fn is_delimited_identifier_start(&self, ch: char) -> bool {
215 ch == '"' || ch == '`'
216 }
217
218 /// Determine if a character starts a potential nested quoted identifier.
219 /// Example: RedShift supports the following quote styles to all mean the same thing:
220 /// ```sql
221 /// SELECT 1 AS foo;
222 /// SELECT 1 AS "foo";
223 /// SELECT 1 AS [foo];
224 /// SELECT 1 AS ["foo"];
225 /// ```
226 fn is_nested_delimited_identifier_start(&self, _ch: char) -> bool {
227 false
228 }
229
230 /// Only applicable whenever [`Self::is_nested_delimited_identifier_start`] returns true
231 /// If the next sequence of tokens potentially represent a nested identifier, then this method
232 /// returns a tuple containing the outer quote style, and if present, the inner (nested) quote style.
233 ///
234 /// Example (Redshift):
235 /// ```text
236 /// `["foo"]` => Some(`[`, Some(`"`))
237 /// `[foo]` => Some(`[`, None)
238 /// `[0]` => None
239 /// `"foo"` => None
240 /// ```
241 fn peek_nested_delimited_identifier_quotes(
242 &self,
243 mut _chars: Peekable<Chars<'_>>,
244 ) -> Option<(char, Option<char>)> {
245 None
246 }
247
248 /// Return the character used to quote identifiers.
249 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
250 None
251 }
252
253 /// Determine if a character is a valid start character for an unquoted identifier
254 fn is_identifier_start(&self, ch: char) -> bool;
255
256 /// Determine if a character is a valid unquoted identifier character
257 fn is_identifier_part(&self, ch: char) -> bool;
258
259 /// Most dialects do not have custom operators. Override this method to provide custom operators.
260 fn is_custom_operator_part(&self, _ch: char) -> bool {
261 false
262 }
263
264 /// Determine if the dialect supports escaping characters via '\' in string literals.
265 ///
266 /// Some dialects like BigQuery and Snowflake support this while others like
267 /// Postgres do not. Such that the following is accepted by the former but
268 /// rejected by the latter.
269 /// ```sql
270 /// SELECT 'ab\'cd';
271 /// ```
272 ///
273 /// Conversely, such dialects reject the following statement which
274 /// otherwise would be valid in the other dialects.
275 /// ```sql
276 /// SELECT '\';
277 /// ```
278 fn supports_string_literal_backslash_escape(&self) -> bool {
279 false
280 }
281
282 /// Determine whether the dialect strips the backslash when escaping LIKE wildcards (%, _).
283 ///
284 /// [MySQL] has a special case when escaping single quoted strings which leaves these unescaped
285 /// so they can be used in LIKE patterns without double-escaping (as is necessary in other
286 /// escaping dialects, such as [Snowflake]). Generally, special characters have escaping rules
287 /// causing them to be replaced with a different byte sequences (e.g. `'\0'` becoming the zero
288 /// byte), and the default if an escaped character does not have a specific escaping rule is to
289 /// strip the backslash (e.g. there is no rule for `h`, so `'\h' = 'h'`). MySQL's special case
290 /// for ignoring LIKE wildcard escapes is to *not* strip the backslash, so that `'\%' = '\\%'`.
291 /// This applies to all string literals though, not just those used in LIKE patterns.
292 ///
293 /// ```text
294 /// mysql> select '\_', hex('\\'), hex('_'), hex('\_');
295 /// +----+-----------+----------+-----------+
296 /// | \_ | hex('\\') | hex('_') | hex('\_') |
297 /// +----+-----------+----------+-----------+
298 /// | \_ | 5C | 5F | 5C5F |
299 /// +----+-----------+----------+-----------+
300 /// 1 row in set (0.00 sec)
301 /// ```
302 ///
303 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/string-literals.html
304 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/functions/like#usage-notes
305 fn ignores_wildcard_escapes(&self) -> bool {
306 false
307 }
308
309 /// Determine if the dialect supports string literals with `U&` prefix.
310 /// This is used to specify Unicode code points in string literals.
311 /// For example, in PostgreSQL, the following is a valid string literal:
312 /// ```sql
313 /// SELECT U&'\0061\0062\0063';
314 /// ```
315 /// This is equivalent to the string literal `'abc'`.
316 /// See
317 /// - [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
318 /// - [H2 docs](http://www.h2database.com/html/grammar.html#string)
319 fn supports_unicode_string_literal(&self) -> bool {
320 false
321 }
322
323 /// Does the dialect support `FILTER (WHERE expr)` for aggregate queries?
324 fn supports_filter_during_aggregation(&self) -> bool {
325 false
326 }
327
328 /// Returns true if the dialect supports referencing another named window
329 /// within a window clause declaration.
330 ///
331 /// Example
332 /// ```sql
333 /// SELECT * FROM mytable
334 /// WINDOW mynamed_window AS another_named_window
335 /// ```
336 fn supports_window_clause_named_window_reference(&self) -> bool {
337 false
338 }
339
340 /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions.
341 /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`]
342 ///
343 /// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function
344 fn supports_within_after_array_aggregation(&self) -> bool {
345 false
346 }
347
348 /// Returns true if the dialects supports `group sets, roll up, or cube` expressions.
349 fn supports_group_by_expr(&self) -> bool {
350 false
351 }
352
353 /// Returns true if the dialects supports `GROUP BY` modifiers prefixed by a `WITH` keyword.
354 /// Example: `GROUP BY value WITH ROLLUP`.
355 fn supports_group_by_with_modifier(&self) -> bool {
356 false
357 }
358
359 /// Indicates whether the dialect supports left-associative join parsing
360 /// by default when parentheses are omitted in nested joins.
361 ///
362 /// Most dialects (like MySQL or Postgres) assume **left-associative** precedence,
363 /// so a query like:
364 ///
365 /// ```sql
366 /// SELECT * FROM t1 NATURAL JOIN t5 INNER JOIN t0 ON ...
367 /// ```
368 /// is interpreted as:
369 /// ```sql
370 /// ((t1 NATURAL JOIN t5) INNER JOIN t0 ON ...)
371 /// ```
372 /// and internally represented as a **flat list** of joins.
373 ///
374 /// In contrast, some dialects (e.g. **Snowflake**) assume **right-associative**
375 /// precedence and interpret the same query as:
376 /// ```sql
377 /// (t1 NATURAL JOIN (t5 INNER JOIN t0 ON ...))
378 /// ```
379 /// which results in a **nested join** structure in the AST.
380 ///
381 /// If this method returns `false`, the parser must build nested join trees
382 /// even in the absence of parentheses to reflect the correct associativity
383 fn supports_left_associative_joins_without_parens(&self) -> bool {
384 true
385 }
386
387 /// Returns true if the dialect supports the `(+)` syntax for OUTER JOIN.
388 fn supports_outer_join_operator(&self) -> bool {
389 false
390 }
391
392 /// Returns true if the dialect supports a join specification on CROSS JOIN.
393 fn supports_cross_join_constraint(&self) -> bool {
394 false
395 }
396
397 /// Returns true if the dialect supports CONNECT BY.
398 fn supports_connect_by(&self) -> bool {
399 false
400 }
401
402 /// Returns true if the dialect supports `EXECUTE IMMEDIATE` statements.
403 fn supports_execute_immediate(&self) -> bool {
404 false
405 }
406
407 /// Returns true if the dialect supports the MATCH_RECOGNIZE operation.
408 fn supports_match_recognize(&self) -> bool {
409 false
410 }
411
412 /// Returns true if the dialect supports `(NOT) IN ()` expressions
413 fn supports_in_empty_list(&self) -> bool {
414 false
415 }
416
417 /// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE | TRY | CATCH} [TRANSACTION]` statements
418 fn supports_start_transaction_modifier(&self) -> bool {
419 false
420 }
421
422 /// Returns true if the dialect supports `END {TRY | CATCH}` statements
423 fn supports_end_transaction_modifier(&self) -> bool {
424 false
425 }
426
427 /// Returns true if the dialect supports named arguments of the form `FUN(a = '1', b = '2')`.
428 fn supports_named_fn_args_with_eq_operator(&self) -> bool {
429 false
430 }
431
432 /// Returns true if the dialect supports named arguments of the form `FUN(a : '1', b : '2')`.
433 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
434 false
435 }
436
437 /// Returns true if the dialect supports named arguments of the form `FUN(a := '1', b := '2')`.
438 fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
439 false
440 }
441
442 /// Returns true if the dialect supports named arguments of the form `FUN(a => '1', b => '2')`.
443 fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
444 true
445 }
446
447 /// Returns true if dialect supports argument name as arbitrary expression.
448 /// e.g. `FUN(LOWER('a'):'1', b:'2')`
449 /// Such function arguments are represented in the AST by the `FunctionArg::ExprNamed` variant,
450 /// otherwise use the `FunctionArg::Named` variant (compatible reason).
451 fn supports_named_fn_args_with_expr_name(&self) -> bool {
452 false
453 }
454
455 /// Returns true if the dialect supports identifiers starting with a numeric
456 /// prefix such as tables named `59901_user_login`
457 fn supports_numeric_prefix(&self) -> bool {
458 false
459 }
460
461 /// Returns true if the dialect supports numbers containing underscores, e.g. `10_000_000`
462 fn supports_numeric_literal_underscores(&self) -> bool {
463 false
464 }
465
466 /// Returns true if the dialects supports specifying null treatment
467 /// as part of a window function's parameter list as opposed
468 /// to after the parameter list.
469 ///
470 /// i.e The following syntax returns true
471 /// ```sql
472 /// FIRST_VALUE(a IGNORE NULLS) OVER ()
473 /// ```
474 /// while the following syntax returns false
475 /// ```sql
476 /// FIRST_VALUE(a) IGNORE NULLS OVER ()
477 /// ```
478 fn supports_window_function_null_treatment_arg(&self) -> bool {
479 false
480 }
481
482 /// Returns true if the dialect supports defining structs or objects using a
483 /// syntax like `{'x': 1, 'y': 2, 'z': 3}`.
484 fn supports_dictionary_syntax(&self) -> bool {
485 false
486 }
487
488 /// Returns true if the dialect supports defining object using the
489 /// syntax like `Map {1: 10, 2: 20}`.
490 fn support_map_literal_syntax(&self) -> bool {
491 false
492 }
493
494 /// Returns true if the dialect supports lambda functions, for example:
495 ///
496 /// ```sql
497 /// SELECT transform(array(1, 2, 3), x -> x + 1); -- returns [2,3,4]
498 /// ```
499 fn supports_lambda_functions(&self) -> bool {
500 false
501 }
502
503 /// Returns true if the dialect supports multiple variable assignment
504 /// using parentheses in a `SET` variable declaration.
505 ///
506 /// ```sql
507 /// SET (variable[, ...]) = (expression[, ...]);
508 /// ```
509 fn supports_parenthesized_set_variables(&self) -> bool {
510 false
511 }
512
513 /// Returns true if the dialect supports multiple `SET` statements
514 /// in a single statement.
515 ///
516 /// ```sql
517 /// SET variable = expression [, variable = expression];
518 /// ```
519 fn supports_comma_separated_set_assignments(&self) -> bool {
520 false
521 }
522
523 /// Returns true if the dialect supports `ORDER BY` in `UPDATE` statements.
524 ///
525 /// ```sql
526 /// UPDATE foo SET bar = false WHERE foo = true ORDER BY foo ASC;
527 /// ```
528 /// See <https://dev.mysql.com/doc/refman/8.4/en/update.html>
529 fn supports_update_order_by(&self) -> bool {
530 false
531 }
532
533 /// Returns true if the dialect supports an `EXCEPT` clause following a
534 /// wildcard in a select list.
535 ///
536 /// For example
537 /// ```sql
538 /// SELECT * EXCEPT order_id FROM orders;
539 /// ```
540 fn supports_select_wildcard_except(&self) -> bool {
541 false
542 }
543
544 /// Returns true if the dialect has a CONVERT function which accepts a type first
545 /// and an expression second, e.g. `CONVERT(varchar, 1)`
546 fn convert_type_before_value(&self) -> bool {
547 false
548 }
549
550 /// Returns true if the dialect supports triple quoted string
551 /// e.g. `"""abc"""`
552 fn supports_triple_quoted_string(&self) -> bool {
553 false
554 }
555
556 /// Dialect-specific prefix parser override
557 fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
558 // return None to fall back to the default behavior
559 None
560 }
561
562 /// Does the dialect support trailing commas around the query?
563 fn supports_trailing_commas(&self) -> bool {
564 false
565 }
566
567 /// Does the dialect support parsing `LIMIT 1, 2` as `LIMIT 2 OFFSET 1`?
568 fn supports_limit_comma(&self) -> bool {
569 false
570 }
571
572 /// Returns true if the dialect supports concatenating of string literal
573 /// Example: `SELECT 'Hello ' "world" => SELECT 'Hello world'`
574 fn supports_string_literal_concatenation(&self) -> bool {
575 false
576 }
577
578 /// Returns true if the dialect supports concatenating string literals with a newline.
579 /// For example, the following statement would return `true`:
580 /// ```sql
581 /// SELECT 'abc' in (
582 /// 'a'
583 /// 'b'
584 /// 'c'
585 /// );
586 /// ```
587 fn supports_string_literal_concatenation_with_newline(&self) -> bool {
588 false
589 }
590
591 /// Does the dialect support trailing commas in the projection list?
592 fn supports_projection_trailing_commas(&self) -> bool {
593 self.supports_trailing_commas()
594 }
595
596 /// Returns true if the dialect supports trailing commas in the `FROM` clause of a `SELECT` statement.
597 /// Example: `SELECT 1 FROM T, U, LIMIT 1`
598 fn supports_from_trailing_commas(&self) -> bool {
599 false
600 }
601
602 /// Returns true if the dialect supports trailing commas in the
603 /// column definitions list of a `CREATE` statement.
604 /// Example: `CREATE TABLE T (x INT, y TEXT,)`
605 fn supports_column_definition_trailing_commas(&self) -> bool {
606 false
607 }
608
609 /// Returns true if the dialect supports double dot notation for object names
610 ///
611 /// Example
612 /// ```sql
613 /// SELECT * FROM db_name..table_name
614 /// ```
615 fn supports_object_name_double_dot_notation(&self) -> bool {
616 false
617 }
618
619 /// Return true if the dialect supports the STRUCT literal
620 ///
621 /// Example
622 /// ```sql
623 /// SELECT STRUCT(1 as one, 'foo' as foo, false)
624 /// ```
625 fn supports_struct_literal(&self) -> bool {
626 false
627 }
628
629 /// Return true if the dialect supports empty projections in SELECT statements
630 ///
631 /// Example
632 /// ```sql
633 /// SELECT from table_name
634 /// ```
635 fn supports_empty_projections(&self) -> bool {
636 false
637 }
638
639 /// Return true if the dialect supports wildcard expansion on
640 /// arbitrary expressions in projections.
641 ///
642 /// Example:
643 /// ```sql
644 /// SELECT STRUCT<STRING>('foo').* FROM T
645 /// ```
646 fn supports_select_expr_star(&self) -> bool {
647 false
648 }
649
650 /// Return true if the dialect supports "FROM-first" selects.
651 ///
652 /// Example:
653 /// ```sql
654 /// FROM table
655 /// SELECT *
656 /// ```
657 fn supports_from_first_select(&self) -> bool {
658 false
659 }
660
661 /// Return true if the dialect supports "FROM-first" inserts.
662 ///
663 /// Example:
664 /// ```sql
665 /// WITH cte AS (SELECT key FROM src)
666 /// FROM cte
667 /// INSERT OVERWRITE table my_table
668 /// SELECT *
669 ///
670 /// See <https://hive.apache.org/docs/latest/language/common-table-expression/>
671 /// ```
672 fn supports_from_first_insert(&self) -> bool {
673 false
674 }
675
676 /// Return true if the dialect supports pipe operator.
677 ///
678 /// Example:
679 /// ```sql
680 /// SELECT *
681 /// FROM table
682 /// |> limit 1
683 /// ```
684 ///
685 /// See <https://cloud.google.com/bigquery/docs/pipe-syntax-guide#basic_syntax>
686 fn supports_pipe_operator(&self) -> bool {
687 false
688 }
689
690 /// Does the dialect support MySQL-style `'user'@'host'` grantee syntax?
691 fn supports_user_host_grantee(&self) -> bool {
692 false
693 }
694
695 /// Does the dialect support the `MATCH() AGAINST()` syntax?
696 fn supports_match_against(&self) -> bool {
697 false
698 }
699
700 /// Returns true if the dialect supports an exclude option
701 /// following a wildcard in the projection section. For example:
702 /// `SELECT * EXCLUDE col1 FROM tbl`.
703 ///
704 /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
705 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select)
706 fn supports_select_wildcard_exclude(&self) -> bool {
707 false
708 }
709
710 /// Returns true if the dialect supports an exclude option
711 /// as the last item in the projection section, not necessarily
712 /// after a wildcard. For example:
713 /// `SELECT *, c1, c2 EXCLUDE c3 FROM tbl`
714 ///
715 /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
716 fn supports_select_exclude(&self) -> bool {
717 false
718 }
719
720 /// Returns true if the dialect supports specifying multiple options
721 /// in a `CREATE TABLE` statement for the structure of the new table. For example:
722 /// `CREATE TABLE t (a INT, b INT) AS SELECT 1 AS b, 2 AS a`
723 fn supports_create_table_multi_schema_info_sources(&self) -> bool {
724 false
725 }
726
727 /// Returns true if the dialect supports MySQL-specific SELECT modifiers
728 /// like `HIGH_PRIORITY`, `STRAIGHT_JOIN`, `SQL_SMALL_RESULT`, etc.
729 ///
730 /// For example:
731 /// ```sql
732 /// SELECT HIGH_PRIORITY STRAIGHT_JOIN SQL_SMALL_RESULT * FROM t1 JOIN t2 ON ...
733 /// ```
734 ///
735 /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/select.html)
736 fn supports_select_modifiers(&self) -> bool {
737 false
738 }
739
740 /// Dialect-specific infix parser override
741 ///
742 /// This method is called to parse the next infix expression.
743 ///
744 /// If `None` is returned, falls back to the default behavior.
745 fn parse_infix(
746 &self,
747 _parser: &mut Parser,
748 _expr: &Expr,
749 _precedence: u8,
750 ) -> Option<Result<Expr, ParserError>> {
751 // return None to fall back to the default behavior
752 None
753 }
754
755 /// Dialect-specific precedence override
756 ///
757 /// This method is called to get the precedence of the next token.
758 ///
759 /// If `None` is returned, falls back to the default behavior.
760 fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
761 // return None to fall back to the default behavior
762 None
763 }
764
765 /// Get the precedence of the next token, looking at the full token stream.
766 ///
767 /// A higher number => higher precedence
768 ///
769 /// See [`Self::get_next_precedence`] to override the behavior for just the
770 /// next token.
771 ///
772 /// The default implementation is used for many dialects, but can be
773 /// overridden to provide dialect-specific behavior.
774 fn get_next_precedence_default(&self, parser: &Parser) -> Result<u8, ParserError> {
775 if let Some(precedence) = self.get_next_precedence(parser) {
776 return precedence;
777 }
778 macro_rules! p {
779 ($precedence:ident) => {
780 self.prec_value(Precedence::$precedence)
781 };
782 }
783
784 let token = parser.peek_token_ref();
785 debug!("get_next_precedence_full() {token:?}");
786 match &token.token {
787 Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
788 Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
789 Token::Word(w) if w.keyword == Keyword::XOR => Ok(p!(Xor)),
790
791 Token::Word(w) if w.keyword == Keyword::AT => {
792 match (
793 &parser.peek_nth_token_ref(1).token,
794 &parser.peek_nth_token_ref(2).token,
795 ) {
796 (Token::Word(w), Token::Word(w2))
797 if w.keyword == Keyword::TIME && w2.keyword == Keyword::ZONE =>
798 {
799 Ok(p!(AtTz))
800 }
801 _ => Ok(self.prec_unknown()),
802 }
803 }
804
805 Token::Word(w) if w.keyword == Keyword::NOT => {
806 match &parser.peek_nth_token_ref(1).token {
807 // The precedence of NOT varies depending on keyword that
808 // follows it. If it is followed by IN, BETWEEN, or LIKE,
809 // it takes on the precedence of those tokens. Otherwise, it
810 // is not an infix operator, and therefore has zero
811 // precedence.
812 Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
813 Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
814 Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
815 Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
816 Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
817 Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
818 Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
819 Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
820 Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
821 Token::Word(w)
822 if w.keyword == Keyword::NULL && !parser.in_column_definition_state() =>
823 {
824 Ok(p!(Is))
825 }
826 _ => Ok(self.prec_unknown()),
827 }
828 }
829 Token::Word(w) if w.keyword == Keyword::NOTNULL && self.supports_notnull_operator() => {
830 Ok(p!(Is))
831 }
832 Token::Word(w) if w.keyword == Keyword::IS => Ok(p!(Is)),
833 Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
834 Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
835 Token::Word(w) if w.keyword == Keyword::OVERLAPS => Ok(p!(Between)),
836 Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
837 Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
838 Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
839 Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
840 Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
841 Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
842 Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
843 Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(p!(Between)),
844 Token::Word(w) if w.keyword == Keyword::DIV => Ok(p!(MulDivModOp)),
845 Token::Period => Ok(p!(Period)),
846 Token::Assignment
847 | Token::Eq
848 | Token::Lt
849 | Token::LtEq
850 | Token::Neq
851 | Token::Gt
852 | Token::GtEq
853 | Token::DoubleEq
854 | Token::Tilde
855 | Token::TildeAsterisk
856 | Token::ExclamationMarkTilde
857 | Token::ExclamationMarkTildeAsterisk
858 | Token::DoubleTilde
859 | Token::DoubleTildeAsterisk
860 | Token::ExclamationMarkDoubleTilde
861 | Token::ExclamationMarkDoubleTildeAsterisk
862 | Token::Spaceship => Ok(p!(Eq)),
863 Token::Pipe
864 | Token::QuestionMarkDash
865 | Token::DoubleSharp
866 | Token::Overlap
867 | Token::AmpersandLeftAngleBracket
868 | Token::AmpersandRightAngleBracket
869 | Token::QuestionMarkDashVerticalBar
870 | Token::AmpersandLeftAngleBracketVerticalBar
871 | Token::VerticalBarAmpersandRightAngleBracket
872 | Token::TwoWayArrow
873 | Token::LeftAngleBracketCaret
874 | Token::RightAngleBracketCaret
875 | Token::QuestionMarkSharp
876 | Token::QuestionMarkDoubleVerticalBar
877 | Token::QuestionPipe
878 | Token::TildeEqual
879 | Token::AtSign
880 | Token::ShiftLeftVerticalBar
881 | Token::VerticalBarShiftRight => Ok(p!(Pipe)),
882 Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
883 Token::Ampersand => Ok(p!(Ampersand)),
884 Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
885 Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
886 Ok(p!(MulDivModOp))
887 }
888 Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
889 Ok(p!(DoubleColon))
890 }
891 Token::Colon => match &parser.peek_nth_token_ref(1).token {
892 // When colon is followed by a string or a number, it's usually in MAP syntax.
893 Token::SingleQuotedString(_) | Token::Number(_, _) => Ok(self.prec_unknown()),
894 // In other cases, it's used in semi-structured data traversal like in variant or JSON
895 // string columns. See `JsonAccess`.
896 _ => Ok(p!(Colon)),
897 },
898 Token::Arrow
899 | Token::LongArrow
900 | Token::HashArrow
901 | Token::HashLongArrow
902 | Token::AtArrow
903 | Token::ArrowAt
904 | Token::HashMinus
905 | Token::AtQuestion
906 | Token::AtAt
907 | Token::Question
908 | Token::QuestionAnd
909 | Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
910 _ => Ok(self.prec_unknown()),
911 }
912 }
913
914 /// Dialect-specific statement parser override
915 ///
916 /// This method is called to parse the next statement.
917 ///
918 /// If `None` is returned, falls back to the default behavior.
919 fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
920 // return None to fall back to the default behavior
921 None
922 }
923
924 /// Dialect-specific column option parser override
925 ///
926 /// This method is called to parse the next column option.
927 ///
928 /// If `None` is returned, falls back to the default behavior.
929 fn parse_column_option(
930 &self,
931 _parser: &mut Parser,
932 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
933 // return None to fall back to the default behavior
934 Ok(None)
935 }
936
937 /// Decide the lexical Precedence of operators.
938 ///
939 /// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
940 fn prec_value(&self, prec: Precedence) -> u8 {
941 match prec {
942 Precedence::Period => 100,
943 Precedence::DoubleColon => 50,
944 Precedence::AtTz => 41,
945 Precedence::MulDivModOp => 40,
946 Precedence::PlusMinus => 30,
947 Precedence::Xor => 24,
948 Precedence::Ampersand => 23,
949 Precedence::Caret => 22,
950 Precedence::Pipe => 21,
951 Precedence::Colon => 21,
952 Precedence::Between => 20,
953 Precedence::Eq => 20,
954 Precedence::Like => 19,
955 Precedence::Is => 17,
956 Precedence::PgOther => 16,
957 Precedence::UnaryNot => 15,
958 Precedence::And => 10,
959 Precedence::Or => 5,
960 }
961 }
962
963 /// Returns the precedence when the precedence is otherwise unknown
964 fn prec_unknown(&self) -> u8 {
965 0
966 }
967
968 /// Returns true if this dialect requires the `TABLE` keyword after `DESCRIBE`
969 ///
970 /// Defaults to false.
971 ///
972 /// If true, the following statement is valid: `DESCRIBE TABLE my_table`
973 /// If false, the following statements are valid: `DESCRIBE my_table` and `DESCRIBE table`
974 fn describe_requires_table_keyword(&self) -> bool {
975 false
976 }
977
978 /// Returns true if this dialect allows the `EXTRACT` function to words other than [`Keyword`].
979 fn allow_extract_custom(&self) -> bool {
980 false
981 }
982
983 /// Returns true if this dialect allows the `EXTRACT` function to use single quotes in the part being extracted.
984 fn allow_extract_single_quotes(&self) -> bool {
985 false
986 }
987
988 /// Returns true if this dialect supports the `EXTRACT` function
989 /// with a comma separator instead of `FROM`.
990 ///
991 /// Example:
992 /// ```sql
993 /// SELECT EXTRACT(YEAR, date_column) FROM table;
994 /// ```
995 ///
996 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/functions/extract)
997 fn supports_extract_comma_syntax(&self) -> bool {
998 false
999 }
1000
1001 /// Returns true if this dialect supports a subquery passed to a function
1002 /// as the only argument without enclosing parentheses.
1003 ///
1004 /// Example:
1005 /// ```sql
1006 /// SELECT FLATTEN(SELECT * FROM tbl);
1007 /// ```
1008 ///
1009 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/functions/flatten)
1010 fn supports_subquery_as_function_arg(&self) -> bool {
1011 false
1012 }
1013
1014 /// Returns true if this dialect supports the `COMMENT` clause in
1015 /// `CREATE VIEW` statements using the `COMMENT = 'comment'` syntax.
1016 ///
1017 /// Example:
1018 /// ```sql
1019 /// CREATE VIEW v COMMENT = 'my comment' AS SELECT 1;
1020 /// ```
1021 ///
1022 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/create-view#optional-parameters)
1023 fn supports_create_view_comment_syntax(&self) -> bool {
1024 false
1025 }
1026
1027 /// Returns true if this dialect supports the `ARRAY` type without
1028 /// specifying an element type.
1029 ///
1030 /// Example:
1031 /// ```sql
1032 /// CREATE TABLE t (a ARRAY);
1033 /// ```
1034 ///
1035 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/data-types-semistructured#array)
1036 fn supports_array_typedef_without_element_type(&self) -> bool {
1037 false
1038 }
1039
1040 /// Returns true if this dialect supports extra parentheses around
1041 /// lone table names or derived tables in the `FROM` clause.
1042 ///
1043 /// Example:
1044 /// ```sql
1045 /// SELECT * FROM (mytable);
1046 /// SELECT * FROM ((SELECT 1));
1047 /// SELECT * FROM (mytable) AS alias;
1048 /// ```
1049 ///
1050 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/from)
1051 fn supports_parens_around_table_factor(&self) -> bool {
1052 false
1053 }
1054
1055 /// Returns true if this dialect supports `VALUES` as a table factor
1056 /// without requiring parentheses around the entire clause.
1057 ///
1058 /// Example:
1059 /// ```sql
1060 /// SELECT * FROM VALUES (1, 'a'), (2, 'b') AS t (col1, col2);
1061 /// ```
1062 ///
1063 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/values)
1064 /// [Databricks](https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-values.html)
1065 fn supports_values_as_table_factor(&self) -> bool {
1066 false
1067 }
1068
1069 /// Returns true if this dialect allows dollar placeholders
1070 /// e.g. `SELECT $var` (SQLite)
1071 fn supports_dollar_placeholder(&self) -> bool {
1072 false
1073 }
1074
1075 /// Returns true if this dialect supports `$` as a prefix for money literals
1076 /// e.g. `SELECT $123.45` (SQL Server)
1077 fn supports_dollar_as_money_prefix(&self) -> bool {
1078 false
1079 }
1080
1081 /// Does the dialect support with clause in create index statement?
1082 /// e.g. `CREATE INDEX idx ON t WITH (key = value, key2)`
1083 fn supports_create_index_with_clause(&self) -> bool {
1084 false
1085 }
1086
1087 /// Whether `INTERVAL` expressions require units (called "qualifiers" in the ANSI SQL spec) to be specified,
1088 /// e.g. `INTERVAL 1 DAY` vs `INTERVAL 1`.
1089 ///
1090 /// Expressions within intervals (e.g. `INTERVAL '1' + '1' DAY`) are only allowed when units are required.
1091 ///
1092 /// See <https://github.com/sqlparser-rs/sqlparser-rs/pull/1398> for more information.
1093 ///
1094 /// When `true`:
1095 /// * `INTERVAL '1' DAY` is VALID
1096 /// * `INTERVAL 1 + 1 DAY` is VALID
1097 /// * `INTERVAL '1' + '1' DAY` is VALID
1098 /// * `INTERVAL '1'` is INVALID
1099 ///
1100 /// When `false`:
1101 /// * `INTERVAL '1'` is VALID
1102 /// * `INTERVAL '1' DAY` is VALID — unit is not required, but still allowed
1103 /// * `INTERVAL 1 + 1 DAY` is INVALID
1104 fn require_interval_qualifier(&self) -> bool {
1105 false
1106 }
1107
1108 /// Returns true if the dialect supports `EXPLAIN` statements with utility options
1109 /// e.g. `EXPLAIN (ANALYZE TRUE, BUFFERS TRUE) SELECT * FROM tbl;`
1110 fn supports_explain_with_utility_options(&self) -> bool {
1111 false
1112 }
1113
1114 /// Returns true if the dialect supports `ASC` and `DESC` in column definitions
1115 /// e.g. `CREATE TABLE t (a INT ASC, b INT DESC);`
1116 fn supports_asc_desc_in_column_definition(&self) -> bool {
1117 false
1118 }
1119
1120 /// Returns true if the dialect supports `a!` expressions
1121 fn supports_factorial_operator(&self) -> bool {
1122 false
1123 }
1124
1125 /// Returns true if the dialect supports `<<` and `>>` shift operators.
1126 fn supports_bitwise_shift_operators(&self) -> bool {
1127 false
1128 }
1129
1130 /// Returns true if the dialect supports nested comments
1131 /// e.g. `/* /* nested */ */`
1132 fn supports_nested_comments(&self) -> bool {
1133 false
1134 }
1135
1136 /// Returns true if the dialect supports optimizer hints in multiline comments
1137 /// e.g. `/*!50110 KEY_BLOCK_SIZE = 1024*/`
1138 fn supports_multiline_comment_hints(&self) -> bool {
1139 false
1140 }
1141
1142 /// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
1143 /// as an alias assignment operator, rather than a boolean expression.
1144 /// For example: the following statements are equivalent for such a dialect:
1145 /// ```sql
1146 /// SELECT col_alias = col FROM tbl;
1147 /// SELECT col_alias AS col FROM tbl;
1148 /// ```
1149 fn supports_eq_alias_assignment(&self) -> bool {
1150 false
1151 }
1152
1153 /// Returns true if this dialect supports the `TRY_CONVERT` function
1154 fn supports_try_convert(&self) -> bool {
1155 false
1156 }
1157
1158 /// Returns true if the dialect supports `!a` syntax for boolean `NOT` expressions.
1159 fn supports_bang_not_operator(&self) -> bool {
1160 false
1161 }
1162
1163 /// Returns true if the dialect supports the `LISTEN`, `UNLISTEN` and `NOTIFY` statements
1164 fn supports_listen_notify(&self) -> bool {
1165 false
1166 }
1167
1168 /// Returns true if the dialect supports the `LOAD DATA` statement
1169 fn supports_load_data(&self) -> bool {
1170 false
1171 }
1172
1173 /// Returns true if the dialect supports the `LOAD extension` statement
1174 fn supports_load_extension(&self) -> bool {
1175 false
1176 }
1177
1178 /// Returns true if this dialect expects the `TOP` option
1179 /// before the `ALL`/`DISTINCT` options in a `SELECT` statement.
1180 fn supports_top_before_distinct(&self) -> bool {
1181 false
1182 }
1183
1184 /// Returns true if the dialect supports boolean literals (`true` and `false`).
1185 /// For example, in MSSQL these are treated as identifiers rather than boolean literals.
1186 fn supports_boolean_literals(&self) -> bool {
1187 true
1188 }
1189
1190 /// Returns true if this dialect supports the `LIKE 'pattern'` option in
1191 /// a `SHOW` statement before the `IN` option
1192 fn supports_show_like_before_in(&self) -> bool {
1193 false
1194 }
1195
1196 /// Returns true if this dialect supports the `COMMENT` statement
1197 fn supports_comment_on(&self) -> bool {
1198 false
1199 }
1200
1201 /// Returns true if the dialect supports the `CREATE TABLE SELECT` statement
1202 fn supports_create_table_select(&self) -> bool {
1203 false
1204 }
1205
1206 /// Returns true if the dialect supports PartiQL for querying semi-structured data
1207 /// <https://partiql.org/index.html>
1208 fn supports_partiql(&self) -> bool {
1209 false
1210 }
1211
1212 /// Returns true if the dialect supports the `CONSTRAINT` keyword without a name
1213 /// in table constraint definitions.
1214 ///
1215 /// Example:
1216 /// ```sql
1217 /// CREATE TABLE t (a INT, CONSTRAINT CHECK (a > 0))
1218 /// ```
1219 ///
1220 /// This is a MySQL extension; the SQL standard requires a name after `CONSTRAINT`.
1221 /// When the name is omitted, the output normalizes to just the constraint type
1222 /// without the `CONSTRAINT` keyword (e.g., `CHECK (a > 0)`).
1223 ///
1224 /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
1225 fn supports_constraint_keyword_without_name(&self) -> bool {
1226 false
1227 }
1228
1229 /// Returns true if the dialect supports the `KEY` keyword as part of
1230 /// column-level constraints in a `CREATE TABLE` statement.
1231 ///
1232 /// When enabled, the parser accepts these MySQL-specific column options:
1233 /// - `UNIQUE [KEY]` — optional `KEY` after `UNIQUE`
1234 /// - `[PRIMARY] KEY` — standalone `KEY` as shorthand for `PRIMARY KEY`
1235 ///
1236 /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
1237 fn supports_key_column_option(&self) -> bool {
1238 false
1239 }
1240
1241 /// Returns true if the specified keyword is reserved and cannot be
1242 /// used as an identifier without special handling like quoting.
1243 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
1244 keywords::RESERVED_FOR_IDENTIFIER.contains(&kw)
1245 }
1246
1247 /// Returns reserved keywords that may prefix a select item expression
1248 /// e.g. `SELECT CONNECT_BY_ROOT name FROM Tbl2` (Snowflake)
1249 fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
1250 &[]
1251 }
1252
1253 /// Returns grantee types that should be treated as identifiers
1254 fn get_reserved_grantees_types(&self) -> &[GranteesType] {
1255 &[]
1256 }
1257
1258 /// Returns true if this dialect supports the `TABLESAMPLE` option
1259 /// before the table alias option. For example:
1260 ///
1261 /// Table sample before alias: `SELECT * FROM tbl AS t TABLESAMPLE (10)`
1262 /// Table sample after alias: `SELECT * FROM tbl TABLESAMPLE (10) AS t`
1263 ///
1264 /// <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#_7_6_table_reference>
1265 fn supports_table_sample_before_alias(&self) -> bool {
1266 false
1267 }
1268
1269 /// Returns true if this dialect supports the `INSERT INTO ... SET col1 = 1, ...` syntax.
1270 ///
1271 /// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
1272 fn supports_insert_set(&self) -> bool {
1273 false
1274 }
1275
1276 /// Does the dialect support table function in insertion?
1277 fn supports_insert_table_function(&self) -> bool {
1278 false
1279 }
1280
1281 /// Does the dialect support table queries in insertion?
1282 ///
1283 /// e.g. `SELECT INTO (<query>) ...`
1284 fn supports_insert_table_query(&self) -> bool {
1285 false
1286 }
1287
1288 /// Does the dialect support insert formats, e.g. `INSERT INTO ... FORMAT <format>`
1289 fn supports_insert_format(&self) -> bool {
1290 false
1291 }
1292
1293 /// Returns true if this dialect supports `INSERT INTO t [[AS] alias] ...`.
1294 fn supports_insert_table_alias(&self) -> bool {
1295 false
1296 }
1297
1298 /// Returns true if this dialect supports `SET` statements without an explicit
1299 /// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
1300 fn supports_set_stmt_without_operator(&self) -> bool {
1301 false
1302 }
1303
1304 /// Returns true if the specified keyword should be parsed as a column identifier.
1305 /// See [keywords::RESERVED_FOR_COLUMN_ALIAS]
1306 fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1307 !keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw)
1308 }
1309
1310 /// Returns true if the specified keyword should be parsed as a select item alias.
1311 /// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
1312 /// to enable looking ahead if needed.
1313 fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
1314 explicit || self.is_column_alias(kw, parser)
1315 }
1316
1317 /// Returns true if the specified keyword should be parsed as a table factor identifier.
1318 /// See [keywords::RESERVED_FOR_TABLE_FACTOR]
1319 fn is_table_factor(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1320 !keywords::RESERVED_FOR_TABLE_FACTOR.contains(kw)
1321 }
1322
1323 /// Returns true if the specified keyword should be parsed as a table factor alias.
1324 /// See [keywords::RESERVED_FOR_TABLE_ALIAS]
1325 fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1326 !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
1327 }
1328
1329 /// Returns true if the specified keyword should be parsed as a table factor alias.
1330 /// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
1331 /// to enable looking ahead if needed.
1332 fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
1333 explicit || self.is_table_alias(kw, parser)
1334 }
1335
1336 /// Returns true if this dialect supports querying historical table data
1337 /// by specifying which version of the data to query.
1338 fn supports_table_versioning(&self) -> bool {
1339 false
1340 }
1341
1342 /// Returns true if this dialect supports the E'...' syntax for string literals
1343 ///
1344 /// Postgres: <https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE>
1345 fn supports_string_escape_constant(&self) -> bool {
1346 false
1347 }
1348
1349 /// Returns true if the dialect supports the table hints in the `FROM` clause.
1350 fn supports_table_hints(&self) -> bool {
1351 false
1352 }
1353
1354 /// Returns true if this dialect requires a whitespace character after `--` to start a single line comment.
1355 ///
1356 /// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/ansi-diff-comments.html>
1357 /// e.g. UPDATE account SET balance=balance--1
1358 // WHERE account_id=5752 ^^^ will be interpreted as two minus signs instead of a comment
1359 fn requires_single_line_comment_whitespace(&self) -> bool {
1360 false
1361 }
1362
1363 /// Returns true if the dialect supports array type definition with brackets with
1364 /// an optional size. For example:
1365 /// ```CREATE TABLE my_table (arr1 INT[], arr2 INT[3])```
1366 /// ```SELECT x::INT[]```
1367 fn supports_array_typedef_with_brackets(&self) -> bool {
1368 false
1369 }
1370 /// Returns true if the dialect supports geometric types.
1371 ///
1372 /// Postgres: <https://www.postgresql.org/docs/9.5/functions-geometry.html>
1373 /// e.g. @@ circle '((0,0),10)'
1374 fn supports_geometric_types(&self) -> bool {
1375 false
1376 }
1377
1378 /// Returns true if the dialect supports `ORDER BY ALL`.
1379 /// `ALL` which means all columns of the SELECT clause.
1380 ///
1381 /// For example: ```SELECT * FROM addresses ORDER BY ALL;```.
1382 fn supports_order_by_all(&self) -> bool {
1383 false
1384 }
1385
1386 /// Returns true if the dialect supports `SET NAMES <charset_name> [COLLATE <collation_name>]`.
1387 ///
1388 /// - [MySQL](https://dev.mysql.com/doc/refman/8.4/en/set-names.html)
1389 /// - [PostgreSQL](https://www.postgresql.org/docs/17/sql-set.html)
1390 ///
1391 /// Note: Postgres doesn't support the `COLLATE` clause, but we permissively parse it anyway.
1392 fn supports_set_names(&self) -> bool {
1393 false
1394 }
1395
1396 /// Returns true if the dialect supports space-separated column options
1397 /// in a `CREATE TABLE` statement. For example:
1398 /// ```sql
1399 /// CREATE TABLE tbl (
1400 /// col INT NOT NULL DEFAULT 0
1401 /// );
1402 /// ```
1403 fn supports_space_separated_column_options(&self) -> bool {
1404 false
1405 }
1406
1407 /// Returns true if the dialect supports the `USING` clause in an `ALTER COLUMN` statement.
1408 /// Example:
1409 /// ```sql
1410 /// ALTER TABLE tbl ALTER COLUMN col SET DATA TYPE <type> USING <exp>`
1411 /// ```
1412 fn supports_alter_column_type_using(&self) -> bool {
1413 false
1414 }
1415
1416 /// Returns true if the dialect supports `ALTER TABLE tbl DROP COLUMN c1, ..., cn`
1417 fn supports_comma_separated_drop_column_list(&self) -> bool {
1418 false
1419 }
1420
1421 /// Returns true if the dialect considers the specified ident as a function
1422 /// that returns an identifier. Typically used to generate identifiers
1423 /// programmatically.
1424 ///
1425 /// - [Snowflake](https://docs.snowflake.com/en/sql-reference/identifier-literal)
1426 fn is_identifier_generating_function_name(
1427 &self,
1428 _ident: &Ident,
1429 _name_parts: &[ObjectNamePart],
1430 ) -> bool {
1431 false
1432 }
1433
1434 /// Returns true if the dialect supports the `x NOTNULL`
1435 /// operator expression.
1436 fn supports_notnull_operator(&self) -> bool {
1437 false
1438 }
1439
1440 /// Returns true if this dialect allows an optional `SIGNED` suffix after integer data types.
1441 ///
1442 /// Example:
1443 /// ```sql
1444 /// CREATE TABLE t (i INT(20) SIGNED);
1445 /// ```
1446 ///
1447 /// Note that this is canonicalized to `INT(20)`.
1448 fn supports_data_type_signed_suffix(&self) -> bool {
1449 false
1450 }
1451
1452 /// Returns true if the dialect supports the `INTERVAL` data type with [Postgres]-style options.
1453 ///
1454 /// Examples:
1455 /// ```sql
1456 /// CREATE TABLE t (i INTERVAL YEAR TO MONTH);
1457 /// SELECT '1 second'::INTERVAL HOUR TO SECOND(3);
1458 /// ```
1459 ///
1460 /// See [`crate::ast::DataType::Interval`] and [`crate::ast::IntervalFields`].
1461 ///
1462 /// [Postgres]: https://www.postgresql.org/docs/17/datatype-datetime.html
1463 fn supports_interval_options(&self) -> bool {
1464 false
1465 }
1466
1467 /// Returns true if the dialect supports specifying which table to copy
1468 /// the schema from inside parenthesis.
1469 ///
1470 /// Not parenthesized:
1471 /// '''sql
1472 /// CREATE TABLE new LIKE old ...
1473 /// '''
1474 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/create-table#label-create-table-like)
1475 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_like)
1476 ///
1477 /// Parenthesized:
1478 /// '''sql
1479 /// CREATE TABLE new (LIKE old ...)
1480 /// '''
1481 /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html)
1482 fn supports_create_table_like_parenthesized(&self) -> bool {
1483 false
1484 }
1485
1486 /// Returns true if the dialect supports `SEMANTIC_VIEW()` table functions.
1487 ///
1488 /// ```sql
1489 /// SELECT * FROM SEMANTIC_VIEW(
1490 /// model_name
1491 /// DIMENSIONS customer.name, customer.region
1492 /// METRICS orders.revenue, orders.count
1493 /// WHERE customer.active = true
1494 /// )
1495 /// ```
1496 fn supports_semantic_view_table_factor(&self) -> bool {
1497 false
1498 }
1499
1500 /// Support quote delimited string literals, e.g. `Q'{...}'`
1501 ///
1502 /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Literals.html#GUID-1824CBAA-6E16-4921-B2A6-112FB02248DA)
1503 fn supports_quote_delimited_string(&self) -> bool {
1504 false
1505 }
1506
1507 /// Returns `true` if the dialect supports query optimizer hints in the
1508 /// format of single and multi line comments immediately following a
1509 /// `SELECT`, `INSERT`, `REPLACE`, `DELETE`, or `MERGE` keyword.
1510 ///
1511 /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
1512 /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Comments.html#SQLRF-GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
1513 fn supports_comment_optimizer_hint(&self) -> bool {
1514 false
1515 }
1516
1517 /// Returns true if the dialect considers the `&&` operator as a boolean AND operator.
1518 fn supports_double_ampersand_operator(&self) -> bool {
1519 false
1520 }
1521
1522 /// Returns true if the dialect supports casting an expression to a binary type
1523 /// using the `BINARY <expr>` syntax.
1524 fn supports_binary_kw_as_cast(&self) -> bool {
1525 false
1526 }
1527
1528 /// Returns true if this dialect supports the `REPLACE` option in a
1529 /// `SELECT *` wildcard expression.
1530 ///
1531 /// Example:
1532 /// ```sql
1533 /// SELECT * REPLACE (col1 AS col1_alias) FROM table;
1534 /// ```
1535 ///
1536 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_replace)
1537 /// [ClickHouse](https://clickhouse.com/docs/sql-reference/statements/select#replace)
1538 /// [DuckDB](https://duckdb.org/docs/sql/query_syntax/select#replace-clause)
1539 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select#parameters)
1540 fn supports_select_wildcard_replace(&self) -> bool {
1541 false
1542 }
1543
1544 /// Returns true if this dialect supports the `ILIKE` option in a
1545 /// `SELECT *` wildcard expression.
1546 ///
1547 /// Example:
1548 /// ```sql
1549 /// SELECT * ILIKE '%pattern%' FROM table;
1550 /// ```
1551 ///
1552 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select#parameters)
1553 fn supports_select_wildcard_ilike(&self) -> bool {
1554 false
1555 }
1556
1557 /// Returns true if this dialect supports the `RENAME` option in a
1558 /// `SELECT *` wildcard expression.
1559 ///
1560 /// Example:
1561 /// ```sql
1562 /// SELECT * RENAME col1 AS col1_alias FROM table;
1563 /// ```
1564 ///
1565 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select#parameters)
1566 fn supports_select_wildcard_rename(&self) -> bool {
1567 false
1568 }
1569
1570 /// Returns true if this dialect supports aliasing a wildcard select item.
1571 ///
1572 /// Example:
1573 /// ```sql
1574 /// SELECT t.* alias FROM t
1575 /// SELECT t.* AS alias FROM t
1576 /// ```
1577 fn supports_select_wildcard_with_alias(&self) -> bool {
1578 false
1579 }
1580
1581 /// Returns true if this dialect supports the `OPTIMIZE TABLE` statement.
1582 ///
1583 /// Example:
1584 /// ```sql
1585 /// OPTIMIZE TABLE table_name;
1586 /// ```
1587 ///
1588 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
1589 fn supports_optimize_table(&self) -> bool {
1590 false
1591 }
1592
1593 /// Returns true if this dialect supports the `INSTALL` statement.
1594 ///
1595 /// Example:
1596 /// ```sql
1597 /// INSTALL extension_name;
1598 /// ```
1599 ///
1600 /// [DuckDB](https://duckdb.org/docs/extensions/overview)
1601 fn supports_install(&self) -> bool {
1602 false
1603 }
1604
1605 /// Returns true if this dialect supports the `DETACH` statement.
1606 ///
1607 /// Example:
1608 /// ```sql
1609 /// DETACH DATABASE db_name;
1610 /// ```
1611 ///
1612 /// [DuckDB](https://duckdb.org/docs/sql/statements/attach#detach-syntax)
1613 fn supports_detach(&self) -> bool {
1614 false
1615 }
1616
1617 /// Returns true if this dialect supports the `PREWHERE` clause
1618 /// in `SELECT` statements.
1619 ///
1620 /// Example:
1621 /// ```sql
1622 /// SELECT * FROM table PREWHERE col > 0 WHERE col < 100;
1623 /// ```
1624 ///
1625 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere)
1626 fn supports_prewhere(&self) -> bool {
1627 false
1628 }
1629
1630 /// Returns true if this dialect supports the `WITH FILL` clause
1631 /// in `ORDER BY` expressions.
1632 ///
1633 /// Example:
1634 /// ```sql
1635 /// SELECT * FROM table ORDER BY col WITH FILL FROM 1 TO 10 STEP 1;
1636 /// ```
1637 ///
1638 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier)
1639 fn supports_with_fill(&self) -> bool {
1640 false
1641 }
1642
1643 /// Returns true if this dialect supports the `LIMIT BY` clause.
1644 ///
1645 /// Example:
1646 /// ```sql
1647 /// SELECT * FROM table LIMIT 10 BY col;
1648 /// ```
1649 ///
1650 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/limit-by)
1651 fn supports_limit_by(&self) -> bool {
1652 false
1653 }
1654
1655 /// Returns true if this dialect supports the `INTERPOLATE` clause
1656 /// in `ORDER BY` expressions.
1657 ///
1658 /// Example:
1659 /// ```sql
1660 /// SELECT * FROM table ORDER BY col WITH FILL INTERPOLATE (col2 AS col2 + 1);
1661 /// ```
1662 ///
1663 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier)
1664 fn supports_interpolate(&self) -> bool {
1665 false
1666 }
1667
1668 /// Returns true if this dialect supports the `SETTINGS` clause.
1669 ///
1670 /// Example:
1671 /// ```sql
1672 /// SELECT * FROM table SETTINGS max_threads = 4;
1673 /// ```
1674 ///
1675 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select#settings-in-select-query)
1676 fn supports_settings(&self) -> bool {
1677 false
1678 }
1679
1680 /// Returns true if this dialect supports the `FORMAT` clause in `SELECT` statements.
1681 ///
1682 /// Example:
1683 /// ```sql
1684 /// SELECT * FROM table FORMAT JSON;
1685 /// ```
1686 ///
1687 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/format)
1688 fn supports_select_format(&self) -> bool {
1689 false
1690 }
1691
1692 /// Returns true if the dialect supports the two-argument comma-separated
1693 /// form of the `TRIM` function: `TRIM(expr, characters)`.
1694 fn supports_comma_separated_trim(&self) -> bool {
1695 false
1696 }
1697
1698 /// Returns true if the dialect supports the `AS` keyword being
1699 /// optional in a CTE definition. For example:
1700 /// ```sql
1701 /// WITH cte_name (SELECT ...)
1702 /// ```
1703 ///
1704 /// [Databricks](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-cte)
1705 fn supports_cte_without_as(&self) -> bool {
1706 false
1707 }
1708
1709 /// Returns true if the dialect supports parenthesized multi-column
1710 /// aliases in SELECT items. For example:
1711 /// ```sql
1712 /// SELECT stack(2, 'a', 'b') AS (col1, col2)
1713 /// ```
1714 ///
1715 /// [Spark SQL](https://spark.apache.org/docs/latest/sql-ref-syntax-qry-select.html)
1716 fn supports_select_item_multi_column_alias(&self) -> bool {
1717 false
1718 }
1719
1720 /// Returns true if the dialect supports XML-related expressions
1721 /// such as `xml '<foo/>'` typed strings, XML functions like
1722 /// `XMLCONCAT`, `XMLELEMENT`, etc.
1723 ///
1724 /// When this returns false, `xml` is treated as a regular identifier.
1725 ///
1726 /// [PostgreSQL](https://www.postgresql.org/docs/current/functions-xml.html)
1727 fn supports_xml_expressions(&self) -> bool {
1728 false
1729 }
1730}
1731
1732/// Operators for which precedence must be defined.
1733///
1734/// Higher number -> higher precedence.
1735/// See expression parsing for how these values are used.
1736#[derive(Debug, Clone, Copy)]
1737pub enum Precedence {
1738 /// Member access operator `.` (highest precedence).
1739 Period,
1740 /// Postgres style type cast `::`.
1741 DoubleColon,
1742 /// Timezone operator (e.g. `AT TIME ZONE`).
1743 AtTz,
1744 /// Multiplication / Division / Modulo operators (`*`, `/`, `%`).
1745 MulDivModOp,
1746 /// Addition / Subtraction (`+`, `-`).
1747 PlusMinus,
1748 /// Bitwise `XOR` operator (`^`).
1749 Xor,
1750 /// Bitwise `AND` operator (`&`).
1751 Ampersand,
1752 /// Bitwise `CARET` (^) for some dialects.
1753 Caret,
1754 /// Bitwise `OR` / pipe operator (`|`).
1755 Pipe,
1756 /// `:` operator for json/variant access.
1757 Colon,
1758 /// `BETWEEN` operator.
1759 Between,
1760 /// Equality operator (`=`).
1761 Eq,
1762 /// Pattern matching (`LIKE`).
1763 Like,
1764 /// `IS` operator (e.g. `IS NULL`).
1765 Is,
1766 /// Other Postgres-specific operators.
1767 PgOther,
1768 /// Unary `NOT`.
1769 UnaryNot,
1770 /// Logical `AND`.
1771 And,
1772 /// Logical `OR` (lowest precedence).
1773 Or,
1774}
1775
1776impl dyn Dialect {
1777 /// Returns true if `self` is the concrete dialect `T`.
1778 #[inline]
1779 pub fn is<T: Dialect>(&self) -> bool {
1780 // borrowed from `Any` implementation
1781 TypeId::of::<T>() == self.dialect()
1782 }
1783}
1784
1785/// Returns the built in [`Dialect`] corresponding to `dialect_name`.
1786///
1787/// See [`Dialect`] documentation for an example.
1788pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
1789 let dialect_name = dialect_name.as_ref();
1790 match dialect_name.to_lowercase().as_str() {
1791 "generic" => Some(Box::new(GenericDialect)),
1792 "mysql" => Some(Box::new(MySqlDialect {})),
1793 "postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
1794 "hive" => Some(Box::new(HiveDialect {})),
1795 "sqlite" => Some(Box::new(SQLiteDialect {})),
1796 "snowflake" => Some(Box::new(SnowflakeDialect)),
1797 "redshift" => Some(Box::new(RedshiftSqlDialect {})),
1798 "mssql" => Some(Box::new(MsSqlDialect {})),
1799 "clickhouse" => Some(Box::new(ClickHouseDialect {})),
1800 "bigquery" => Some(Box::new(BigQueryDialect)),
1801 "ansi" => Some(Box::new(AnsiDialect {})),
1802 "duckdb" => Some(Box::new(DuckDbDialect {})),
1803 "databricks" => Some(Box::new(DatabricksDialect {})),
1804 "oracle" => Some(Box::new(OracleDialect {})),
1805 _ => None,
1806 }
1807}
1808
1809#[cfg(test)]
1810mod tests {
1811 use super::*;
1812
1813 struct DialectHolder<'a> {
1814 dialect: &'a dyn Dialect,
1815 }
1816
1817 #[test]
1818 fn test_is_dialect() {
1819 let generic_dialect: &dyn Dialect = &GenericDialect {};
1820 let ansi_dialect: &dyn Dialect = &AnsiDialect {};
1821
1822 let generic_holder = DialectHolder {
1823 dialect: generic_dialect,
1824 };
1825 let ansi_holder = DialectHolder {
1826 dialect: ansi_dialect,
1827 };
1828
1829 assert!(dialect_of!(generic_holder is GenericDialect | AnsiDialect),);
1830 assert!(!dialect_of!(generic_holder is AnsiDialect));
1831 assert!(dialect_of!(ansi_holder is AnsiDialect));
1832 assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
1833 assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
1834 }
1835
1836 #[test]
1837 fn test_dialect_from_str() {
1838 assert!(parse_dialect("generic").is::<GenericDialect>());
1839 assert!(parse_dialect("mysql").is::<MySqlDialect>());
1840 assert!(parse_dialect("MySql").is::<MySqlDialect>());
1841 assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
1842 assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
1843 assert!(parse_dialect("hive").is::<HiveDialect>());
1844 assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
1845 assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
1846 assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
1847 assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
1848 assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
1849 assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
1850 assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
1851 assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
1852 assert!(parse_dialect("ansi").is::<AnsiDialect>());
1853 assert!(parse_dialect("ANSI").is::<AnsiDialect>());
1854 assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
1855 assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
1856 assert!(parse_dialect("DataBricks").is::<DatabricksDialect>());
1857 assert!(parse_dialect("databricks").is::<DatabricksDialect>());
1858
1859 // error cases
1860 assert!(dialect_from_str("Unknown").is_none());
1861 assert!(dialect_from_str("").is_none());
1862 }
1863
1864 fn parse_dialect(v: &str) -> Box<dyn Dialect> {
1865 dialect_from_str(v).unwrap()
1866 }
1867
1868 #[test]
1869 #[cfg(feature = "derive-dialect")]
1870 fn test_dialect_override() {
1871 derive_dialect!(EnhancedGenericDialect, GenericDialect,
1872 preserve_type_id = true,
1873 overrides = {
1874 supports_order_by_all = true,
1875 supports_nested_comments = true,
1876 supports_triple_quoted_string = true,
1877 },
1878 );
1879 let dialect = EnhancedGenericDialect::new();
1880
1881 assert!(dialect.supports_order_by_all());
1882 assert!(dialect.supports_nested_comments());
1883 assert!(dialect.supports_triple_quoted_string());
1884
1885 let d: &dyn Dialect = &dialect;
1886 assert!(d.is::<GenericDialect>());
1887 }
1888
1889 #[test]
1890 fn identifier_quote_style() {
1891 let tests: Vec<(&dyn Dialect, &str, Option<char>)> = vec![
1892 (&GenericDialect {}, "id", None),
1893 (&SQLiteDialect {}, "id", Some('`')),
1894 (&PostgreSqlDialect {}, "id", Some('"')),
1895 ];
1896
1897 for (dialect, ident, expected) in tests {
1898 let actual = dialect.identifier_quote_style(ident);
1899
1900 assert_eq!(actual, expected);
1901 }
1902 }
1903
1904 #[test]
1905 fn parse_with_wrapped_dialect() {
1906 /// Wrapper for a dialect. In a real-world example, this wrapper
1907 /// would tweak the behavior of the dialect. For the test case,
1908 /// it wraps all methods unaltered.
1909 #[derive(Debug)]
1910 struct WrappedDialect(MySqlDialect);
1911
1912 impl Dialect for WrappedDialect {
1913 fn dialect(&self) -> std::any::TypeId {
1914 self.0.dialect()
1915 }
1916
1917 fn is_identifier_start(&self, ch: char) -> bool {
1918 self.0.is_identifier_start(ch)
1919 }
1920
1921 fn is_delimited_identifier_start(&self, ch: char) -> bool {
1922 self.0.is_delimited_identifier_start(ch)
1923 }
1924
1925 fn is_nested_delimited_identifier_start(&self, ch: char) -> bool {
1926 self.0.is_nested_delimited_identifier_start(ch)
1927 }
1928
1929 fn peek_nested_delimited_identifier_quotes(
1930 &self,
1931 chars: std::iter::Peekable<std::str::Chars<'_>>,
1932 ) -> Option<(char, Option<char>)> {
1933 self.0.peek_nested_delimited_identifier_quotes(chars)
1934 }
1935
1936 fn identifier_quote_style(&self, identifier: &str) -> Option<char> {
1937 self.0.identifier_quote_style(identifier)
1938 }
1939
1940 fn supports_string_literal_backslash_escape(&self) -> bool {
1941 self.0.supports_string_literal_backslash_escape()
1942 }
1943
1944 fn supports_filter_during_aggregation(&self) -> bool {
1945 self.0.supports_filter_during_aggregation()
1946 }
1947
1948 fn supports_within_after_array_aggregation(&self) -> bool {
1949 self.0.supports_within_after_array_aggregation()
1950 }
1951
1952 fn supports_group_by_expr(&self) -> bool {
1953 self.0.supports_group_by_expr()
1954 }
1955
1956 fn supports_in_empty_list(&self) -> bool {
1957 self.0.supports_in_empty_list()
1958 }
1959
1960 fn convert_type_before_value(&self) -> bool {
1961 self.0.convert_type_before_value()
1962 }
1963
1964 fn parse_prefix(
1965 &self,
1966 parser: &mut sqlparser::parser::Parser,
1967 ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
1968 self.0.parse_prefix(parser)
1969 }
1970
1971 fn parse_infix(
1972 &self,
1973 parser: &mut sqlparser::parser::Parser,
1974 expr: &Expr,
1975 precedence: u8,
1976 ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
1977 self.0.parse_infix(parser, expr, precedence)
1978 }
1979
1980 fn get_next_precedence(
1981 &self,
1982 parser: &sqlparser::parser::Parser,
1983 ) -> Option<Result<u8, sqlparser::parser::ParserError>> {
1984 self.0.get_next_precedence(parser)
1985 }
1986
1987 fn parse_statement(
1988 &self,
1989 parser: &mut sqlparser::parser::Parser,
1990 ) -> Option<Result<Statement, sqlparser::parser::ParserError>> {
1991 self.0.parse_statement(parser)
1992 }
1993
1994 fn is_identifier_part(&self, ch: char) -> bool {
1995 self.0.is_identifier_part(ch)
1996 }
1997 }
1998
1999 #[allow(clippy::needless_raw_string_hashes)]
2000 let statement = r#"SELECT 'Wayne\'s World'"#;
2001 let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
2002 let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
2003 assert!(res1.is_ok());
2004 assert_eq!(res1, res2);
2005 }
2006}