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