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