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