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