mod ansi;
mod bigquery;
mod clickhouse;
mod duckdb;
mod generic;
mod hive;
mod mssql;
mod mysql;
mod postgresql;
mod redshift;
mod snowflake;
mod sqlite;
use crate::ast::{Expr, Statement};
use core::any::{Any, TypeId};
use core::fmt::Debug;
use core::iter::Peekable;
use core::str::Chars;
pub use self::ansi::AnsiDialect;
pub use self::bigquery::BigQueryDialect;
pub use self::clickhouse::ClickHouseDialect;
pub use self::duckdb::DuckDbDialect;
pub use self::generic::GenericDialect;
pub use self::hive::HiveDialect;
pub use self::mssql::MsSqlDialect;
pub use self::mysql::MySqlDialect;
pub use self::postgresql::PostgreSqlDialect;
pub use self::redshift::RedshiftSqlDialect;
pub use self::snowflake::SnowflakeDialect;
pub use self::sqlite::SQLiteDialect;
pub use crate::keywords;
use crate::parser::{Parser, ParserError};
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
macro_rules! dialect_of {
( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
($($parsed_dialect.dialect.is::<$dialect_type>())||+)
};
}
pub trait Dialect: Debug + Any {
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '"' || ch == '`'
}
fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
true
}
fn is_identifier_start(&self, ch: char) -> bool;
fn is_identifier_part(&self, ch: char) -> bool;
fn supports_filter_during_aggregation(&self) -> bool {
false
}
fn supports_within_after_array_aggregation(&self) -> bool {
false
}
fn supports_group_by_expr(&self) -> bool {
false
}
fn supports_substring_from_for_expr(&self) -> bool {
true
}
fn supports_in_empty_list(&self) -> bool {
false
}
fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
None
}
fn parse_infix(
&self,
_parser: &mut Parser,
_expr: &Expr,
_precedence: u8,
) -> Option<Result<Expr, ParserError>> {
None
}
fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
None
}
fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
None
}
}
impl dyn Dialect {
#[inline]
pub fn is<T: Dialect>(&self) -> bool {
TypeId::of::<T>() == self.type_id()
}
}
pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
let dialect_name = dialect_name.as_ref();
match dialect_name.to_lowercase().as_str() {
"generic" => Some(Box::new(GenericDialect)),
"mysql" => Some(Box::new(MySqlDialect {})),
"postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
"hive" => Some(Box::new(HiveDialect {})),
"sqlite" => Some(Box::new(SQLiteDialect {})),
"snowflake" => Some(Box::new(SnowflakeDialect)),
"redshift" => Some(Box::new(RedshiftSqlDialect {})),
"mssql" => Some(Box::new(MsSqlDialect {})),
"clickhouse" => Some(Box::new(ClickHouseDialect {})),
"bigquery" => Some(Box::new(BigQueryDialect)),
"ansi" => Some(Box::new(AnsiDialect {})),
"duckdb" => Some(Box::new(DuckDbDialect {})),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::ansi::AnsiDialect;
use super::generic::GenericDialect;
use super::*;
struct DialectHolder<'a> {
dialect: &'a dyn Dialect,
}
#[test]
fn test_is_dialect() {
let generic_dialect: &dyn Dialect = &GenericDialect {};
let ansi_dialect: &dyn Dialect = &AnsiDialect {};
let generic_holder = DialectHolder {
dialect: generic_dialect,
};
let ansi_holder = DialectHolder {
dialect: ansi_dialect,
};
assert!(dialect_of!(generic_holder is GenericDialect | AnsiDialect),);
assert!(!dialect_of!(generic_holder is AnsiDialect));
assert!(dialect_of!(ansi_holder is AnsiDialect));
assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
}
#[test]
fn test_dialect_from_str() {
assert!(parse_dialect("generic").is::<GenericDialect>());
assert!(parse_dialect("mysql").is::<MySqlDialect>());
assert!(parse_dialect("MySql").is::<MySqlDialect>());
assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
assert!(parse_dialect("hive").is::<HiveDialect>());
assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
assert!(parse_dialect("ansi").is::<AnsiDialect>());
assert!(parse_dialect("ANSI").is::<AnsiDialect>());
assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
assert!(dialect_from_str("Unknown").is_none());
assert!(dialect_from_str("").is_none());
}
fn parse_dialect(v: &str) -> Box<dyn Dialect> {
dialect_from_str(v).unwrap()
}
}