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