sqltk_parser/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, 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/// Encapsulates the differences between SQL implementations.
79///
80/// # SQL Dialects
81///
82/// SQL implementations deviate from one another, either due to
83/// custom extensions or various historical reasons. This trait
84/// encapsulates the parsing differences between dialects.
85///
86/// [`GenericDialect`] is the most permissive dialect, and parses the union of
87/// all the other dialects, when there is no ambiguity. However, it does not
88/// currently allow `CREATE TABLE` statements without types specified for all
89/// columns; use [`SQLiteDialect`] if you require that.
90///
91/// # Examples
92/// Most users create a [`Dialect`] directly, as shown on the [module
93/// level documentation]:
94///
95/// ```
96/// # use sqltk_parser::dialect::AnsiDialect;
97/// let dialect = AnsiDialect {};
98/// ```
99///
100/// It is also possible to dynamically create a [`Dialect`] from its
101/// name. For example:
102///
103/// ```
104/// # use sqltk_parser::dialect::{AnsiDialect, dialect_from_str};
105/// let dialect = dialect_from_str("ansi").unwrap();
106///
107/// // Parsed dialect is an instance of `AnsiDialect`:
108/// assert!(dialect.is::<AnsiDialect>());
109/// ```
110///
111/// [module level documentation]: crate
112pub trait Dialect: Debug + Any {
113 /// Determine the [`TypeId`] of this dialect.
114 ///
115 /// By default, return the same [`TypeId`] as [`Any::type_id`]. Can be overridden
116 /// by dialects that behave like other dialects
117 /// (for example when wrapping a dialect).
118 fn dialect(&self) -> TypeId {
119 self.type_id()
120 }
121
122 /// Determine if a character starts a quoted identifier. The default
123 /// implementation, accepting "double quoted" ids is both ANSI-compliant
124 /// and appropriate for most dialects (with the notable exception of
125 /// MySQL, MS SQL, and sqlite). You can accept one of characters listed
126 /// in `Word::matching_end_quote` here
127 fn is_delimited_identifier_start(&self, ch: char) -> bool {
128 ch == '"' || ch == '`'
129 }
130
131 /// Return the character used to quote identifiers.
132 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
133 None
134 }
135
136 /// Determine if quoted characters are proper for identifier
137 fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
138 true
139 }
140
141 /// Determine if a character is a valid start character for an unquoted identifier
142 fn is_identifier_start(&self, ch: char) -> bool;
143
144 /// Determine if a character is a valid unquoted identifier character
145 fn is_identifier_part(&self, ch: char) -> bool;
146
147 /// Most dialects do not have custom operators. Override this method to provide custom operators.
148 fn is_custom_operator_part(&self, _ch: char) -> bool {
149 false
150 }
151
152 /// Determine if the dialect supports escaping characters via '\' in string literals.
153 ///
154 /// Some dialects like BigQuery and Snowflake support this while others like
155 /// Postgres do not. Such that the following is accepted by the former but
156 /// rejected by the latter.
157 /// ```sql
158 /// SELECT 'ab\'cd';
159 /// ```
160 ///
161 /// Conversely, such dialects reject the following statement which
162 /// otherwise would be valid in the other dialects.
163 /// ```sql
164 /// SELECT '\';
165 /// ```
166 fn supports_string_literal_backslash_escape(&self) -> bool {
167 false
168 }
169
170 /// Determine if the dialect supports string literals with `U&` prefix.
171 /// This is used to specify Unicode code points in string literals.
172 /// For example, in PostgreSQL, the following is a valid string literal:
173 /// ```sql
174 /// SELECT U&'\0061\0062\0063';
175 /// ```
176 /// This is equivalent to the string literal `'abc'`.
177 /// See
178 /// - [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
179 /// - [H2 docs](http://www.h2database.com/html/grammar.html#string)
180 fn supports_unicode_string_literal(&self) -> bool {
181 false
182 }
183
184 /// Does the dialect support `FILTER (WHERE expr)` for aggregate queries?
185 fn supports_filter_during_aggregation(&self) -> bool {
186 false
187 }
188
189 /// Returns true if the dialect supports referencing another named window
190 /// within a window clause declaration.
191 ///
192 /// Example
193 /// ```sql
194 /// SELECT * FROM mytable
195 /// WINDOW mynamed_window AS another_named_window
196 /// ```
197 fn supports_window_clause_named_window_reference(&self) -> bool {
198 false
199 }
200
201 /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions.
202 /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`]
203 ///
204 /// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function
205 fn supports_within_after_array_aggregation(&self) -> bool {
206 false
207 }
208
209 /// Returns true if the dialects supports `group sets, roll up, or cube` expressions.
210 fn supports_group_by_expr(&self) -> bool {
211 false
212 }
213
214 /// Returns true if the dialect supports CONNECT BY.
215 fn supports_connect_by(&self) -> bool {
216 false
217 }
218
219 /// Returns true if the dialect supports the MATCH_RECOGNIZE operation.
220 fn supports_match_recognize(&self) -> bool {
221 false
222 }
223
224 /// Returns true if the dialect supports `(NOT) IN ()` expressions
225 fn supports_in_empty_list(&self) -> bool {
226 false
227 }
228
229 /// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE} [TRANSACTION]` statements
230 fn supports_start_transaction_modifier(&self) -> bool {
231 false
232 }
233
234 /// Returns true if the dialect supports named arguments of the form `FUN(a = '1', b = '2')`.
235 fn supports_named_fn_args_with_eq_operator(&self) -> bool {
236 false
237 }
238
239 /// Returns true if the dialect supports named arguments of the form `FUN(a : '1', b : '2')`.
240 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
241 false
242 }
243
244 /// Returns true if the dialect supports named arguments of the form `FUN(a := '1', b := '2')`.
245 fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
246 false
247 }
248
249 /// Returns true if the dialect supports named arguments of the form `FUN(a => '1', b => '2')`.
250 fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
251 true
252 }
253
254 /// Returns true if dialect supports argument name as arbitrary expression.
255 /// e.g. `FUN(LOWER('a'):'1', b:'2')`
256 /// Such function arguments are represented in the AST by the `FunctionArg::ExprNamed` variant,
257 /// otherwise use the `FunctionArg::Named` variant (compatible reason).
258 fn supports_named_fn_args_with_expr_name(&self) -> bool {
259 false
260 }
261
262 /// Returns true if the dialect supports identifiers starting with a numeric
263 /// prefix such as tables named `59901_user_login`
264 fn supports_numeric_prefix(&self) -> bool {
265 false
266 }
267
268 /// Returns true if the dialects supports specifying null treatment
269 /// as part of a window function's parameter list as opposed
270 /// to after the parameter list.
271 ///
272 /// i.e The following syntax returns true
273 /// ```sql
274 /// FIRST_VALUE(a IGNORE NULLS) OVER ()
275 /// ```
276 /// while the following syntax returns false
277 /// ```sql
278 /// FIRST_VALUE(a) IGNORE NULLS OVER ()
279 /// ```
280 fn supports_window_function_null_treatment_arg(&self) -> bool {
281 false
282 }
283
284 /// Returns true if the dialect supports defining structs or objects using a
285 /// syntax like `{'x': 1, 'y': 2, 'z': 3}`.
286 fn supports_dictionary_syntax(&self) -> bool {
287 false
288 }
289
290 /// Returns true if the dialect supports defining object using the
291 /// syntax like `Map {1: 10, 2: 20}`.
292 fn support_map_literal_syntax(&self) -> bool {
293 false
294 }
295
296 /// Returns true if the dialect supports lambda functions, for example:
297 ///
298 /// ```sql
299 /// SELECT transform(array(1, 2, 3), x -> x + 1); -- returns [2,3,4]
300 /// ```
301 fn supports_lambda_functions(&self) -> bool {
302 false
303 }
304
305 /// Returns true if the dialect supports method calls, for example:
306 ///
307 /// ```sql
308 /// SELECT (SELECT ',' + name FROM sys.objects FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
309 /// ```
310 fn supports_methods(&self) -> bool {
311 false
312 }
313
314 /// Returns true if the dialect supports multiple variable assignment
315 /// using parentheses in a `SET` variable declaration.
316 ///
317 /// ```sql
318 /// SET (variable[, ...]) = (expression[, ...]);
319 /// ```
320 fn supports_parenthesized_set_variables(&self) -> bool {
321 false
322 }
323
324 /// Returns true if the dialect supports an `EXCEPT` clause following a
325 /// wildcard in a select list.
326 ///
327 /// For example
328 /// ```sql
329 /// SELECT * EXCEPT order_id FROM orders;
330 /// ```
331 fn supports_select_wildcard_except(&self) -> bool {
332 false
333 }
334
335 /// Returns true if the dialect has a CONVERT function which accepts a type first
336 /// and an expression second, e.g. `CONVERT(varchar, 1)`
337 fn convert_type_before_value(&self) -> bool {
338 false
339 }
340
341 /// Returns true if the dialect supports triple quoted string
342 /// e.g. `"""abc"""`
343 fn supports_triple_quoted_string(&self) -> bool {
344 false
345 }
346
347 /// Dialect-specific prefix parser override
348 fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
349 // return None to fall back to the default behavior
350 None
351 }
352
353 /// Does the dialect support trailing commas around the query?
354 fn supports_trailing_commas(&self) -> bool {
355 false
356 }
357
358 /// Does the dialect support parsing `LIMIT 1, 2` as `LIMIT 2 OFFSET 1`?
359 fn supports_limit_comma(&self) -> bool {
360 false
361 }
362
363 /// Does the dialect support trailing commas in the projection list?
364 fn supports_projection_trailing_commas(&self) -> bool {
365 self.supports_trailing_commas()
366 }
367
368 /// Returns true if the dialect supports double dot notation for object names
369 ///
370 /// Example
371 /// ```sql
372 /// SELECT * FROM db_name..table_name
373 /// ```
374 fn supports_object_name_double_dot_notation(&self) -> bool {
375 false
376 }
377
378 /// Return true if the dialect supports the STRUCT literal
379 ///
380 /// Example
381 /// ```sql
382 /// SELECT STRUCT(1 as one, 'foo' as foo, false)
383 /// ```
384 fn supports_struct_literal(&self) -> bool {
385 false
386 }
387
388 /// Dialect-specific infix parser override
389 ///
390 /// This method is called to parse the next infix expression.
391 ///
392 /// If `None` is returned, falls back to the default behavior.
393 fn parse_infix(
394 &self,
395 _parser: &mut Parser,
396 _expr: &Expr,
397 _precedence: u8,
398 ) -> Option<Result<Expr, ParserError>> {
399 // return None to fall back to the default behavior
400 None
401 }
402
403 /// Dialect-specific precedence override
404 ///
405 /// This method is called to get the precedence of the next token.
406 ///
407 /// If `None` is returned, falls back to the default behavior.
408 fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
409 // return None to fall back to the default behavior
410 None
411 }
412
413 /// Get the precedence of the next token, looking at the full token stream.
414 ///
415 /// A higher number => higher precedence
416 ///
417 /// See [`Self::get_next_precedence`] to override the behavior for just the
418 /// next token.
419 ///
420 /// The default implementation is used for many dialects, but can be
421 /// overridden to provide dialect-specific behavior.
422 fn get_next_precedence_default(&self, parser: &Parser) -> Result<u8, ParserError> {
423 if let Some(precedence) = self.get_next_precedence(parser) {
424 return precedence;
425 }
426 macro_rules! p {
427 ($precedence:ident) => {
428 self.prec_value(Precedence::$precedence)
429 };
430 }
431
432 let token = parser.peek_token();
433 debug!("get_next_precedence_full() {:?}", token);
434 match token.token {
435 Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
436 Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
437 Token::Word(w) if w.keyword == Keyword::XOR => Ok(p!(Xor)),
438
439 Token::Word(w) if w.keyword == Keyword::AT => {
440 match (
441 parser.peek_nth_token(1).token,
442 parser.peek_nth_token(2).token,
443 ) {
444 (Token::Word(w), Token::Word(w2))
445 if w.keyword == Keyword::TIME && w2.keyword == Keyword::ZONE =>
446 {
447 Ok(p!(AtTz))
448 }
449 _ => Ok(self.prec_unknown()),
450 }
451 }
452
453 Token::Word(w) if w.keyword == Keyword::NOT => match parser.peek_nth_token(1).token {
454 // The precedence of NOT varies depending on keyword that
455 // follows it. If it is followed by IN, BETWEEN, or LIKE,
456 // it takes on the precedence of those tokens. Otherwise, it
457 // is not an infix operator, and therefore has zero
458 // precedence.
459 Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
460 Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
461 Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
462 Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
463 Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
464 Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
465 Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
466 _ => Ok(self.prec_unknown()),
467 },
468 Token::Word(w) if w.keyword == Keyword::IS => Ok(p!(Is)),
469 Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
470 Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
471 Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
472 Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
473 Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
474 Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
475 Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
476 Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(p!(Between)),
477 Token::Word(w) if w.keyword == Keyword::DIV => Ok(p!(MulDivModOp)),
478 Token::Eq
479 | Token::Lt
480 | Token::LtEq
481 | Token::Neq
482 | Token::Gt
483 | Token::GtEq
484 | Token::DoubleEq
485 | Token::Tilde
486 | Token::TildeAsterisk
487 | Token::ExclamationMarkTilde
488 | Token::ExclamationMarkTildeAsterisk
489 | Token::DoubleTilde
490 | Token::DoubleTildeAsterisk
491 | Token::ExclamationMarkDoubleTilde
492 | Token::ExclamationMarkDoubleTildeAsterisk
493 | Token::Spaceship => Ok(p!(Eq)),
494 Token::Pipe => Ok(p!(Pipe)),
495 Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
496 Token::Ampersand => Ok(p!(Ampersand)),
497 Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
498 Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
499 Ok(p!(MulDivModOp))
500 }
501 Token::DoubleColon
502 | Token::ExclamationMark
503 | Token::LBracket
504 | Token::Overlap
505 | Token::CaretAt => Ok(p!(DoubleColon)),
506 Token::Arrow
507 | Token::LongArrow
508 | Token::HashArrow
509 | Token::HashLongArrow
510 | Token::AtArrow
511 | Token::ArrowAt
512 | Token::HashMinus
513 | Token::AtQuestion
514 | Token::AtAt
515 | Token::Question
516 | Token::QuestionAnd
517 | Token::QuestionPipe
518 | Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
519 _ => Ok(self.prec_unknown()),
520 }
521 }
522
523 /// Dialect-specific statement parser override
524 ///
525 /// This method is called to parse the next statement.
526 ///
527 /// If `None` is returned, falls back to the default behavior.
528 fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
529 // return None to fall back to the default behavior
530 None
531 }
532
533 /// Dialect-specific column option parser override
534 ///
535 /// This method is called to parse the next column option.
536 ///
537 /// If `None` is returned, falls back to the default behavior.
538 fn parse_column_option(
539 &self,
540 _parser: &mut Parser,
541 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
542 // return None to fall back to the default behavior
543 Ok(None)
544 }
545
546 /// Decide the lexical Precedence of operators.
547 ///
548 /// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
549 fn prec_value(&self, prec: Precedence) -> u8 {
550 match prec {
551 Precedence::DoubleColon => 50,
552 Precedence::AtTz => 41,
553 Precedence::MulDivModOp => 40,
554 Precedence::PlusMinus => 30,
555 Precedence::Xor => 24,
556 Precedence::Ampersand => 23,
557 Precedence::Caret => 22,
558 Precedence::Pipe => 21,
559 Precedence::Between => 20,
560 Precedence::Eq => 20,
561 Precedence::Like => 19,
562 Precedence::Is => 17,
563 Precedence::PgOther => 16,
564 Precedence::UnaryNot => 15,
565 Precedence::And => 10,
566 Precedence::Or => 5,
567 }
568 }
569
570 /// Returns the precedence when the precedence is otherwise unknown
571 fn prec_unknown(&self) -> u8 {
572 0
573 }
574
575 /// Returns true if this dialect requires the `TABLE` keyword after `DESCRIBE`
576 ///
577 /// Defaults to false.
578 ///
579 /// If true, the following statement is valid: `DESCRIBE TABLE my_table`
580 /// If false, the following statements are valid: `DESCRIBE my_table` and `DESCRIBE table`
581 fn describe_requires_table_keyword(&self) -> bool {
582 false
583 }
584
585 /// Returns true if this dialect allows the `EXTRACT` function to words other than [`Keyword`].
586 fn allow_extract_custom(&self) -> bool {
587 false
588 }
589
590 /// Returns true if this dialect allows the `EXTRACT` function to use single quotes in the part being extracted.
591 fn allow_extract_single_quotes(&self) -> bool {
592 false
593 }
594
595 /// Does the dialect support with clause in create index statement?
596 /// e.g. `CREATE INDEX idx ON t WITH (key = value, key2)`
597 fn supports_create_index_with_clause(&self) -> bool {
598 false
599 }
600
601 /// Whether `INTERVAL` expressions require units (called "qualifiers" in the ANSI SQL spec) to be specified,
602 /// e.g. `INTERVAL 1 DAY` vs `INTERVAL 1`.
603 ///
604 /// Expressions within intervals (e.g. `INTERVAL '1' + '1' DAY`) are only allowed when units are required.
605 ///
606 /// See <https://github.com/sqlparser-rs/sqlparser-rs/pull/1398> for more information.
607 ///
608 /// When `true`:
609 /// * `INTERVAL '1' DAY` is VALID
610 /// * `INTERVAL 1 + 1 DAY` is VALID
611 /// * `INTERVAL '1' + '1' DAY` is VALID
612 /// * `INTERVAL '1'` is INVALID
613 ///
614 /// When `false`:
615 /// * `INTERVAL '1'` is VALID
616 /// * `INTERVAL '1' DAY` is VALID — unit is not required, but still allowed
617 /// * `INTERVAL 1 + 1 DAY` is INVALID
618 fn require_interval_qualifier(&self) -> bool {
619 false
620 }
621
622 fn supports_explain_with_utility_options(&self) -> bool {
623 false
624 }
625
626 fn supports_asc_desc_in_column_definition(&self) -> bool {
627 false
628 }
629
630 /// Returns true if the dialect supports `a!` expressions
631 fn supports_factorial_operator(&self) -> bool {
632 false
633 }
634
635 /// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
636 /// as an alias assignment operator, rather than a boolean expression.
637 /// For example: the following statements are equivalent for such a dialect:
638 /// ```sql
639 /// SELECT col_alias = col FROM tbl;
640 /// SELECT col_alias AS col FROM tbl;
641 /// ```
642 fn supports_eq_alias_assignment(&self) -> bool {
643 false
644 }
645
646 /// Returns true if this dialect supports the `TRY_CONVERT` function
647 fn supports_try_convert(&self) -> bool {
648 false
649 }
650
651 /// Returns true if the dialect supports `!a` syntax for boolean `NOT` expressions.
652 fn supports_bang_not_operator(&self) -> bool {
653 false
654 }
655
656 /// Returns true if the dialect supports the `LISTEN`, `UNLISTEN` and `NOTIFY` statements
657 fn supports_listen_notify(&self) -> bool {
658 false
659 }
660
661 /// Returns true if the dialect supports the `LOAD DATA` statement
662 fn supports_load_data(&self) -> bool {
663 false
664 }
665
666 /// Returns true if the dialect supports the `LOAD extension` statement
667 fn supports_load_extension(&self) -> bool {
668 false
669 }
670
671 /// Returns true if this dialect expects the `TOP` option
672 /// before the `ALL`/`DISTINCT` options in a `SELECT` statement.
673 fn supports_top_before_distinct(&self) -> bool {
674 false
675 }
676
677 /// Returns true if the dialect supports boolean literals (`true` and `false`).
678 /// For example, in MSSQL these are treated as identifiers rather than boolean literals.
679 fn supports_boolean_literals(&self) -> bool {
680 true
681 }
682
683 /// Returns true if this dialect supports the `LIKE 'pattern'` option in
684 /// a `SHOW` statement before the `IN` option
685 fn supports_show_like_before_in(&self) -> bool {
686 false
687 }
688
689 /// Returns true if this dialect supports the `COMMENT` statement
690 fn supports_comment_on(&self) -> bool {
691 false
692 }
693
694 /// Returns true if the dialect supports the `CREATE TABLE SELECT` statement
695 fn supports_create_table_select(&self) -> bool {
696 false
697 }
698
699 /// Returns true if the dialect supports PartiQL for querying semi-structured data
700 /// <https://partiql.org/index.html>
701 fn supports_partiql(&self) -> bool {
702 false
703 }
704
705 /// Returns true if the specified keyword is reserved and cannot be
706 /// used as an identifier without special handling like quoting.
707 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
708 keywords::RESERVED_FOR_IDENTIFIER.contains(&kw)
709 }
710}
711
712/// This represents the operators for which precedence must be defined
713///
714/// higher number -> higher precedence
715#[derive(Debug, Clone, Copy)]
716pub enum Precedence {
717 DoubleColon,
718 AtTz,
719 MulDivModOp,
720 PlusMinus,
721 Xor,
722 Ampersand,
723 Caret,
724 Pipe,
725 Between,
726 Eq,
727 Like,
728 Is,
729 PgOther,
730 UnaryNot,
731 And,
732 Or,
733}
734
735impl dyn Dialect {
736 #[inline]
737 pub fn is<T: Dialect>(&self) -> bool {
738 // borrowed from `Any` implementation
739 TypeId::of::<T>() == self.dialect()
740 }
741}
742
743/// Returns the built in [`Dialect`] corresponding to `dialect_name`.
744///
745/// See [`Dialect`] documentation for an example.
746pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
747 let dialect_name = dialect_name.as_ref();
748 match dialect_name.to_lowercase().as_str() {
749 "generic" => Some(Box::new(GenericDialect)),
750 "mysql" => Some(Box::new(MySqlDialect {})),
751 "postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
752 "hive" => Some(Box::new(HiveDialect {})),
753 "sqlite" => Some(Box::new(SQLiteDialect {})),
754 "snowflake" => Some(Box::new(SnowflakeDialect)),
755 "redshift" => Some(Box::new(RedshiftSqlDialect {})),
756 "mssql" => Some(Box::new(MsSqlDialect {})),
757 "clickhouse" => Some(Box::new(ClickHouseDialect {})),
758 "bigquery" => Some(Box::new(BigQueryDialect)),
759 "ansi" => Some(Box::new(AnsiDialect {})),
760 "duckdb" => Some(Box::new(DuckDbDialect {})),
761 "databricks" => Some(Box::new(DatabricksDialect {})),
762 _ => None,
763 }
764}
765
766#[cfg(test)]
767mod tests {
768 use super::*;
769
770 struct DialectHolder<'a> {
771 dialect: &'a dyn Dialect,
772 }
773
774 #[test]
775 fn test_is_dialect() {
776 let generic_dialect: &dyn Dialect = &GenericDialect {};
777 let ansi_dialect: &dyn Dialect = &AnsiDialect {};
778
779 let generic_holder = DialectHolder {
780 dialect: generic_dialect,
781 };
782 let ansi_holder = DialectHolder {
783 dialect: ansi_dialect,
784 };
785
786 assert!(dialect_of!(generic_holder is GenericDialect | AnsiDialect),);
787 assert!(!dialect_of!(generic_holder is AnsiDialect));
788 assert!(dialect_of!(ansi_holder is AnsiDialect));
789 assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
790 assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
791 }
792
793 #[test]
794 fn test_dialect_from_str() {
795 assert!(parse_dialect("generic").is::<GenericDialect>());
796 assert!(parse_dialect("mysql").is::<MySqlDialect>());
797 assert!(parse_dialect("MySql").is::<MySqlDialect>());
798 assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
799 assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
800 assert!(parse_dialect("hive").is::<HiveDialect>());
801 assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
802 assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
803 assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
804 assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
805 assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
806 assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
807 assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
808 assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
809 assert!(parse_dialect("ansi").is::<AnsiDialect>());
810 assert!(parse_dialect("ANSI").is::<AnsiDialect>());
811 assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
812 assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
813 assert!(parse_dialect("DataBricks").is::<DatabricksDialect>());
814 assert!(parse_dialect("databricks").is::<DatabricksDialect>());
815
816 // error cases
817 assert!(dialect_from_str("Unknown").is_none());
818 assert!(dialect_from_str("").is_none());
819 }
820
821 fn parse_dialect(v: &str) -> Box<dyn Dialect> {
822 dialect_from_str(v).unwrap()
823 }
824
825 #[test]
826 fn identifier_quote_style() {
827 let tests: Vec<(&dyn Dialect, &str, Option<char>)> = vec![
828 (&GenericDialect {}, "id", None),
829 (&SQLiteDialect {}, "id", Some('`')),
830 (&PostgreSqlDialect {}, "id", Some('"')),
831 ];
832
833 for (dialect, ident, expected) in tests {
834 let actual = dialect.identifier_quote_style(ident);
835
836 assert_eq!(actual, expected);
837 }
838 }
839
840 #[test]
841 fn parse_with_wrapped_dialect() {
842 /// Wrapper for a dialect. In a real-world example, this wrapper
843 /// would tweak the behavior of the dialect. For the test case,
844 /// it wraps all methods unaltered.
845 #[derive(Debug)]
846 struct WrappedDialect(MySqlDialect);
847
848 impl Dialect for WrappedDialect {
849 fn dialect(&self) -> std::any::TypeId {
850 self.0.dialect()
851 }
852
853 fn is_identifier_start(&self, ch: char) -> bool {
854 self.0.is_identifier_start(ch)
855 }
856
857 fn is_delimited_identifier_start(&self, ch: char) -> bool {
858 self.0.is_delimited_identifier_start(ch)
859 }
860
861 fn identifier_quote_style(&self, identifier: &str) -> Option<char> {
862 self.0.identifier_quote_style(identifier)
863 }
864
865 fn supports_string_literal_backslash_escape(&self) -> bool {
866 self.0.supports_string_literal_backslash_escape()
867 }
868
869 fn is_proper_identifier_inside_quotes(
870 &self,
871 chars: std::iter::Peekable<std::str::Chars<'_>>,
872 ) -> bool {
873 self.0.is_proper_identifier_inside_quotes(chars)
874 }
875
876 fn supports_filter_during_aggregation(&self) -> bool {
877 self.0.supports_filter_during_aggregation()
878 }
879
880 fn supports_within_after_array_aggregation(&self) -> bool {
881 self.0.supports_within_after_array_aggregation()
882 }
883
884 fn supports_group_by_expr(&self) -> bool {
885 self.0.supports_group_by_expr()
886 }
887
888 fn supports_in_empty_list(&self) -> bool {
889 self.0.supports_in_empty_list()
890 }
891
892 fn convert_type_before_value(&self) -> bool {
893 self.0.convert_type_before_value()
894 }
895
896 fn parse_prefix(
897 &self,
898 parser: &mut sqltk_parser::parser::Parser,
899 ) -> Option<Result<Expr, sqltk_parser::parser::ParserError>> {
900 self.0.parse_prefix(parser)
901 }
902
903 fn parse_infix(
904 &self,
905 parser: &mut sqltk_parser::parser::Parser,
906 expr: &Expr,
907 precedence: u8,
908 ) -> Option<Result<Expr, sqltk_parser::parser::ParserError>> {
909 self.0.parse_infix(parser, expr, precedence)
910 }
911
912 fn get_next_precedence(
913 &self,
914 parser: &sqltk_parser::parser::Parser,
915 ) -> Option<Result<u8, sqltk_parser::parser::ParserError>> {
916 self.0.get_next_precedence(parser)
917 }
918
919 fn parse_statement(
920 &self,
921 parser: &mut sqltk_parser::parser::Parser,
922 ) -> Option<Result<Statement, sqltk_parser::parser::ParserError>> {
923 self.0.parse_statement(parser)
924 }
925
926 fn is_identifier_part(&self, ch: char) -> bool {
927 self.0.is_identifier_part(ch)
928 }
929 }
930
931 #[allow(clippy::needless_raw_string_hashes)]
932 let statement = r#"SELECT 'Wayne\'s World'"#;
933 let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
934 let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
935 assert!(res1.is_ok());
936 assert_eq!(res1, res2);
937 }
938}