1use std::fmt;
16use std::str::FromStr;
17
18use crate::ast::dialect::FeatureSet;
19use crate::dialect::Ansi;
20#[cfg(feature = "bigquery")]
21use crate::dialect::BigQuery;
22#[cfg(feature = "clickhouse")]
23use crate::dialect::ClickHouse;
24#[cfg(feature = "databricks")]
25use crate::dialect::Databricks;
26#[cfg(feature = "duckdb")]
27use crate::dialect::DuckDb;
28#[cfg(feature = "hive")]
29use crate::dialect::Hive;
30#[cfg(feature = "lenient")]
31use crate::dialect::Lenient;
32#[cfg(feature = "mssql")]
33use crate::dialect::Mssql;
34#[cfg(feature = "mysql")]
35use crate::dialect::MySql;
36#[cfg(feature = "postgres")]
37use crate::dialect::Postgres;
38#[cfg(feature = "quiltdb")]
39use crate::dialect::QuiltDb;
40#[cfg(feature = "redshift")]
41use crate::dialect::Redshift;
42#[cfg(feature = "snowflake")]
43use crate::dialect::Snowflake;
44#[cfg(feature = "sqlite")]
45use crate::dialect::Sqlite;
46use crate::error::ParseResult;
47use crate::parser::{ParseConfig, Parsed, Recovered, parse_recovering_with, parse_with};
48use crate::render::RenderDialect;
49use crate::tokenizer::{LexError, Token, TriviaIndex, tokenize_with, tokenize_with_trivia};
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
77#[non_exhaustive]
78pub enum BuiltinDialect {
79 Ansi,
81 #[cfg(feature = "postgres")]
83 Postgres,
84 #[cfg(feature = "quiltdb")]
86 QuiltDb,
87 #[cfg(feature = "mysql")]
89 MySql,
90 #[cfg(feature = "sqlite")]
92 Sqlite,
93 #[cfg(feature = "duckdb")]
95 DuckDb,
96 #[cfg(feature = "bigquery")]
98 BigQuery,
99 #[cfg(feature = "hive")]
101 Hive,
102 #[cfg(feature = "clickhouse")]
104 ClickHouse,
105 #[cfg(feature = "databricks")]
107 Databricks,
108 #[cfg(feature = "mssql")]
110 Mssql,
111 #[cfg(feature = "snowflake")]
113 Snowflake,
114 #[cfg(feature = "redshift")]
116 Redshift,
117 #[cfg(feature = "lenient")]
120 Lenient,
121}
122
123impl BuiltinDialect {
124 pub const ALL: &'static [BuiltinDialect] = &[
130 BuiltinDialect::Ansi,
131 #[cfg(feature = "postgres")]
132 BuiltinDialect::Postgres,
133 #[cfg(feature = "quiltdb")]
134 BuiltinDialect::QuiltDb,
135 #[cfg(feature = "mysql")]
136 BuiltinDialect::MySql,
137 #[cfg(feature = "sqlite")]
138 BuiltinDialect::Sqlite,
139 #[cfg(feature = "duckdb")]
140 BuiltinDialect::DuckDb,
141 #[cfg(feature = "bigquery")]
142 BuiltinDialect::BigQuery,
143 #[cfg(feature = "hive")]
144 BuiltinDialect::Hive,
145 #[cfg(feature = "clickhouse")]
146 BuiltinDialect::ClickHouse,
147 #[cfg(feature = "databricks")]
148 BuiltinDialect::Databricks,
149 #[cfg(feature = "mssql")]
150 BuiltinDialect::Mssql,
151 #[cfg(feature = "snowflake")]
152 BuiltinDialect::Snowflake,
153 #[cfg(feature = "redshift")]
154 BuiltinDialect::Redshift,
155 #[cfg(feature = "lenient")]
156 BuiltinDialect::Lenient,
157 ];
158
159 pub fn from_name(name: &str) -> Option<Self> {
176 if name.eq_ignore_ascii_case("ansi") || name.eq_ignore_ascii_case("generic") {
177 return Some(Self::Ansi);
178 }
179 #[cfg(feature = "postgres")]
180 if name.eq_ignore_ascii_case("postgres")
181 || name.eq_ignore_ascii_case("postgresql")
182 || name.eq_ignore_ascii_case("pg")
183 {
184 return Some(Self::Postgres);
185 }
186 #[cfg(feature = "quiltdb")]
187 if name.eq_ignore_ascii_case("quiltdb") || name.eq_ignore_ascii_case("quilt") {
188 return Some(Self::QuiltDb);
189 }
190 #[cfg(feature = "mysql")]
191 if name.eq_ignore_ascii_case("mysql") || name.eq_ignore_ascii_case("mariadb") {
192 return Some(Self::MySql);
193 }
194 #[cfg(feature = "sqlite")]
195 if name.eq_ignore_ascii_case("sqlite") || name.eq_ignore_ascii_case("sqlite3") {
196 return Some(Self::Sqlite);
197 }
198 #[cfg(feature = "duckdb")]
199 if name.eq_ignore_ascii_case("duckdb") || name.eq_ignore_ascii_case("duck") {
200 return Some(Self::DuckDb);
201 }
202 #[cfg(feature = "bigquery")]
203 if name.eq_ignore_ascii_case("bigquery")
204 || name.eq_ignore_ascii_case("bq")
205 || name.eq_ignore_ascii_case("zetasql")
206 {
207 return Some(Self::BigQuery);
208 }
209 #[cfg(feature = "hive")]
210 if name.eq_ignore_ascii_case("hive") || name.eq_ignore_ascii_case("hiveql") {
211 return Some(Self::Hive);
212 }
213 #[cfg(feature = "clickhouse")]
214 if name.eq_ignore_ascii_case("clickhouse") || name.eq_ignore_ascii_case("ch") {
215 return Some(Self::ClickHouse);
216 }
217 #[cfg(feature = "databricks")]
218 if name.eq_ignore_ascii_case("databricks") || name.eq_ignore_ascii_case("dbx") {
219 return Some(Self::Databricks);
220 }
221 #[cfg(feature = "mssql")]
222 if name.eq_ignore_ascii_case("mssql")
223 || name.eq_ignore_ascii_case("tsql")
224 || name.eq_ignore_ascii_case("sqlserver")
225 {
226 return Some(Self::Mssql);
227 }
228 #[cfg(feature = "snowflake")]
229 if name.eq_ignore_ascii_case("snowflake") || name.eq_ignore_ascii_case("sf") {
230 return Some(Self::Snowflake);
231 }
232 #[cfg(feature = "redshift")]
236 if name.eq_ignore_ascii_case("redshift") || name.eq_ignore_ascii_case("amazonredshift") {
237 return Some(Self::Redshift);
238 }
239 #[cfg(feature = "lenient")]
240 if name.eq_ignore_ascii_case("lenient") || name.eq_ignore_ascii_case("permissive") {
241 return Some(Self::Lenient);
242 }
243 None
244 }
245
246 pub const fn name(self) -> &'static str {
249 match self {
250 Self::Ansi => "ansi",
251 #[cfg(feature = "postgres")]
252 Self::Postgres => "postgres",
253 #[cfg(feature = "quiltdb")]
254 Self::QuiltDb => "quiltdb",
255 #[cfg(feature = "mysql")]
256 Self::MySql => "mysql",
257 #[cfg(feature = "sqlite")]
258 Self::Sqlite => "sqlite",
259 #[cfg(feature = "duckdb")]
260 Self::DuckDb => "duckdb",
261 #[cfg(feature = "bigquery")]
262 Self::BigQuery => "bigquery",
263 #[cfg(feature = "hive")]
264 Self::Hive => "hive",
265 #[cfg(feature = "clickhouse")]
266 Self::ClickHouse => "clickhouse",
267 #[cfg(feature = "databricks")]
268 Self::Databricks => "databricks",
269 #[cfg(feature = "mssql")]
270 Self::Mssql => "mssql",
271 #[cfg(feature = "snowflake")]
272 Self::Snowflake => "snowflake",
273 #[cfg(feature = "redshift")]
274 Self::Redshift => "redshift",
275 #[cfg(feature = "lenient")]
276 Self::Lenient => "lenient",
277 }
278 }
279
280 pub const fn aliases(self) -> &'static [&'static str] {
283 match self {
284 Self::Ansi => &["ansi", "generic"],
285 #[cfg(feature = "postgres")]
286 Self::Postgres => &["postgres", "postgresql", "pg"],
287 #[cfg(feature = "quiltdb")]
288 Self::QuiltDb => &["quiltdb", "quilt"],
289 #[cfg(feature = "mysql")]
290 Self::MySql => &["mysql", "mariadb"],
291 #[cfg(feature = "sqlite")]
292 Self::Sqlite => &["sqlite", "sqlite3"],
293 #[cfg(feature = "duckdb")]
294 Self::DuckDb => &["duckdb", "duck"],
295 #[cfg(feature = "bigquery")]
296 Self::BigQuery => &["bigquery", "bq", "zetasql"],
297 #[cfg(feature = "hive")]
298 Self::Hive => &["hive", "hiveql"],
299 #[cfg(feature = "clickhouse")]
300 Self::ClickHouse => &["clickhouse", "ch"],
301 #[cfg(feature = "databricks")]
302 Self::Databricks => &["databricks", "dbx"],
303 #[cfg(feature = "mssql")]
304 Self::Mssql => &["mssql", "tsql", "sqlserver"],
305 #[cfg(feature = "snowflake")]
306 Self::Snowflake => &["snowflake", "sf"],
307 #[cfg(feature = "redshift")]
308 Self::Redshift => &["redshift", "amazonredshift"],
309 #[cfg(feature = "lenient")]
310 Self::Lenient => &["lenient", "permissive"],
311 }
312 }
313
314 pub fn features(self) -> &'static FeatureSet {
318 match self {
319 Self::Ansi => &FeatureSet::ANSI,
320 #[cfg(feature = "postgres")]
321 Self::Postgres => &FeatureSet::POSTGRES,
322 #[cfg(feature = "quiltdb")]
323 Self::QuiltDb => &FeatureSet::QUILTDB,
324 #[cfg(feature = "mysql")]
325 Self::MySql => &FeatureSet::MYSQL,
326 #[cfg(feature = "sqlite")]
327 Self::Sqlite => &FeatureSet::SQLITE,
328 #[cfg(feature = "duckdb")]
329 Self::DuckDb => &FeatureSet::DUCKDB,
330 #[cfg(feature = "bigquery")]
331 Self::BigQuery => &FeatureSet::BIGQUERY,
332 #[cfg(feature = "hive")]
333 Self::Hive => &FeatureSet::HIVE,
334 #[cfg(feature = "clickhouse")]
335 Self::ClickHouse => &FeatureSet::CLICKHOUSE,
336 #[cfg(feature = "databricks")]
337 Self::Databricks => &FeatureSet::DATABRICKS,
338 #[cfg(feature = "mssql")]
339 Self::Mssql => &FeatureSet::MSSQL,
340 #[cfg(feature = "snowflake")]
341 Self::Snowflake => &FeatureSet::SNOWFLAKE,
342 #[cfg(feature = "redshift")]
343 Self::Redshift => &FeatureSet::REDSHIFT,
344 #[cfg(feature = "lenient")]
345 Self::Lenient => &FeatureSet::LENIENT,
346 }
347 }
348}
349
350impl fmt::Display for BuiltinDialect {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 f.write_str(self.name())
361 }
362}
363
364impl FromStr for BuiltinDialect {
365 type Err = ParseBuiltinDialectError;
366
367 fn from_str(s: &str) -> Result<Self, Self::Err> {
371 Self::from_name(s).ok_or_else(|| ParseBuiltinDialectError { name: s.into() })
372 }
373}
374
375impl Default for BuiltinDialect {
376 fn default() -> Self {
379 Self::Ansi
380 }
381}
382
383#[derive(Clone, Debug, PartialEq, Eq)]
390pub struct ParseBuiltinDialectError {
391 name: Box<str>,
392}
393
394impl ParseBuiltinDialectError {
395 pub fn name(&self) -> &str {
397 &self.name
398 }
399}
400
401impl fmt::Display for ParseBuiltinDialectError {
402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 write!(
404 f,
405 "unknown built-in dialect {:?}: not a recognized name or alias, or its dialect \
406 is not compiled into this build",
407 self.name,
408 )
409 }
410}
411
412impl std::error::Error for ParseBuiltinDialectError {}
413
414pub fn parse_builtin(src: &str, dialect: BuiltinDialect) -> ParseResult<Parsed> {
438 parse_builtin_with(src, ParseConfig::new(dialect))
439}
440
441pub fn parse_builtin_with(src: &str, config: ParseConfig<BuiltinDialect>) -> ParseResult<Parsed> {
448 let dialect = config.dialect;
449 match dialect {
450 BuiltinDialect::Ansi => parse_with(src, config.dialect(Ansi)),
451 #[cfg(feature = "postgres")]
452 BuiltinDialect::Postgres => parse_with(src, config.dialect(Postgres)),
453 #[cfg(feature = "quiltdb")]
454 BuiltinDialect::QuiltDb => parse_with(src, config.dialect(QuiltDb)),
455 #[cfg(feature = "mysql")]
456 BuiltinDialect::MySql => parse_with(src, config.dialect(MySql)),
457 #[cfg(feature = "sqlite")]
458 BuiltinDialect::Sqlite => parse_with(src, config.dialect(Sqlite)),
459 #[cfg(feature = "duckdb")]
460 BuiltinDialect::DuckDb => parse_with(src, config.dialect(DuckDb)),
461 #[cfg(feature = "bigquery")]
462 BuiltinDialect::BigQuery => parse_with(src, config.dialect(BigQuery)),
463 #[cfg(feature = "hive")]
464 BuiltinDialect::Hive => parse_with(src, config.dialect(Hive)),
465 #[cfg(feature = "clickhouse")]
466 BuiltinDialect::ClickHouse => parse_with(src, config.dialect(ClickHouse)),
467 #[cfg(feature = "databricks")]
468 BuiltinDialect::Databricks => parse_with(src, config.dialect(Databricks)),
469 #[cfg(feature = "mssql")]
470 BuiltinDialect::Mssql => parse_with(src, config.dialect(Mssql)),
471 #[cfg(feature = "snowflake")]
472 BuiltinDialect::Snowflake => parse_with(src, config.dialect(Snowflake)),
473 #[cfg(feature = "redshift")]
474 BuiltinDialect::Redshift => parse_with(src, config.dialect(Redshift)),
475 #[cfg(feature = "lenient")]
476 BuiltinDialect::Lenient => parse_with(src, config.dialect(Lenient)),
477 }
478}
479
480pub fn parse_recovering_builtin(src: &str, dialect: BuiltinDialect) -> ParseResult<Recovered> {
483 parse_recovering_builtin_with(src, ParseConfig::new(dialect))
484}
485
486pub fn parse_recovering_builtin_with(
488 src: &str,
489 config: ParseConfig<BuiltinDialect>,
490) -> ParseResult<Recovered> {
491 let dialect = config.dialect;
492 match dialect {
493 BuiltinDialect::Ansi => parse_recovering_with(src, config.dialect(Ansi)),
494 #[cfg(feature = "postgres")]
495 BuiltinDialect::Postgres => parse_recovering_with(src, config.dialect(Postgres)),
496 #[cfg(feature = "quiltdb")]
497 BuiltinDialect::QuiltDb => parse_recovering_with(src, config.dialect(QuiltDb)),
498 #[cfg(feature = "mysql")]
499 BuiltinDialect::MySql => parse_recovering_with(src, config.dialect(MySql)),
500 #[cfg(feature = "sqlite")]
501 BuiltinDialect::Sqlite => parse_recovering_with(src, config.dialect(Sqlite)),
502 #[cfg(feature = "duckdb")]
503 BuiltinDialect::DuckDb => parse_recovering_with(src, config.dialect(DuckDb)),
504 #[cfg(feature = "bigquery")]
505 BuiltinDialect::BigQuery => parse_recovering_with(src, config.dialect(BigQuery)),
506 #[cfg(feature = "hive")]
507 BuiltinDialect::Hive => parse_recovering_with(src, config.dialect(Hive)),
508 #[cfg(feature = "clickhouse")]
509 BuiltinDialect::ClickHouse => parse_recovering_with(src, config.dialect(ClickHouse)),
510 #[cfg(feature = "databricks")]
511 BuiltinDialect::Databricks => parse_recovering_with(src, config.dialect(Databricks)),
512 #[cfg(feature = "mssql")]
513 BuiltinDialect::Mssql => parse_recovering_with(src, config.dialect(Mssql)),
514 #[cfg(feature = "snowflake")]
515 BuiltinDialect::Snowflake => parse_recovering_with(src, config.dialect(Snowflake)),
516 #[cfg(feature = "redshift")]
517 BuiltinDialect::Redshift => parse_recovering_with(src, config.dialect(Redshift)),
518 #[cfg(feature = "lenient")]
519 BuiltinDialect::Lenient => parse_recovering_with(src, config.dialect(Lenient)),
520 }
521}
522
523pub fn tokenize_with_builtin(src: &str, dialect: BuiltinDialect) -> Result<Vec<Token>, LexError> {
525 tokenize_with(src, dialect.features())
526}
527
528pub fn tokenize_with_builtin_trivia(
530 src: &str,
531 dialect: BuiltinDialect,
532) -> Result<(Vec<Token>, TriviaIndex), LexError> {
533 tokenize_with_trivia(src, dialect.features())
534}
535
536impl RenderDialect for BuiltinDialect {
537 fn render_features(&self) -> FeatureSet {
538 self.features().clone()
539 }
540}
541
542#[cfg(test)]
543mod tests {
544 use super::*;
545
546 #[test]
547 fn ansi_is_always_built_in_and_round_trips_its_name() {
548 let ansi = BuiltinDialect::from_name("ansi").expect("ansi resolves");
549 assert_eq!(ansi, BuiltinDialect::Ansi);
550 assert_eq!(
552 BuiltinDialect::from_name("ANSI"),
553 Some(BuiltinDialect::Ansi)
554 );
555 assert_eq!(
556 BuiltinDialect::from_name("Generic"),
557 Some(BuiltinDialect::Ansi)
558 );
559 for dialect in BuiltinDialect::ALL {
561 assert_eq!(BuiltinDialect::from_name(dialect.name()), Some(*dialect));
562 }
563 assert_eq!(BuiltinDialect::Ansi.features(), &FeatureSet::ANSI);
564 }
565
566 #[test]
567 fn unknown_name_is_a_clean_none() {
568 for name in ["", "oracle", "postgre", "my sql"] {
576 assert_eq!(BuiltinDialect::from_name(name), None, "{name:?}");
577 }
578 }
579
580 #[test]
581 fn display_and_fromstr_round_trip_over_all_including_aliases_and_case() {
582 for &dialect in BuiltinDialect::ALL {
583 assert_eq!(dialect.to_string(), dialect.name());
586 assert_eq!(dialect.name().parse::<BuiltinDialect>(), Ok(dialect));
587 assert_eq!(dialect.to_string().parse::<BuiltinDialect>(), Ok(dialect));
588 for alias in dialect.aliases() {
590 assert_eq!(alias.parse::<BuiltinDialect>(), Ok(dialect), "{alias:?}");
591 assert_eq!(
592 alias.to_uppercase().parse::<BuiltinDialect>(),
593 Ok(dialect),
594 "{alias:?} upper",
595 );
596 }
597 }
598 assert_eq!(BuiltinDialect::default(), BuiltinDialect::Ansi);
599 }
600
601 #[test]
602 fn fromstr_error_carries_the_name_and_is_a_std_error() {
603 let err = "no-such-dialect".parse::<BuiltinDialect>().unwrap_err();
604 assert_eq!(err.name(), "no-such-dialect");
605 let as_error: &dyn std::error::Error = &err;
607 assert!(as_error.to_string().contains("no-such-dialect"));
608 }
609
610 #[test]
611 fn parse_builtin_parses_under_ansi() {
612 let parsed = parse_builtin("SELECT 1", BuiltinDialect::Ansi).expect("parses");
613 assert_eq!(parsed.statements().len(), 1);
614 }
615
616 #[cfg(feature = "postgres")]
617 #[test]
618 fn postgres_builtin_resolves_and_parses_its_surface() {
619 assert_eq!(
620 BuiltinDialect::from_name("postgresql"),
621 Some(BuiltinDialect::Postgres)
622 );
623 assert_eq!(
624 BuiltinDialect::from_name("PG"),
625 Some(BuiltinDialect::Postgres)
626 );
627 assert_eq!(BuiltinDialect::Postgres.features(), &FeatureSet::POSTGRES);
628 assert!(parse_builtin("SELECT $1", BuiltinDialect::Postgres).is_ok());
631 assert!(parse_builtin("SELECT $1", BuiltinDialect::Ansi).is_err());
632 }
633
634 #[cfg(feature = "mysql")]
635 #[test]
636 fn mysql_builtin_resolves_and_parses_its_surface() {
637 assert_eq!(
638 BuiltinDialect::from_name("MySQL"),
639 Some(BuiltinDialect::MySql)
640 );
641 assert_eq!(BuiltinDialect::MySql.features(), &FeatureSet::MYSQL);
642 assert!(parse_builtin("SELECT a FROM t LIMIT 5, 10", BuiltinDialect::MySql).is_ok());
645 assert!(parse_builtin("SELECT a FROM t LIMIT 5, 10", BuiltinDialect::Ansi).is_err());
646 }
647
648 #[cfg(feature = "sqlite")]
649 #[test]
650 fn sqlite_builtin_resolves_and_parses_its_surface() {
651 assert_eq!(
652 BuiltinDialect::from_name("SQLite"),
653 Some(BuiltinDialect::Sqlite)
654 );
655 assert_eq!(
656 BuiltinDialect::from_name("sqlite3"),
657 Some(BuiltinDialect::Sqlite)
658 );
659 assert_eq!(BuiltinDialect::Sqlite.features(), &FeatureSet::SQLITE);
660 assert!(parse_builtin("SELECT 1 == 1", BuiltinDialect::Sqlite).is_ok());
663 assert!(parse_builtin("SELECT 1 == 1", BuiltinDialect::Ansi).is_err());
664 assert!(parse_builtin("SELECT $value", BuiltinDialect::Sqlite).is_ok());
665 }
666
667 #[cfg(feature = "duckdb")]
668 #[test]
669 fn duckdb_builtin_resolves_and_parses_its_surface() {
670 assert_eq!(
671 BuiltinDialect::from_name("DuckDB"),
672 Some(BuiltinDialect::DuckDb)
673 );
674 assert_eq!(
675 BuiltinDialect::from_name("duck"),
676 Some(BuiltinDialect::DuckDb)
677 );
678 assert_eq!(BuiltinDialect::DuckDb.features(), &FeatureSet::DUCKDB);
679 assert!(parse_builtin("SELECT 0xFF + 1", BuiltinDialect::DuckDb).is_ok());
683 assert!(parse_builtin("SELECT 0xFF + 1", BuiltinDialect::Ansi).is_err());
684 assert!(parse_builtin("SELECT", BuiltinDialect::DuckDb).is_err());
687 }
688
689 #[cfg(feature = "bigquery")]
690 #[test]
691 fn bigquery_builtin_resolves_and_parses_its_surface() {
692 assert_eq!(
693 BuiltinDialect::from_name("BigQuery"),
694 Some(BuiltinDialect::BigQuery)
695 );
696 assert_eq!(
698 BuiltinDialect::from_name("bq"),
699 Some(BuiltinDialect::BigQuery)
700 );
701 assert_eq!(
702 BuiltinDialect::from_name("ZetaSQL"),
703 Some(BuiltinDialect::BigQuery)
704 );
705 assert_eq!(BuiltinDialect::BigQuery.features(), &FeatureSet::BIGQUERY);
706 assert!(
710 parse_builtin(
711 "SELECT * FROM UNNEST(arr) WITH OFFSET AS pos",
712 BuiltinDialect::BigQuery
713 )
714 .is_ok()
715 );
716 assert!(
717 parse_builtin(
718 "SELECT * FROM UNNEST(arr) WITH OFFSET AS pos",
719 BuiltinDialect::Ansi
720 )
721 .is_err()
722 );
723 }
724
725 #[cfg(feature = "hive")]
726 #[test]
727 fn hive_builtin_resolves_and_parses_its_surface() {
728 assert_eq!(
729 BuiltinDialect::from_name("Hive"),
730 Some(BuiltinDialect::Hive)
731 );
732 assert_eq!(
734 BuiltinDialect::from_name("HiveQL"),
735 Some(BuiltinDialect::Hive)
736 );
737 assert_eq!(BuiltinDialect::Hive.features(), &FeatureSet::HIVE);
738 assert!(
742 parse_builtin(
743 "SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
744 BuiltinDialect::Hive
745 )
746 .is_ok()
747 );
748 assert!(
749 parse_builtin(
750 "SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
751 BuiltinDialect::Ansi
752 )
753 .is_err()
754 );
755 }
756
757 #[cfg(feature = "clickhouse")]
758 #[test]
759 fn clickhouse_builtin_resolves_and_parses_its_surface() {
760 assert_eq!(
761 BuiltinDialect::from_name("ClickHouse"),
762 Some(BuiltinDialect::ClickHouse)
763 );
764 assert_eq!(
765 BuiltinDialect::from_name("ch"),
766 Some(BuiltinDialect::ClickHouse)
767 );
768 assert_eq!(
769 BuiltinDialect::ClickHouse.features(),
770 &FeatureSet::CLICKHOUSE
771 );
772 assert!(
776 parse_builtin(
777 "SELECT a FROM t SETTINGS max_threads = 8",
778 BuiltinDialect::ClickHouse
779 )
780 .is_ok()
781 );
782 assert!(
783 parse_builtin(
784 "SELECT a FROM t SETTINGS max_threads = 8",
785 BuiltinDialect::Ansi
786 )
787 .is_err()
788 );
789 }
790
791 #[cfg(feature = "snowflake")]
792 #[test]
793 fn snowflake_builtin_resolves_and_parses_its_surface() {
794 assert_eq!(
795 BuiltinDialect::from_name("Snowflake"),
796 Some(BuiltinDialect::Snowflake)
797 );
798 assert_eq!(
799 BuiltinDialect::from_name("sf"),
800 Some(BuiltinDialect::Snowflake)
801 );
802 assert_eq!(BuiltinDialect::Snowflake.features(), &FeatureSet::SNOWFLAKE);
803 assert!(parse_builtin("SELECT src:customer[0].name", BuiltinDialect::Snowflake).is_ok());
807 assert!(parse_builtin("SELECT src:customer[0].name", BuiltinDialect::Ansi).is_err());
808 }
809
810 #[cfg(feature = "redshift")]
811 #[test]
812 fn redshift_builtin_resolves_and_defers_its_pg_heritage_surface() {
813 assert_eq!(
814 BuiltinDialect::from_name("Redshift"),
815 Some(BuiltinDialect::Redshift)
816 );
817 assert_eq!(
819 BuiltinDialect::from_name("AmazonRedshift"),
820 Some(BuiltinDialect::Redshift)
821 );
822 assert_eq!(BuiltinDialect::from_name("rs"), None);
824 assert_eq!(BuiltinDialect::Redshift.features(), &FeatureSet::REDSHIFT);
825 assert!(parse_builtin("SELECT \"Col\" FROM t", BuiltinDialect::Redshift).is_ok());
828 assert!(
832 parse_builtin(
833 "SELECT * FROM t WHERE name ILIKE 'a%'",
834 BuiltinDialect::Redshift
835 )
836 .is_err()
837 );
838 }
839
840 #[cfg(feature = "databricks")]
841 #[test]
842 fn databricks_builtin_resolves_and_parses_its_surface() {
843 assert_eq!(
844 BuiltinDialect::from_name("Databricks"),
845 Some(BuiltinDialect::Databricks)
846 );
847 assert_eq!(
848 BuiltinDialect::from_name("dbx"),
849 Some(BuiltinDialect::Databricks)
850 );
851 assert_eq!(
852 BuiltinDialect::Databricks.features(),
853 &FeatureSet::DATABRICKS
854 );
855 assert!(
859 parse_builtin(
860 "SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
861 BuiltinDialect::Databricks
862 )
863 .is_ok()
864 );
865 assert!(
866 parse_builtin(
867 "SELECT * FROM a LEFT SEMI JOIN b ON a.x = b.x",
868 BuiltinDialect::Ansi
869 )
870 .is_err()
871 );
872 }
873
874 #[cfg(feature = "mssql")]
875 #[test]
876 fn mssql_builtin_resolves_and_parses_its_surface() {
877 assert_eq!(
878 BuiltinDialect::from_name("MSSQL"),
879 Some(BuiltinDialect::Mssql)
880 );
881 assert_eq!(
883 BuiltinDialect::from_name("tsql"),
884 Some(BuiltinDialect::Mssql)
885 );
886 assert_eq!(
887 BuiltinDialect::from_name("SqlServer"),
888 Some(BuiltinDialect::Mssql)
889 );
890 assert_eq!(BuiltinDialect::Mssql.features(), &FeatureSet::MSSQL);
891 assert!(
895 parse_builtin(
896 "SELECT * FROM a CROSS APPLY (SELECT 1) AS t",
897 BuiltinDialect::Mssql
898 )
899 .is_ok()
900 );
901 assert!(
902 parse_builtin(
903 "SELECT * FROM a CROSS APPLY (SELECT 1) AS t",
904 BuiltinDialect::Ansi
905 )
906 .is_err()
907 );
908 }
909
910 #[cfg(feature = "lenient")]
911 #[test]
912 fn lenient_builtin_resolves_and_parses_its_union() {
913 assert_eq!(
914 BuiltinDialect::from_name("Lenient"),
915 Some(BuiltinDialect::Lenient)
916 );
917 assert_eq!(
918 BuiltinDialect::from_name("permissive"),
919 Some(BuiltinDialect::Lenient)
920 );
921 assert_eq!(BuiltinDialect::Lenient.features(), &FeatureSet::LENIENT);
922 assert!(parse_builtin(r#"SELECT "a", `b`, [c] FROM t"#, BuiltinDialect::Lenient).is_ok());
926 assert!(parse_builtin("SELECT `b` FROM t", BuiltinDialect::Ansi).is_err());
927 }
928}