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) => {
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 Expr::StringLiteral(converted)
543 } else {
544 expr
545 }
546 }
547 _ => transform_expr(expr, target),
548 }
549}
550
551fn detect_format_style(format_str: &str) -> time::TimeFormatStyle {
553 if format_str.contains('%') {
555 if format_str.contains("%i") {
557 time::TimeFormatStyle::Mysql
559 } else {
560 time::TimeFormatStyle::Strftime
562 }
563 } else if format_str.contains("YYYY") || format_str.contains("yyyy") {
564 if format_str.contains("HH24") || format_str.contains("MI") || format_str.contains("SS") {
566 time::TimeFormatStyle::Postgres
568 } else if format_str.contains("mm") && format_str.contains("ss") {
569 time::TimeFormatStyle::Java
571 } else if format_str.contains("FF") {
572 time::TimeFormatStyle::Snowflake
574 } else if format_str.contains("MM") && format_str.contains("DD") {
575 time::TimeFormatStyle::Postgres
577 } else {
578 time::TimeFormatStyle::Java
580 }
581 } else {
582 time::TimeFormatStyle::Strftime
584 }
585}
586
587pub(crate) fn map_function_name(name: &str, target: Dialect) -> String {
593 let upper = name.to_uppercase();
594 match upper.as_str() {
595 "NOW" => {
597 if is_tsql_family(target) {
598 "GETDATE".to_string()
599 } else if matches!(
600 target,
601 Dialect::Ansi
602 | Dialect::BigQuery
603 | Dialect::Snowflake
604 | Dialect::Oracle
605 | Dialect::ClickHouse
606 | Dialect::Exasol
607 | Dialect::Teradata
608 | Dialect::Druid
609 | Dialect::Dremio
610 | Dialect::Tableau
611 ) || is_presto_family(target)
612 || is_hive_family(target)
613 {
614 "CURRENT_TIMESTAMP".to_string()
615 } else {
616 name.to_string()
618 }
619 }
620 "GETDATE" => {
621 if is_tsql_family(target) {
622 name.to_string()
623 } else if is_postgres_family(target)
624 || matches!(target, Dialect::Mysql | Dialect::DuckDb | Dialect::Sqlite)
625 {
626 "NOW".to_string()
627 } else {
628 "CURRENT_TIMESTAMP".to_string()
629 }
630 }
631
632 "LEN" => {
634 if is_tsql_family(target) || matches!(target, Dialect::BigQuery | Dialect::Snowflake) {
635 name.to_string()
636 } else {
637 "LENGTH".to_string()
638 }
639 }
640 "LENGTH" if is_tsql_family(target) => "LEN".to_string(),
641
642 "SUBSTR" => {
644 if is_mysql_family(target)
645 || matches!(target, Dialect::Sqlite | Dialect::Oracle)
646 || is_hive_family(target)
647 {
648 "SUBSTR".to_string()
649 } else {
650 "SUBSTRING".to_string()
651 }
652 }
653 "SUBSTRING" => {
654 if is_mysql_family(target)
655 || matches!(target, Dialect::Sqlite | Dialect::Oracle)
656 || is_hive_family(target)
657 {
658 "SUBSTR".to_string()
659 } else {
660 name.to_string()
661 }
662 }
663
664 "IFNULL" => {
666 if is_tsql_family(target) {
667 "ISNULL".to_string()
668 } else if is_mysql_family(target) || matches!(target, Dialect::Sqlite) {
669 name.to_string()
671 } else {
672 "COALESCE".to_string()
673 }
674 }
675 "ISNULL" => {
676 if is_tsql_family(target) {
677 name.to_string()
678 } else if is_mysql_family(target) || matches!(target, Dialect::Sqlite) {
679 "IFNULL".to_string()
680 } else {
681 "COALESCE".to_string()
682 }
683 }
684
685 "NVL" => {
687 if matches!(target, Dialect::Oracle | Dialect::Snowflake) {
688 name.to_string()
689 } else if is_mysql_family(target) || matches!(target, Dialect::Sqlite) {
690 "IFNULL".to_string()
691 } else if is_tsql_family(target) {
692 "ISNULL".to_string()
693 } else {
694 "COALESCE".to_string()
695 }
696 }
697
698 "RANDOM" => {
700 if matches!(
701 target,
702 Dialect::Postgres | Dialect::Sqlite | Dialect::DuckDb
703 ) {
704 name.to_string()
705 } else {
706 "RAND".to_string()
707 }
708 }
709 "RAND" => {
710 if matches!(
711 target,
712 Dialect::Postgres | Dialect::Sqlite | Dialect::DuckDb
713 ) {
714 "RANDOM".to_string()
715 } else {
716 name.to_string()
717 }
718 }
719
720 _ => name.to_string(),
722 }
723}
724
725pub(crate) fn map_data_type(dt: DataType, target: Dialect) -> DataType {
731 match (dt, target) {
732 (DataType::Text, t) if matches!(t, Dialect::BigQuery) || is_hive_family(t) => {
735 DataType::String
736 }
737 (DataType::String, t)
739 if is_postgres_family(t) || is_mysql_family(t) || matches!(t, Dialect::Sqlite) =>
740 {
741 DataType::Text
742 }
743
744 (DataType::Int, Dialect::BigQuery) => DataType::BigInt,
746
747 (DataType::Float, Dialect::BigQuery) => DataType::Double,
749
750 (DataType::Bytea, t)
752 if is_mysql_family(t)
753 || matches!(t, Dialect::Sqlite | Dialect::Oracle)
754 || is_hive_family(t) =>
755 {
756 DataType::Blob
757 }
758 (DataType::Blob, t) if is_postgres_family(t) => DataType::Bytea,
759
760 (DataType::Boolean, Dialect::Mysql) => DataType::Boolean,
762
763 (dt, _) => dt,
765 }
766}
767
768fn transform_limit(sel: &mut SelectStatement, target: Dialect) {
778 if is_tsql_family(target) {
779 if let Some(limit) = sel.limit.take() {
781 if sel.offset.is_none() {
782 sel.top = Some(Box::new(limit));
783 } else {
784 sel.fetch_first = Some(limit);
786 }
787 }
788 if sel.offset.is_none() {
790 if let Some(fetch) = sel.fetch_first.take() {
791 sel.top = Some(Box::new(fetch));
792 }
793 }
794 } else if matches!(target, Dialect::Oracle) {
795 if let Some(limit) = sel.limit.take() {
797 sel.fetch_first = Some(limit);
798 }
799 if let Some(top) = sel.top.take() {
800 sel.fetch_first = Some(*top);
801 }
802 } else {
803 if let Some(top) = sel.top.take() {
805 if sel.limit.is_none() {
806 sel.limit = Some(*top);
807 }
808 }
809 if let Some(fetch) = sel.fetch_first.take() {
810 if sel.limit.is_none() {
811 sel.limit = Some(fetch);
812 }
813 }
814 }
815}
816
817fn transform_quotes(expr: Expr, target: Dialect) -> Expr {
824 match expr {
825 Expr::Column {
826 table,
827 name,
828 quote_style,
829 table_quote_style,
830 } => {
831 let new_qs = if quote_style.is_quoted() {
832 QuoteStyle::for_dialect(target)
833 } else {
834 QuoteStyle::None
835 };
836 let new_tqs = if table_quote_style.is_quoted() {
837 QuoteStyle::for_dialect(target)
838 } else {
839 QuoteStyle::None
840 };
841 Expr::Column {
842 table,
843 name,
844 quote_style: new_qs,
845 table_quote_style: new_tqs,
846 }
847 }
848 Expr::BinaryOp { left, op, right } => Expr::BinaryOp {
850 left: Box::new(transform_quotes(*left, target)),
851 op,
852 right: Box::new(transform_quotes(*right, target)),
853 },
854 Expr::UnaryOp { op, expr } => Expr::UnaryOp {
855 op,
856 expr: Box::new(transform_quotes(*expr, target)),
857 },
858 Expr::Function {
859 name,
860 args,
861 distinct,
862 filter,
863 over,
864 } => Expr::Function {
865 name,
866 args: args
867 .into_iter()
868 .map(|a| transform_quotes(a, target))
869 .collect(),
870 distinct,
871 filter: filter.map(|f| Box::new(transform_quotes(*f, target))),
872 over,
873 },
874 Expr::TypedFunction { func, filter, over } => Expr::TypedFunction {
875 func: func.transform_children(&|e| transform_quotes(e, target)),
876 filter: filter.map(|f| Box::new(transform_quotes(*f, target))),
877 over,
878 },
879 Expr::Nested(inner) => Expr::Nested(Box::new(transform_quotes(*inner, target))),
880 Expr::Alias { expr, name } => Expr::Alias {
881 expr: Box::new(transform_quotes(*expr, target)),
882 name,
883 },
884 other => other,
885 }
886}
887
888fn transform_quotes_in_select(sel: &mut SelectStatement, target: Dialect) {
890 for item in &mut sel.columns {
892 if let SelectItem::Expr { expr, .. } = item {
893 *expr = transform_quotes(expr.clone(), target);
894 }
895 }
896 if let Some(wh) = &mut sel.where_clause {
898 *wh = transform_quotes(wh.clone(), target);
899 }
900 for gb in &mut sel.group_by {
902 *gb = transform_quotes(gb.clone(), target);
903 }
904 if let Some(having) = &mut sel.having {
906 *having = transform_quotes(having.clone(), target);
907 }
908 for ob in &mut sel.order_by {
910 ob.expr = transform_quotes(ob.expr.clone(), target);
911 }
912 if let Some(from) = &mut sel.from {
914 transform_quotes_in_table_source(&mut from.source, target);
915 }
916 for join in &mut sel.joins {
917 transform_quotes_in_table_source(&mut join.table, target);
918 if let Some(on) = &mut join.on {
919 *on = transform_quotes(on.clone(), target);
920 }
921 }
922}
923
924fn transform_quotes_in_table_source(source: &mut TableSource, target: Dialect) {
925 match source {
926 TableSource::Table(tref) => {
927 if tref.name_quote_style.is_quoted() {
928 tref.name_quote_style = QuoteStyle::for_dialect(target);
929 }
930 }
931 TableSource::Subquery { .. } => {}
932 TableSource::TableFunction { .. } => {}
933 TableSource::Lateral { source } => transform_quotes_in_table_source(source, target),
934 TableSource::Pivot { source, .. } | TableSource::Unpivot { source, .. } => {
935 transform_quotes_in_table_source(source, target);
936 }
937 TableSource::Unnest { .. } => {}
938 }
939}