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