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