1use serde::{Deserialize, Serialize};
2
3use crate::ast::*;
4
5pub mod plugin;
6pub mod time;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub enum Dialect {
15 Ansi,
18
19 Athena,
22 BigQuery,
24 ClickHouse,
26 Databricks,
28 DuckDb,
30 Hive,
32 Mysql,
34 Oracle,
36 Postgres,
38 Presto,
40 Redshift,
42 Snowflake,
44 Spark,
46 Sqlite,
48 StarRocks,
50 Trino,
52 Tsql,
54
55 Doris,
58 Dremio,
60 Drill,
62 Druid,
64 Exasol,
66 Fabric,
68 Materialize,
70 Prql,
72 RisingWave,
74 SingleStore,
76 Tableau,
78 Teradata,
80}
81
82impl std::fmt::Display for Dialect {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 match self {
85 Dialect::Ansi => write!(f, "ANSI SQL"),
86 Dialect::Athena => write!(f, "Athena"),
87 Dialect::BigQuery => write!(f, "BigQuery"),
88 Dialect::ClickHouse => write!(f, "ClickHouse"),
89 Dialect::Databricks => write!(f, "Databricks"),
90 Dialect::DuckDb => write!(f, "DuckDB"),
91 Dialect::Hive => write!(f, "Hive"),
92 Dialect::Mysql => write!(f, "MySQL"),
93 Dialect::Oracle => write!(f, "Oracle"),
94 Dialect::Postgres => write!(f, "PostgreSQL"),
95 Dialect::Presto => write!(f, "Presto"),
96 Dialect::Redshift => write!(f, "Redshift"),
97 Dialect::Snowflake => write!(f, "Snowflake"),
98 Dialect::Spark => write!(f, "Spark"),
99 Dialect::Sqlite => write!(f, "SQLite"),
100 Dialect::StarRocks => write!(f, "StarRocks"),
101 Dialect::Trino => write!(f, "Trino"),
102 Dialect::Tsql => write!(f, "T-SQL"),
103 Dialect::Doris => write!(f, "Doris"),
104 Dialect::Dremio => write!(f, "Dremio"),
105 Dialect::Drill => write!(f, "Drill"),
106 Dialect::Druid => write!(f, "Druid"),
107 Dialect::Exasol => write!(f, "Exasol"),
108 Dialect::Fabric => write!(f, "Fabric"),
109 Dialect::Materialize => write!(f, "Materialize"),
110 Dialect::Prql => write!(f, "PRQL"),
111 Dialect::RisingWave => write!(f, "RisingWave"),
112 Dialect::SingleStore => write!(f, "SingleStore"),
113 Dialect::Tableau => write!(f, "Tableau"),
114 Dialect::Teradata => write!(f, "Teradata"),
115 }
116 }
117}
118
119impl Dialect {
120 #[must_use]
122 pub fn support_level(&self) -> &'static str {
123 match self {
124 Dialect::Ansi
125 | Dialect::Athena
126 | Dialect::BigQuery
127 | Dialect::ClickHouse
128 | Dialect::Databricks
129 | Dialect::DuckDb
130 | Dialect::Hive
131 | Dialect::Mysql
132 | Dialect::Oracle
133 | Dialect::Postgres
134 | Dialect::Presto
135 | Dialect::Redshift
136 | Dialect::Snowflake
137 | Dialect::Spark
138 | Dialect::Sqlite
139 | Dialect::StarRocks
140 | Dialect::Trino
141 | Dialect::Tsql => "Official",
142
143 Dialect::Doris
144 | Dialect::Dremio
145 | Dialect::Drill
146 | Dialect::Druid
147 | Dialect::Exasol
148 | Dialect::Fabric
149 | Dialect::Materialize
150 | Dialect::Prql
151 | Dialect::RisingWave
152 | Dialect::SingleStore
153 | Dialect::Tableau
154 | Dialect::Teradata => "Community",
155 }
156 }
157
158 #[must_use]
160 pub fn all() -> &'static [Dialect] {
161 &[
162 Dialect::Ansi,
163 Dialect::Athena,
164 Dialect::BigQuery,
165 Dialect::ClickHouse,
166 Dialect::Databricks,
167 Dialect::Doris,
168 Dialect::Dremio,
169 Dialect::Drill,
170 Dialect::Druid,
171 Dialect::DuckDb,
172 Dialect::Exasol,
173 Dialect::Fabric,
174 Dialect::Hive,
175 Dialect::Materialize,
176 Dialect::Mysql,
177 Dialect::Oracle,
178 Dialect::Postgres,
179 Dialect::Presto,
180 Dialect::Prql,
181 Dialect::Redshift,
182 Dialect::RisingWave,
183 Dialect::SingleStore,
184 Dialect::Snowflake,
185 Dialect::Spark,
186 Dialect::Sqlite,
187 Dialect::StarRocks,
188 Dialect::Tableau,
189 Dialect::Teradata,
190 Dialect::Trino,
191 Dialect::Tsql,
192 ]
193 }
194
195 pub fn from_str(s: &str) -> Option<Dialect> {
197 match s.to_lowercase().as_str() {
198 "" | "ansi" => Some(Dialect::Ansi),
199 "athena" => Some(Dialect::Athena),
200 "bigquery" => Some(Dialect::BigQuery),
201 "clickhouse" => Some(Dialect::ClickHouse),
202 "databricks" => Some(Dialect::Databricks),
203 "doris" => Some(Dialect::Doris),
204 "dremio" => Some(Dialect::Dremio),
205 "drill" => Some(Dialect::Drill),
206 "druid" => Some(Dialect::Druid),
207 "duckdb" => Some(Dialect::DuckDb),
208 "exasol" => Some(Dialect::Exasol),
209 "fabric" => Some(Dialect::Fabric),
210 "hive" => Some(Dialect::Hive),
211 "materialize" => Some(Dialect::Materialize),
212 "mysql" => Some(Dialect::Mysql),
213 "oracle" => Some(Dialect::Oracle),
214 "postgres" | "postgresql" => Some(Dialect::Postgres),
215 "presto" => Some(Dialect::Presto),
216 "prql" => Some(Dialect::Prql),
217 "redshift" => Some(Dialect::Redshift),
218 "risingwave" => Some(Dialect::RisingWave),
219 "singlestore" => Some(Dialect::SingleStore),
220 "snowflake" => Some(Dialect::Snowflake),
221 "spark" => Some(Dialect::Spark),
222 "sqlite" => Some(Dialect::Sqlite),
223 "starrocks" => Some(Dialect::StarRocks),
224 "tableau" => Some(Dialect::Tableau),
225 "teradata" => Some(Dialect::Teradata),
226 "trino" => Some(Dialect::Trino),
227 "tsql" | "mssql" | "sqlserver" => Some(Dialect::Tsql),
228 _ => None,
229 }
230 }
231}
232
233fn is_mysql_family(d: Dialect) -> bool {
239 matches!(
240 d,
241 Dialect::Mysql | Dialect::Doris | Dialect::SingleStore | Dialect::StarRocks
242 )
243}
244
245fn is_postgres_family(d: Dialect) -> bool {
247 matches!(
248 d,
249 Dialect::Postgres | Dialect::Redshift | Dialect::Materialize | Dialect::RisingWave
250 )
251}
252
253fn is_presto_family(d: Dialect) -> bool {
255 matches!(d, Dialect::Presto | Dialect::Trino | Dialect::Athena)
256}
257
258fn is_hive_family(d: Dialect) -> bool {
260 matches!(d, Dialect::Hive | Dialect::Spark | Dialect::Databricks)
261}
262
263fn is_tsql_family(d: Dialect) -> bool {
265 matches!(d, Dialect::Tsql | Dialect::Fabric)
266}
267
268pub(crate) fn supports_ilike_builtin(d: Dialect) -> bool {
270 matches!(
271 d,
272 Dialect::Postgres
273 | Dialect::Redshift
274 | Dialect::Materialize
275 | Dialect::RisingWave
276 | Dialect::DuckDb
277 | Dialect::Snowflake
278 | Dialect::ClickHouse
279 | Dialect::Trino
280 | Dialect::Presto
281 | Dialect::Athena
282 | Dialect::Databricks
283 | Dialect::Spark
284 | Dialect::Hive
285 | Dialect::StarRocks
286 | Dialect::Exasol
287 | Dialect::Druid
288 | Dialect::Dremio
289 )
290}
291
292#[must_use]
303pub fn transform(statement: &Statement, from: Dialect, to: Dialect) -> Statement {
304 if from == to {
305 return statement.clone();
306 }
307 let mut stmt = statement.clone();
308 transform_statement(&mut stmt, to);
309 stmt
310}
311
312fn transform_statement(statement: &mut Statement, target: Dialect) {
313 match statement {
314 Statement::Select(sel) => {
315 transform_limit(sel, target);
317 transform_quotes_in_select(sel, target);
319
320 for item in &mut sel.columns {
321 if let SelectItem::Expr { expr, .. } = item {
322 *expr = transform_expr(expr.clone(), target);
323 }
324 }
325 if let Some(wh) = &mut sel.where_clause {
326 *wh = transform_expr(wh.clone(), target);
327 }
328 for gb in &mut sel.group_by {
329 *gb = transform_expr(gb.clone(), target);
330 }
331 if let Some(having) = &mut sel.having {
332 *having = transform_expr(having.clone(), target);
333 }
334 }
335 Statement::Insert(ins) => {
336 if let InsertSource::Values(rows) = &mut ins.source {
337 for row in rows {
338 for val in row {
339 *val = transform_expr(val.clone(), target);
340 }
341 }
342 }
343 }
344 Statement::Update(upd) => {
345 for (_, val) in &mut upd.assignments {
346 *val = transform_expr(val.clone(), target);
347 }
348 if let Some(wh) = &mut upd.where_clause {
349 *wh = transform_expr(wh.clone(), target);
350 }
351 }
352 Statement::CreateTable(ct) => {
354 for col in &mut ct.columns {
355 col.data_type = map_data_type(col.data_type.clone(), target);
356 if let Some(default) = &mut col.default {
357 *default = transform_expr(default.clone(), target);
358 }
359 }
360 for constraint in &mut ct.constraints {
362 if let TableConstraint::Check { expr, .. } = constraint {
363 *expr = transform_expr(expr.clone(), target);
364 }
365 }
366 if let Some(as_select) = &mut ct.as_select {
368 transform_statement(as_select, target);
369 }
370 }
371 Statement::AlterTable(alt) => {
373 for action in &mut alt.actions {
374 match action {
375 AlterTableAction::AddColumn(col) => {
376 col.data_type = map_data_type(col.data_type.clone(), target);
377 if let Some(default) = &mut col.default {
378 *default = transform_expr(default.clone(), target);
379 }
380 }
381 AlterTableAction::AlterColumnType { data_type, .. } => {
382 *data_type = map_data_type(data_type.clone(), target);
383 }
384 _ => {}
385 }
386 }
387 }
388 _ => {}
389 }
390}
391
392fn transform_expr(expr: Expr, target: Dialect) -> Expr {
394 match expr {
395 Expr::Function {
397 name,
398 args,
399 distinct,
400 filter,
401 over,
402 } => {
403 let new_name = map_function_name(&name, target);
404 let new_args: Vec<Expr> = args
405 .into_iter()
406 .map(|a| transform_expr(a, target))
407 .collect();
408 Expr::Function {
409 name: new_name,
410 args: new_args,
411 distinct,
412 filter: filter.map(|f| Box::new(transform_expr(*f, target))),
413 over,
414 }
415 }
416 Expr::TypedFunction { func, filter, over } => {
419 let transformed_func = transform_typed_function(func, target);
420 Expr::TypedFunction {
421 func: transformed_func,
422 filter: filter.map(|f| Box::new(transform_expr(*f, target))),
423 over,
424 }
425 }
426 Expr::ILike {
428 expr,
429 pattern,
430 negated,
431 escape,
432 } if !supports_ilike_builtin(target) => Expr::Like {
433 expr: Box::new(Expr::TypedFunction {
434 func: TypedFunction::Lower {
435 expr: Box::new(transform_expr(*expr, target)),
436 },
437 filter: None,
438 over: None,
439 }),
440 pattern: Box::new(Expr::TypedFunction {
441 func: TypedFunction::Lower {
442 expr: Box::new(transform_expr(*pattern, target)),
443 },
444 filter: None,
445 over: None,
446 }),
447 negated,
448 escape,
449 },
450 Expr::Cast { expr, data_type } => Expr::Cast {
452 expr: Box::new(transform_expr(*expr, target)),
453 data_type: map_data_type(data_type, target),
454 },
455 Expr::BinaryOp { left, op, right } => Expr::BinaryOp {
457 left: Box::new(transform_expr(*left, target)),
458 op,
459 right: Box::new(transform_expr(*right, target)),
460 },
461 Expr::UnaryOp { op, expr } => Expr::UnaryOp {
462 op,
463 expr: Box::new(transform_expr(*expr, target)),
464 },
465 Expr::Nested(inner) => Expr::Nested(Box::new(transform_expr(*inner, target))),
466 Expr::Column {
468 table,
469 name,
470 quote_style,
471 table_quote_style,
472 } => {
473 let new_qs = if quote_style.is_quoted() {
474 QuoteStyle::for_dialect(target)
475 } else {
476 QuoteStyle::None
477 };
478 let new_tqs = if table_quote_style.is_quoted() {
479 QuoteStyle::for_dialect(target)
480 } else {
481 QuoteStyle::None
482 };
483 Expr::Column {
484 table,
485 name,
486 quote_style: new_qs,
487 table_quote_style: new_tqs,
488 }
489 }
490 other => other,
492 }
493}
494
495fn transform_typed_function(func: TypedFunction, target: Dialect) -> TypedFunction {
504 match func {
505 TypedFunction::TimeToStr { expr, format } => {
506 let transformed_expr = Box::new(transform_expr(*expr, target));
507 let transformed_format = transform_format_expr(*format, target);
508 TypedFunction::TimeToStr {
509 expr: transformed_expr,
510 format: Box::new(transformed_format),
511 }
512 }
513 TypedFunction::StrToTime { expr, format } => {
514 let transformed_expr = Box::new(transform_expr(*expr, target));
515 let transformed_format = transform_format_expr(*format, target);
516 TypedFunction::StrToTime {
517 expr: transformed_expr,
518 format: Box::new(transformed_format),
519 }
520 }
521 other => other.transform_children(&|e| transform_expr(e, target)),
523 }
524}
525
526fn transform_format_expr(expr: Expr, target: Dialect) -> Expr {
531 match &expr {
535 Expr::StringLiteral(s) | Expr::NationalStringLiteral(s) => {
536 let detected_source = detect_format_style(s);
537 let target_style = time::TimeFormatStyle::for_dialect(target);
538
539 if detected_source != target_style {
541 let converted = time::format_time(s, detected_source, target_style);
542 match expr {
543 Expr::NationalStringLiteral(_) => Expr::NationalStringLiteral(converted),
544 _ => Expr::StringLiteral(converted),
545 }
546 } else {
547 expr
548 }
549 }
550 _ => transform_expr(expr, target),
551 }
552}
553
554fn detect_format_style(format_str: &str) -> time::TimeFormatStyle {
556 if format_str.contains('%') {
558 if format_str.contains("%i") {
560 time::TimeFormatStyle::Mysql
562 } else {
563 time::TimeFormatStyle::Strftime
565 }
566 } else if format_str.contains("YYYY") || format_str.contains("yyyy") {
567 if format_str.contains("HH24") || format_str.contains("MI") || format_str.contains("SS") {
569 time::TimeFormatStyle::Postgres
571 } else if format_str.contains("mm") && format_str.contains("ss") {
572 time::TimeFormatStyle::Java
574 } else if format_str.contains("FF") {
575 time::TimeFormatStyle::Snowflake
577 } else if format_str.contains("MM") && format_str.contains("DD") {
578 time::TimeFormatStyle::Postgres
580 } else {
581 time::TimeFormatStyle::Java
583 }
584 } else {
585 time::TimeFormatStyle::Strftime
587 }
588}
589
590pub(crate) fn map_function_name(name: &str, target: Dialect) -> String {
596 let upper = name.to_uppercase();
597 match upper.as_str() {
598 "NOW" => {
600 if is_tsql_family(target) {
601 "GETDATE".to_string()
602 } else if matches!(
603 target,
604 Dialect::Ansi
605 | Dialect::BigQuery
606 | Dialect::Snowflake
607 | Dialect::Oracle
608 | Dialect::ClickHouse
609 | Dialect::Exasol
610 | Dialect::Teradata
611 | Dialect::Druid
612 | Dialect::Dremio
613 | Dialect::Tableau
614 ) || is_presto_family(target)
615 || is_hive_family(target)
616 {
617 "CURRENT_TIMESTAMP".to_string()
618 } else {
619 name.to_string()
621 }
622 }
623 "GETDATE" => {
624 if is_tsql_family(target) {
625 name.to_string()
626 } else if is_postgres_family(target)
627 || matches!(target, Dialect::Mysql | Dialect::DuckDb | Dialect::Sqlite)
628 {
629 "NOW".to_string()
630 } else {
631 "CURRENT_TIMESTAMP".to_string()
632 }
633 }
634
635 "LEN" => {
637 if is_tsql_family(target) || matches!(target, Dialect::BigQuery | Dialect::Snowflake) {
638 name.to_string()
639 } else {
640 "LENGTH".to_string()
641 }
642 }
643 "LENGTH" if is_tsql_family(target) => "LEN".to_string(),
644
645 "SUBSTR" => {
647 if is_mysql_family(target)
648 || matches!(target, Dialect::Sqlite | Dialect::Oracle)
649 || is_hive_family(target)
650 {
651 "SUBSTR".to_string()
652 } else {
653 "SUBSTRING".to_string()
654 }
655 }
656 "SUBSTRING" => {
657 if is_mysql_family(target)
658 || matches!(target, Dialect::Sqlite | Dialect::Oracle)
659 || is_hive_family(target)
660 {
661 "SUBSTR".to_string()
662 } else {
663 name.to_string()
664 }
665 }
666
667 "IFNULL" => {
669 if is_tsql_family(target) {
670 "ISNULL".to_string()
671 } else if is_mysql_family(target) || matches!(target, Dialect::Sqlite) {
672 name.to_string()
674 } else {
675 "COALESCE".to_string()
676 }
677 }
678 "ISNULL" => {
679 if is_tsql_family(target) {
680 name.to_string()
681 } else if is_mysql_family(target) || matches!(target, Dialect::Sqlite) {
682 "IFNULL".to_string()
683 } else {
684 "COALESCE".to_string()
685 }
686 }
687
688 "NVL" => {
690 if matches!(target, Dialect::Oracle | Dialect::Snowflake) {
691 name.to_string()
692 } else if is_mysql_family(target) || matches!(target, Dialect::Sqlite) {
693 "IFNULL".to_string()
694 } else if is_tsql_family(target) {
695 "ISNULL".to_string()
696 } else {
697 "COALESCE".to_string()
698 }
699 }
700
701 "RANDOM" => {
703 if matches!(
704 target,
705 Dialect::Postgres | Dialect::Sqlite | Dialect::DuckDb
706 ) {
707 name.to_string()
708 } else {
709 "RAND".to_string()
710 }
711 }
712 "RAND" => {
713 if matches!(
714 target,
715 Dialect::Postgres | Dialect::Sqlite | Dialect::DuckDb
716 ) {
717 "RANDOM".to_string()
718 } else {
719 name.to_string()
720 }
721 }
722
723 _ => name.to_string(),
725 }
726}
727
728pub(crate) fn map_data_type(dt: DataType, target: Dialect) -> DataType {
734 match (dt, target) {
735 (DataType::Text, t) if matches!(t, Dialect::BigQuery) || is_hive_family(t) => {
738 DataType::String
739 }
740 (DataType::String, t)
742 if is_postgres_family(t) || is_mysql_family(t) || matches!(t, Dialect::Sqlite) =>
743 {
744 DataType::Text
745 }
746
747 (DataType::Int, Dialect::BigQuery) => DataType::BigInt,
749
750 (DataType::Float, Dialect::BigQuery) => DataType::Double,
752
753 (DataType::Bytea, t)
755 if is_mysql_family(t)
756 || matches!(t, Dialect::Sqlite | Dialect::Oracle)
757 || is_hive_family(t) =>
758 {
759 DataType::Blob
760 }
761 (DataType::Blob, t) if is_postgres_family(t) => DataType::Bytea,
762
763 (DataType::Boolean, Dialect::Mysql) => DataType::Boolean,
765
766 (dt, _) => dt,
768 }
769}
770
771fn transform_limit(sel: &mut SelectStatement, target: Dialect) {
781 if is_tsql_family(target) {
782 if let Some(limit) = sel.limit.take() {
784 if sel.offset.is_none() {
785 sel.top = Some(Box::new(limit));
786 } else {
787 sel.fetch_first = Some(limit);
789 }
790 }
791 if sel.offset.is_none() {
793 if let Some(fetch) = sel.fetch_first.take() {
794 sel.top = Some(Box::new(fetch));
795 }
796 }
797 } else if matches!(target, Dialect::Oracle) {
798 if let Some(limit) = sel.limit.take() {
800 sel.fetch_first = Some(limit);
801 }
802 if let Some(top) = sel.top.take() {
803 sel.fetch_first = Some(*top);
804 }
805 } else {
806 if let Some(top) = sel.top.take() {
808 if sel.limit.is_none() {
809 sel.limit = Some(*top);
810 }
811 }
812 if let Some(fetch) = sel.fetch_first.take() {
813 if sel.limit.is_none() {
814 sel.limit = Some(fetch);
815 }
816 }
817 }
818}
819
820fn transform_quotes(expr: Expr, target: Dialect) -> Expr {
827 match expr {
828 Expr::Column {
829 table,
830 name,
831 quote_style,
832 table_quote_style,
833 } => {
834 let new_qs = if quote_style.is_quoted() {
835 QuoteStyle::for_dialect(target)
836 } else {
837 QuoteStyle::None
838 };
839 let new_tqs = if table_quote_style.is_quoted() {
840 QuoteStyle::for_dialect(target)
841 } else {
842 QuoteStyle::None
843 };
844 Expr::Column {
845 table,
846 name,
847 quote_style: new_qs,
848 table_quote_style: new_tqs,
849 }
850 }
851 Expr::BinaryOp { left, op, right } => Expr::BinaryOp {
853 left: Box::new(transform_quotes(*left, target)),
854 op,
855 right: Box::new(transform_quotes(*right, target)),
856 },
857 Expr::UnaryOp { op, expr } => Expr::UnaryOp {
858 op,
859 expr: Box::new(transform_quotes(*expr, target)),
860 },
861 Expr::Function {
862 name,
863 args,
864 distinct,
865 filter,
866 over,
867 } => Expr::Function {
868 name,
869 args: args
870 .into_iter()
871 .map(|a| transform_quotes(a, target))
872 .collect(),
873 distinct,
874 filter: filter.map(|f| Box::new(transform_quotes(*f, target))),
875 over,
876 },
877 Expr::TypedFunction { func, filter, over } => Expr::TypedFunction {
878 func: func.transform_children(&|e| transform_quotes(e, target)),
879 filter: filter.map(|f| Box::new(transform_quotes(*f, target))),
880 over,
881 },
882 Expr::Nested(inner) => Expr::Nested(Box::new(transform_quotes(*inner, target))),
883 Expr::Alias { expr, name } => Expr::Alias {
884 expr: Box::new(transform_quotes(*expr, target)),
885 name,
886 },
887 other => other,
888 }
889}
890
891fn transform_quotes_in_select(sel: &mut SelectStatement, target: Dialect) {
893 for item in &mut sel.columns {
895 if let SelectItem::Expr { expr, .. } = item {
896 *expr = transform_quotes(expr.clone(), target);
897 }
898 }
899 if let Some(wh) = &mut sel.where_clause {
901 *wh = transform_quotes(wh.clone(), target);
902 }
903 for gb in &mut sel.group_by {
905 *gb = transform_quotes(gb.clone(), target);
906 }
907 if let Some(having) = &mut sel.having {
909 *having = transform_quotes(having.clone(), target);
910 }
911 for ob in &mut sel.order_by {
913 ob.expr = transform_quotes(ob.expr.clone(), target);
914 }
915 if let Some(from) = &mut sel.from {
917 transform_quotes_in_table_source(&mut from.source, target);
918 }
919 for join in &mut sel.joins {
920 transform_quotes_in_table_source(&mut join.table, target);
921 if let Some(on) = &mut join.on {
922 *on = transform_quotes(on.clone(), target);
923 }
924 }
925}
926
927fn transform_quotes_in_table_source(source: &mut TableSource, target: Dialect) {
928 match source {
929 TableSource::Table(tref) => {
930 if tref.name_quote_style.is_quoted() {
931 tref.name_quote_style = QuoteStyle::for_dialect(target);
932 }
933 }
934 TableSource::Subquery { .. } => {}
935 TableSource::TableFunction { .. } => {}
936 TableSource::Lateral { source } => transform_quotes_in_table_source(source, target),
937 TableSource::Pivot { source, .. } | TableSource::Unpivot { source, .. } => {
938 transform_quotes_in_table_source(source, target);
939 }
940 TableSource::Unnest { .. } => {}
941 }
942}