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