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 pipe operator.
662 ///
663 /// Example:
664 /// ```sql
665 /// SELECT *
666 /// FROM table
667 /// |> limit 1
668 /// ```
669 ///
670 /// See <https://cloud.google.com/bigquery/docs/pipe-syntax-guide#basic_syntax>
671 fn supports_pipe_operator(&self) -> bool {
672 false
673 }
674
675 /// Does the dialect support MySQL-style `'user'@'host'` grantee syntax?
676 fn supports_user_host_grantee(&self) -> bool {
677 false
678 }
679
680 /// Does the dialect support the `MATCH() AGAINST()` syntax?
681 fn supports_match_against(&self) -> bool {
682 false
683 }
684
685 /// Returns true if the dialect supports an exclude option
686 /// following a wildcard in the projection section. For example:
687 /// `SELECT * EXCLUDE col1 FROM tbl`.
688 ///
689 /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
690 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select)
691 fn supports_select_wildcard_exclude(&self) -> bool {
692 false
693 }
694
695 /// Returns true if the dialect supports an exclude option
696 /// as the last item in the projection section, not necessarily
697 /// after a wildcard. For example:
698 /// `SELECT *, c1, c2 EXCLUDE c3 FROM tbl`
699 ///
700 /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
701 fn supports_select_exclude(&self) -> bool {
702 false
703 }
704
705 /// Returns true if the dialect supports specifying multiple options
706 /// in a `CREATE TABLE` statement for the structure of the new table. For example:
707 /// `CREATE TABLE t (a INT, b INT) AS SELECT 1 AS b, 2 AS a`
708 fn supports_create_table_multi_schema_info_sources(&self) -> bool {
709 false
710 }
711
712 /// Returns true if the dialect supports MySQL-specific SELECT modifiers
713 /// like `HIGH_PRIORITY`, `STRAIGHT_JOIN`, `SQL_SMALL_RESULT`, etc.
714 ///
715 /// For example:
716 /// ```sql
717 /// SELECT HIGH_PRIORITY STRAIGHT_JOIN SQL_SMALL_RESULT * FROM t1 JOIN t2 ON ...
718 /// ```
719 ///
720 /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/select.html)
721 fn supports_select_modifiers(&self) -> bool {
722 false
723 }
724
725 /// Dialect-specific infix parser override
726 ///
727 /// This method is called to parse the next infix expression.
728 ///
729 /// If `None` is returned, falls back to the default behavior.
730 fn parse_infix(
731 &self,
732 _parser: &mut Parser,
733 _expr: &Expr,
734 _precedence: u8,
735 ) -> Option<Result<Expr, ParserError>> {
736 // return None to fall back to the default behavior
737 None
738 }
739
740 /// Dialect-specific precedence override
741 ///
742 /// This method is called to get the precedence of the next token.
743 ///
744 /// If `None` is returned, falls back to the default behavior.
745 fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
746 // return None to fall back to the default behavior
747 None
748 }
749
750 /// Get the precedence of the next token, looking at the full token stream.
751 ///
752 /// A higher number => higher precedence
753 ///
754 /// See [`Self::get_next_precedence`] to override the behavior for just the
755 /// next token.
756 ///
757 /// The default implementation is used for many dialects, but can be
758 /// overridden to provide dialect-specific behavior.
759 fn get_next_precedence_default(&self, parser: &Parser) -> Result<u8, ParserError> {
760 if let Some(precedence) = self.get_next_precedence(parser) {
761 return precedence;
762 }
763 macro_rules! p {
764 ($precedence:ident) => {
765 self.prec_value(Precedence::$precedence)
766 };
767 }
768
769 let token = parser.peek_token_ref();
770 debug!("get_next_precedence_full() {token:?}");
771 match &token.token {
772 Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
773 Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
774 Token::Word(w) if w.keyword == Keyword::XOR => Ok(p!(Xor)),
775
776 Token::Word(w) if w.keyword == Keyword::AT => {
777 match (
778 &parser.peek_nth_token_ref(1).token,
779 &parser.peek_nth_token_ref(2).token,
780 ) {
781 (Token::Word(w), Token::Word(w2))
782 if w.keyword == Keyword::TIME && w2.keyword == Keyword::ZONE =>
783 {
784 Ok(p!(AtTz))
785 }
786 _ => Ok(self.prec_unknown()),
787 }
788 }
789
790 Token::Word(w) if w.keyword == Keyword::NOT => {
791 match &parser.peek_nth_token_ref(1).token {
792 // The precedence of NOT varies depending on keyword that
793 // follows it. If it is followed by IN, BETWEEN, or LIKE,
794 // it takes on the precedence of those tokens. Otherwise, it
795 // is not an infix operator, and therefore has zero
796 // precedence.
797 Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
798 Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
799 Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
800 Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
801 Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
802 Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
803 Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
804 Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
805 Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
806 Token::Word(w)
807 if w.keyword == Keyword::NULL && !parser.in_column_definition_state() =>
808 {
809 Ok(p!(Is))
810 }
811 _ => Ok(self.prec_unknown()),
812 }
813 }
814 Token::Word(w) if w.keyword == Keyword::NOTNULL && self.supports_notnull_operator() => {
815 Ok(p!(Is))
816 }
817 Token::Word(w) if w.keyword == Keyword::IS => Ok(p!(Is)),
818 Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
819 Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
820 Token::Word(w) if w.keyword == Keyword::OVERLAPS => Ok(p!(Between)),
821 Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
822 Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
823 Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
824 Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
825 Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
826 Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
827 Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
828 Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(p!(Between)),
829 Token::Word(w) if w.keyword == Keyword::DIV => Ok(p!(MulDivModOp)),
830 Token::Period => Ok(p!(Period)),
831 Token::Assignment
832 | Token::Eq
833 | Token::Lt
834 | Token::LtEq
835 | Token::Neq
836 | Token::Gt
837 | Token::GtEq
838 | Token::DoubleEq
839 | Token::Tilde
840 | Token::TildeAsterisk
841 | Token::ExclamationMarkTilde
842 | Token::ExclamationMarkTildeAsterisk
843 | Token::DoubleTilde
844 | Token::DoubleTildeAsterisk
845 | Token::ExclamationMarkDoubleTilde
846 | Token::ExclamationMarkDoubleTildeAsterisk
847 | Token::Spaceship => Ok(p!(Eq)),
848 Token::Pipe
849 | Token::QuestionMarkDash
850 | Token::DoubleSharp
851 | Token::Overlap
852 | Token::AmpersandLeftAngleBracket
853 | Token::AmpersandRightAngleBracket
854 | Token::QuestionMarkDashVerticalBar
855 | Token::AmpersandLeftAngleBracketVerticalBar
856 | Token::VerticalBarAmpersandRightAngleBracket
857 | Token::TwoWayArrow
858 | Token::LeftAngleBracketCaret
859 | Token::RightAngleBracketCaret
860 | Token::QuestionMarkSharp
861 | Token::QuestionMarkDoubleVerticalBar
862 | Token::QuestionPipe
863 | Token::TildeEqual
864 | Token::AtSign
865 | Token::ShiftLeftVerticalBar
866 | Token::VerticalBarShiftRight => Ok(p!(Pipe)),
867 Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
868 Token::Ampersand => Ok(p!(Ampersand)),
869 Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
870 Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
871 Ok(p!(MulDivModOp))
872 }
873 Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
874 Ok(p!(DoubleColon))
875 }
876 Token::Colon => match &parser.peek_nth_token_ref(1).token {
877 // When colon is followed by a string or a number, it's usually in MAP syntax.
878 Token::SingleQuotedString(_) | Token::Number(_, _) => Ok(self.prec_unknown()),
879 // In other cases, it's used in semi-structured data traversal like in variant or JSON
880 // string columns. See `JsonAccess`.
881 _ => Ok(p!(Colon)),
882 },
883 Token::Arrow
884 | Token::LongArrow
885 | Token::HashArrow
886 | Token::HashLongArrow
887 | Token::AtArrow
888 | Token::ArrowAt
889 | Token::HashMinus
890 | Token::AtQuestion
891 | Token::AtAt
892 | Token::Question
893 | Token::QuestionAnd
894 | Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
895 _ => Ok(self.prec_unknown()),
896 }
897 }
898
899 /// Dialect-specific statement parser override
900 ///
901 /// This method is called to parse the next statement.
902 ///
903 /// If `None` is returned, falls back to the default behavior.
904 fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
905 // return None to fall back to the default behavior
906 None
907 }
908
909 /// Dialect-specific column option parser override
910 ///
911 /// This method is called to parse the next column option.
912 ///
913 /// If `None` is returned, falls back to the default behavior.
914 fn parse_column_option(
915 &self,
916 _parser: &mut Parser,
917 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
918 // return None to fall back to the default behavior
919 Ok(None)
920 }
921
922 /// Decide the lexical Precedence of operators.
923 ///
924 /// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
925 fn prec_value(&self, prec: Precedence) -> u8 {
926 match prec {
927 Precedence::Period => 100,
928 Precedence::DoubleColon => 50,
929 Precedence::AtTz => 41,
930 Precedence::MulDivModOp => 40,
931 Precedence::PlusMinus => 30,
932 Precedence::Xor => 24,
933 Precedence::Ampersand => 23,
934 Precedence::Caret => 22,
935 Precedence::Pipe => 21,
936 Precedence::Colon => 21,
937 Precedence::Between => 20,
938 Precedence::Eq => 20,
939 Precedence::Like => 19,
940 Precedence::Is => 17,
941 Precedence::PgOther => 16,
942 Precedence::UnaryNot => 15,
943 Precedence::And => 10,
944 Precedence::Or => 5,
945 }
946 }
947
948 /// Returns the precedence when the precedence is otherwise unknown
949 fn prec_unknown(&self) -> u8 {
950 0
951 }
952
953 /// Returns true if this dialect requires the `TABLE` keyword after `DESCRIBE`
954 ///
955 /// Defaults to false.
956 ///
957 /// If true, the following statement is valid: `DESCRIBE TABLE my_table`
958 /// If false, the following statements are valid: `DESCRIBE my_table` and `DESCRIBE table`
959 fn describe_requires_table_keyword(&self) -> bool {
960 false
961 }
962
963 /// Returns true if this dialect allows the `EXTRACT` function to words other than [`Keyword`].
964 fn allow_extract_custom(&self) -> bool {
965 false
966 }
967
968 /// Returns true if this dialect allows the `EXTRACT` function to use single quotes in the part being extracted.
969 fn allow_extract_single_quotes(&self) -> bool {
970 false
971 }
972
973 /// Returns true if this dialect supports the `EXTRACT` function
974 /// with a comma separator instead of `FROM`.
975 ///
976 /// Example:
977 /// ```sql
978 /// SELECT EXTRACT(YEAR, date_column) FROM table;
979 /// ```
980 ///
981 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/functions/extract)
982 fn supports_extract_comma_syntax(&self) -> bool {
983 false
984 }
985
986 /// Returns true if this dialect supports a subquery passed to a function
987 /// as the only argument without enclosing parentheses.
988 ///
989 /// Example:
990 /// ```sql
991 /// SELECT FLATTEN(SELECT * FROM tbl);
992 /// ```
993 ///
994 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/functions/flatten)
995 fn supports_subquery_as_function_arg(&self) -> bool {
996 false
997 }
998
999 /// Returns true if this dialect supports the `COMMENT` clause in
1000 /// `CREATE VIEW` statements using the `COMMENT = 'comment'` syntax.
1001 ///
1002 /// Example:
1003 /// ```sql
1004 /// CREATE VIEW v COMMENT = 'my comment' AS SELECT 1;
1005 /// ```
1006 ///
1007 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/create-view#optional-parameters)
1008 fn supports_create_view_comment_syntax(&self) -> bool {
1009 false
1010 }
1011
1012 /// Returns true if this dialect supports the `ARRAY` type without
1013 /// specifying an element type.
1014 ///
1015 /// Example:
1016 /// ```sql
1017 /// CREATE TABLE t (a ARRAY);
1018 /// ```
1019 ///
1020 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/data-types-semistructured#array)
1021 fn supports_array_typedef_without_element_type(&self) -> bool {
1022 false
1023 }
1024
1025 /// Returns true if this dialect supports extra parentheses around
1026 /// lone table names or derived tables in the `FROM` clause.
1027 ///
1028 /// Example:
1029 /// ```sql
1030 /// SELECT * FROM (mytable);
1031 /// SELECT * FROM ((SELECT 1));
1032 /// SELECT * FROM (mytable) AS alias;
1033 /// ```
1034 ///
1035 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/from)
1036 fn supports_parens_around_table_factor(&self) -> bool {
1037 false
1038 }
1039
1040 /// Returns true if this dialect supports `VALUES` as a table factor
1041 /// without requiring parentheses around the entire clause.
1042 ///
1043 /// Example:
1044 /// ```sql
1045 /// SELECT * FROM VALUES (1, 'a'), (2, 'b') AS t (col1, col2);
1046 /// ```
1047 ///
1048 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/values)
1049 /// [Databricks](https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-values.html)
1050 fn supports_values_as_table_factor(&self) -> bool {
1051 false
1052 }
1053
1054 /// Returns true if this dialect allows dollar placeholders
1055 /// e.g. `SELECT $var` (SQLite)
1056 fn supports_dollar_placeholder(&self) -> bool {
1057 false
1058 }
1059
1060 /// Returns true if this dialect supports `$` as a prefix for money literals
1061 /// e.g. `SELECT $123.45` (SQL Server)
1062 fn supports_dollar_as_money_prefix(&self) -> bool {
1063 false
1064 }
1065
1066 /// Does the dialect support with clause in create index statement?
1067 /// e.g. `CREATE INDEX idx ON t WITH (key = value, key2)`
1068 fn supports_create_index_with_clause(&self) -> bool {
1069 false
1070 }
1071
1072 /// Whether `INTERVAL` expressions require units (called "qualifiers" in the ANSI SQL spec) to be specified,
1073 /// e.g. `INTERVAL 1 DAY` vs `INTERVAL 1`.
1074 ///
1075 /// Expressions within intervals (e.g. `INTERVAL '1' + '1' DAY`) are only allowed when units are required.
1076 ///
1077 /// See <https://github.com/sqlparser-rs/sqlparser-rs/pull/1398> for more information.
1078 ///
1079 /// When `true`:
1080 /// * `INTERVAL '1' DAY` is VALID
1081 /// * `INTERVAL 1 + 1 DAY` is VALID
1082 /// * `INTERVAL '1' + '1' DAY` is VALID
1083 /// * `INTERVAL '1'` is INVALID
1084 ///
1085 /// When `false`:
1086 /// * `INTERVAL '1'` is VALID
1087 /// * `INTERVAL '1' DAY` is VALID — unit is not required, but still allowed
1088 /// * `INTERVAL 1 + 1 DAY` is INVALID
1089 fn require_interval_qualifier(&self) -> bool {
1090 false
1091 }
1092
1093 /// Returns true if the dialect supports `EXPLAIN` statements with utility options
1094 /// e.g. `EXPLAIN (ANALYZE TRUE, BUFFERS TRUE) SELECT * FROM tbl;`
1095 fn supports_explain_with_utility_options(&self) -> bool {
1096 false
1097 }
1098
1099 /// Returns true if the dialect supports `ASC` and `DESC` in column definitions
1100 /// e.g. `CREATE TABLE t (a INT ASC, b INT DESC);`
1101 fn supports_asc_desc_in_column_definition(&self) -> bool {
1102 false
1103 }
1104
1105 /// Returns true if the dialect supports `a!` expressions
1106 fn supports_factorial_operator(&self) -> bool {
1107 false
1108 }
1109
1110 /// Returns true if the dialect supports `<<` and `>>` shift operators.
1111 fn supports_bitwise_shift_operators(&self) -> bool {
1112 false
1113 }
1114
1115 /// Returns true if the dialect supports nested comments
1116 /// e.g. `/* /* nested */ */`
1117 fn supports_nested_comments(&self) -> bool {
1118 false
1119 }
1120
1121 /// Returns true if the dialect supports optimizer hints in multiline comments
1122 /// e.g. `/*!50110 KEY_BLOCK_SIZE = 1024*/`
1123 fn supports_multiline_comment_hints(&self) -> bool {
1124 false
1125 }
1126
1127 /// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
1128 /// as an alias assignment operator, rather than a boolean expression.
1129 /// For example: the following statements are equivalent for such a dialect:
1130 /// ```sql
1131 /// SELECT col_alias = col FROM tbl;
1132 /// SELECT col_alias AS col FROM tbl;
1133 /// ```
1134 fn supports_eq_alias_assignment(&self) -> bool {
1135 false
1136 }
1137
1138 /// Returns true if this dialect supports the `TRY_CONVERT` function
1139 fn supports_try_convert(&self) -> bool {
1140 false
1141 }
1142
1143 /// Returns true if the dialect supports `!a` syntax for boolean `NOT` expressions.
1144 fn supports_bang_not_operator(&self) -> bool {
1145 false
1146 }
1147
1148 /// Returns true if the dialect supports the `LISTEN`, `UNLISTEN` and `NOTIFY` statements
1149 fn supports_listen_notify(&self) -> bool {
1150 false
1151 }
1152
1153 /// Returns true if the dialect supports the `LOAD DATA` statement
1154 fn supports_load_data(&self) -> bool {
1155 false
1156 }
1157
1158 /// Returns true if the dialect supports the `LOAD extension` statement
1159 fn supports_load_extension(&self) -> bool {
1160 false
1161 }
1162
1163 /// Returns true if this dialect expects the `TOP` option
1164 /// before the `ALL`/`DISTINCT` options in a `SELECT` statement.
1165 fn supports_top_before_distinct(&self) -> bool {
1166 false
1167 }
1168
1169 /// Returns true if the dialect supports boolean literals (`true` and `false`).
1170 /// For example, in MSSQL these are treated as identifiers rather than boolean literals.
1171 fn supports_boolean_literals(&self) -> bool {
1172 true
1173 }
1174
1175 /// Returns true if this dialect supports the `LIKE 'pattern'` option in
1176 /// a `SHOW` statement before the `IN` option
1177 fn supports_show_like_before_in(&self) -> bool {
1178 false
1179 }
1180
1181 /// Returns true if this dialect supports the `COMMENT` statement
1182 fn supports_comment_on(&self) -> bool {
1183 false
1184 }
1185
1186 /// Returns true if the dialect supports the `CREATE TABLE SELECT` statement
1187 fn supports_create_table_select(&self) -> bool {
1188 false
1189 }
1190
1191 /// Returns true if the dialect supports PartiQL for querying semi-structured data
1192 /// <https://partiql.org/index.html>
1193 fn supports_partiql(&self) -> bool {
1194 false
1195 }
1196
1197 /// Returns true if the dialect supports the `CONSTRAINT` keyword without a name
1198 /// in table constraint definitions.
1199 ///
1200 /// Example:
1201 /// ```sql
1202 /// CREATE TABLE t (a INT, CONSTRAINT CHECK (a > 0))
1203 /// ```
1204 ///
1205 /// This is a MySQL extension; the SQL standard requires a name after `CONSTRAINT`.
1206 /// When the name is omitted, the output normalizes to just the constraint type
1207 /// without the `CONSTRAINT` keyword (e.g., `CHECK (a > 0)`).
1208 ///
1209 /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
1210 fn supports_constraint_keyword_without_name(&self) -> bool {
1211 false
1212 }
1213
1214 /// Returns true if the dialect supports the `KEY` keyword as part of
1215 /// column-level constraints in a `CREATE TABLE` statement.
1216 ///
1217 /// When enabled, the parser accepts these MySQL-specific column options:
1218 /// - `UNIQUE [KEY]` — optional `KEY` after `UNIQUE`
1219 /// - `[PRIMARY] KEY` — standalone `KEY` as shorthand for `PRIMARY KEY`
1220 ///
1221 /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
1222 fn supports_key_column_option(&self) -> bool {
1223 false
1224 }
1225
1226 /// Returns true if the specified keyword is reserved and cannot be
1227 /// used as an identifier without special handling like quoting.
1228 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
1229 keywords::RESERVED_FOR_IDENTIFIER.contains(&kw)
1230 }
1231
1232 /// Returns reserved keywords that may prefix a select item expression
1233 /// e.g. `SELECT CONNECT_BY_ROOT name FROM Tbl2` (Snowflake)
1234 fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
1235 &[]
1236 }
1237
1238 /// Returns grantee types that should be treated as identifiers
1239 fn get_reserved_grantees_types(&self) -> &[GranteesType] {
1240 &[]
1241 }
1242
1243 /// Returns true if this dialect supports the `TABLESAMPLE` option
1244 /// before the table alias option. For example:
1245 ///
1246 /// Table sample before alias: `SELECT * FROM tbl AS t TABLESAMPLE (10)`
1247 /// Table sample after alias: `SELECT * FROM tbl TABLESAMPLE (10) AS t`
1248 ///
1249 /// <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#_7_6_table_reference>
1250 fn supports_table_sample_before_alias(&self) -> bool {
1251 false
1252 }
1253
1254 /// Returns true if this dialect supports the `INSERT INTO ... SET col1 = 1, ...` syntax.
1255 ///
1256 /// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
1257 fn supports_insert_set(&self) -> bool {
1258 false
1259 }
1260
1261 /// Does the dialect support table function in insertion?
1262 fn supports_insert_table_function(&self) -> bool {
1263 false
1264 }
1265
1266 /// Does the dialect support table queries in insertion?
1267 ///
1268 /// e.g. `SELECT INTO (<query>) ...`
1269 fn supports_insert_table_query(&self) -> bool {
1270 false
1271 }
1272
1273 /// Does the dialect support insert formats, e.g. `INSERT INTO ... FORMAT <format>`
1274 fn supports_insert_format(&self) -> bool {
1275 false
1276 }
1277
1278 /// Returns true if this dialect supports `INSERT INTO t [[AS] alias] ...`.
1279 fn supports_insert_table_alias(&self) -> bool {
1280 false
1281 }
1282
1283 /// Returns true if this dialect supports `SET` statements without an explicit
1284 /// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
1285 fn supports_set_stmt_without_operator(&self) -> bool {
1286 false
1287 }
1288
1289 /// Returns true if the specified keyword should be parsed as a column identifier.
1290 /// See [keywords::RESERVED_FOR_COLUMN_ALIAS]
1291 fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1292 !keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw)
1293 }
1294
1295 /// Returns true if the specified keyword should be parsed as a select item alias.
1296 /// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
1297 /// to enable looking ahead if needed.
1298 fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
1299 explicit || self.is_column_alias(kw, parser)
1300 }
1301
1302 /// Returns true if the specified keyword should be parsed as a table factor identifier.
1303 /// See [keywords::RESERVED_FOR_TABLE_FACTOR]
1304 fn is_table_factor(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1305 !keywords::RESERVED_FOR_TABLE_FACTOR.contains(kw)
1306 }
1307
1308 /// Returns true if the specified keyword should be parsed as a table factor alias.
1309 /// See [keywords::RESERVED_FOR_TABLE_ALIAS]
1310 fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
1311 !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
1312 }
1313
1314 /// Returns true if the specified keyword should be parsed as a table factor alias.
1315 /// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
1316 /// to enable looking ahead if needed.
1317 fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
1318 explicit || self.is_table_alias(kw, parser)
1319 }
1320
1321 /// Returns true if this dialect supports querying historical table data
1322 /// by specifying which version of the data to query.
1323 fn supports_table_versioning(&self) -> bool {
1324 false
1325 }
1326
1327 /// Returns true if this dialect supports the E'...' syntax for string literals
1328 ///
1329 /// Postgres: <https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE>
1330 fn supports_string_escape_constant(&self) -> bool {
1331 false
1332 }
1333
1334 /// Returns true if the dialect supports the table hints in the `FROM` clause.
1335 fn supports_table_hints(&self) -> bool {
1336 false
1337 }
1338
1339 /// Returns true if this dialect requires a whitespace character after `--` to start a single line comment.
1340 ///
1341 /// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/ansi-diff-comments.html>
1342 /// e.g. UPDATE account SET balance=balance--1
1343 // WHERE account_id=5752 ^^^ will be interpreted as two minus signs instead of a comment
1344 fn requires_single_line_comment_whitespace(&self) -> bool {
1345 false
1346 }
1347
1348 /// Returns true if the dialect supports array type definition with brackets with
1349 /// an optional size. For example:
1350 /// ```CREATE TABLE my_table (arr1 INT[], arr2 INT[3])```
1351 /// ```SELECT x::INT[]```
1352 fn supports_array_typedef_with_brackets(&self) -> bool {
1353 false
1354 }
1355 /// Returns true if the dialect supports geometric types.
1356 ///
1357 /// Postgres: <https://www.postgresql.org/docs/9.5/functions-geometry.html>
1358 /// e.g. @@ circle '((0,0),10)'
1359 fn supports_geometric_types(&self) -> bool {
1360 false
1361 }
1362
1363 /// Returns true if the dialect supports `ORDER BY ALL`.
1364 /// `ALL` which means all columns of the SELECT clause.
1365 ///
1366 /// For example: ```SELECT * FROM addresses ORDER BY ALL;```.
1367 fn supports_order_by_all(&self) -> bool {
1368 false
1369 }
1370
1371 /// Returns true if the dialect supports `SET NAMES <charset_name> [COLLATE <collation_name>]`.
1372 ///
1373 /// - [MySQL](https://dev.mysql.com/doc/refman/8.4/en/set-names.html)
1374 /// - [PostgreSQL](https://www.postgresql.org/docs/17/sql-set.html)
1375 ///
1376 /// Note: Postgres doesn't support the `COLLATE` clause, but we permissively parse it anyway.
1377 fn supports_set_names(&self) -> bool {
1378 false
1379 }
1380
1381 /// Returns true if the dialect supports space-separated column options
1382 /// in a `CREATE TABLE` statement. For example:
1383 /// ```sql
1384 /// CREATE TABLE tbl (
1385 /// col INT NOT NULL DEFAULT 0
1386 /// );
1387 /// ```
1388 fn supports_space_separated_column_options(&self) -> bool {
1389 false
1390 }
1391
1392 /// Returns true if the dialect supports the `USING` clause in an `ALTER COLUMN` statement.
1393 /// Example:
1394 /// ```sql
1395 /// ALTER TABLE tbl ALTER COLUMN col SET DATA TYPE <type> USING <exp>`
1396 /// ```
1397 fn supports_alter_column_type_using(&self) -> bool {
1398 false
1399 }
1400
1401 /// Returns true if the dialect supports `ALTER TABLE tbl DROP COLUMN c1, ..., cn`
1402 fn supports_comma_separated_drop_column_list(&self) -> bool {
1403 false
1404 }
1405
1406 /// Returns true if the dialect considers the specified ident as a function
1407 /// that returns an identifier. Typically used to generate identifiers
1408 /// programmatically.
1409 ///
1410 /// - [Snowflake](https://docs.snowflake.com/en/sql-reference/identifier-literal)
1411 fn is_identifier_generating_function_name(
1412 &self,
1413 _ident: &Ident,
1414 _name_parts: &[ObjectNamePart],
1415 ) -> bool {
1416 false
1417 }
1418
1419 /// Returns true if the dialect supports the `x NOTNULL`
1420 /// operator expression.
1421 fn supports_notnull_operator(&self) -> bool {
1422 false
1423 }
1424
1425 /// Returns true if this dialect allows an optional `SIGNED` suffix after integer data types.
1426 ///
1427 /// Example:
1428 /// ```sql
1429 /// CREATE TABLE t (i INT(20) SIGNED);
1430 /// ```
1431 ///
1432 /// Note that this is canonicalized to `INT(20)`.
1433 fn supports_data_type_signed_suffix(&self) -> bool {
1434 false
1435 }
1436
1437 /// Returns true if the dialect supports the `INTERVAL` data type with [Postgres]-style options.
1438 ///
1439 /// Examples:
1440 /// ```sql
1441 /// CREATE TABLE t (i INTERVAL YEAR TO MONTH);
1442 /// SELECT '1 second'::INTERVAL HOUR TO SECOND(3);
1443 /// ```
1444 ///
1445 /// See [`crate::ast::DataType::Interval`] and [`crate::ast::IntervalFields`].
1446 ///
1447 /// [Postgres]: https://www.postgresql.org/docs/17/datatype-datetime.html
1448 fn supports_interval_options(&self) -> bool {
1449 false
1450 }
1451
1452 /// Returns true if the dialect supports specifying which table to copy
1453 /// the schema from inside parenthesis.
1454 ///
1455 /// Not parenthesized:
1456 /// '''sql
1457 /// CREATE TABLE new LIKE old ...
1458 /// '''
1459 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/create-table#label-create-table-like)
1460 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_like)
1461 ///
1462 /// Parenthesized:
1463 /// '''sql
1464 /// CREATE TABLE new (LIKE old ...)
1465 /// '''
1466 /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html)
1467 fn supports_create_table_like_parenthesized(&self) -> bool {
1468 false
1469 }
1470
1471 /// Returns true if the dialect supports `SEMANTIC_VIEW()` table functions.
1472 ///
1473 /// ```sql
1474 /// SELECT * FROM SEMANTIC_VIEW(
1475 /// model_name
1476 /// DIMENSIONS customer.name, customer.region
1477 /// METRICS orders.revenue, orders.count
1478 /// WHERE customer.active = true
1479 /// )
1480 /// ```
1481 fn supports_semantic_view_table_factor(&self) -> bool {
1482 false
1483 }
1484
1485 /// Support quote delimited string literals, e.g. `Q'{...}'`
1486 ///
1487 /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Literals.html#GUID-1824CBAA-6E16-4921-B2A6-112FB02248DA)
1488 fn supports_quote_delimited_string(&self) -> bool {
1489 false
1490 }
1491
1492 /// Returns `true` if the dialect supports query optimizer hints in the
1493 /// format of single and multi line comments immediately following a
1494 /// `SELECT`, `INSERT`, `REPLACE`, `DELETE`, or `MERGE` keyword.
1495 ///
1496 /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
1497 /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Comments.html#SQLRF-GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
1498 fn supports_comment_optimizer_hint(&self) -> bool {
1499 false
1500 }
1501
1502 /// Returns true if the dialect considers the `&&` operator as a boolean AND operator.
1503 fn supports_double_ampersand_operator(&self) -> bool {
1504 false
1505 }
1506
1507 /// Returns true if the dialect supports casting an expression to a binary type
1508 /// using the `BINARY <expr>` syntax.
1509 fn supports_binary_kw_as_cast(&self) -> bool {
1510 false
1511 }
1512
1513 /// Returns true if this dialect supports the `REPLACE` option in a
1514 /// `SELECT *` wildcard expression.
1515 ///
1516 /// Example:
1517 /// ```sql
1518 /// SELECT * REPLACE (col1 AS col1_alias) FROM table;
1519 /// ```
1520 ///
1521 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_replace)
1522 /// [ClickHouse](https://clickhouse.com/docs/sql-reference/statements/select#replace)
1523 /// [DuckDB](https://duckdb.org/docs/sql/query_syntax/select#replace-clause)
1524 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select#parameters)
1525 fn supports_select_wildcard_replace(&self) -> bool {
1526 false
1527 }
1528
1529 /// Returns true if this dialect supports the `ILIKE` option in a
1530 /// `SELECT *` wildcard expression.
1531 ///
1532 /// Example:
1533 /// ```sql
1534 /// SELECT * ILIKE '%pattern%' FROM table;
1535 /// ```
1536 ///
1537 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select#parameters)
1538 fn supports_select_wildcard_ilike(&self) -> bool {
1539 false
1540 }
1541
1542 /// Returns true if this dialect supports the `RENAME` option in a
1543 /// `SELECT *` wildcard expression.
1544 ///
1545 /// Example:
1546 /// ```sql
1547 /// SELECT * RENAME col1 AS col1_alias FROM table;
1548 /// ```
1549 ///
1550 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/select#parameters)
1551 fn supports_select_wildcard_rename(&self) -> bool {
1552 false
1553 }
1554
1555 /// Returns true if this dialect supports aliasing a wildcard select item.
1556 ///
1557 /// Example:
1558 /// ```sql
1559 /// SELECT t.* alias FROM t
1560 /// SELECT t.* AS alias FROM t
1561 /// ```
1562 fn supports_select_wildcard_with_alias(&self) -> bool {
1563 false
1564 }
1565
1566 /// Returns true if this dialect supports the `OPTIMIZE TABLE` statement.
1567 ///
1568 /// Example:
1569 /// ```sql
1570 /// OPTIMIZE TABLE table_name;
1571 /// ```
1572 ///
1573 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
1574 fn supports_optimize_table(&self) -> bool {
1575 false
1576 }
1577
1578 /// Returns true if this dialect supports the `INSTALL` statement.
1579 ///
1580 /// Example:
1581 /// ```sql
1582 /// INSTALL extension_name;
1583 /// ```
1584 ///
1585 /// [DuckDB](https://duckdb.org/docs/extensions/overview)
1586 fn supports_install(&self) -> bool {
1587 false
1588 }
1589
1590 /// Returns true if this dialect supports the `DETACH` statement.
1591 ///
1592 /// Example:
1593 /// ```sql
1594 /// DETACH DATABASE db_name;
1595 /// ```
1596 ///
1597 /// [DuckDB](https://duckdb.org/docs/sql/statements/attach#detach-syntax)
1598 fn supports_detach(&self) -> bool {
1599 false
1600 }
1601
1602 /// Returns true if this dialect supports the `PREWHERE` clause
1603 /// in `SELECT` statements.
1604 ///
1605 /// Example:
1606 /// ```sql
1607 /// SELECT * FROM table PREWHERE col > 0 WHERE col < 100;
1608 /// ```
1609 ///
1610 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere)
1611 fn supports_prewhere(&self) -> bool {
1612 false
1613 }
1614
1615 /// Returns true if this dialect supports the `WITH FILL` clause
1616 /// in `ORDER BY` expressions.
1617 ///
1618 /// Example:
1619 /// ```sql
1620 /// SELECT * FROM table ORDER BY col WITH FILL FROM 1 TO 10 STEP 1;
1621 /// ```
1622 ///
1623 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier)
1624 fn supports_with_fill(&self) -> bool {
1625 false
1626 }
1627
1628 /// Returns true if this dialect supports the `LIMIT BY` clause.
1629 ///
1630 /// Example:
1631 /// ```sql
1632 /// SELECT * FROM table LIMIT 10 BY col;
1633 /// ```
1634 ///
1635 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/limit-by)
1636 fn supports_limit_by(&self) -> bool {
1637 false
1638 }
1639
1640 /// Returns true if this dialect supports the `INTERPOLATE` clause
1641 /// in `ORDER BY` expressions.
1642 ///
1643 /// Example:
1644 /// ```sql
1645 /// SELECT * FROM table ORDER BY col WITH FILL INTERPOLATE (col2 AS col2 + 1);
1646 /// ```
1647 ///
1648 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier)
1649 fn supports_interpolate(&self) -> bool {
1650 false
1651 }
1652
1653 /// Returns true if this dialect supports the `SETTINGS` clause.
1654 ///
1655 /// Example:
1656 /// ```sql
1657 /// SELECT * FROM table SETTINGS max_threads = 4;
1658 /// ```
1659 ///
1660 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select#settings-in-select-query)
1661 fn supports_settings(&self) -> bool {
1662 false
1663 }
1664
1665 /// Returns true if this dialect supports the `FORMAT` clause in `SELECT` statements.
1666 ///
1667 /// Example:
1668 /// ```sql
1669 /// SELECT * FROM table FORMAT JSON;
1670 /// ```
1671 ///
1672 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/format)
1673 fn supports_select_format(&self) -> bool {
1674 false
1675 }
1676
1677 /// Returns true if the dialect supports the two-argument comma-separated
1678 /// form of the `TRIM` function: `TRIM(expr, characters)`.
1679 fn supports_comma_separated_trim(&self) -> bool {
1680 false
1681 }
1682
1683 /// Returns true if the dialect supports the `AS` keyword being
1684 /// optional in a CTE definition. For example:
1685 /// ```sql
1686 /// WITH cte_name (SELECT ...)
1687 /// ```
1688 ///
1689 /// [Databricks](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-cte)
1690 fn supports_cte_without_as(&self) -> bool {
1691 false
1692 }
1693
1694 /// Returns true if the dialect supports parenthesized multi-column
1695 /// aliases in SELECT items. For example:
1696 /// ```sql
1697 /// SELECT stack(2, 'a', 'b') AS (col1, col2)
1698 /// ```
1699 ///
1700 /// [Spark SQL](https://spark.apache.org/docs/latest/sql-ref-syntax-qry-select.html)
1701 fn supports_select_item_multi_column_alias(&self) -> bool {
1702 false
1703 }
1704
1705 /// Returns true if the dialect supports XML-related expressions
1706 /// such as `xml '<foo/>'` typed strings, XML functions like
1707 /// `XMLCONCAT`, `XMLELEMENT`, etc.
1708 ///
1709 /// When this returns false, `xml` is treated as a regular identifier.
1710 ///
1711 /// [PostgreSQL](https://www.postgresql.org/docs/current/functions-xml.html)
1712 fn supports_xml_expressions(&self) -> bool {
1713 false
1714 }
1715}
1716
1717/// Operators for which precedence must be defined.
1718///
1719/// Higher number -> higher precedence.
1720/// See expression parsing for how these values are used.
1721#[derive(Debug, Clone, Copy)]
1722pub enum Precedence {
1723 /// Member access operator `.` (highest precedence).
1724 Period,
1725 /// Postgres style type cast `::`.
1726 DoubleColon,
1727 /// Timezone operator (e.g. `AT TIME ZONE`).
1728 AtTz,
1729 /// Multiplication / Division / Modulo operators (`*`, `/`, `%`).
1730 MulDivModOp,
1731 /// Addition / Subtraction (`+`, `-`).
1732 PlusMinus,
1733 /// Bitwise `XOR` operator (`^`).
1734 Xor,
1735 /// Bitwise `AND` operator (`&`).
1736 Ampersand,
1737 /// Bitwise `CARET` (^) for some dialects.
1738 Caret,
1739 /// Bitwise `OR` / pipe operator (`|`).
1740 Pipe,
1741 /// `:` operator for json/variant access.
1742 Colon,
1743 /// `BETWEEN` operator.
1744 Between,
1745 /// Equality operator (`=`).
1746 Eq,
1747 /// Pattern matching (`LIKE`).
1748 Like,
1749 /// `IS` operator (e.g. `IS NULL`).
1750 Is,
1751 /// Other Postgres-specific operators.
1752 PgOther,
1753 /// Unary `NOT`.
1754 UnaryNot,
1755 /// Logical `AND`.
1756 And,
1757 /// Logical `OR` (lowest precedence).
1758 Or,
1759}
1760
1761impl dyn Dialect {
1762 /// Returns true if `self` is the concrete dialect `T`.
1763 #[inline]
1764 pub fn is<T: Dialect>(&self) -> bool {
1765 // borrowed from `Any` implementation
1766 TypeId::of::<T>() == self.dialect()
1767 }
1768}
1769
1770/// Returns the built in [`Dialect`] corresponding to `dialect_name`.
1771///
1772/// See [`Dialect`] documentation for an example.
1773pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
1774 let dialect_name = dialect_name.as_ref();
1775 match dialect_name.to_lowercase().as_str() {
1776 "generic" => Some(Box::new(GenericDialect)),
1777 "mysql" => Some(Box::new(MySqlDialect {})),
1778 "postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
1779 "hive" => Some(Box::new(HiveDialect {})),
1780 "sqlite" => Some(Box::new(SQLiteDialect {})),
1781 "snowflake" => Some(Box::new(SnowflakeDialect)),
1782 "redshift" => Some(Box::new(RedshiftSqlDialect {})),
1783 "mssql" => Some(Box::new(MsSqlDialect {})),
1784 "clickhouse" => Some(Box::new(ClickHouseDialect {})),
1785 "bigquery" => Some(Box::new(BigQueryDialect)),
1786 "ansi" => Some(Box::new(AnsiDialect {})),
1787 "duckdb" => Some(Box::new(DuckDbDialect {})),
1788 "databricks" => Some(Box::new(DatabricksDialect {})),
1789 "oracle" => Some(Box::new(OracleDialect {})),
1790 _ => None,
1791 }
1792}
1793
1794#[cfg(test)]
1795mod tests {
1796 use super::*;
1797
1798 struct DialectHolder<'a> {
1799 dialect: &'a dyn Dialect,
1800 }
1801
1802 #[test]
1803 fn test_is_dialect() {
1804 let generic_dialect: &dyn Dialect = &GenericDialect {};
1805 let ansi_dialect: &dyn Dialect = &AnsiDialect {};
1806
1807 let generic_holder = DialectHolder {
1808 dialect: generic_dialect,
1809 };
1810 let ansi_holder = DialectHolder {
1811 dialect: ansi_dialect,
1812 };
1813
1814 assert!(dialect_of!(generic_holder is GenericDialect | AnsiDialect),);
1815 assert!(!dialect_of!(generic_holder is AnsiDialect));
1816 assert!(dialect_of!(ansi_holder is AnsiDialect));
1817 assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
1818 assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
1819 }
1820
1821 #[test]
1822 fn test_dialect_from_str() {
1823 assert!(parse_dialect("generic").is::<GenericDialect>());
1824 assert!(parse_dialect("mysql").is::<MySqlDialect>());
1825 assert!(parse_dialect("MySql").is::<MySqlDialect>());
1826 assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
1827 assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
1828 assert!(parse_dialect("hive").is::<HiveDialect>());
1829 assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
1830 assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
1831 assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
1832 assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
1833 assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
1834 assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
1835 assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
1836 assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
1837 assert!(parse_dialect("ansi").is::<AnsiDialect>());
1838 assert!(parse_dialect("ANSI").is::<AnsiDialect>());
1839 assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
1840 assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
1841 assert!(parse_dialect("DataBricks").is::<DatabricksDialect>());
1842 assert!(parse_dialect("databricks").is::<DatabricksDialect>());
1843
1844 // error cases
1845 assert!(dialect_from_str("Unknown").is_none());
1846 assert!(dialect_from_str("").is_none());
1847 }
1848
1849 fn parse_dialect(v: &str) -> Box<dyn Dialect> {
1850 dialect_from_str(v).unwrap()
1851 }
1852
1853 #[test]
1854 #[cfg(feature = "derive-dialect")]
1855 fn test_dialect_override() {
1856 derive_dialect!(EnhancedGenericDialect, GenericDialect,
1857 preserve_type_id = true,
1858 overrides = {
1859 supports_order_by_all = true,
1860 supports_nested_comments = true,
1861 supports_triple_quoted_string = true,
1862 },
1863 );
1864 let dialect = EnhancedGenericDialect::new();
1865
1866 assert!(dialect.supports_order_by_all());
1867 assert!(dialect.supports_nested_comments());
1868 assert!(dialect.supports_triple_quoted_string());
1869
1870 let d: &dyn Dialect = &dialect;
1871 assert!(d.is::<GenericDialect>());
1872 }
1873
1874 #[test]
1875 fn identifier_quote_style() {
1876 let tests: Vec<(&dyn Dialect, &str, Option<char>)> = vec![
1877 (&GenericDialect {}, "id", None),
1878 (&SQLiteDialect {}, "id", Some('`')),
1879 (&PostgreSqlDialect {}, "id", Some('"')),
1880 ];
1881
1882 for (dialect, ident, expected) in tests {
1883 let actual = dialect.identifier_quote_style(ident);
1884
1885 assert_eq!(actual, expected);
1886 }
1887 }
1888
1889 #[test]
1890 fn parse_with_wrapped_dialect() {
1891 /// Wrapper for a dialect. In a real-world example, this wrapper
1892 /// would tweak the behavior of the dialect. For the test case,
1893 /// it wraps all methods unaltered.
1894 #[derive(Debug)]
1895 struct WrappedDialect(MySqlDialect);
1896
1897 impl Dialect for WrappedDialect {
1898 fn dialect(&self) -> std::any::TypeId {
1899 self.0.dialect()
1900 }
1901
1902 fn is_identifier_start(&self, ch: char) -> bool {
1903 self.0.is_identifier_start(ch)
1904 }
1905
1906 fn is_delimited_identifier_start(&self, ch: char) -> bool {
1907 self.0.is_delimited_identifier_start(ch)
1908 }
1909
1910 fn is_nested_delimited_identifier_start(&self, ch: char) -> bool {
1911 self.0.is_nested_delimited_identifier_start(ch)
1912 }
1913
1914 fn peek_nested_delimited_identifier_quotes(
1915 &self,
1916 chars: std::iter::Peekable<std::str::Chars<'_>>,
1917 ) -> Option<(char, Option<char>)> {
1918 self.0.peek_nested_delimited_identifier_quotes(chars)
1919 }
1920
1921 fn identifier_quote_style(&self, identifier: &str) -> Option<char> {
1922 self.0.identifier_quote_style(identifier)
1923 }
1924
1925 fn supports_string_literal_backslash_escape(&self) -> bool {
1926 self.0.supports_string_literal_backslash_escape()
1927 }
1928
1929 fn supports_filter_during_aggregation(&self) -> bool {
1930 self.0.supports_filter_during_aggregation()
1931 }
1932
1933 fn supports_within_after_array_aggregation(&self) -> bool {
1934 self.0.supports_within_after_array_aggregation()
1935 }
1936
1937 fn supports_group_by_expr(&self) -> bool {
1938 self.0.supports_group_by_expr()
1939 }
1940
1941 fn supports_in_empty_list(&self) -> bool {
1942 self.0.supports_in_empty_list()
1943 }
1944
1945 fn convert_type_before_value(&self) -> bool {
1946 self.0.convert_type_before_value()
1947 }
1948
1949 fn parse_prefix(
1950 &self,
1951 parser: &mut sqlparser::parser::Parser,
1952 ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
1953 self.0.parse_prefix(parser)
1954 }
1955
1956 fn parse_infix(
1957 &self,
1958 parser: &mut sqlparser::parser::Parser,
1959 expr: &Expr,
1960 precedence: u8,
1961 ) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
1962 self.0.parse_infix(parser, expr, precedence)
1963 }
1964
1965 fn get_next_precedence(
1966 &self,
1967 parser: &sqlparser::parser::Parser,
1968 ) -> Option<Result<u8, sqlparser::parser::ParserError>> {
1969 self.0.get_next_precedence(parser)
1970 }
1971
1972 fn parse_statement(
1973 &self,
1974 parser: &mut sqlparser::parser::Parser,
1975 ) -> Option<Result<Statement, sqlparser::parser::ParserError>> {
1976 self.0.parse_statement(parser)
1977 }
1978
1979 fn is_identifier_part(&self, ch: char) -> bool {
1980 self.0.is_identifier_part(ch)
1981 }
1982 }
1983
1984 #[allow(clippy::needless_raw_string_hashes)]
1985 let statement = r#"SELECT 'Wayne\'s World'"#;
1986 let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
1987 let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
1988 assert!(res1.is_ok());
1989 assert_eq!(res1, res2);
1990 }
1991}