use std::fmt;
use std::str::FromStr;
use crate::ast::dialect::FeatureSet;
use crate::dialect::Ansi;
#[cfg(feature = "bigquery")]
use crate::dialect::BigQuery;
#[cfg(feature = "clickhouse")]
use crate::dialect::ClickHouse;
#[cfg(feature = "databricks")]
use crate::dialect::Databricks;
#[cfg(feature = "duckdb")]
use crate::dialect::DuckDb;
#[cfg(feature = "hive")]
use crate::dialect::Hive;
#[cfg(feature = "lenient")]
use crate::dialect::Lenient;
#[cfg(feature = "mssql")]
use crate::dialect::Mssql;
#[cfg(feature = "mysql")]
use crate::dialect::MySql;
#[cfg(feature = "postgres")]
use crate::dialect::Postgres;
#[cfg(feature = "quiltdb")]
use crate::dialect::QuiltDb;
#[cfg(feature = "redshift")]
use crate::dialect::Redshift;
#[cfg(feature = "snowflake")]
use crate::dialect::Snowflake;
#[cfg(feature = "sqlite")]
use crate::dialect::Sqlite;
use crate::error::ParseResult;
use crate::parser::{ParseConfig, Parsed, Recovered, parse_recovering_with, parse_with};
use crate::render::RenderDialect;
use crate::tokenizer::{LexError, Token, TriviaIndex, tokenize_with, tokenize_with_trivia};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum BuiltinDialect {
Ansi,
#[cfg(feature = "postgres")]
Postgres,
#[cfg(feature = "quiltdb")]
QuiltDb,
#[cfg(feature = "mysql")]
MySql,
#[cfg(feature = "sqlite")]
Sqlite,
#[cfg(feature = "duckdb")]
DuckDb,
#[cfg(feature = "bigquery")]
BigQuery,
#[cfg(feature = "hive")]
Hive,
#[cfg(feature = "clickhouse")]
ClickHouse,
#[cfg(feature = "databricks")]
Databricks,
#[cfg(feature = "mssql")]
Mssql,
#[cfg(feature = "snowflake")]
Snowflake,
#[cfg(feature = "redshift")]
Redshift,
#[cfg(feature = "lenient")]
Lenient,
}
impl BuiltinDialect {
pub const ALL: &'static [BuiltinDialect] = &[
BuiltinDialect::Ansi,
#[cfg(feature = "postgres")]
BuiltinDialect::Postgres,
#[cfg(feature = "quiltdb")]
BuiltinDialect::QuiltDb,
#[cfg(feature = "mysql")]
BuiltinDialect::MySql,
#[cfg(feature = "sqlite")]
BuiltinDialect::Sqlite,
#[cfg(feature = "duckdb")]
BuiltinDialect::DuckDb,
#[cfg(feature = "bigquery")]
BuiltinDialect::BigQuery,
#[cfg(feature = "hive")]
BuiltinDialect::Hive,
#[cfg(feature = "clickhouse")]
BuiltinDialect::ClickHouse,
#[cfg(feature = "databricks")]
BuiltinDialect::Databricks,
#[cfg(feature = "mssql")]
BuiltinDialect::Mssql,
#[cfg(feature = "snowflake")]
BuiltinDialect::Snowflake,
#[cfg(feature = "redshift")]
BuiltinDialect::Redshift,
#[cfg(feature = "lenient")]
BuiltinDialect::Lenient,
];
pub fn from_name(name: &str) -> Option<Self> {
if name.eq_ignore_ascii_case("ansi") || name.eq_ignore_ascii_case("generic") {
return Some(Self::Ansi);
}
#[cfg(feature = "postgres")]
if name.eq_ignore_ascii_case("postgres")
|| name.eq_ignore_ascii_case("postgresql")
|| name.eq_ignore_ascii_case("pg")
{
return Some(Self::Postgres);
}
#[cfg(feature = "quiltdb")]
if name.eq_ignore_ascii_case("quiltdb") || name.eq_ignore_ascii_case("quilt") {
return Some(Self::QuiltDb);
}
#[cfg(feature = "mysql")]
if name.eq_ignore_ascii_case("mysql") || name.eq_ignore_ascii_case("mariadb") {
return Some(Self::MySql);
}
#[cfg(feature = "sqlite")]
if name.eq_ignore_ascii_case("sqlite") || name.eq_ignore_ascii_case("sqlite3") {
return Some(Self::Sqlite);
}
#[cfg(feature = "duckdb")]
if name.eq_ignore_ascii_case("duckdb") || name.eq_ignore_ascii_case("duck") {
return Some(Self::DuckDb);
}
#[cfg(feature = "bigquery")]
if name.eq_ignore_ascii_case("bigquery")
|| name.eq_ignore_ascii_case("bq")
|| name.eq_ignore_ascii_case("zetasql")
{
return Some(Self::BigQuery);
}
#[cfg(feature = "hive")]
if name.eq_ignore_ascii_case("hive") || name.eq_ignore_ascii_case("hiveql") {
return Some(Self::Hive);
}
#[cfg(feature = "clickhouse")]
if name.eq_ignore_ascii_case("clickhouse") || name.eq_ignore_ascii_case("ch") {
return Some(Self::ClickHouse);
}
#[cfg(feature = "databricks")]
if name.eq_ignore_ascii_case("databricks") || name.eq_ignore_ascii_case("dbx") {
return Some(Self::Databricks);
}
#[cfg(feature = "mssql")]
if name.eq_ignore_ascii_case("mssql")
|| name.eq_ignore_ascii_case("tsql")
|| name.eq_ignore_ascii_case("sqlserver")
{
return Some(Self::Mssql);
}
#[cfg(feature = "snowflake")]
if name.eq_ignore_ascii_case("snowflake") || name.eq_ignore_ascii_case("sf") {
return Some(Self::Snowflake);
}
#[cfg(feature = "redshift")]
if name.eq_ignore_ascii_case("redshift") || name.eq_ignore_ascii_case("amazonredshift") {
return Some(Self::Redshift);
}
#[cfg(feature = "lenient")]
if name.eq_ignore_ascii_case("lenient") || name.eq_ignore_ascii_case("permissive") {
return Some(Self::Lenient);
}
None
}
pub const fn name(self) -> &'static str {
match self {
Self::Ansi => "ansi",
#[cfg(feature = "postgres")]
Self::Postgres => "postgres",
#[cfg(feature = "quiltdb")]
Self::QuiltDb => "quiltdb",
#[cfg(feature = "mysql")]
Self::MySql => "mysql",
#[cfg(feature = "sqlite")]
Self::Sqlite => "sqlite",
#[cfg(feature = "duckdb")]
Self::DuckDb => "duckdb",
#[cfg(feature = "bigquery")]
Self::BigQuery => "bigquery",
#[cfg(feature = "hive")]
Self::Hive => "hive",
#[cfg(feature = "clickhouse")]
Self::ClickHouse => "clickhouse",
#[cfg(feature = "databricks")]
Self::Databricks => "databricks",
#[cfg(feature = "mssql")]
Self::Mssql => "mssql",
#[cfg(feature = "snowflake")]
Self::Snowflake => "snowflake",
#[cfg(feature = "redshift")]
Self::Redshift => "redshift",
#[cfg(feature = "lenient")]
Self::Lenient => "lenient",
}
}
pub const fn aliases(self) -> &'static [&'static str] {
match self {
Self::Ansi => &["ansi", "generic"],
#[cfg(feature = "postgres")]
Self::Postgres => &["postgres", "postgresql", "pg"],
#[cfg(feature = "quiltdb")]
Self::QuiltDb => &["quiltdb", "quilt"],
#[cfg(feature = "mysql")]
Self::MySql => &["mysql", "mariadb"],
#[cfg(feature = "sqlite")]
Self::Sqlite => &["sqlite", "sqlite3"],
#[cfg(feature = "duckdb")]
Self::DuckDb => &["duckdb", "duck"],
#[cfg(feature = "bigquery")]
Self::BigQuery => &["bigquery", "bq", "zetasql"],
#[cfg(feature = "hive")]
Self::Hive => &["hive", "hiveql"],
#[cfg(feature = "clickhouse")]
Self::ClickHouse => &["clickhouse", "ch"],
#[cfg(feature = "databricks")]
Self::Databricks => &["databricks", "dbx"],
#[cfg(feature = "mssql")]
Self::Mssql => &["mssql", "tsql", "sqlserver"],
#[cfg(feature = "snowflake")]
Self::Snowflake => &["snowflake", "sf"],
#[cfg(feature = "redshift")]
Self::Redshift => &["redshift", "amazonredshift"],
#[cfg(feature = "lenient")]
Self::Lenient => &["lenient", "permissive"],
}
}
pub fn features(self) -> &'static FeatureSet {
match self {
Self::Ansi => &FeatureSet::ANSI,
#[cfg(feature = "postgres")]
Self::Postgres => &FeatureSet::POSTGRES,
#[cfg(feature = "quiltdb")]
Self::QuiltDb => &FeatureSet::QUILTDB,
#[cfg(feature = "mysql")]
Self::MySql => &FeatureSet::MYSQL,
#[cfg(feature = "sqlite")]
Self::Sqlite => &FeatureSet::SQLITE,
#[cfg(feature = "duckdb")]
Self::DuckDb => &FeatureSet::DUCKDB,
#[cfg(feature = "bigquery")]
Self::BigQuery => &FeatureSet::BIGQUERY,
#[cfg(feature = "hive")]
Self::Hive => &FeatureSet::HIVE,
#[cfg(feature = "clickhouse")]
Self::ClickHouse => &FeatureSet::CLICKHOUSE,
#[cfg(feature = "databricks")]
Self::Databricks => &FeatureSet::DATABRICKS,
#[cfg(feature = "mssql")]
Self::Mssql => &FeatureSet::MSSQL,
#[cfg(feature = "snowflake")]
Self::Snowflake => &FeatureSet::SNOWFLAKE,
#[cfg(feature = "redshift")]
Self::Redshift => &FeatureSet::REDSHIFT,
#[cfg(feature = "lenient")]
Self::Lenient => &FeatureSet::LENIENT,
}
}
}
impl fmt::Display for BuiltinDialect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
impl FromStr for BuiltinDialect {
type Err = ParseBuiltinDialectError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_name(s).ok_or_else(|| ParseBuiltinDialectError { name: s.into() })
}
}
impl Default for BuiltinDialect {
fn default() -> Self {
Self::Ansi
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseBuiltinDialectError {
name: Box<str>,
}
impl ParseBuiltinDialectError {
pub fn name(&self) -> &str {
&self.name
}
}
impl fmt::Display for ParseBuiltinDialectError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"unknown built-in dialect {:?}: not a recognized name or alias, or its dialect \
is not compiled into this build",
self.name,
)
}
}
impl std::error::Error for ParseBuiltinDialectError {}
pub fn parse_builtin(src: &str, dialect: BuiltinDialect) -> ParseResult<Parsed> {
parse_builtin_with(src, ParseConfig::new(dialect))
}
pub fn parse_builtin_with(src: &str, config: ParseConfig<BuiltinDialect>) -> ParseResult<Parsed> {
let dialect = config.dialect;
match dialect {
BuiltinDialect::Ansi => parse_with(src, config.dialect(Ansi)),
#[cfg(feature = "postgres")]
BuiltinDialect::Postgres => parse_with(src, config.dialect(Postgres)),
#[cfg(feature = "quiltdb")]
BuiltinDialect::QuiltDb => parse_with(src, config.dialect(QuiltDb)),
#[cfg(feature = "mysql")]
BuiltinDialect::MySql => parse_with(src, config.dialect(MySql)),
#[cfg(feature = "sqlite")]
BuiltinDialect::Sqlite => parse_with(src, config.dialect(Sqlite)),
#[cfg(feature = "duckdb")]
BuiltinDialect::DuckDb => parse_with(src, config.dialect(DuckDb)),
#[cfg(feature = "bigquery")]
BuiltinDialect::BigQuery => parse_with(src, config.dialect(BigQuery)),
#[cfg(feature = "hive")]
BuiltinDialect::Hive => parse_with(src, config.dialect(Hive)),
#[cfg(feature = "clickhouse")]
BuiltinDialect::ClickHouse => parse_with(src, config.dialect(ClickHouse)),
#[cfg(feature = "databricks")]
BuiltinDialect::Databricks => parse_with(src, config.dialect(Databricks)),
#[cfg(feature = "mssql")]
BuiltinDialect::Mssql => parse_with(src, config.dialect(Mssql)),
#[cfg(feature = "snowflake")]
BuiltinDialect::Snowflake => parse_with(src, config.dialect(Snowflake)),
#[cfg(feature = "redshift")]
BuiltinDialect::Redshift => parse_with(src, config.dialect(Redshift)),
#[cfg(feature = "lenient")]
BuiltinDialect::Lenient => parse_with(src, config.dialect(Lenient)),
}
}
pub fn parse_recovering_builtin(src: &str, dialect: BuiltinDialect) -> ParseResult<Recovered> {
parse_recovering_builtin_with(src, ParseConfig::new(dialect))
}
pub fn parse_recovering_builtin_with(
src: &str,
config: ParseConfig<BuiltinDialect>,
) -> ParseResult<Recovered> {
let dialect = config.dialect;
match dialect {
BuiltinDialect::Ansi => parse_recovering_with(src, config.dialect(Ansi)),
#[cfg(feature = "postgres")]
BuiltinDialect::Postgres => parse_recovering_with(src, config.dialect(Postgres)),
#[cfg(feature = "quiltdb")]
BuiltinDialect::QuiltDb => parse_recovering_with(src, config.dialect(QuiltDb)),
#[cfg(feature = "mysql")]
BuiltinDialect::MySql => parse_recovering_with(src, config.dialect(MySql)),
#[cfg(feature = "sqlite")]
BuiltinDialect::Sqlite => parse_recovering_with(src, config.dialect(Sqlite)),
#[cfg(feature = "duckdb")]
BuiltinDialect::DuckDb => parse_recovering_with(src, config.dialect(DuckDb)),
#[cfg(feature = "bigquery")]
BuiltinDialect::BigQuery => parse_recovering_with(src, config.dialect(BigQuery)),
#[cfg(feature = "hive")]
BuiltinDialect::Hive => parse_recovering_with(src, config.dialect(Hive)),
#[cfg(feature = "clickhouse")]
BuiltinDialect::ClickHouse => parse_recovering_with(src, config.dialect(ClickHouse)),
#[cfg(feature = "databricks")]
BuiltinDialect::Databricks => parse_recovering_with(src, config.dialect(Databricks)),
#[cfg(feature = "mssql")]
BuiltinDialect::Mssql => parse_recovering_with(src, config.dialect(Mssql)),
#[cfg(feature = "snowflake")]
BuiltinDialect::Snowflake => parse_recovering_with(src, config.dialect(Snowflake)),
#[cfg(feature = "redshift")]
BuiltinDialect::Redshift => parse_recovering_with(src, config.dialect(Redshift)),
#[cfg(feature = "lenient")]
BuiltinDialect::Lenient => parse_recovering_with(src, config.dialect(Lenient)),
}
}
pub fn tokenize_with_builtin(src: &str, dialect: BuiltinDialect) -> Result<Vec<Token>, LexError> {
tokenize_with(src, dialect.features())
}
pub fn tokenize_with_builtin_trivia(
src: &str,
dialect: BuiltinDialect,
) -> Result<(Vec<Token>, TriviaIndex), LexError> {
tokenize_with_trivia(src, dialect.features())
}
impl RenderDialect for BuiltinDialect {
fn render_features(&self) -> FeatureSet {
self.features().clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ansi_is_always_built_in_and_round_trips_its_name() {
let ansi = BuiltinDialect::from_name("ansi").expect("ansi resolves");
assert_eq!(ansi, BuiltinDialect::Ansi);
assert_eq!(
BuiltinDialect::from_name("ANSI"),
Some(BuiltinDialect::Ansi)
);
assert_eq!(
BuiltinDialect::from_name("Generic"),
Some(BuiltinDialect::Ansi)
);
for dialect in BuiltinDialect::ALL {
assert_eq!(BuiltinDialect::from_name(dialect.name()), Some(*dialect));
}
assert_eq!(BuiltinDialect::Ansi.features(), &FeatureSet::ANSI);
}
#[test]
fn unknown_name_is_a_clean_none() {
for name in ["", "oracle", "postgre", "my sql"] {
assert_eq!(BuiltinDialect::from_name(name), None, "{name:?}");
}
}
#[test]
fn display_and_fromstr_round_trip_over_all_including_aliases_and_case() {
for &dialect in BuiltinDialect::ALL {
assert_eq!(dialect.to_string(), dialect.name());
assert_eq!(dialect.name().parse::<BuiltinDialect>(), Ok(dialect));
assert_eq!(dialect.to_string().parse::<BuiltinDialect>(), Ok(dialect));
for alias in dialect.aliases() {
assert_eq!(alias.parse::<BuiltinDialect>(), Ok(dialect), "{alias:?}");
assert_eq!(
alias.to_uppercase().parse::<BuiltinDialect>(),
Ok(dialect),
"{alias:?} upper",
);
}
}
assert_eq!(BuiltinDialect::default(), BuiltinDialect::Ansi);
}
#[test]
fn fromstr_error_carries_the_name_and_is_a_std_error() {
let err = "no-such-dialect".parse::<BuiltinDialect>().unwrap_err();
assert_eq!(err.name(), "no-such-dialect");
let as_error: &dyn std::error::Error = &err;
assert!(as_error.to_string().contains("no-such-dialect"));
}
#[test]
fn parse_builtin_parses_under_ansi() {
let parsed = parse_builtin("SELECT 1", BuiltinDialect::Ansi).expect("parses");
assert_eq!(parsed.statements().len(), 1);
}
#[cfg(feature = "postgres")]
#[test]
fn postgres_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("postgresql"),
Some(BuiltinDialect::Postgres)
);
assert_eq!(
BuiltinDialect::from_name("PG"),
Some(BuiltinDialect::Postgres)
);
assert_eq!(BuiltinDialect::Postgres.features(), &FeatureSet::POSTGRES);
assert!(parse_builtin("SELECT $1", BuiltinDialect::Postgres).is_ok());
assert!(parse_builtin("SELECT $1", BuiltinDialect::Ansi).is_err());
}
#[cfg(feature = "mysql")]
#[test]
fn mysql_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("MySQL"),
Some(BuiltinDialect::MySql)
);
assert_eq!(BuiltinDialect::MySql.features(), &FeatureSet::MYSQL);
assert!(parse_builtin("SELECT a FROM t LIMIT 5, 10", BuiltinDialect::MySql).is_ok());
assert!(parse_builtin("SELECT a FROM t LIMIT 5, 10", BuiltinDialect::Ansi).is_err());
}
#[cfg(feature = "sqlite")]
#[test]
fn sqlite_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("SQLite"),
Some(BuiltinDialect::Sqlite)
);
assert_eq!(
BuiltinDialect::from_name("sqlite3"),
Some(BuiltinDialect::Sqlite)
);
assert_eq!(BuiltinDialect::Sqlite.features(), &FeatureSet::SQLITE);
assert!(parse_builtin("SELECT 1 == 1", BuiltinDialect::Sqlite).is_ok());
assert!(parse_builtin("SELECT 1 == 1", BuiltinDialect::Ansi).is_err());
assert!(parse_builtin("SELECT $value", BuiltinDialect::Sqlite).is_ok());
}
#[cfg(feature = "duckdb")]
#[test]
fn duckdb_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("DuckDB"),
Some(BuiltinDialect::DuckDb)
);
assert_eq!(
BuiltinDialect::from_name("duck"),
Some(BuiltinDialect::DuckDb)
);
assert_eq!(BuiltinDialect::DuckDb.features(), &FeatureSet::DUCKDB);
assert!(parse_builtin("SELECT 0xFF + 1", BuiltinDialect::DuckDb).is_ok());
assert!(parse_builtin("SELECT 0xFF + 1", BuiltinDialect::Ansi).is_err());
assert!(parse_builtin("SELECT", BuiltinDialect::DuckDb).is_err());
}
#[cfg(feature = "bigquery")]
#[test]
fn bigquery_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("BigQuery"),
Some(BuiltinDialect::BigQuery)
);
assert_eq!(
BuiltinDialect::from_name("bq"),
Some(BuiltinDialect::BigQuery)
);
assert_eq!(
BuiltinDialect::from_name("ZetaSQL"),
Some(BuiltinDialect::BigQuery)
);
assert_eq!(BuiltinDialect::BigQuery.features(), &FeatureSet::BIGQUERY);
assert!(
parse_builtin(
"SELECT * FROM UNNEST(arr) WITH OFFSET AS pos",
BuiltinDialect::BigQuery
)
.is_ok()
);
assert!(
parse_builtin(
"SELECT * FROM UNNEST(arr) WITH OFFSET AS pos",
BuiltinDialect::Ansi
)
.is_err()
);
}
#[cfg(feature = "hive")]
#[test]
fn hive_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("Hive"),
Some(BuiltinDialect::Hive)
);
assert_eq!(
BuiltinDialect::from_name("HiveQL"),
Some(BuiltinDialect::Hive)
);
assert_eq!(BuiltinDialect::Hive.features(), &FeatureSet::HIVE);
assert!(
parse_builtin(
"SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
BuiltinDialect::Hive
)
.is_ok()
);
assert!(
parse_builtin(
"SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
BuiltinDialect::Ansi
)
.is_err()
);
}
#[cfg(feature = "clickhouse")]
#[test]
fn clickhouse_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("ClickHouse"),
Some(BuiltinDialect::ClickHouse)
);
assert_eq!(
BuiltinDialect::from_name("ch"),
Some(BuiltinDialect::ClickHouse)
);
assert_eq!(
BuiltinDialect::ClickHouse.features(),
&FeatureSet::CLICKHOUSE
);
assert!(
parse_builtin(
"SELECT a FROM t SETTINGS max_threads = 8",
BuiltinDialect::ClickHouse
)
.is_ok()
);
assert!(
parse_builtin(
"SELECT a FROM t SETTINGS max_threads = 8",
BuiltinDialect::Ansi
)
.is_err()
);
}
#[cfg(feature = "snowflake")]
#[test]
fn snowflake_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("Snowflake"),
Some(BuiltinDialect::Snowflake)
);
assert_eq!(
BuiltinDialect::from_name("sf"),
Some(BuiltinDialect::Snowflake)
);
assert_eq!(BuiltinDialect::Snowflake.features(), &FeatureSet::SNOWFLAKE);
assert!(parse_builtin("SELECT src:customer[0].name", BuiltinDialect::Snowflake).is_ok());
assert!(parse_builtin("SELECT src:customer[0].name", BuiltinDialect::Ansi).is_err());
}
#[cfg(feature = "redshift")]
#[test]
fn redshift_builtin_resolves_and_defers_its_pg_heritage_surface() {
assert_eq!(
BuiltinDialect::from_name("Redshift"),
Some(BuiltinDialect::Redshift)
);
assert_eq!(
BuiltinDialect::from_name("AmazonRedshift"),
Some(BuiltinDialect::Redshift)
);
assert_eq!(BuiltinDialect::from_name("rs"), None);
assert_eq!(BuiltinDialect::Redshift.features(), &FeatureSet::REDSHIFT);
assert!(parse_builtin("SELECT \"Col\" FROM t", BuiltinDialect::Redshift).is_ok());
assert!(
parse_builtin(
"SELECT * FROM t WHERE name ILIKE 'a%'",
BuiltinDialect::Redshift
)
.is_err()
);
}
#[cfg(feature = "databricks")]
#[test]
fn databricks_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("Databricks"),
Some(BuiltinDialect::Databricks)
);
assert_eq!(
BuiltinDialect::from_name("dbx"),
Some(BuiltinDialect::Databricks)
);
assert_eq!(
BuiltinDialect::Databricks.features(),
&FeatureSet::DATABRICKS
);
assert!(
parse_builtin(
"SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
BuiltinDialect::Databricks
)
.is_ok()
);
assert!(
parse_builtin(
"SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
BuiltinDialect::Ansi
)
.is_err()
);
}
#[cfg(feature = "mssql")]
#[test]
fn mssql_builtin_resolves_and_parses_its_surface() {
assert_eq!(
BuiltinDialect::from_name("MSSQL"),
Some(BuiltinDialect::Mssql)
);
assert_eq!(
BuiltinDialect::from_name("tsql"),
Some(BuiltinDialect::Mssql)
);
assert_eq!(
BuiltinDialect::from_name("SqlServer"),
Some(BuiltinDialect::Mssql)
);
assert_eq!(BuiltinDialect::Mssql.features(), &FeatureSet::MSSQL);
assert!(
parse_builtin(
"SELECT * FROM a CROSS APPLY (SELECT 1) AS t",
BuiltinDialect::Mssql
)
.is_ok()
);
assert!(
parse_builtin(
"SELECT * FROM a CROSS APPLY (SELECT 1) AS t",
BuiltinDialect::Ansi
)
.is_err()
);
}
#[cfg(feature = "lenient")]
#[test]
fn lenient_builtin_resolves_and_parses_its_union() {
assert_eq!(
BuiltinDialect::from_name("Lenient"),
Some(BuiltinDialect::Lenient)
);
assert_eq!(
BuiltinDialect::from_name("permissive"),
Some(BuiltinDialect::Lenient)
);
assert_eq!(BuiltinDialect::Lenient.features(), &FeatureSet::LENIENT);
assert!(parse_builtin(r#"SELECT "a", `b`, [c] FROM t"#, BuiltinDialect::Lenient).is_ok());
assert!(parse_builtin("SELECT `b` FROM t", BuiltinDialect::Ansi).is_err());
}
}