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