1mod generic; #[cfg(feature = "transpile")]
24mod normalization;
25
26#[cfg(feature = "dialect-athena")]
27mod athena;
28#[cfg(feature = "dialect-bigquery")]
29mod bigquery;
30#[cfg(feature = "dialect-clickhouse")]
31mod clickhouse;
32#[cfg(feature = "dialect-cockroachdb")]
33mod cockroachdb;
34#[cfg(feature = "dialect-databricks")]
35mod databricks;
36#[cfg(feature = "dialect-datafusion")]
37mod datafusion;
38#[cfg(feature = "dialect-doris")]
39mod doris;
40#[cfg(feature = "dialect-dremio")]
41mod dremio;
42#[cfg(feature = "dialect-drill")]
43mod drill;
44#[cfg(feature = "dialect-druid")]
45mod druid;
46#[cfg(feature = "dialect-duckdb")]
47mod duckdb;
48#[cfg(feature = "dialect-dune")]
49mod dune;
50#[cfg(feature = "dialect-exasol")]
51mod exasol;
52#[cfg(feature = "dialect-fabric")]
53mod fabric;
54#[cfg(feature = "dialect-hive")]
55mod hive;
56#[cfg(feature = "dialect-materialize")]
57mod materialize;
58#[cfg(feature = "dialect-mysql")]
59mod mysql;
60#[cfg(feature = "dialect-oracle")]
61mod oracle;
62#[cfg(feature = "dialect-postgresql")]
63mod postgres;
64#[cfg(feature = "dialect-presto")]
65mod presto;
66#[cfg(feature = "dialect-redshift")]
67mod redshift;
68#[cfg(feature = "dialect-risingwave")]
69mod risingwave;
70#[cfg(feature = "dialect-singlestore")]
71mod singlestore;
72#[cfg(feature = "dialect-snowflake")]
73mod snowflake;
74#[cfg(feature = "dialect-solr")]
75mod solr;
76#[cfg(feature = "dialect-spark")]
77mod spark;
78#[cfg(feature = "dialect-sqlite")]
79mod sqlite;
80#[cfg(feature = "dialect-starrocks")]
81mod starrocks;
82#[cfg(feature = "dialect-tableau")]
83mod tableau;
84#[cfg(feature = "dialect-teradata")]
85mod teradata;
86#[cfg(feature = "dialect-tidb")]
87mod tidb;
88#[cfg(feature = "dialect-trino")]
89mod trino;
90#[cfg(any(feature = "dialect-tsql", feature = "dialect-fabric"))]
91mod tsql;
92
93pub use generic::GenericDialect; #[cfg(feature = "dialect-athena")]
96pub use athena::AthenaDialect;
97#[cfg(feature = "dialect-bigquery")]
98pub use bigquery::BigQueryDialect;
99#[cfg(feature = "dialect-clickhouse")]
100pub use clickhouse::ClickHouseDialect;
101#[cfg(feature = "dialect-cockroachdb")]
102pub use cockroachdb::CockroachDBDialect;
103#[cfg(feature = "dialect-databricks")]
104pub use databricks::DatabricksDialect;
105#[cfg(feature = "dialect-datafusion")]
106pub use datafusion::DataFusionDialect;
107#[cfg(feature = "dialect-doris")]
108pub use doris::DorisDialect;
109#[cfg(feature = "dialect-dremio")]
110pub use dremio::DremioDialect;
111#[cfg(feature = "dialect-drill")]
112pub use drill::DrillDialect;
113#[cfg(feature = "dialect-druid")]
114pub use druid::DruidDialect;
115#[cfg(feature = "dialect-duckdb")]
116pub use duckdb::DuckDBDialect;
117#[cfg(feature = "dialect-dune")]
118pub use dune::DuneDialect;
119#[cfg(feature = "dialect-exasol")]
120pub use exasol::ExasolDialect;
121#[cfg(feature = "dialect-fabric")]
122pub use fabric::FabricDialect;
123#[cfg(feature = "dialect-hive")]
124pub use hive::HiveDialect;
125#[cfg(feature = "dialect-materialize")]
126pub use materialize::MaterializeDialect;
127#[cfg(feature = "dialect-mysql")]
128pub use mysql::MySQLDialect;
129#[cfg(feature = "dialect-oracle")]
130pub use oracle::OracleDialect;
131#[cfg(feature = "dialect-postgresql")]
132pub use postgres::PostgresDialect;
133#[cfg(feature = "dialect-presto")]
134pub use presto::PrestoDialect;
135#[cfg(feature = "dialect-redshift")]
136pub use redshift::RedshiftDialect;
137#[cfg(feature = "dialect-risingwave")]
138pub use risingwave::RisingWaveDialect;
139#[cfg(feature = "dialect-singlestore")]
140pub use singlestore::SingleStoreDialect;
141#[cfg(feature = "dialect-snowflake")]
142pub use snowflake::SnowflakeDialect;
143#[cfg(feature = "dialect-solr")]
144pub use solr::SolrDialect;
145#[cfg(feature = "dialect-spark")]
146pub use spark::SparkDialect;
147#[cfg(feature = "dialect-sqlite")]
148pub use sqlite::SQLiteDialect;
149#[cfg(feature = "dialect-starrocks")]
150pub use starrocks::StarRocksDialect;
151#[cfg(feature = "dialect-tableau")]
152pub use tableau::TableauDialect;
153#[cfg(feature = "dialect-teradata")]
154pub use teradata::TeradataDialect;
155#[cfg(feature = "dialect-tidb")]
156pub use tidb::TiDBDialect;
157#[cfg(feature = "dialect-trino")]
158pub use trino::TrinoDialect;
159#[cfg(feature = "dialect-tsql")]
160pub use tsql::TSQLDialect;
161
162use crate::error::Result;
163#[cfg(feature = "transpile")]
164use crate::expressions::{
165 BinaryOp, Case, Cast, ColumnConstraint, DateBin, DateTimeField, Fetch, Function, Identifier,
166 Interval, IntervalUnit, IntervalUnitSpec, JoinKind, Literal, Offset, Over, Select, Subquery,
167 Top, Var, WindowFrame, WindowFrameBound, WindowFrameKind,
168};
169use crate::expressions::{DataType, Expression};
170#[cfg(any(
171 feature = "transpile",
172 feature = "ast-tools",
173 feature = "generate",
174 feature = "semantic"
175))]
176use crate::expressions::{From, FunctionBody, Join, Null, OrderBy, OutputClause, TableRef, With};
177#[cfg(feature = "transpile")]
178use crate::generator::UnsupportedLevel;
179#[cfg(feature = "generate")]
180use crate::generator::{Generator, GeneratorConfig};
181#[cfg(feature = "transpile")]
182use crate::guard::enforce_generate_ast;
183use crate::guard::{enforce_input, ComplexityGuardOptions, ParseOptions};
184#[cfg(feature = "transpile")]
185use crate::helper::find_new_name;
186use crate::parser::Parser;
187#[cfg(feature = "transpile")]
188use crate::tokens::TokenType;
189use crate::tokens::{Token, Tokenizer, TokenizerConfig};
190#[cfg(feature = "transpile")]
191use crate::traversal::{is_aggregate, ExpressionWalk};
192use serde::{Deserialize, Serialize};
193use std::collections::HashMap;
194#[cfg(feature = "transpile")]
195use std::collections::HashSet;
196use std::sync::{Arc, LazyLock, RwLock};
197
198#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
207#[serde(rename_all = "lowercase")]
208pub enum DialectType {
209 Generic,
211 PostgreSQL,
213 MySQL,
215 BigQuery,
217 Snowflake,
219 DuckDB,
221 SQLite,
223 Hive,
225 Spark,
227 Trino,
229 Presto,
231 Redshift,
233 TSQL,
235 Oracle,
237 ClickHouse,
239 Databricks,
241 Athena,
243 Teradata,
245 Doris,
247 StarRocks,
249 Materialize,
251 RisingWave,
253 SingleStore,
255 CockroachDB,
257 TiDB,
259 Druid,
261 Solr,
263 Tableau,
265 Dune,
267 Fabric,
269 Drill,
271 Dremio,
273 Exasol,
275 DataFusion,
277}
278
279impl DialectType {
280 pub(crate) const fn supports_string_aliases(self, explicit_as: bool) -> bool {
283 matches!(
284 self,
285 DialectType::TSQL | DialectType::Fabric | DialectType::MySQL | DialectType::SQLite
286 ) || (matches!(self, DialectType::DuckDB) && explicit_as)
287 }
288}
289
290impl Default for DialectType {
291 fn default() -> Self {
292 DialectType::Generic
293 }
294}
295
296impl std::fmt::Display for DialectType {
297 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
298 match self {
299 DialectType::Generic => write!(f, "generic"),
300 DialectType::PostgreSQL => write!(f, "postgresql"),
301 DialectType::MySQL => write!(f, "mysql"),
302 DialectType::BigQuery => write!(f, "bigquery"),
303 DialectType::Snowflake => write!(f, "snowflake"),
304 DialectType::DuckDB => write!(f, "duckdb"),
305 DialectType::SQLite => write!(f, "sqlite"),
306 DialectType::Hive => write!(f, "hive"),
307 DialectType::Spark => write!(f, "spark"),
308 DialectType::Trino => write!(f, "trino"),
309 DialectType::Presto => write!(f, "presto"),
310 DialectType::Redshift => write!(f, "redshift"),
311 DialectType::TSQL => write!(f, "tsql"),
312 DialectType::Oracle => write!(f, "oracle"),
313 DialectType::ClickHouse => write!(f, "clickhouse"),
314 DialectType::Databricks => write!(f, "databricks"),
315 DialectType::Athena => write!(f, "athena"),
316 DialectType::Teradata => write!(f, "teradata"),
317 DialectType::Doris => write!(f, "doris"),
318 DialectType::StarRocks => write!(f, "starrocks"),
319 DialectType::Materialize => write!(f, "materialize"),
320 DialectType::RisingWave => write!(f, "risingwave"),
321 DialectType::SingleStore => write!(f, "singlestore"),
322 DialectType::CockroachDB => write!(f, "cockroachdb"),
323 DialectType::TiDB => write!(f, "tidb"),
324 DialectType::Druid => write!(f, "druid"),
325 DialectType::Solr => write!(f, "solr"),
326 DialectType::Tableau => write!(f, "tableau"),
327 DialectType::Dune => write!(f, "dune"),
328 DialectType::Fabric => write!(f, "fabric"),
329 DialectType::Drill => write!(f, "drill"),
330 DialectType::Dremio => write!(f, "dremio"),
331 DialectType::Exasol => write!(f, "exasol"),
332 DialectType::DataFusion => write!(f, "datafusion"),
333 }
334 }
335}
336
337impl std::str::FromStr for DialectType {
338 type Err = crate::error::Error;
339
340 fn from_str(s: &str) -> Result<Self> {
341 match s.to_ascii_lowercase().as_str() {
342 "generic" | "" => Ok(DialectType::Generic),
343 "postgres" | "postgresql" => Ok(DialectType::PostgreSQL),
344 "mysql" => Ok(DialectType::MySQL),
345 "bigquery" => Ok(DialectType::BigQuery),
346 "snowflake" => Ok(DialectType::Snowflake),
347 "duckdb" => Ok(DialectType::DuckDB),
348 "sqlite" => Ok(DialectType::SQLite),
349 "hive" => Ok(DialectType::Hive),
350 "spark" | "spark2" => Ok(DialectType::Spark),
351 "trino" => Ok(DialectType::Trino),
352 "presto" => Ok(DialectType::Presto),
353 "redshift" => Ok(DialectType::Redshift),
354 "tsql" | "mssql" | "sqlserver" => Ok(DialectType::TSQL),
355 "oracle" => Ok(DialectType::Oracle),
356 "clickhouse" => Ok(DialectType::ClickHouse),
357 "databricks" => Ok(DialectType::Databricks),
358 "athena" => Ok(DialectType::Athena),
359 "teradata" => Ok(DialectType::Teradata),
360 "doris" => Ok(DialectType::Doris),
361 "starrocks" => Ok(DialectType::StarRocks),
362 "materialize" => Ok(DialectType::Materialize),
363 "risingwave" => Ok(DialectType::RisingWave),
364 "singlestore" | "memsql" => Ok(DialectType::SingleStore),
365 "cockroachdb" | "cockroach" => Ok(DialectType::CockroachDB),
366 "tidb" => Ok(DialectType::TiDB),
367 "druid" => Ok(DialectType::Druid),
368 "solr" => Ok(DialectType::Solr),
369 "tableau" => Ok(DialectType::Tableau),
370 "dune" => Ok(DialectType::Dune),
371 "fabric" => Ok(DialectType::Fabric),
372 "drill" => Ok(DialectType::Drill),
373 "dremio" => Ok(DialectType::Dremio),
374 "exasol" => Ok(DialectType::Exasol),
375 "datafusion" | "arrow-datafusion" | "arrow_datafusion" => Ok(DialectType::DataFusion),
376 _ => Err(crate::error::Error::parse(
377 format!("Unknown dialect: {}", s),
378 0,
379 0,
380 0,
381 0,
382 )),
383 }
384 }
385}
386
387pub trait DialectImpl {
403 fn dialect_type(&self) -> DialectType;
405
406 fn tokenizer_config(&self) -> TokenizerConfig {
411 TokenizerConfig::default()
412 }
413
414 #[cfg(feature = "generate")]
419 fn generator_config(&self) -> GeneratorConfig {
420 GeneratorConfig::default()
421 }
422
423 #[cfg(feature = "generate")]
429 fn generator_config_for_expr(&self, _expr: &Expression) -> GeneratorConfig {
430 self.generator_config()
431 }
432
433 #[cfg(feature = "transpile")]
439 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
440 Ok(expr)
441 }
442
443 #[cfg(feature = "transpile")]
449 fn preprocess(&self, expr: Expression) -> Result<Expression> {
450 Ok(expr)
451 }
452}
453
454#[cfg(any(
461 feature = "transpile",
462 feature = "ast-tools",
463 feature = "generate",
464 feature = "semantic"
465))]
466fn transform_data_type_recursive<F>(
467 dt: crate::expressions::DataType,
468 transform_fn: &F,
469) -> Result<crate::expressions::DataType>
470where
471 F: Fn(Expression) -> Result<Expression>,
472{
473 use crate::expressions::DataType;
474 let dt_expr = transform_fn(Expression::DataType(dt))?;
476 let dt = match dt_expr {
477 Expression::DataType(d) => d,
478 _ => {
479 return Ok(match dt_expr {
480 _ => DataType::Custom {
481 name: "UNKNOWN".to_string(),
482 },
483 })
484 }
485 };
486 match dt {
488 DataType::Array {
489 element_type,
490 dimension,
491 } => {
492 let inner = transform_data_type_recursive(*element_type, transform_fn)?;
493 Ok(DataType::Array {
494 element_type: Box::new(inner),
495 dimension,
496 })
497 }
498 DataType::List { element_type } => {
499 let inner = transform_data_type_recursive(*element_type, transform_fn)?;
500 Ok(DataType::List {
501 element_type: Box::new(inner),
502 })
503 }
504 DataType::Struct { fields, nested } => {
505 let mut new_fields = Vec::new();
506 for mut field in fields {
507 field.data_type = transform_data_type_recursive(field.data_type, transform_fn)?;
508 new_fields.push(field);
509 }
510 Ok(DataType::Struct {
511 fields: new_fields,
512 nested,
513 })
514 }
515 DataType::Map {
516 key_type,
517 value_type,
518 } => {
519 let k = transform_data_type_recursive(*key_type, transform_fn)?;
520 let v = transform_data_type_recursive(*value_type, transform_fn)?;
521 Ok(DataType::Map {
522 key_type: Box::new(k),
523 value_type: Box::new(v),
524 })
525 }
526 other => Ok(other),
527 }
528}
529
530#[cfg(feature = "transpile")]
533fn duckdb_to_presto_format(fmt: &str) -> String {
534 let mut result = fmt.to_string();
536 result = result.replace("%-m", "\x01NOPADM\x01");
538 result = result.replace("%-d", "\x01NOPADD\x01");
539 result = result.replace("%-I", "\x01NOPADI\x01");
540 result = result.replace("%-H", "\x01NOPADH\x01");
541 result = result.replace("%H:%M:%S", "\x01HMS\x01");
542 result = result.replace("%Y-%m-%d", "\x01YMD\x01");
543 result = result.replace("%M", "%i");
545 result = result.replace("%S", "%s");
546 result = result.replace("\x01NOPADM\x01", "%c");
548 result = result.replace("\x01NOPADD\x01", "%e");
549 result = result.replace("\x01NOPADI\x01", "%l");
550 result = result.replace("\x01NOPADH\x01", "%k");
551 result = result.replace("\x01HMS\x01", "%T");
552 result = result.replace("\x01YMD\x01", "%Y-%m-%d");
553 result
554}
555
556#[cfg(feature = "transpile")]
559fn duckdb_to_bigquery_format(fmt: &str) -> String {
560 let mut result = fmt.to_string();
561 result = result.replace("%-d", "%e");
563 result = result.replace("%Y-%m-%d %H:%M:%S", "%F %T");
564 result = result.replace("%Y-%m-%d", "%F");
565 result = result.replace("%H:%M:%S", "%T");
566 result
567}
568
569#[cfg(feature = "transpile")]
570fn presto_to_java_format(fmt: &str) -> String {
571 fmt.replace("%Y", "yyyy")
572 .replace("%m", "MM")
573 .replace("%d", "dd")
574 .replace("%H", "HH")
575 .replace("%i", "mm")
576 .replace("%S", "ss")
577 .replace("%s", "ss")
578 .replace("%y", "yy")
579 .replace("%T", "HH:mm:ss")
580 .replace("%F", "yyyy-MM-dd")
581 .replace("%M", "MMMM")
582}
583
584#[cfg(feature = "transpile")]
585fn presto_to_java_parse_format(fmt: &str) -> String {
586 fmt.replace("%Y", "yyyy")
587 .replace("%m", "M")
588 .replace("%d", "d")
589 .replace("%H", "H")
590 .replace("%i", "m")
591 .replace("%S", "s")
592 .replace("%s", "s")
593 .replace("%y", "yy")
594 .replace("%T", "H:m:s")
595 .replace("%F", "yyyy-M-d")
596 .replace("%M", "MMMM")
597}
598
599#[cfg(feature = "transpile")]
600fn normalize_presto_format(fmt: &str) -> String {
601 fmt.replace("%H:%i:%S", "%T").replace("%H:%i:%s", "%T")
602}
603
604#[cfg(feature = "transpile")]
605fn presto_to_duckdb_format(fmt: &str) -> String {
606 fmt.replace("%i", "%M")
607 .replace("%s", "%S")
608 .replace("%T", "%H:%M:%S")
609}
610
611#[cfg(feature = "transpile")]
612fn presto_to_bigquery_format(fmt: &str) -> String {
613 fmt.replace("%Y-%m-%d", "%F")
614 .replace("%H:%i:%S", "%T")
615 .replace("%H:%i:%s", "%T")
616 .replace("%i", "%M")
617 .replace("%s", "%S")
618}
619
620#[cfg(feature = "transpile")]
621fn is_default_presto_timestamp_format(fmt: &str) -> bool {
622 let normalized = normalize_presto_format(fmt);
623 normalized == "%Y-%m-%d %T"
624 || normalized == "%Y-%m-%d %H:%i:%S"
625 || fmt == "%Y-%m-%d %H:%i:%S"
626 || fmt == "%Y-%m-%d %T"
627}
628
629#[cfg(feature = "transpile")]
630fn is_default_presto_date_format(fmt: &str) -> bool {
631 fmt == "%Y-%m-%d" || fmt == "%F"
632}
633
634#[cfg(any(
642 feature = "transpile",
643 feature = "ast-tools",
644 feature = "generate",
645 feature = "semantic"
646))]
647pub fn transform_recursive<F>(expr: Expression, transform_fn: &F) -> Result<Expression>
648where
649 F: Fn(Expression) -> Result<Expression>,
650{
651 #[cfg(feature = "stacker")]
652 {
653 let red_zone = if cfg!(debug_assertions) {
654 4 * 1024 * 1024
655 } else {
656 1024 * 1024
657 };
658 stacker::maybe_grow(red_zone, 8 * 1024 * 1024, move || {
659 transform_recursive_inner(expr, transform_fn)
660 })
661 }
662 #[cfg(not(feature = "stacker"))]
663 {
664 transform_recursive_inner(expr, transform_fn)
665 }
666}
667
668#[cfg(any(
669 feature = "transpile",
670 feature = "ast-tools",
671 feature = "generate",
672 feature = "semantic"
673))]
674fn transform_recursive_inner<F>(expr: Expression, transform_fn: &F) -> Result<Expression>
675where
676 F: Fn(Expression) -> Result<Expression>,
677{
678 enum Task {
679 Visit(Expression),
680 Finish {
681 shell: Expression,
682 child_count: usize,
683 },
684 }
685
686 fn uses_generated_dispatch(expression: &Expression) -> bool {
690 match expression {
691 Expression::Select(select) => {
692 select.joins.is_empty()
693 && select.with.is_none()
694 && select.order_by.is_none()
695 && select.windows.is_none()
696 && select.settings.is_none()
697 }
698 Expression::Union(set_op) => set_op.with.is_none() && set_op.order_by.is_none(),
699 Expression::Intersect(set_op) => set_op.with.is_none() && set_op.order_by.is_none(),
700 Expression::Except(set_op) => set_op.with.is_none() && set_op.order_by.is_none(),
701 Expression::Literal(_)
702 | Expression::Boolean(_)
703 | Expression::Null(_)
704 | Expression::Identifier(_)
705 | Expression::Star(_)
706 | Expression::Parameter(_)
707 | Expression::Placeholder(_)
708 | Expression::SessionParameter(_)
709 | Expression::Alias(_)
710 | Expression::Paren(_)
711 | Expression::Not(_)
712 | Expression::Neg(_)
713 | Expression::IsNull(_)
714 | Expression::IsTrue(_)
715 | Expression::IsFalse(_)
716 | Expression::Subquery(_)
717 | Expression::Exists(_)
718 | Expression::Any(_)
719 | Expression::All(_)
720 | Expression::TableArgument(_)
721 | Expression::And(_)
722 | Expression::Or(_)
723 | Expression::Add(_)
724 | Expression::Sub(_)
725 | Expression::Mul(_)
726 | Expression::Div(_)
727 | Expression::Eq(_)
728 | Expression::NullSafeEq(_)
729 | Expression::NullSafeNeq(_)
730 | Expression::Lt(_)
731 | Expression::Gt(_)
732 | Expression::Neq(_)
733 | Expression::Lte(_)
734 | Expression::Gte(_)
735 | Expression::Mod(_)
736 | Expression::Concat(_)
737 | Expression::BitwiseAnd(_)
738 | Expression::BitwiseOr(_)
739 | Expression::BitwiseXor(_)
740 | Expression::Is(_)
741 | Expression::MemberOf(_)
742 | Expression::ArrayContainsAll(_)
743 | Expression::ArrayContainedBy(_)
744 | Expression::ArrayOverlaps(_)
745 | Expression::TsMatch(_)
746 | Expression::Adjacent(_)
747 | Expression::Like(_)
748 | Expression::ILike(_)
749 | Expression::Function(_)
750 | Expression::Lead(_)
751 | Expression::Lag(_)
752 | Expression::Array(_)
753 | Expression::Tuple(_)
754 | Expression::ArrayFunc(_)
755 | Expression::Coalesce(_)
756 | Expression::Greatest(_)
757 | Expression::Least(_)
758 | Expression::ArrayConcat(_)
759 | Expression::ArrayIntersect(_)
760 | Expression::ArrayZip(_)
761 | Expression::MapConcat(_)
762 | Expression::JsonArray(_)
763 | Expression::From(_) => true,
764 _ => false,
765 }
766 }
767
768 let mut tasks = vec![Task::Visit(expr)];
769 let mut results = Vec::new();
770
771 while let Some(task) = tasks.pop() {
772 match task {
773 Task::Visit(mut expression) => {
774 if !uses_generated_dispatch(&expression) {
775 results.push(transform_recursive_reference(expression, transform_fn)?);
776 continue;
777 }
778
779 let mut children = Vec::new();
780 crate::ast_children::for_each_child_mut(&mut expression, |child| {
781 children.push(std::mem::replace(child, Expression::Null(Null)));
782 });
783 let child_count = children.len();
784 tasks.push(Task::Finish {
785 shell: expression,
786 child_count,
787 });
788 for child in children.into_iter().rev() {
789 tasks.push(Task::Visit(child));
790 }
791 }
792 Task::Finish {
793 mut shell,
794 child_count,
795 } => {
796 if results.len() < child_count {
797 return Err(crate::error::Error::Internal(
798 "transform result stack underflow".to_string(),
799 ));
800 }
801 let transformed_children = results.split_off(results.len() - child_count);
802 let mut transformed_children = transformed_children.into_iter();
803 crate::ast_children::for_each_child_mut(&mut shell, |child| {
804 *child = transformed_children
805 .next()
806 .expect("validated transform child count");
807 });
808 if transformed_children.next().is_some() {
809 return Err(crate::error::Error::Internal(
810 "transform child restoration mismatch".to_string(),
811 ));
812 }
813 results.push(transform_fn(shell)?);
814 }
815 }
816 }
817
818 match results.len() {
819 1 => Ok(results.pop().expect("single transform result")),
820 _ => Err(crate::error::Error::Internal(
821 "unexpected transform result stack size".to_string(),
822 )),
823 }
824}
825
826#[cfg(any(
827 feature = "transpile",
828 feature = "ast-tools",
829 feature = "generate",
830 feature = "semantic"
831))]
832fn transform_table_ref_recursive<F>(table: TableRef, transform_fn: &F) -> Result<TableRef>
833where
834 F: Fn(Expression) -> Result<Expression>,
835{
836 match transform_recursive(Expression::Table(Box::new(table)), transform_fn)? {
837 Expression::Table(table) => Ok(*table),
838 _ => Err(crate::error::Error::parse(
839 "TableRef transformation returned non-table expression",
840 0,
841 0,
842 0,
843 0,
844 )),
845 }
846}
847
848#[cfg(any(
849 feature = "transpile",
850 feature = "ast-tools",
851 feature = "generate",
852 feature = "semantic"
853))]
854fn transform_from_recursive<F>(from: From, transform_fn: &F) -> Result<From>
855where
856 F: Fn(Expression) -> Result<Expression>,
857{
858 match transform_recursive(Expression::From(Box::new(from)), transform_fn)? {
859 Expression::From(from) => Ok(*from),
860 _ => Err(crate::error::Error::parse(
861 "FROM transformation returned non-FROM expression",
862 0,
863 0,
864 0,
865 0,
866 )),
867 }
868}
869
870#[cfg(any(
871 feature = "transpile",
872 feature = "ast-tools",
873 feature = "generate",
874 feature = "semantic"
875))]
876fn transform_join_recursive<F>(mut join: Join, transform_fn: &F) -> Result<Join>
877where
878 F: Fn(Expression) -> Result<Expression>,
879{
880 join.this = transform_recursive(join.this, transform_fn)?;
881 if let Some(on) = join.on.take() {
882 join.on = Some(transform_recursive(on, transform_fn)?);
883 }
884 if let Some(match_condition) = join.match_condition.take() {
885 join.match_condition = Some(transform_recursive(match_condition, transform_fn)?);
886 }
887 join.pivots = join
888 .pivots
889 .into_iter()
890 .map(|pivot| transform_recursive(pivot, transform_fn))
891 .collect::<Result<Vec<_>>>()?;
892
893 match transform_fn(Expression::Join(Box::new(join)))? {
894 Expression::Join(join) => Ok(*join),
895 _ => Err(crate::error::Error::parse(
896 "Join transformation returned non-join expression",
897 0,
898 0,
899 0,
900 0,
901 )),
902 }
903}
904
905#[cfg(any(
906 feature = "transpile",
907 feature = "ast-tools",
908 feature = "generate",
909 feature = "semantic"
910))]
911fn transform_output_clause_recursive<F>(
912 mut output: OutputClause,
913 transform_fn: &F,
914) -> Result<OutputClause>
915where
916 F: Fn(Expression) -> Result<Expression>,
917{
918 output.columns = output
919 .columns
920 .into_iter()
921 .map(|column| transform_recursive(column, transform_fn))
922 .collect::<Result<Vec<_>>>()?;
923 if let Some(into_table) = output.into_table.take() {
924 output.into_table = Some(transform_recursive(into_table, transform_fn)?);
925 }
926 Ok(output)
927}
928
929#[cfg(any(
930 feature = "transpile",
931 feature = "ast-tools",
932 feature = "generate",
933 feature = "semantic"
934))]
935fn transform_with_recursive<F>(mut with: With, transform_fn: &F) -> Result<With>
936where
937 F: Fn(Expression) -> Result<Expression>,
938{
939 with.ctes = with
940 .ctes
941 .into_iter()
942 .map(|mut cte| {
943 cte.this = transform_recursive(cte.this, transform_fn)?;
944 Ok(cte)
945 })
946 .collect::<Result<Vec<_>>>()?;
947 if let Some(search) = with.search.take() {
948 with.search = Some(Box::new(transform_recursive(*search, transform_fn)?));
949 }
950 Ok(with)
951}
952
953#[cfg(any(
954 feature = "transpile",
955 feature = "ast-tools",
956 feature = "generate",
957 feature = "semantic"
958))]
959fn transform_order_by_recursive<F>(mut order: OrderBy, transform_fn: &F) -> Result<OrderBy>
960where
961 F: Fn(Expression) -> Result<Expression>,
962{
963 order.expressions = order
964 .expressions
965 .into_iter()
966 .map(|mut ordered| {
967 let original = ordered.this.clone();
968 ordered.this = transform_recursive(ordered.this, transform_fn).unwrap_or(original);
969 match transform_fn(Expression::Ordered(Box::new(ordered.clone()))) {
970 Ok(Expression::Ordered(transformed)) => Ok(*transformed),
971 Ok(_) | Err(_) => Ok(ordered),
972 }
973 })
974 .collect::<Result<Vec<_>>>()?;
975 Ok(order)
976}
977
978#[cfg(any(
979 feature = "transpile",
980 feature = "ast-tools",
981 feature = "generate",
982 feature = "semantic"
983))]
984fn transform_recursive_reference<F>(expr: Expression, transform_fn: &F) -> Result<Expression>
985where
986 F: Fn(Expression) -> Result<Expression>,
987{
988 use crate::expressions::BinaryOp;
989
990 macro_rules! recurse_agg {
992 ($variant:ident, $f:expr) => {{
993 let mut f = $f;
994 f.this = transform_recursive(f.this, transform_fn)?;
995 if let Some(filter) = f.filter.take() {
996 f.filter = Some(transform_recursive(filter, transform_fn)?);
997 }
998 for ord in &mut f.order_by {
999 ord.this = transform_recursive(
1000 std::mem::replace(&mut ord.this, Expression::Null(crate::expressions::Null)),
1001 transform_fn,
1002 )?;
1003 }
1004 if let Some((ref mut expr, _)) = f.having_max {
1005 *expr = Box::new(transform_recursive(
1006 std::mem::replace(expr.as_mut(), Expression::Null(crate::expressions::Null)),
1007 transform_fn,
1008 )?);
1009 }
1010 if let Some(limit) = f.limit.take() {
1011 f.limit = Some(Box::new(transform_recursive(*limit, transform_fn)?));
1012 }
1013 Expression::$variant(f)
1014 }};
1015 }
1016
1017 macro_rules! transform_binary {
1019 ($variant:ident, $op:expr) => {{
1020 let left = transform_recursive($op.left, transform_fn)?;
1021 let right = transform_recursive($op.right, transform_fn)?;
1022 Expression::$variant(Box::new(BinaryOp {
1023 left,
1024 right,
1025 left_comments: $op.left_comments,
1026 operator_comments: $op.operator_comments,
1027 trailing_comments: $op.trailing_comments,
1028 inferred_type: $op.inferred_type,
1029 }))
1030 }};
1031 }
1032
1033 if matches!(
1035 &expr,
1036 Expression::Literal(_)
1037 | Expression::Boolean(_)
1038 | Expression::Null(_)
1039 | Expression::Identifier(_)
1040 | Expression::Star(_)
1041 | Expression::Parameter(_)
1042 | Expression::Placeholder(_)
1043 | Expression::SessionParameter(_)
1044 ) {
1045 return transform_fn(expr);
1046 }
1047
1048 let expr = match expr {
1050 Expression::Select(mut select) => {
1051 select.expressions = select
1052 .expressions
1053 .into_iter()
1054 .map(|e| transform_recursive(e, transform_fn))
1055 .collect::<Result<Vec<_>>>()?;
1056
1057 if let Some(mut from) = select.from.take() {
1059 from.expressions = from
1060 .expressions
1061 .into_iter()
1062 .map(|e| transform_recursive(e, transform_fn))
1063 .collect::<Result<Vec<_>>>()?;
1064 select.from = Some(from);
1065 }
1066
1067 select.joins = select
1069 .joins
1070 .into_iter()
1071 .map(|mut join| {
1072 join.this = transform_recursive(join.this, transform_fn)?;
1073 if let Some(on) = join.on.take() {
1074 join.on = Some(transform_recursive(on, transform_fn)?);
1075 }
1076 match transform_fn(Expression::Join(Box::new(join)))? {
1078 Expression::Join(j) => Ok(*j),
1079 _ => Err(crate::error::Error::parse(
1080 "Join transformation returned non-join expression",
1081 0,
1082 0,
1083 0,
1084 0,
1085 )),
1086 }
1087 })
1088 .collect::<Result<Vec<_>>>()?;
1089
1090 select.lateral_views = select
1092 .lateral_views
1093 .into_iter()
1094 .map(|mut lv| {
1095 lv.this = transform_recursive(lv.this, transform_fn)?;
1096 Ok(lv)
1097 })
1098 .collect::<Result<Vec<_>>>()?;
1099
1100 if let Some(mut where_clause) = select.where_clause.take() {
1102 where_clause.this = transform_recursive(where_clause.this, transform_fn)?;
1103 select.where_clause = Some(where_clause);
1104 }
1105
1106 if let Some(mut group_by) = select.group_by.take() {
1108 group_by.expressions = group_by
1109 .expressions
1110 .into_iter()
1111 .map(|e| transform_recursive(e, transform_fn))
1112 .collect::<Result<Vec<_>>>()?;
1113 select.group_by = Some(group_by);
1114 }
1115
1116 if let Some(mut having) = select.having.take() {
1118 having.this = transform_recursive(having.this, transform_fn)?;
1119 select.having = Some(having);
1120 }
1121
1122 if let Some(mut with) = select.with.take() {
1124 with.ctes = with
1125 .ctes
1126 .into_iter()
1127 .map(|mut cte| {
1128 let original = cte.this.clone();
1129 cte.this = transform_recursive(cte.this, transform_fn).unwrap_or(original);
1130 cte
1131 })
1132 .collect();
1133 select.with = Some(with);
1134 }
1135
1136 if let Some(mut order) = select.order_by.take() {
1138 order.expressions = order
1139 .expressions
1140 .into_iter()
1141 .map(|o| {
1142 let mut o = o;
1143 let original = o.this.clone();
1144 o.this = transform_recursive(o.this, transform_fn).unwrap_or(original);
1145 match transform_fn(Expression::Ordered(Box::new(o.clone()))) {
1147 Ok(Expression::Ordered(transformed)) => *transformed,
1148 Ok(_) | Err(_) => o,
1149 }
1150 })
1151 .collect();
1152 select.order_by = Some(order);
1153 }
1154
1155 if let Some(ref mut windows) = select.windows {
1157 for nw in windows.iter_mut() {
1158 nw.spec.order_by = std::mem::take(&mut nw.spec.order_by)
1159 .into_iter()
1160 .map(|o| {
1161 let mut o = o;
1162 let original = o.this.clone();
1163 o.this = transform_recursive(o.this, transform_fn).unwrap_or(original);
1164 match transform_fn(Expression::Ordered(Box::new(o.clone()))) {
1165 Ok(Expression::Ordered(transformed)) => *transformed,
1166 Ok(_) | Err(_) => o,
1167 }
1168 })
1169 .collect();
1170 }
1171 }
1172
1173 if let Some(mut qual) = select.qualify.take() {
1175 qual.this = transform_recursive(qual.this, transform_fn)?;
1176 select.qualify = Some(qual);
1177 }
1178
1179 Expression::Select(select)
1180 }
1181 Expression::Function(mut f) => {
1182 f.args = f
1183 .args
1184 .into_iter()
1185 .map(|e| transform_recursive(e, transform_fn))
1186 .collect::<Result<Vec<_>>>()?;
1187 Expression::Function(f)
1188 }
1189 Expression::AggregateFunction(mut f) => {
1190 f.args = f
1191 .args
1192 .into_iter()
1193 .map(|e| transform_recursive(e, transform_fn))
1194 .collect::<Result<Vec<_>>>()?;
1195 if let Some(filter) = f.filter {
1196 f.filter = Some(transform_recursive(filter, transform_fn)?);
1197 }
1198 Expression::AggregateFunction(f)
1199 }
1200 Expression::WindowFunction(mut wf) => {
1201 wf.this = transform_recursive(wf.this, transform_fn)?;
1202 wf.over.partition_by = wf
1203 .over
1204 .partition_by
1205 .into_iter()
1206 .map(|e| transform_recursive(e, transform_fn))
1207 .collect::<Result<Vec<_>>>()?;
1208 wf.over.order_by = wf
1210 .over
1211 .order_by
1212 .into_iter()
1213 .map(|o| {
1214 let mut o = o;
1215 o.this = transform_recursive(o.this, transform_fn)?;
1216 match transform_fn(Expression::Ordered(Box::new(o)))? {
1217 Expression::Ordered(transformed) => Ok(*transformed),
1218 _ => Err(crate::error::Error::parse(
1219 "Ordered transformation returned non-Ordered expression",
1220 0,
1221 0,
1222 0,
1223 0,
1224 )),
1225 }
1226 })
1227 .collect::<Result<Vec<_>>>()?;
1228 Expression::WindowFunction(wf)
1229 }
1230 Expression::Alias(mut a) => {
1231 a.this = transform_recursive(a.this, transform_fn)?;
1232 Expression::Alias(a)
1233 }
1234 Expression::Cast(mut c) => {
1235 c.this = transform_recursive(c.this, transform_fn)?;
1236 c.to = transform_data_type_recursive(c.to, transform_fn)?;
1238 Expression::Cast(c)
1239 }
1240 Expression::And(op) => transform_binary!(And, *op),
1241 Expression::Or(op) => transform_binary!(Or, *op),
1242 Expression::Add(op) => transform_binary!(Add, *op),
1243 Expression::Sub(op) => transform_binary!(Sub, *op),
1244 Expression::Mul(op) => transform_binary!(Mul, *op),
1245 Expression::Div(op) => transform_binary!(Div, *op),
1246 Expression::Eq(op) => transform_binary!(Eq, *op),
1247 Expression::Lt(op) => transform_binary!(Lt, *op),
1248 Expression::Gt(op) => transform_binary!(Gt, *op),
1249 Expression::Paren(mut p) => {
1250 p.this = transform_recursive(p.this, transform_fn)?;
1251 Expression::Paren(p)
1252 }
1253 Expression::Coalesce(mut f) => {
1254 f.expressions = f
1255 .expressions
1256 .into_iter()
1257 .map(|e| transform_recursive(e, transform_fn))
1258 .collect::<Result<Vec<_>>>()?;
1259 Expression::Coalesce(f)
1260 }
1261 Expression::IfNull(mut f) => {
1262 f.this = transform_recursive(f.this, transform_fn)?;
1263 f.expression = transform_recursive(f.expression, transform_fn)?;
1264 Expression::IfNull(f)
1265 }
1266 Expression::Nvl(mut f) => {
1267 f.this = transform_recursive(f.this, transform_fn)?;
1268 f.expression = transform_recursive(f.expression, transform_fn)?;
1269 Expression::Nvl(f)
1270 }
1271 Expression::In(mut i) => {
1272 i.this = transform_recursive(i.this, transform_fn)?;
1273 i.expressions = i
1274 .expressions
1275 .into_iter()
1276 .map(|e| transform_recursive(e, transform_fn))
1277 .collect::<Result<Vec<_>>>()?;
1278 if let Some(query) = i.query {
1279 i.query = Some(transform_recursive(query, transform_fn)?);
1280 }
1281 Expression::In(i)
1282 }
1283 Expression::Not(mut n) => {
1284 n.this = transform_recursive(n.this, transform_fn)?;
1285 Expression::Not(n)
1286 }
1287 Expression::ArraySlice(mut s) => {
1288 s.this = transform_recursive(s.this, transform_fn)?;
1289 if let Some(start) = s.start {
1290 s.start = Some(transform_recursive(start, transform_fn)?);
1291 }
1292 if let Some(end) = s.end {
1293 s.end = Some(transform_recursive(end, transform_fn)?);
1294 }
1295 Expression::ArraySlice(s)
1296 }
1297 Expression::Subscript(mut s) => {
1298 s.this = transform_recursive(s.this, transform_fn)?;
1299 s.index = transform_recursive(s.index, transform_fn)?;
1300 Expression::Subscript(s)
1301 }
1302 Expression::Array(mut a) => {
1303 a.expressions = a
1304 .expressions
1305 .into_iter()
1306 .map(|e| transform_recursive(e, transform_fn))
1307 .collect::<Result<Vec<_>>>()?;
1308 Expression::Array(a)
1309 }
1310 Expression::Struct(mut s) => {
1311 let mut new_fields = Vec::new();
1312 for (name, expr) in s.fields {
1313 let transformed = transform_recursive(expr, transform_fn)?;
1314 new_fields.push((name, transformed));
1315 }
1316 s.fields = new_fields;
1317 Expression::Struct(s)
1318 }
1319 Expression::NamedArgument(mut na) => {
1320 na.value = transform_recursive(na.value, transform_fn)?;
1321 Expression::NamedArgument(na)
1322 }
1323 Expression::MapFunc(mut m) => {
1324 m.keys = m
1325 .keys
1326 .into_iter()
1327 .map(|e| transform_recursive(e, transform_fn))
1328 .collect::<Result<Vec<_>>>()?;
1329 m.values = m
1330 .values
1331 .into_iter()
1332 .map(|e| transform_recursive(e, transform_fn))
1333 .collect::<Result<Vec<_>>>()?;
1334 Expression::MapFunc(m)
1335 }
1336 Expression::ArrayFunc(mut a) => {
1337 a.expressions = a
1338 .expressions
1339 .into_iter()
1340 .map(|e| transform_recursive(e, transform_fn))
1341 .collect::<Result<Vec<_>>>()?;
1342 Expression::ArrayFunc(a)
1343 }
1344 Expression::Lambda(mut l) => {
1345 l.body = transform_recursive(l.body, transform_fn)?;
1346 Expression::Lambda(l)
1347 }
1348 Expression::JsonExtract(mut f) => {
1349 f.this = transform_recursive(f.this, transform_fn)?;
1350 f.path = transform_recursive(f.path, transform_fn)?;
1351 Expression::JsonExtract(f)
1352 }
1353 Expression::JsonExtractScalar(mut f) => {
1354 f.this = transform_recursive(f.this, transform_fn)?;
1355 f.path = transform_recursive(f.path, transform_fn)?;
1356 Expression::JsonExtractScalar(f)
1357 }
1358
1359 Expression::Length(mut f) => {
1362 f.this = transform_recursive(f.this, transform_fn)?;
1363 Expression::Length(f)
1364 }
1365 Expression::Upper(mut f) => {
1366 f.this = transform_recursive(f.this, transform_fn)?;
1367 Expression::Upper(f)
1368 }
1369 Expression::Lower(mut f) => {
1370 f.this = transform_recursive(f.this, transform_fn)?;
1371 Expression::Lower(f)
1372 }
1373 Expression::LTrim(mut f) => {
1374 f.this = transform_recursive(f.this, transform_fn)?;
1375 Expression::LTrim(f)
1376 }
1377 Expression::RTrim(mut f) => {
1378 f.this = transform_recursive(f.this, transform_fn)?;
1379 Expression::RTrim(f)
1380 }
1381 Expression::Reverse(mut f) => {
1382 f.this = transform_recursive(f.this, transform_fn)?;
1383 Expression::Reverse(f)
1384 }
1385 Expression::Abs(mut f) => {
1386 f.this = transform_recursive(f.this, transform_fn)?;
1387 Expression::Abs(f)
1388 }
1389 Expression::Ceil(mut f) => {
1390 f.this = transform_recursive(f.this, transform_fn)?;
1391 Expression::Ceil(f)
1392 }
1393 Expression::Floor(mut f) => {
1394 f.this = transform_recursive(f.this, transform_fn)?;
1395 Expression::Floor(f)
1396 }
1397 Expression::Sign(mut f) => {
1398 f.this = transform_recursive(f.this, transform_fn)?;
1399 Expression::Sign(f)
1400 }
1401 Expression::Sqrt(mut f) => {
1402 f.this = transform_recursive(f.this, transform_fn)?;
1403 Expression::Sqrt(f)
1404 }
1405 Expression::Cbrt(mut f) => {
1406 f.this = transform_recursive(f.this, transform_fn)?;
1407 Expression::Cbrt(f)
1408 }
1409 Expression::Ln(mut f) => {
1410 f.this = transform_recursive(f.this, transform_fn)?;
1411 Expression::Ln(f)
1412 }
1413 Expression::Log(mut f) => {
1414 f.this = transform_recursive(f.this, transform_fn)?;
1415 if let Some(base) = f.base {
1416 f.base = Some(transform_recursive(base, transform_fn)?);
1417 }
1418 Expression::Log(f)
1419 }
1420 Expression::Exp(mut f) => {
1421 f.this = transform_recursive(f.this, transform_fn)?;
1422 Expression::Exp(f)
1423 }
1424 Expression::Date(mut f) => {
1425 f.this = transform_recursive(f.this, transform_fn)?;
1426 Expression::Date(f)
1427 }
1428 Expression::Stddev(f) => recurse_agg!(Stddev, f),
1429 Expression::StddevSamp(f) => recurse_agg!(StddevSamp, f),
1430 Expression::Variance(f) => recurse_agg!(Variance, f),
1431
1432 Expression::ModFunc(mut f) => {
1434 f.this = transform_recursive(f.this, transform_fn)?;
1435 f.expression = transform_recursive(f.expression, transform_fn)?;
1436 Expression::ModFunc(f)
1437 }
1438 Expression::Power(mut f) => {
1439 f.this = transform_recursive(f.this, transform_fn)?;
1440 f.expression = transform_recursive(f.expression, transform_fn)?;
1441 Expression::Power(f)
1442 }
1443 Expression::MapFromArrays(mut f) => {
1444 f.this = transform_recursive(f.this, transform_fn)?;
1445 f.expression = transform_recursive(f.expression, transform_fn)?;
1446 Expression::MapFromArrays(f)
1447 }
1448 Expression::ElementAt(mut f) => {
1449 f.this = transform_recursive(f.this, transform_fn)?;
1450 f.expression = transform_recursive(f.expression, transform_fn)?;
1451 Expression::ElementAt(f)
1452 }
1453 Expression::MapContainsKey(mut f) => {
1454 f.this = transform_recursive(f.this, transform_fn)?;
1455 f.expression = transform_recursive(f.expression, transform_fn)?;
1456 Expression::MapContainsKey(f)
1457 }
1458 Expression::Left(mut f) => {
1459 f.this = transform_recursive(f.this, transform_fn)?;
1460 f.length = transform_recursive(f.length, transform_fn)?;
1461 Expression::Left(f)
1462 }
1463 Expression::Right(mut f) => {
1464 f.this = transform_recursive(f.this, transform_fn)?;
1465 f.length = transform_recursive(f.length, transform_fn)?;
1466 Expression::Right(f)
1467 }
1468 Expression::Repeat(mut f) => {
1469 f.this = transform_recursive(f.this, transform_fn)?;
1470 f.times = transform_recursive(f.times, transform_fn)?;
1471 Expression::Repeat(f)
1472 }
1473
1474 Expression::Substring(mut f) => {
1476 f.this = transform_recursive(f.this, transform_fn)?;
1477 f.start = transform_recursive(f.start, transform_fn)?;
1478 if let Some(len) = f.length {
1479 f.length = Some(transform_recursive(len, transform_fn)?);
1480 }
1481 Expression::Substring(f)
1482 }
1483 Expression::Replace(mut f) => {
1484 f.this = transform_recursive(f.this, transform_fn)?;
1485 f.old = transform_recursive(f.old, transform_fn)?;
1486 f.new = transform_recursive(f.new, transform_fn)?;
1487 Expression::Replace(f)
1488 }
1489 Expression::ConcatWs(mut f) => {
1490 f.separator = transform_recursive(f.separator, transform_fn)?;
1491 f.expressions = f
1492 .expressions
1493 .into_iter()
1494 .map(|e| transform_recursive(e, transform_fn))
1495 .collect::<Result<Vec<_>>>()?;
1496 Expression::ConcatWs(f)
1497 }
1498 Expression::Trim(mut f) => {
1499 f.this = transform_recursive(f.this, transform_fn)?;
1500 if let Some(chars) = f.characters {
1501 f.characters = Some(transform_recursive(chars, transform_fn)?);
1502 }
1503 Expression::Trim(f)
1504 }
1505 Expression::Split(mut f) => {
1506 f.this = transform_recursive(f.this, transform_fn)?;
1507 f.delimiter = transform_recursive(f.delimiter, transform_fn)?;
1508 Expression::Split(f)
1509 }
1510 Expression::Lpad(mut f) => {
1511 f.this = transform_recursive(f.this, transform_fn)?;
1512 f.length = transform_recursive(f.length, transform_fn)?;
1513 if let Some(fill) = f.fill {
1514 f.fill = Some(transform_recursive(fill, transform_fn)?);
1515 }
1516 Expression::Lpad(f)
1517 }
1518 Expression::Rpad(mut f) => {
1519 f.this = transform_recursive(f.this, transform_fn)?;
1520 f.length = transform_recursive(f.length, transform_fn)?;
1521 if let Some(fill) = f.fill {
1522 f.fill = Some(transform_recursive(fill, transform_fn)?);
1523 }
1524 Expression::Rpad(f)
1525 }
1526
1527 Expression::Case(mut c) => {
1529 if let Some(operand) = c.operand {
1530 c.operand = Some(transform_recursive(operand, transform_fn)?);
1531 }
1532 c.whens = c
1533 .whens
1534 .into_iter()
1535 .map(|(cond, then)| {
1536 let new_cond = transform_recursive(cond.clone(), transform_fn).unwrap_or(cond);
1537 let new_then = transform_recursive(then.clone(), transform_fn).unwrap_or(then);
1538 (new_cond, new_then)
1539 })
1540 .collect();
1541 if let Some(else_expr) = c.else_ {
1542 c.else_ = Some(transform_recursive(else_expr, transform_fn)?);
1543 }
1544 Expression::Case(c)
1545 }
1546 Expression::IfFunc(mut f) => {
1547 f.condition = transform_recursive(f.condition, transform_fn)?;
1548 f.true_value = transform_recursive(f.true_value, transform_fn)?;
1549 if let Some(false_val) = f.false_value {
1550 f.false_value = Some(transform_recursive(false_val, transform_fn)?);
1551 }
1552 Expression::IfFunc(f)
1553 }
1554
1555 Expression::DateAdd(mut f) => {
1557 f.this = transform_recursive(f.this, transform_fn)?;
1558 f.interval = transform_recursive(f.interval, transform_fn)?;
1559 Expression::DateAdd(f)
1560 }
1561 Expression::DateSub(mut f) => {
1562 f.this = transform_recursive(f.this, transform_fn)?;
1563 f.interval = transform_recursive(f.interval, transform_fn)?;
1564 Expression::DateSub(f)
1565 }
1566 Expression::DateDiff(mut f) => {
1567 f.this = transform_recursive(f.this, transform_fn)?;
1568 f.expression = transform_recursive(f.expression, transform_fn)?;
1569 Expression::DateDiff(f)
1570 }
1571 Expression::DateTrunc(mut f) => {
1572 f.this = transform_recursive(f.this, transform_fn)?;
1573 Expression::DateTrunc(f)
1574 }
1575 Expression::Extract(mut f) => {
1576 f.this = transform_recursive(f.this, transform_fn)?;
1577 Expression::Extract(f)
1578 }
1579
1580 Expression::JsonObject(mut f) => {
1582 f.pairs = f
1583 .pairs
1584 .into_iter()
1585 .map(|(k, v)| {
1586 let new_k = transform_recursive(k, transform_fn)?;
1587 let new_v = transform_recursive(v, transform_fn)?;
1588 Ok((new_k, new_v))
1589 })
1590 .collect::<Result<Vec<_>>>()?;
1591 Expression::JsonObject(f)
1592 }
1593
1594 Expression::Subquery(mut s) => {
1596 s.this = transform_recursive(s.this, transform_fn)?;
1597 Expression::Subquery(s)
1598 }
1599 Expression::Exists(mut e) => {
1600 e.this = transform_recursive(e.this, transform_fn)?;
1601 Expression::Exists(e)
1602 }
1603 Expression::Describe(mut d) => {
1604 d.target = transform_recursive(d.target, transform_fn)?;
1605 Expression::Describe(d)
1606 }
1607
1608 Expression::Union(mut u) => {
1610 let left = std::mem::replace(&mut u.left, Expression::Null(Null));
1611 u.left = transform_recursive(left, transform_fn)?;
1612 let right = std::mem::replace(&mut u.right, Expression::Null(Null));
1613 u.right = transform_recursive(right, transform_fn)?;
1614 if let Some(mut order) = u.order_by.take() {
1615 order.expressions = order
1616 .expressions
1617 .into_iter()
1618 .map(|o| {
1619 let mut o = o;
1620 let original = o.this.clone();
1621 o.this = transform_recursive(o.this, transform_fn).unwrap_or(original);
1622 match transform_fn(Expression::Ordered(Box::new(o.clone()))) {
1623 Ok(Expression::Ordered(transformed)) => *transformed,
1624 Ok(_) | Err(_) => o,
1625 }
1626 })
1627 .collect();
1628 u.order_by = Some(order);
1629 }
1630 if let Some(mut with) = u.with.take() {
1631 with.ctes = with
1632 .ctes
1633 .into_iter()
1634 .map(|mut cte| {
1635 let original = cte.this.clone();
1636 cte.this = transform_recursive(cte.this, transform_fn).unwrap_or(original);
1637 cte
1638 })
1639 .collect();
1640 u.with = Some(with);
1641 }
1642 Expression::Union(u)
1643 }
1644 Expression::Intersect(mut i) => {
1645 let left = std::mem::replace(&mut i.left, Expression::Null(Null));
1646 i.left = transform_recursive(left, transform_fn)?;
1647 let right = std::mem::replace(&mut i.right, Expression::Null(Null));
1648 i.right = transform_recursive(right, transform_fn)?;
1649 if let Some(mut order) = i.order_by.take() {
1650 order.expressions = order
1651 .expressions
1652 .into_iter()
1653 .map(|o| {
1654 let mut o = o;
1655 let original = o.this.clone();
1656 o.this = transform_recursive(o.this, transform_fn).unwrap_or(original);
1657 match transform_fn(Expression::Ordered(Box::new(o.clone()))) {
1658 Ok(Expression::Ordered(transformed)) => *transformed,
1659 Ok(_) | Err(_) => o,
1660 }
1661 })
1662 .collect();
1663 i.order_by = Some(order);
1664 }
1665 if let Some(mut with) = i.with.take() {
1666 with.ctes = with
1667 .ctes
1668 .into_iter()
1669 .map(|mut cte| {
1670 let original = cte.this.clone();
1671 cte.this = transform_recursive(cte.this, transform_fn).unwrap_or(original);
1672 cte
1673 })
1674 .collect();
1675 i.with = Some(with);
1676 }
1677 Expression::Intersect(i)
1678 }
1679 Expression::Except(mut e) => {
1680 let left = std::mem::replace(&mut e.left, Expression::Null(Null));
1681 e.left = transform_recursive(left, transform_fn)?;
1682 let right = std::mem::replace(&mut e.right, Expression::Null(Null));
1683 e.right = transform_recursive(right, transform_fn)?;
1684 if let Some(mut order) = e.order_by.take() {
1685 order.expressions = order
1686 .expressions
1687 .into_iter()
1688 .map(|o| {
1689 let mut o = o;
1690 let original = o.this.clone();
1691 o.this = transform_recursive(o.this, transform_fn).unwrap_or(original);
1692 match transform_fn(Expression::Ordered(Box::new(o.clone()))) {
1693 Ok(Expression::Ordered(transformed)) => *transformed,
1694 Ok(_) | Err(_) => o,
1695 }
1696 })
1697 .collect();
1698 e.order_by = Some(order);
1699 }
1700 if let Some(mut with) = e.with.take() {
1701 with.ctes = with
1702 .ctes
1703 .into_iter()
1704 .map(|mut cte| {
1705 let original = cte.this.clone();
1706 cte.this = transform_recursive(cte.this, transform_fn).unwrap_or(original);
1707 cte
1708 })
1709 .collect();
1710 e.with = Some(with);
1711 }
1712 Expression::Except(e)
1713 }
1714
1715 Expression::Insert(mut ins) => {
1717 let mut new_values = Vec::new();
1719 for row in ins.values {
1720 let mut new_row = Vec::new();
1721 for e in row {
1722 new_row.push(transform_recursive(e, transform_fn)?);
1723 }
1724 new_values.push(new_row);
1725 }
1726 ins.values = new_values;
1727
1728 if let Some(query) = ins.query {
1730 ins.query = Some(transform_recursive(query, transform_fn)?);
1731 }
1732
1733 let mut new_returning = Vec::new();
1735 for e in ins.returning {
1736 new_returning.push(transform_recursive(e, transform_fn)?);
1737 }
1738 ins.returning = new_returning;
1739
1740 if let Some(on_conflict) = ins.on_conflict {
1742 ins.on_conflict = Some(Box::new(transform_recursive(*on_conflict, transform_fn)?));
1743 }
1744
1745 Expression::Insert(ins)
1746 }
1747 Expression::Update(mut upd) => {
1748 upd.table = transform_table_ref_recursive(upd.table, transform_fn)?;
1749 upd.extra_tables = upd
1750 .extra_tables
1751 .into_iter()
1752 .map(|table| transform_table_ref_recursive(table, transform_fn))
1753 .collect::<Result<Vec<_>>>()?;
1754 upd.table_joins = upd
1755 .table_joins
1756 .into_iter()
1757 .map(|join| transform_join_recursive(join, transform_fn))
1758 .collect::<Result<Vec<_>>>()?;
1759 upd.set = upd
1760 .set
1761 .into_iter()
1762 .map(|(id, val)| {
1763 let new_val = transform_recursive(val.clone(), transform_fn).unwrap_or(val);
1764 (id, new_val)
1765 })
1766 .collect();
1767 if let Some(from_clause) = upd.from_clause.take() {
1768 upd.from_clause = Some(transform_from_recursive(from_clause, transform_fn)?);
1769 }
1770 upd.from_joins = upd
1771 .from_joins
1772 .into_iter()
1773 .map(|join| transform_join_recursive(join, transform_fn))
1774 .collect::<Result<Vec<_>>>()?;
1775 if let Some(mut where_clause) = upd.where_clause.take() {
1776 where_clause.this = transform_recursive(where_clause.this, transform_fn)?;
1777 upd.where_clause = Some(where_clause);
1778 }
1779 upd.returning = upd
1780 .returning
1781 .into_iter()
1782 .map(|expr| transform_recursive(expr, transform_fn))
1783 .collect::<Result<Vec<_>>>()?;
1784 if let Some(output) = upd.output.take() {
1785 upd.output = Some(transform_output_clause_recursive(output, transform_fn)?);
1786 }
1787 if let Some(with) = upd.with.take() {
1788 upd.with = Some(transform_with_recursive(with, transform_fn)?);
1789 }
1790 if let Some(limit) = upd.limit.take() {
1791 upd.limit = Some(transform_recursive(limit, transform_fn)?);
1792 }
1793 if let Some(order_by) = upd.order_by.take() {
1794 upd.order_by = Some(transform_order_by_recursive(order_by, transform_fn)?);
1795 }
1796 Expression::Update(upd)
1797 }
1798 Expression::Delete(mut del) => {
1799 del.table = transform_table_ref_recursive(del.table, transform_fn)?;
1800 del.using = del
1801 .using
1802 .into_iter()
1803 .map(|table| transform_table_ref_recursive(table, transform_fn))
1804 .collect::<Result<Vec<_>>>()?;
1805 if let Some(mut where_clause) = del.where_clause.take() {
1806 where_clause.this = transform_recursive(where_clause.this, transform_fn)?;
1807 del.where_clause = Some(where_clause);
1808 }
1809 if let Some(output) = del.output.take() {
1810 del.output = Some(transform_output_clause_recursive(output, transform_fn)?);
1811 }
1812 if let Some(with) = del.with.take() {
1813 del.with = Some(transform_with_recursive(with, transform_fn)?);
1814 }
1815 if let Some(limit) = del.limit.take() {
1816 del.limit = Some(transform_recursive(limit, transform_fn)?);
1817 }
1818 if let Some(order_by) = del.order_by.take() {
1819 del.order_by = Some(transform_order_by_recursive(order_by, transform_fn)?);
1820 }
1821 del.returning = del
1822 .returning
1823 .into_iter()
1824 .map(|expr| transform_recursive(expr, transform_fn))
1825 .collect::<Result<Vec<_>>>()?;
1826 del.tables = del
1827 .tables
1828 .into_iter()
1829 .map(|table| transform_table_ref_recursive(table, transform_fn))
1830 .collect::<Result<Vec<_>>>()?;
1831 del.joins = del
1832 .joins
1833 .into_iter()
1834 .map(|join| transform_join_recursive(join, transform_fn))
1835 .collect::<Result<Vec<_>>>()?;
1836 Expression::Delete(del)
1837 }
1838
1839 Expression::With(mut w) => {
1841 w.ctes = w
1842 .ctes
1843 .into_iter()
1844 .map(|mut cte| {
1845 let original = cte.this.clone();
1846 cte.this = transform_recursive(cte.this, transform_fn).unwrap_or(original);
1847 cte
1848 })
1849 .collect();
1850 Expression::With(w)
1851 }
1852 Expression::Cte(mut c) => {
1853 c.this = transform_recursive(c.this, transform_fn)?;
1854 Expression::Cte(c)
1855 }
1856
1857 Expression::Ordered(mut o) => {
1859 o.this = transform_recursive(o.this, transform_fn)?;
1860 Expression::Ordered(o)
1861 }
1862
1863 Expression::Neg(mut n) => {
1865 n.this = transform_recursive(n.this, transform_fn)?;
1866 Expression::Neg(n)
1867 }
1868
1869 Expression::Between(mut b) => {
1871 b.this = transform_recursive(b.this, transform_fn)?;
1872 b.low = transform_recursive(b.low, transform_fn)?;
1873 b.high = transform_recursive(b.high, transform_fn)?;
1874 Expression::Between(b)
1875 }
1876 Expression::IsNull(mut i) => {
1877 i.this = transform_recursive(i.this, transform_fn)?;
1878 Expression::IsNull(i)
1879 }
1880 Expression::IsTrue(mut i) => {
1881 i.this = transform_recursive(i.this, transform_fn)?;
1882 Expression::IsTrue(i)
1883 }
1884 Expression::IsFalse(mut i) => {
1885 i.this = transform_recursive(i.this, transform_fn)?;
1886 Expression::IsFalse(i)
1887 }
1888
1889 Expression::Like(mut l) => {
1891 l.left = transform_recursive(l.left, transform_fn)?;
1892 l.right = transform_recursive(l.right, transform_fn)?;
1893 Expression::Like(l)
1894 }
1895 Expression::ILike(mut l) => {
1896 l.left = transform_recursive(l.left, transform_fn)?;
1897 l.right = transform_recursive(l.right, transform_fn)?;
1898 Expression::ILike(l)
1899 }
1900
1901 Expression::Neq(op) => transform_binary!(Neq, *op),
1903 Expression::Lte(op) => transform_binary!(Lte, *op),
1904 Expression::Gte(op) => transform_binary!(Gte, *op),
1905 Expression::Mod(op) => transform_binary!(Mod, *op),
1906 Expression::Concat(op) => transform_binary!(Concat, *op),
1907 Expression::BitwiseAnd(op) => transform_binary!(BitwiseAnd, *op),
1908 Expression::BitwiseOr(op) => transform_binary!(BitwiseOr, *op),
1909 Expression::BitwiseXor(op) => transform_binary!(BitwiseXor, *op),
1910 Expression::Is(op) => transform_binary!(Is, *op),
1911
1912 Expression::TryCast(mut c) => {
1914 c.this = transform_recursive(c.this, transform_fn)?;
1915 c.to = transform_data_type_recursive(c.to, transform_fn)?;
1916 Expression::TryCast(c)
1917 }
1918 Expression::SafeCast(mut c) => {
1919 c.this = transform_recursive(c.this, transform_fn)?;
1920 c.to = transform_data_type_recursive(c.to, transform_fn)?;
1921 Expression::SafeCast(c)
1922 }
1923
1924 Expression::Unnest(mut f) => {
1926 f.this = transform_recursive(f.this, transform_fn)?;
1927 f.expressions = f
1928 .expressions
1929 .into_iter()
1930 .map(|e| transform_recursive(e, transform_fn))
1931 .collect::<Result<Vec<_>>>()?;
1932 Expression::Unnest(f)
1933 }
1934 Expression::Explode(mut f) => {
1935 f.this = transform_recursive(f.this, transform_fn)?;
1936 Expression::Explode(f)
1937 }
1938 Expression::GroupConcat(mut f) => {
1939 f.this = transform_recursive(f.this, transform_fn)?;
1940 Expression::GroupConcat(f)
1941 }
1942 Expression::StringAgg(mut f) => {
1943 f.this = transform_recursive(f.this, transform_fn)?;
1944 if let Some(order_by) = f.order_by.take() {
1945 f.order_by = Some(
1946 order_by
1947 .into_iter()
1948 .map(|mut ordered| {
1949 let original = ordered.this.clone();
1950 ordered.this =
1951 transform_recursive(ordered.this, transform_fn).unwrap_or(original);
1952 match transform_fn(Expression::Ordered(Box::new(ordered.clone()))) {
1953 Ok(Expression::Ordered(transformed)) => Ok(*transformed),
1954 Ok(_) | Err(_) => Ok(ordered),
1955 }
1956 })
1957 .collect::<Result<Vec<_>>>()?,
1958 );
1959 }
1960 Expression::StringAgg(f)
1961 }
1962 Expression::ListAgg(mut f) => {
1963 f.this = transform_recursive(f.this, transform_fn)?;
1964 Expression::ListAgg(f)
1965 }
1966 Expression::ArrayAgg(mut f) => {
1967 f.this = transform_recursive(f.this, transform_fn)?;
1968 Expression::ArrayAgg(f)
1969 }
1970 Expression::ParseJson(mut f) => {
1971 f.this = transform_recursive(f.this, transform_fn)?;
1972 Expression::ParseJson(f)
1973 }
1974 Expression::ToJson(mut f) => {
1975 f.this = transform_recursive(f.this, transform_fn)?;
1976 Expression::ToJson(f)
1977 }
1978 Expression::JSONExtract(mut e) => {
1979 e.this = Box::new(transform_recursive(*e.this, transform_fn)?);
1980 e.expression = Box::new(transform_recursive(*e.expression, transform_fn)?);
1981 Expression::JSONExtract(e)
1982 }
1983 Expression::JSONExtractScalar(mut e) => {
1984 e.this = Box::new(transform_recursive(*e.this, transform_fn)?);
1985 e.expression = Box::new(transform_recursive(*e.expression, transform_fn)?);
1986 Expression::JSONExtractScalar(e)
1987 }
1988
1989 Expression::StrToTime(mut e) => {
1991 e.this = Box::new(transform_recursive(*e.this, transform_fn)?);
1992 Expression::StrToTime(e)
1993 }
1994
1995 Expression::UnixToTime(mut e) => {
1997 e.this = Box::new(transform_recursive(*e.this, transform_fn)?);
1998 Expression::UnixToTime(e)
1999 }
2000
2001 Expression::CreateTable(mut ct) => {
2003 for col in &mut ct.columns {
2004 if let Some(default_expr) = col.default.take() {
2005 col.default = Some(transform_recursive(default_expr, transform_fn)?);
2006 }
2007 if let Some(on_update_expr) = col.on_update.take() {
2008 col.on_update = Some(transform_recursive(on_update_expr, transform_fn)?);
2009 }
2010 }
2015 if let Some(as_select) = ct.as_select.take() {
2016 ct.as_select = Some(transform_recursive(as_select, transform_fn)?);
2017 }
2018 Expression::CreateTable(ct)
2019 }
2020
2021 Expression::CreateView(mut cv) => {
2023 cv.query = transform_recursive(cv.query, transform_fn)?;
2024 Expression::CreateView(cv)
2025 }
2026
2027 Expression::CreateTask(mut ct) => {
2029 ct.body = transform_recursive(ct.body, transform_fn)?;
2030 Expression::CreateTask(ct)
2031 }
2032
2033 Expression::Prepare(mut prepare) => {
2035 prepare.statement = transform_recursive(prepare.statement, transform_fn)?;
2036 Expression::Prepare(prepare)
2037 }
2038
2039 Expression::Execute(mut execute) => {
2041 execute.this = transform_recursive(execute.this, transform_fn)?;
2042 execute.arguments = execute
2043 .arguments
2044 .into_iter()
2045 .map(|argument| transform_recursive(argument, transform_fn))
2046 .collect::<Result<Vec<_>>>()?;
2047 execute.parameters = execute
2048 .parameters
2049 .into_iter()
2050 .map(|mut parameter| {
2051 parameter.value = transform_recursive(parameter.value, transform_fn)?;
2052 Ok(parameter)
2053 })
2054 .collect::<Result<Vec<_>>>()?;
2055 Expression::Execute(execute)
2056 }
2057
2058 Expression::CreateProcedure(mut cp) => {
2060 if let Some(body) = cp.body.take() {
2061 cp.body = Some(match body {
2062 FunctionBody::Expression(expr) => {
2063 FunctionBody::Expression(transform_recursive(expr, transform_fn)?)
2064 }
2065 FunctionBody::Return(expr) => {
2066 FunctionBody::Return(transform_recursive(expr, transform_fn)?)
2067 }
2068 FunctionBody::Statements(stmts) => {
2069 let transformed_stmts = stmts
2070 .into_iter()
2071 .map(|s| transform_recursive(s, transform_fn))
2072 .collect::<Result<Vec<_>>>()?;
2073 FunctionBody::Statements(transformed_stmts)
2074 }
2075 other => other,
2076 });
2077 }
2078 Expression::CreateProcedure(cp)
2079 }
2080
2081 Expression::CreateFunction(mut cf) => {
2083 if let Some(body) = cf.body.take() {
2084 cf.body = Some(match body {
2085 FunctionBody::Expression(expr) => {
2086 FunctionBody::Expression(transform_recursive(expr, transform_fn)?)
2087 }
2088 FunctionBody::Return(expr) => {
2089 FunctionBody::Return(transform_recursive(expr, transform_fn)?)
2090 }
2091 FunctionBody::Statements(stmts) => {
2092 let transformed_stmts = stmts
2093 .into_iter()
2094 .map(|s| transform_recursive(s, transform_fn))
2095 .collect::<Result<Vec<_>>>()?;
2096 FunctionBody::Statements(transformed_stmts)
2097 }
2098 other => other,
2099 });
2100 }
2101 Expression::CreateFunction(cf)
2102 }
2103
2104 Expression::MemberOf(op) => transform_binary!(MemberOf, *op),
2106 Expression::ArrayContainsAll(op) => transform_binary!(ArrayContainsAll, *op),
2108 Expression::ArrayContainedBy(op) => transform_binary!(ArrayContainedBy, *op),
2110 Expression::ArrayOverlaps(op) => transform_binary!(ArrayOverlaps, *op),
2112 Expression::TsMatch(op) => transform_binary!(TsMatch, *op),
2114 Expression::Adjacent(op) => transform_binary!(Adjacent, *op),
2116
2117 Expression::Table(mut t) => {
2119 if let Some(when) = t.when.take() {
2120 let transformed =
2121 transform_recursive(Expression::HistoricalData(when), transform_fn)?;
2122 if let Expression::HistoricalData(hd) = transformed {
2123 t.when = Some(hd);
2124 }
2125 }
2126 if let Some(changes) = t.changes.take() {
2127 let transformed = transform_recursive(Expression::Changes(changes), transform_fn)?;
2128 if let Expression::Changes(c) = transformed {
2129 t.changes = Some(c);
2130 }
2131 }
2132 Expression::Table(t)
2133 }
2134
2135 Expression::HistoricalData(mut hd) => {
2137 *hd.expression = transform_recursive(*hd.expression, transform_fn)?;
2138 Expression::HistoricalData(hd)
2139 }
2140
2141 Expression::Changes(mut c) => {
2143 if let Some(at_before) = c.at_before.take() {
2144 c.at_before = Some(Box::new(transform_recursive(*at_before, transform_fn)?));
2145 }
2146 if let Some(end) = c.end.take() {
2147 c.end = Some(Box::new(transform_recursive(*end, transform_fn)?));
2148 }
2149 Expression::Changes(c)
2150 }
2151
2152 Expression::TableArgument(mut ta) => {
2154 ta.this = transform_recursive(ta.this, transform_fn)?;
2155 Expression::TableArgument(ta)
2156 }
2157
2158 Expression::JoinedTable(mut jt) => {
2160 jt.left = transform_recursive(jt.left, transform_fn)?;
2161 jt.joins = jt
2162 .joins
2163 .into_iter()
2164 .map(|mut join| {
2165 join.this = transform_recursive(join.this, transform_fn)?;
2166 if let Some(on) = join.on.take() {
2167 join.on = Some(transform_recursive(on, transform_fn)?);
2168 }
2169 match transform_fn(Expression::Join(Box::new(join)))? {
2170 Expression::Join(j) => Ok(*j),
2171 _ => Err(crate::error::Error::parse(
2172 "Join transformation returned non-join expression",
2173 0,
2174 0,
2175 0,
2176 0,
2177 )),
2178 }
2179 })
2180 .collect::<Result<Vec<_>>>()?;
2181 jt.lateral_views = jt
2182 .lateral_views
2183 .into_iter()
2184 .map(|mut lv| {
2185 lv.this = transform_recursive(lv.this, transform_fn)?;
2186 Ok(lv)
2187 })
2188 .collect::<Result<Vec<_>>>()?;
2189 Expression::JoinedTable(jt)
2190 }
2191
2192 Expression::Lateral(mut lat) => {
2194 *lat.this = transform_recursive(*lat.this, transform_fn)?;
2195 Expression::Lateral(lat)
2196 }
2197
2198 Expression::WithinGroup(mut wg) => {
2202 wg.order_by = wg
2203 .order_by
2204 .into_iter()
2205 .map(|mut o| {
2206 let original = o.this.clone();
2207 o.this = transform_recursive(o.this, transform_fn).unwrap_or(original);
2208 match transform_fn(Expression::Ordered(Box::new(o.clone()))) {
2209 Ok(Expression::Ordered(transformed)) => *transformed,
2210 Ok(_) | Err(_) => o,
2211 }
2212 })
2213 .collect();
2214 Expression::WithinGroup(wg)
2215 }
2216
2217 Expression::Filter(mut f) => {
2219 f.this = Box::new(transform_recursive(*f.this, transform_fn)?);
2220 f.expression = Box::new(transform_recursive(*f.expression, transform_fn)?);
2221 Expression::Filter(f)
2222 }
2223
2224 Expression::Sum(f) => recurse_agg!(Sum, f),
2228 Expression::Avg(f) => recurse_agg!(Avg, f),
2229 Expression::Min(f) => recurse_agg!(Min, f),
2230 Expression::Max(f) => recurse_agg!(Max, f),
2231 Expression::CountIf(f) => recurse_agg!(CountIf, f),
2232 Expression::StddevPop(f) => recurse_agg!(StddevPop, f),
2233 Expression::VarPop(f) => recurse_agg!(VarPop, f),
2234 Expression::VarSamp(f) => recurse_agg!(VarSamp, f),
2235 Expression::Median(f) => recurse_agg!(Median, f),
2236 Expression::Mode(f) => recurse_agg!(Mode, f),
2237 Expression::First(f) => recurse_agg!(First, f),
2238 Expression::Last(f) => recurse_agg!(Last, f),
2239 Expression::AnyValue(f) => recurse_agg!(AnyValue, f),
2240 Expression::ApproxDistinct(f) => recurse_agg!(ApproxDistinct, f),
2241 Expression::ApproxCountDistinct(f) => recurse_agg!(ApproxCountDistinct, f),
2242 Expression::LogicalAnd(f) => recurse_agg!(LogicalAnd, f),
2243 Expression::LogicalOr(f) => recurse_agg!(LogicalOr, f),
2244 Expression::Skewness(f) => recurse_agg!(Skewness, f),
2245 Expression::ArrayConcatAgg(f) => recurse_agg!(ArrayConcatAgg, f),
2246 Expression::ArrayUniqueAgg(f) => recurse_agg!(ArrayUniqueAgg, f),
2247 Expression::BoolXorAgg(f) => recurse_agg!(BoolXorAgg, f),
2248 Expression::BitwiseOrAgg(f) => recurse_agg!(BitwiseOrAgg, f),
2249 Expression::BitwiseAndAgg(f) => recurse_agg!(BitwiseAndAgg, f),
2250 Expression::BitwiseXorAgg(f) => recurse_agg!(BitwiseXorAgg, f),
2251
2252 Expression::Count(mut c) => {
2254 if let Some(this) = c.this.take() {
2255 c.this = Some(transform_recursive(this, transform_fn)?);
2256 }
2257 if let Some(filter) = c.filter.take() {
2258 c.filter = Some(transform_recursive(filter, transform_fn)?);
2259 }
2260 Expression::Count(c)
2261 }
2262
2263 Expression::PipeOperator(mut pipe) => {
2264 pipe.this = transform_recursive(pipe.this, transform_fn)?;
2265 pipe.expression = transform_recursive(pipe.expression, transform_fn)?;
2266 Expression::PipeOperator(pipe)
2267 }
2268
2269 Expression::ArrayExcept(mut f) => {
2271 f.this = transform_recursive(f.this, transform_fn)?;
2272 f.expression = transform_recursive(f.expression, transform_fn)?;
2273 Expression::ArrayExcept(f)
2274 }
2275 Expression::ArrayContains(mut f) => {
2276 f.this = transform_recursive(f.this, transform_fn)?;
2277 f.expression = transform_recursive(f.expression, transform_fn)?;
2278 Expression::ArrayContains(f)
2279 }
2280 Expression::ArrayDistinct(mut f) => {
2281 f.this = transform_recursive(f.this, transform_fn)?;
2282 Expression::ArrayDistinct(f)
2283 }
2284 Expression::ArrayPosition(mut f) => {
2285 f.this = transform_recursive(f.this, transform_fn)?;
2286 f.expression = transform_recursive(f.expression, transform_fn)?;
2287 Expression::ArrayPosition(f)
2288 }
2289
2290 other => other,
2292 };
2293
2294 transform_fn(expr)
2296}
2297
2298struct CachedDialectConfig {
2308 tokenizer_config: Arc<TokenizerConfig>,
2309 #[cfg(feature = "generate")]
2310 generator_config: Arc<GeneratorConfig>,
2311}
2312
2313struct DialectConfigs {
2314 tokenizer_config: Arc<TokenizerConfig>,
2315 #[cfg(feature = "generate")]
2316 generator_config: Arc<GeneratorConfig>,
2317 #[cfg(feature = "transpile")]
2318 transformer: Box<dyn Fn(Expression) -> Result<Expression> + Send + Sync>,
2319}
2320
2321macro_rules! cached_dialect {
2323 ($static_name:ident, $dialect_struct:expr, $feature:literal) => {
2324 #[cfg(feature = $feature)]
2325 static $static_name: LazyLock<CachedDialectConfig> = LazyLock::new(|| {
2326 let d = $dialect_struct;
2327 CachedDialectConfig {
2328 tokenizer_config: Arc::new(d.tokenizer_config()),
2329 #[cfg(feature = "generate")]
2330 generator_config: Arc::new(d.generator_config()),
2331 }
2332 });
2333 };
2334}
2335
2336static CACHED_GENERIC: LazyLock<CachedDialectConfig> = LazyLock::new(|| {
2337 let d = GenericDialect;
2338 CachedDialectConfig {
2339 tokenizer_config: Arc::new(d.tokenizer_config()),
2340 #[cfg(feature = "generate")]
2341 generator_config: Arc::new(d.generator_config()),
2342 }
2343});
2344
2345cached_dialect!(CACHED_POSTGRESQL, PostgresDialect, "dialect-postgresql");
2346cached_dialect!(CACHED_MYSQL, MySQLDialect, "dialect-mysql");
2347cached_dialect!(CACHED_BIGQUERY, BigQueryDialect, "dialect-bigquery");
2348cached_dialect!(CACHED_SNOWFLAKE, SnowflakeDialect, "dialect-snowflake");
2349cached_dialect!(CACHED_DUCKDB, DuckDBDialect, "dialect-duckdb");
2350cached_dialect!(CACHED_TSQL, TSQLDialect, "dialect-tsql");
2351cached_dialect!(CACHED_ORACLE, OracleDialect, "dialect-oracle");
2352cached_dialect!(CACHED_HIVE, HiveDialect, "dialect-hive");
2353cached_dialect!(CACHED_SPARK, SparkDialect, "dialect-spark");
2354cached_dialect!(CACHED_SQLITE, SQLiteDialect, "dialect-sqlite");
2355cached_dialect!(CACHED_PRESTO, PrestoDialect, "dialect-presto");
2356cached_dialect!(CACHED_TRINO, TrinoDialect, "dialect-trino");
2357cached_dialect!(CACHED_REDSHIFT, RedshiftDialect, "dialect-redshift");
2358cached_dialect!(CACHED_CLICKHOUSE, ClickHouseDialect, "dialect-clickhouse");
2359cached_dialect!(CACHED_DATABRICKS, DatabricksDialect, "dialect-databricks");
2360cached_dialect!(CACHED_ATHENA, AthenaDialect, "dialect-athena");
2361cached_dialect!(CACHED_TERADATA, TeradataDialect, "dialect-teradata");
2362cached_dialect!(CACHED_DORIS, DorisDialect, "dialect-doris");
2363cached_dialect!(CACHED_STARROCKS, StarRocksDialect, "dialect-starrocks");
2364cached_dialect!(
2365 CACHED_MATERIALIZE,
2366 MaterializeDialect,
2367 "dialect-materialize"
2368);
2369cached_dialect!(CACHED_RISINGWAVE, RisingWaveDialect, "dialect-risingwave");
2370cached_dialect!(
2371 CACHED_SINGLESTORE,
2372 SingleStoreDialect,
2373 "dialect-singlestore"
2374);
2375cached_dialect!(
2376 CACHED_COCKROACHDB,
2377 CockroachDBDialect,
2378 "dialect-cockroachdb"
2379);
2380cached_dialect!(CACHED_TIDB, TiDBDialect, "dialect-tidb");
2381cached_dialect!(CACHED_DRUID, DruidDialect, "dialect-druid");
2382cached_dialect!(CACHED_SOLR, SolrDialect, "dialect-solr");
2383cached_dialect!(CACHED_TABLEAU, TableauDialect, "dialect-tableau");
2384cached_dialect!(CACHED_DUNE, DuneDialect, "dialect-dune");
2385cached_dialect!(CACHED_FABRIC, FabricDialect, "dialect-fabric");
2386cached_dialect!(CACHED_DRILL, DrillDialect, "dialect-drill");
2387cached_dialect!(CACHED_DREMIO, DremioDialect, "dialect-dremio");
2388cached_dialect!(CACHED_EXASOL, ExasolDialect, "dialect-exasol");
2389cached_dialect!(CACHED_DATAFUSION, DataFusionDialect, "dialect-datafusion");
2390
2391fn configs_for_dialect_type(dt: DialectType) -> DialectConfigs {
2392 macro_rules! from_cache {
2394 ($cache:expr, $dialect_struct:expr) => {{
2395 let c = &*$cache;
2396 DialectConfigs {
2397 tokenizer_config: c.tokenizer_config.clone(),
2398 #[cfg(feature = "generate")]
2399 generator_config: c.generator_config.clone(),
2400 #[cfg(feature = "transpile")]
2401 transformer: Box::new(move |e| $dialect_struct.transform_expr(e)),
2402 }
2403 }};
2404 }
2405 match dt {
2406 #[cfg(feature = "dialect-postgresql")]
2407 DialectType::PostgreSQL => from_cache!(CACHED_POSTGRESQL, PostgresDialect),
2408 #[cfg(feature = "dialect-mysql")]
2409 DialectType::MySQL => from_cache!(CACHED_MYSQL, MySQLDialect),
2410 #[cfg(feature = "dialect-bigquery")]
2411 DialectType::BigQuery => from_cache!(CACHED_BIGQUERY, BigQueryDialect),
2412 #[cfg(feature = "dialect-snowflake")]
2413 DialectType::Snowflake => from_cache!(CACHED_SNOWFLAKE, SnowflakeDialect),
2414 #[cfg(feature = "dialect-duckdb")]
2415 DialectType::DuckDB => from_cache!(CACHED_DUCKDB, DuckDBDialect),
2416 #[cfg(feature = "dialect-tsql")]
2417 DialectType::TSQL => from_cache!(CACHED_TSQL, TSQLDialect),
2418 #[cfg(feature = "dialect-oracle")]
2419 DialectType::Oracle => from_cache!(CACHED_ORACLE, OracleDialect),
2420 #[cfg(feature = "dialect-hive")]
2421 DialectType::Hive => from_cache!(CACHED_HIVE, HiveDialect),
2422 #[cfg(feature = "dialect-spark")]
2423 DialectType::Spark => from_cache!(CACHED_SPARK, SparkDialect),
2424 #[cfg(feature = "dialect-sqlite")]
2425 DialectType::SQLite => from_cache!(CACHED_SQLITE, SQLiteDialect),
2426 #[cfg(feature = "dialect-presto")]
2427 DialectType::Presto => from_cache!(CACHED_PRESTO, PrestoDialect),
2428 #[cfg(feature = "dialect-trino")]
2429 DialectType::Trino => from_cache!(CACHED_TRINO, TrinoDialect),
2430 #[cfg(feature = "dialect-redshift")]
2431 DialectType::Redshift => from_cache!(CACHED_REDSHIFT, RedshiftDialect),
2432 #[cfg(feature = "dialect-clickhouse")]
2433 DialectType::ClickHouse => from_cache!(CACHED_CLICKHOUSE, ClickHouseDialect),
2434 #[cfg(feature = "dialect-databricks")]
2435 DialectType::Databricks => from_cache!(CACHED_DATABRICKS, DatabricksDialect),
2436 #[cfg(feature = "dialect-athena")]
2437 DialectType::Athena => from_cache!(CACHED_ATHENA, AthenaDialect),
2438 #[cfg(feature = "dialect-teradata")]
2439 DialectType::Teradata => from_cache!(CACHED_TERADATA, TeradataDialect),
2440 #[cfg(feature = "dialect-doris")]
2441 DialectType::Doris => from_cache!(CACHED_DORIS, DorisDialect),
2442 #[cfg(feature = "dialect-starrocks")]
2443 DialectType::StarRocks => from_cache!(CACHED_STARROCKS, StarRocksDialect),
2444 #[cfg(feature = "dialect-materialize")]
2445 DialectType::Materialize => from_cache!(CACHED_MATERIALIZE, MaterializeDialect),
2446 #[cfg(feature = "dialect-risingwave")]
2447 DialectType::RisingWave => from_cache!(CACHED_RISINGWAVE, RisingWaveDialect),
2448 #[cfg(feature = "dialect-singlestore")]
2449 DialectType::SingleStore => from_cache!(CACHED_SINGLESTORE, SingleStoreDialect),
2450 #[cfg(feature = "dialect-cockroachdb")]
2451 DialectType::CockroachDB => from_cache!(CACHED_COCKROACHDB, CockroachDBDialect),
2452 #[cfg(feature = "dialect-tidb")]
2453 DialectType::TiDB => from_cache!(CACHED_TIDB, TiDBDialect),
2454 #[cfg(feature = "dialect-druid")]
2455 DialectType::Druid => from_cache!(CACHED_DRUID, DruidDialect),
2456 #[cfg(feature = "dialect-solr")]
2457 DialectType::Solr => from_cache!(CACHED_SOLR, SolrDialect),
2458 #[cfg(feature = "dialect-tableau")]
2459 DialectType::Tableau => from_cache!(CACHED_TABLEAU, TableauDialect),
2460 #[cfg(feature = "dialect-dune")]
2461 DialectType::Dune => from_cache!(CACHED_DUNE, DuneDialect),
2462 #[cfg(feature = "dialect-fabric")]
2463 DialectType::Fabric => from_cache!(CACHED_FABRIC, FabricDialect),
2464 #[cfg(feature = "dialect-drill")]
2465 DialectType::Drill => from_cache!(CACHED_DRILL, DrillDialect),
2466 #[cfg(feature = "dialect-dremio")]
2467 DialectType::Dremio => from_cache!(CACHED_DREMIO, DremioDialect),
2468 #[cfg(feature = "dialect-exasol")]
2469 DialectType::Exasol => from_cache!(CACHED_EXASOL, ExasolDialect),
2470 #[cfg(feature = "dialect-datafusion")]
2471 DialectType::DataFusion => from_cache!(CACHED_DATAFUSION, DataFusionDialect),
2472 _ => from_cache!(CACHED_GENERIC, GenericDialect),
2473 }
2474}
2475
2476static CUSTOM_DIALECT_REGISTRY: LazyLock<RwLock<HashMap<String, Arc<CustomDialectConfig>>>> =
2481 LazyLock::new(|| RwLock::new(HashMap::new()));
2482
2483struct CustomDialectConfig {
2484 name: String,
2485 base_dialect: DialectType,
2486 tokenizer_config: Arc<TokenizerConfig>,
2487 #[cfg(feature = "generate")]
2488 generator_config: GeneratorConfig,
2489 #[cfg(feature = "transpile")]
2490 transform: Option<Arc<dyn Fn(Expression) -> Result<Expression> + Send + Sync>>,
2491 #[cfg(feature = "transpile")]
2492 preprocess: Option<Arc<dyn Fn(Expression) -> Result<Expression> + Send + Sync>>,
2493}
2494
2495pub struct CustomDialectBuilder {
2523 name: String,
2524 base_dialect: DialectType,
2525 tokenizer_modifier: Option<Box<dyn FnOnce(&mut TokenizerConfig)>>,
2526 #[cfg(feature = "generate")]
2527 generator_modifier: Option<Box<dyn FnOnce(&mut GeneratorConfig)>>,
2528 #[cfg(feature = "transpile")]
2529 transform: Option<Arc<dyn Fn(Expression) -> Result<Expression> + Send + Sync>>,
2530 #[cfg(feature = "transpile")]
2531 preprocess: Option<Arc<dyn Fn(Expression) -> Result<Expression> + Send + Sync>>,
2532}
2533
2534impl CustomDialectBuilder {
2535 pub fn new(name: impl Into<String>) -> Self {
2537 Self {
2538 name: name.into(),
2539 base_dialect: DialectType::Generic,
2540 tokenizer_modifier: None,
2541 #[cfg(feature = "generate")]
2542 generator_modifier: None,
2543 #[cfg(feature = "transpile")]
2544 transform: None,
2545 #[cfg(feature = "transpile")]
2546 preprocess: None,
2547 }
2548 }
2549
2550 pub fn based_on(mut self, dialect: DialectType) -> Self {
2552 self.base_dialect = dialect;
2553 self
2554 }
2555
2556 pub fn tokenizer_config_modifier<F>(mut self, f: F) -> Self
2558 where
2559 F: FnOnce(&mut TokenizerConfig) + 'static,
2560 {
2561 self.tokenizer_modifier = Some(Box::new(f));
2562 self
2563 }
2564
2565 #[cfg(feature = "generate")]
2567 pub fn generator_config_modifier<F>(mut self, f: F) -> Self
2568 where
2569 F: FnOnce(&mut GeneratorConfig) + 'static,
2570 {
2571 self.generator_modifier = Some(Box::new(f));
2572 self
2573 }
2574
2575 #[cfg(feature = "transpile")]
2580 pub fn transform_fn<F>(mut self, f: F) -> Self
2581 where
2582 F: Fn(Expression) -> Result<Expression> + Send + Sync + 'static,
2583 {
2584 self.transform = Some(Arc::new(f));
2585 self
2586 }
2587
2588 #[cfg(feature = "transpile")]
2593 pub fn preprocess_fn<F>(mut self, f: F) -> Self
2594 where
2595 F: Fn(Expression) -> Result<Expression> + Send + Sync + 'static,
2596 {
2597 self.preprocess = Some(Arc::new(f));
2598 self
2599 }
2600
2601 pub fn register(self) -> Result<()> {
2607 if DialectType::from_str(&self.name).is_ok() {
2609 return Err(crate::error::Error::parse(
2610 format!(
2611 "Cannot register custom dialect '{}': name collides with built-in dialect",
2612 self.name
2613 ),
2614 0,
2615 0,
2616 0,
2617 0,
2618 ));
2619 }
2620
2621 let base_configs = configs_for_dialect_type(self.base_dialect);
2623 let mut tok_config = (*base_configs.tokenizer_config).clone();
2624 #[cfg(feature = "generate")]
2625 let mut gen_config = (*base_configs.generator_config).clone();
2626
2627 if let Some(tok_mod) = self.tokenizer_modifier {
2629 tok_mod(&mut tok_config);
2630 }
2631 #[cfg(feature = "generate")]
2632 if let Some(gen_mod) = self.generator_modifier {
2633 gen_mod(&mut gen_config);
2634 }
2635
2636 let config = CustomDialectConfig {
2637 name: self.name.clone(),
2638 base_dialect: self.base_dialect,
2639 tokenizer_config: Arc::new(tok_config),
2640 #[cfg(feature = "generate")]
2641 generator_config: gen_config,
2642 #[cfg(feature = "transpile")]
2643 transform: self.transform,
2644 #[cfg(feature = "transpile")]
2645 preprocess: self.preprocess,
2646 };
2647
2648 register_custom_dialect(config)
2649 }
2650}
2651
2652use std::str::FromStr;
2653
2654fn register_custom_dialect(config: CustomDialectConfig) -> Result<()> {
2655 let mut registry = CUSTOM_DIALECT_REGISTRY.write().map_err(|e| {
2656 crate::error::Error::parse(format!("Registry lock poisoned: {}", e), 0, 0, 0, 0)
2657 })?;
2658
2659 if registry.contains_key(&config.name) {
2660 return Err(crate::error::Error::parse(
2661 format!("Custom dialect '{}' is already registered", config.name),
2662 0,
2663 0,
2664 0,
2665 0,
2666 ));
2667 }
2668
2669 registry.insert(config.name.clone(), Arc::new(config));
2670 Ok(())
2671}
2672
2673pub fn unregister_custom_dialect(name: &str) -> bool {
2678 if let Ok(mut registry) = CUSTOM_DIALECT_REGISTRY.write() {
2679 registry.remove(name).is_some()
2680 } else {
2681 false
2682 }
2683}
2684
2685fn get_custom_dialect_config(name: &str) -> Option<Arc<CustomDialectConfig>> {
2686 CUSTOM_DIALECT_REGISTRY
2687 .read()
2688 .ok()
2689 .and_then(|registry| registry.get(name).cloned())
2690}
2691
2692pub struct Dialect {
2715 dialect_type: DialectType,
2716 tokenizer: Tokenizer,
2717 #[cfg(feature = "generate")]
2718 generator_config: Arc<GeneratorConfig>,
2719 #[cfg(feature = "transpile")]
2720 transformer: Box<dyn Fn(Expression) -> Result<Expression> + Send + Sync>,
2721 #[cfg(feature = "generate")]
2723 generator_config_for_expr: Option<Box<dyn Fn(&Expression) -> GeneratorConfig + Send + Sync>>,
2724 #[cfg(feature = "transpile")]
2726 custom_preprocess: Option<Box<dyn Fn(Expression) -> Result<Expression> + Send + Sync>>,
2727}
2728
2729#[cfg(feature = "transpile")]
2738#[derive(Debug, Clone, Serialize, Deserialize)]
2739#[serde(rename_all = "camelCase", default)]
2740#[non_exhaustive]
2741pub struct TranspileOptions {
2742 pub pretty: bool,
2744 pub unsupported_level: UnsupportedLevel,
2749 pub max_unsupported: usize,
2751 pub complexity_guard: ComplexityGuardOptions,
2753}
2754
2755#[cfg(feature = "transpile")]
2756impl Default for TranspileOptions {
2757 fn default() -> Self {
2758 Self {
2759 pretty: false,
2760 unsupported_level: UnsupportedLevel::Warn,
2761 max_unsupported: 3,
2762 complexity_guard: ComplexityGuardOptions::default(),
2763 }
2764 }
2765}
2766
2767#[cfg(feature = "transpile")]
2768impl TranspileOptions {
2769 pub fn pretty() -> Self {
2771 Self {
2772 pretty: true,
2773 ..Default::default()
2774 }
2775 }
2776
2777 pub fn strict() -> Self {
2779 Self {
2780 unsupported_level: UnsupportedLevel::Raise,
2781 ..Default::default()
2782 }
2783 }
2784
2785 pub fn with_unsupported_level(mut self, level: UnsupportedLevel) -> Self {
2787 self.unsupported_level = level;
2788 self
2789 }
2790
2791 pub fn with_max_unsupported(mut self, max: usize) -> Self {
2793 self.max_unsupported = max;
2794 self
2795 }
2796
2797 pub fn with_complexity_guard(mut self, guard: ComplexityGuardOptions) -> Self {
2799 self.complexity_guard = guard;
2800 self
2801 }
2802}
2803
2804#[cfg(feature = "transpile")]
2811pub trait TranspileTarget {
2812 fn with_dialect<R>(self, f: impl FnOnce(&Dialect) -> R) -> R;
2814}
2815
2816#[cfg(feature = "transpile")]
2817impl TranspileTarget for DialectType {
2818 fn with_dialect<R>(self, f: impl FnOnce(&Dialect) -> R) -> R {
2819 f(&Dialect::get(self))
2820 }
2821}
2822
2823#[cfg(feature = "transpile")]
2824impl TranspileTarget for &Dialect {
2825 fn with_dialect<R>(self, f: impl FnOnce(&Dialect) -> R) -> R {
2826 f(self)
2827 }
2828}
2829
2830impl Dialect {
2831 pub fn get(dialect_type: DialectType) -> Self {
2838 let configs = configs_for_dialect_type(dialect_type);
2839 let tokenizer_config = configs.tokenizer_config;
2840 #[cfg(feature = "generate")]
2841 let generator_config = configs.generator_config;
2842 #[cfg(feature = "transpile")]
2843 let transformer = configs.transformer;
2844
2845 #[cfg(feature = "generate")]
2847 let generator_config_for_expr: Option<
2848 Box<dyn Fn(&Expression) -> GeneratorConfig + Send + Sync>,
2849 > = match dialect_type {
2850 #[cfg(feature = "dialect-athena")]
2851 DialectType::Athena => Some(Box::new(|expr| {
2852 AthenaDialect.generator_config_for_expr(expr)
2853 })),
2854 _ => None,
2855 };
2856
2857 Self {
2858 dialect_type,
2859 tokenizer: Tokenizer::from_shared_config(tokenizer_config),
2860 #[cfg(feature = "generate")]
2861 generator_config,
2862 #[cfg(feature = "transpile")]
2863 transformer,
2864 #[cfg(feature = "generate")]
2865 generator_config_for_expr,
2866 #[cfg(feature = "transpile")]
2867 custom_preprocess: None,
2868 }
2869 }
2870
2871 pub fn get_by_name(name: &str) -> Option<Self> {
2877 if let Ok(dt) = DialectType::from_str(name) {
2879 return Some(Self::get(dt));
2880 }
2881
2882 let config = get_custom_dialect_config(name)?;
2884 Some(Self::from_custom_config(&config))
2885 }
2886
2887 fn from_custom_config(config: &CustomDialectConfig) -> Self {
2889 #[cfg(feature = "transpile")]
2891 let transformer: Box<dyn Fn(Expression) -> Result<Expression> + Send + Sync> =
2892 if let Some(ref custom_transform) = config.transform {
2893 let t = Arc::clone(custom_transform);
2894 Box::new(move |e| t(e))
2895 } else {
2896 configs_for_dialect_type(config.base_dialect).transformer
2897 };
2898
2899 #[cfg(feature = "transpile")]
2901 let custom_preprocess: Option<
2902 Box<dyn Fn(Expression) -> Result<Expression> + Send + Sync>,
2903 > = config.preprocess.as_ref().map(|p| {
2904 let p = Arc::clone(p);
2905 Box::new(move |e: Expression| p(e))
2906 as Box<dyn Fn(Expression) -> Result<Expression> + Send + Sync>
2907 });
2908
2909 Self {
2910 dialect_type: config.base_dialect,
2911 tokenizer: Tokenizer::from_shared_config(config.tokenizer_config.clone()),
2912 #[cfg(feature = "generate")]
2913 generator_config: Arc::new(config.generator_config.clone()),
2914 #[cfg(feature = "transpile")]
2915 transformer,
2916 #[cfg(feature = "generate")]
2917 generator_config_for_expr: None,
2918 #[cfg(feature = "transpile")]
2919 custom_preprocess,
2920 }
2921 }
2922
2923 pub fn dialect_type(&self) -> DialectType {
2925 self.dialect_type
2926 }
2927
2928 #[cfg(feature = "generate")]
2930 pub fn generator_config(&self) -> &GeneratorConfig {
2931 &self.generator_config
2932 }
2933
2934 pub fn parse(&self, sql: &str) -> Result<Vec<Expression>> {
2940 self.parse_with_guard(sql, self.default_complexity_guard())
2941 }
2942
2943 pub fn parse_with_options(&self, sql: &str, options: &ParseOptions) -> Result<Vec<Expression>> {
2945 self.parse_with_guard(
2946 sql,
2947 options
2948 .complexity_guard
2949 .unwrap_or_else(|| self.default_complexity_guard()),
2950 )
2951 }
2952
2953 fn parse_with_guard(
2954 &self,
2955 sql: &str,
2956 complexity_guard: ComplexityGuardOptions,
2957 ) -> Result<Vec<Expression>> {
2958 enforce_input(sql, &complexity_guard)?;
2959 let source: Arc<str> = Arc::from(sql);
2960 let (tokens, token_guard_stats) = self.tokenizer.tokenize_for_parser(&source)?;
2961 let config = crate::parser::ParserConfig {
2962 dialect: Some(self.dialect_type),
2963 complexity_guard,
2964 ..Default::default()
2965 };
2966 let mut parser = Parser::with_parser_tokens(tokens, token_guard_stats, config, source);
2967 parser.parse()
2968 }
2969
2970 fn default_complexity_guard(&self) -> ComplexityGuardOptions {
2971 let mut guard = ComplexityGuardOptions::default();
2972 if matches!(self.dialect_type, DialectType::ClickHouse) {
2973 guard.max_ast_depth = Some(4_096);
2974 guard.max_function_call_depth = Some(512);
2975 }
2976 guard
2977 }
2978
2979 #[cfg(feature = "transpile")]
2980 fn default_transpile_complexity_guard(
2981 &self,
2982 target_dialect: &Dialect,
2983 guard: ComplexityGuardOptions,
2984 ) -> ComplexityGuardOptions {
2985 if guard != ComplexityGuardOptions::default() {
2986 return guard;
2987 }
2988
2989 if matches!(self.dialect_type, DialectType::ClickHouse)
2990 || matches!(target_dialect.dialect_type, DialectType::ClickHouse)
2991 {
2992 let mut guard = guard;
2993 guard.max_ast_depth = Some(4_096);
2994 guard.max_function_call_depth = Some(512);
2995 guard
2996 } else {
2997 guard
2998 }
2999 }
3000
3001 pub fn parse_data_type(&self, sql: &str) -> Result<DataType> {
3006 self.parse_data_type_with_options(sql, &ParseOptions::default())
3007 }
3008
3009 pub fn parse_data_type_with_options(
3011 &self,
3012 sql: &str,
3013 options: &ParseOptions,
3014 ) -> Result<DataType> {
3015 let complexity_guard = options
3016 .complexity_guard
3017 .unwrap_or_else(|| self.default_complexity_guard());
3018 enforce_input(sql, &complexity_guard)?;
3019 let source: Arc<str> = Arc::from(sql);
3020 let (tokens, token_guard_stats) = self.tokenizer.tokenize_for_parser(&source)?;
3021 let config = crate::parser::ParserConfig {
3022 dialect: Some(self.dialect_type),
3023 complexity_guard,
3024 ..Default::default()
3025 };
3026 let mut parser = Parser::with_parser_tokens(tokens, token_guard_stats, config, source);
3027 parser.parse_standalone_data_type()
3028 }
3029
3030 pub fn tokenize(&self, sql: &str) -> Result<Vec<Token>> {
3032 self.tokenizer.tokenize(sql)
3033 }
3034
3035 #[cfg(feature = "generate")]
3038 fn get_config_for_expr(&self, expr: &Expression) -> GeneratorConfig {
3039 if let Some(ref config_fn) = self.generator_config_for_expr {
3040 config_fn(expr)
3041 } else {
3042 (*self.generator_config).clone()
3043 }
3044 }
3045
3046 #[cfg(feature = "generate")]
3052 pub fn generate(&self, expr: &Expression) -> Result<String> {
3053 if self.generator_config_for_expr.is_none() {
3055 let mut generator = Generator::with_arc_config(self.generator_config.clone());
3056 return generator.generate(expr);
3057 }
3058 let config = self.get_config_for_expr(expr);
3059 let mut generator = Generator::with_config(config);
3060 generator.generate(expr)
3061 }
3062
3063 #[cfg(feature = "generate")]
3065 pub fn generate_pretty(&self, expr: &Expression) -> Result<String> {
3066 let mut config = self.get_config_for_expr(expr);
3067 config.pretty = true;
3068 let mut generator = Generator::with_config(config).with_preserved_null_ordering();
3069 generator.generate(expr)
3070 }
3071
3072 #[cfg(all(feature = "semantic", feature = "generate"))]
3074 pub(crate) fn generate_with_guard(
3075 &self,
3076 expr: &Expression,
3077 guard: Option<ComplexityGuardOptions>,
3078 ) -> Result<String> {
3079 let Some(guard) = guard else {
3080 return self.generate(expr);
3081 };
3082 let mut config = self.get_config_for_expr(expr);
3083 config.complexity_guard = guard;
3084 Generator::with_config(config).generate(expr)
3085 }
3086
3087 #[cfg(feature = "generate")]
3089 pub fn generate_with_source(&self, expr: &Expression, source: DialectType) -> Result<String> {
3090 let mut config = self.get_config_for_expr(expr);
3091 config.source_dialect = Some(source);
3092 let mut generator = Generator::with_config(config);
3093 generator.generate(expr)
3094 }
3095
3096 #[cfg(feature = "generate")]
3098 pub fn generate_pretty_with_source(
3099 &self,
3100 expr: &Expression,
3101 source: DialectType,
3102 ) -> Result<String> {
3103 let mut config = self.get_config_for_expr(expr);
3104 config.pretty = true;
3105 config.source_dialect = Some(source);
3106 let mut generator = Generator::with_config(config);
3107 generator.generate(expr)
3108 }
3109
3110 #[cfg(all(feature = "generate", feature = "transpile"))]
3112 fn generate_with_transpile_options(
3113 &self,
3114 expr: &Expression,
3115 source: DialectType,
3116 opts: &TranspileOptions,
3117 ) -> Result<String> {
3118 let mut config = self.get_config_for_expr(expr);
3119 config.source_dialect = Some(source);
3120 config.pretty = opts.pretty;
3121 config.unsupported_level = opts.unsupported_level;
3122 config.max_unsupported = opts.max_unsupported.max(1);
3123 config.complexity_guard = opts.complexity_guard;
3124 let mut generator = Generator::with_config(config);
3125 generator.generate(expr)
3126 }
3127
3128 #[cfg(feature = "generate")]
3130 pub fn generate_with_identify(&self, expr: &Expression) -> Result<String> {
3131 let mut config = self.get_config_for_expr(expr);
3132 config.always_quote_identifiers = true;
3133 let mut generator = Generator::with_config(config);
3134 generator.generate(expr)
3135 }
3136
3137 #[cfg(feature = "generate")]
3139 pub fn generate_pretty_with_identify(&self, expr: &Expression) -> Result<String> {
3140 let mut config = (*self.generator_config).clone();
3141 config.pretty = true;
3142 config.always_quote_identifiers = true;
3143 let mut generator = Generator::with_config(config);
3144 generator.generate(expr)
3145 }
3146
3147 #[cfg(feature = "generate")]
3149 pub fn generate_with_overrides(
3150 &self,
3151 expr: &Expression,
3152 overrides: impl FnOnce(&mut GeneratorConfig),
3153 ) -> Result<String> {
3154 let mut config = self.get_config_for_expr(expr);
3155 overrides(&mut config);
3156 let mut generator = Generator::with_config(config);
3157 generator.generate(expr)
3158 }
3159
3160 #[cfg(feature = "transpile")]
3171 pub fn transform(&self, expr: Expression) -> Result<Expression> {
3172 self.transform_with_guard(expr, self.default_complexity_guard())
3173 }
3174
3175 #[cfg(feature = "transpile")]
3176 fn transform_with_guard(
3177 &self,
3178 expr: Expression,
3179 complexity_guard: ComplexityGuardOptions,
3180 ) -> Result<Expression> {
3181 enforce_generate_ast(&expr, &complexity_guard)?;
3182 let preprocessed = self.preprocess(expr)?;
3184 transform_recursive(preprocessed, &self.transformer)
3186 }
3187
3188 #[cfg(feature = "transpile")]
3190 fn preprocess(&self, expr: Expression) -> Result<Expression> {
3191 if let Some(ref custom_preprocess) = self.custom_preprocess {
3193 return custom_preprocess(expr);
3194 }
3195
3196 #[cfg(any(
3197 feature = "dialect-mysql",
3198 feature = "dialect-postgresql",
3199 feature = "dialect-bigquery",
3200 feature = "dialect-snowflake",
3201 feature = "dialect-tsql",
3202 feature = "dialect-spark",
3203 feature = "dialect-databricks",
3204 feature = "dialect-hive",
3205 feature = "dialect-sqlite",
3206 feature = "dialect-trino",
3207 feature = "dialect-presto",
3208 feature = "dialect-duckdb",
3209 feature = "dialect-redshift",
3210 feature = "dialect-starrocks",
3211 feature = "dialect-oracle",
3212 feature = "dialect-clickhouse",
3213 feature = "dialect-fabric",
3214 ))]
3215 use crate::transforms;
3216
3217 match self.dialect_type {
3218 #[cfg(feature = "dialect-mysql")]
3221 DialectType::MySQL => {
3222 let expr = transforms::eliminate_qualify(expr)?;
3223 let expr = transforms::eliminate_full_outer_join(expr)?;
3224 let expr = transforms::eliminate_semi_and_anti_joins(expr)?;
3225 let expr = transforms::unnest_generate_date_array_using_recursive_cte(expr)?;
3226 Ok(expr)
3227 }
3228 #[cfg(feature = "dialect-postgresql")]
3232 DialectType::PostgreSQL => {
3233 let expr = transforms::eliminate_qualify(expr)?;
3234 let expr = transforms::eliminate_semi_and_anti_joins(expr)?;
3235 let expr = transforms::unwrap_unnest_generate_series_for_postgres(expr)?;
3236 let expr = if let Expression::CreateFunction(mut cf) = expr {
3241 if cf.body.is_none() {
3242 for opt in &mut cf.set_options {
3243 if let crate::expressions::FunctionSetValue::Value { use_to, .. } =
3244 &mut opt.value
3245 {
3246 *use_to = false;
3247 }
3248 }
3249 }
3250 Expression::CreateFunction(cf)
3251 } else {
3252 expr
3253 };
3254 Ok(expr)
3255 }
3256 #[cfg(feature = "dialect-bigquery")]
3258 DialectType::BigQuery => {
3259 let expr = transforms::eliminate_semi_and_anti_joins(expr)?;
3260 let expr = transforms::pushdown_cte_column_names(expr)?;
3261 let expr = transforms::explode_projection_to_unnest(expr, DialectType::BigQuery)?;
3262 Ok(expr)
3263 }
3264 #[cfg(feature = "dialect-snowflake")]
3266 DialectType::Snowflake => {
3267 let expr = transforms::eliminate_semi_and_anti_joins(expr)?;
3268 let expr = transforms::eliminate_window_clause(expr)?;
3269 let expr = transforms::snowflake_flatten_projection_to_unnest(expr)?;
3270 Ok(expr)
3271 }
3272 #[cfg(feature = "dialect-tsql")]
3278 DialectType::TSQL => {
3279 let expr = transforms::eliminate_qualify(expr)?;
3280 let expr = transforms::eliminate_semi_and_anti_joins(expr)?;
3281 let expr = transforms::normalize_grouping_sets_for_tsql(expr)?;
3282 let expr =
3283 transforms::expand_distinct_grouping_sets_for_tsql(expr, DialectType::TSQL)?;
3284 let expr = transforms::ensure_bools(expr)?;
3285 let expr = transforms::unnest_generate_date_array_using_recursive_cte(expr)?;
3286 let expr = transforms::strip_cte_materialization(expr)?;
3287 let expr = transforms::move_ctes_to_top_level(expr)?;
3288 let expr = transforms::qualify_derived_table_outputs(expr)?;
3289 Ok(expr)
3290 }
3291 #[cfg(feature = "dialect-fabric")]
3294 DialectType::Fabric => {
3295 let expr = transforms::normalize_grouping_sets_for_tsql(expr)?;
3296 let expr =
3297 transforms::expand_distinct_grouping_sets_for_tsql(expr, DialectType::Fabric)?;
3298 let expr = transforms::ensure_bools(expr)?;
3299 let expr = transforms::strip_cte_materialization(expr)?;
3300 let expr = transforms::move_ctes_to_top_level(expr)?;
3301 Ok(expr)
3302 }
3303 #[cfg(feature = "dialect-spark")]
3306 DialectType::Spark => {
3307 let expr = transforms::eliminate_qualify(expr)?;
3308 let expr = transforms::add_auto_table_alias(expr)?;
3309 let expr = transforms::simplify_nested_paren_values(expr)?;
3310 let expr = transforms::move_ctes_to_top_level(expr)?;
3311 Ok(expr)
3312 }
3313 #[cfg(feature = "dialect-databricks")]
3316 DialectType::Databricks => {
3317 let expr = transforms::add_auto_table_alias(expr)?;
3318 let expr = transforms::simplify_nested_paren_values(expr)?;
3319 let expr = transforms::move_ctes_to_top_level(expr)?;
3320 Ok(expr)
3321 }
3322 #[cfg(feature = "dialect-hive")]
3324 DialectType::Hive => {
3325 let expr = transforms::eliminate_qualify(expr)?;
3326 let expr = transforms::move_ctes_to_top_level(expr)?;
3327 Ok(expr)
3328 }
3329 #[cfg(feature = "dialect-sqlite")]
3331 DialectType::SQLite => {
3332 let expr = transforms::eliminate_qualify(expr)?;
3333 Ok(expr)
3334 }
3335 #[cfg(feature = "dialect-trino")]
3337 DialectType::Trino => {
3338 let expr = transforms::eliminate_qualify(expr)?;
3339 let expr = transforms::explode_projection_to_unnest(expr, DialectType::Trino)?;
3340 Ok(expr)
3341 }
3342 #[cfg(feature = "dialect-presto")]
3344 DialectType::Presto => {
3345 let expr = transforms::eliminate_qualify(expr)?;
3346 let expr = transforms::eliminate_window_clause(expr)?;
3347 let expr = transforms::explode_projection_to_unnest(expr, DialectType::Presto)?;
3348 Ok(expr)
3349 }
3350 #[cfg(feature = "dialect-duckdb")]
3354 DialectType::DuckDB => {
3355 let expr = transforms::expand_posexplode_duckdb(expr)?;
3356 let expr = transforms::expand_like_any(expr)?;
3357 Ok(expr)
3358 }
3359 #[cfg(feature = "dialect-redshift")]
3361 DialectType::Redshift => {
3362 let expr = transforms::eliminate_qualify(expr)?;
3363 let expr = transforms::eliminate_window_clause(expr)?;
3364 let expr = transforms::unnest_generate_date_array_using_recursive_cte(expr)?;
3365 Ok(expr)
3366 }
3367 #[cfg(feature = "dialect-starrocks")]
3369 DialectType::StarRocks => {
3370 let expr = transforms::eliminate_qualify(expr)?;
3371 let expr = transforms::expand_between_in_delete(expr)?;
3372 let expr = transforms::eliminate_distinct_on_for_dialect(
3373 expr,
3374 Some(DialectType::StarRocks),
3375 Some(DialectType::StarRocks),
3376 )?;
3377 let expr = transforms::unnest_generate_date_array_using_recursive_cte(expr)?;
3378 Ok(expr)
3379 }
3380 #[cfg(feature = "dialect-datafusion")]
3382 DialectType::DataFusion => Ok(expr),
3383 #[cfg(feature = "dialect-oracle")]
3385 DialectType::Oracle => {
3386 let expr = transforms::eliminate_qualify(expr)?;
3387 Ok(expr)
3388 }
3389 #[cfg(feature = "dialect-drill")]
3391 DialectType::Drill => Ok(expr),
3392 #[cfg(feature = "dialect-teradata")]
3394 DialectType::Teradata => Ok(expr),
3395 #[cfg(feature = "dialect-clickhouse")]
3397 DialectType::ClickHouse => {
3398 let expr = transforms::no_limit_order_by_union(expr)?;
3399 Ok(expr)
3400 }
3401 _ => Ok(expr),
3403 }
3404 }
3405
3406 #[cfg(feature = "transpile")]
3419 pub fn transpile<T: TranspileTarget>(&self, sql: &str, target: T) -> Result<Vec<String>> {
3420 self.transpile_with(sql, target, TranspileOptions::default())
3421 }
3422
3423 #[cfg(feature = "transpile")]
3425 pub fn transpile_with<T: TranspileTarget>(
3426 &self,
3427 sql: &str,
3428 target: T,
3429 opts: TranspileOptions,
3430 ) -> Result<Vec<String>> {
3431 target.with_dialect(|td| self.transpile_inner(sql, td, &opts))
3432 }
3433
3434 #[cfg(feature = "transpile")]
3435 fn transpile_inner(
3436 &self,
3437 sql: &str,
3438 target_dialect: &Dialect,
3439 opts: &TranspileOptions,
3440 ) -> Result<Vec<String>> {
3441 let mut effective_opts = opts.clone();
3442 effective_opts.complexity_guard =
3443 self.default_transpile_complexity_guard(target_dialect, opts.complexity_guard);
3444 let opts = &effective_opts;
3445 let target = target_dialect.dialect_type;
3446 if matches!(self.dialect_type, DialectType::PostgreSQL)
3447 && matches!(target, DialectType::SQLite)
3448 {
3449 self.reject_pgvector_distance_operators_for_sqlite(sql)?;
3450 }
3451 let expressions = self.parse_with_guard(sql, opts.complexity_guard)?;
3452 let generic_identity =
3453 self.dialect_type == DialectType::Generic && target == DialectType::Generic;
3454
3455 if generic_identity {
3456 return expressions
3457 .into_iter()
3458 .map(|expr| {
3459 Self::reject_strict_unsupported(&expr, self.dialect_type, target, opts)?;
3460 target_dialect.generate_with_transpile_options(&expr, self.dialect_type, opts)
3461 })
3462 .collect();
3463 }
3464
3465 expressions
3466 .into_iter()
3467 .map(|expr| {
3468 let expr = if matches!(self.dialect_type, DialectType::DuckDB) {
3472 use crate::expressions::DataType as DT;
3473 transform_recursive(expr, &|e| match e {
3474 Expression::DataType(DT::VarChar { .. }) => {
3475 Ok(Expression::DataType(DT::Text))
3476 }
3477 Expression::DataType(DT::Char { .. }) => Ok(Expression::DataType(DT::Text)),
3478 _ => Ok(e),
3479 })?
3480 } else {
3481 expr
3482 };
3483
3484 Self::reject_clickhouse_session_semantics(&expr, self.dialect_type, target, opts)?;
3485 Self::reject_postgres_tsql_strict_regex_predicates(
3486 &expr,
3487 self.dialect_type,
3488 target,
3489 opts,
3490 )?;
3491 Self::reject_tsql_strict_json_constructor_return_types(
3492 &expr,
3493 self.dialect_type,
3494 target,
3495 opts,
3496 )?;
3497 Self::reject_postgres_tsql_strict_json_aggregate_modifiers(
3498 &expr,
3499 self.dialect_type,
3500 target,
3501 opts,
3502 )?;
3503
3504 let normalized =
3508 if self.dialect_type != target && self.dialect_type != DialectType::Generic {
3509 self.transform_with_guard(expr, opts.complexity_guard)?
3510 } else {
3511 expr
3512 };
3513
3514 let normalized =
3519 if matches!(self.dialect_type, DialectType::TSQL | DialectType::Fabric)
3520 && !matches!(target, DialectType::TSQL | DialectType::Fabric)
3521 {
3522 transform_recursive(normalized, &|e| {
3523 if let Expression::Function(ref f) = e {
3524 if f.name.eq_ignore_ascii_case("ISNULL") && f.args.len() == 2 {
3525 if let (
3527 Expression::Function(ref jq),
3528 Expression::Function(ref jv),
3529 ) = (&f.args[0], &f.args[1])
3530 {
3531 if jq.name.eq_ignore_ascii_case("JSON_QUERY")
3532 && jv.name.eq_ignore_ascii_case("JSON_VALUE")
3533 {
3534 return Ok(f.args[0].clone());
3536 }
3537 }
3538 }
3539 }
3540 Ok(e)
3541 })?
3542 } else {
3543 normalized
3544 };
3545
3546 let normalized = if matches!(self.dialect_type, DialectType::Snowflake)
3550 && !matches!(target, DialectType::Snowflake)
3551 {
3552 transform_recursive(normalized, &|e| match e {
3553 Expression::Function(ref f)
3554 if f.name.eq_ignore_ascii_case("CURRENT_TIME") =>
3555 {
3556 let precision = if matches!(target, DialectType::ClickHouse) {
3557 f.args.first().cloned().map(Box::new)
3558 } else {
3559 None
3560 };
3561 Ok(Expression::Localtime(Box::new(
3562 crate::expressions::Localtime { this: precision },
3563 )))
3564 }
3565 Expression::Localtime(ref localtime)
3566 if !matches!(target, DialectType::ClickHouse)
3567 && localtime.this.is_some() =>
3568 {
3569 Ok(Expression::Localtime(Box::new(
3570 crate::expressions::Localtime { this: None },
3571 )))
3572 }
3573 _ => Ok(e),
3574 })?
3575 } else {
3576 normalized
3577 };
3578
3579 let normalized = if matches!(self.dialect_type, DialectType::Snowflake)
3583 && matches!(target, DialectType::DuckDB)
3584 {
3585 transform_recursive(normalized, &|e| {
3586 if let Expression::Function(ref f) = e {
3587 if f.name.eq_ignore_ascii_case("REPEAT") && f.args.len() == 2 {
3588 if let Expression::Literal(ref lit) = f.args[0] {
3590 if let crate::expressions::Literal::String(ref s) = lit.as_ref()
3591 {
3592 if s == " " {
3593 if !matches!(f.args[1], Expression::Cast(_)) {
3595 let mut new_args = f.args.clone();
3596 new_args[1] = Expression::Cast(Box::new(
3597 crate::expressions::Cast {
3598 this: new_args[1].clone(),
3599 to: crate::expressions::DataType::BigInt {
3600 length: None,
3601 },
3602 trailing_comments: Vec::new(),
3603 double_colon_syntax: false,
3604 format: None,
3605 default: None,
3606 inferred_type: None,
3607 },
3608 ));
3609 return Ok(Expression::Function(Box::new(
3610 crate::expressions::Function {
3611 name: f.name.clone(),
3612 args: new_args,
3613 distinct: f.distinct,
3614 trailing_comments: f
3615 .trailing_comments
3616 .clone(),
3617 use_bracket_syntax: f.use_bracket_syntax,
3618 no_parens: f.no_parens,
3619 quoted: f.quoted,
3620 span: None,
3621 inferred_type: None,
3622 },
3623 )));
3624 }
3625 }
3626 }
3627 }
3628 }
3629 }
3630 Ok(e)
3631 })?
3632 } else {
3633 normalized
3634 };
3635
3636 let normalized = if matches!(self.dialect_type, DialectType::BigQuery)
3639 && !matches!(target, DialectType::BigQuery)
3640 {
3641 crate::transforms::propagate_struct_field_names(normalized)?
3642 } else {
3643 normalized
3644 };
3645
3646 let normalized = if matches!(self.dialect_type, DialectType::Snowflake)
3651 && matches!(target, DialectType::DuckDB)
3652 {
3653 fn make_scaled_random() -> Expression {
3654 let lower =
3655 Expression::Literal(Box::new(crate::expressions::Literal::Number(
3656 "-9.223372036854776E+18".to_string(),
3657 )));
3658 let upper =
3659 Expression::Literal(Box::new(crate::expressions::Literal::Number(
3660 "9.223372036854776e+18".to_string(),
3661 )));
3662 let random_call = Expression::Random(crate::expressions::Random);
3663 let range_size = Expression::Paren(Box::new(crate::expressions::Paren {
3664 this: Expression::Sub(Box::new(crate::expressions::BinaryOp {
3665 left: upper,
3666 right: lower.clone(),
3667 left_comments: vec![],
3668 operator_comments: vec![],
3669 trailing_comments: vec![],
3670 inferred_type: None,
3671 })),
3672 trailing_comments: vec![],
3673 }));
3674 let scaled = Expression::Mul(Box::new(crate::expressions::BinaryOp {
3675 left: random_call,
3676 right: range_size,
3677 left_comments: vec![],
3678 operator_comments: vec![],
3679 trailing_comments: vec![],
3680 inferred_type: None,
3681 }));
3682 let shifted = Expression::Add(Box::new(crate::expressions::BinaryOp {
3683 left: lower,
3684 right: scaled,
3685 left_comments: vec![],
3686 operator_comments: vec![],
3687 trailing_comments: vec![],
3688 inferred_type: None,
3689 }));
3690 Expression::Cast(Box::new(crate::expressions::Cast {
3691 this: shifted,
3692 to: crate::expressions::DataType::BigInt { length: None },
3693 trailing_comments: vec![],
3694 double_colon_syntax: false,
3695 format: None,
3696 default: None,
3697 inferred_type: None,
3698 }))
3699 }
3700
3701 let normalized = transform_recursive(normalized, &|e| {
3708 if let Expression::Function(ref f) = e {
3709 let n = f.name.to_ascii_uppercase();
3710 if n == "UNIFORM" || n == "NORMAL" || n == "ZIPF" || n == "RANDSTR" {
3711 if let Expression::Function(mut f) = e {
3712 for arg in f.args.iter_mut() {
3713 if let Expression::Rand(ref r) = arg {
3714 if r.lower.is_none() && r.upper.is_none() {
3715 if let Some(ref seed) = r.seed {
3716 *arg = Expression::Function(Box::new(
3719 crate::expressions::Function::new(
3720 "RANDOM".to_string(),
3721 vec![*seed.clone()],
3722 ),
3723 ));
3724 }
3725 }
3726 }
3727 }
3728 return Ok(Expression::Function(f));
3729 }
3730 }
3731 }
3732 Ok(e)
3733 })?;
3734
3735 transform_recursive(normalized, &|e| {
3743 if let Expression::Function(ref f) = e {
3744 let n = f.name.to_ascii_uppercase();
3745 if n == "UNIFORM" || n == "NORMAL" || n == "ZIPF" {
3746 if let Expression::Function(mut f) = e {
3747 for arg in f.args.iter_mut() {
3748 if let Expression::Cast(ref cast) = arg {
3750 if matches!(
3751 cast.to,
3752 crate::expressions::DataType::BigInt { .. }
3753 ) {
3754 if let Expression::Add(ref add) = cast.this {
3755 if let Expression::Literal(ref lit) = add.left {
3756 if let crate::expressions::Literal::Number(
3757 ref num,
3758 ) = lit.as_ref()
3759 {
3760 if num == "-9.223372036854776E+18" {
3761 *arg = Expression::Random(
3762 crate::expressions::Random,
3763 );
3764 }
3765 }
3766 }
3767 }
3768 }
3769 }
3770 }
3771 return Ok(Expression::Function(f));
3772 }
3773 return Ok(e);
3774 }
3775 }
3776 match e {
3777 Expression::Random(_) => Ok(make_scaled_random()),
3778 Expression::Rand(ref r) if r.lower.is_none() && r.upper.is_none() => {
3781 Ok(make_scaled_random())
3782 }
3783 _ => Ok(e),
3784 }
3785 })?
3786 } else {
3787 normalized
3788 };
3789
3790 let normalized = normalization::normalize(
3792 normalized,
3793 self.dialect_type,
3794 target,
3795 matches!(
3796 opts.unsupported_level,
3797 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
3798 ),
3799 )?;
3800
3801 let normalized = if matches!(target, DialectType::TSQL | DialectType::Fabric) {
3802 Self::normalize_tsql_fetch_overlaps_date_bin(normalized)?
3803 } else {
3804 normalized
3805 };
3806
3807 let normalized =
3808 if matches!(
3809 self.dialect_type,
3810 DialectType::PostgreSQL | DialectType::CockroachDB
3811 ) && !matches!(target, DialectType::PostgreSQL | DialectType::CockroachDB)
3812 {
3813 Self::normalize_postgres_type_function_casts(normalized, target)?
3814 } else {
3815 normalized
3816 };
3817
3818 let normalized = if matches!(self.dialect_type, DialectType::SQLite)
3819 && !matches!(target, DialectType::SQLite)
3820 {
3821 Self::normalize_sqlite_double_quoted_defaults(normalized)?
3822 } else {
3823 normalized
3824 };
3825
3826 let normalized = if matches!(self.dialect_type, DialectType::PostgreSQL)
3827 && matches!(target, DialectType::SQLite)
3828 {
3829 Self::normalize_postgres_to_sqlite_types(normalized)?
3830 } else {
3831 normalized
3832 };
3833
3834 let normalized = if matches!(self.dialect_type, DialectType::PostgreSQL)
3835 && matches!(target, DialectType::Fabric)
3836 {
3837 Self::normalize_postgres_to_fabric_types(normalized)?
3838 } else {
3839 normalized
3840 };
3841
3842 let normalized = if matches!(self.dialect_type, DialectType::BigQuery)
3846 && matches!(target, DialectType::DuckDB)
3847 {
3848 crate::transforms::wrap_duckdb_unnest_struct(normalized)?
3849 } else {
3850 normalized
3851 };
3852
3853 let normalized = if matches!(self.dialect_type, DialectType::BigQuery)
3856 && matches!(
3857 target,
3858 DialectType::DuckDB
3859 | DialectType::Presto
3860 | DialectType::Trino
3861 | DialectType::Athena
3862 | DialectType::Spark
3863 | DialectType::Databricks
3864 ) {
3865 crate::transforms::unnest_alias_to_column_alias(normalized)?
3866 } else if matches!(self.dialect_type, DialectType::BigQuery)
3867 && matches!(target, DialectType::BigQuery | DialectType::Redshift)
3868 {
3869 let result = crate::transforms::unnest_from_to_cross_join(normalized)?;
3872 if matches!(target, DialectType::Redshift) {
3874 crate::transforms::strip_unnest_column_refs(result)?
3875 } else {
3876 result
3877 }
3878 } else {
3879 normalized
3880 };
3881
3882 let normalized = if matches!(
3885 self.dialect_type,
3886 DialectType::PostgreSQL | DialectType::Redshift
3887 ) && matches!(
3888 target,
3889 DialectType::Presto | DialectType::Trino | DialectType::Athena
3890 ) {
3891 crate::transforms::wrap_unnest_join_aliases(normalized)?
3892 } else {
3893 normalized
3894 };
3895
3896 let normalized = crate::transforms::eliminate_distinct_on_for_dialect(
3900 normalized,
3901 Some(target),
3902 Some(self.dialect_type),
3903 )?;
3904
3905 let normalized = if matches!(target, DialectType::Snowflake) {
3907 Self::transform_generate_date_array_snowflake(normalized)?
3908 } else {
3909 normalized
3910 };
3911
3912 let normalized = if matches!(
3914 target,
3915 DialectType::Spark | DialectType::Databricks | DialectType::Hive
3916 ) {
3917 crate::transforms::unnest_to_explode_select(normalized)?
3918 } else {
3919 normalized
3920 };
3921
3922 let normalized = if matches!(target, DialectType::ClickHouse | DialectType::TSQL) {
3924 crate::transforms::no_limit_order_by_union(normalized)?
3925 } else {
3926 normalized
3927 };
3928
3929 let normalized = if matches!(
3930 self.dialect_type,
3931 DialectType::PostgreSQL | DialectType::CockroachDB
3932 ) && matches!(target, DialectType::TSQL | DialectType::Fabric)
3933 {
3934 Self::normalize_postgres_boolean_semantics_for_tsql(normalized)?
3935 } else {
3936 normalized
3937 };
3938
3939 let normalized = if self.dialect_type == DialectType::PostgreSQL
3940 && matches!(target, DialectType::TSQL | DialectType::Fabric)
3941 {
3942 Self::normalize_postgres_bytea_literals_for_tsql(normalized)?
3943 } else {
3944 normalized
3945 };
3946
3947 let normalized = if matches!(
3948 self.dialect_type,
3949 DialectType::PostgreSQL | DialectType::CockroachDB
3950 ) && matches!(target, DialectType::TSQL | DialectType::Fabric)
3951 {
3952 Self::normalize_postgres_string_semantics_for_tsql(normalized)?
3953 } else {
3954 normalized
3955 };
3956
3957 let normalized = if matches!(target, DialectType::TSQL | DialectType::Fabric)
3961 && !matches!(self.dialect_type, DialectType::TSQL | DialectType::Fabric)
3962 {
3963 transform_recursive(normalized, &|e| {
3964 if let Expression::Count(ref c) = e {
3965 let args = if c.star {
3967 vec![Expression::Star(crate::expressions::Star {
3968 table: None,
3969 except: None,
3970 replace: None,
3971 rename: None,
3972 trailing_comments: Vec::new(),
3973 span: None,
3974 })]
3975 } else if let Some(ref this) = c.this {
3976 vec![this.clone()]
3977 } else {
3978 vec![]
3979 };
3980 Ok(Expression::AggregateFunction(Box::new(
3981 crate::expressions::AggregateFunction {
3982 name: "COUNT_BIG".to_string(),
3983 args,
3984 distinct: c.distinct,
3985 filter: c.filter.clone(),
3986 order_by: Vec::new(),
3987 limit: None,
3988 ignore_nulls: None,
3989 inferred_type: None,
3990 },
3991 )))
3992 } else {
3993 Ok(e)
3994 }
3995 })?
3996 } else {
3997 normalized
3998 };
3999
4000 let normalized = if matches!(target, DialectType::TSQL | DialectType::Fabric)
4004 && !matches!(self.dialect_type, DialectType::TSQL | DialectType::Fabric)
4005 {
4006 let normalized = if self.dialect_type == DialectType::PostgreSQL {
4007 Self::rewrite_postgres_row_value_equality_for_tsql(normalized)?
4008 } else {
4009 normalized
4010 };
4011 Self::rewrite_boolean_values_for_tsql(normalized)?
4012 } else {
4013 normalized
4014 };
4015
4016 let normalized = if matches!(
4017 self.dialect_type,
4018 DialectType::PostgreSQL | DialectType::CockroachDB
4019 ) && matches!(target, DialectType::TSQL | DialectType::Fabric)
4020 {
4021 Self::rewrite_postgres_format_for_tsql(normalized, target)?
4022 } else {
4023 normalized
4024 };
4025
4026 let normalized = if self.dialect_type == DialectType::PostgreSQL
4027 && matches!(target, DialectType::TSQL | DialectType::Fabric)
4028 {
4029 Self::normalize_postgres_only_for_tsql(normalized)?
4030 } else {
4031 normalized
4032 };
4033
4034 let transformed =
4035 target_dialect.transform_with_guard(normalized, opts.complexity_guard)?;
4036
4037 let transformed = if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4041 Self::rewrite_aggregate_filters_for_tsql(transformed)?
4042 } else {
4043 transformed
4044 };
4045
4046 let transformed = if matches!(
4047 self.dialect_type,
4048 DialectType::PostgreSQL | DialectType::CockroachDB
4049 ) && matches!(target, DialectType::TSQL | DialectType::Fabric)
4050 {
4051 crate::transforms::grouped_percentiles_to_tsql_windows(transformed)?
4052 } else {
4053 transformed
4054 };
4055
4056 let transformed = if matches!(
4057 self.dialect_type,
4058 DialectType::PostgreSQL | DialectType::CockroachDB
4059 ) && matches!(target, DialectType::TSQL | DialectType::Fabric)
4060 {
4061 Self::normalize_postgres_trim_for_tsql(transformed)?
4062 } else {
4063 transformed
4064 };
4065
4066 let transformed = if matches!(
4067 self.dialect_type,
4068 DialectType::PostgreSQL | DialectType::CockroachDB
4069 ) && matches!(target, DialectType::TSQL | DialectType::Fabric)
4070 {
4071 Self::rewrite_postgres_json_array_elements_select_for_tsql(transformed)?
4072 } else {
4073 transformed
4074 };
4075
4076 let transformed = if matches!(target, DialectType::DuckDB) {
4078 Self::seq_rownum_to_range(transformed)?
4079 } else {
4080 transformed
4081 };
4082
4083 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4084 Self::reject_tsql_interval_casts(&transformed, target, opts)?;
4085 }
4086
4087 let transformed = if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4088 Self::rewrite_tsql_interval_casts_to_varchar(transformed)?
4089 } else {
4090 transformed
4091 };
4092
4093 let transformed = if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4094 Self::legalize_tsql_nested_order_by(transformed)?
4095 } else {
4096 transformed
4097 };
4098
4099 Self::reject_strict_unsupported(&transformed, self.dialect_type, target, opts)?;
4100
4101 let mut sql = target_dialect.generate_with_transpile_options(
4102 &transformed,
4103 self.dialect_type,
4104 opts,
4105 )?;
4106
4107 if opts.pretty && target == DialectType::Snowflake {
4109 sql = Self::normalize_snowflake_pretty(sql);
4110 }
4111
4112 Ok(sql)
4113 })
4114 .collect()
4115 }
4116}
4117
4118#[cfg(feature = "transpile")]
4120impl Dialect {
4121 fn legalize_tsql_nested_order_by(expr: Expression) -> Result<Expression> {
4122 let preserve_root_order = matches!(&expr, Expression::Select(select) if Self::tsql_select_needs_order_offset(select));
4123
4124 let mut transformed = transform_recursive(expr, &|node| match node {
4125 Expression::Select(mut select) => {
4126 Self::legalize_tsql_select_offset(&mut select);
4127 if Self::tsql_select_needs_order_offset(&select) {
4128 select.offset = Some(Offset {
4129 this: Expression::Literal(Box::new(Literal::Number("0".to_string()))),
4130 rows: Some(true),
4131 });
4132 }
4133 Ok(Expression::Select(select))
4134 }
4135 Expression::Subquery(mut subquery) => {
4136 Self::legalize_tsql_offset(&mut subquery.order_by, &mut subquery.offset, false);
4137 Ok(Expression::Subquery(subquery))
4138 }
4139 Expression::Union(mut union) => {
4140 Self::legalize_tsql_set_offset(&mut union.order_by, &mut union.offset);
4141 Ok(Expression::Union(union))
4142 }
4143 Expression::Intersect(mut intersect) => {
4144 Self::legalize_tsql_set_offset(&mut intersect.order_by, &mut intersect.offset);
4145 Ok(Expression::Intersect(intersect))
4146 }
4147 Expression::Except(mut except) => {
4148 Self::legalize_tsql_set_offset(&mut except.order_by, &mut except.offset);
4149 Ok(Expression::Except(except))
4150 }
4151 other => Ok(other),
4152 })?;
4153
4154 if preserve_root_order {
4155 if let Expression::Select(select) = &mut transformed {
4156 select.offset = None;
4157 }
4158 }
4159
4160 Self::drop_tsql_unbounded_nested_set_order_by(transformed)
4161 }
4162
4163 fn drop_tsql_unbounded_nested_set_order_by(mut expr: Expression) -> Result<Expression> {
4164 let root_order_by = Self::take_tsql_root_set_order_by(&mut expr);
4165
4166 let mut transformed = transform_recursive(expr, &|node| match node {
4167 Expression::Union(mut union) => {
4168 if union.limit.is_none() && union.offset.is_none() {
4169 union.order_by = None;
4170 }
4171 Ok(Expression::Union(union))
4172 }
4173 Expression::Intersect(mut intersect) => {
4174 if intersect.limit.is_none() && intersect.offset.is_none() {
4175 intersect.order_by = None;
4176 }
4177 Ok(Expression::Intersect(intersect))
4178 }
4179 Expression::Except(mut except) => {
4180 if except.limit.is_none() && except.offset.is_none() {
4181 except.order_by = None;
4182 }
4183 Ok(Expression::Except(except))
4184 }
4185 other => Ok(other),
4186 })?;
4187
4188 if let Some(order_by) = root_order_by {
4189 Self::restore_tsql_root_set_order_by(&mut transformed, order_by);
4190 }
4191
4192 Ok(transformed)
4193 }
4194
4195 fn take_tsql_root_set_order_by(expr: &mut Expression) -> Option<OrderBy> {
4196 match expr {
4197 Expression::Union(union) => union.order_by.take(),
4198 Expression::Intersect(intersect) => intersect.order_by.take(),
4199 Expression::Except(except) => except.order_by.take(),
4200 Expression::Subquery(subquery) if subquery.alias.is_none() => {
4201 Self::take_tsql_root_set_order_by(&mut subquery.this)
4202 }
4203 Expression::Paren(paren) => Self::take_tsql_root_set_order_by(&mut paren.this),
4204 _ => None,
4205 }
4206 }
4207
4208 fn restore_tsql_root_set_order_by(expr: &mut Expression, order_by: OrderBy) {
4209 match expr {
4210 Expression::Union(union) => union.order_by = Some(order_by),
4211 Expression::Intersect(intersect) => intersect.order_by = Some(order_by),
4212 Expression::Except(except) => except.order_by = Some(order_by),
4213 Expression::Subquery(subquery) if subquery.alias.is_none() => {
4214 Self::restore_tsql_root_set_order_by(&mut subquery.this, order_by);
4215 }
4216 Expression::Paren(paren) => {
4217 Self::restore_tsql_root_set_order_by(&mut paren.this, order_by);
4218 }
4219 _ => {}
4220 }
4221 }
4222
4223 fn legalize_tsql_select_offset(select: &mut crate::expressions::Select) {
4224 let has_fetch = select.fetch.is_some();
4225 Self::legalize_tsql_offset(&mut select.order_by, &mut select.offset, has_fetch);
4226 }
4227
4228 fn legalize_tsql_offset(
4229 order_by: &mut Option<OrderBy>,
4230 offset: &mut Option<Offset>,
4231 retain_inert_offset: bool,
4232 ) {
4233 if order_by.is_some() {
4234 return;
4235 }
4236
4237 if offset
4238 .as_ref()
4239 .is_some_and(|offset| Self::tsql_offset_is_inert(&offset.this))
4240 && !retain_inert_offset
4241 {
4242 *offset = None;
4243 } else if offset.is_some() {
4244 *order_by = Some(Generator::dummy_tsql_order_by());
4245 }
4246 }
4247
4248 fn legalize_tsql_set_offset(
4249 order_by: &mut Option<OrderBy>,
4250 offset: &mut Option<Box<Expression>>,
4251 ) {
4252 if order_by.is_some() {
4253 return;
4254 }
4255
4256 if offset.as_deref().is_some_and(Self::tsql_offset_is_inert) {
4257 *offset = None;
4258 } else if offset.is_some() {
4259 *order_by = Some(Generator::dummy_tsql_order_by());
4260 }
4261 }
4262
4263 fn tsql_offset_is_inert(expr: &Expression) -> bool {
4264 match expr {
4265 Expression::Null(_) => true,
4266 Expression::Literal(literal) => match literal.as_ref() {
4267 Literal::Number(value) => value.parse::<i128>().is_ok_and(|value| value == 0),
4268 _ => false,
4269 },
4270 _ => false,
4271 }
4272 }
4273
4274 fn tsql_select_needs_order_offset(select: &crate::expressions::Select) -> bool {
4275 select.order_by.is_some()
4276 && select.top.is_none()
4277 && select.limit.is_none()
4278 && select.offset.is_none()
4279 && select.fetch.is_none()
4280 && select.for_xml.is_empty()
4281 && select.for_json.is_empty()
4282 }
4283
4284 fn reject_clickhouse_session_semantics(
4285 expr: &Expression,
4286 source: DialectType,
4287 target: DialectType,
4288 opts: &TranspileOptions,
4289 ) -> Result<()> {
4290 if !matches!(
4291 opts.unsupported_level,
4292 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4293 ) || target != DialectType::ClickHouse
4294 || source == DialectType::ClickHouse
4295 {
4296 return Ok(());
4297 }
4298
4299 const JOIN_USE_NULLS_DIAGNOSTIC: &str = "ClickHouse outer joins require the target setting join_use_nulls = 1 to preserve unmatched-row NULL semantics";
4300 const AGGREGATE_NULL_FOR_EMPTY_DIAGNOSTIC: &str = "ClickHouse non-count aggregates require the target setting aggregate_functions_null_for_empty = 1 to preserve empty-input NULL semantics";
4301
4302 fn is_current_session_time(node: &Expression) -> bool {
4303 match node {
4304 Expression::CurrentDate(_)
4305 | Expression::CurrentTime(_)
4306 | Expression::CurrentTimestamp(_)
4307 | Expression::CurrentTimestampLTZ(_)
4308 | Expression::Localtime(_)
4309 | Expression::Localtimestamp(_)
4310 | Expression::Systimestamp(_) => true,
4311 Expression::Function(function) if !function.quoted => matches!(
4312 function.name.to_ascii_uppercase().as_str(),
4313 "CURRENT_DATE"
4314 | "CURRENT_TIME"
4315 | "LOCALTIME"
4316 | "CURRENT_TIMESTAMP"
4317 | "CURRENT_TIMESTAMP_LTZ"
4318 | "LOCALTIMESTAMP"
4319 | "NOW"
4320 | "GETDATE"
4321 | "SYSTIMESTAMP"
4322 ),
4323 _ => false,
4324 }
4325 }
4326
4327 fn is_session_week_part(expression: &Expression) -> bool {
4328 let part = match expression {
4329 Expression::Literal(literal) => match literal.as_ref() {
4330 Literal::String(value) => Some(value.as_str()),
4331 _ => None,
4332 },
4333 Expression::Identifier(identifier) => Some(identifier.name.as_str()),
4334 Expression::Var(var) => Some(var.this.as_str()),
4335 Expression::Column(column) if column.table.is_none() => {
4336 Some(column.name.name.as_str())
4337 }
4338 _ => None,
4339 };
4340 part.is_some_and(|part| {
4341 matches!(
4342 part.to_ascii_uppercase().as_str(),
4343 "WEEK" | "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY"
4344 )
4345 })
4346 }
4347
4348 fn is_session_week_trunc(node: &Expression) -> bool {
4349 match node {
4350 Expression::DateTrunc(date_trunc) => {
4351 matches!(date_trunc.unit, DateTimeField::Week)
4352 }
4353 Expression::Function(function)
4354 if !function.quoted && function.name.eq_ignore_ascii_case("DATE_TRUNC") =>
4355 {
4356 function.args.first().is_some_and(is_session_week_part)
4357 }
4358 _ => false,
4359 }
4360 }
4361
4362 fn is_null_extending_clickhouse_join(node: &Expression) -> bool {
4363 fn join_is_null_extending(join: &Join) -> bool {
4364 matches!(
4365 join.kind,
4366 JoinKind::Left
4367 | JoinKind::Right
4368 | JoinKind::Full
4369 | JoinKind::NaturalLeft
4370 | JoinKind::NaturalRight
4371 | JoinKind::NaturalFull
4372 | JoinKind::AsOfLeft
4373 | JoinKind::AsOfRight
4374 )
4375 }
4376
4377 fn joins_are_null_extending(joins: &[Join]) -> bool {
4378 joins.iter().any(join_is_null_extending)
4379 }
4380
4381 match node {
4382 Expression::Join(join) => join_is_null_extending(join),
4383 Expression::Select(select) => joins_are_null_extending(&select.joins),
4384 Expression::JoinedTable(joined) => joins_are_null_extending(&joined.joins),
4385 Expression::Update(update) => {
4386 joins_are_null_extending(&update.table_joins)
4387 || joins_are_null_extending(&update.from_joins)
4388 }
4389 Expression::Delete(delete) => joins_are_null_extending(&delete.joins),
4390 _ => false,
4391 }
4392 }
4393
4394 fn is_count_like_aggregate(node: &Expression) -> bool {
4395 match node {
4396 Expression::Count(_)
4397 | Expression::CountIf(_)
4398 | Expression::ApproxDistinct(_)
4399 | Expression::ApproxCountDistinct(_) => true,
4400 Expression::AggregateFunction(function) => matches!(
4401 function.name.to_ascii_uppercase().as_str(),
4402 "COUNT" | "COUNT_IF" | "COUNTIF" | "APPROX_DISTINCT" | "APPROX_COUNT_DISTINCT"
4403 ),
4404 _ => false,
4405 }
4406 }
4407
4408 fn is_empty_input_sensitive_aggregate(node: &Expression, source: DialectType) -> bool {
4409 Dialect::node_is_aggregate_function(node)
4410 && !is_count_like_aggregate(node)
4411 && !matches!(node, Expression::BitwiseCount(_))
4412 && !matches!(node, Expression::Median(_) if source == DialectType::Snowflake)
4413 && !matches!(
4414 node,
4415 Expression::AggregateFunction(function)
4416 if function.name.to_ascii_lowercase().ends_with("ornull")
4417 )
4418 }
4419
4420 fn setting_is_enabled(setting: &Expression, name: &str) -> bool {
4421 let Expression::Eq(equality) = setting else {
4422 return false;
4423 };
4424 let setting_name = match &equality.left {
4425 Expression::Identifier(identifier) => identifier.name.as_str(),
4426 Expression::Column(column) if column.table.is_none() => column.name.name.as_str(),
4427 Expression::Var(var) => var.this.as_str(),
4428 _ => return false,
4429 };
4430 let enabled = match &equality.right {
4431 Expression::Literal(literal) => {
4432 matches!(literal.as_ref(), Literal::Number(value) if value.parse::<i128>().is_ok_and(|value| value == 1))
4433 }
4434 Expression::Boolean(boolean) => boolean.value,
4435 _ => false,
4436 };
4437 setting_name.eq_ignore_ascii_case(name) && enabled
4438 }
4439
4440 fn query_has_enabled_setting(expr: &Expression, name: &str) -> bool {
4441 expr.dfs().any(|node| {
4442 matches!(
4443 node,
4444 Expression::Select(select)
4445 if select.settings.as_ref().is_some_and(|settings| {
4446 settings.iter().any(|setting| setting_is_enabled(setting, name))
4447 })
4448 )
4449 })
4450 }
4451
4452 let mut diagnostics = Vec::new();
4453 let join_use_nulls_enabled = query_has_enabled_setting(expr, "join_use_nulls");
4454 let aggregate_null_for_empty_enabled =
4455 query_has_enabled_setting(expr, "aggregate_functions_null_for_empty");
4456 for node in expr.dfs() {
4457 if source == DialectType::Snowflake && is_current_session_time(node) {
4458 Self::push_unsupported_diagnostic(
4459 &mut diagnostics,
4460 "Snowflake current date/time expressions depend on the session TIMEZONE, which cannot be preserved for ClickHouse",
4461 );
4462 }
4463 if source == DialectType::Snowflake && is_session_week_trunc(node) {
4464 Self::push_unsupported_diagnostic(
4465 &mut diagnostics,
4466 "Snowflake DATE_TRUNC with a week unit depends on the session WEEK_START, which cannot be preserved for ClickHouse",
4467 );
4468 }
4469 if !join_use_nulls_enabled && is_null_extending_clickhouse_join(node) {
4470 Self::push_unsupported_diagnostic(&mut diagnostics, JOIN_USE_NULLS_DIAGNOSTIC);
4471 }
4472 if !aggregate_null_for_empty_enabled && is_empty_input_sensitive_aggregate(node, source)
4473 {
4474 Self::push_unsupported_diagnostic(
4475 &mut diagnostics,
4476 AGGREGATE_NULL_FOR_EMPTY_DIAGNOSTIC,
4477 );
4478 }
4479 if opts.unsupported_level == UnsupportedLevel::Immediate && !diagnostics.is_empty() {
4480 break;
4481 }
4482 }
4483
4484 if diagnostics.is_empty() {
4485 return Ok(());
4486 }
4487
4488 let limit = if opts.unsupported_level == UnsupportedLevel::Immediate {
4489 1
4490 } else {
4491 opts.max_unsupported.max(1)
4492 };
4493 let mut messages = diagnostics.iter().take(limit).cloned().collect::<Vec<_>>();
4494 if diagnostics.len() > limit {
4495 messages.push(format!("... and {} more", diagnostics.len() - limit));
4496 }
4497
4498 Err(crate::error::Error::unsupported(
4499 messages.join("; "),
4500 target.to_string(),
4501 ))
4502 }
4503
4504 fn reject_strict_unsupported(
4505 expr: &Expression,
4506 source: DialectType,
4507 target: DialectType,
4508 opts: &TranspileOptions,
4509 ) -> Result<()> {
4510 if !matches!(
4511 opts.unsupported_level,
4512 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4513 ) {
4514 return Ok(());
4515 }
4516
4517 let mut diagnostics = Vec::new();
4518 if matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4519 && matches!(target, DialectType::TSQL | DialectType::Fabric)
4520 && Self::tsql_apply_has_invalid_outer_aggregate(expr)
4521 {
4522 Self::push_unsupported_diagnostic(
4523 &mut diagnostics,
4524 "APPLY aggregate expressions that combine an outer reference with another column reference",
4525 );
4526 }
4527 let structural_grouping_tuples =
4528 if matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4529 && matches!(target, DialectType::TSQL | DialectType::Fabric)
4530 {
4531 Self::collect_tsql_grouping_tuple_nodes(expr)
4532 } else {
4533 HashSet::new()
4534 };
4535
4536 for node in expr.dfs() {
4537 if source == DialectType::Snowflake && target == DialectType::ClickHouse {
4538 if Self::node_is_function_named(node, "TO_CHAR") {
4539 Self::push_unsupported_diagnostic(
4540 &mut diagnostics,
4541 "Snowflake TO_CHAR overload or dynamic format",
4542 );
4543 }
4544 if Self::node_is_function_named(node, "TRY_TO_DOUBLE")
4545 || matches!(node, Expression::ToDouble(to_double) if to_double.safe.is_some() && to_double.format.is_some())
4546 {
4547 Self::push_unsupported_diagnostic(
4548 &mut diagnostics,
4549 "Snowflake TRY_TO_DOUBLE with a format model",
4550 );
4551 }
4552 if Self::node_is_function_named(node, "TRY_TO_NUMBER")
4553 || Self::node_is_function_named(node, "TRY_TO_NUMERIC")
4554 || Self::node_is_function_named(node, "TRY_TO_DECIMAL")
4555 || matches!(node, Expression::ToNumber(to_number) if to_number.safe.is_some())
4556 {
4557 Self::push_unsupported_diagnostic(
4558 &mut diagnostics,
4559 "Snowflake TRY_TO_NUMBER decimal conversion semantics",
4560 );
4561 }
4562 if Self::node_is_function_named(node, "FLATTEN") {
4563 Self::push_unsupported_diagnostic(
4564 &mut diagnostics,
4565 "Snowflake FLATTEN table-function semantics",
4566 );
4567 }
4568 }
4569
4570 if matches!(target, DialectType::Fabric | DialectType::Hive)
4571 && Self::node_has_recursive_with(node)
4572 {
4573 Self::push_unsupported_diagnostic(&mut diagnostics, "recursive CTEs");
4574 }
4575
4576 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4577 && Self::node_has_lateral(node)
4578 {
4579 Self::push_unsupported_diagnostic(&mut diagnostics, "LATERAL joins and subqueries");
4580 }
4581
4582 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4583 if Self::node_has_join_using(node) {
4584 Self::push_unsupported_diagnostic(&mut diagnostics, "JOIN USING clauses");
4585 }
4586 if Self::node_has_natural_join(node) {
4587 Self::push_unsupported_diagnostic(&mut diagnostics, "NATURAL JOIN");
4588 }
4589 if Self::node_has_unsupported_relation_column_aliases(node) {
4590 Self::push_unsupported_diagnostic(
4591 &mut diagnostics,
4592 "column alias lists on base or joined table references",
4593 );
4594 }
4595 if Self::node_has_qualified_whole_row_aggregate_argument(node) {
4596 Self::push_unsupported_diagnostic(
4597 &mut diagnostics,
4598 "qualified whole-row aggregate arguments",
4599 );
4600 }
4601 if Self::node_has_subquery_in_aggregate_argument(node) {
4602 Self::push_unsupported_diagnostic(
4603 &mut diagnostics,
4604 "aggregate arguments containing subqueries",
4605 );
4606 }
4607 }
4608
4609 if !Self::target_supports_distinct_on(target) && Self::node_has_distinct_on(node) {
4610 Self::push_unsupported_diagnostic(&mut diagnostics, "DISTINCT ON");
4611 }
4612
4613 if !Self::target_supports_remaining_unnest(target) && Self::node_is_unnest(node) {
4614 Self::push_unsupported_diagnostic(&mut diagnostics, "UNNEST");
4615 }
4616
4617 if !Self::target_supports_remaining_explode(target) && Self::node_is_explode(node) {
4618 Self::push_unsupported_diagnostic(&mut diagnostics, "EXPLODE");
4619 }
4620
4621 if Self::target_lacks_array_agg(target) && Self::node_is_array_agg(node) {
4622 Self::push_unsupported_diagnostic(&mut diagnostics, "ARRAY_AGG");
4623 }
4624
4625 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4626 && Self::node_is_distinct_string_agg(node)
4627 {
4628 Self::push_unsupported_diagnostic(&mut diagnostics, "STRING_AGG with DISTINCT");
4629 }
4630
4631 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4632 && matches!(node, Expression::NthValue(_))
4633 {
4634 Self::push_unsupported_diagnostic(&mut diagnostics, "NTH_VALUE");
4635 }
4636
4637 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4638 if let Some(frame) = Self::node_window_frame(node) {
4639 if matches!(frame.kind, WindowFrameKind::Groups) {
4640 Self::push_unsupported_diagnostic(&mut diagnostics, "GROUPS window frames");
4641 }
4642 if matches!(frame.kind, WindowFrameKind::Range)
4643 && (Self::window_frame_bound_has_value_offset(&frame.start)
4644 || frame
4645 .end
4646 .as_ref()
4647 .is_some_and(Self::window_frame_bound_has_value_offset))
4648 {
4649 Self::push_unsupported_diagnostic(
4650 &mut diagnostics,
4651 "value-offset RANGE window frames",
4652 );
4653 }
4654 if frame.exclude.is_some() {
4655 Self::push_unsupported_diagnostic(
4656 &mut diagnostics,
4657 "window frame EXCLUDE clauses",
4658 );
4659 }
4660 }
4661 }
4662
4663 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4664 && Self::node_is_regex_predicate(node)
4665 {
4666 Self::push_unsupported_diagnostic(
4667 &mut diagnostics,
4668 "regular expression predicates",
4669 );
4670 }
4671
4672 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4673 && Self::node_is_non_subquery_any(node)
4674 {
4675 Self::push_unsupported_diagnostic(
4676 &mut diagnostics,
4677 "ANY over non-subquery expressions",
4678 );
4679 }
4680
4681 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4682 && Self::node_is_row_value_subquery_comparison(node)
4683 {
4684 Self::push_unsupported_diagnostic(
4685 &mut diagnostics,
4686 "row-value subquery comparisons",
4687 );
4688 }
4689
4690 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4691 && Self::node_is_row_value_values_membership(node)
4692 {
4693 Self::push_unsupported_diagnostic(
4694 &mut diagnostics,
4695 "row-value VALUES membership comparisons",
4696 );
4697 }
4698
4699 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4700 && Self::node_has_fetch_with_ties(node)
4701 {
4702 Self::push_unsupported_diagnostic(&mut diagnostics, "FETCH WITH TIES without TOP");
4703 }
4704
4705 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4706 && Self::node_is_overlaps(node)
4707 {
4708 Self::push_unsupported_diagnostic(&mut diagnostics, "OVERLAPS");
4709 }
4710
4711 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4712 && Self::node_is_date_bin(node)
4713 {
4714 Self::push_unsupported_diagnostic(&mut diagnostics, "DATE_BIN");
4715 }
4716
4717 if source == DialectType::PostgreSQL
4718 && matches!(target, DialectType::TSQL | DialectType::Fabric)
4719 && Self::node_is_unresolved_postgres_date_subtraction(node)
4720 {
4721 Self::push_unsupported_diagnostic(
4722 &mut diagnostics,
4723 "PostgreSQL date subtraction with an unresolved column type",
4724 );
4725 }
4726
4727 if matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4728 && !matches!(target, DialectType::PostgreSQL | DialectType::CockroachDB)
4729 {
4730 if Self::node_is_postgres_json_build_object(node)
4731 && !(matches!(target, DialectType::TSQL | DialectType::Fabric)
4732 && Self::postgres_json_build_object_can_lower_to_json_object(node))
4733 {
4734 Self::push_unsupported_diagnostic(
4735 &mut diagnostics,
4736 "PostgreSQL JSON_BUILD_OBJECT",
4737 );
4738 }
4739 if Self::node_is_function_named(node, "TO_TSVECTOR") {
4740 Self::push_unsupported_diagnostic(&mut diagnostics, "PostgreSQL TO_TSVECTOR");
4741 }
4742 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4743 if let Some(composite_semantics) =
4744 Self::postgres_tsql_unsupported_composite_semantics(
4745 node,
4746 structural_grouping_tuples.contains(&(node as *const Expression)),
4747 )
4748 {
4749 Self::push_unsupported_diagnostic(
4750 &mut diagnostics,
4751 &format!("PostgreSQL {composite_semantics}"),
4752 );
4753 }
4754 if Self::node_is_postgres_unknown_cast(node) {
4755 Self::push_unsupported_diagnostic(
4756 &mut diagnostics,
4757 "PostgreSQL unresolved UNKNOWN casts",
4758 );
4759 }
4760 if let Some(collation_name) =
4761 Self::postgres_tsql_unsupported_collation_name(node)
4762 {
4763 Self::push_unsupported_diagnostic(
4764 &mut diagnostics,
4765 &format!("PostgreSQL collation \"{collation_name}\""),
4766 );
4767 }
4768 if let Some(array_semantics) =
4769 Self::postgres_tsql_unsupported_array_semantics(node)
4770 {
4771 Self::push_unsupported_diagnostic(
4772 &mut diagnostics,
4773 &format!("PostgreSQL {array_semantics}"),
4774 );
4775 }
4776 if let Some(string_semantics) =
4777 Self::postgres_tsql_unsupported_string_semantics(node)
4778 {
4779 Self::push_unsupported_diagnostic(
4780 &mut diagnostics,
4781 &format!("PostgreSQL {string_semantics}"),
4782 );
4783 }
4784 if source == DialectType::PostgreSQL {
4785 if let Some(binary_semantics) =
4786 Self::postgres_tsql_unsupported_binary_semantics(node)
4787 {
4788 Self::push_unsupported_diagnostic(
4789 &mut diagnostics,
4790 &format!("PostgreSQL {binary_semantics}"),
4791 );
4792 }
4793 }
4794 if let Some(function_name) =
4795 Self::postgres_tsql_unsupported_function_name(node, target)
4796 {
4797 Self::push_unsupported_diagnostic(
4798 &mut diagnostics,
4799 &format!("PostgreSQL {function_name}"),
4800 );
4801 }
4802 }
4803 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4804 && Self::node_is_postgres_type_function_cast(node)
4805 {
4806 Self::push_unsupported_diagnostic(
4807 &mut diagnostics,
4808 "PostgreSQL type-name function casts",
4809 );
4810 }
4811 }
4812
4813 if opts.unsupported_level == UnsupportedLevel::Immediate && !diagnostics.is_empty() {
4814 break;
4815 }
4816 }
4817
4818 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4819 Self::collect_tsql_unsupported_ordered_sets(expr, &mut diagnostics);
4820 Self::collect_tsql_windows_missing_order(expr, &HashMap::new(), &mut diagnostics);
4821 }
4822
4823 if diagnostics.is_empty() {
4824 return Ok(());
4825 }
4826
4827 let limit = if opts.unsupported_level == UnsupportedLevel::Immediate {
4828 1
4829 } else {
4830 opts.max_unsupported.max(1)
4831 };
4832 let mut messages = diagnostics.iter().take(limit).cloned().collect::<Vec<_>>();
4833 if diagnostics.len() > limit {
4834 messages.push(format!("... and {} more", diagnostics.len() - limit));
4835 }
4836
4837 Err(crate::error::Error::unsupported(
4838 messages.join("; "),
4839 target.to_string(),
4840 ))
4841 }
4842
4843 fn reject_postgres_tsql_strict_regex_predicates(
4844 expr: &Expression,
4845 source: DialectType,
4846 target: DialectType,
4847 opts: &TranspileOptions,
4848 ) -> Result<()> {
4849 if !matches!(
4850 opts.unsupported_level,
4851 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4852 ) || !matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4853 || !matches!(target, DialectType::TSQL | DialectType::Fabric)
4854 {
4855 return Ok(());
4856 }
4857
4858 if expr.dfs().any(Self::node_is_regex_predicate) {
4859 return Err(crate::error::Error::unsupported(
4860 "regular expression predicates",
4861 target.to_string(),
4862 ));
4863 }
4864
4865 Ok(())
4866 }
4867
4868 fn reject_tsql_strict_json_constructor_return_types(
4869 expr: &Expression,
4870 source: DialectType,
4871 target: DialectType,
4872 opts: &TranspileOptions,
4873 ) -> Result<()> {
4874 if !matches!(
4875 opts.unsupported_level,
4876 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4877 ) || source == target
4878 || !matches!(target, DialectType::TSQL | DialectType::Fabric)
4879 {
4880 return Ok(());
4881 }
4882
4883 let mut diagnostics = Vec::new();
4884 for node in expr.dfs() {
4885 if let Some(return_type) =
4886 normalization::unsupported_tsql_json_constructor_return_type(node)
4887 {
4888 let message =
4889 format!("SQL/JSON constructor RETURNING {return_type} cannot be preserved");
4890 Self::push_unsupported_diagnostic(&mut diagnostics, &message);
4891 if opts.unsupported_level == UnsupportedLevel::Immediate {
4892 break;
4893 }
4894 }
4895 }
4896
4897 if diagnostics.is_empty() {
4898 return Ok(());
4899 }
4900
4901 let limit = if opts.unsupported_level == UnsupportedLevel::Immediate {
4902 1
4903 } else {
4904 opts.max_unsupported.max(1)
4905 };
4906 let mut messages = diagnostics.iter().take(limit).cloned().collect::<Vec<_>>();
4907 if diagnostics.len() > limit {
4908 messages.push(format!("... and {} more", diagnostics.len() - limit));
4909 }
4910
4911 Err(crate::error::Error::unsupported(
4912 messages.join("; "),
4913 target.to_string(),
4914 ))
4915 }
4916
4917 fn reject_postgres_tsql_strict_json_aggregate_modifiers(
4918 expr: &Expression,
4919 source: DialectType,
4920 target: DialectType,
4921 opts: &TranspileOptions,
4922 ) -> Result<()> {
4923 if !matches!(
4924 opts.unsupported_level,
4925 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4926 ) || !matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4927 || !matches!(target, DialectType::TSQL | DialectType::Fabric)
4928 {
4929 return Ok(());
4930 }
4931
4932 let mut diagnostics = Vec::new();
4933 for node in expr.dfs() {
4934 match node {
4935 Expression::Function(function)
4936 if !function.quoted
4937 && matches!(
4938 function.name.to_ascii_uppercase().as_str(),
4939 "JSON_AGG" | "JSONB_AGG"
4940 ) =>
4941 {
4942 let name = function.name.to_ascii_uppercase();
4943 if function.args.len() != 1 {
4944 Self::push_unsupported_diagnostic(
4945 &mut diagnostics,
4946 &format!("PostgreSQL {name} with invalid argument count"),
4947 );
4948 }
4949 if function.distinct {
4950 Self::push_unsupported_diagnostic(
4951 &mut diagnostics,
4952 &format!("PostgreSQL {name} with DISTINCT"),
4953 );
4954 }
4955 }
4956 Expression::AggregateFunction(function)
4957 if matches!(
4958 function.name.to_ascii_uppercase().as_str(),
4959 "JSON_AGG" | "JSONB_AGG"
4960 ) =>
4961 {
4962 let name = function.name.to_ascii_uppercase();
4963 if function.args.len() != 1 {
4964 Self::push_unsupported_diagnostic(
4965 &mut diagnostics,
4966 &format!("PostgreSQL {name} with invalid argument count"),
4967 );
4968 }
4969 if function.distinct {
4970 Self::push_unsupported_diagnostic(
4971 &mut diagnostics,
4972 &format!("PostgreSQL {name} with DISTINCT"),
4973 );
4974 }
4975 if function.filter.is_some() {
4976 Self::push_unsupported_diagnostic(
4977 &mut diagnostics,
4978 &format!("PostgreSQL {name} with FILTER"),
4979 );
4980 }
4981 if function.limit.is_some() || function.ignore_nulls.is_some() {
4982 Self::push_unsupported_diagnostic(
4983 &mut diagnostics,
4984 &format!("PostgreSQL {name} with unsupported aggregate modifiers"),
4985 );
4986 }
4987 }
4988 Expression::Filter(filter) => {
4989 if let Some(name) = Self::postgres_json_aggregate_name(&filter.this) {
4990 Self::push_unsupported_diagnostic(
4991 &mut diagnostics,
4992 &format!("PostgreSQL {name} with FILTER"),
4993 );
4994 }
4995 }
4996 _ => {}
4997 }
4998
4999 if opts.unsupported_level == UnsupportedLevel::Immediate && !diagnostics.is_empty() {
5000 break;
5001 }
5002 }
5003
5004 if diagnostics.is_empty() {
5005 return Ok(());
5006 }
5007
5008 let limit = if opts.unsupported_level == UnsupportedLevel::Immediate {
5009 1
5010 } else {
5011 opts.max_unsupported.max(1)
5012 };
5013 let mut messages = diagnostics.iter().take(limit).cloned().collect::<Vec<_>>();
5014 if diagnostics.len() > limit {
5015 messages.push(format!("... and {} more", diagnostics.len() - limit));
5016 }
5017
5018 Err(crate::error::Error::unsupported(
5019 messages.join("; "),
5020 target.to_string(),
5021 ))
5022 }
5023
5024 fn postgres_json_aggregate_name(expr: &Expression) -> Option<String> {
5025 let name = match expr {
5026 Expression::Function(function) if !function.quoted => &function.name,
5027 Expression::AggregateFunction(function) => &function.name,
5028 _ => return None,
5029 };
5030 let name = name.to_ascii_uppercase();
5031 matches!(name.as_str(), "JSON_AGG" | "JSONB_AGG").then_some(name)
5032 }
5033
5034 fn push_unsupported_diagnostic(diagnostics: &mut Vec<String>, message: &str) {
5035 if !diagnostics.iter().any(|existing| existing == message) {
5036 diagnostics.push(message.to_string());
5037 }
5038 }
5039
5040 fn node_is_unresolved_postgres_date_subtraction(expr: &Expression) -> bool {
5041 let Expression::Sub(op) = expr else {
5042 return false;
5043 };
5044
5045 (Self::is_explicit_date_expr(&op.left) && Self::is_column_expr(&op.right))
5046 || (Self::is_column_expr(&op.left) && Self::is_explicit_date_expr(&op.right))
5047 }
5048
5049 fn is_column_expr(expr: &Expression) -> bool {
5050 match expr {
5051 Expression::Column(_) => true,
5052 Expression::Paren(paren) => Self::is_column_expr(&paren.this),
5053 _ => false,
5054 }
5055 }
5056
5057 fn node_window_frame(expr: &Expression) -> Option<&WindowFrame> {
5058 match expr {
5059 Expression::WindowFunction(window) => window.over.frame.as_ref(),
5060 Expression::Window(window) | Expression::WindowSpec(window) => window.frame.as_ref(),
5061 _ => None,
5062 }
5063 }
5064
5065 fn window_frame_bound_has_value_offset(bound: &WindowFrameBound) -> bool {
5066 matches!(
5067 bound,
5068 WindowFrameBound::Preceding(_)
5069 | WindowFrameBound::Following(_)
5070 | WindowFrameBound::Value(_)
5071 | WindowFrameBound::BarePreceding
5072 | WindowFrameBound::BareFollowing
5073 )
5074 }
5075
5076 fn collect_tsql_windows_missing_order(
5077 expr: &Expression,
5078 active_windows: &HashMap<String, Over>,
5079 diagnostics: &mut Vec<String>,
5080 ) {
5081 if let Expression::Select(select) = expr {
5082 let local_windows = select
5083 .windows
5084 .as_ref()
5085 .map(|windows| {
5086 windows
5087 .iter()
5088 .map(|window| (window.name.name.to_ascii_lowercase(), window.spec.clone()))
5089 .collect()
5090 })
5091 .unwrap_or_default();
5092
5093 for child in expr.children() {
5094 Self::collect_tsql_windows_missing_order(child, &local_windows, diagnostics);
5095 }
5096 return;
5097 }
5098
5099 if let Expression::WindowFunction(window) = expr {
5100 let (has_order, has_frame) = Self::effective_window_order_and_frame(
5101 &window.over,
5102 active_windows,
5103 &mut Vec::new(),
5104 );
5105
5106 if !has_order {
5107 if has_frame {
5108 Self::push_unsupported_diagnostic(
5109 diagnostics,
5110 "window frames without ORDER BY",
5111 );
5112 }
5113 if let Some(function_name) =
5114 Self::tsql_window_function_requiring_order(&window.this)
5115 {
5116 Self::push_unsupported_diagnostic(
5117 diagnostics,
5118 &format!("{function_name} without ORDER BY"),
5119 );
5120 }
5121 }
5122 }
5123
5124 for child in expr.children() {
5125 Self::collect_tsql_windows_missing_order(child, active_windows, diagnostics);
5126 }
5127 }
5128
5129 fn effective_window_order_and_frame(
5130 over: &Over,
5131 active_windows: &HashMap<String, Over>,
5132 seen: &mut Vec<String>,
5133 ) -> (bool, bool) {
5134 let inherited = over
5135 .window_name
5136 .as_ref()
5137 .and_then(|name| {
5138 let key = name.name.to_ascii_lowercase();
5139 if seen.iter().any(|seen_name| seen_name == &key) {
5140 return None;
5141 }
5142 let named = active_windows.get(&key)?;
5143 seen.push(key);
5144 let properties =
5145 Self::effective_window_order_and_frame(named, active_windows, seen);
5146 seen.pop();
5147 Some(properties)
5148 })
5149 .unwrap_or((false, false));
5150
5151 (
5152 !over.order_by.is_empty() || inherited.0,
5153 over.frame.is_some() || inherited.1,
5154 )
5155 }
5156
5157 fn tsql_window_function_requiring_order(expr: &Expression) -> Option<&'static str> {
5158 match expr {
5159 Expression::FirstValue(_) => Some("FIRST_VALUE"),
5160 Expression::LastValue(_) => Some("LAST_VALUE"),
5161 Expression::Function(function) if function.name.eq_ignore_ascii_case("FIRST_VALUE") => {
5162 Some("FIRST_VALUE")
5163 }
5164 Expression::Function(function) if function.name.eq_ignore_ascii_case("LAST_VALUE") => {
5165 Some("LAST_VALUE")
5166 }
5167 _ => None,
5168 }
5169 }
5170
5171 fn collect_tsql_unsupported_ordered_sets(expr: &Expression, diagnostics: &mut Vec<String>) {
5172 match expr {
5173 Expression::WindowFunction(window) => {
5174 if let Expression::WithinGroup(within_group) = &window.this {
5175 if Self::within_group_is_hypothetical_set(within_group) {
5176 Self::push_unsupported_diagnostic(
5177 diagnostics,
5178 "RANK/DENSE_RANK/CUME_DIST/PERCENT_RANK hypothetical-set aggregates",
5179 );
5180 return;
5181 }
5182
5183 if Self::within_group_is_mode(within_group) {
5184 Self::push_unsupported_diagnostic(
5185 diagnostics,
5186 "MODE ordered-set aggregates",
5187 );
5188 return;
5189 }
5190
5191 if Self::within_group_is_percentile(within_group) {
5192 if !window.over.order_by.is_empty() || window.over.frame.is_some() {
5193 Self::push_unsupported_diagnostic(
5194 diagnostics,
5195 "PERCENTILE_CONT/PERCENTILE_DISC window ORDER BY or frame clauses",
5196 );
5197 }
5198 return;
5199 }
5200 }
5201 }
5202 Expression::WithinGroup(within_group) => {
5203 if Self::within_group_is_hypothetical_set(within_group) {
5204 Self::push_unsupported_diagnostic(
5205 diagnostics,
5206 "RANK/DENSE_RANK/CUME_DIST/PERCENT_RANK hypothetical-set aggregates",
5207 );
5208 return;
5209 }
5210
5211 if Self::within_group_is_mode(within_group) {
5212 Self::push_unsupported_diagnostic(diagnostics, "MODE ordered-set aggregates");
5213 return;
5214 }
5215
5216 if Self::within_group_is_percentile(within_group) {
5217 Self::push_unsupported_diagnostic(
5218 diagnostics,
5219 "PERCENTILE_CONT/PERCENTILE_DISC ordered-set aggregates without OVER",
5220 );
5221 return;
5222 }
5223 }
5224 _ => {}
5225 }
5226
5227 for child in expr.children() {
5228 Self::collect_tsql_unsupported_ordered_sets(child, diagnostics);
5229 }
5230 }
5231
5232 fn within_group_is_hypothetical_set(within_group: &crate::expressions::WithinGroup) -> bool {
5233 match &within_group.this {
5234 Expression::Function(function) => Self::is_hypothetical_set_name(&function.name),
5235 Expression::AggregateFunction(function) => {
5236 Self::is_hypothetical_set_name(&function.name)
5237 }
5238 Expression::Rank(_)
5239 | Expression::DenseRank(_)
5240 | Expression::CumeDist(_)
5241 | Expression::PercentRank(_) => true,
5242 _ => false,
5243 }
5244 }
5245
5246 fn within_group_is_percentile(within_group: &crate::expressions::WithinGroup) -> bool {
5247 match &within_group.this {
5248 Expression::Function(function) => Self::is_percentile_ordered_set_name(&function.name),
5249 Expression::AggregateFunction(function) => {
5250 Self::is_percentile_ordered_set_name(&function.name)
5251 }
5252 Expression::PercentileCont(_) | Expression::PercentileDisc(_) => true,
5253 _ => false,
5254 }
5255 }
5256
5257 fn within_group_is_mode(within_group: &crate::expressions::WithinGroup) -> bool {
5258 match &within_group.this {
5259 Expression::Function(function) => function.name.eq_ignore_ascii_case("MODE"),
5260 Expression::AggregateFunction(function) => function.name.eq_ignore_ascii_case("MODE"),
5261 Expression::Mode(_) => true,
5262 _ => false,
5263 }
5264 }
5265
5266 fn is_percentile_ordered_set_name(name: &str) -> bool {
5267 name.eq_ignore_ascii_case("PERCENTILE_CONT") || name.eq_ignore_ascii_case("PERCENTILE_DISC")
5268 }
5269
5270 fn is_hypothetical_set_name(name: &str) -> bool {
5271 name.eq_ignore_ascii_case("RANK")
5272 || name.eq_ignore_ascii_case("DENSE_RANK")
5273 || name.eq_ignore_ascii_case("CUME_DIST")
5274 || name.eq_ignore_ascii_case("PERCENT_RANK")
5275 }
5276
5277 fn target_supports_distinct_on(target: DialectType) -> bool {
5278 matches!(target, DialectType::PostgreSQL | DialectType::DuckDB)
5279 }
5280
5281 fn node_has_distinct_on(expr: &Expression) -> bool {
5282 matches!(
5283 expr,
5284 Expression::Select(select)
5285 if select
5286 .distinct_on
5287 .as_ref()
5288 .is_some_and(|distinct_on| !distinct_on.is_empty())
5289 )
5290 }
5291
5292 fn node_has_recursive_with(expr: &Expression) -> bool {
5293 fn recursive(with: &Option<With>) -> bool {
5294 with.as_ref().is_some_and(|with| with.recursive)
5295 }
5296
5297 match expr {
5298 Expression::With(with) => with.recursive,
5299 Expression::Select(select) => recursive(&select.with),
5300 Expression::Union(union) => recursive(&union.with),
5301 Expression::Intersect(intersect) => recursive(&intersect.with),
5302 Expression::Except(except) => recursive(&except.with),
5303 Expression::Pivot(pivot) => recursive(&pivot.with),
5304 Expression::Insert(insert) => recursive(&insert.with),
5305 Expression::Update(update) => recursive(&update.with),
5306 Expression::Delete(delete) => recursive(&delete.with),
5307 _ => false,
5308 }
5309 }
5310
5311 fn node_has_lateral(expr: &Expression) -> bool {
5312 fn join_has_lateral(join: &Join) -> bool {
5313 matches!(
5314 join.kind,
5315 crate::expressions::JoinKind::Lateral | crate::expressions::JoinKind::LeftLateral
5316 ) || Dialect::node_has_lateral(&join.this)
5317 || join.on.as_ref().is_some_and(Dialect::node_has_lateral)
5318 || join
5319 .match_condition
5320 .as_ref()
5321 .is_some_and(Dialect::node_has_lateral)
5322 || join.pivots.iter().any(Dialect::node_has_lateral)
5323 }
5324
5325 fn joins_have_lateral(joins: &[Join]) -> bool {
5326 joins.iter().any(join_has_lateral)
5327 }
5328
5329 match expr {
5330 Expression::Subquery(subquery) => {
5331 subquery.lateral || Dialect::node_has_lateral(&subquery.this)
5332 }
5333 Expression::Lateral(_) | Expression::LateralView(_) => true,
5334 Expression::Join(join) => join_has_lateral(join),
5335 Expression::Select(select) => {
5336 !select.lateral_views.is_empty()
5337 || joins_have_lateral(&select.joins)
5338 || select
5339 .from
5340 .as_ref()
5341 .is_some_and(|from| from.expressions.iter().any(Dialect::node_has_lateral))
5342 }
5343 Expression::JoinedTable(joined) => {
5344 !joined.lateral_views.is_empty()
5345 || Dialect::node_has_lateral(&joined.left)
5346 || joins_have_lateral(&joined.joins)
5347 }
5348 Expression::Update(update) => {
5349 joins_have_lateral(&update.table_joins) || joins_have_lateral(&update.from_joins)
5350 }
5351 _ => false,
5352 }
5353 }
5354
5355 fn node_has_join_using(expr: &Expression) -> bool {
5356 fn has_using(joins: &[Join]) -> bool {
5357 joins.iter().any(|join| !join.using.is_empty())
5358 }
5359
5360 match expr {
5361 Expression::Join(join) => !join.using.is_empty(),
5362 Expression::Select(select) => has_using(&select.joins),
5363 Expression::JoinedTable(joined) => has_using(&joined.joins),
5364 Expression::Update(update) => {
5365 has_using(&update.table_joins) || has_using(&update.from_joins)
5366 }
5367 Expression::Delete(delete) => has_using(&delete.joins),
5368 _ => false,
5369 }
5370 }
5371
5372 fn node_has_natural_join(expr: &Expression) -> bool {
5373 fn is_natural(join: &Join) -> bool {
5374 matches!(
5375 join.kind,
5376 crate::expressions::JoinKind::Natural
5377 | crate::expressions::JoinKind::NaturalLeft
5378 | crate::expressions::JoinKind::NaturalRight
5379 | crate::expressions::JoinKind::NaturalFull
5380 )
5381 }
5382
5383 fn has_natural(joins: &[Join]) -> bool {
5384 joins.iter().any(is_natural)
5385 }
5386
5387 match expr {
5388 Expression::Join(join) => is_natural(join),
5389 Expression::Select(select) => has_natural(&select.joins),
5390 Expression::JoinedTable(joined) => has_natural(&joined.joins),
5391 Expression::Update(update) => {
5392 has_natural(&update.table_joins) || has_natural(&update.from_joins)
5393 }
5394 Expression::Delete(delete) => has_natural(&delete.joins),
5395 _ => false,
5396 }
5397 }
5398
5399 fn node_has_unsupported_relation_column_aliases(expr: &Expression) -> bool {
5400 match expr {
5401 Expression::Table(table) => !table.column_aliases.is_empty(),
5402 Expression::Alias(alias) => {
5403 !alias.column_aliases.is_empty()
5404 && matches!(
5405 alias.this,
5406 Expression::Table(_) | Expression::JoinedTable(_)
5407 )
5408 }
5409 _ => false,
5410 }
5411 }
5412
5413 fn node_is_aggregate_function(expr: &Expression) -> bool {
5414 is_aggregate(expr)
5415 }
5416
5417 fn node_has_qualified_whole_row_aggregate_argument(expr: &Expression) -> bool {
5418 fn contains_qualified_star(expr: &Expression) -> bool {
5419 match expr {
5420 Expression::Star(star) => star.table.is_some(),
5421 Expression::Select(_)
5424 | Expression::Subquery(_)
5425 | Expression::Union(_)
5426 | Expression::Intersect(_)
5427 | Expression::Except(_) => false,
5428 _ => expr.children().into_iter().any(contains_qualified_star),
5429 }
5430 }
5431
5432 Self::node_is_aggregate_function(expr)
5433 && expr.children().into_iter().any(contains_qualified_star)
5434 }
5435
5436 fn node_has_subquery_in_aggregate_argument(expr: &Expression) -> bool {
5437 fn contains_query(expr: &Expression) -> bool {
5438 matches!(
5439 expr,
5440 Expression::Select(_)
5441 | Expression::Subquery(_)
5442 | Expression::Union(_)
5443 | Expression::Intersect(_)
5444 | Expression::Except(_)
5445 ) || expr.children().into_iter().any(contains_query)
5446 }
5447
5448 Self::node_is_aggregate_function(expr) && expr.children().into_iter().any(contains_query)
5449 }
5450
5451 fn tsql_apply_has_invalid_outer_aggregate(expr: &Expression) -> bool {
5452 fn collect_source_names(expr: &Expression, names: &mut HashSet<String>) {
5455 let mut insert = |name: &Identifier| {
5456 if !name.name.is_empty() {
5457 names.insert(name.name.to_ascii_lowercase());
5458 }
5459 };
5460
5461 match expr {
5462 Expression::Table(table) => {
5463 insert(table.alias.as_ref().unwrap_or(&table.name));
5464 }
5465 Expression::Subquery(subquery) => {
5466 if let Some(alias) = &subquery.alias {
5467 insert(alias);
5468 }
5469 }
5470 Expression::Alias(alias) => insert(&alias.alias),
5471 Expression::JoinedTable(joined) => {
5472 if let Some(alias) = &joined.alias {
5473 insert(alias);
5474 } else {
5475 collect_source_names(&joined.left, names);
5476 for join in &joined.joins {
5477 collect_source_names(&join.this, names);
5478 }
5479 }
5480 }
5481 Expression::Paren(paren) => collect_source_names(&paren.this, names),
5482 Expression::Pivot(pivot) => {
5483 if let Some(alias) = &pivot.alias {
5484 insert(alias);
5485 } else {
5486 collect_source_names(&pivot.this, names);
5487 }
5488 }
5489 Expression::Unpivot(unpivot) => {
5490 if let Some(alias) = &unpivot.alias {
5491 insert(alias);
5492 } else {
5493 collect_source_names(&unpivot.this, names);
5494 }
5495 }
5496 _ => {}
5497 }
5498 }
5499
5500 fn collect_columns<'a>(
5501 expr: &'a Expression,
5502 columns: &mut Vec<&'a crate::expressions::Column>,
5503 ) {
5504 match expr {
5505 Expression::Column(column) => columns.push(column),
5506 Expression::Select(_)
5509 | Expression::Subquery(_)
5510 | Expression::Union(_)
5511 | Expression::Intersect(_)
5512 | Expression::Except(_) => {}
5513 _ => {
5514 for child in expr.children() {
5515 collect_columns(child, columns);
5516 }
5517 }
5518 }
5519 }
5520
5521 fn same_column(
5522 left: &crate::expressions::Column,
5523 right: &crate::expressions::Column,
5524 ) -> bool {
5525 let same_identifier =
5526 |left: &Identifier, right: &Identifier| left.name.eq_ignore_ascii_case(&right.name);
5527
5528 same_identifier(&left.name, &right.name)
5529 && match (&left.table, &right.table) {
5530 (Some(left), Some(right)) => same_identifier(left, right),
5531 (None, None) => true,
5532 _ => false,
5533 }
5534 }
5535
5536 fn aggregate_is_invalid(expr: &Expression, local_sources: &HashSet<String>) -> bool {
5537 let mut columns = Vec::new();
5538 collect_columns(expr, &mut columns);
5539
5540 let outer_column = columns.iter().copied().find(|column| match &column.table {
5541 Some(table) => !local_sources.contains(&table.name.to_ascii_lowercase()),
5542 None => local_sources.is_empty(),
5545 });
5546
5547 outer_column
5548 .is_some_and(|outer| columns.iter().any(|column| !same_column(outer, column)))
5549 }
5550
5551 fn expression_has_invalid_aggregate(
5552 expr: &Expression,
5553 local_sources: &HashSet<String>,
5554 ) -> bool {
5555 if Dialect::node_is_aggregate_function(expr)
5556 && aggregate_is_invalid(expr, local_sources)
5557 {
5558 return true;
5559 }
5560
5561 match expr {
5562 Expression::Select(_)
5563 | Expression::Subquery(_)
5564 | Expression::Union(_)
5565 | Expression::Intersect(_)
5566 | Expression::Except(_) => false,
5567 _ => expr
5568 .children()
5569 .into_iter()
5570 .any(|child| expression_has_invalid_aggregate(child, local_sources)),
5571 }
5572 }
5573
5574 fn select_has_invalid_aggregate(select: &Select) -> bool {
5575 let mut local_sources = HashSet::new();
5576 if let Some(from) = &select.from {
5577 for source in &from.expressions {
5578 collect_source_names(source, &mut local_sources);
5579 }
5580 }
5581 for join in &select.joins {
5582 collect_source_names(&join.this, &mut local_sources);
5583 }
5584
5585 let invalid =
5586 |expr: &Expression| expression_has_invalid_aggregate(expr, &local_sources);
5587
5588 select.expressions.iter().any(invalid)
5589 || select.prewhere.as_ref().is_some_and(invalid)
5590 || select
5591 .where_clause
5592 .as_ref()
5593 .is_some_and(|where_clause| invalid(&where_clause.this))
5594 || select
5595 .group_by
5596 .as_ref()
5597 .is_some_and(|group_by| group_by.expressions.iter().any(invalid))
5598 || select
5599 .having
5600 .as_ref()
5601 .is_some_and(|having| invalid(&having.this))
5602 || select
5603 .qualify
5604 .as_ref()
5605 .is_some_and(|qualify| invalid(&qualify.this))
5606 || select.order_by.as_ref().is_some_and(|order_by| {
5607 order_by
5608 .expressions
5609 .iter()
5610 .any(|ordered| invalid(&ordered.this))
5611 })
5612 }
5613
5614 fn apply_rhs_is_invalid(rhs: &Expression) -> bool {
5615 rhs.dfs().any(|node| match node {
5616 Expression::Select(select) => select_has_invalid_aggregate(select),
5617 _ => false,
5618 })
5619 }
5620
5621 fn joins_have_invalid_aggregate(joins: &[Join]) -> bool {
5622 joins.iter().any(|join| {
5623 matches!(
5624 join.kind,
5625 crate::expressions::JoinKind::CrossApply
5626 | crate::expressions::JoinKind::OuterApply
5627 ) && apply_rhs_is_invalid(&join.this)
5628 })
5629 }
5630
5631 expr.dfs().any(|node| match node {
5632 Expression::Select(select) => joins_have_invalid_aggregate(&select.joins),
5633 Expression::JoinedTable(joined) => joins_have_invalid_aggregate(&joined.joins),
5634 Expression::Update(update) => {
5635 joins_have_invalid_aggregate(&update.table_joins)
5636 || joins_have_invalid_aggregate(&update.from_joins)
5637 }
5638 Expression::Delete(delete) => joins_have_invalid_aggregate(&delete.joins),
5639 _ => false,
5640 })
5641 }
5642
5643 fn target_supports_remaining_unnest(target: DialectType) -> bool {
5644 matches!(
5645 target,
5646 DialectType::PostgreSQL
5647 | DialectType::BigQuery
5648 | DialectType::DuckDB
5649 | DialectType::Presto
5650 | DialectType::Trino
5651 | DialectType::Athena
5652 )
5653 }
5654
5655 fn target_supports_remaining_explode(target: DialectType) -> bool {
5656 matches!(
5657 target,
5658 DialectType::Spark | DialectType::Databricks | DialectType::Hive
5659 )
5660 }
5661
5662 fn target_lacks_array_agg(target: DialectType) -> bool {
5663 matches!(
5664 target,
5665 DialectType::Fabric
5666 | DialectType::TSQL
5667 | DialectType::MySQL
5668 | DialectType::SQLite
5669 | DialectType::Oracle
5670 )
5671 }
5672
5673 fn node_is_unnest(expr: &Expression) -> bool {
5674 matches!(expr, Expression::Unnest(_)) || Self::node_is_function_named(expr, "UNNEST")
5675 }
5676
5677 fn node_is_explode(expr: &Expression) -> bool {
5678 matches!(expr, Expression::Explode(_) | Expression::ExplodeOuter(_))
5679 || Self::node_is_function_named(expr, "EXPLODE")
5680 || Self::node_is_function_named(expr, "EXPLODE_OUTER")
5681 }
5682
5683 fn node_is_array_agg(expr: &Expression) -> bool {
5684 matches!(expr, Expression::ArrayAgg(_)) || Self::node_is_function_named(expr, "ARRAY_AGG")
5685 }
5686
5687 fn node_is_distinct_string_agg(expr: &Expression) -> bool {
5688 match expr {
5689 Expression::StringAgg(agg) => agg.distinct,
5690 Expression::Function(function) => {
5691 function.distinct && function.name.eq_ignore_ascii_case("STRING_AGG")
5692 }
5693 Expression::AggregateFunction(function) => {
5694 function.distinct && function.name.eq_ignore_ascii_case("STRING_AGG")
5695 }
5696 _ => false,
5697 }
5698 }
5699
5700 fn postgres_tsql_unsupported_collation_name(expr: &Expression) -> Option<&'static str> {
5701 let Expression::Collation(collation) = expr else {
5702 return None;
5703 };
5704
5705 if collation.collation.eq_ignore_ascii_case("C") {
5706 Some("C")
5707 } else if collation.collation.eq_ignore_ascii_case("POSIX") {
5708 Some("POSIX")
5709 } else {
5710 None
5711 }
5712 }
5713
5714 fn collect_tsql_grouping_tuple_nodes(expr: &Expression) -> HashSet<*const Expression> {
5715 let mut tuples = HashSet::new();
5716
5717 for node in expr.dfs() {
5718 let Expression::Select(select) = node else {
5719 continue;
5720 };
5721 let Some(group_by) = &select.group_by else {
5722 continue;
5723 };
5724
5725 for expression in &group_by.expressions {
5726 Self::collect_tsql_grouping_element_tuples(expression, &mut tuples);
5727 }
5728 }
5729
5730 tuples
5731 }
5732
5733 fn collect_tsql_grouping_element_tuples(
5734 expr: &Expression,
5735 tuples: &mut HashSet<*const Expression>,
5736 ) {
5737 match expr {
5738 Expression::GroupingSets(grouping_sets) => {
5739 for expression in &grouping_sets.expressions {
5740 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5741 }
5742 }
5743 Expression::Rollup(rollup) => {
5744 for expression in &rollup.expressions {
5745 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5746 }
5747 }
5748 Expression::Cube(cube) => {
5749 for expression in &cube.expressions {
5750 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5751 }
5752 }
5753 Expression::Function(function)
5754 if !function.quoted
5755 && (function.name.eq_ignore_ascii_case("GROUPING SETS")
5756 || function.name.eq_ignore_ascii_case("ROLLUP")
5757 || function.name.eq_ignore_ascii_case("CUBE")) =>
5758 {
5759 for expression in &function.args {
5760 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5761 }
5762 }
5763 _ => {}
5764 }
5765 }
5766
5767 fn collect_tsql_grouping_unit_tuples(
5768 expr: &Expression,
5769 tuples: &mut HashSet<*const Expression>,
5770 ) {
5771 match expr {
5772 Expression::Tuple(tuple) => {
5773 tuples.insert(expr as *const Expression);
5774 for expression in &tuple.expressions {
5775 match expression {
5776 Expression::Tuple(_) | Expression::Paren(_) => {
5777 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5778 }
5779 Expression::GroupingSets(_)
5780 | Expression::Rollup(_)
5781 | Expression::Cube(_) => {
5782 Self::collect_tsql_grouping_element_tuples(expression, tuples);
5783 }
5784 Expression::Function(function)
5785 if !function.quoted
5786 && (function.name.eq_ignore_ascii_case("GROUPING SETS")
5787 || function.name.eq_ignore_ascii_case("ROLLUP")
5788 || function.name.eq_ignore_ascii_case("CUBE")) =>
5789 {
5790 Self::collect_tsql_grouping_element_tuples(expression, tuples);
5791 }
5792 _ => {}
5793 }
5794 }
5795 }
5796 Expression::Paren(paren) => {
5797 Self::collect_tsql_grouping_unit_tuples(&paren.this, tuples);
5798 }
5799 Expression::GroupingSets(_) | Expression::Rollup(_) | Expression::Cube(_) => {
5800 Self::collect_tsql_grouping_element_tuples(expr, tuples);
5801 }
5802 Expression::Function(function)
5803 if !function.quoted
5804 && (function.name.eq_ignore_ascii_case("GROUPING SETS")
5805 || function.name.eq_ignore_ascii_case("ROLLUP")
5806 || function.name.eq_ignore_ascii_case("CUBE")) =>
5807 {
5808 Self::collect_tsql_grouping_element_tuples(expr, tuples);
5809 }
5810 _ => {}
5811 }
5812 }
5813
5814 fn postgres_tsql_unsupported_composite_semantics(
5815 expr: &Expression,
5816 structural_grouping_tuple: bool,
5817 ) -> Option<&'static str> {
5818 match expr {
5819 Expression::Tuple(_) if !structural_grouping_tuple => Some("row/composite values"),
5820 Expression::Struct(_) | Expression::StructFunc(_) => Some("row/composite values"),
5821 Expression::Function(function)
5822 if !function.quoted && function.name.eq_ignore_ascii_case("ROW") =>
5823 {
5824 Some("row/composite values")
5825 }
5826 Expression::StructExtract(_) => Some("row/composite field access"),
5827 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) if matches!(&cast.this, Expression::Star(star) if star.table.is_some()) => {
5828 Some("qualified whole-row casts")
5829 }
5830 _ => None,
5831 }
5832 }
5833
5834 fn node_is_postgres_unknown_cast(expr: &Expression) -> bool {
5835 match expr {
5836 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
5837 normalization::is_postgres_unknown_type(&cast.to)
5838 }
5839 _ => false,
5840 }
5841 }
5842
5843 fn postgres_tsql_unsupported_array_semantics(expr: &Expression) -> Option<&'static str> {
5844 match expr {
5845 Expression::Array(_) | Expression::ArrayFunc(_) => Some("array literals"),
5846 Expression::Subscript(_) => Some("array subscripts"),
5847 Expression::ArraySlice(_) => Some("array slices"),
5848 Expression::DataType(DataType::Array { .. }) => Some("array data types"),
5849 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
5850 if matches!(&cast.to, DataType::Array { .. }) =>
5851 {
5852 Some("array data types")
5853 }
5854 Expression::ArrayLength(_) | Expression::ArraySize(_) => Some("ARRAY_LENGTH"),
5855 Expression::Cardinality(_) => Some("CARDINALITY"),
5856 Expression::ArrayToString(_) | Expression::ArrayJoin(_) => Some("ARRAY_TO_STRING"),
5857 Expression::StringToArray(_) => Some("STRING_TO_ARRAY"),
5858 Expression::ArrayContains(_)
5859 | Expression::ArrayPosition(_)
5860 | Expression::ArrayAppend(_)
5861 | Expression::ArrayPrepend(_)
5862 | Expression::ArrayConcat(_)
5863 | Expression::ArraySort(_)
5864 | Expression::ArrayReverse(_)
5865 | Expression::ArrayDistinct(_)
5866 | Expression::ArrayFilter(_)
5867 | Expression::ArrayTransform(_)
5868 | Expression::ArrayFlatten(_)
5869 | Expression::ArrayCompact(_)
5870 | Expression::ArrayIntersect(_)
5871 | Expression::ArrayUnion(_)
5872 | Expression::ArrayExcept(_)
5873 | Expression::ArrayRemove(_)
5874 | Expression::ArrayZip(_)
5875 | Expression::ArrayAll(_)
5876 | Expression::ArrayAny(_)
5877 | Expression::ArrayConstructCompact(_)
5878 | Expression::ArraySum(_) => Some("array functions"),
5879 Expression::ArrayContainsAll(_)
5880 | Expression::ArrayContainedBy(_)
5881 | Expression::ArrayOverlaps(_) => Some("array operators"),
5882 Expression::Function(function) => {
5883 Self::postgres_tsql_unsupported_array_function_name_str(&function.name)
5884 }
5885 Expression::AggregateFunction(function) => {
5886 Self::postgres_tsql_unsupported_array_function_name_str(&function.name)
5887 }
5888 _ => None,
5889 }
5890 }
5891
5892 fn postgres_tsql_unsupported_array_function_name_str(name: &str) -> Option<&'static str> {
5893 if name.eq_ignore_ascii_case("ARRAY") {
5894 Some("array literals")
5895 } else if name.eq_ignore_ascii_case("ARRAY_LENGTH")
5896 || name.eq_ignore_ascii_case("ARRAY_SIZE")
5897 {
5898 Some("ARRAY_LENGTH")
5899 } else if name.eq_ignore_ascii_case("CARDINALITY") {
5900 Some("CARDINALITY")
5901 } else if name.eq_ignore_ascii_case("ARRAY_TO_STRING")
5902 || name.eq_ignore_ascii_case("ARRAY_JOIN")
5903 {
5904 Some("ARRAY_TO_STRING")
5905 } else if name.eq_ignore_ascii_case("STRING_TO_ARRAY") {
5906 Some("STRING_TO_ARRAY")
5907 } else {
5908 None
5909 }
5910 }
5911
5912 fn node_is_regex_predicate(expr: &Expression) -> bool {
5913 matches!(
5914 expr,
5915 Expression::SimilarTo(_) | Expression::RegexpLike(_) | Expression::RegexpILike(_)
5916 ) || Self::node_is_function_named(expr, "REGEXP_LIKE")
5917 || Self::node_is_function_named(expr, "REGEXP_I_LIKE")
5918 || Self::node_is_function_named(expr, "REGEXP_ILIKE")
5919 }
5920
5921 fn node_is_non_subquery_any(expr: &Expression) -> bool {
5922 matches!(
5923 expr,
5924 Expression::Any(q) if !Self::quantified_rhs_is_subquery(&q.subquery)
5925 )
5926 }
5927
5928 fn quantified_rhs_is_subquery(expr: &Expression) -> bool {
5929 match expr {
5930 Expression::Select(_) | Expression::Subquery(_) => true,
5931 Expression::Paren(paren) => Self::quantified_rhs_is_subquery(&paren.this),
5932 _ => false,
5933 }
5934 }
5935
5936 fn node_is_row_value_subquery_comparison(expr: &Expression) -> bool {
5937 match expr {
5938 Expression::In(in_expr) => {
5939 Self::in_rhs_is_subquery_like(in_expr) && Self::expr_is_row_value(&in_expr.this)
5940 }
5941 Expression::Eq(op) | Expression::Neq(op) => {
5942 (Self::expr_is_row_value(&op.left) && Self::expr_is_subquery_like(&op.right))
5943 || (Self::expr_is_row_value(&op.right) && Self::expr_is_subquery_like(&op.left))
5944 }
5945 _ => false,
5946 }
5947 }
5948
5949 fn node_is_row_value_values_membership(expr: &Expression) -> bool {
5950 matches!(
5951 expr,
5952 Expression::In(in_expr)
5953 if Self::expr_is_row_value(&in_expr.this)
5954 && Self::in_rhs_is_values_like(in_expr)
5955 )
5956 }
5957
5958 fn expr_is_row_value(expr: &Expression) -> bool {
5959 match expr {
5960 Expression::Tuple(tuple) => tuple.expressions.len() > 1,
5961 Expression::Function(function) if function.name.eq_ignore_ascii_case("ROW") => {
5962 function.args.len() > 1
5963 }
5964 Expression::Paren(paren) => Self::expr_is_row_value(&paren.this),
5965 _ => false,
5966 }
5967 }
5968
5969 fn expr_is_subquery_like(expr: &Expression) -> bool {
5970 match expr {
5971 Expression::Select(_) | Expression::Subquery(_) => true,
5972 Expression::Paren(paren) => Self::expr_is_subquery_like(&paren.this),
5973 _ => false,
5974 }
5975 }
5976
5977 fn in_rhs_is_subquery_like(in_expr: &crate::expressions::In) -> bool {
5978 if in_expr
5979 .query
5980 .as_ref()
5981 .is_some_and(Self::expr_is_subquery_like)
5982 {
5983 return true;
5984 }
5985
5986 in_expr.expressions.len() == 1 && Self::expr_is_subquery_like(&in_expr.expressions[0])
5987 }
5988
5989 fn in_rhs_is_values_like(in_expr: &crate::expressions::In) -> bool {
5990 if in_expr
5991 .query
5992 .as_ref()
5993 .is_some_and(Self::expr_is_values_like)
5994 {
5995 return true;
5996 }
5997
5998 (in_expr.expressions.len() == 1
5999 && Self::expr_is_values_like(&in_expr.expressions[0]))
6000 || in_expr.expressions.first().is_some_and(|expr| {
6001 matches!(expr, Expression::Function(function) if function.name.eq_ignore_ascii_case("VALUES"))
6002 })
6003 }
6004
6005 fn expr_is_values_like(expr: &Expression) -> bool {
6006 match expr {
6007 Expression::Values(_) => true,
6008 Expression::Paren(paren) => Self::expr_is_values_like(&paren.this),
6009 Expression::Subquery(subquery) => Self::expr_is_values_like(&subquery.this),
6010 _ => false,
6011 }
6012 }
6013
6014 fn normalize_tsql_fetch_overlaps_date_bin(expr: Expression) -> Result<Expression> {
6015 transform_recursive(expr, &|e| match e {
6016 Expression::Select(mut select) => {
6017 if select.top.is_none() && select.offset.is_none() {
6018 if let Some(fetch) = select.fetch.take() {
6019 if let Some(top) = Self::fetch_with_ties_to_top(fetch.clone()) {
6020 select.top = Some(top);
6021 } else {
6022 select.fetch = Some(fetch);
6023 }
6024 }
6025 }
6026 Self::rewrite_tsql_overlaps_in_select_predicates(&mut select)?;
6027 Ok(Expression::Select(select))
6028 }
6029 Expression::DateBin(date_bin) => {
6030 let date_bin = *date_bin;
6031 if let Some(rewritten) = Self::date_bin_to_date_bucket(date_bin.clone()) {
6032 Ok(rewritten)
6033 } else {
6034 Ok(Expression::DateBin(Box::new(date_bin)))
6035 }
6036 }
6037 Expression::Function(function) => {
6038 let function = *function;
6039 if function.name.eq_ignore_ascii_case("DATE_BIN") {
6040 if let Some(rewritten) = Self::date_bin_function_to_date_bucket(&function) {
6041 Ok(rewritten)
6042 } else {
6043 Ok(Expression::Function(Box::new(function)))
6044 }
6045 } else {
6046 Ok(Expression::Function(Box::new(function)))
6047 }
6048 }
6049 _ => Ok(e),
6050 })
6051 }
6052
6053 fn rewrite_tsql_overlaps_in_select_predicates(
6054 select: &mut crate::expressions::Select,
6055 ) -> Result<()> {
6056 if let Some(where_clause) = &mut select.where_clause {
6057 where_clause.this = Self::rewrite_tsql_overlaps_predicate(where_clause.this.clone())?;
6058 }
6059 if let Some(having) = &mut select.having {
6060 having.this = Self::rewrite_tsql_overlaps_predicate(having.this.clone())?;
6061 }
6062 if let Some(qualify) = &mut select.qualify {
6063 qualify.this = Self::rewrite_tsql_overlaps_predicate(qualify.this.clone())?;
6064 }
6065 for join in &mut select.joins {
6066 if let Some(on) = join.on.take() {
6067 join.on = Some(Self::rewrite_tsql_overlaps_predicate(on)?);
6068 }
6069 if let Some(match_condition) = join.match_condition.take() {
6070 join.match_condition =
6071 Some(Self::rewrite_tsql_overlaps_predicate(match_condition)?);
6072 }
6073 }
6074 Ok(())
6075 }
6076
6077 fn rewrite_tsql_overlaps_predicate(expr: Expression) -> Result<Expression> {
6078 transform_recursive(expr, &|e| match e {
6079 Expression::Overlaps(overlaps) => {
6080 let overlaps = *overlaps;
6081 if let Some(rewritten) = Self::rewrite_full_overlaps_for_tsql(&overlaps) {
6082 Ok(rewritten)
6083 } else {
6084 Ok(Expression::Overlaps(Box::new(overlaps)))
6085 }
6086 }
6087 _ => Ok(e),
6088 })
6089 }
6090
6091 fn fetch_with_ties_to_top(fetch: Fetch) -> Option<Top> {
6092 if !fetch.with_ties {
6093 return None;
6094 }
6095
6096 fetch.count.map(|count| Top {
6097 this: count,
6098 percent: fetch.percent,
6099 with_ties: true,
6100 parenthesized: true,
6101 })
6102 }
6103
6104 fn rewrite_full_overlaps_for_tsql(
6105 overlaps: &crate::expressions::OverlapsExpr,
6106 ) -> Option<Expression> {
6107 let (left_start, left_end, right_start, right_end) =
6108 if let (Some(left_start), Some(left_end), Some(right_start), Some(right_end)) = (
6109 overlaps.left_start.as_ref(),
6110 overlaps.left_end.as_ref(),
6111 overlaps.right_start.as_ref(),
6112 overlaps.right_end.as_ref(),
6113 ) {
6114 (left_start, left_end, right_start, right_end)
6115 } else if let (
6116 Some(Expression::Tuple(left_tuple)),
6117 Some(Expression::Tuple(right_tuple)),
6118 ) = (&overlaps.this, &overlaps.expression)
6119 {
6120 if left_tuple.expressions.len() != 2 || right_tuple.expressions.len() != 2 {
6121 return None;
6122 }
6123 (
6124 &left_tuple.expressions[0],
6125 &left_tuple.expressions[1],
6126 &right_tuple.expressions[0],
6127 &right_tuple.expressions[1],
6128 )
6129 } else {
6130 return None;
6131 };
6132
6133 let left_min = Self::case_min(left_start.clone(), left_end.clone());
6134 let left_max = Self::case_max(left_start.clone(), left_end.clone());
6135 let right_min = Self::case_min(right_start.clone(), right_end.clone());
6136 let right_max = Self::case_max(right_start.clone(), right_end.clone());
6137
6138 Some(Expression::And(Box::new(BinaryOp::new(
6139 Expression::Lte(Box::new(BinaryOp::new(left_min, right_max))),
6140 Expression::Lte(Box::new(BinaryOp::new(right_min, left_max))),
6141 ))))
6142 }
6143
6144 fn case_min(left: Expression, right: Expression) -> Expression {
6145 Expression::Case(Box::new(Case {
6146 operand: None,
6147 whens: vec![(
6148 Expression::Lte(Box::new(BinaryOp::new(left.clone(), right.clone()))),
6149 left,
6150 )],
6151 else_: Some(right),
6152 comments: Vec::new(),
6153 inferred_type: None,
6154 }))
6155 }
6156
6157 fn case_max(left: Expression, right: Expression) -> Expression {
6158 Expression::Case(Box::new(Case {
6159 operand: None,
6160 whens: vec![(
6161 Expression::Gte(Box::new(BinaryOp::new(left.clone(), right.clone()))),
6162 left,
6163 )],
6164 else_: Some(right),
6165 comments: Vec::new(),
6166 inferred_type: None,
6167 }))
6168 }
6169
6170 fn date_bin_to_date_bucket(date_bin: DateBin) -> Option<Expression> {
6171 if date_bin.unit.is_some() || date_bin.zone.is_some() {
6172 return None;
6173 }
6174
6175 let (datepart, number) = Self::date_bucket_parts(&date_bin.this)?;
6176 let mut args = vec![
6177 Self::date_bucket_datepart(datepart),
6178 number,
6179 *date_bin.expression,
6180 ];
6181 if let Some(origin) = date_bin.origin {
6182 args.push(*origin);
6183 }
6184
6185 Some(Expression::Function(Box::new(Function::new(
6186 "DATE_BUCKET".to_string(),
6187 args,
6188 ))))
6189 }
6190
6191 fn date_bin_function_to_date_bucket(function: &Function) -> Option<Expression> {
6192 if !(2..=3).contains(&function.args.len()) {
6193 return None;
6194 }
6195
6196 let (datepart, number) = Self::date_bucket_parts(&function.args[0])?;
6197 let mut args = vec![
6198 Self::date_bucket_datepart(datepart),
6199 number,
6200 function.args[1].clone(),
6201 ];
6202 if let Some(origin) = function.args.get(2) {
6203 args.push(origin.clone());
6204 }
6205
6206 Some(Expression::Function(Box::new(Function::new(
6207 "DATE_BUCKET".to_string(),
6208 args,
6209 ))))
6210 }
6211
6212 fn date_bucket_parts(stride: &Expression) -> Option<(&'static str, Expression)> {
6213 match stride {
6214 Expression::Literal(lit) => match lit.as_ref() {
6215 Literal::String(value) => Self::date_bucket_parts_from_string(value),
6216 _ => None,
6217 },
6218 Expression::Interval(interval) => Self::date_bucket_parts_from_interval(interval),
6219 _ => None,
6220 }
6221 }
6222
6223 fn date_bucket_parts_from_interval(interval: &Interval) -> Option<(&'static str, Expression)> {
6224 match &interval.unit {
6225 Some(IntervalUnitSpec::Simple { unit, .. }) => {
6226 let datepart = Self::date_bucket_datepart_from_unit(*unit)?;
6227 let amount = interval
6228 .this
6229 .as_ref()
6230 .and_then(Self::date_bucket_amount_expr)?;
6231 Some((datepart, amount))
6232 }
6233 None => interval.this.as_ref().and_then(|expr| match expr {
6234 Expression::Literal(lit) => match lit.as_ref() {
6235 Literal::String(value) => Self::date_bucket_parts_from_string(value),
6236 _ => None,
6237 },
6238 _ => None,
6239 }),
6240 _ => None,
6241 }
6242 }
6243
6244 fn date_bucket_parts_from_string(value: &str) -> Option<(&'static str, Expression)> {
6245 let mut parts = value.split_whitespace();
6246 let amount = parts.next()?;
6247 let unit = parts.next()?;
6248 if parts.next().is_some() {
6249 return None;
6250 }
6251
6252 Some((
6253 Self::date_bucket_datepart_from_name(unit)?,
6254 Self::positive_integer_expr(amount)?,
6255 ))
6256 }
6257
6258 fn date_bucket_amount_expr(expr: &Expression) -> Option<Expression> {
6259 match expr {
6260 Expression::Literal(lit) => match lit.as_ref() {
6261 Literal::Number(value) => Self::positive_integer_expr(value),
6262 Literal::String(value) => Self::positive_integer_expr(value),
6263 _ => None,
6264 },
6265 _ => Some(expr.clone()),
6266 }
6267 }
6268
6269 fn positive_integer_expr(value: &str) -> Option<Expression> {
6270 let parsed = value.trim().parse::<i64>().ok()?;
6271 (parsed > 0).then(|| Expression::number(parsed))
6272 }
6273
6274 fn date_bucket_datepart(datepart: &str) -> Expression {
6275 Expression::Var(Box::new(Var {
6276 this: datepart.to_string(),
6277 }))
6278 }
6279
6280 fn date_bucket_datepart_from_unit(unit: IntervalUnit) -> Option<&'static str> {
6281 match unit {
6282 IntervalUnit::Week => Some("WEEK"),
6283 IntervalUnit::Day => Some("DAY"),
6284 IntervalUnit::Hour => Some("HOUR"),
6285 IntervalUnit::Minute => Some("MINUTE"),
6286 IntervalUnit::Second => Some("SECOND"),
6287 IntervalUnit::Millisecond => Some("MILLISECOND"),
6288 _ => None,
6289 }
6290 }
6291
6292 fn date_bucket_datepart_from_name(unit: &str) -> Option<&'static str> {
6293 match unit.trim().to_ascii_uppercase().as_str() {
6294 "WEEK" | "WEEKS" | "W" | "WK" | "WKS" | "WW" => Some("WEEK"),
6295 "DAY" | "DAYS" | "D" | "DD" => Some("DAY"),
6296 "HOUR" | "HOURS" | "H" | "HH" | "HR" | "HRS" => Some("HOUR"),
6297 "MINUTE" | "MINUTES" | "MI" | "MIN" | "MINS" | "N" => Some("MINUTE"),
6298 "SECOND" | "SECONDS" | "S" | "SEC" | "SECS" | "SS" => Some("SECOND"),
6299 "MILLISECOND" | "MILLISECONDS" | "MS" | "MSEC" | "MSECS" | "MILLISEC" | "MILLISECS" => {
6300 Some("MILLISECOND")
6301 }
6302 _ => None,
6303 }
6304 }
6305
6306 fn node_has_fetch_with_ties(expr: &Expression) -> bool {
6307 matches!(
6308 expr,
6309 Expression::Select(select)
6310 if select
6311 .fetch
6312 .as_ref()
6313 .is_some_and(|fetch| fetch.with_ties)
6314 )
6315 }
6316
6317 fn node_is_overlaps(expr: &Expression) -> bool {
6318 matches!(expr, Expression::Overlaps(_))
6319 }
6320
6321 fn node_is_date_bin(expr: &Expression) -> bool {
6322 matches!(expr, Expression::DateBin(_)) || Self::node_is_function_named(expr, "DATE_BIN")
6323 }
6324
6325 fn node_is_function_named(expr: &Expression, name: &str) -> bool {
6326 match expr {
6327 Expression::Function(function) => function.name.eq_ignore_ascii_case(name),
6328 Expression::AggregateFunction(function) => function.name.eq_ignore_ascii_case(name),
6329 _ => false,
6330 }
6331 }
6332
6333 fn node_is_postgres_json_build_object(expr: &Expression) -> bool {
6334 match expr {
6335 Expression::Function(function) => {
6336 function.name.eq_ignore_ascii_case("JSON_BUILD_OBJECT")
6337 || function.name.eq_ignore_ascii_case("JSONB_BUILD_OBJECT")
6338 }
6339 _ => false,
6340 }
6341 }
6342
6343 fn postgres_json_build_object_can_lower_to_json_object(expr: &Expression) -> bool {
6344 matches!(
6345 expr,
6346 Expression::Function(function)
6347 if (function.name.eq_ignore_ascii_case("JSON_BUILD_OBJECT")
6348 || function.name.eq_ignore_ascii_case("JSONB_BUILD_OBJECT"))
6349 && !function.distinct
6350 && function.args.len() % 2 == 0
6351 )
6352 }
6353
6354 fn node_is_postgres_json_array_elements(expr: &Expression) -> bool {
6355 matches!(
6356 expr,
6357 Expression::Function(function)
6358 if function.name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS")
6359 || function.name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS")
6360 || function.name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS_TEXT")
6361 || function.name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS_TEXT")
6362 )
6363 }
6364
6365 fn postgres_tsql_unsupported_function_name(
6366 expr: &Expression,
6367 target: DialectType,
6368 ) -> Option<&'static str> {
6369 match expr {
6370 Expression::Lpad(_) => Some("LPAD"),
6371 Expression::Rpad(_) => Some("RPAD"),
6372 Expression::SplitPart(_) => Some("SPLIT_PART"),
6373 Expression::Initcap(_) => Some("INITCAP"),
6374 Expression::RegexpReplace(_) => Some("REGEXP_REPLACE"),
6375 Expression::RegexpInstr(_) => Some("REGEXP_INSTR"),
6376 Expression::RegexpCount(_) => Some("REGEXP_COUNT"),
6377 Expression::RegexpSplit(_) => Some("REGEXP_SPLIT"),
6378 Expression::DecodeCase(_) => Some("DECODE"),
6379 Expression::ToJson(_) => Some("TO_JSON"),
6380 Expression::JSONBObjectAgg(_) => Some("JSONB_OBJECT_AGG"),
6381 Expression::ToNumber(_) => Some("TO_NUMBER"),
6382 Expression::WidthBucket(_) => Some("WIDTH_BUCKET"),
6383 Expression::BitwiseAndAgg(_) => Some("BIT_AND"),
6384 Expression::BitwiseOrAgg(_) => Some("BIT_OR"),
6385 Expression::BitwiseXorAgg(_) => Some("BIT_XOR"),
6386 Expression::Corr(_) => Some("CORR"),
6387 Expression::CovarPop(_) => Some("COVAR_POP"),
6388 Expression::CovarSamp(_) => Some("COVAR_SAMP"),
6389 Expression::RegrAvgx(_) => Some("REGR_AVGX"),
6390 Expression::RegrAvgy(_) => Some("REGR_AVGY"),
6391 Expression::RegrCount(_) => Some("REGR_COUNT"),
6392 Expression::RegrIntercept(_) => Some("REGR_INTERCEPT"),
6393 Expression::RegrR2(_) => Some("REGR_R2"),
6394 Expression::RegrSlope(_) => Some("REGR_SLOPE"),
6395 Expression::RegrSxx(_) => Some("REGR_SXX"),
6396 Expression::RegrSxy(_) => Some("REGR_SXY"),
6397 Expression::RegrSyy(_) => Some("REGR_SYY"),
6398 Expression::Function(function) => {
6399 Self::postgres_tsql_unsupported_function_name_str(&function.name, target)
6400 }
6401 Expression::AggregateFunction(function) => {
6402 Self::postgres_tsql_unsupported_function_name_str(&function.name, target)
6403 }
6404 _ => None,
6405 }
6406 }
6407
6408 fn postgres_tsql_unsupported_function_name_str(
6409 name: &str,
6410 target: DialectType,
6411 ) -> Option<&'static str> {
6412 if name.eq_ignore_ascii_case("LPAD") {
6413 Some("LPAD")
6414 } else if name.eq_ignore_ascii_case("RPAD") {
6415 Some("RPAD")
6416 } else if name.eq_ignore_ascii_case("SPLIT_PART") {
6417 Some("SPLIT_PART")
6418 } else if name.eq_ignore_ascii_case("INITCAP") {
6419 Some("INITCAP")
6420 } else if name.eq_ignore_ascii_case("TO_JSON") {
6421 Some("TO_JSON")
6422 } else if name.eq_ignore_ascii_case("TO_JSONB") {
6423 Some("TO_JSONB")
6424 } else if name.eq_ignore_ascii_case("JSONB_OBJECT_AGG") {
6425 Some("JSONB_OBJECT_AGG")
6426 } else if name.eq_ignore_ascii_case("ROW_TO_JSON") {
6427 Some("ROW_TO_JSON")
6428 } else if name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS") {
6429 Some("JSON_ARRAY_ELEMENTS")
6430 } else if name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS") {
6431 Some("JSONB_ARRAY_ELEMENTS")
6432 } else if name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS_TEXT") {
6433 Some("JSON_ARRAY_ELEMENTS_TEXT")
6434 } else if name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS_TEXT") {
6435 Some("JSONB_ARRAY_ELEMENTS_TEXT")
6436 } else if name.eq_ignore_ascii_case("ENCODE") {
6437 Some("ENCODE")
6438 } else if name.eq_ignore_ascii_case("DECODE") {
6439 Some("DECODE")
6440 } else if name.eq_ignore_ascii_case("REGEXP_REPLACE") {
6441 Some("REGEXP_REPLACE")
6442 } else if name.eq_ignore_ascii_case("REGEXP_COUNT") {
6443 Some("REGEXP_COUNT")
6444 } else if name.eq_ignore_ascii_case("REGEXP_INSTR") {
6445 Some("REGEXP_INSTR")
6446 } else if name.eq_ignore_ascii_case("REGEXP_SUBSTR") {
6447 Some("REGEXP_SUBSTR")
6448 } else if name.eq_ignore_ascii_case("REGEXP_SPLIT") {
6449 Some("REGEXP_SPLIT")
6450 } else if name.eq_ignore_ascii_case("REGEXP_SPLIT_TO_ARRAY") {
6451 Some("REGEXP_SPLIT_TO_ARRAY")
6452 } else if name.eq_ignore_ascii_case("REGEXP_SPLIT_TO_TABLE") {
6453 Some("REGEXP_SPLIT_TO_TABLE")
6454 } else if name.eq_ignore_ascii_case("SHA224") {
6455 Some("SHA224")
6456 } else if name.eq_ignore_ascii_case("SHA384") {
6457 Some("SHA384")
6458 } else if name.eq_ignore_ascii_case("TO_BIN") {
6459 Some("TO_BIN")
6460 } else if name.eq_ignore_ascii_case("TO_OCT") {
6461 Some("TO_OCT")
6462 } else if target == DialectType::TSQL && name.eq_ignore_ascii_case("UNISTR") {
6463 Some("UNISTR")
6464 } else if name.eq_ignore_ascii_case("AGE") {
6465 Some("AGE")
6466 } else if name.eq_ignore_ascii_case("ERF") {
6467 Some("ERF")
6468 } else if name.eq_ignore_ascii_case("SINH") {
6469 Some("SINH")
6470 } else if name.eq_ignore_ascii_case("COSH") {
6471 Some("COSH")
6472 } else if name.eq_ignore_ascii_case("TANH") {
6473 Some("TANH")
6474 } else if name.eq_ignore_ascii_case("ASINH") {
6475 Some("ASINH")
6476 } else if name.eq_ignore_ascii_case("ACOSH") {
6477 Some("ACOSH")
6478 } else if name.eq_ignore_ascii_case("ATANH") {
6479 Some("ATANH")
6480 } else if name.eq_ignore_ascii_case("GCD") {
6481 Some("GCD")
6482 } else if name.eq_ignore_ascii_case("LCM") {
6483 Some("LCM")
6484 } else if name.eq_ignore_ascii_case("QUOTE_LITERAL") {
6485 Some("QUOTE_LITERAL")
6486 } else if name.eq_ignore_ascii_case("WIDTH_BUCKET") {
6487 Some("WIDTH_BUCKET")
6488 } else if name.eq_ignore_ascii_case("SCALE") {
6489 Some("SCALE")
6490 } else if name.eq_ignore_ascii_case("TRIM_SCALE") {
6491 Some("TRIM_SCALE")
6492 } else if name.eq_ignore_ascii_case("MIN_SCALE") {
6493 Some("MIN_SCALE")
6494 } else if name.eq_ignore_ascii_case("FACTORIAL") {
6495 Some("FACTORIAL")
6496 } else if name.eq_ignore_ascii_case("PG_LSN") {
6497 Some("PG_LSN")
6498 } else if name.eq_ignore_ascii_case("TO_CHAR") {
6499 Some("TO_CHAR")
6500 } else if name.eq_ignore_ascii_case("PG_TYPEOF") {
6501 Some("PG_TYPEOF")
6502 } else if name.eq_ignore_ascii_case("BIT_AND") {
6503 Some("BIT_AND")
6504 } else if name.eq_ignore_ascii_case("BIT_OR") {
6505 Some("BIT_OR")
6506 } else if name.eq_ignore_ascii_case("BIT_XOR") {
6507 Some("BIT_XOR")
6508 } else if name.eq_ignore_ascii_case("CORR") {
6509 Some("CORR")
6510 } else if name.eq_ignore_ascii_case("COVAR_POP") {
6511 Some("COVAR_POP")
6512 } else if name.eq_ignore_ascii_case("COVAR_SAMP") {
6513 Some("COVAR_SAMP")
6514 } else if name.eq_ignore_ascii_case("REGR_AVGX") {
6515 Some("REGR_AVGX")
6516 } else if name.eq_ignore_ascii_case("REGR_AVGY") {
6517 Some("REGR_AVGY")
6518 } else if name.eq_ignore_ascii_case("REGR_COUNT") {
6519 Some("REGR_COUNT")
6520 } else if name.eq_ignore_ascii_case("REGR_INTERCEPT") {
6521 Some("REGR_INTERCEPT")
6522 } else if name.eq_ignore_ascii_case("REGR_R2") {
6523 Some("REGR_R2")
6524 } else if name.eq_ignore_ascii_case("REGR_SLOPE") {
6525 Some("REGR_SLOPE")
6526 } else if name.eq_ignore_ascii_case("REGR_SXX") {
6527 Some("REGR_SXX")
6528 } else if name.eq_ignore_ascii_case("REGR_SXY") {
6529 Some("REGR_SXY")
6530 } else if name.eq_ignore_ascii_case("REGR_SYY") {
6531 Some("REGR_SYY")
6532 } else if name.eq_ignore_ascii_case("FLOAT8_ACCUM") {
6533 Some("FLOAT8_ACCUM")
6534 } else if name.eq_ignore_ascii_case("FLOAT8_REGR_ACCUM") {
6535 Some("FLOAT8_REGR_ACCUM")
6536 } else if name.eq_ignore_ascii_case("FLOAT8_COMBINE") {
6537 Some("FLOAT8_COMBINE")
6538 } else if name.eq_ignore_ascii_case("FLOAT8_REGR_COMBINE") {
6539 Some("FLOAT8_REGR_COMBINE")
6540 } else if name.eq_ignore_ascii_case("BOOLAND_STATEFUNC") {
6541 Some("BOOLAND_STATEFUNC")
6542 } else if name.eq_ignore_ascii_case("BOOLOR_STATEFUNC") {
6543 Some("BOOLOR_STATEFUNC")
6544 } else {
6545 None
6546 }
6547 }
6548
6549 fn normalize_postgres_trim_for_tsql(expr: Expression) -> Result<Expression> {
6550 transform_recursive(expr, &|e| match e {
6551 Expression::Trim(trim) => {
6552 let mut trim = *trim;
6553 trim.characters = trim.characters.map(Self::strip_postgres_text_literal_cast);
6554 match trim.position {
6555 crate::expressions::TrimPosition::Both
6556 if trim.position_explicit && trim.characters.is_some() =>
6557 {
6558 trim.position_explicit = false;
6559 trim.sql_standard_syntax = true;
6560 Ok(Expression::Trim(Box::new(trim)))
6561 }
6562 crate::expressions::TrimPosition::Leading if trim.characters.is_some() => {
6563 let characters = trim.characters.take().expect("checked above");
6564 Ok(Expression::Function(Box::new(Function::new(
6565 "LTRIM",
6566 vec![trim.this, characters],
6567 ))))
6568 }
6569 crate::expressions::TrimPosition::Trailing if trim.characters.is_some() => {
6570 let characters = trim.characters.take().expect("checked above");
6571 Ok(Expression::Function(Box::new(Function::new(
6572 "RTRIM",
6573 vec![trim.this, characters],
6574 ))))
6575 }
6576 _ => Ok(Expression::Trim(Box::new(trim))),
6577 }
6578 }
6579 other => Ok(other),
6580 })
6581 }
6582
6583 fn normalize_postgres_string_semantics_for_tsql(expr: Expression) -> Result<Expression> {
6584 transform_recursive(expr, &|e| match e {
6585 Expression::Like(mut op) => {
6586 Self::recover_postgres_like_escape(&mut op);
6587 Ok(Expression::Like(op))
6588 }
6589 Expression::ILike(mut op) => {
6590 Self::recover_postgres_like_escape(&mut op);
6591 Ok(Expression::ILike(op))
6592 }
6593 Expression::Substring(mut substring)
6594 if substring.length.is_none()
6595 && Self::is_explicitly_numeric_expression(&substring.start) =>
6596 {
6597 substring.length = Some(Expression::number(i32::MAX as i64));
6598 Ok(Expression::Substring(substring))
6599 }
6600 Expression::Trim(mut trim) => {
6601 trim.characters = trim.characters.map(Self::strip_postgres_text_literal_cast);
6602 Ok(Expression::Trim(trim))
6603 }
6604 Expression::Function(mut function)
6605 if !function.quoted
6606 && matches!(
6607 function.name.to_ascii_uppercase().as_str(),
6608 "BTRIM" | "LTRIM" | "RTRIM"
6609 )
6610 && function.args.len() == 2 =>
6611 {
6612 function.args[1] = Self::strip_postgres_text_literal_cast(function.args[1].clone());
6613 Ok(Expression::Function(function))
6614 }
6615 Expression::Translate(translate) => {
6616 Ok(Self::normalize_postgres_translate_for_tsql(*translate))
6617 }
6618 Expression::Function(function)
6619 if !function.quoted
6620 && function.name.eq_ignore_ascii_case("TRANSLATE")
6621 && function.args.len() == 3 =>
6622 {
6623 Ok(Self::normalize_postgres_translate_function_for_tsql(
6624 *function,
6625 ))
6626 }
6627 other => Ok(other),
6628 })
6629 }
6630
6631 fn normalize_postgres_bytea_literals_for_tsql(expr: Expression) -> Result<Expression> {
6632 transform_recursive(expr, &|e| match e {
6633 Expression::Cast(cast) if Self::is_postgres_bytea_data_type(&cast.to) => {
6634 let Some(value) = Self::postgres_plain_string_literal_value(&cast.this) else {
6635 return Ok(Expression::Cast(cast));
6636 };
6637 let Some(hex) = Self::postgres_bytea_hex_payload(value) else {
6638 return Ok(Expression::Cast(cast));
6639 };
6640
6641 Ok(Expression::Literal(Box::new(Literal::HexString(hex))))
6645 }
6646 other => Ok(other),
6647 })
6648 }
6649
6650 fn postgres_plain_string_literal_value(expr: &Expression) -> Option<&str> {
6651 match expr {
6652 Expression::Literal(literal) => match literal.as_ref() {
6653 Literal::String(value) => Some(value),
6654 _ => None,
6655 },
6656 Expression::Paren(paren) => Self::postgres_plain_string_literal_value(&paren.this),
6657 _ => None,
6658 }
6659 }
6660
6661 fn postgres_bytea_hex_payload(value: &str) -> Option<String> {
6662 let payload = value.strip_prefix("\\x")?;
6663 if payload.is_empty() {
6664 return Some(String::new());
6665 }
6666
6667 let mut chars = payload.chars().peekable();
6668 let mut hex = String::with_capacity(payload.len());
6669 loop {
6670 let high = chars.next()?;
6671 let low = chars.next()?;
6672 if !high.is_ascii_hexdigit() || !low.is_ascii_hexdigit() {
6673 return None;
6674 }
6675 hex.push(high);
6676 hex.push(low);
6677
6678 let Some(next) = chars.peek().copied() else {
6679 return Some(hex);
6680 };
6681 if next.is_ascii_whitespace() {
6682 while chars
6683 .peek()
6684 .is_some_and(|character| character.is_ascii_whitespace())
6685 {
6686 chars.next();
6687 }
6688 chars.peek()?;
6691 }
6692 }
6693 }
6694
6695 fn is_postgres_bytea_data_type(data_type: &DataType) -> bool {
6696 match data_type {
6697 DataType::VarBinary { length: None } => true,
6698 DataType::Custom { name } => name.trim().eq_ignore_ascii_case("BYTEA"),
6699 _ => false,
6700 }
6701 }
6702
6703 fn postgres_tsql_unsupported_binary_semantics(expr: &Expression) -> Option<&'static str> {
6704 let cast = match expr {
6705 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
6706 if Self::is_postgres_bytea_data_type(&cast.to) =>
6707 {
6708 cast
6709 }
6710 _ => return None,
6711 };
6712
6713 let literal = match &cast.this {
6714 Expression::Literal(literal) => literal.as_ref(),
6715 Expression::Paren(paren) => match &paren.this {
6716 Expression::Literal(literal) => literal.as_ref(),
6717 _ => return None,
6718 },
6719 _ => return None,
6720 };
6721 let value = match literal {
6722 Literal::String(value) | Literal::EscapeString(value) => value,
6723 _ => return None,
6724 };
6725
6726 if value.starts_with("\\x") {
6727 Some("bytea hex literals with invalid or unsupported formatting")
6728 } else if value.contains('\\') {
6729 Some("bytea escape-format literals")
6730 } else {
6731 None
6732 }
6733 }
6734
6735 fn recover_postgres_like_escape(op: &mut crate::expressions::LikeOp) {
6736 if op.escape.is_some() {
6737 return;
6738 }
6739
6740 let Expression::Function(function) = &op.right else {
6741 return;
6742 };
6743 if function.quoted
6744 || function.distinct
6745 || !function.name.eq_ignore_ascii_case("LIKE_ESCAPE")
6746 || function.args.len() != 2
6747 {
6748 return;
6749 }
6750
6751 let pattern = function.args[0].clone();
6752 let escape = function.args[1].clone();
6753 op.right = Self::strip_postgres_text_literal_cast(pattern);
6754 op.escape = Some(Self::strip_postgres_text_literal_cast(escape));
6755 }
6756
6757 fn normalize_postgres_translate_for_tsql(
6758 mut translate: crate::expressions::Translate,
6759 ) -> Expression {
6760 let (Some(from), Some(to)) = (&translate.from_, &translate.to) else {
6761 return Expression::Translate(Box::new(translate));
6762 };
6763
6764 let (Some(from_value), Some(to_value)) = (
6765 Self::postgres_text_literal_value(from),
6766 Self::postgres_text_literal_value(to),
6767 ) else {
6768 return Expression::Translate(Box::new(translate));
6769 };
6770 let from_value = from_value.to_string();
6771 let to_value = to_value.to_string();
6772
6773 if from_value.chars().count() > to_value.chars().count() {
6774 if let Some(input) = Self::postgres_text_literal_value(&translate.this) {
6775 return Expression::string(Self::translate_postgres_literal(
6776 input,
6777 &from_value,
6778 &to_value,
6779 ));
6780 }
6781 return Expression::Translate(Box::new(translate));
6782 }
6783
6784 translate.from_ = Some(Box::new(Self::strip_postgres_text_literal_cast(
6785 *translate.from_.expect("checked above"),
6786 )));
6787 let normalized_to = if from_value.chars().count() < to_value.chars().count() {
6788 Expression::string(
6789 to_value
6790 .chars()
6791 .take(from_value.chars().count())
6792 .collect::<String>(),
6793 )
6794 } else {
6795 Self::strip_postgres_text_literal_cast(*translate.to.expect("checked above"))
6796 };
6797 translate.to = Some(Box::new(normalized_to));
6798 Expression::Translate(Box::new(translate))
6799 }
6800
6801 fn normalize_postgres_translate_function_for_tsql(mut function: Function) -> Expression {
6802 let from = Self::postgres_text_literal_value(&function.args[1]);
6803 let to = Self::postgres_text_literal_value(&function.args[2]);
6804 let (Some(from), Some(to)) = (from, to) else {
6805 return Expression::Function(Box::new(function));
6806 };
6807 let from = from.to_string();
6808 let to = to.to_string();
6809
6810 if from.chars().count() > to.chars().count() {
6811 if let Some(input) = Self::postgres_text_literal_value(&function.args[0]) {
6812 return Expression::string(Self::translate_postgres_literal(input, &from, &to));
6813 }
6814 return Expression::Function(Box::new(function));
6815 }
6816
6817 function.args[1] = Self::strip_postgres_text_literal_cast(function.args[1].clone());
6818 function.args[2] = if from.chars().count() < to.chars().count() {
6819 Expression::string(to.chars().take(from.chars().count()).collect::<String>())
6820 } else {
6821 Self::strip_postgres_text_literal_cast(function.args[2].clone())
6822 };
6823 Expression::Function(Box::new(function))
6824 }
6825
6826 fn translate_postgres_literal(input: &str, from: &str, to: &str) -> String {
6827 let from = from.chars().collect::<Vec<_>>();
6828 let to = to.chars().collect::<Vec<_>>();
6829 let mut output = String::with_capacity(input.len());
6830
6831 for ch in input.chars() {
6832 match from.iter().position(|candidate| *candidate == ch) {
6833 Some(index) if index < to.len() => output.push(to[index]),
6834 Some(_) => {}
6835 None => output.push(ch),
6836 }
6837 }
6838
6839 output
6840 }
6841
6842 fn postgres_tsql_unsupported_string_semantics(expr: &Expression) -> Option<&'static str> {
6843 match expr {
6844 Expression::Substring(substring) if substring.length.is_none() => {
6845 if Self::postgres_text_literal_value(&substring.start).is_some() {
6846 Some("regular-expression SUBSTRING")
6847 } else {
6848 Some("SUBSTRING without a statically numeric start position")
6849 }
6850 }
6851 Expression::Translate(translate) => {
6852 let from = translate
6853 .from_
6854 .as_deref()
6855 .and_then(Self::postgres_text_literal_value);
6856 let to = translate
6857 .to
6858 .as_deref()
6859 .and_then(Self::postgres_text_literal_value);
6860 match (from, to) {
6861 (Some(from), Some(to)) if from.chars().count() == to.chars().count() => None,
6862 _ => Some("TRANSLATE with source and replacement lengths that differ or cannot be proven equal"),
6863 }
6864 }
6865 Expression::Function(function)
6866 if !function.quoted && function.name.eq_ignore_ascii_case("LIKE_ESCAPE") =>
6867 {
6868 Some("LIKE_ESCAPE helper outside a LIKE predicate")
6869 }
6870 Expression::Function(function)
6871 if !function.quoted
6872 && function.name.eq_ignore_ascii_case("TRANSLATE")
6873 && function.args.len() == 3 =>
6874 {
6875 let from = Self::postgres_text_literal_value(&function.args[1]);
6876 let to = Self::postgres_text_literal_value(&function.args[2]);
6877 match (from, to) {
6878 (Some(from), Some(to)) if from.chars().count() == to.chars().count() => None,
6879 _ => Some("TRANSLATE with source and replacement lengths that differ or cannot be proven equal"),
6880 }
6881 }
6882 Expression::Trim(trim)
6883 if trim
6884 .characters
6885 .as_ref()
6886 .is_some_and(Self::is_unbounded_text_cast) =>
6887 {
6888 Some("TRIM character set cast to an unbounded text type")
6889 }
6890 Expression::Function(function)
6891 if !function.quoted
6892 && matches!(
6893 function.name.to_ascii_uppercase().as_str(),
6894 "LTRIM" | "RTRIM"
6895 )
6896 && function.args.len() == 2
6897 && Self::is_unbounded_text_cast(&function.args[1]) =>
6898 {
6899 Some("TRIM character set cast to an unbounded text type")
6900 }
6901 _ => None,
6902 }
6903 }
6904
6905 fn strip_postgres_text_literal_cast(expr: Expression) -> Expression {
6906 match expr {
6907 Expression::Cast(cast)
6908 if Self::is_text_data_type(&cast.to)
6909 && Self::postgres_text_literal_value(&cast.this).is_some() =>
6910 {
6911 Self::strip_postgres_text_literal_cast(cast.this)
6912 }
6913 Expression::TryCast(cast)
6914 if Self::is_text_data_type(&cast.to)
6915 && Self::postgres_text_literal_value(&cast.this).is_some() =>
6916 {
6917 Self::strip_postgres_text_literal_cast(cast.this)
6918 }
6919 Expression::SafeCast(cast)
6920 if Self::is_text_data_type(&cast.to)
6921 && Self::postgres_text_literal_value(&cast.this).is_some() =>
6922 {
6923 Self::strip_postgres_text_literal_cast(cast.this)
6924 }
6925 Expression::Paren(mut paren)
6926 if Self::postgres_text_literal_value(&paren.this).is_some() =>
6927 {
6928 paren.this = Self::strip_postgres_text_literal_cast(paren.this);
6929 Expression::Paren(paren)
6930 }
6931 other => other,
6932 }
6933 }
6934
6935 fn postgres_text_literal_value(expr: &Expression) -> Option<&str> {
6936 match expr {
6937 Expression::Literal(literal) if literal.is_string() => Some(literal.value_str()),
6938 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
6939 if Self::is_text_data_type(&cast.to) =>
6940 {
6941 Self::postgres_text_literal_value(&cast.this)
6942 }
6943 Expression::Alias(alias) => Self::postgres_text_literal_value(&alias.this),
6944 Expression::Paren(paren) => Self::postgres_text_literal_value(&paren.this),
6945 _ => None,
6946 }
6947 }
6948
6949 fn is_text_data_type(data_type: &DataType) -> bool {
6950 match data_type {
6951 DataType::Char { .. }
6952 | DataType::VarChar { .. }
6953 | DataType::String { .. }
6954 | DataType::Text
6955 | DataType::TextWithLength { .. } => true,
6956 DataType::Custom { name } => {
6957 let base = name
6958 .split_once('(')
6959 .map_or(name.as_str(), |(base, _)| base)
6960 .trim();
6961 matches!(
6962 base.to_ascii_uppercase().as_str(),
6963 "CHAR"
6964 | "NCHAR"
6965 | "VARCHAR"
6966 | "NVARCHAR"
6967 | "TEXT"
6968 | "NTEXT"
6969 | "STRING"
6970 | "CHARACTER VARYING"
6971 )
6972 }
6973 _ => false,
6974 }
6975 }
6976
6977 fn is_unbounded_text_cast(expr: &Expression) -> bool {
6978 let data_type = match expr {
6979 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
6980 &cast.to
6981 }
6982 Expression::Paren(paren) => return Self::is_unbounded_text_cast(&paren.this),
6983 _ => return false,
6984 };
6985
6986 match data_type {
6987 DataType::Text => true,
6988 DataType::VarChar { length: None, .. } | DataType::String { length: None } => true,
6989 DataType::Custom { name } => name.to_ascii_uppercase().contains("(MAX)"),
6990 _ => false,
6991 }
6992 }
6993
6994 fn is_explicitly_numeric_expression(expr: &Expression) -> bool {
6995 if expr.inferred_type().is_some_and(Self::is_numeric_data_type) {
6996 return true;
6997 }
6998
6999 match expr {
7000 Expression::Literal(literal) => literal.is_number(),
7001 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
7002 Self::is_numeric_data_type(&cast.to)
7003 }
7004 Expression::Alias(alias) => Self::is_explicitly_numeric_expression(&alias.this),
7005 Expression::Paren(paren) => Self::is_explicitly_numeric_expression(&paren.this),
7006 Expression::Neg(unary) => Self::is_explicitly_numeric_expression(&unary.this),
7007 _ => false,
7008 }
7009 }
7010
7011 fn is_numeric_data_type(data_type: &DataType) -> bool {
7012 match data_type {
7013 DataType::TinyInt { .. }
7014 | DataType::SmallInt { .. }
7015 | DataType::Int { .. }
7016 | DataType::BigInt { .. }
7017 | DataType::Float { .. }
7018 | DataType::Double { .. }
7019 | DataType::Decimal { .. } => true,
7020 DataType::Custom { name } => {
7021 let base = name
7022 .split_once('(')
7023 .map_or(name.as_str(), |(base, _)| base)
7024 .trim();
7025 matches!(
7026 base.to_ascii_uppercase().as_str(),
7027 "TINYINT"
7028 | "SMALLINT"
7029 | "INT"
7030 | "INTEGER"
7031 | "BIGINT"
7032 | "DECIMAL"
7033 | "NUMERIC"
7034 | "REAL"
7035 | "FLOAT"
7036 | "MONEY"
7037 | "SMALLMONEY"
7038 )
7039 }
7040 _ => false,
7041 }
7042 }
7043
7044 fn normalize_postgres_only_for_tsql(expr: Expression) -> Result<Expression> {
7045 transform_recursive(expr, &|e| match e {
7046 Expression::Table(mut table) if table.only => {
7047 table.only = false;
7048 Ok(Expression::Table(table))
7049 }
7050 other => Ok(other),
7051 })
7052 }
7053
7054 fn rewrite_postgres_json_array_elements_select_for_tsql(
7055 expr: Expression,
7056 ) -> Result<Expression> {
7057 let Expression::Select(select) = expr else {
7058 return Ok(expr);
7059 };
7060 let mut select = *select;
7061 if !Self::is_plain_single_projection_select(&select) {
7062 return Ok(Expression::Select(Box::new(select)));
7063 }
7064
7065 let Some(json_arg) =
7066 Self::postgres_json_array_elements_projection_arg(&select.expressions[0])
7067 else {
7068 return Ok(Expression::Select(Box::new(select)));
7069 };
7070
7071 select.expressions = vec![Expression::column("value")];
7072 select.from = Some(From {
7073 expressions: vec![Expression::OpenJSON(Box::new(
7074 crate::expressions::OpenJSON {
7075 this: Box::new(json_arg),
7076 path: None,
7077 expressions: Vec::new(),
7078 },
7079 ))],
7080 });
7081
7082 Ok(Expression::Select(Box::new(select)))
7083 }
7084
7085 fn is_plain_single_projection_select(select: &crate::expressions::Select) -> bool {
7086 select.expressions.len() == 1
7087 && select.from.is_none()
7088 && select.joins.is_empty()
7089 && select.lateral_views.is_empty()
7090 && select.prewhere.is_none()
7091 && select.where_clause.is_none()
7092 && select.group_by.is_none()
7093 && select.having.is_none()
7094 && select.qualify.is_none()
7095 && select.order_by.is_none()
7096 && select.distribute_by.is_none()
7097 && select.cluster_by.is_none()
7098 && select.sort_by.is_none()
7099 && select.limit.is_none()
7100 && select.offset.is_none()
7101 && select.limit_by.is_none()
7102 && select.fetch.is_none()
7103 && !select.distinct
7104 && select.distinct_on.is_none()
7105 && select.top.is_none()
7106 && select.with.is_none()
7107 && select.sample.is_none()
7108 && select.into.is_none()
7109 && select.locks.is_empty()
7110 && select.for_xml.is_empty()
7111 && select.for_json.is_empty()
7112 && select.exclude.is_none()
7113 }
7114
7115 fn postgres_json_array_elements_projection_arg(expr: &Expression) -> Option<Expression> {
7116 match expr {
7117 Expression::Function(function)
7118 if Self::node_is_postgres_json_array_elements(expr) && function.args.len() == 1 =>
7119 {
7120 Some(function.args[0].clone())
7121 }
7122 Expression::Alias(alias) => {
7123 Self::postgres_json_array_elements_projection_arg(&alias.this)
7124 }
7125 _ => None,
7126 }
7127 }
7128
7129 fn normalize_postgres_type_function_casts(
7130 expr: Expression,
7131 target: DialectType,
7132 ) -> Result<Expression> {
7133 transform_recursive(expr, &|e| match e {
7134 Expression::Function(function) => {
7135 let mut function = *function;
7136 if function.args.len() == 1
7137 && !function.distinct
7138 && !function.quoted
7139 && !function.use_bracket_syntax
7140 && !function.name.contains('.')
7141 {
7142 if let Some(to) = Self::postgres_type_function_data_type(&function.name) {
7143 let this = function.args.remove(0);
7144 let cast = Cast {
7145 this,
7146 to,
7147 trailing_comments: function.trailing_comments,
7148 double_colon_syntax: false,
7149 format: None,
7150 default: None,
7151 inferred_type: function.inferred_type,
7152 };
7153 return Ok(
7154 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
7155 normalization::rewrite_postgres_float_to_integer_cast(cast)
7156 } else {
7157 Expression::Cast(Box::new(cast))
7158 },
7159 );
7160 }
7161 }
7162 Ok(Expression::Function(Box::new(function)))
7163 }
7164 _ => Ok(e),
7165 })
7166 }
7167
7168 fn node_is_postgres_type_function_cast(expr: &Expression) -> bool {
7169 matches!(
7170 expr,
7171 Expression::Function(function)
7172 if !function.quoted
7173 && !function.use_bracket_syntax
7174 && !function.name.contains('.')
7175 && Self::postgres_type_function_data_type(&function.name).is_some()
7176 )
7177 }
7178
7179 fn postgres_type_function_data_type(name: &str) -> Option<DataType> {
7180 match name.to_ascii_uppercase().as_str() {
7181 "NUMERIC" | "DECIMAL" | "DEC" => Some(DataType::Decimal {
7182 precision: None,
7183 scale: None,
7184 }),
7185 "INT2" | "SMALLINT" => Some(DataType::SmallInt { length: None }),
7186 "INT4" | "INT" => Some(DataType::Int {
7187 length: None,
7188 integer_spelling: false,
7189 }),
7190 "INTEGER" => Some(DataType::Int {
7191 length: None,
7192 integer_spelling: true,
7193 }),
7194 "INT8" | "BIGINT" => Some(DataType::BigInt { length: None }),
7195 "FLOAT4" | "REAL" => Some(DataType::Float {
7196 precision: None,
7197 scale: None,
7198 real_spelling: true,
7199 }),
7200 "FLOAT8" => Some(DataType::Double {
7201 precision: None,
7202 scale: None,
7203 }),
7204 "BOOL" | "BOOLEAN" => Some(DataType::Boolean),
7205 "TEXT" => Some(DataType::Text),
7206 "VARCHAR" => Some(DataType::VarChar {
7207 length: None,
7208 parenthesized_length: false,
7209 }),
7210 "UUID" => Some(DataType::Uuid),
7211 _ => None,
7212 }
7213 }
7214
7215 fn rewrite_boolean_values_for_tsql(expr: Expression) -> Result<Expression> {
7216 match expr {
7217 Expression::Select(select) => Self::rewrite_boolean_values_in_tsql_select(select),
7218 Expression::Subquery(mut subquery) => {
7219 subquery.this = Self::rewrite_boolean_values_for_tsql(subquery.this)?;
7220 Ok(Expression::Subquery(subquery))
7221 }
7222 Expression::Union(mut union) => {
7223 let left = std::mem::replace(&mut union.left, Expression::null());
7224 let right = std::mem::replace(&mut union.right, Expression::null());
7225 union.left = Self::rewrite_boolean_values_for_tsql(left)?;
7226 union.right = Self::rewrite_boolean_values_for_tsql(right)?;
7227 if let Some(mut with) = union.with.take() {
7228 with.ctes = with
7229 .ctes
7230 .into_iter()
7231 .map(|mut cte| {
7232 cte.this = Self::rewrite_boolean_values_for_tsql(cte.this)?;
7233 Ok(cte)
7234 })
7235 .collect::<Result<Vec<_>>>()?;
7236 union.with = Some(with);
7237 }
7238 Ok(Expression::Union(union))
7239 }
7240 Expression::Intersect(mut intersect) => {
7241 let left = std::mem::replace(&mut intersect.left, Expression::null());
7242 let right = std::mem::replace(&mut intersect.right, Expression::null());
7243 intersect.left = Self::rewrite_boolean_values_for_tsql(left)?;
7244 intersect.right = Self::rewrite_boolean_values_for_tsql(right)?;
7245 Ok(Expression::Intersect(intersect))
7246 }
7247 Expression::Except(mut except) => {
7248 let left = std::mem::replace(&mut except.left, Expression::null());
7249 let right = std::mem::replace(&mut except.right, Expression::null());
7250 except.left = Self::rewrite_boolean_values_for_tsql(left)?;
7251 except.right = Self::rewrite_boolean_values_for_tsql(right)?;
7252 Ok(Expression::Except(except))
7253 }
7254 other => Self::rewrite_tsql_boolean_nested_contexts(other),
7255 }
7256 }
7257
7258 fn rewrite_postgres_row_value_equality_for_tsql(expr: Expression) -> Result<Expression> {
7259 transform_recursive(expr, &|e| match e {
7260 Expression::Eq(op) => {
7261 let op = *op;
7262 Ok(Self::postgres_row_value_equality_to_tsql_scalar(&op)
7263 .unwrap_or_else(|| Expression::Eq(Box::new(op))))
7264 }
7265 other => Ok(other),
7266 })
7267 }
7268
7269 fn postgres_row_value_equality_to_tsql_scalar(op: &BinaryOp) -> Option<Expression> {
7270 let (row, query) =
7271 if Self::expr_is_row_value(&op.left) && Self::expr_is_subquery_like(&op.right) {
7272 (&op.left, &op.right)
7273 } else if Self::expr_is_row_value(&op.right) && Self::expr_is_subquery_like(&op.left) {
7274 (&op.right, &op.left)
7275 } else {
7276 return None;
7277 };
7278
7279 let row_values = Self::row_value_expressions(row)?;
7280 let projection_count = Self::subquery_projection_count(query)?;
7281 if row_values.is_empty() || row_values.len() != projection_count {
7282 return None;
7283 }
7284
7285 let mut taken_names = HashSet::new();
7290 Self::collect_generated_alias_conflicts(row, &mut taken_names);
7291 Self::collect_generated_alias_conflicts(query, &mut taken_names);
7292
7293 let source_alias = find_new_name(&taken_names, "_polyglot_row");
7294 taken_names.insert(source_alias.to_ascii_lowercase());
7295 let column_aliases = (1..=row_values.len())
7296 .map(|index| {
7297 let name = find_new_name(&taken_names, &format!("_polyglot_row_value_{index}"));
7298 taken_names.insert(name.to_ascii_lowercase());
7299 Identifier::new(name)
7300 })
7301 .collect::<Vec<_>>();
7302 let source = Self::subquery_as_derived_table(
7303 query,
7304 Identifier::new(&source_alias),
7305 column_aliases.clone(),
7306 )?;
7307
7308 let mut equal_components = Vec::with_capacity(row_values.len());
7309 let mut unequal_components = Vec::with_capacity(row_values.len());
7310 for (column, row_value) in column_aliases.into_iter().zip(row_values) {
7311 let projected = Expression::qualified_column(source_alias.clone(), column.name);
7312 equal_components.push(Expression::Eq(Box::new(BinaryOp::new(
7313 projected.clone(),
7314 row_value.clone(),
7315 ))));
7316 unequal_components.push(Expression::Neq(Box::new(BinaryOp::new(
7317 projected, row_value,
7318 ))));
7319 }
7320
7321 let all_equal = equal_components
7322 .into_iter()
7323 .reduce(|left, right| Expression::And(Box::new(BinaryOp::new(left, right))))?;
7324 let any_unequal = unequal_components
7325 .into_iter()
7326 .reduce(|left, right| Expression::Or(Box::new(BinaryOp::new(left, right))))?;
7327 let comparison = Expression::Case(Box::new(Case {
7328 operand: None,
7329 whens: vec![
7330 (all_equal, Expression::number(1)),
7331 (any_unequal, Expression::number(0)),
7332 ],
7333 else_: Some(Expression::null()),
7334 comments: Vec::new(),
7335 inferred_type: None,
7336 }));
7337
7338 let scalar_select = Select::new().column(comparison).from(source);
7339 let scalar_subquery = Expression::Subquery(Box::new(Subquery {
7340 this: Expression::Select(Box::new(scalar_select)),
7341 alias: None,
7342 column_aliases: Vec::new(),
7343 alias_explicit_as: false,
7344 alias_keyword: None,
7345 order_by: None,
7346 limit: None,
7347 offset: None,
7348 distribute_by: None,
7349 sort_by: None,
7350 cluster_by: None,
7351 lateral: false,
7352 modifiers_inside: false,
7353 trailing_comments: Vec::new(),
7354 inferred_type: Some(DataType::Boolean),
7355 }));
7356
7357 Some(Expression::Cast(Box::new(Cast {
7358 this: scalar_subquery,
7359 to: DataType::Boolean,
7360 trailing_comments: Vec::new(),
7361 double_colon_syntax: false,
7362 format: None,
7363 default: None,
7364 inferred_type: Some(DataType::Boolean),
7365 })))
7366 }
7367
7368 fn row_value_expressions(expr: &Expression) -> Option<Vec<Expression>> {
7369 match expr {
7370 Expression::Tuple(tuple) => Some(tuple.expressions.clone()),
7371 Expression::Function(function) if function.name.eq_ignore_ascii_case("ROW") => {
7372 Some(function.args.clone())
7373 }
7374 Expression::Paren(paren) => Self::row_value_expressions(&paren.this),
7375 _ => None,
7376 }
7377 }
7378
7379 fn subquery_projection_count(expr: &Expression) -> Option<usize> {
7380 match expr {
7381 Expression::Select(select) => Some(select.expressions.len()),
7382 Expression::Subquery(subquery) => Self::subquery_projection_count(&subquery.this),
7383 Expression::Paren(paren) => Self::subquery_projection_count(&paren.this),
7384 _ => None,
7385 }
7386 }
7387
7388 fn subquery_as_derived_table(
7389 expr: &Expression,
7390 alias: Identifier,
7391 column_aliases: Vec<Identifier>,
7392 ) -> Option<Expression> {
7393 match expr.clone() {
7394 Expression::Subquery(mut subquery) => {
7395 subquery.alias = Some(alias);
7396 subquery.column_aliases = column_aliases;
7397 subquery.alias_explicit_as = true;
7398 subquery.alias_keyword = None;
7399 Some(Expression::Subquery(subquery))
7400 }
7401 Expression::Select(_) | Expression::Paren(_) => {
7402 Some(Expression::Subquery(Box::new(Subquery {
7403 this: expr.clone(),
7404 alias: Some(alias),
7405 column_aliases,
7406 alias_explicit_as: true,
7407 alias_keyword: None,
7408 order_by: None,
7409 limit: None,
7410 offset: None,
7411 distribute_by: None,
7412 sort_by: None,
7413 cluster_by: None,
7414 lateral: false,
7415 modifiers_inside: false,
7416 trailing_comments: Vec::new(),
7417 inferred_type: None,
7418 })))
7419 }
7420 _ => None,
7421 }
7422 }
7423
7424 fn collect_generated_alias_conflicts(expr: &Expression, names: &mut HashSet<String>) {
7425 fn insert(names: &mut HashSet<String>, identifier: &Identifier) {
7426 if !identifier.name.is_empty() {
7427 names.insert(identifier.name.to_ascii_lowercase());
7428 }
7429 }
7430
7431 for node in expr.dfs() {
7432 match node {
7433 Expression::Identifier(identifier) => insert(names, identifier),
7434 Expression::Column(column) => {
7435 insert(names, &column.name);
7436 if let Some(table) = &column.table {
7437 insert(names, table);
7438 }
7439 }
7440 Expression::Table(table) => {
7441 insert(names, &table.name);
7442 if let Some(schema) = &table.schema {
7443 insert(names, schema);
7444 }
7445 if let Some(catalog) = &table.catalog {
7446 insert(names, catalog);
7447 }
7448 if let Some(alias) = &table.alias {
7449 insert(names, alias);
7450 }
7451 for alias in &table.column_aliases {
7452 insert(names, alias);
7453 }
7454 }
7455 Expression::Alias(alias) => {
7456 insert(names, &alias.alias);
7457 for column_alias in &alias.column_aliases {
7458 insert(names, column_alias);
7459 }
7460 }
7461 Expression::Subquery(subquery) => {
7462 if let Some(alias) = &subquery.alias {
7463 insert(names, alias);
7464 }
7465 for column_alias in &subquery.column_aliases {
7466 insert(names, column_alias);
7467 }
7468 }
7469 Expression::Cte(cte) => {
7470 insert(names, &cte.alias);
7471 for column in &cte.columns {
7472 insert(names, column);
7473 }
7474 for key in &cte.key_expressions {
7475 insert(names, key);
7476 }
7477 }
7478 Expression::Values(values) => {
7479 if let Some(alias) = &values.alias {
7480 insert(names, alias);
7481 }
7482 for column_alias in &values.column_aliases {
7483 insert(names, column_alias);
7484 }
7485 }
7486 Expression::Unnest(unnest) => {
7487 if let Some(alias) = &unnest.alias {
7488 insert(names, alias);
7489 }
7490 if let Some(offset_alias) = &unnest.offset_alias {
7491 insert(names, offset_alias);
7492 }
7493 }
7494 _ => {}
7495 }
7496 }
7497 }
7498
7499 fn rewrite_postgres_format_for_tsql(
7500 expr: Expression,
7501 target: DialectType,
7502 ) -> Result<Expression> {
7503 transform_recursive(expr, &|e| match e {
7504 Expression::Function(f) if f.name.eq_ignore_ascii_case("FORMAT") => {
7505 Self::postgres_format_function_to_tsql(*f, target)
7506 }
7507 other => Ok(other),
7508 })
7509 }
7510
7511 fn postgres_format_function_to_tsql(f: Function, target: DialectType) -> Result<Expression> {
7512 let Some(format_expr) = f.args.first() else {
7513 return Err(Self::unsupported_postgres_format_for_tsql(
7514 target,
7515 "missing format string",
7516 ));
7517 };
7518
7519 let format = match format_expr {
7520 Expression::Literal(lit) if lit.is_string() => lit.value_str(),
7521 _ => {
7522 return Err(Self::unsupported_postgres_format_for_tsql(
7523 target,
7524 "dynamic format strings",
7525 ))
7526 }
7527 };
7528
7529 let value_args = &f.args[1..];
7530 let mut arg_index = 0usize;
7531 let mut literal = String::new();
7532 let mut segments = Vec::new();
7533 let mut chars = format.chars();
7534
7535 while let Some(ch) = chars.next() {
7536 if ch != '%' {
7537 literal.push(ch);
7538 continue;
7539 }
7540
7541 let Some(specifier) = chars.next() else {
7542 return Err(Self::unsupported_postgres_format_for_tsql(
7543 target,
7544 "unterminated format specifier",
7545 ));
7546 };
7547
7548 match specifier {
7549 '%' => literal.push('%'),
7550 's' => {
7551 if !literal.is_empty() {
7552 segments.push(Expression::string(std::mem::take(&mut literal)));
7553 }
7554 let Some(arg) = value_args.get(arg_index) else {
7555 return Err(Self::unsupported_postgres_format_for_tsql(
7556 target,
7557 "not enough arguments",
7558 ));
7559 };
7560 segments.push(arg.clone());
7561 arg_index += 1;
7562 }
7563 other => {
7564 return Err(Self::unsupported_postgres_format_for_tsql(
7565 target,
7566 format!("unsupported format specifier %{other}"),
7567 ))
7568 }
7569 }
7570 }
7571
7572 if !literal.is_empty() {
7573 segments.push(Expression::string(literal));
7574 }
7575
7576 if arg_index != value_args.len() {
7577 return Err(Self::unsupported_postgres_format_for_tsql(
7578 target,
7579 "unused format arguments",
7580 ));
7581 }
7582
7583 Ok(Self::postgres_format_segments_to_tsql_concat(segments))
7584 }
7585
7586 fn postgres_format_segments_to_tsql_concat(mut segments: Vec<Expression>) -> Expression {
7587 if segments.is_empty() {
7588 return Expression::string("");
7589 }
7590
7591 if segments.len() == 1 {
7592 let only = segments.pop().expect("one segment");
7593 if matches!(&only, Expression::Literal(lit) if lit.is_string()) {
7594 return only;
7595 }
7596
7597 return Expression::Function(Box::new(Function::new(
7598 "CONCAT".to_string(),
7599 vec![only, Expression::string("")],
7600 )));
7601 }
7602
7603 Expression::Function(Box::new(Function::new("CONCAT".to_string(), segments)))
7604 }
7605
7606 fn unsupported_postgres_format_for_tsql(
7607 target: DialectType,
7608 reason: impl Into<String>,
7609 ) -> crate::error::Error {
7610 crate::error::Error::unsupported(
7611 format!("PostgreSQL format() ({})", reason.into()),
7612 target.to_string(),
7613 )
7614 }
7615
7616 fn rewrite_boolean_values_in_tsql_select(
7617 mut select: Box<crate::expressions::Select>,
7618 ) -> Result<Expression> {
7619 if let Some(mut with) = select.with.take() {
7620 with.ctes = with
7621 .ctes
7622 .into_iter()
7623 .map(|mut cte| {
7624 cte.this = Self::rewrite_boolean_values_for_tsql(cte.this)?;
7625 Ok(cte)
7626 })
7627 .collect::<Result<Vec<_>>>()?;
7628 select.with = Some(with);
7629 }
7630
7631 select.expressions = select
7632 .expressions
7633 .into_iter()
7634 .map(Self::rewrite_tsql_boolean_scalar_value)
7635 .collect::<Result<Vec<_>>>()?;
7636
7637 if let Some(mut from) = select.from.take() {
7638 from.expressions = from
7639 .expressions
7640 .into_iter()
7641 .map(Self::rewrite_tsql_boolean_nested_contexts)
7642 .collect::<Result<Vec<_>>>()?;
7643 select.from = Some(from);
7644 }
7645
7646 select.joins = select
7647 .joins
7648 .into_iter()
7649 .map(|mut join| {
7650 join.this = Self::rewrite_tsql_boolean_nested_contexts(join.this)?;
7651 if let Some(on) = join.on.take() {
7652 join.on = Some(Self::rewrite_tsql_boolean_predicate_context(on)?);
7653 }
7654 if let Some(match_condition) = join.match_condition.take() {
7655 join.match_condition = Some(Self::rewrite_tsql_boolean_predicate_context(
7656 match_condition,
7657 )?);
7658 }
7659 join.pivots = join
7660 .pivots
7661 .into_iter()
7662 .map(Self::rewrite_tsql_boolean_nested_contexts)
7663 .collect::<Result<Vec<_>>>()?;
7664 Ok(join)
7665 })
7666 .collect::<Result<Vec<_>>>()?;
7667
7668 select.lateral_views = select
7669 .lateral_views
7670 .into_iter()
7671 .map(|mut lateral_view| {
7672 lateral_view.this = Self::rewrite_tsql_boolean_nested_contexts(lateral_view.this)?;
7673 Ok(lateral_view)
7674 })
7675 .collect::<Result<Vec<_>>>()?;
7676
7677 if let Some(prewhere) = select.prewhere.take() {
7678 select.prewhere = Some(Self::rewrite_tsql_boolean_predicate_context(prewhere)?);
7679 }
7680
7681 if let Some(mut where_clause) = select.where_clause.take() {
7682 where_clause.this = Self::rewrite_tsql_boolean_predicate_context(where_clause.this)?;
7683 select.where_clause = Some(where_clause);
7684 }
7685
7686 if let Some(mut group_by) = select.group_by.take() {
7687 group_by.expressions = group_by
7688 .expressions
7689 .into_iter()
7690 .map(Self::rewrite_tsql_boolean_scalar_value)
7691 .collect::<Result<Vec<_>>>()?;
7692 select.group_by = Some(group_by);
7693 }
7694
7695 if let Some(mut having) = select.having.take() {
7696 having.this = Self::rewrite_tsql_boolean_predicate_context(having.this)?;
7697 select.having = Some(having);
7698 }
7699
7700 if let Some(mut qualify) = select.qualify.take() {
7701 qualify.this = Self::rewrite_tsql_boolean_predicate_context(qualify.this)?;
7702 select.qualify = Some(qualify);
7703 }
7704
7705 if let Some(mut order_by) = select.order_by.take() {
7706 order_by.expressions = Self::rewrite_tsql_boolean_ordered_values(order_by.expressions)?;
7707 select.order_by = Some(order_by);
7708 }
7709
7710 if let Some(mut distribute_by) = select.distribute_by.take() {
7711 distribute_by.expressions = distribute_by
7712 .expressions
7713 .into_iter()
7714 .map(Self::rewrite_tsql_boolean_scalar_value)
7715 .collect::<Result<Vec<_>>>()?;
7716 select.distribute_by = Some(distribute_by);
7717 }
7718
7719 if let Some(mut cluster_by) = select.cluster_by.take() {
7720 cluster_by.expressions =
7721 Self::rewrite_tsql_boolean_ordered_values(cluster_by.expressions)?;
7722 select.cluster_by = Some(cluster_by);
7723 }
7724
7725 if let Some(mut sort_by) = select.sort_by.take() {
7726 sort_by.expressions = Self::rewrite_tsql_boolean_ordered_values(sort_by.expressions)?;
7727 select.sort_by = Some(sort_by);
7728 }
7729
7730 if let Some(limit_by) = select.limit_by.take() {
7731 select.limit_by = Some(
7732 limit_by
7733 .into_iter()
7734 .map(Self::rewrite_tsql_boolean_scalar_value)
7735 .collect::<Result<Vec<_>>>()?,
7736 );
7737 }
7738
7739 if let Some(distinct_on) = select.distinct_on.take() {
7740 select.distinct_on = Some(
7741 distinct_on
7742 .into_iter()
7743 .map(Self::rewrite_tsql_boolean_scalar_value)
7744 .collect::<Result<Vec<_>>>()?,
7745 );
7746 }
7747
7748 if let Some(mut sample) = select.sample.take() {
7749 sample.size = Self::rewrite_tsql_boolean_nested_contexts(sample.size)?;
7750 if let Some(offset) = sample.offset.take() {
7751 sample.offset = Some(Self::rewrite_tsql_boolean_nested_contexts(offset)?);
7752 }
7753 if let Some(bucket_numerator) = sample.bucket_numerator.take() {
7754 sample.bucket_numerator = Some(Box::new(
7755 Self::rewrite_tsql_boolean_nested_contexts(*bucket_numerator)?,
7756 ));
7757 }
7758 if let Some(bucket_denominator) = sample.bucket_denominator.take() {
7759 sample.bucket_denominator = Some(Box::new(
7760 Self::rewrite_tsql_boolean_nested_contexts(*bucket_denominator)?,
7761 ));
7762 }
7763 if let Some(bucket_field) = sample.bucket_field.take() {
7764 sample.bucket_field = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7765 *bucket_field,
7766 )?));
7767 }
7768 select.sample = Some(sample);
7769 }
7770
7771 if let Some(settings) = select.settings.take() {
7772 select.settings = Some(
7773 settings
7774 .into_iter()
7775 .map(Self::rewrite_tsql_boolean_nested_contexts)
7776 .collect::<Result<Vec<_>>>()?,
7777 );
7778 }
7779
7780 if let Some(format) = select.format.take() {
7781 select.format = Some(Self::rewrite_tsql_boolean_nested_contexts(format)?);
7782 }
7783
7784 if let Some(mut windows) = select.windows.take() {
7785 for window in windows.iter_mut() {
7786 Self::rewrite_tsql_boolean_over_values(&mut window.spec)?;
7787 }
7788 select.windows = Some(windows);
7789 }
7790
7791 Ok(Expression::Select(select))
7792 }
7793
7794 fn normalize_postgres_boolean_semantics_for_tsql(expr: Expression) -> Result<Expression> {
7795 transform_recursive(expr, &|e| match e {
7796 Expression::Function(function)
7797 if function.args.len() == 2
7798 && (function.name.eq_ignore_ascii_case("BOOLEQ")
7799 || function.name.eq_ignore_ascii_case("BOOLNE")) =>
7800 {
7801 let is_equal = function.name.eq_ignore_ascii_case("BOOLEQ");
7802 let mut args = function.args.into_iter();
7803 let op = BinaryOp {
7804 left: args.next().expect("checked boolean operator arity"),
7805 right: args.next().expect("checked boolean operator arity"),
7806 left_comments: Vec::new(),
7807 operator_comments: Vec::new(),
7808 trailing_comments: function.trailing_comments,
7809 inferred_type: None,
7810 };
7811 if is_equal {
7812 Ok(Expression::Eq(Box::new(op)))
7813 } else {
7814 Ok(Expression::Neq(Box::new(op)))
7815 }
7816 }
7817 Expression::Cast(cast)
7818 if matches!(cast.to, DataType::Text)
7819 && Self::is_known_postgres_boolean_expression(&cast.this) =>
7820 {
7821 Ok(Self::postgres_boolean_text_value(cast.this))
7822 }
7823 other => Ok(other),
7824 })
7825 }
7826
7827 fn is_known_postgres_boolean_expression(expr: &Expression) -> bool {
7828 match expr {
7829 Expression::Boolean(_) => true,
7830 Expression::Cast(cast) => matches!(cast.to, DataType::Boolean),
7831 Expression::Paren(paren) => Self::is_known_postgres_boolean_expression(&paren.this),
7832 other => Self::is_tsql_boolean_value_expression(other),
7833 }
7834 }
7835
7836 fn postgres_boolean_text_value(predicate: Expression) -> Expression {
7837 if let Expression::Boolean(boolean) = predicate {
7838 return Expression::string(if boolean.value { "true" } else { "false" });
7839 }
7840
7841 Self::three_valued_boolean_case(
7842 predicate,
7843 Expression::string("true"),
7844 Expression::string("false"),
7845 )
7846 }
7847
7848 fn rewrite_tsql_boolean_scalar_value(expr: Expression) -> Result<Expression> {
7849 if let Expression::Boolean(boolean) = expr {
7850 return Ok(Expression::Cast(Box::new(Cast {
7851 this: Expression::Boolean(boolean),
7852 to: DataType::Boolean,
7853 trailing_comments: Vec::new(),
7854 double_colon_syntax: false,
7855 format: None,
7856 default: None,
7857 inferred_type: None,
7858 })));
7859 }
7860
7861 if Self::is_tsql_boolean_value_expression(&expr) {
7862 let can_be_unknown = Self::tsql_boolean_expression_can_be_unknown(&expr)
7865 && !Self::node_is_row_value_subquery_comparison(&expr);
7866 let predicate = Self::rewrite_tsql_boolean_predicate_context(expr)?;
7867 return Ok(Self::tsql_boolean_value_case(predicate, can_be_unknown));
7868 }
7869
7870 match expr {
7871 Expression::Alias(mut alias) => {
7872 alias.this = Self::rewrite_tsql_boolean_scalar_value(alias.this)?;
7873 Ok(Expression::Alias(alias))
7874 }
7875 Expression::Paren(mut paren) => {
7876 paren.this = Self::rewrite_tsql_boolean_scalar_value(paren.this)?;
7877 Ok(Expression::Paren(paren))
7878 }
7879 Expression::Cast(mut cast) => {
7880 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
7881 if let Some(format) = cast.format.take() {
7882 cast.format = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7883 *format,
7884 )?));
7885 }
7886 if let Some(default) = cast.default.take() {
7887 cast.default =
7888 Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*default)?));
7889 }
7890 Ok(Expression::Cast(cast))
7891 }
7892 Expression::TryCast(mut cast) => {
7893 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
7894 if let Some(format) = cast.format.take() {
7895 cast.format = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7896 *format,
7897 )?));
7898 }
7899 if let Some(default) = cast.default.take() {
7900 cast.default =
7901 Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*default)?));
7902 }
7903 Ok(Expression::TryCast(cast))
7904 }
7905 Expression::SafeCast(mut cast) => {
7906 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
7907 if let Some(format) = cast.format.take() {
7908 cast.format = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7909 *format,
7910 )?));
7911 }
7912 if let Some(default) = cast.default.take() {
7913 cast.default =
7914 Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*default)?));
7915 }
7916 Ok(Expression::SafeCast(cast))
7917 }
7918 Expression::Case(mut case) => {
7919 let is_simple_case = case.operand.is_some();
7920 if let Some(operand) = case.operand.take() {
7921 case.operand = Some(Self::rewrite_tsql_boolean_scalar_value(operand)?);
7922 }
7923 case.whens = case
7924 .whens
7925 .into_iter()
7926 .map(|(condition, result)| {
7927 let condition = if is_simple_case {
7928 Self::rewrite_tsql_boolean_scalar_value(condition)?
7929 } else {
7930 Self::rewrite_tsql_boolean_predicate_context(condition)?
7931 };
7932 Ok((condition, Self::rewrite_tsql_boolean_scalar_value(result)?))
7933 })
7934 .collect::<Result<Vec<_>>>()?;
7935 if let Some(else_) = case.else_.take() {
7936 case.else_ = Some(Self::rewrite_tsql_boolean_scalar_value(else_)?);
7937 }
7938 Ok(Expression::Case(case))
7939 }
7940 Expression::IfFunc(mut if_func) => {
7941 if_func.condition =
7942 Self::rewrite_tsql_boolean_predicate_context(if_func.condition)?;
7943 if_func.true_value = Self::rewrite_tsql_boolean_scalar_value(if_func.true_value)?;
7944 if let Some(false_value) = if_func.false_value.take() {
7945 if_func.false_value =
7946 Some(Self::rewrite_tsql_boolean_scalar_value(false_value)?);
7947 }
7948 Ok(Expression::IfFunc(if_func))
7949 }
7950 Expression::WindowFunction(mut window_function) => {
7951 window_function.this =
7952 Self::rewrite_tsql_boolean_nested_contexts(window_function.this)?;
7953 Self::rewrite_tsql_boolean_over_values(&mut window_function.over)?;
7954 if let Some(mut keep) = window_function.keep.take() {
7955 keep.order_by = Self::rewrite_tsql_boolean_ordered_values(keep.order_by)?;
7956 window_function.keep = Some(keep);
7957 }
7958 Ok(Expression::WindowFunction(window_function))
7959 }
7960 Expression::WithinGroup(mut within_group) => {
7961 within_group.this = Self::rewrite_tsql_boolean_nested_contexts(within_group.this)?;
7962 within_group.order_by =
7963 Self::rewrite_tsql_boolean_ordered_values(within_group.order_by)?;
7964 Ok(Expression::WithinGroup(within_group))
7965 }
7966 Expression::Subquery(mut subquery) => {
7967 subquery.this = Self::rewrite_boolean_values_for_tsql(subquery.this)?;
7968 Ok(Expression::Subquery(subquery))
7969 }
7970 Expression::Select(select) => Self::rewrite_boolean_values_in_tsql_select(select),
7971 other => Self::rewrite_tsql_boolean_nested_contexts(other),
7972 }
7973 }
7974
7975 fn rewrite_tsql_boolean_predicate_context(expr: Expression) -> Result<Expression> {
7976 let expr = Self::rewrite_tsql_boolean_nested_contexts(expr)?;
7977 Ok(crate::transforms::ensure_bool_condition(expr))
7978 }
7979
7980 fn rewrite_tsql_boolean_nested_contexts(expr: Expression) -> Result<Expression> {
7981 transform_recursive(expr, &|e| match e {
7982 Expression::Select(select) => Self::rewrite_boolean_values_in_tsql_select(select),
7983 Expression::Subquery(mut subquery) => {
7984 subquery.this = Self::rewrite_boolean_values_for_tsql(subquery.this)?;
7985 Ok(Expression::Subquery(subquery))
7986 }
7987 Expression::Union(_) | Expression::Intersect(_) | Expression::Except(_) => {
7988 Self::rewrite_boolean_values_for_tsql(e)
7989 }
7990 other => Self::rewrite_tsql_boolean_cast_operand(other),
7991 })
7992 }
7993
7994 fn rewrite_tsql_boolean_cast_operand(expr: Expression) -> Result<Expression> {
7995 macro_rules! rewrite_cast_operand {
7996 ($variant:ident, $cast:expr) => {{
7997 let mut cast = $cast;
7998 if Self::is_tsql_boolean_value_expression(&cast.this) {
7999 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
8000 }
8001 Ok(Expression::$variant(cast))
8002 }};
8003 }
8004
8005 match expr {
8006 Expression::Cast(cast) => rewrite_cast_operand!(Cast, cast),
8007 Expression::TryCast(cast) => rewrite_cast_operand!(TryCast, cast),
8008 Expression::SafeCast(cast) => rewrite_cast_operand!(SafeCast, cast),
8009 other => Ok(other),
8010 }
8011 }
8012
8013 fn rewrite_tsql_boolean_ordered_values(
8014 ordered: Vec<crate::expressions::Ordered>,
8015 ) -> Result<Vec<crate::expressions::Ordered>> {
8016 ordered
8017 .into_iter()
8018 .map(|mut ordered| {
8019 ordered.this = Self::rewrite_tsql_boolean_scalar_value(ordered.this)?;
8020 if let Some(with_fill) = ordered.with_fill.take() {
8021 ordered.with_fill = Some(Box::new(
8022 Self::rewrite_tsql_boolean_with_fill_values(*with_fill)?,
8023 ));
8024 }
8025 Ok(ordered)
8026 })
8027 .collect()
8028 }
8029
8030 fn rewrite_tsql_boolean_with_fill_values(
8031 mut with_fill: crate::expressions::WithFill,
8032 ) -> Result<crate::expressions::WithFill> {
8033 if let Some(from) = with_fill.from_.take() {
8034 with_fill.from_ = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*from)?));
8035 }
8036 if let Some(to) = with_fill.to.take() {
8037 with_fill.to = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*to)?));
8038 }
8039 if let Some(step) = with_fill.step.take() {
8040 with_fill.step = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*step)?));
8041 }
8042 if let Some(staleness) = with_fill.staleness.take() {
8043 with_fill.staleness = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(
8044 *staleness,
8045 )?));
8046 }
8047 if let Some(interpolate) = with_fill.interpolate.take() {
8048 with_fill.interpolate = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(
8049 *interpolate,
8050 )?));
8051 }
8052 Ok(with_fill)
8053 }
8054
8055 fn rewrite_tsql_boolean_over_values(over: &mut crate::expressions::Over) -> Result<()> {
8056 over.partition_by = std::mem::take(&mut over.partition_by)
8057 .into_iter()
8058 .map(Self::rewrite_tsql_boolean_scalar_value)
8059 .collect::<Result<Vec<_>>>()?;
8060 over.order_by =
8061 Self::rewrite_tsql_boolean_ordered_values(std::mem::take(&mut over.order_by))?;
8062 Ok(())
8063 }
8064
8065 fn is_tsql_boolean_value_expression(expr: &Expression) -> bool {
8066 match expr {
8067 Expression::Paren(paren) => Self::is_tsql_boolean_value_expression(&paren.this),
8068 Expression::Eq(_)
8069 | Expression::Neq(_)
8070 | Expression::Lt(_)
8071 | Expression::Lte(_)
8072 | Expression::Gt(_)
8073 | Expression::Gte(_)
8074 | Expression::Is(_)
8075 | Expression::IsNull(_)
8076 | Expression::IsTrue(_)
8077 | Expression::IsFalse(_)
8078 | Expression::Like(_)
8079 | Expression::ILike(_)
8080 | Expression::StartsWith(_)
8081 | Expression::SimilarTo(_)
8082 | Expression::Glob(_)
8083 | Expression::RegexpLike(_)
8084 | Expression::In(_)
8085 | Expression::Between(_)
8086 | Expression::Exists(_)
8087 | Expression::And(_)
8088 | Expression::Or(_)
8089 | Expression::Not(_)
8090 | Expression::Any(_)
8091 | Expression::All(_)
8092 | Expression::NullSafeEq(_)
8093 | Expression::NullSafeNeq(_)
8094 | Expression::EqualNull(_) => true,
8095 _ => false,
8096 }
8097 }
8098
8099 fn tsql_boolean_expression_can_be_unknown(expr: &Expression) -> bool {
8100 match expr {
8101 Expression::Boolean(_)
8102 | Expression::IsNull(_)
8103 | Expression::IsTrue(_)
8104 | Expression::IsFalse(_)
8105 | Expression::Exists(_)
8106 | Expression::NullSafeEq(_)
8107 | Expression::NullSafeNeq(_)
8108 | Expression::EqualNull(_) => false,
8109 Expression::Paren(paren) => Self::tsql_boolean_expression_can_be_unknown(&paren.this),
8110 Expression::Not(op) => Self::tsql_boolean_expression_can_be_unknown(&op.this),
8111 Expression::And(op) | Expression::Or(op) => {
8112 Self::tsql_boolean_expression_can_be_unknown(&op.left)
8113 || Self::tsql_boolean_expression_can_be_unknown(&op.right)
8114 }
8115 _ => true,
8116 }
8117 }
8118
8119 fn tsql_boolean_value_case(predicate: Expression, can_be_unknown: bool) -> Expression {
8120 let case = if can_be_unknown {
8121 Self::three_valued_boolean_case(predicate, Expression::number(1), Expression::number(0))
8122 } else {
8123 Expression::Case(Box::new(crate::expressions::Case {
8124 operand: None,
8125 whens: vec![(predicate, Expression::number(1))],
8126 else_: Some(Expression::number(0)),
8127 comments: Vec::new(),
8128 inferred_type: None,
8129 }))
8130 };
8131
8132 Expression::Cast(Box::new(Cast {
8133 this: case,
8134 to: DataType::Boolean,
8135 trailing_comments: Vec::new(),
8136 double_colon_syntax: false,
8137 format: None,
8138 default: None,
8139 inferred_type: None,
8140 }))
8141 }
8142
8143 fn three_valued_boolean_case(
8144 predicate: Expression,
8145 true_value: Expression,
8146 false_value: Expression,
8147 ) -> Expression {
8148 let false_operand = if matches!(predicate, Expression::And(_) | Expression::Or(_)) {
8149 Expression::Paren(Box::new(crate::expressions::Paren {
8150 this: predicate.clone(),
8151 trailing_comments: Vec::new(),
8152 }))
8153 } else {
8154 predicate.clone()
8155 };
8156 let false_predicate = Expression::Not(Box::new(crate::expressions::UnaryOp {
8157 this: false_operand,
8158 inferred_type: None,
8159 }));
8160
8161 Expression::Case(Box::new(crate::expressions::Case {
8162 operand: None,
8163 whens: vec![(predicate, true_value), (false_predicate, false_value)],
8164 else_: Some(Expression::null()),
8165 comments: Vec::new(),
8166 inferred_type: None,
8167 }))
8168 }
8169
8170 fn rewrite_aggregate_filters_for_tsql(expr: Expression) -> Result<Expression> {
8171 transform_recursive(expr, &|e| Self::rewrite_aggregate_filter_for_tsql(e))
8172 }
8173
8174 fn rewrite_aggregate_filter_for_tsql(expr: Expression) -> Result<Expression> {
8175 macro_rules! rewrite_agg_filter {
8176 ($variant:ident, $agg:expr) => {{
8177 let mut agg = $agg;
8178 if let Some(filter) = agg.filter.take() {
8179 let this = std::mem::replace(&mut agg.this, Expression::null());
8180 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8181 }
8182 Ok(Expression::$variant(agg))
8183 }};
8184 }
8185
8186 match expr {
8187 Expression::Filter(filter) => {
8188 let condition = match *filter.expression {
8189 Expression::Where(where_) => where_.this,
8190 other => other,
8191 };
8192 Ok(Self::push_filter_into_tsql_aggregate(
8193 *filter.this,
8194 condition,
8195 ))
8196 }
8197 Expression::AggregateFunction(mut agg) => {
8198 if let Some(filter) = agg.filter.take() {
8199 Self::rewrite_generic_aggregate_filter_for_tsql(&mut agg, filter);
8200 }
8201 Ok(Expression::AggregateFunction(agg))
8202 }
8203 Expression::Count(mut count) => {
8204 if let Some(filter) = count.filter.take() {
8205 let value = if count.star {
8206 Expression::number(1)
8207 } else {
8208 count.this.take().unwrap_or_else(|| Expression::number(1))
8209 };
8210 count.star = false;
8211 count.this = Some(Self::conditional_aggregate_value_for_tsql(filter, value));
8212 }
8213 Ok(Expression::Count(count))
8214 }
8215 Expression::Sum(agg) => rewrite_agg_filter!(Sum, agg),
8216 Expression::Avg(agg) => rewrite_agg_filter!(Avg, agg),
8217 Expression::Min(agg) => rewrite_agg_filter!(Min, agg),
8218 Expression::Max(agg) => rewrite_agg_filter!(Max, agg),
8219 Expression::ArrayAgg(agg) => rewrite_agg_filter!(ArrayAgg, agg),
8220 Expression::CountIf(agg) => Ok(Expression::CountIf(agg)),
8221 Expression::Stddev(agg) => rewrite_agg_filter!(Stddev, agg),
8222 Expression::StddevPop(agg) => rewrite_agg_filter!(StddevPop, agg),
8223 Expression::StddevSamp(agg) => rewrite_agg_filter!(StddevSamp, agg),
8224 Expression::Variance(agg) => rewrite_agg_filter!(Variance, agg),
8225 Expression::VarPop(agg) => rewrite_agg_filter!(VarPop, agg),
8226 Expression::VarSamp(agg) => rewrite_agg_filter!(VarSamp, agg),
8227 Expression::Median(agg) => rewrite_agg_filter!(Median, agg),
8228 Expression::Mode(agg) => rewrite_agg_filter!(Mode, agg),
8229 Expression::First(agg) => rewrite_agg_filter!(First, agg),
8230 Expression::Last(agg) => rewrite_agg_filter!(Last, agg),
8231 Expression::AnyValue(agg) => rewrite_agg_filter!(AnyValue, agg),
8232 Expression::ApproxDistinct(agg) => rewrite_agg_filter!(ApproxDistinct, agg),
8233 Expression::ApproxCountDistinct(agg) => {
8234 rewrite_agg_filter!(ApproxCountDistinct, agg)
8235 }
8236 Expression::LogicalAnd(agg) => rewrite_agg_filter!(LogicalAnd, agg),
8237 Expression::LogicalOr(agg) => rewrite_agg_filter!(LogicalOr, agg),
8238 Expression::Skewness(agg) => rewrite_agg_filter!(Skewness, agg),
8239 Expression::ArrayConcatAgg(agg) => rewrite_agg_filter!(ArrayConcatAgg, agg),
8240 Expression::ArrayUniqueAgg(agg) => rewrite_agg_filter!(ArrayUniqueAgg, agg),
8241 Expression::BoolXorAgg(agg) => rewrite_agg_filter!(BoolXorAgg, agg),
8242 Expression::BitwiseAndAgg(agg) => rewrite_agg_filter!(BitwiseAndAgg, agg),
8243 Expression::BitwiseOrAgg(agg) => rewrite_agg_filter!(BitwiseOrAgg, agg),
8244 Expression::BitwiseXorAgg(agg) => rewrite_agg_filter!(BitwiseXorAgg, agg),
8245 Expression::StringAgg(mut agg) => {
8246 if let Some(filter) = agg.filter.take() {
8247 let this = std::mem::replace(&mut agg.this, Expression::null());
8248 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8249 }
8250 Ok(Expression::StringAgg(agg))
8251 }
8252 Expression::GroupConcat(mut agg) => {
8253 if let Some(filter) = agg.filter.take() {
8254 let this = std::mem::replace(&mut agg.this, Expression::null());
8255 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8256 }
8257 Ok(Expression::GroupConcat(agg))
8258 }
8259 Expression::ListAgg(mut agg) => {
8260 if let Some(filter) = agg.filter.take() {
8261 let this = std::mem::replace(&mut agg.this, Expression::null());
8262 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8263 }
8264 Ok(Expression::ListAgg(agg))
8265 }
8266 Expression::WithinGroup(mut within_group) => {
8267 within_group.this = Self::rewrite_aggregate_filters_for_tsql(within_group.this)?;
8268 Ok(Expression::WithinGroup(within_group))
8269 }
8270 other => Ok(other),
8271 }
8272 }
8273
8274 fn push_filter_into_tsql_aggregate(expr: Expression, filter: Expression) -> Expression {
8275 macro_rules! push_agg_filter {
8276 ($variant:ident, $agg:expr) => {{
8277 let mut agg = $agg;
8278 let this = std::mem::replace(&mut agg.this, Expression::null());
8279 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8280 agg.filter = None;
8281 Expression::$variant(agg)
8282 }};
8283 }
8284
8285 match expr {
8286 Expression::AggregateFunction(mut agg) => {
8287 Self::rewrite_generic_aggregate_filter_for_tsql(&mut agg, filter);
8288 Expression::AggregateFunction(agg)
8289 }
8290 Expression::Count(mut count) => {
8291 let value = if count.star {
8292 Expression::number(1)
8293 } else {
8294 count.this.take().unwrap_or_else(|| Expression::number(1))
8295 };
8296 count.star = false;
8297 count.filter = None;
8298 count.this = Some(Self::conditional_aggregate_value_for_tsql(filter, value));
8299 Expression::Count(count)
8300 }
8301 Expression::Sum(agg) => push_agg_filter!(Sum, agg),
8302 Expression::Avg(agg) => push_agg_filter!(Avg, agg),
8303 Expression::Min(agg) => push_agg_filter!(Min, agg),
8304 Expression::Max(agg) => push_agg_filter!(Max, agg),
8305 Expression::ArrayAgg(agg) => push_agg_filter!(ArrayAgg, agg),
8306 Expression::CountIf(mut agg) => {
8307 agg.filter = Some(filter);
8308 Expression::CountIf(agg)
8309 }
8310 Expression::Stddev(agg) => push_agg_filter!(Stddev, agg),
8311 Expression::StddevPop(agg) => push_agg_filter!(StddevPop, agg),
8312 Expression::StddevSamp(agg) => push_agg_filter!(StddevSamp, agg),
8313 Expression::Variance(agg) => push_agg_filter!(Variance, agg),
8314 Expression::VarPop(agg) => push_agg_filter!(VarPop, agg),
8315 Expression::VarSamp(agg) => push_agg_filter!(VarSamp, agg),
8316 Expression::Median(agg) => push_agg_filter!(Median, agg),
8317 Expression::Mode(agg) => push_agg_filter!(Mode, agg),
8318 Expression::First(agg) => push_agg_filter!(First, agg),
8319 Expression::Last(agg) => push_agg_filter!(Last, agg),
8320 Expression::AnyValue(agg) => push_agg_filter!(AnyValue, agg),
8321 Expression::ApproxDistinct(agg) => push_agg_filter!(ApproxDistinct, agg),
8322 Expression::ApproxCountDistinct(agg) => {
8323 push_agg_filter!(ApproxCountDistinct, agg)
8324 }
8325 Expression::LogicalAnd(agg) => push_agg_filter!(LogicalAnd, agg),
8326 Expression::LogicalOr(agg) => push_agg_filter!(LogicalOr, agg),
8327 Expression::Skewness(agg) => push_agg_filter!(Skewness, agg),
8328 Expression::ArrayConcatAgg(agg) => push_agg_filter!(ArrayConcatAgg, agg),
8329 Expression::ArrayUniqueAgg(agg) => push_agg_filter!(ArrayUniqueAgg, agg),
8330 Expression::BoolXorAgg(agg) => push_agg_filter!(BoolXorAgg, agg),
8331 Expression::BitwiseAndAgg(agg) => push_agg_filter!(BitwiseAndAgg, agg),
8332 Expression::BitwiseOrAgg(agg) => push_agg_filter!(BitwiseOrAgg, agg),
8333 Expression::BitwiseXorAgg(agg) => push_agg_filter!(BitwiseXorAgg, agg),
8334 Expression::StringAgg(mut agg) => {
8335 let this = std::mem::replace(&mut agg.this, Expression::null());
8336 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8337 agg.filter = None;
8338 Expression::StringAgg(agg)
8339 }
8340 Expression::GroupConcat(mut agg) => {
8341 let this = std::mem::replace(&mut agg.this, Expression::null());
8342 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8343 agg.filter = None;
8344 Expression::GroupConcat(agg)
8345 }
8346 Expression::ListAgg(mut agg) => {
8347 let this = std::mem::replace(&mut agg.this, Expression::null());
8348 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8349 agg.filter = None;
8350 Expression::ListAgg(agg)
8351 }
8352 Expression::WithinGroup(mut within_group) => {
8353 within_group.this =
8354 Self::push_filter_into_tsql_aggregate(within_group.this, filter);
8355 Expression::WithinGroup(within_group)
8356 }
8357 other => Expression::Filter(Box::new(crate::expressions::Filter {
8358 this: Box::new(other),
8359 expression: Box::new(filter),
8360 })),
8361 }
8362 }
8363
8364 fn rewrite_generic_aggregate_filter_for_tsql(
8365 agg: &mut crate::expressions::AggregateFunction,
8366 filter: Expression,
8367 ) {
8368 let is_count =
8369 agg.name.eq_ignore_ascii_case("COUNT") || agg.name.eq_ignore_ascii_case("COUNT_BIG");
8370 let is_count_star = is_count
8371 && (agg.args.is_empty()
8372 || (agg.args.len() == 1 && matches!(agg.args[0], Expression::Star(_))));
8373
8374 if is_count_star {
8375 agg.args = vec![Self::conditional_aggregate_value_for_tsql(
8376 filter,
8377 Expression::number(1),
8378 )];
8379 } else if !agg.args.is_empty() {
8380 agg.args = agg
8381 .args
8382 .drain(..)
8383 .map(|arg| Self::conditional_aggregate_value_for_tsql(filter.clone(), arg))
8384 .collect();
8385 } else {
8386 agg.filter = Some(filter);
8387 }
8388 }
8389
8390 fn conditional_aggregate_value_for_tsql(filter: Expression, value: Expression) -> Expression {
8391 let filter = crate::transforms::ensure_bool_condition(filter);
8392 Expression::Case(Box::new(crate::expressions::Case {
8393 operand: None,
8394 whens: vec![(filter, value)],
8395 else_: None,
8396 comments: Vec::new(),
8397 inferred_type: None,
8398 }))
8399 }
8400
8401 fn reject_pgvector_distance_operators_for_sqlite(&self, sql: &str) -> Result<()> {
8402 let tokens = self.tokenize(sql)?;
8403 for (i, token) in tokens.iter().enumerate() {
8404 if token.token_type == TokenType::NullsafeEq {
8405 return Err(crate::error::Error::unsupported(
8406 "PostgreSQL pgvector cosine distance operator <=>",
8407 "SQLite",
8408 ));
8409 }
8410 if token.token_type == TokenType::Lt
8411 && tokens
8412 .get(i + 1)
8413 .is_some_and(|token| token.token_type == TokenType::Tilde)
8414 && tokens
8415 .get(i + 2)
8416 .is_some_and(|token| token.token_type == TokenType::Gt)
8417 {
8418 return Err(crate::error::Error::unsupported(
8419 "PostgreSQL pgvector Hamming distance operator <~>",
8420 "SQLite",
8421 ));
8422 }
8423 }
8424 Ok(())
8425 }
8426
8427 fn normalize_sqlite_double_quoted_defaults(expr: Expression) -> Result<Expression> {
8428 fn normalize_default_expr(expr: Expression) -> Result<Expression> {
8429 transform_recursive(expr, &|e| match e {
8430 Expression::Column(col)
8431 if col.table.is_none() && col.name.quoted && !col.join_mark =>
8432 {
8433 Ok(Expression::Literal(Box::new(Literal::String(
8434 col.name.name,
8435 ))))
8436 }
8437 Expression::Identifier(id) if id.quoted => {
8438 Ok(Expression::Literal(Box::new(Literal::String(id.name))))
8439 }
8440 _ => Ok(e),
8441 })
8442 }
8443
8444 fn normalize_column_default(col: &mut crate::expressions::ColumnDef) -> Result<()> {
8445 if let Some(default) = col.default.take() {
8446 col.default = Some(normalize_default_expr(default)?);
8447 }
8448
8449 for constraint in &mut col.constraints {
8450 if let ColumnConstraint::Default(default) = constraint {
8451 *default = normalize_default_expr(default.clone())?;
8452 }
8453 }
8454
8455 Ok(())
8456 }
8457
8458 transform_recursive(expr, &|e| match e {
8459 Expression::CreateTable(mut ct) => {
8460 for column in &mut ct.columns {
8461 normalize_column_default(column)?;
8462 }
8463 Ok(Expression::CreateTable(ct))
8464 }
8465 Expression::ColumnDef(mut col) => {
8466 normalize_column_default(&mut col)?;
8467 Ok(Expression::ColumnDef(col))
8468 }
8469 _ => Ok(e),
8470 })
8471 }
8472
8473 fn normalize_postgres_to_sqlite_types(expr: Expression) -> Result<Expression> {
8474 fn sqlite_type(dt: crate::expressions::DataType) -> crate::expressions::DataType {
8475 use crate::expressions::DataType;
8476
8477 match dt {
8478 DataType::Bit { .. } => DataType::Int {
8479 length: None,
8480 integer_spelling: true,
8481 },
8482 DataType::TextWithLength { .. } => DataType::Text,
8483 DataType::VarChar { .. } => DataType::Text,
8484 DataType::Char { .. } => DataType::Text,
8485 DataType::Timestamp { timezone: true, .. } => DataType::Text,
8486 DataType::Custom { name } => {
8487 let base = name
8488 .split_once('(')
8489 .map_or(name.as_str(), |(base, _)| base)
8490 .trim();
8491 if base.eq_ignore_ascii_case("TSVECTOR")
8492 || base.eq_ignore_ascii_case("TIMESTAMPTZ")
8493 || base.eq_ignore_ascii_case("TIMESTAMP WITH TIME ZONE")
8494 || base.eq_ignore_ascii_case("NVARCHAR")
8495 || base.eq_ignore_ascii_case("NCHAR")
8496 {
8497 DataType::Text
8498 } else {
8499 DataType::Custom { name }
8500 }
8501 }
8502 _ => dt,
8503 }
8504 }
8505
8506 transform_recursive(expr, &|e| match e {
8507 Expression::DataType(dt) => Ok(Expression::DataType(sqlite_type(dt))),
8508 Expression::CreateTable(mut ct) => {
8509 for column in &mut ct.columns {
8510 column.data_type = sqlite_type(column.data_type.clone());
8511 }
8512 Ok(Expression::CreateTable(ct))
8513 }
8514 _ => Ok(e),
8515 })
8516 }
8517
8518 fn normalize_postgres_to_fabric_types(expr: Expression) -> Result<Expression> {
8519 fn fabric_type(dt: crate::expressions::DataType) -> crate::expressions::DataType {
8520 use crate::expressions::DataType;
8521
8522 match dt {
8523 DataType::Decimal {
8524 precision: None,
8525 scale: None,
8526 } => DataType::Decimal {
8527 precision: Some(38),
8528 scale: Some(10),
8529 },
8530 DataType::Json | DataType::JsonB => DataType::Custom {
8531 name: "VARCHAR(MAX)".to_string(),
8532 },
8533 _ => dt,
8534 }
8535 }
8536
8537 transform_recursive(expr, &|e| match e {
8538 Expression::DataType(dt) => Ok(Expression::DataType(fabric_type(dt))),
8539 Expression::CreateTable(mut ct) => {
8540 for column in &mut ct.columns {
8541 column.data_type = fabric_type(column.data_type.clone());
8542 }
8543 Ok(Expression::CreateTable(ct))
8544 }
8545 Expression::ColumnDef(mut col) => {
8546 col.data_type = fabric_type(col.data_type);
8547 Ok(Expression::ColumnDef(col))
8548 }
8549 _ => Ok(e),
8550 })
8551 }
8552
8553 fn seq_rownum_to_range(expr: Expression) -> Result<Expression> {
8557 if let Expression::Select(mut select) = expr {
8558 let has_range_from = if let Some(ref from) = select.from {
8560 from.expressions.iter().any(|e| {
8561 match e {
8563 Expression::Function(f) => f.name.eq_ignore_ascii_case("RANGE"),
8564 Expression::Alias(a) => {
8565 matches!(&a.this, Expression::Function(f) if f.name.eq_ignore_ascii_case("RANGE"))
8566 }
8567 _ => false,
8568 }
8569 })
8570 } else {
8571 false
8572 };
8573
8574 if has_range_from {
8575 select.expressions = select
8577 .expressions
8578 .into_iter()
8579 .map(|e| Self::replace_rownum_with_range(e))
8580 .collect();
8581 }
8582
8583 Ok(Expression::Select(select))
8584 } else {
8585 Ok(expr)
8586 }
8587 }
8588
8589 fn replace_rownum_with_range(expr: Expression) -> Expression {
8591 match expr {
8592 Expression::Mod(op) => {
8594 let new_left = Self::try_replace_rownum_paren(&op.left);
8595 Expression::Mod(Box::new(crate::expressions::BinaryOp {
8596 left: new_left,
8597 right: op.right,
8598 left_comments: op.left_comments,
8599 operator_comments: op.operator_comments,
8600 trailing_comments: op.trailing_comments,
8601 inferred_type: op.inferred_type,
8602 }))
8603 }
8604 Expression::Paren(p) => {
8606 let inner = Self::replace_rownum_with_range(p.this);
8607 Expression::Paren(Box::new(crate::expressions::Paren {
8608 this: inner,
8609 trailing_comments: p.trailing_comments,
8610 }))
8611 }
8612 Expression::Case(mut c) => {
8613 c.whens = c
8615 .whens
8616 .into_iter()
8617 .map(|(cond, then)| {
8618 (
8619 Self::replace_rownum_with_range(cond),
8620 Self::replace_rownum_with_range(then),
8621 )
8622 })
8623 .collect();
8624 if let Some(else_) = c.else_ {
8625 c.else_ = Some(Self::replace_rownum_with_range(else_));
8626 }
8627 Expression::Case(c)
8628 }
8629 Expression::Gte(op) => Expression::Gte(Box::new(crate::expressions::BinaryOp {
8630 left: Self::replace_rownum_with_range(op.left),
8631 right: op.right,
8632 left_comments: op.left_comments,
8633 operator_comments: op.operator_comments,
8634 trailing_comments: op.trailing_comments,
8635 inferred_type: op.inferred_type,
8636 })),
8637 Expression::Sub(op) => Expression::Sub(Box::new(crate::expressions::BinaryOp {
8638 left: Self::replace_rownum_with_range(op.left),
8639 right: op.right,
8640 left_comments: op.left_comments,
8641 operator_comments: op.operator_comments,
8642 trailing_comments: op.trailing_comments,
8643 inferred_type: op.inferred_type,
8644 })),
8645 Expression::Alias(mut a) => {
8646 a.this = Self::replace_rownum_with_range(a.this);
8647 Expression::Alias(a)
8648 }
8649 other => other,
8650 }
8651 }
8652
8653 fn try_replace_rownum_paren(expr: &Expression) -> Expression {
8655 if let Expression::Paren(ref p) = expr {
8656 if let Expression::Sub(ref sub) = p.this {
8657 if let Expression::WindowFunction(ref wf) = sub.left {
8658 if let Expression::Function(ref f) = wf.this {
8659 if f.name.eq_ignore_ascii_case("ROW_NUMBER") {
8660 if let Expression::Literal(ref lit) = sub.right {
8661 if let crate::expressions::Literal::Number(ref n) = lit.as_ref() {
8662 if n == "1" {
8663 return Expression::column("range");
8664 }
8665 }
8666 }
8667 }
8668 }
8669 }
8670 }
8671 }
8672 expr.clone()
8673 }
8674
8675 fn transform_generate_date_array_snowflake(expr: Expression) -> Result<Expression> {
8682 use crate::expressions::*;
8683 transform_recursive(expr, &|e| {
8684 if let Expression::ArraySize(ref af) = e {
8686 if let Expression::Function(ref f) = af.this {
8687 if f.name.eq_ignore_ascii_case("GENERATE_DATE_ARRAY") && f.args.len() >= 2 {
8688 let result = Self::convert_array_size_gda_snowflake(f)?;
8689 return Ok(result);
8690 }
8691 }
8692 }
8693
8694 let Expression::Select(mut sel) = e else {
8695 return Ok(e);
8696 };
8697
8698 let mut gda_info: Option<(String, Expression, Expression, String)> = None; let mut gda_join_idx: Option<usize> = None;
8701
8702 for (idx, join) in sel.joins.iter().enumerate() {
8703 let (unnest_ref, alias_name) = match &join.this {
8707 Expression::Unnest(ref unnest) => {
8708 let alias = unnest.alias.as_ref().map(|id| id.name.clone());
8709 (Some(unnest.as_ref()), alias)
8710 }
8711 Expression::Alias(ref a) => {
8712 if let Expression::Unnest(ref unnest) = a.this {
8713 (Some(unnest.as_ref()), Some(a.alias.name.clone()))
8714 } else {
8715 (None, None)
8716 }
8717 }
8718 _ => (None, None),
8719 };
8720
8721 if let (Some(unnest), Some(alias)) = (unnest_ref, alias_name) {
8722 if let Expression::Function(ref f) = unnest.this {
8724 if f.name.eq_ignore_ascii_case("GENERATE_DATE_ARRAY") && f.args.len() >= 2 {
8725 let start_expr = f.args[0].clone();
8726 let end_expr = f.args[1].clone();
8727 let step = f.args.get(2).cloned();
8728
8729 let unit = if let Some(Expression::Interval(ref iv)) = step {
8731 if let Some(IntervalUnitSpec::Simple { ref unit, .. }) = iv.unit {
8732 Some(format!("{:?}", unit).to_ascii_uppercase())
8733 } else if let Some(ref this) = iv.this {
8734 if let Expression::Literal(lit) = this {
8736 if let Literal::String(ref s) = lit.as_ref() {
8737 let parts: Vec<&str> = s.split_whitespace().collect();
8738 if parts.len() == 2 {
8739 Some(parts[1].to_ascii_uppercase())
8740 } else if parts.len() == 1 {
8741 let upper = parts[0].to_ascii_uppercase();
8743 if matches!(
8744 upper.as_str(),
8745 "YEAR"
8746 | "QUARTER"
8747 | "MONTH"
8748 | "WEEK"
8749 | "DAY"
8750 | "HOUR"
8751 | "MINUTE"
8752 | "SECOND"
8753 ) {
8754 Some(upper)
8755 } else {
8756 None
8757 }
8758 } else {
8759 None
8760 }
8761 } else {
8762 None
8763 }
8764 } else {
8765 None
8766 }
8767 } else {
8768 None
8769 }
8770 } else {
8771 None
8772 };
8773
8774 if let Some(unit_str) = unit {
8775 gda_info = Some((alias, start_expr, end_expr, unit_str));
8776 gda_join_idx = Some(idx);
8777 }
8778 }
8779 }
8780 }
8781 if gda_info.is_some() {
8782 break;
8783 }
8784 }
8785
8786 let Some((alias_name, start_expr, end_expr, unit_str)) = gda_info else {
8787 let result = Self::try_transform_from_gda_snowflake(sel);
8790 return result;
8791 };
8792 let join_idx = gda_join_idx.unwrap();
8793
8794 let datediff = Expression::Function(Box::new(Function::new(
8798 "DATEDIFF".to_string(),
8799 vec![
8800 Expression::boxed_column(Column {
8801 name: Identifier::new(&unit_str),
8802 table: None,
8803 join_mark: false,
8804 trailing_comments: vec![],
8805 span: None,
8806 inferred_type: None,
8807 }),
8808 start_expr.clone(),
8809 end_expr.clone(),
8810 ],
8811 )));
8812 let datediff_plus_one = Expression::Add(Box::new(BinaryOp {
8813 left: datediff,
8814 right: Expression::Literal(Box::new(Literal::Number("1".to_string()))),
8815 left_comments: vec![],
8816 operator_comments: vec![],
8817 trailing_comments: vec![],
8818 inferred_type: None,
8819 }));
8820
8821 let array_gen_range = Expression::Function(Box::new(Function::new(
8822 "ARRAY_GENERATE_RANGE".to_string(),
8823 vec![
8824 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
8825 datediff_plus_one,
8826 ],
8827 )));
8828
8829 let flatten_input = Expression::NamedArgument(Box::new(NamedArgument {
8831 name: Identifier::new("INPUT"),
8832 value: array_gen_range,
8833 separator: crate::expressions::NamedArgSeparator::DArrow,
8834 }));
8835 let flatten = Expression::Function(Box::new(Function::new(
8836 "FLATTEN".to_string(),
8837 vec![flatten_input],
8838 )));
8839
8840 let alias_table = Alias {
8842 this: flatten,
8843 alias: Identifier::new("_t0"),
8844 column_aliases: vec![
8845 Identifier::new("seq"),
8846 Identifier::new("key"),
8847 Identifier::new("path"),
8848 Identifier::new("index"),
8849 Identifier::new(&alias_name),
8850 Identifier::new("this"),
8851 ],
8852 alias_explicit_as: false,
8853 alias_keyword: None,
8854 pre_alias_comments: vec![],
8855 trailing_comments: vec![],
8856 inferred_type: None,
8857 };
8858 let lateral_expr = Expression::Lateral(Box::new(Lateral {
8859 this: Box::new(Expression::Alias(Box::new(alias_table))),
8860 view: None,
8861 outer: None,
8862 alias: None,
8863 alias_quoted: false,
8864 cross_apply: None,
8865 ordinality: None,
8866 column_aliases: vec![],
8867 }));
8868
8869 sel.joins.remove(join_idx);
8871 if let Some(ref mut from) = sel.from {
8872 from.expressions.push(lateral_expr);
8873 }
8874
8875 let dateadd_expr = Expression::Function(Box::new(Function::new(
8877 "DATEADD".to_string(),
8878 vec![
8879 Expression::boxed_column(Column {
8880 name: Identifier::new(&unit_str),
8881 table: None,
8882 join_mark: false,
8883 trailing_comments: vec![],
8884 span: None,
8885 inferred_type: None,
8886 }),
8887 Expression::Cast(Box::new(Cast {
8888 this: Expression::boxed_column(Column {
8889 name: Identifier::new(&alias_name),
8890 table: None,
8891 join_mark: false,
8892 trailing_comments: vec![],
8893 span: None,
8894 inferred_type: None,
8895 }),
8896 to: DataType::Int {
8897 length: None,
8898 integer_spelling: false,
8899 },
8900 trailing_comments: vec![],
8901 double_colon_syntax: false,
8902 format: None,
8903 default: None,
8904 inferred_type: None,
8905 })),
8906 Expression::Cast(Box::new(Cast {
8907 this: start_expr.clone(),
8908 to: DataType::Date,
8909 trailing_comments: vec![],
8910 double_colon_syntax: false,
8911 format: None,
8912 default: None,
8913 inferred_type: None,
8914 })),
8915 ],
8916 )));
8917
8918 let new_exprs: Vec<Expression> = sel
8920 .expressions
8921 .iter()
8922 .map(|expr| Self::replace_column_ref_with_dateadd(expr, &alias_name, &dateadd_expr))
8923 .collect();
8924 sel.expressions = new_exprs;
8925
8926 Ok(Expression::Select(sel))
8927 })
8928 }
8929
8930 fn replace_column_ref_with_dateadd(
8932 expr: &Expression,
8933 alias_name: &str,
8934 dateadd: &Expression,
8935 ) -> Expression {
8936 use crate::expressions::*;
8937 match expr {
8938 Expression::Column(c) if c.name.name == alias_name && c.table.is_none() => {
8939 Expression::Alias(Box::new(Alias {
8941 this: dateadd.clone(),
8942 alias: Identifier::new(alias_name),
8943 column_aliases: vec![],
8944 alias_explicit_as: false,
8945 alias_keyword: None,
8946 pre_alias_comments: vec![],
8947 trailing_comments: vec![],
8948 inferred_type: None,
8949 }))
8950 }
8951 Expression::Alias(a) => {
8952 let new_this = Self::replace_column_ref_inner(&a.this, alias_name, dateadd);
8954 Expression::Alias(Box::new(Alias {
8955 this: new_this,
8956 alias: a.alias.clone(),
8957 column_aliases: a.column_aliases.clone(),
8958 alias_explicit_as: false,
8959 alias_keyword: None,
8960 pre_alias_comments: a.pre_alias_comments.clone(),
8961 trailing_comments: a.trailing_comments.clone(),
8962 inferred_type: None,
8963 }))
8964 }
8965 _ => expr.clone(),
8966 }
8967 }
8968
8969 fn replace_column_ref_inner(
8971 expr: &Expression,
8972 alias_name: &str,
8973 dateadd: &Expression,
8974 ) -> Expression {
8975 use crate::expressions::*;
8976 match expr {
8977 Expression::Column(c) if c.name.name == alias_name && c.table.is_none() => {
8978 dateadd.clone()
8979 }
8980 Expression::Add(op) => {
8981 let left = Self::replace_column_ref_inner(&op.left, alias_name, dateadd);
8982 let right = Self::replace_column_ref_inner(&op.right, alias_name, dateadd);
8983 Expression::Add(Box::new(BinaryOp {
8984 left,
8985 right,
8986 left_comments: op.left_comments.clone(),
8987 operator_comments: op.operator_comments.clone(),
8988 trailing_comments: op.trailing_comments.clone(),
8989 inferred_type: None,
8990 }))
8991 }
8992 Expression::Sub(op) => {
8993 let left = Self::replace_column_ref_inner(&op.left, alias_name, dateadd);
8994 let right = Self::replace_column_ref_inner(&op.right, alias_name, dateadd);
8995 Expression::Sub(Box::new(BinaryOp {
8996 left,
8997 right,
8998 left_comments: op.left_comments.clone(),
8999 operator_comments: op.operator_comments.clone(),
9000 trailing_comments: op.trailing_comments.clone(),
9001 inferred_type: None,
9002 }))
9003 }
9004 Expression::Mul(op) => {
9005 let left = Self::replace_column_ref_inner(&op.left, alias_name, dateadd);
9006 let right = Self::replace_column_ref_inner(&op.right, alias_name, dateadd);
9007 Expression::Mul(Box::new(BinaryOp {
9008 left,
9009 right,
9010 left_comments: op.left_comments.clone(),
9011 operator_comments: op.operator_comments.clone(),
9012 trailing_comments: op.trailing_comments.clone(),
9013 inferred_type: None,
9014 }))
9015 }
9016 _ => expr.clone(),
9017 }
9018 }
9019
9020 fn try_transform_from_gda_snowflake(
9023 mut sel: Box<crate::expressions::Select>,
9024 ) -> Result<Expression> {
9025 use crate::expressions::*;
9026
9027 let mut gda_info: Option<(
9029 usize,
9030 String,
9031 Expression,
9032 Expression,
9033 String,
9034 Option<(String, Vec<Identifier>)>,
9035 )> = None; if let Some(ref from) = sel.from {
9038 for (idx, table_expr) in from.expressions.iter().enumerate() {
9039 let (unnest_opt, outer_alias_info) = match table_expr {
9042 Expression::Unnest(ref unnest) => (Some(unnest.as_ref()), None),
9043 Expression::Alias(ref a) => {
9044 if let Expression::Unnest(ref unnest) = a.this {
9045 let alias_info = (a.alias.name.clone(), a.column_aliases.clone());
9046 (Some(unnest.as_ref()), Some(alias_info))
9047 } else {
9048 (None, None)
9049 }
9050 }
9051 _ => (None, None),
9052 };
9053
9054 if let Some(unnest) = unnest_opt {
9055 let func_opt = match &unnest.this {
9057 Expression::Function(ref f)
9058 if f.name.eq_ignore_ascii_case("GENERATE_DATE_ARRAY")
9059 && f.args.len() >= 2 =>
9060 {
9061 Some(f)
9062 }
9063 _ => None,
9065 };
9066
9067 if let Some(f) = func_opt {
9068 let start_expr = f.args[0].clone();
9069 let end_expr = f.args[1].clone();
9070 let step = f.args.get(2).cloned();
9071
9072 let unit = Self::extract_interval_unit_str(&step);
9074 let col_name = outer_alias_info
9075 .as_ref()
9076 .and_then(|(_, cols)| cols.first().map(|id| id.name.clone()))
9077 .unwrap_or_else(|| "value".to_string());
9078
9079 if let Some(unit_str) = unit {
9080 gda_info = Some((
9081 idx,
9082 col_name,
9083 start_expr,
9084 end_expr,
9085 unit_str,
9086 outer_alias_info,
9087 ));
9088 break;
9089 }
9090 }
9091 }
9092 }
9093 }
9094
9095 let Some((from_idx, col_name, start_expr, end_expr, unit_str, outer_alias_info)) = gda_info
9096 else {
9097 return Ok(Expression::Select(sel));
9098 };
9099
9100 let datediff = Expression::Function(Box::new(Function::new(
9106 "DATEDIFF".to_string(),
9107 vec![
9108 Expression::boxed_column(Column {
9109 name: Identifier::new(&unit_str),
9110 table: None,
9111 join_mark: false,
9112 trailing_comments: vec![],
9113 span: None,
9114 inferred_type: None,
9115 }),
9116 start_expr.clone(),
9117 end_expr.clone(),
9118 ],
9119 )));
9120 let datediff_plus_one = Expression::Add(Box::new(BinaryOp {
9122 left: datediff,
9123 right: Expression::Literal(Box::new(Literal::Number("1".to_string()))),
9124 left_comments: vec![],
9125 operator_comments: vec![],
9126 trailing_comments: vec![],
9127 inferred_type: None,
9128 }));
9129
9130 let array_gen_range = Expression::Function(Box::new(Function::new(
9131 "ARRAY_GENERATE_RANGE".to_string(),
9132 vec![
9133 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
9134 datediff_plus_one,
9135 ],
9136 )));
9137
9138 let flatten_input = Expression::NamedArgument(Box::new(NamedArgument {
9140 name: Identifier::new("INPUT"),
9141 value: array_gen_range,
9142 separator: crate::expressions::NamedArgSeparator::DArrow,
9143 }));
9144 let flatten = Expression::Function(Box::new(Function::new(
9145 "FLATTEN".to_string(),
9146 vec![flatten_input],
9147 )));
9148
9149 let table_alias_name = outer_alias_info
9151 .as_ref()
9152 .map(|(name, _)| name.clone())
9153 .unwrap_or_else(|| "_t0".to_string());
9154
9155 let table_func =
9157 Expression::Function(Box::new(Function::new("TABLE".to_string(), vec![flatten])));
9158 let flatten_aliased = Expression::Alias(Box::new(Alias {
9159 this: table_func,
9160 alias: Identifier::new(&table_alias_name),
9161 column_aliases: vec![
9162 Identifier::new("seq"),
9163 Identifier::new("key"),
9164 Identifier::new("path"),
9165 Identifier::new("index"),
9166 Identifier::new(&col_name),
9167 Identifier::new("this"),
9168 ],
9169 alias_explicit_as: false,
9170 alias_keyword: None,
9171 pre_alias_comments: vec![],
9172 trailing_comments: vec![],
9173 inferred_type: None,
9174 }));
9175
9176 let dateadd_expr = Expression::Function(Box::new(Function::new(
9178 "DATEADD".to_string(),
9179 vec![
9180 Expression::boxed_column(Column {
9181 name: Identifier::new(&unit_str),
9182 table: None,
9183 join_mark: false,
9184 trailing_comments: vec![],
9185 span: None,
9186 inferred_type: None,
9187 }),
9188 Expression::Cast(Box::new(Cast {
9189 this: Expression::boxed_column(Column {
9190 name: Identifier::new(&col_name),
9191 table: None,
9192 join_mark: false,
9193 trailing_comments: vec![],
9194 span: None,
9195 inferred_type: None,
9196 }),
9197 to: DataType::Int {
9198 length: None,
9199 integer_spelling: false,
9200 },
9201 trailing_comments: vec![],
9202 double_colon_syntax: false,
9203 format: None,
9204 default: None,
9205 inferred_type: None,
9206 })),
9207 start_expr.clone(),
9209 ],
9210 )));
9211 let dateadd_aliased = Expression::Alias(Box::new(Alias {
9212 this: dateadd_expr,
9213 alias: Identifier::new(&col_name),
9214 column_aliases: vec![],
9215 alias_explicit_as: false,
9216 alias_keyword: None,
9217 pre_alias_comments: vec![],
9218 trailing_comments: vec![],
9219 inferred_type: None,
9220 }));
9221
9222 let mut inner_select = Select::new();
9224 inner_select.expressions = vec![dateadd_aliased];
9225 inner_select.from = Some(From {
9226 expressions: vec![flatten_aliased],
9227 });
9228
9229 let inner_select_expr = Expression::Select(Box::new(inner_select));
9230 let subquery = Expression::Subquery(Box::new(Subquery {
9231 this: inner_select_expr,
9232 alias: None,
9233 column_aliases: vec![],
9234 alias_explicit_as: false,
9235 alias_keyword: None,
9236 order_by: None,
9237 limit: None,
9238 offset: None,
9239 distribute_by: None,
9240 sort_by: None,
9241 cluster_by: None,
9242 lateral: false,
9243 modifiers_inside: false,
9244 trailing_comments: vec![],
9245 inferred_type: None,
9246 }));
9247
9248 let replacement = if let Some((alias_name, col_aliases)) = outer_alias_info {
9250 Expression::Alias(Box::new(Alias {
9251 this: subquery,
9252 alias: Identifier::new(&alias_name),
9253 column_aliases: col_aliases,
9254 alias_explicit_as: false,
9255 alias_keyword: None,
9256 pre_alias_comments: vec![],
9257 trailing_comments: vec![],
9258 inferred_type: None,
9259 }))
9260 } else {
9261 subquery
9262 };
9263
9264 if let Some(ref mut from) = sel.from {
9266 from.expressions[from_idx] = replacement;
9267 }
9268
9269 Ok(Expression::Select(sel))
9270 }
9271
9272 fn convert_array_size_gda_snowflake(f: &crate::expressions::Function) -> Result<Expression> {
9276 use crate::expressions::*;
9277
9278 let start_expr = f.args[0].clone();
9279 let end_expr = f.args[1].clone();
9280 let step = f.args.get(2).cloned();
9281 let unit_str = Self::extract_interval_unit_str(&step).unwrap_or_else(|| "DAY".to_string());
9282 let col_name = "value";
9283
9284 let datediff = Expression::Function(Box::new(Function::new(
9286 "DATEDIFF".to_string(),
9287 vec![
9288 Expression::boxed_column(Column {
9289 name: Identifier::new(&unit_str),
9290 table: None,
9291 join_mark: false,
9292 trailing_comments: vec![],
9293 span: None,
9294 inferred_type: None,
9295 }),
9296 start_expr.clone(),
9297 end_expr.clone(),
9298 ],
9299 )));
9300 let datediff_plus_one = Expression::Add(Box::new(BinaryOp {
9302 left: datediff,
9303 right: Expression::Literal(Box::new(Literal::Number("1".to_string()))),
9304 left_comments: vec![],
9305 operator_comments: vec![],
9306 trailing_comments: vec![],
9307 inferred_type: None,
9308 }));
9309
9310 let array_gen_range = Expression::Function(Box::new(Function::new(
9311 "ARRAY_GENERATE_RANGE".to_string(),
9312 vec![
9313 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
9314 datediff_plus_one,
9315 ],
9316 )));
9317
9318 let flatten_input = Expression::NamedArgument(Box::new(NamedArgument {
9319 name: Identifier::new("INPUT"),
9320 value: array_gen_range,
9321 separator: crate::expressions::NamedArgSeparator::DArrow,
9322 }));
9323 let flatten = Expression::Function(Box::new(Function::new(
9324 "FLATTEN".to_string(),
9325 vec![flatten_input],
9326 )));
9327
9328 let table_func =
9329 Expression::Function(Box::new(Function::new("TABLE".to_string(), vec![flatten])));
9330 let flatten_aliased = Expression::Alias(Box::new(Alias {
9331 this: table_func,
9332 alias: Identifier::new("_t0"),
9333 column_aliases: vec![
9334 Identifier::new("seq"),
9335 Identifier::new("key"),
9336 Identifier::new("path"),
9337 Identifier::new("index"),
9338 Identifier::new(col_name),
9339 Identifier::new("this"),
9340 ],
9341 alias_explicit_as: false,
9342 alias_keyword: None,
9343 pre_alias_comments: vec![],
9344 trailing_comments: vec![],
9345 inferred_type: None,
9346 }));
9347
9348 let dateadd_expr = Expression::Function(Box::new(Function::new(
9349 "DATEADD".to_string(),
9350 vec![
9351 Expression::boxed_column(Column {
9352 name: Identifier::new(&unit_str),
9353 table: None,
9354 join_mark: false,
9355 trailing_comments: vec![],
9356 span: None,
9357 inferred_type: None,
9358 }),
9359 Expression::Cast(Box::new(Cast {
9360 this: Expression::boxed_column(Column {
9361 name: Identifier::new(col_name),
9362 table: None,
9363 join_mark: false,
9364 trailing_comments: vec![],
9365 span: None,
9366 inferred_type: None,
9367 }),
9368 to: DataType::Int {
9369 length: None,
9370 integer_spelling: false,
9371 },
9372 trailing_comments: vec![],
9373 double_colon_syntax: false,
9374 format: None,
9375 default: None,
9376 inferred_type: None,
9377 })),
9378 start_expr.clone(),
9379 ],
9380 )));
9381 let dateadd_aliased = Expression::Alias(Box::new(Alias {
9382 this: dateadd_expr,
9383 alias: Identifier::new(col_name),
9384 column_aliases: vec![],
9385 alias_explicit_as: false,
9386 alias_keyword: None,
9387 pre_alias_comments: vec![],
9388 trailing_comments: vec![],
9389 inferred_type: None,
9390 }));
9391
9392 let mut inner_select = Select::new();
9394 inner_select.expressions = vec![dateadd_aliased];
9395 inner_select.from = Some(From {
9396 expressions: vec![flatten_aliased],
9397 });
9398
9399 let inner_subquery = Expression::Subquery(Box::new(Subquery {
9401 this: Expression::Select(Box::new(inner_select)),
9402 alias: None,
9403 column_aliases: vec![],
9404 alias_explicit_as: false,
9405 alias_keyword: None,
9406 order_by: None,
9407 limit: None,
9408 offset: None,
9409 distribute_by: None,
9410 sort_by: None,
9411 cluster_by: None,
9412 lateral: false,
9413 modifiers_inside: false,
9414 trailing_comments: vec![],
9415 inferred_type: None,
9416 }));
9417
9418 let star = Expression::Star(Star {
9420 table: None,
9421 except: None,
9422 replace: None,
9423 rename: None,
9424 trailing_comments: vec![],
9425 span: None,
9426 });
9427 let array_agg = Expression::ArrayAgg(Box::new(AggFunc {
9428 this: star,
9429 distinct: false,
9430 filter: None,
9431 order_by: vec![],
9432 name: Some("ARRAY_AGG".to_string()),
9433 ignore_nulls: None,
9434 having_max: None,
9435 limit: None,
9436 inferred_type: None,
9437 }));
9438
9439 let mut outer_select = Select::new();
9440 outer_select.expressions = vec![array_agg];
9441 outer_select.from = Some(From {
9442 expressions: vec![inner_subquery],
9443 });
9444
9445 let outer_subquery = Expression::Subquery(Box::new(Subquery {
9447 this: Expression::Select(Box::new(outer_select)),
9448 alias: None,
9449 column_aliases: vec![],
9450 alias_explicit_as: false,
9451 alias_keyword: None,
9452 order_by: None,
9453 limit: None,
9454 offset: None,
9455 distribute_by: None,
9456 sort_by: None,
9457 cluster_by: None,
9458 lateral: false,
9459 modifiers_inside: false,
9460 trailing_comments: vec![],
9461 inferred_type: None,
9462 }));
9463
9464 Ok(Expression::ArraySize(Box::new(UnaryFunc::new(
9466 outer_subquery,
9467 ))))
9468 }
9469
9470 fn extract_interval_unit_str(step: &Option<Expression>) -> Option<String> {
9472 use crate::expressions::*;
9473 if let Some(Expression::Interval(ref iv)) = step {
9474 if let Some(IntervalUnitSpec::Simple { ref unit, .. }) = iv.unit {
9475 return Some(format!("{:?}", unit).to_ascii_uppercase());
9476 }
9477 if let Some(ref this) = iv.this {
9478 if let Expression::Literal(lit) = this {
9479 if let Literal::String(ref s) = lit.as_ref() {
9480 let parts: Vec<&str> = s.split_whitespace().collect();
9481 if parts.len() == 2 {
9482 return Some(parts[1].to_ascii_uppercase());
9483 } else if parts.len() == 1 {
9484 let upper = parts[0].to_ascii_uppercase();
9485 if matches!(
9486 upper.as_str(),
9487 "YEAR"
9488 | "QUARTER"
9489 | "MONTH"
9490 | "WEEK"
9491 | "DAY"
9492 | "HOUR"
9493 | "MINUTE"
9494 | "SECOND"
9495 ) {
9496 return Some(upper);
9497 }
9498 }
9499 }
9500 }
9501 }
9502 }
9503 if step.is_none() {
9505 return Some("DAY".to_string());
9506 }
9507 None
9508 }
9509
9510 fn normalize_snowflake_pretty(mut sql: String) -> String {
9511 if sql.contains("LATERAL IFF(_u.pos = _u_2.pos_2, _u_2.entity, NULL) AS datasource(SEQ, KEY, PATH, INDEX, VALUE, THIS)")
9512 && sql.contains("ARRAY_GENERATE_RANGE(0, (GREATEST(ARRAY_SIZE(INPUT => PARSE_JSON(flags))) - 1) + 1)")
9513 {
9514 sql = sql.replace(
9515 "AND uc.user_id <> ALL (SELECT DISTINCT\n _id\n FROM users, LATERAL IFF(_u.pos = _u_2.pos_2, _u_2.entity, NULL) AS datasource(SEQ, KEY, PATH, INDEX, VALUE, THIS)\n WHERE\n GET_PATH(datasource.value, 'name') = 'something')",
9516 "AND uc.user_id <> ALL (\n SELECT DISTINCT\n _id\n FROM users, LATERAL IFF(_u.pos = _u_2.pos_2, _u_2.entity, NULL) AS datasource(SEQ, KEY, PATH, INDEX, VALUE, THIS)\n WHERE\n GET_PATH(datasource.value, 'name') = 'something'\n )",
9517 );
9518
9519 sql = sql.replace(
9520 "CROSS JOIN TABLE(FLATTEN(INPUT => ARRAY_GENERATE_RANGE(0, (GREATEST(ARRAY_SIZE(INPUT => PARSE_JSON(flags))) - 1) + 1))) AS _u(seq, key, path, index, pos, this)",
9521 "CROSS JOIN TABLE(FLATTEN(INPUT => ARRAY_GENERATE_RANGE(0, (\n GREATEST(ARRAY_SIZE(INPUT => PARSE_JSON(flags))) - 1\n) + 1))) AS _u(seq, key, path, index, pos, this)",
9522 );
9523
9524 sql = sql.replace(
9525 "OR (_u.pos > (ARRAY_SIZE(INPUT => PARSE_JSON(flags)) - 1)\n AND _u_2.pos_2 = (ARRAY_SIZE(INPUT => PARSE_JSON(flags)) - 1))",
9526 "OR (\n _u.pos > (\n ARRAY_SIZE(INPUT => PARSE_JSON(flags)) - 1\n )\n AND _u_2.pos_2 = (\n ARRAY_SIZE(INPUT => PARSE_JSON(flags)) - 1\n )\n )",
9527 );
9528 }
9529
9530 sql
9531 }
9532
9533 #[cfg(feature = "transpile")]
9534 fn wrap_tsql_top_level_values(expr: Expression) -> Expression {
9535 match expr {
9536 Expression::Values(values) => Self::tsql_values_as_select(*values),
9537 Expression::Union(mut union) => {
9538 let left = std::mem::replace(&mut union.left, Expression::Null(Null));
9539 let right = std::mem::replace(&mut union.right, Expression::Null(Null));
9540 union.left = Self::wrap_tsql_values_set_operand(left);
9541 union.right = Self::wrap_tsql_values_set_operand(right);
9542 Expression::Union(union)
9543 }
9544 Expression::Intersect(mut intersect) => {
9545 let left = std::mem::replace(&mut intersect.left, Expression::Null(Null));
9546 let right = std::mem::replace(&mut intersect.right, Expression::Null(Null));
9547 intersect.left = Self::wrap_tsql_values_set_operand(left);
9548 intersect.right = Self::wrap_tsql_values_set_operand(right);
9549 Expression::Intersect(intersect)
9550 }
9551 Expression::Except(mut except) => {
9552 let left = std::mem::replace(&mut except.left, Expression::Null(Null));
9553 let right = std::mem::replace(&mut except.right, Expression::Null(Null));
9554 except.left = Self::wrap_tsql_values_set_operand(left);
9555 except.right = Self::wrap_tsql_values_set_operand(right);
9556 Expression::Except(except)
9557 }
9558 other => other,
9559 }
9560 }
9561
9562 #[cfg(feature = "transpile")]
9563 fn wrap_tsql_values_set_operand(expr: Expression) -> Expression {
9564 match expr {
9565 Expression::Values(values) => Self::tsql_values_as_select(*values),
9566 Expression::Select(mut select)
9567 if Self::is_parser_wrapped_values_set_operand(&select) =>
9568 {
9569 let mut from = select.from.take().expect("checked as present");
9570 let Expression::Values(values) = from
9571 .expressions
9572 .pop()
9573 .expect("checked as a single VALUES source")
9574 else {
9575 unreachable!("checked as a VALUES source");
9576 };
9577 Self::tsql_values_as_select(*values)
9578 }
9579 Expression::Annotated(mut annotated) => {
9580 annotated.this = Self::wrap_tsql_values_set_operand(annotated.this);
9581 Expression::Annotated(annotated)
9582 }
9583 Expression::Union(mut union) => {
9584 let left = std::mem::replace(&mut union.left, Expression::Null(Null));
9585 let right = std::mem::replace(&mut union.right, Expression::Null(Null));
9586 union.left = Self::wrap_tsql_values_set_operand(left);
9587 union.right = Self::wrap_tsql_values_set_operand(right);
9588 Expression::Union(union)
9589 }
9590 Expression::Intersect(mut intersect) => {
9591 let left = std::mem::replace(&mut intersect.left, Expression::Null(Null));
9592 let right = std::mem::replace(&mut intersect.right, Expression::Null(Null));
9593 intersect.left = Self::wrap_tsql_values_set_operand(left);
9594 intersect.right = Self::wrap_tsql_values_set_operand(right);
9595 Expression::Intersect(intersect)
9596 }
9597 Expression::Except(mut except) => {
9598 let left = std::mem::replace(&mut except.left, Expression::Null(Null));
9599 let right = std::mem::replace(&mut except.right, Expression::Null(Null));
9600 except.left = Self::wrap_tsql_values_set_operand(left);
9601 except.right = Self::wrap_tsql_values_set_operand(right);
9602 Expression::Except(except)
9603 }
9604 other => other,
9605 }
9606 }
9607
9608 #[cfg(feature = "transpile")]
9609 fn is_parser_wrapped_values_set_operand(select: &Select) -> bool {
9610 let Some(from) = &select.from else {
9611 return false;
9612 };
9613 let [Expression::Values(values)] = from.expressions.as_slice() else {
9614 return false;
9615 };
9616 if !values
9617 .alias
9618 .as_ref()
9619 .is_some_and(|alias| alias.name == "_values")
9620 {
9621 return false;
9622 }
9623
9624 let mut parser_wrapper = Select::new();
9625 parser_wrapper.expressions = vec![Expression::star()];
9626 parser_wrapper.from = Some(from.clone());
9627 select == &parser_wrapper
9628 }
9629
9630 #[cfg(feature = "transpile")]
9631 fn tsql_values_as_select(mut values: crate::expressions::Values) -> Expression {
9632 let column_aliases = if values.column_aliases.is_empty() {
9633 let column_count = values
9634 .expressions
9635 .first()
9636 .map(|row| row.expressions.len())
9637 .unwrap_or(0);
9638 (1..=column_count)
9639 .map(|index| Identifier::new(format!("column{index}")))
9640 .collect()
9641 } else {
9642 std::mem::take(&mut values.column_aliases)
9643 };
9644
9645 values.alias = None;
9646
9647 let values_subquery = Expression::Subquery(Box::new(crate::expressions::Subquery {
9648 this: Expression::Values(Box::new(values)),
9649 alias: Some(Identifier::new("_v")),
9650 column_aliases,
9651 alias_explicit_as: false,
9652 alias_keyword: None,
9653 order_by: None,
9654 limit: None,
9655 offset: None,
9656 distribute_by: None,
9657 sort_by: None,
9658 cluster_by: None,
9659 lateral: false,
9660 modifiers_inside: false,
9661 trailing_comments: Vec::new(),
9662 inferred_type: None,
9663 }));
9664
9665 let mut select = crate::expressions::Select::new();
9666 select.expressions = vec![Expression::star()];
9667 select.from = Some(From {
9668 expressions: vec![values_subquery],
9669 });
9670
9671 Expression::Select(Box::new(select))
9672 }
9673
9674 fn extract_interval_parts(
9675 interval_expr: &Expression,
9676 ) -> Option<(Expression, crate::expressions::IntervalUnit)> {
9677 use crate::expressions::{DataType, IntervalUnit, IntervalUnitSpec, Literal};
9678
9679 fn unit_from_str(unit: &str) -> Option<IntervalUnit> {
9680 match unit.trim().to_ascii_uppercase().as_str() {
9681 "YEAR" | "YEARS" | "Y" | "YR" | "YRS" | "YY" | "YYYY" => Some(IntervalUnit::Year),
9682 "QUARTER" | "QUARTERS" | "Q" | "QTR" | "QTRS" | "QQ" => Some(IntervalUnit::Quarter),
9683 "MONTH" | "MONTHS" | "MON" | "MONS" | "MM" => Some(IntervalUnit::Month),
9684 "WEEK" | "WEEKS" | "W" | "WK" | "WKS" | "WW" | "ISOWEEK" => {
9685 Some(IntervalUnit::Week)
9686 }
9687 "DAY" | "DAYS" | "D" | "DD" => Some(IntervalUnit::Day),
9688 "HOUR" | "HOURS" | "H" | "HH" | "HR" | "HRS" => Some(IntervalUnit::Hour),
9689 "MINUTE" | "MINUTES" | "MI" | "MIN" | "MINS" | "N" => Some(IntervalUnit::Minute),
9690 "SECOND" | "SECONDS" | "S" | "SEC" | "SECS" | "SS" => Some(IntervalUnit::Second),
9691 "MILLISECOND" | "MILLISECONDS" | "MS" | "MSEC" | "MSECS" | "MSECOND"
9692 | "MSECONDS" | "MILLISEC" | "MILLISECS" | "MILLISECON" => {
9693 Some(IntervalUnit::Millisecond)
9694 }
9695 "MICROSECOND" | "MICROSECONDS" | "US" | "USEC" | "USECS" | "USECOND"
9696 | "USECONDS" | "MICROSEC" | "MICROSECS" | "MCS" => Some(IntervalUnit::Microsecond),
9697 "NANOSECOND" | "NANOSECONDS" | "NS" | "NSEC" | "NSECS" | "NSECOND" | "NSECONDS"
9698 | "NANOSEC" | "NANOSECS" => Some(IntervalUnit::Nanosecond),
9699 _ => None,
9700 }
9701 }
9702
9703 fn parts_from_literal_string(s: &str) -> Option<(Expression, IntervalUnit)> {
9704 let mut parts = s.split_whitespace();
9705 let value = parts.next()?;
9706 let unit = unit_from_str(parts.next()?)?;
9707 Some((
9708 Expression::Literal(Box::new(Literal::String(value.to_string()))),
9709 unit,
9710 ))
9711 }
9712
9713 fn unit_from_spec(unit: &IntervalUnitSpec) -> Option<IntervalUnit> {
9714 match unit {
9715 IntervalUnitSpec::Simple { unit, .. } => Some(*unit),
9716 IntervalUnitSpec::Expr(expr) => match expr.as_ref() {
9717 Expression::Day(_) => Some(IntervalUnit::Day),
9718 Expression::Month(_) => Some(IntervalUnit::Month),
9719 Expression::Year(_) => Some(IntervalUnit::Year),
9720 Expression::Identifier(id) => unit_from_str(&id.name),
9721 Expression::Var(v) => unit_from_str(&v.this),
9722 Expression::Column(col) => unit_from_str(&col.name.name),
9723 _ => None,
9724 },
9725 _ => None,
9726 }
9727 }
9728
9729 match interval_expr {
9730 Expression::Interval(iv) => {
9731 let val = iv.this.clone().unwrap_or(Expression::number(0));
9732 if let Expression::Literal(lit) = &val {
9733 if let Literal::String(s) = lit.as_ref() {
9734 if let Some(parts) = parts_from_literal_string(s) {
9735 return Some(parts);
9736 }
9737 }
9738 }
9739 let unit = iv
9740 .unit
9741 .as_ref()
9742 .and_then(unit_from_spec)
9743 .unwrap_or(IntervalUnit::Day);
9744 Some((val, unit))
9745 }
9746 Expression::Cast(cast) if matches!(cast.to, DataType::Interval { .. }) => {
9747 if let Expression::Literal(lit) = &cast.this {
9748 if let Literal::String(s) = lit.as_ref() {
9749 if let Some(parts) = parts_from_literal_string(s) {
9750 return Some(parts);
9751 }
9752 }
9753 }
9754 let unit = match &cast.to {
9755 DataType::Interval {
9756 unit: Some(unit), ..
9757 } => unit_from_str(unit).unwrap_or(IntervalUnit::Day),
9758 _ => IntervalUnit::Day,
9759 };
9760 Some((cast.this.clone(), unit))
9761 }
9762 _ => None,
9763 }
9764 }
9765
9766 fn data_type_is_interval(dt: &DataType) -> bool {
9767 match dt {
9768 DataType::Interval { .. } => true,
9769 DataType::Custom { name } => name.trim().eq_ignore_ascii_case("INTERVAL"),
9770 _ => false,
9771 }
9772 }
9773
9774 fn node_is_interval_cast(node: &Expression) -> bool {
9775 match node {
9776 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
9777 Self::data_type_is_interval(&c.to)
9778 }
9779 _ => false,
9780 }
9781 }
9782
9783 fn reject_tsql_interval_casts(
9784 expr: &Expression,
9785 target: DialectType,
9786 opts: &TranspileOptions,
9787 ) -> Result<()> {
9788 if !matches!(
9789 opts.unsupported_level,
9790 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
9791 ) {
9792 return Ok(());
9793 }
9794
9795 if expr.dfs().any(Self::node_is_interval_cast) {
9796 return Err(crate::error::Error::unsupported(
9797 "INTERVAL casts",
9798 target.to_string(),
9799 ));
9800 }
9801
9802 Ok(())
9803 }
9804
9805 fn tsql_varchar_max_type() -> DataType {
9806 DataType::Custom {
9807 name: "VARCHAR(MAX)".to_string(),
9808 }
9809 }
9810
9811 fn rewrite_tsql_interval_casts_to_varchar(expr: Expression) -> Result<Expression> {
9812 transform_recursive(expr, &|e| match e {
9813 Expression::Cast(mut cast) if Self::data_type_is_interval(&cast.to) => {
9814 cast.to = Self::tsql_varchar_max_type();
9815 cast.double_colon_syntax = false;
9816 Ok(Expression::Cast(cast))
9817 }
9818 Expression::TryCast(mut cast) if Self::data_type_is_interval(&cast.to) => {
9819 cast.to = Self::tsql_varchar_max_type();
9820 cast.double_colon_syntax = false;
9821 Ok(Expression::TryCast(cast))
9822 }
9823 Expression::SafeCast(mut cast) if Self::data_type_is_interval(&cast.to) => {
9824 cast.to = Self::tsql_varchar_max_type();
9825 cast.double_colon_syntax = false;
9826 Ok(Expression::SafeCast(cast))
9827 }
9828 _ => Ok(e),
9829 })
9830 }
9831
9832 fn rewrite_tsql_interval_arithmetic_legacy(
9833 expr: &Expression,
9834 source: DialectType,
9835 ) -> Option<Expression> {
9836 match expr {
9837 Expression::Add(op) => {
9838 if Self::extract_interval_parts(&op.right).is_some() {
9839 return Some(Self::build_tsql_dateadd_from_interval(
9840 op.left.clone(),
9841 &op.right,
9842 false,
9843 ));
9844 }
9845
9846 if Self::is_postgres_family_source(source) {
9847 if Self::is_explicit_date_expr(&op.left)
9848 && Self::is_integer_day_offset_expr(&op.right)
9849 {
9850 return Some(Self::build_tsql_dateadd_days(
9851 op.left.clone(),
9852 op.right.clone(),
9853 false,
9854 ));
9855 }
9856
9857 if Self::is_integer_day_offset_expr(&op.left)
9858 && Self::is_explicit_date_expr(&op.right)
9859 {
9860 return Some(Self::build_tsql_dateadd_days(
9861 op.right.clone(),
9862 op.left.clone(),
9863 false,
9864 ));
9865 }
9866 }
9867
9868 None
9869 }
9870 Expression::Sub(op) => {
9871 if Self::extract_interval_parts(&op.right).is_some() {
9872 return Some(Self::build_tsql_dateadd_from_interval(
9873 op.left.clone(),
9874 &op.right,
9875 true,
9876 ));
9877 }
9878
9879 if Self::is_postgres_family_source(source) {
9880 if Self::is_explicit_date_expr(&op.left)
9881 && Self::is_explicit_date_expr(&op.right)
9882 {
9883 return Some(Self::build_tsql_datediff_days(
9884 op.right.clone(),
9885 op.left.clone(),
9886 ));
9887 }
9888
9889 if Self::is_explicit_date_expr(&op.left)
9890 && Self::is_integer_day_offset_expr(&op.right)
9891 {
9892 return Some(Self::build_tsql_dateadd_days(
9893 op.left.clone(),
9894 op.right.clone(),
9895 true,
9896 ));
9897 }
9898 }
9899
9900 None
9901 }
9902 _ => None,
9903 }
9904 }
9905
9906 fn is_postgres_family_source(source: DialectType) -> bool {
9907 matches!(
9908 source,
9909 DialectType::PostgreSQL
9910 | DialectType::Redshift
9911 | DialectType::Materialize
9912 | DialectType::RisingWave
9913 | DialectType::CockroachDB
9914 )
9915 }
9916
9917 fn is_explicit_date_expr(expr: &Expression) -> bool {
9918 use crate::expressions::Literal;
9919
9920 match expr {
9921 Expression::Literal(lit) => matches!(lit.as_ref(), Literal::Date(_)),
9922 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
9923 matches!(c.to, crate::expressions::DataType::Date)
9924 }
9925 Expression::Paren(p) => Self::is_explicit_date_expr(&p.this),
9926 Expression::CurrentDate(_)
9927 | Expression::Date(_)
9928 | Expression::MakeDate(_)
9929 | Expression::ToDate(_)
9930 | Expression::DateStrToDate(_) => true,
9931 _ => false,
9932 }
9933 }
9934
9935 fn is_integer_day_offset_expr(expr: &Expression) -> bool {
9936 use crate::expressions::Literal;
9937
9938 match expr {
9939 Expression::Literal(lit) => match lit.as_ref() {
9940 Literal::Number(n) => n.parse::<i64>().is_ok(),
9941 _ => false,
9942 },
9943 Expression::Parameter(_) | Expression::Placeholder(_) => true,
9944 Expression::Neg(op) => Self::is_integer_day_offset_expr(&op.this),
9945 Expression::Paren(p) => Self::is_integer_day_offset_expr(&p.this),
9946 _ => false,
9947 }
9948 }
9949
9950 fn build_tsql_datediff_days(start: Expression, end: Expression) -> Expression {
9951 Expression::Function(Box::new(Function::new(
9952 "DATEDIFF".to_string(),
9953 vec![Expression::Identifier(Identifier::new("DAY")), start, end],
9954 )))
9955 }
9956
9957 fn build_tsql_dateadd_days(date: Expression, amount: Expression, subtract: bool) -> Expression {
9958 Expression::Function(Box::new(Function::new(
9959 "DATEADD".to_string(),
9960 vec![
9961 Expression::Identifier(Identifier::new("DAY")),
9962 Self::tsql_dateadd_amount(amount, subtract),
9963 date,
9964 ],
9965 )))
9966 }
9967
9968 fn build_tsql_dateadd_from_interval(
9969 date: Expression,
9970 interval: &Expression,
9971 subtract: bool,
9972 ) -> Expression {
9973 let (value, unit) = Self::extract_interval_parts(interval)
9974 .unwrap_or_else(|| (interval.clone(), crate::expressions::IntervalUnit::Day));
9975 let unit = normalization::temporal::interval_unit_to_string(&unit);
9976 let amount = Self::tsql_dateadd_amount(value, subtract);
9977
9978 Expression::Function(Box::new(Function::new(
9979 "DATEADD".to_string(),
9980 vec![Expression::Identifier(Identifier::new(unit)), amount, date],
9981 )))
9982 }
9983
9984 fn tsql_dateadd_amount(value: Expression, negate: bool) -> Expression {
9985 use crate::expressions::{Parameter, ParameterStyle, UnaryOp};
9986
9987 fn numeric_literal_value(value: &Expression) -> Option<&str> {
9988 match value {
9989 Expression::Literal(lit) => match lit.as_ref() {
9990 crate::expressions::Literal::Number(n)
9991 | crate::expressions::Literal::String(n) => Some(n.as_str()),
9992 _ => None,
9993 },
9994 _ => None,
9995 }
9996 }
9997
9998 fn colon_parameter(value: &Expression) -> Option<Expression> {
9999 let Expression::Literal(lit) = value else {
10000 return None;
10001 };
10002 let crate::expressions::Literal::String(s) = lit.as_ref() else {
10003 return None;
10004 };
10005 let name = s.strip_prefix(':')?;
10006 if name.is_empty()
10007 || !name
10008 .chars()
10009 .all(|ch| ch.is_ascii_alphanumeric() || ch == '_')
10010 {
10011 return None;
10012 }
10013
10014 Some(Expression::Parameter(Box::new(Parameter {
10015 name: if name.chars().all(|ch| ch.is_ascii_digit()) {
10016 None
10017 } else {
10018 Some(name.to_string())
10019 },
10020 index: name.parse::<u32>().ok(),
10021 style: ParameterStyle::Colon,
10022 quoted: false,
10023 string_quoted: false,
10024 expression: None,
10025 })))
10026 }
10027
10028 let value = colon_parameter(&value).unwrap_or(value);
10029
10030 if let Some(n) = numeric_literal_value(&value) {
10031 if let Ok(parsed) = n.parse::<f64>() {
10032 let normalized = if negate { -parsed } else { parsed };
10033 let rendered = if normalized.fract() == 0.0 {
10034 format!("{}", normalized as i64)
10035 } else {
10036 normalized.to_string()
10037 };
10038 return Expression::Literal(Box::new(crate::expressions::Literal::Number(
10039 rendered,
10040 )));
10041 }
10042 }
10043
10044 if !negate {
10045 return value;
10046 }
10047
10048 match value {
10049 Expression::Neg(op) => op.this,
10050 other => Expression::Neg(Box::new(UnaryOp {
10051 this: other,
10052 inferred_type: None,
10053 })),
10054 }
10055 }
10056
10057 const PRESERVED_TO_DATE: &'static str = "_POLYGLOT_TO_DATE";
10061}
10062
10063#[cfg(test)]
10064mod tests {
10065 use super::*;
10066
10067 #[test]
10068 fn built_in_dialect_instances_share_tokenizer_config() {
10069 let first = Dialect::get(DialectType::PostgreSQL);
10070 let second = Dialect::get(DialectType::PostgreSQL);
10071
10072 assert!(first.tokenizer.shares_config_with(&second.tokenizer));
10073 }
10074
10075 #[test]
10076 fn test_dialect_type_from_str() {
10077 assert_eq!(
10078 "postgres".parse::<DialectType>().unwrap(),
10079 DialectType::PostgreSQL
10080 );
10081 assert_eq!(
10082 "postgresql".parse::<DialectType>().unwrap(),
10083 DialectType::PostgreSQL
10084 );
10085 assert_eq!("mysql".parse::<DialectType>().unwrap(), DialectType::MySQL);
10086 assert_eq!(
10087 "bigquery".parse::<DialectType>().unwrap(),
10088 DialectType::BigQuery
10089 );
10090 }
10091
10092 #[test]
10093 fn test_basic_transpile() {
10094 let dialect = Dialect::get(DialectType::Generic);
10095 let result = dialect
10096 .transpile("SELECT 1", DialectType::PostgreSQL)
10097 .unwrap();
10098 assert_eq!(result.len(), 1);
10099 assert_eq!(result[0], "SELECT 1");
10100 }
10101
10102 #[test]
10103 fn test_sqlite_double_quoted_column_defaults_to_postgres_strings() {
10104 let sqlite = Dialect::get(DialectType::SQLite);
10105 let result = sqlite
10106 .transpile(
10107 r#"CREATE TABLE "_collections" (
10108 "type" TEXT DEFAULT "base" NOT NULL,
10109 "fields" JSON DEFAULT "[]" NOT NULL,
10110 "options" JSON DEFAULT "{}" NOT NULL
10111 )"#,
10112 DialectType::PostgreSQL,
10113 )
10114 .unwrap();
10115
10116 assert!(result[0].contains(r#""type" TEXT DEFAULT 'base' NOT NULL"#));
10117 assert!(result[0].contains(r#""fields" JSON DEFAULT '[]' NOT NULL"#));
10118 assert!(result[0].contains(r#""options" JSON DEFAULT '{}' NOT NULL"#));
10119 }
10120
10121 #[test]
10122 fn test_sqlite_identity_preserves_double_quoted_column_defaults() {
10123 let sqlite = Dialect::get(DialectType::SQLite);
10124 let result = sqlite
10125 .transpile(
10126 r#"CREATE TABLE "_collections" ("type" TEXT DEFAULT "base" NOT NULL)"#,
10127 DialectType::SQLite,
10128 )
10129 .unwrap();
10130
10131 assert_eq!(
10132 result[0],
10133 r#"CREATE TABLE "_collections" ("type" TEXT DEFAULT "base" NOT NULL)"#
10134 );
10135 }
10136
10137 #[test]
10138 fn test_function_transformation_mysql() {
10139 let dialect = Dialect::get(DialectType::Generic);
10141 let result = dialect
10142 .transpile("SELECT NVL(a, b)", DialectType::MySQL)
10143 .unwrap();
10144 assert_eq!(result[0], "SELECT IFNULL(a, b)");
10145 }
10146
10147 #[test]
10148 fn test_get_path_duckdb() {
10149 let snowflake = Dialect::get(DialectType::Snowflake);
10151
10152 let result_sf_sf = snowflake
10154 .transpile(
10155 "SELECT PARSE_JSON('{\"fruit\":\"banana\"}'):fruit",
10156 DialectType::Snowflake,
10157 )
10158 .unwrap();
10159 eprintln!("Snowflake->Snowflake colon: {}", result_sf_sf[0]);
10160
10161 let result_sf_dk = snowflake
10163 .transpile(
10164 "SELECT PARSE_JSON('{\"fruit\":\"banana\"}'):fruit",
10165 DialectType::DuckDB,
10166 )
10167 .unwrap();
10168 eprintln!("Snowflake->DuckDB colon: {}", result_sf_dk[0]);
10169
10170 let result_gp = snowflake
10172 .transpile(
10173 "SELECT GET_PATH(PARSE_JSON('{\"fruit\":\"banana\"}'), 'fruit')",
10174 DialectType::DuckDB,
10175 )
10176 .unwrap();
10177 eprintln!("Snowflake->DuckDB explicit GET_PATH: {}", result_gp[0]);
10178 }
10179
10180 #[test]
10181 fn test_function_transformation_postgres() {
10182 let dialect = Dialect::get(DialectType::Generic);
10184 let result = dialect
10185 .transpile("SELECT IFNULL(a, b)", DialectType::PostgreSQL)
10186 .unwrap();
10187 assert_eq!(result[0], "SELECT COALESCE(a, b)");
10188
10189 let result = dialect
10191 .transpile("SELECT NVL(a, b)", DialectType::PostgreSQL)
10192 .unwrap();
10193 assert_eq!(result[0], "SELECT COALESCE(a, b)");
10194 }
10195
10196 #[test]
10197 fn test_hive_cast_to_trycast() {
10198 let hive = Dialect::get(DialectType::Hive);
10200 let result = hive
10201 .transpile("CAST(1 AS INT)", DialectType::DuckDB)
10202 .unwrap();
10203 assert_eq!(result[0], "TRY_CAST(1 AS INT)");
10204
10205 let result = hive
10206 .transpile("CAST(1 AS INT)", DialectType::Presto)
10207 .unwrap();
10208 assert_eq!(result[0], "TRY_CAST(1 AS INTEGER)");
10209 }
10210
10211 #[test]
10212 fn test_hive_array_identity() {
10213 let sql = "CREATE EXTERNAL TABLE `my_table` (`a7` ARRAY<DATE>) ROW FORMAT SERDE 'a' STORED AS INPUTFORMAT 'b' OUTPUTFORMAT 'c' LOCATION 'd' TBLPROPERTIES ('e'='f')";
10215 let hive = Dialect::get(DialectType::Hive);
10216
10217 let result = hive.transpile(sql, DialectType::Hive).unwrap();
10219 eprintln!("Hive ARRAY via transpile: {}", result[0]);
10220 assert!(
10221 result[0].contains("ARRAY<DATE>"),
10222 "transpile: Expected ARRAY<DATE>, got: {}",
10223 result[0]
10224 );
10225
10226 let ast = hive.parse(sql).unwrap();
10228 let transformed = hive.transform(ast[0].clone()).unwrap();
10229 let output = hive.generate(&transformed).unwrap();
10230 eprintln!("Hive ARRAY via identity path: {}", output);
10231 assert!(
10232 output.contains("ARRAY<DATE>"),
10233 "identity path: Expected ARRAY<DATE>, got: {}",
10234 output
10235 );
10236 }
10237
10238 #[test]
10239 fn test_starrocks_delete_between_expansion() {
10240 let dialect = Dialect::get(DialectType::Generic);
10242
10243 let result = dialect
10245 .transpile(
10246 "DELETE FROM t WHERE a BETWEEN b AND c",
10247 DialectType::StarRocks,
10248 )
10249 .unwrap();
10250 assert_eq!(result[0], "DELETE FROM t WHERE a >= b AND a <= c");
10251
10252 let result = dialect
10254 .transpile(
10255 "DELETE FROM t WHERE a NOT BETWEEN b AND c",
10256 DialectType::StarRocks,
10257 )
10258 .unwrap();
10259 assert_eq!(result[0], "DELETE FROM t WHERE a < b OR a > c");
10260
10261 let result = dialect
10263 .transpile(
10264 "SELECT * FROM t WHERE a BETWEEN b AND c",
10265 DialectType::StarRocks,
10266 )
10267 .unwrap();
10268 assert!(
10269 result[0].contains("BETWEEN"),
10270 "BETWEEN should be preserved in SELECT"
10271 );
10272 }
10273
10274 #[test]
10275 fn test_snowflake_ltrim_rtrim_parse() {
10276 let sf = Dialect::get(DialectType::Snowflake);
10277 let sql = "SELECT LTRIM(RTRIM(col)) FROM t1";
10278 let result = sf.transpile(sql, DialectType::DuckDB);
10279 match &result {
10280 Ok(r) => eprintln!("LTRIM/RTRIM result: {}", r[0]),
10281 Err(e) => eprintln!("LTRIM/RTRIM error: {}", e),
10282 }
10283 assert!(
10284 result.is_ok(),
10285 "Expected successful parse of LTRIM(RTRIM(col)), got error: {:?}",
10286 result.err()
10287 );
10288 }
10289
10290 #[test]
10291 fn test_duckdb_count_if_parse() {
10292 let duck = Dialect::get(DialectType::DuckDB);
10293 let sql = "COUNT_IF(x)";
10294 let result = duck.transpile(sql, DialectType::DuckDB);
10295 match &result {
10296 Ok(r) => eprintln!("COUNT_IF result: {}", r[0]),
10297 Err(e) => eprintln!("COUNT_IF error: {}", e),
10298 }
10299 assert!(
10300 result.is_ok(),
10301 "Expected successful parse of COUNT_IF(x), got error: {:?}",
10302 result.err()
10303 );
10304 }
10305
10306 #[test]
10307 fn test_tsql_cast_tinyint_parse() {
10308 let tsql = Dialect::get(DialectType::TSQL);
10309 let sql = "CAST(X AS TINYINT)";
10310 let result = tsql.transpile(sql, DialectType::DuckDB);
10311 match &result {
10312 Ok(r) => eprintln!("TSQL CAST TINYINT result: {}", r[0]),
10313 Err(e) => eprintln!("TSQL CAST TINYINT error: {}", e),
10314 }
10315 assert!(
10316 result.is_ok(),
10317 "Expected successful transpile, got error: {:?}",
10318 result.err()
10319 );
10320 }
10321
10322 #[test]
10323 fn test_pg_hash_bitwise_xor() {
10324 let dialect = Dialect::get(DialectType::PostgreSQL);
10325 let result = dialect.transpile("x # y", DialectType::PostgreSQL).unwrap();
10326 assert_eq!(result[0], "x # y");
10327 }
10328
10329 #[test]
10330 fn test_pg_array_to_duckdb() {
10331 let dialect = Dialect::get(DialectType::PostgreSQL);
10332 let result = dialect
10333 .transpile("SELECT ARRAY[1, 2, 3] @> ARRAY[1, 2]", DialectType::DuckDB)
10334 .unwrap();
10335 assert_eq!(result[0], "SELECT [1, 2, 3] @> [1, 2]");
10336 }
10337
10338 #[test]
10339 fn test_array_remove_bigquery() {
10340 let dialect = Dialect::get(DialectType::Generic);
10341 let result = dialect
10342 .transpile("ARRAY_REMOVE(the_array, target)", DialectType::BigQuery)
10343 .unwrap();
10344 assert_eq!(
10345 result[0],
10346 "ARRAY(SELECT _u FROM UNNEST(the_array) AS _u WHERE _u <> target)"
10347 );
10348 }
10349
10350 #[test]
10351 fn test_map_clickhouse_case() {
10352 let dialect = Dialect::get(DialectType::Generic);
10353 let parsed = dialect
10354 .parse("CAST(MAP('a', '1') AS MAP(TEXT, TEXT))")
10355 .unwrap();
10356 eprintln!("MAP parsed: {:?}", parsed);
10357 let result = dialect
10358 .transpile(
10359 "CAST(MAP('a', '1') AS MAP(TEXT, TEXT))",
10360 DialectType::ClickHouse,
10361 )
10362 .unwrap();
10363 eprintln!("MAP result: {}", result[0]);
10364 }
10365
10366 #[test]
10367 fn test_generate_date_array_presto() {
10368 let dialect = Dialect::get(DialectType::Generic);
10369 let result = dialect.transpile(
10370 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10371 DialectType::Presto,
10372 ).unwrap();
10373 eprintln!("GDA -> Presto: {}", result[0]);
10374 assert_eq!(result[0], "SELECT * FROM UNNEST(SEQUENCE(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), (1 * INTERVAL '7' DAY)))");
10375 }
10376
10377 #[test]
10378 fn test_generate_date_array_postgres() {
10379 let dialect = Dialect::get(DialectType::Generic);
10380 let result = dialect.transpile(
10381 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10382 DialectType::PostgreSQL,
10383 ).unwrap();
10384 eprintln!("GDA -> PostgreSQL: {}", result[0]);
10385 }
10386
10387 #[test]
10388 fn test_generate_date_array_snowflake() {
10389 let dialect = Dialect::get(DialectType::Generic);
10390 let result = dialect
10391 .transpile(
10392 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10393 DialectType::Snowflake,
10394 )
10395 .unwrap();
10396 eprintln!("GDA -> Snowflake: {}", result[0]);
10397 }
10398
10399 #[test]
10400 fn test_array_length_generate_date_array_snowflake() {
10401 let dialect = Dialect::get(DialectType::Generic);
10402 let result = dialect.transpile(
10403 "SELECT ARRAY_LENGTH(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10404 DialectType::Snowflake,
10405 ).unwrap();
10406 eprintln!("ARRAY_LENGTH(GDA) -> Snowflake: {}", result[0]);
10407 }
10408
10409 #[test]
10410 fn test_generate_date_array_mysql() {
10411 let dialect = Dialect::get(DialectType::Generic);
10412 let result = dialect.transpile(
10413 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10414 DialectType::MySQL,
10415 ).unwrap();
10416 eprintln!("GDA -> MySQL: {}", result[0]);
10417 }
10418
10419 #[test]
10420 fn test_generate_date_array_redshift() {
10421 let dialect = Dialect::get(DialectType::Generic);
10422 let result = dialect.transpile(
10423 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10424 DialectType::Redshift,
10425 ).unwrap();
10426 eprintln!("GDA -> Redshift: {}", result[0]);
10427 }
10428
10429 #[test]
10430 fn test_generate_date_array_tsql() {
10431 let dialect = Dialect::get(DialectType::Generic);
10432 let result = dialect.transpile(
10433 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10434 DialectType::TSQL,
10435 ).unwrap();
10436 eprintln!("GDA -> TSQL: {}", result[0]);
10437 }
10438
10439 #[test]
10440 fn test_struct_colon_syntax() {
10441 let dialect = Dialect::get(DialectType::Generic);
10442 let result = dialect.transpile(
10444 "CAST((1, 2, 3, 4) AS STRUCT<a TINYINT, b SMALLINT, c INT, d BIGINT>)",
10445 DialectType::ClickHouse,
10446 );
10447 match result {
10448 Ok(r) => eprintln!("STRUCT no colon -> ClickHouse: {}", r[0]),
10449 Err(e) => eprintln!("STRUCT no colon error: {}", e),
10450 }
10451 let result = dialect.transpile(
10453 "CAST((1, 2, 3, 4) AS STRUCT<a: TINYINT, b: SMALLINT, c: INT, d: BIGINT>)",
10454 DialectType::ClickHouse,
10455 );
10456 match result {
10457 Ok(r) => eprintln!("STRUCT colon -> ClickHouse: {}", r[0]),
10458 Err(e) => eprintln!("STRUCT colon error: {}", e),
10459 }
10460 }
10461
10462 #[test]
10463 fn test_generate_date_array_cte_wrapped_mysql() {
10464 let dialect = Dialect::get(DialectType::Generic);
10465 let result = dialect.transpile(
10466 "WITH dates AS (SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))) SELECT * FROM dates",
10467 DialectType::MySQL,
10468 ).unwrap();
10469 eprintln!("GDA CTE -> MySQL: {}", result[0]);
10470 }
10471
10472 #[test]
10473 fn test_generate_date_array_cte_wrapped_tsql() {
10474 let dialect = Dialect::get(DialectType::Generic);
10475 let result = dialect.transpile(
10476 "WITH dates AS (SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))) SELECT * FROM dates",
10477 DialectType::TSQL,
10478 ).unwrap();
10479 eprintln!("GDA CTE -> TSQL: {}", result[0]);
10480 }
10481
10482 #[test]
10483 fn test_decode_literal_no_null_check() {
10484 let dialect = Dialect::get(DialectType::Oracle);
10486 let result = dialect
10487 .transpile("SELECT decode(1,2,3,4)", DialectType::DuckDB)
10488 .unwrap();
10489 assert_eq!(
10490 result[0], "SELECT CASE WHEN 1 = 2 THEN 3 ELSE 4 END",
10491 "Literal DECODE should not have IS NULL checks"
10492 );
10493 }
10494
10495 #[test]
10496 fn test_decode_column_vs_literal_no_null_check() {
10497 let dialect = Dialect::get(DialectType::Oracle);
10499 let result = dialect
10500 .transpile("SELECT decode(col, 2, 3, 4) FROM t", DialectType::DuckDB)
10501 .unwrap();
10502 assert_eq!(
10503 result[0], "SELECT CASE WHEN col = 2 THEN 3 ELSE 4 END FROM t",
10504 "Column vs literal DECODE should not have IS NULL checks"
10505 );
10506 }
10507
10508 #[test]
10509 fn test_decode_column_vs_column_keeps_null_check() {
10510 let dialect = Dialect::get(DialectType::Oracle);
10512 let result = dialect
10513 .transpile("SELECT decode(col, col2, 3, 4) FROM t", DialectType::DuckDB)
10514 .unwrap();
10515 assert!(
10516 result[0].contains("IS NULL"),
10517 "Column vs column DECODE should have IS NULL checks, got: {}",
10518 result[0]
10519 );
10520 }
10521
10522 #[test]
10523 fn test_decode_null_search() {
10524 let dialect = Dialect::get(DialectType::Oracle);
10526 let result = dialect
10527 .transpile("SELECT decode(col, NULL, 3, 4) FROM t", DialectType::DuckDB)
10528 .unwrap();
10529 assert_eq!(
10530 result[0],
10531 "SELECT CASE WHEN col IS NULL THEN 3 ELSE 4 END FROM t",
10532 );
10533 }
10534
10535 #[test]
10540 fn test_regexp_substr_snowflake_to_duckdb_2arg() {
10541 let dialect = Dialect::get(DialectType::Snowflake);
10542 let result = dialect
10543 .transpile("SELECT REGEXP_SUBSTR(s, 'pattern')", DialectType::DuckDB)
10544 .unwrap();
10545 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10546 }
10547
10548 #[test]
10549 fn test_regexp_substr_snowflake_to_duckdb_3arg_pos1() {
10550 let dialect = Dialect::get(DialectType::Snowflake);
10551 let result = dialect
10552 .transpile("SELECT REGEXP_SUBSTR(s, 'pattern', 1)", DialectType::DuckDB)
10553 .unwrap();
10554 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10555 }
10556
10557 #[test]
10558 fn test_regexp_substr_snowflake_to_duckdb_3arg_pos_gt1() {
10559 let dialect = Dialect::get(DialectType::Snowflake);
10560 let result = dialect
10561 .transpile("SELECT REGEXP_SUBSTR(s, 'pattern', 3)", DialectType::DuckDB)
10562 .unwrap();
10563 assert_eq!(
10564 result[0],
10565 "SELECT REGEXP_EXTRACT(NULLIF(SUBSTRING(s, 3), ''), 'pattern')"
10566 );
10567 }
10568
10569 #[test]
10570 fn test_regexp_substr_snowflake_to_duckdb_4arg_occ_gt1() {
10571 let dialect = Dialect::get(DialectType::Snowflake);
10572 let result = dialect
10573 .transpile(
10574 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 3)",
10575 DialectType::DuckDB,
10576 )
10577 .unwrap();
10578 assert_eq!(
10579 result[0],
10580 "SELECT ARRAY_EXTRACT(REGEXP_EXTRACT_ALL(s, 'pattern'), 3)"
10581 );
10582 }
10583
10584 #[test]
10585 fn test_regexp_substr_snowflake_to_duckdb_5arg_e_flag() {
10586 let dialect = Dialect::get(DialectType::Snowflake);
10587 let result = dialect
10588 .transpile(
10589 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e')",
10590 DialectType::DuckDB,
10591 )
10592 .unwrap();
10593 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10594 }
10595
10596 #[test]
10597 fn test_regexp_substr_snowflake_to_duckdb_6arg_group0() {
10598 let dialect = Dialect::get(DialectType::Snowflake);
10599 let result = dialect
10600 .transpile(
10601 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e', 0)",
10602 DialectType::DuckDB,
10603 )
10604 .unwrap();
10605 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10606 }
10607
10608 #[test]
10609 fn test_regexp_substr_snowflake_identity_strip_group0() {
10610 let dialect = Dialect::get(DialectType::Snowflake);
10611 let result = dialect
10612 .transpile(
10613 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e', 0)",
10614 DialectType::Snowflake,
10615 )
10616 .unwrap();
10617 assert_eq!(result[0], "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e')");
10618 }
10619
10620 #[test]
10621 fn test_regexp_substr_all_snowflake_to_duckdb_2arg() {
10622 let dialect = Dialect::get(DialectType::Snowflake);
10623 let result = dialect
10624 .transpile(
10625 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern')",
10626 DialectType::DuckDB,
10627 )
10628 .unwrap();
10629 assert_eq!(result[0], "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')");
10630 }
10631
10632 #[test]
10633 fn test_regexp_substr_all_snowflake_to_duckdb_3arg_pos_gt1() {
10634 let dialect = Dialect::get(DialectType::Snowflake);
10635 let result = dialect
10636 .transpile(
10637 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 3)",
10638 DialectType::DuckDB,
10639 )
10640 .unwrap();
10641 assert_eq!(
10642 result[0],
10643 "SELECT REGEXP_EXTRACT_ALL(SUBSTRING(s, 3), 'pattern')"
10644 );
10645 }
10646
10647 #[test]
10648 fn test_regexp_substr_all_snowflake_to_duckdb_5arg_e_flag() {
10649 let dialect = Dialect::get(DialectType::Snowflake);
10650 let result = dialect
10651 .transpile(
10652 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e')",
10653 DialectType::DuckDB,
10654 )
10655 .unwrap();
10656 assert_eq!(result[0], "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')");
10657 }
10658
10659 #[test]
10660 fn test_regexp_substr_all_snowflake_to_duckdb_6arg_group0() {
10661 let dialect = Dialect::get(DialectType::Snowflake);
10662 let result = dialect
10663 .transpile(
10664 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e', 0)",
10665 DialectType::DuckDB,
10666 )
10667 .unwrap();
10668 assert_eq!(result[0], "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')");
10669 }
10670
10671 #[test]
10672 fn test_regexp_substr_all_snowflake_identity_strip_group0() {
10673 let dialect = Dialect::get(DialectType::Snowflake);
10674 let result = dialect
10675 .transpile(
10676 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e', 0)",
10677 DialectType::Snowflake,
10678 )
10679 .unwrap();
10680 assert_eq!(
10681 result[0],
10682 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e')"
10683 );
10684 }
10685
10686 #[test]
10687 fn test_regexp_count_snowflake_to_duckdb_2arg() {
10688 let dialect = Dialect::get(DialectType::Snowflake);
10689 let result = dialect
10690 .transpile("SELECT REGEXP_COUNT(s, 'pattern')", DialectType::DuckDB)
10691 .unwrap();
10692 assert_eq!(
10693 result[0],
10694 "SELECT CASE WHEN 'pattern' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(s, 'pattern')) END"
10695 );
10696 }
10697
10698 #[test]
10699 fn test_regexp_count_snowflake_to_duckdb_3arg() {
10700 let dialect = Dialect::get(DialectType::Snowflake);
10701 let result = dialect
10702 .transpile("SELECT REGEXP_COUNT(s, 'pattern', 3)", DialectType::DuckDB)
10703 .unwrap();
10704 assert_eq!(
10705 result[0],
10706 "SELECT CASE WHEN 'pattern' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(SUBSTRING(s, 3), 'pattern')) END"
10707 );
10708 }
10709
10710 #[test]
10711 fn test_regexp_count_snowflake_to_duckdb_4arg_flags() {
10712 let dialect = Dialect::get(DialectType::Snowflake);
10713 let result = dialect
10714 .transpile(
10715 "SELECT REGEXP_COUNT(s, 'pattern', 1, 'i')",
10716 DialectType::DuckDB,
10717 )
10718 .unwrap();
10719 assert_eq!(
10720 result[0],
10721 "SELECT CASE WHEN '(?i)' || 'pattern' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(SUBSTRING(s, 1), '(?i)' || 'pattern')) END"
10722 );
10723 }
10724
10725 #[test]
10726 fn test_regexp_count_snowflake_to_duckdb_4arg_flags_literal_string() {
10727 let dialect = Dialect::get(DialectType::Snowflake);
10728 let result = dialect
10729 .transpile(
10730 "SELECT REGEXP_COUNT('Hello World', 'L', 1, 'im')",
10731 DialectType::DuckDB,
10732 )
10733 .unwrap();
10734 assert_eq!(
10735 result[0],
10736 "SELECT CASE WHEN '(?im)' || 'L' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(SUBSTRING('Hello World', 1), '(?im)' || 'L')) END"
10737 );
10738 }
10739
10740 #[test]
10741 fn test_regexp_replace_snowflake_to_duckdb_5arg_pos1_occ1() {
10742 let dialect = Dialect::get(DialectType::Snowflake);
10743 let result = dialect
10744 .transpile(
10745 "SELECT REGEXP_REPLACE(s, 'pattern', 'repl', 1, 1)",
10746 DialectType::DuckDB,
10747 )
10748 .unwrap();
10749 assert_eq!(result[0], "SELECT REGEXP_REPLACE(s, 'pattern', 'repl')");
10750 }
10751
10752 #[test]
10753 fn test_regexp_replace_snowflake_to_duckdb_5arg_pos_gt1_occ0() {
10754 let dialect = Dialect::get(DialectType::Snowflake);
10755 let result = dialect
10756 .transpile(
10757 "SELECT REGEXP_REPLACE(s, 'pattern', 'repl', 3, 0)",
10758 DialectType::DuckDB,
10759 )
10760 .unwrap();
10761 assert_eq!(
10762 result[0],
10763 "SELECT SUBSTRING(s, 1, 2) || REGEXP_REPLACE(SUBSTRING(s, 3), 'pattern', 'repl', 'g')"
10764 );
10765 }
10766
10767 #[test]
10768 fn test_regexp_replace_snowflake_to_duckdb_5arg_pos_gt1_occ1() {
10769 let dialect = Dialect::get(DialectType::Snowflake);
10770 let result = dialect
10771 .transpile(
10772 "SELECT REGEXP_REPLACE(s, 'pattern', 'repl', 3, 1)",
10773 DialectType::DuckDB,
10774 )
10775 .unwrap();
10776 assert_eq!(
10777 result[0],
10778 "SELECT SUBSTRING(s, 1, 2) || REGEXP_REPLACE(SUBSTRING(s, 3), 'pattern', 'repl')"
10779 );
10780 }
10781
10782 #[test]
10783 fn test_rlike_snowflake_to_duckdb_2arg() {
10784 let dialect = Dialect::get(DialectType::Snowflake);
10785 let result = dialect
10786 .transpile("SELECT RLIKE(a, b)", DialectType::DuckDB)
10787 .unwrap();
10788 assert_eq!(result[0], "SELECT REGEXP_FULL_MATCH(a, b)");
10789 }
10790
10791 #[test]
10792 fn test_rlike_snowflake_to_duckdb_3arg_flags() {
10793 let dialect = Dialect::get(DialectType::Snowflake);
10794 let result = dialect
10795 .transpile("SELECT RLIKE(a, b, 'i')", DialectType::DuckDB)
10796 .unwrap();
10797 assert_eq!(result[0], "SELECT REGEXP_FULL_MATCH(a, b, 'i')");
10798 }
10799
10800 #[test]
10801 fn test_regexp_extract_all_bigquery_to_snowflake_no_capture() {
10802 let dialect = Dialect::get(DialectType::BigQuery);
10803 let result = dialect
10804 .transpile(
10805 "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')",
10806 DialectType::Snowflake,
10807 )
10808 .unwrap();
10809 assert_eq!(result[0], "SELECT REGEXP_SUBSTR_ALL(s, 'pattern')");
10810 }
10811
10812 #[test]
10813 fn test_regexp_extract_all_bigquery_to_snowflake_with_capture() {
10814 let dialect = Dialect::get(DialectType::BigQuery);
10815 let result = dialect
10816 .transpile(
10817 "SELECT REGEXP_EXTRACT_ALL(s, '(a)[0-9]')",
10818 DialectType::Snowflake,
10819 )
10820 .unwrap();
10821 assert_eq!(
10822 result[0],
10823 "SELECT REGEXP_SUBSTR_ALL(s, '(a)[0-9]', 1, 1, 'c', 1)"
10824 );
10825 }
10826
10827 #[test]
10828 fn test_regexp_instr_snowflake_to_duckdb_2arg() {
10829 let dialect = Dialect::get(DialectType::Snowflake);
10830 let result = dialect
10831 .transpile("SELECT REGEXP_INSTR(s, 'pattern')", DialectType::DuckDB)
10832 .unwrap();
10833 assert!(
10834 result[0].contains("CASE WHEN"),
10835 "Expected CASE WHEN in result: {}",
10836 result[0]
10837 );
10838 assert!(
10839 result[0].contains("LIST_SUM"),
10840 "Expected LIST_SUM in result: {}",
10841 result[0]
10842 );
10843 }
10844
10845 #[test]
10846 fn test_array_except_generic_to_duckdb() {
10847 let dialect = Dialect::get(DialectType::Generic);
10848 let result = dialect
10849 .transpile(
10850 "SELECT ARRAY_EXCEPT(ARRAY(1, 2, 3), ARRAY(2))",
10851 DialectType::DuckDB,
10852 )
10853 .unwrap();
10854 eprintln!("ARRAY_EXCEPT Generic->DuckDB: {}", result[0]);
10855 assert!(
10856 result[0].contains("CASE WHEN"),
10857 "Expected CASE WHEN: {}",
10858 result[0]
10859 );
10860 assert!(
10861 result[0].contains("LIST_FILTER"),
10862 "Expected LIST_FILTER: {}",
10863 result[0]
10864 );
10865 assert!(
10866 result[0].contains("LIST_DISTINCT"),
10867 "Expected LIST_DISTINCT: {}",
10868 result[0]
10869 );
10870 assert!(
10871 result[0].contains("IS NOT DISTINCT FROM"),
10872 "Expected IS NOT DISTINCT FROM: {}",
10873 result[0]
10874 );
10875 assert!(
10876 result[0].contains("= 0"),
10877 "Expected = 0 filter: {}",
10878 result[0]
10879 );
10880 }
10881
10882 #[test]
10883 fn test_array_except_generic_to_snowflake() {
10884 let dialect = Dialect::get(DialectType::Generic);
10885 let result = dialect
10886 .transpile(
10887 "SELECT ARRAY_EXCEPT(ARRAY(1, 2, 3), ARRAY(2))",
10888 DialectType::Snowflake,
10889 )
10890 .unwrap();
10891 eprintln!("ARRAY_EXCEPT Generic->Snowflake: {}", result[0]);
10892 assert_eq!(result[0], "SELECT ARRAY_EXCEPT([1, 2, 3], [2])");
10893 }
10894
10895 #[test]
10896 fn test_array_except_generic_to_presto() {
10897 let dialect = Dialect::get(DialectType::Generic);
10898 let result = dialect
10899 .transpile(
10900 "SELECT ARRAY_EXCEPT(ARRAY(1, 2, 3), ARRAY(2))",
10901 DialectType::Presto,
10902 )
10903 .unwrap();
10904 eprintln!("ARRAY_EXCEPT Generic->Presto: {}", result[0]);
10905 assert_eq!(result[0], "SELECT ARRAY_EXCEPT(ARRAY[1, 2, 3], ARRAY[2])");
10906 }
10907
10908 #[test]
10909 fn test_array_except_snowflake_to_duckdb() {
10910 let dialect = Dialect::get(DialectType::Snowflake);
10911 let result = dialect
10912 .transpile("SELECT ARRAY_EXCEPT([1, 2, 3], [2])", DialectType::DuckDB)
10913 .unwrap();
10914 eprintln!("ARRAY_EXCEPT Snowflake->DuckDB: {}", result[0]);
10915 assert!(
10916 result[0].contains("CASE WHEN"),
10917 "Expected CASE WHEN: {}",
10918 result[0]
10919 );
10920 assert!(
10921 result[0].contains("LIST_TRANSFORM"),
10922 "Expected LIST_TRANSFORM: {}",
10923 result[0]
10924 );
10925 }
10926
10927 #[test]
10928 fn test_array_contains_snowflake_to_snowflake() {
10929 let dialect = Dialect::get(DialectType::Snowflake);
10930 let result = dialect
10931 .transpile(
10932 "SELECT ARRAY_CONTAINS(x, [1, NULL, 3])",
10933 DialectType::Snowflake,
10934 )
10935 .unwrap();
10936 eprintln!("ARRAY_CONTAINS Snowflake->Snowflake: {}", result[0]);
10937 assert_eq!(result[0], "SELECT ARRAY_CONTAINS(x, [1, NULL, 3])");
10938 }
10939
10940 #[test]
10941 fn test_array_contains_snowflake_to_duckdb() {
10942 let dialect = Dialect::get(DialectType::Snowflake);
10943 let result = dialect
10944 .transpile(
10945 "SELECT ARRAY_CONTAINS(x, [1, NULL, 3])",
10946 DialectType::DuckDB,
10947 )
10948 .unwrap();
10949 eprintln!("ARRAY_CONTAINS Snowflake->DuckDB: {}", result[0]);
10950 assert!(
10951 result[0].contains("CASE WHEN"),
10952 "Expected CASE WHEN: {}",
10953 result[0]
10954 );
10955 assert!(
10956 result[0].contains("NULLIF"),
10957 "Expected NULLIF: {}",
10958 result[0]
10959 );
10960 assert!(
10961 result[0].contains("ARRAY_CONTAINS"),
10962 "Expected ARRAY_CONTAINS: {}",
10963 result[0]
10964 );
10965 }
10966
10967 #[test]
10968 fn test_array_distinct_snowflake_to_duckdb() {
10969 let dialect = Dialect::get(DialectType::Snowflake);
10970 let result = dialect
10971 .transpile(
10972 "SELECT ARRAY_DISTINCT([1, 2, 2, 3, 1])",
10973 DialectType::DuckDB,
10974 )
10975 .unwrap();
10976 eprintln!("ARRAY_DISTINCT Snowflake->DuckDB: {}", result[0]);
10977 assert!(
10978 result[0].contains("CASE WHEN"),
10979 "Expected CASE WHEN: {}",
10980 result[0]
10981 );
10982 assert!(
10983 result[0].contains("LIST_DISTINCT"),
10984 "Expected LIST_DISTINCT: {}",
10985 result[0]
10986 );
10987 assert!(
10988 result[0].contains("LIST_APPEND"),
10989 "Expected LIST_APPEND: {}",
10990 result[0]
10991 );
10992 assert!(
10993 result[0].contains("LIST_FILTER"),
10994 "Expected LIST_FILTER: {}",
10995 result[0]
10996 );
10997 }
10998}