sqlparser/dialect/
mod.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13mod ansi;
14mod bigquery;
15mod clickhouse;
16mod generic;
17mod hive;
18mod mssql;
19mod mysql;
20mod postgresql;
21mod redshift;
22mod snowflake;
23mod sqlite;
24
25use crate::ast::{Expr, Statement};
26use core::any::{Any, TypeId};
27use core::fmt::Debug;
28use core::iter::Peekable;
29use core::str::Chars;
30
31pub use self::ansi::AnsiDialect;
32pub use self::bigquery::BigQueryDialect;
33pub use self::clickhouse::ClickHouseDialect;
34pub use self::generic::GenericDialect;
35pub use self::hive::HiveDialect;
36pub use self::mssql::MsSqlDialect;
37pub use self::mysql::MySqlDialect;
38pub use self::postgresql::PostgreSqlDialect;
39pub use self::redshift::RedshiftSqlDialect;
40pub use self::snowflake::SnowflakeDialect;
41pub use self::sqlite::SQLiteDialect;
42pub use crate::keywords;
43use crate::parser::{Parser, ParserError};
44
45/// `dialect_of!(parser is SQLiteDialect |  GenericDialect)` evaluates
46/// to `true` if `parser.dialect` is one of the `Dialect`s specified.
47macro_rules! dialect_of {
48    ( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
49        ($($parsed_dialect.dialect.is::<$dialect_type>())||+)
50    };
51}
52
53pub trait Dialect: Debug + Any {
54    /// Determine if a character starts a quoted identifier. The default
55    /// implementation, accepting "double quoted" ids is both ANSI-compliant
56    /// and appropriate for most dialects (with the notable exception of
57    /// MySQL, MS SQL, and sqlite). You can accept one of characters listed
58    /// in `Word::matching_end_quote` here
59    fn is_delimited_identifier_start(&self, ch: char) -> bool {
60        ch == '"'
61    }
62    /// Determine if quoted characters are proper for identifier
63    fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
64        true
65    }
66    /// Determine if a character is a valid start character for an unquoted identifier
67    fn is_identifier_start(&self, ch: char) -> bool;
68    /// Determine if a character is a valid unquoted identifier character
69    fn is_identifier_part(&self, ch: char) -> bool;
70    /// Does the dialect support `FILTER (WHERE expr)` for aggregate queries?
71    fn supports_filter_during_aggregation(&self) -> bool {
72        false
73    }
74    /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions.
75    /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`]
76    ///
77    /// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function
78    fn supports_within_after_array_aggregation(&self) -> bool {
79        false
80    }
81    /// Dialect-specific prefix parser override
82    fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
83        // return None to fall back to the default behavior
84        None
85    }
86    /// Dialect-specific infix parser override
87    fn parse_infix(
88        &self,
89        _parser: &mut Parser,
90        _expr: &Expr,
91        _precedence: u8,
92    ) -> Option<Result<Expr, ParserError>> {
93        // return None to fall back to the default behavior
94        None
95    }
96    /// Dialect-specific precedence override
97    fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
98        // return None to fall back to the default behavior
99        None
100    }
101    /// Dialect-specific statement parser override
102    fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
103        // return None to fall back to the default behavior
104        None
105    }
106}
107
108impl dyn Dialect {
109    #[inline]
110    pub fn is<T: Dialect>(&self) -> bool {
111        // borrowed from `Any` implementation
112        TypeId::of::<T>() == self.type_id()
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::ansi::AnsiDialect;
119    use super::generic::GenericDialect;
120    use super::*;
121
122    struct DialectHolder<'a> {
123        dialect: &'a dyn Dialect,
124    }
125
126    #[test]
127    fn test_is_dialect() {
128        let generic_dialect: &dyn Dialect = &GenericDialect {};
129        let ansi_dialect: &dyn Dialect = &AnsiDialect {};
130
131        let generic_holder = DialectHolder {
132            dialect: generic_dialect,
133        };
134        let ansi_holder = DialectHolder {
135            dialect: ansi_dialect,
136        };
137
138        assert!(dialect_of!(generic_holder is GenericDialect |  AnsiDialect),);
139        assert!(!dialect_of!(generic_holder is  AnsiDialect));
140        assert!(dialect_of!(ansi_holder is AnsiDialect));
141        assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
142        assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
143    }
144}