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