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::{is_aggregate, 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 if Self::node_has_subquery_in_aggregate_argument(node) {
4565 Self::push_unsupported_diagnostic(
4566 &mut diagnostics,
4567 "aggregate arguments containing subqueries",
4568 );
4569 }
4570 }
4571
4572 if !Self::target_supports_distinct_on(target) && Self::node_has_distinct_on(node) {
4573 Self::push_unsupported_diagnostic(&mut diagnostics, "DISTINCT ON");
4574 }
4575
4576 if !Self::target_supports_remaining_unnest(target) && Self::node_is_unnest(node) {
4577 Self::push_unsupported_diagnostic(&mut diagnostics, "UNNEST");
4578 }
4579
4580 if !Self::target_supports_remaining_explode(target) && Self::node_is_explode(node) {
4581 Self::push_unsupported_diagnostic(&mut diagnostics, "EXPLODE");
4582 }
4583
4584 if Self::target_lacks_array_agg(target) && Self::node_is_array_agg(node) {
4585 Self::push_unsupported_diagnostic(&mut diagnostics, "ARRAY_AGG");
4586 }
4587
4588 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4589 && Self::node_is_distinct_string_agg(node)
4590 {
4591 Self::push_unsupported_diagnostic(&mut diagnostics, "STRING_AGG with DISTINCT");
4592 }
4593
4594 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4595 && matches!(node, Expression::NthValue(_))
4596 {
4597 Self::push_unsupported_diagnostic(&mut diagnostics, "NTH_VALUE");
4598 }
4599
4600 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4601 if let Some(frame) = Self::node_window_frame(node) {
4602 if matches!(frame.kind, WindowFrameKind::Groups) {
4603 Self::push_unsupported_diagnostic(&mut diagnostics, "GROUPS window frames");
4604 }
4605 if matches!(frame.kind, WindowFrameKind::Range)
4606 && (Self::window_frame_bound_has_value_offset(&frame.start)
4607 || frame
4608 .end
4609 .as_ref()
4610 .is_some_and(Self::window_frame_bound_has_value_offset))
4611 {
4612 Self::push_unsupported_diagnostic(
4613 &mut diagnostics,
4614 "value-offset RANGE window frames",
4615 );
4616 }
4617 if frame.exclude.is_some() {
4618 Self::push_unsupported_diagnostic(
4619 &mut diagnostics,
4620 "window frame EXCLUDE clauses",
4621 );
4622 }
4623 }
4624 }
4625
4626 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4627 && Self::node_is_regex_predicate(node)
4628 {
4629 Self::push_unsupported_diagnostic(
4630 &mut diagnostics,
4631 "regular expression predicates",
4632 );
4633 }
4634
4635 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4636 && Self::node_is_non_subquery_any(node)
4637 {
4638 Self::push_unsupported_diagnostic(
4639 &mut diagnostics,
4640 "ANY over non-subquery expressions",
4641 );
4642 }
4643
4644 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4645 && Self::node_is_row_value_subquery_comparison(node)
4646 {
4647 Self::push_unsupported_diagnostic(
4648 &mut diagnostics,
4649 "row-value subquery comparisons",
4650 );
4651 }
4652
4653 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4654 && Self::node_is_row_value_values_membership(node)
4655 {
4656 Self::push_unsupported_diagnostic(
4657 &mut diagnostics,
4658 "row-value VALUES membership comparisons",
4659 );
4660 }
4661
4662 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4663 && Self::node_has_fetch_with_ties(node)
4664 {
4665 Self::push_unsupported_diagnostic(&mut diagnostics, "FETCH WITH TIES without TOP");
4666 }
4667
4668 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4669 && Self::node_is_overlaps(node)
4670 {
4671 Self::push_unsupported_diagnostic(&mut diagnostics, "OVERLAPS");
4672 }
4673
4674 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4675 && Self::node_is_date_bin(node)
4676 {
4677 Self::push_unsupported_diagnostic(&mut diagnostics, "DATE_BIN");
4678 }
4679
4680 if source == DialectType::PostgreSQL
4681 && matches!(target, DialectType::TSQL | DialectType::Fabric)
4682 && Self::node_is_unresolved_postgres_date_subtraction(node)
4683 {
4684 Self::push_unsupported_diagnostic(
4685 &mut diagnostics,
4686 "PostgreSQL date subtraction with an unresolved column type",
4687 );
4688 }
4689
4690 if matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4691 && !matches!(target, DialectType::PostgreSQL | DialectType::CockroachDB)
4692 {
4693 if Self::node_is_postgres_json_build_object(node)
4694 && !(matches!(target, DialectType::TSQL | DialectType::Fabric)
4695 && Self::postgres_json_build_object_can_lower_to_json_object(node))
4696 {
4697 Self::push_unsupported_diagnostic(
4698 &mut diagnostics,
4699 "PostgreSQL JSON_BUILD_OBJECT",
4700 );
4701 }
4702 if Self::node_is_function_named(node, "TO_TSVECTOR") {
4703 Self::push_unsupported_diagnostic(&mut diagnostics, "PostgreSQL TO_TSVECTOR");
4704 }
4705 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4706 if let Some(composite_semantics) =
4707 Self::postgres_tsql_unsupported_composite_semantics(
4708 node,
4709 structural_grouping_tuples.contains(&(node as *const Expression)),
4710 )
4711 {
4712 Self::push_unsupported_diagnostic(
4713 &mut diagnostics,
4714 &format!("PostgreSQL {composite_semantics}"),
4715 );
4716 }
4717 if Self::node_is_postgres_unknown_cast(node) {
4718 Self::push_unsupported_diagnostic(
4719 &mut diagnostics,
4720 "PostgreSQL unresolved UNKNOWN casts",
4721 );
4722 }
4723 if let Some(collation_name) =
4724 Self::postgres_tsql_unsupported_collation_name(node)
4725 {
4726 Self::push_unsupported_diagnostic(
4727 &mut diagnostics,
4728 &format!("PostgreSQL collation \"{collation_name}\""),
4729 );
4730 }
4731 if let Some(array_semantics) =
4732 Self::postgres_tsql_unsupported_array_semantics(node)
4733 {
4734 Self::push_unsupported_diagnostic(
4735 &mut diagnostics,
4736 &format!("PostgreSQL {array_semantics}"),
4737 );
4738 }
4739 if let Some(string_semantics) =
4740 Self::postgres_tsql_unsupported_string_semantics(node)
4741 {
4742 Self::push_unsupported_diagnostic(
4743 &mut diagnostics,
4744 &format!("PostgreSQL {string_semantics}"),
4745 );
4746 }
4747 if source == DialectType::PostgreSQL {
4748 if let Some(binary_semantics) =
4749 Self::postgres_tsql_unsupported_binary_semantics(node)
4750 {
4751 Self::push_unsupported_diagnostic(
4752 &mut diagnostics,
4753 &format!("PostgreSQL {binary_semantics}"),
4754 );
4755 }
4756 }
4757 if let Some(function_name) =
4758 Self::postgres_tsql_unsupported_function_name(node, target)
4759 {
4760 Self::push_unsupported_diagnostic(
4761 &mut diagnostics,
4762 &format!("PostgreSQL {function_name}"),
4763 );
4764 }
4765 }
4766 if matches!(target, DialectType::TSQL | DialectType::Fabric)
4767 && Self::node_is_postgres_type_function_cast(node)
4768 {
4769 Self::push_unsupported_diagnostic(
4770 &mut diagnostics,
4771 "PostgreSQL type-name function casts",
4772 );
4773 }
4774 }
4775
4776 if opts.unsupported_level == UnsupportedLevel::Immediate && !diagnostics.is_empty() {
4777 break;
4778 }
4779 }
4780
4781 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
4782 Self::collect_tsql_unsupported_ordered_sets(expr, &mut diagnostics);
4783 Self::collect_tsql_windows_missing_order(expr, &HashMap::new(), &mut diagnostics);
4784 }
4785
4786 if diagnostics.is_empty() {
4787 return Ok(());
4788 }
4789
4790 let limit = if opts.unsupported_level == UnsupportedLevel::Immediate {
4791 1
4792 } else {
4793 opts.max_unsupported.max(1)
4794 };
4795 let mut messages = diagnostics.iter().take(limit).cloned().collect::<Vec<_>>();
4796 if diagnostics.len() > limit {
4797 messages.push(format!("... and {} more", diagnostics.len() - limit));
4798 }
4799
4800 Err(crate::error::Error::unsupported(
4801 messages.join("; "),
4802 target.to_string(),
4803 ))
4804 }
4805
4806 fn reject_postgres_tsql_strict_regex_predicates(
4807 expr: &Expression,
4808 source: DialectType,
4809 target: DialectType,
4810 opts: &TranspileOptions,
4811 ) -> Result<()> {
4812 if !matches!(
4813 opts.unsupported_level,
4814 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4815 ) || !matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4816 || !matches!(target, DialectType::TSQL | DialectType::Fabric)
4817 {
4818 return Ok(());
4819 }
4820
4821 if expr.dfs().any(Self::node_is_regex_predicate) {
4822 return Err(crate::error::Error::unsupported(
4823 "regular expression predicates",
4824 target.to_string(),
4825 ));
4826 }
4827
4828 Ok(())
4829 }
4830
4831 fn reject_tsql_strict_json_constructor_return_types(
4832 expr: &Expression,
4833 source: DialectType,
4834 target: DialectType,
4835 opts: &TranspileOptions,
4836 ) -> Result<()> {
4837 if !matches!(
4838 opts.unsupported_level,
4839 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4840 ) || source == target
4841 || !matches!(target, DialectType::TSQL | DialectType::Fabric)
4842 {
4843 return Ok(());
4844 }
4845
4846 let mut diagnostics = Vec::new();
4847 for node in expr.dfs() {
4848 if let Some(return_type) =
4849 normalization::unsupported_tsql_json_constructor_return_type(node)
4850 {
4851 let message =
4852 format!("SQL/JSON constructor RETURNING {return_type} cannot be preserved");
4853 Self::push_unsupported_diagnostic(&mut diagnostics, &message);
4854 if opts.unsupported_level == UnsupportedLevel::Immediate {
4855 break;
4856 }
4857 }
4858 }
4859
4860 if diagnostics.is_empty() {
4861 return Ok(());
4862 }
4863
4864 let limit = if opts.unsupported_level == UnsupportedLevel::Immediate {
4865 1
4866 } else {
4867 opts.max_unsupported.max(1)
4868 };
4869 let mut messages = diagnostics.iter().take(limit).cloned().collect::<Vec<_>>();
4870 if diagnostics.len() > limit {
4871 messages.push(format!("... and {} more", diagnostics.len() - limit));
4872 }
4873
4874 Err(crate::error::Error::unsupported(
4875 messages.join("; "),
4876 target.to_string(),
4877 ))
4878 }
4879
4880 fn reject_postgres_tsql_strict_json_aggregate_modifiers(
4881 expr: &Expression,
4882 source: DialectType,
4883 target: DialectType,
4884 opts: &TranspileOptions,
4885 ) -> Result<()> {
4886 if !matches!(
4887 opts.unsupported_level,
4888 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
4889 ) || !matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4890 || !matches!(target, DialectType::TSQL | DialectType::Fabric)
4891 {
4892 return Ok(());
4893 }
4894
4895 let mut diagnostics = Vec::new();
4896 for node in expr.dfs() {
4897 match node {
4898 Expression::Function(function)
4899 if !function.quoted
4900 && matches!(
4901 function.name.to_ascii_uppercase().as_str(),
4902 "JSON_AGG" | "JSONB_AGG"
4903 ) =>
4904 {
4905 let name = function.name.to_ascii_uppercase();
4906 if function.args.len() != 1 {
4907 Self::push_unsupported_diagnostic(
4908 &mut diagnostics,
4909 &format!("PostgreSQL {name} with invalid argument count"),
4910 );
4911 }
4912 if function.distinct {
4913 Self::push_unsupported_diagnostic(
4914 &mut diagnostics,
4915 &format!("PostgreSQL {name} with DISTINCT"),
4916 );
4917 }
4918 }
4919 Expression::AggregateFunction(function)
4920 if matches!(
4921 function.name.to_ascii_uppercase().as_str(),
4922 "JSON_AGG" | "JSONB_AGG"
4923 ) =>
4924 {
4925 let name = function.name.to_ascii_uppercase();
4926 if function.args.len() != 1 {
4927 Self::push_unsupported_diagnostic(
4928 &mut diagnostics,
4929 &format!("PostgreSQL {name} with invalid argument count"),
4930 );
4931 }
4932 if function.distinct {
4933 Self::push_unsupported_diagnostic(
4934 &mut diagnostics,
4935 &format!("PostgreSQL {name} with DISTINCT"),
4936 );
4937 }
4938 if function.filter.is_some() {
4939 Self::push_unsupported_diagnostic(
4940 &mut diagnostics,
4941 &format!("PostgreSQL {name} with FILTER"),
4942 );
4943 }
4944 if function.limit.is_some() || function.ignore_nulls.is_some() {
4945 Self::push_unsupported_diagnostic(
4946 &mut diagnostics,
4947 &format!("PostgreSQL {name} with unsupported aggregate modifiers"),
4948 );
4949 }
4950 }
4951 Expression::Filter(filter) => {
4952 if let Some(name) = Self::postgres_json_aggregate_name(&filter.this) {
4953 Self::push_unsupported_diagnostic(
4954 &mut diagnostics,
4955 &format!("PostgreSQL {name} with FILTER"),
4956 );
4957 }
4958 }
4959 _ => {}
4960 }
4961
4962 if opts.unsupported_level == UnsupportedLevel::Immediate && !diagnostics.is_empty() {
4963 break;
4964 }
4965 }
4966
4967 if diagnostics.is_empty() {
4968 return Ok(());
4969 }
4970
4971 let limit = if opts.unsupported_level == UnsupportedLevel::Immediate {
4972 1
4973 } else {
4974 opts.max_unsupported.max(1)
4975 };
4976 let mut messages = diagnostics.iter().take(limit).cloned().collect::<Vec<_>>();
4977 if diagnostics.len() > limit {
4978 messages.push(format!("... and {} more", diagnostics.len() - limit));
4979 }
4980
4981 Err(crate::error::Error::unsupported(
4982 messages.join("; "),
4983 target.to_string(),
4984 ))
4985 }
4986
4987 fn postgres_json_aggregate_name(expr: &Expression) -> Option<String> {
4988 let name = match expr {
4989 Expression::Function(function) if !function.quoted => &function.name,
4990 Expression::AggregateFunction(function) => &function.name,
4991 _ => return None,
4992 };
4993 let name = name.to_ascii_uppercase();
4994 matches!(name.as_str(), "JSON_AGG" | "JSONB_AGG").then_some(name)
4995 }
4996
4997 fn push_unsupported_diagnostic(diagnostics: &mut Vec<String>, message: &str) {
4998 if !diagnostics.iter().any(|existing| existing == message) {
4999 diagnostics.push(message.to_string());
5000 }
5001 }
5002
5003 fn node_is_unresolved_postgres_date_subtraction(expr: &Expression) -> bool {
5004 let Expression::Sub(op) = expr else {
5005 return false;
5006 };
5007
5008 (Self::is_explicit_date_expr(&op.left) && Self::is_column_expr(&op.right))
5009 || (Self::is_column_expr(&op.left) && Self::is_explicit_date_expr(&op.right))
5010 }
5011
5012 fn is_column_expr(expr: &Expression) -> bool {
5013 match expr {
5014 Expression::Column(_) => true,
5015 Expression::Paren(paren) => Self::is_column_expr(&paren.this),
5016 _ => false,
5017 }
5018 }
5019
5020 fn node_window_frame(expr: &Expression) -> Option<&WindowFrame> {
5021 match expr {
5022 Expression::WindowFunction(window) => window.over.frame.as_ref(),
5023 Expression::Window(window) | Expression::WindowSpec(window) => window.frame.as_ref(),
5024 _ => None,
5025 }
5026 }
5027
5028 fn window_frame_bound_has_value_offset(bound: &WindowFrameBound) -> bool {
5029 matches!(
5030 bound,
5031 WindowFrameBound::Preceding(_)
5032 | WindowFrameBound::Following(_)
5033 | WindowFrameBound::Value(_)
5034 | WindowFrameBound::BarePreceding
5035 | WindowFrameBound::BareFollowing
5036 )
5037 }
5038
5039 fn collect_tsql_windows_missing_order(
5040 expr: &Expression,
5041 active_windows: &HashMap<String, Over>,
5042 diagnostics: &mut Vec<String>,
5043 ) {
5044 if let Expression::Select(select) = expr {
5045 let local_windows = select
5046 .windows
5047 .as_ref()
5048 .map(|windows| {
5049 windows
5050 .iter()
5051 .map(|window| (window.name.name.to_ascii_lowercase(), window.spec.clone()))
5052 .collect()
5053 })
5054 .unwrap_or_default();
5055
5056 for child in expr.children() {
5057 Self::collect_tsql_windows_missing_order(child, &local_windows, diagnostics);
5058 }
5059 return;
5060 }
5061
5062 if let Expression::WindowFunction(window) = expr {
5063 let (has_order, has_frame) = Self::effective_window_order_and_frame(
5064 &window.over,
5065 active_windows,
5066 &mut Vec::new(),
5067 );
5068
5069 if !has_order {
5070 if has_frame {
5071 Self::push_unsupported_diagnostic(
5072 diagnostics,
5073 "window frames without ORDER BY",
5074 );
5075 }
5076 if let Some(function_name) =
5077 Self::tsql_window_function_requiring_order(&window.this)
5078 {
5079 Self::push_unsupported_diagnostic(
5080 diagnostics,
5081 &format!("{function_name} without ORDER BY"),
5082 );
5083 }
5084 }
5085 }
5086
5087 for child in expr.children() {
5088 Self::collect_tsql_windows_missing_order(child, active_windows, diagnostics);
5089 }
5090 }
5091
5092 fn effective_window_order_and_frame(
5093 over: &Over,
5094 active_windows: &HashMap<String, Over>,
5095 seen: &mut Vec<String>,
5096 ) -> (bool, bool) {
5097 let inherited = over
5098 .window_name
5099 .as_ref()
5100 .and_then(|name| {
5101 let key = name.name.to_ascii_lowercase();
5102 if seen.iter().any(|seen_name| seen_name == &key) {
5103 return None;
5104 }
5105 let named = active_windows.get(&key)?;
5106 seen.push(key);
5107 let properties =
5108 Self::effective_window_order_and_frame(named, active_windows, seen);
5109 seen.pop();
5110 Some(properties)
5111 })
5112 .unwrap_or((false, false));
5113
5114 (
5115 !over.order_by.is_empty() || inherited.0,
5116 over.frame.is_some() || inherited.1,
5117 )
5118 }
5119
5120 fn tsql_window_function_requiring_order(expr: &Expression) -> Option<&'static str> {
5121 match expr {
5122 Expression::FirstValue(_) => Some("FIRST_VALUE"),
5123 Expression::LastValue(_) => Some("LAST_VALUE"),
5124 Expression::Function(function) if function.name.eq_ignore_ascii_case("FIRST_VALUE") => {
5125 Some("FIRST_VALUE")
5126 }
5127 Expression::Function(function) if function.name.eq_ignore_ascii_case("LAST_VALUE") => {
5128 Some("LAST_VALUE")
5129 }
5130 _ => None,
5131 }
5132 }
5133
5134 fn collect_tsql_unsupported_ordered_sets(expr: &Expression, diagnostics: &mut Vec<String>) {
5135 match expr {
5136 Expression::WindowFunction(window) => {
5137 if let Expression::WithinGroup(within_group) = &window.this {
5138 if Self::within_group_is_hypothetical_set(within_group) {
5139 Self::push_unsupported_diagnostic(
5140 diagnostics,
5141 "RANK/DENSE_RANK/CUME_DIST/PERCENT_RANK hypothetical-set aggregates",
5142 );
5143 return;
5144 }
5145
5146 if Self::within_group_is_mode(within_group) {
5147 Self::push_unsupported_diagnostic(
5148 diagnostics,
5149 "MODE ordered-set aggregates",
5150 );
5151 return;
5152 }
5153
5154 if Self::within_group_is_percentile(within_group) {
5155 if !window.over.order_by.is_empty() || window.over.frame.is_some() {
5156 Self::push_unsupported_diagnostic(
5157 diagnostics,
5158 "PERCENTILE_CONT/PERCENTILE_DISC window ORDER BY or frame clauses",
5159 );
5160 }
5161 return;
5162 }
5163 }
5164 }
5165 Expression::WithinGroup(within_group) => {
5166 if Self::within_group_is_hypothetical_set(within_group) {
5167 Self::push_unsupported_diagnostic(
5168 diagnostics,
5169 "RANK/DENSE_RANK/CUME_DIST/PERCENT_RANK hypothetical-set aggregates",
5170 );
5171 return;
5172 }
5173
5174 if Self::within_group_is_mode(within_group) {
5175 Self::push_unsupported_diagnostic(diagnostics, "MODE ordered-set aggregates");
5176 return;
5177 }
5178
5179 if Self::within_group_is_percentile(within_group) {
5180 Self::push_unsupported_diagnostic(
5181 diagnostics,
5182 "PERCENTILE_CONT/PERCENTILE_DISC ordered-set aggregates without OVER",
5183 );
5184 return;
5185 }
5186 }
5187 _ => {}
5188 }
5189
5190 for child in expr.children() {
5191 Self::collect_tsql_unsupported_ordered_sets(child, diagnostics);
5192 }
5193 }
5194
5195 fn within_group_is_hypothetical_set(within_group: &crate::expressions::WithinGroup) -> bool {
5196 match &within_group.this {
5197 Expression::Function(function) => Self::is_hypothetical_set_name(&function.name),
5198 Expression::AggregateFunction(function) => {
5199 Self::is_hypothetical_set_name(&function.name)
5200 }
5201 Expression::Rank(_)
5202 | Expression::DenseRank(_)
5203 | Expression::CumeDist(_)
5204 | Expression::PercentRank(_) => true,
5205 _ => false,
5206 }
5207 }
5208
5209 fn within_group_is_percentile(within_group: &crate::expressions::WithinGroup) -> bool {
5210 match &within_group.this {
5211 Expression::Function(function) => Self::is_percentile_ordered_set_name(&function.name),
5212 Expression::AggregateFunction(function) => {
5213 Self::is_percentile_ordered_set_name(&function.name)
5214 }
5215 Expression::PercentileCont(_) | Expression::PercentileDisc(_) => true,
5216 _ => false,
5217 }
5218 }
5219
5220 fn within_group_is_mode(within_group: &crate::expressions::WithinGroup) -> bool {
5221 match &within_group.this {
5222 Expression::Function(function) => function.name.eq_ignore_ascii_case("MODE"),
5223 Expression::AggregateFunction(function) => function.name.eq_ignore_ascii_case("MODE"),
5224 Expression::Mode(_) => true,
5225 _ => false,
5226 }
5227 }
5228
5229 fn is_percentile_ordered_set_name(name: &str) -> bool {
5230 name.eq_ignore_ascii_case("PERCENTILE_CONT") || name.eq_ignore_ascii_case("PERCENTILE_DISC")
5231 }
5232
5233 fn is_hypothetical_set_name(name: &str) -> bool {
5234 name.eq_ignore_ascii_case("RANK")
5235 || name.eq_ignore_ascii_case("DENSE_RANK")
5236 || name.eq_ignore_ascii_case("CUME_DIST")
5237 || name.eq_ignore_ascii_case("PERCENT_RANK")
5238 }
5239
5240 fn target_supports_distinct_on(target: DialectType) -> bool {
5241 matches!(target, DialectType::PostgreSQL | DialectType::DuckDB)
5242 }
5243
5244 fn node_has_distinct_on(expr: &Expression) -> bool {
5245 matches!(
5246 expr,
5247 Expression::Select(select)
5248 if select
5249 .distinct_on
5250 .as_ref()
5251 .is_some_and(|distinct_on| !distinct_on.is_empty())
5252 )
5253 }
5254
5255 fn node_has_recursive_with(expr: &Expression) -> bool {
5256 fn recursive(with: &Option<With>) -> bool {
5257 with.as_ref().is_some_and(|with| with.recursive)
5258 }
5259
5260 match expr {
5261 Expression::With(with) => with.recursive,
5262 Expression::Select(select) => recursive(&select.with),
5263 Expression::Union(union) => recursive(&union.with),
5264 Expression::Intersect(intersect) => recursive(&intersect.with),
5265 Expression::Except(except) => recursive(&except.with),
5266 Expression::Pivot(pivot) => recursive(&pivot.with),
5267 Expression::Insert(insert) => recursive(&insert.with),
5268 Expression::Update(update) => recursive(&update.with),
5269 Expression::Delete(delete) => recursive(&delete.with),
5270 _ => false,
5271 }
5272 }
5273
5274 fn node_has_lateral(expr: &Expression) -> bool {
5275 fn join_has_lateral(join: &Join) -> bool {
5276 matches!(
5277 join.kind,
5278 crate::expressions::JoinKind::Lateral | crate::expressions::JoinKind::LeftLateral
5279 ) || Dialect::node_has_lateral(&join.this)
5280 || join.on.as_ref().is_some_and(Dialect::node_has_lateral)
5281 || join
5282 .match_condition
5283 .as_ref()
5284 .is_some_and(Dialect::node_has_lateral)
5285 || join.pivots.iter().any(Dialect::node_has_lateral)
5286 }
5287
5288 fn joins_have_lateral(joins: &[Join]) -> bool {
5289 joins.iter().any(join_has_lateral)
5290 }
5291
5292 match expr {
5293 Expression::Subquery(subquery) => {
5294 subquery.lateral || Dialect::node_has_lateral(&subquery.this)
5295 }
5296 Expression::Lateral(_) | Expression::LateralView(_) => true,
5297 Expression::Join(join) => join_has_lateral(join),
5298 Expression::Select(select) => {
5299 !select.lateral_views.is_empty()
5300 || joins_have_lateral(&select.joins)
5301 || select
5302 .from
5303 .as_ref()
5304 .is_some_and(|from| from.expressions.iter().any(Dialect::node_has_lateral))
5305 }
5306 Expression::JoinedTable(joined) => {
5307 !joined.lateral_views.is_empty()
5308 || Dialect::node_has_lateral(&joined.left)
5309 || joins_have_lateral(&joined.joins)
5310 }
5311 Expression::Update(update) => {
5312 joins_have_lateral(&update.table_joins) || joins_have_lateral(&update.from_joins)
5313 }
5314 _ => false,
5315 }
5316 }
5317
5318 fn node_has_join_using(expr: &Expression) -> bool {
5319 fn has_using(joins: &[Join]) -> bool {
5320 joins.iter().any(|join| !join.using.is_empty())
5321 }
5322
5323 match expr {
5324 Expression::Join(join) => !join.using.is_empty(),
5325 Expression::Select(select) => has_using(&select.joins),
5326 Expression::JoinedTable(joined) => has_using(&joined.joins),
5327 Expression::Update(update) => {
5328 has_using(&update.table_joins) || has_using(&update.from_joins)
5329 }
5330 Expression::Delete(delete) => has_using(&delete.joins),
5331 _ => false,
5332 }
5333 }
5334
5335 fn node_has_natural_join(expr: &Expression) -> bool {
5336 fn is_natural(join: &Join) -> bool {
5337 matches!(
5338 join.kind,
5339 crate::expressions::JoinKind::Natural
5340 | crate::expressions::JoinKind::NaturalLeft
5341 | crate::expressions::JoinKind::NaturalRight
5342 | crate::expressions::JoinKind::NaturalFull
5343 )
5344 }
5345
5346 fn has_natural(joins: &[Join]) -> bool {
5347 joins.iter().any(is_natural)
5348 }
5349
5350 match expr {
5351 Expression::Join(join) => is_natural(join),
5352 Expression::Select(select) => has_natural(&select.joins),
5353 Expression::JoinedTable(joined) => has_natural(&joined.joins),
5354 Expression::Update(update) => {
5355 has_natural(&update.table_joins) || has_natural(&update.from_joins)
5356 }
5357 Expression::Delete(delete) => has_natural(&delete.joins),
5358 _ => false,
5359 }
5360 }
5361
5362 fn node_has_unsupported_relation_column_aliases(expr: &Expression) -> bool {
5363 match expr {
5364 Expression::Table(table) => !table.column_aliases.is_empty(),
5365 Expression::Alias(alias) => {
5366 !alias.column_aliases.is_empty()
5367 && matches!(
5368 alias.this,
5369 Expression::Table(_) | Expression::JoinedTable(_)
5370 )
5371 }
5372 _ => false,
5373 }
5374 }
5375
5376 fn node_is_aggregate_function(expr: &Expression) -> bool {
5377 is_aggregate(expr)
5378 }
5379
5380 fn node_has_qualified_whole_row_aggregate_argument(expr: &Expression) -> bool {
5381 fn contains_qualified_star(expr: &Expression) -> bool {
5382 match expr {
5383 Expression::Star(star) => star.table.is_some(),
5384 Expression::Select(_)
5387 | Expression::Subquery(_)
5388 | Expression::Union(_)
5389 | Expression::Intersect(_)
5390 | Expression::Except(_) => false,
5391 _ => expr.children().into_iter().any(contains_qualified_star),
5392 }
5393 }
5394
5395 Self::node_is_aggregate_function(expr)
5396 && expr.children().into_iter().any(contains_qualified_star)
5397 }
5398
5399 fn node_has_subquery_in_aggregate_argument(expr: &Expression) -> bool {
5400 fn contains_query(expr: &Expression) -> bool {
5401 matches!(
5402 expr,
5403 Expression::Select(_)
5404 | Expression::Subquery(_)
5405 | Expression::Union(_)
5406 | Expression::Intersect(_)
5407 | Expression::Except(_)
5408 ) || expr.children().into_iter().any(contains_query)
5409 }
5410
5411 Self::node_is_aggregate_function(expr) && expr.children().into_iter().any(contains_query)
5412 }
5413
5414 fn tsql_apply_has_invalid_outer_aggregate(expr: &Expression) -> bool {
5415 fn collect_source_names(expr: &Expression, names: &mut HashSet<String>) {
5418 let mut insert = |name: &Identifier| {
5419 if !name.name.is_empty() {
5420 names.insert(name.name.to_ascii_lowercase());
5421 }
5422 };
5423
5424 match expr {
5425 Expression::Table(table) => {
5426 insert(table.alias.as_ref().unwrap_or(&table.name));
5427 }
5428 Expression::Subquery(subquery) => {
5429 if let Some(alias) = &subquery.alias {
5430 insert(alias);
5431 }
5432 }
5433 Expression::Alias(alias) => insert(&alias.alias),
5434 Expression::JoinedTable(joined) => {
5435 if let Some(alias) = &joined.alias {
5436 insert(alias);
5437 } else {
5438 collect_source_names(&joined.left, names);
5439 for join in &joined.joins {
5440 collect_source_names(&join.this, names);
5441 }
5442 }
5443 }
5444 Expression::Paren(paren) => collect_source_names(&paren.this, names),
5445 Expression::Pivot(pivot) => {
5446 if let Some(alias) = &pivot.alias {
5447 insert(alias);
5448 } else {
5449 collect_source_names(&pivot.this, names);
5450 }
5451 }
5452 Expression::Unpivot(unpivot) => {
5453 if let Some(alias) = &unpivot.alias {
5454 insert(alias);
5455 } else {
5456 collect_source_names(&unpivot.this, names);
5457 }
5458 }
5459 _ => {}
5460 }
5461 }
5462
5463 fn collect_columns<'a>(
5464 expr: &'a Expression,
5465 columns: &mut Vec<&'a crate::expressions::Column>,
5466 ) {
5467 match expr {
5468 Expression::Column(column) => columns.push(column),
5469 Expression::Select(_)
5472 | Expression::Subquery(_)
5473 | Expression::Union(_)
5474 | Expression::Intersect(_)
5475 | Expression::Except(_) => {}
5476 _ => {
5477 for child in expr.children() {
5478 collect_columns(child, columns);
5479 }
5480 }
5481 }
5482 }
5483
5484 fn same_column(
5485 left: &crate::expressions::Column,
5486 right: &crate::expressions::Column,
5487 ) -> bool {
5488 let same_identifier =
5489 |left: &Identifier, right: &Identifier| left.name.eq_ignore_ascii_case(&right.name);
5490
5491 same_identifier(&left.name, &right.name)
5492 && match (&left.table, &right.table) {
5493 (Some(left), Some(right)) => same_identifier(left, right),
5494 (None, None) => true,
5495 _ => false,
5496 }
5497 }
5498
5499 fn aggregate_is_invalid(expr: &Expression, local_sources: &HashSet<String>) -> bool {
5500 let mut columns = Vec::new();
5501 collect_columns(expr, &mut columns);
5502
5503 let outer_column = columns.iter().copied().find(|column| match &column.table {
5504 Some(table) => !local_sources.contains(&table.name.to_ascii_lowercase()),
5505 None => local_sources.is_empty(),
5508 });
5509
5510 outer_column
5511 .is_some_and(|outer| columns.iter().any(|column| !same_column(outer, column)))
5512 }
5513
5514 fn expression_has_invalid_aggregate(
5515 expr: &Expression,
5516 local_sources: &HashSet<String>,
5517 ) -> bool {
5518 if Dialect::node_is_aggregate_function(expr)
5519 && aggregate_is_invalid(expr, local_sources)
5520 {
5521 return true;
5522 }
5523
5524 match expr {
5525 Expression::Select(_)
5526 | Expression::Subquery(_)
5527 | Expression::Union(_)
5528 | Expression::Intersect(_)
5529 | Expression::Except(_) => false,
5530 _ => expr
5531 .children()
5532 .into_iter()
5533 .any(|child| expression_has_invalid_aggregate(child, local_sources)),
5534 }
5535 }
5536
5537 fn select_has_invalid_aggregate(select: &Select) -> bool {
5538 let mut local_sources = HashSet::new();
5539 if let Some(from) = &select.from {
5540 for source in &from.expressions {
5541 collect_source_names(source, &mut local_sources);
5542 }
5543 }
5544 for join in &select.joins {
5545 collect_source_names(&join.this, &mut local_sources);
5546 }
5547
5548 let invalid =
5549 |expr: &Expression| expression_has_invalid_aggregate(expr, &local_sources);
5550
5551 select.expressions.iter().any(invalid)
5552 || select.prewhere.as_ref().is_some_and(invalid)
5553 || select
5554 .where_clause
5555 .as_ref()
5556 .is_some_and(|where_clause| invalid(&where_clause.this))
5557 || select
5558 .group_by
5559 .as_ref()
5560 .is_some_and(|group_by| group_by.expressions.iter().any(invalid))
5561 || select
5562 .having
5563 .as_ref()
5564 .is_some_and(|having| invalid(&having.this))
5565 || select
5566 .qualify
5567 .as_ref()
5568 .is_some_and(|qualify| invalid(&qualify.this))
5569 || select.order_by.as_ref().is_some_and(|order_by| {
5570 order_by
5571 .expressions
5572 .iter()
5573 .any(|ordered| invalid(&ordered.this))
5574 })
5575 }
5576
5577 fn apply_rhs_is_invalid(rhs: &Expression) -> bool {
5578 rhs.dfs().any(|node| match node {
5579 Expression::Select(select) => select_has_invalid_aggregate(select),
5580 _ => false,
5581 })
5582 }
5583
5584 fn joins_have_invalid_aggregate(joins: &[Join]) -> bool {
5585 joins.iter().any(|join| {
5586 matches!(
5587 join.kind,
5588 crate::expressions::JoinKind::CrossApply
5589 | crate::expressions::JoinKind::OuterApply
5590 ) && apply_rhs_is_invalid(&join.this)
5591 })
5592 }
5593
5594 expr.dfs().any(|node| match node {
5595 Expression::Select(select) => joins_have_invalid_aggregate(&select.joins),
5596 Expression::JoinedTable(joined) => joins_have_invalid_aggregate(&joined.joins),
5597 Expression::Update(update) => {
5598 joins_have_invalid_aggregate(&update.table_joins)
5599 || joins_have_invalid_aggregate(&update.from_joins)
5600 }
5601 Expression::Delete(delete) => joins_have_invalid_aggregate(&delete.joins),
5602 _ => false,
5603 })
5604 }
5605
5606 fn target_supports_remaining_unnest(target: DialectType) -> bool {
5607 matches!(
5608 target,
5609 DialectType::PostgreSQL
5610 | DialectType::BigQuery
5611 | DialectType::DuckDB
5612 | DialectType::Presto
5613 | DialectType::Trino
5614 | DialectType::Athena
5615 )
5616 }
5617
5618 fn target_supports_remaining_explode(target: DialectType) -> bool {
5619 matches!(
5620 target,
5621 DialectType::Spark | DialectType::Databricks | DialectType::Hive
5622 )
5623 }
5624
5625 fn target_lacks_array_agg(target: DialectType) -> bool {
5626 matches!(
5627 target,
5628 DialectType::Fabric
5629 | DialectType::TSQL
5630 | DialectType::MySQL
5631 | DialectType::SQLite
5632 | DialectType::Oracle
5633 )
5634 }
5635
5636 fn node_is_unnest(expr: &Expression) -> bool {
5637 matches!(expr, Expression::Unnest(_)) || Self::node_is_function_named(expr, "UNNEST")
5638 }
5639
5640 fn node_is_explode(expr: &Expression) -> bool {
5641 matches!(expr, Expression::Explode(_) | Expression::ExplodeOuter(_))
5642 || Self::node_is_function_named(expr, "EXPLODE")
5643 || Self::node_is_function_named(expr, "EXPLODE_OUTER")
5644 }
5645
5646 fn node_is_array_agg(expr: &Expression) -> bool {
5647 matches!(expr, Expression::ArrayAgg(_)) || Self::node_is_function_named(expr, "ARRAY_AGG")
5648 }
5649
5650 fn node_is_distinct_string_agg(expr: &Expression) -> bool {
5651 match expr {
5652 Expression::StringAgg(agg) => agg.distinct,
5653 Expression::Function(function) => {
5654 function.distinct && function.name.eq_ignore_ascii_case("STRING_AGG")
5655 }
5656 Expression::AggregateFunction(function) => {
5657 function.distinct && function.name.eq_ignore_ascii_case("STRING_AGG")
5658 }
5659 _ => false,
5660 }
5661 }
5662
5663 fn postgres_tsql_unsupported_collation_name(expr: &Expression) -> Option<&'static str> {
5664 let Expression::Collation(collation) = expr else {
5665 return None;
5666 };
5667
5668 if collation.collation.eq_ignore_ascii_case("C") {
5669 Some("C")
5670 } else if collation.collation.eq_ignore_ascii_case("POSIX") {
5671 Some("POSIX")
5672 } else {
5673 None
5674 }
5675 }
5676
5677 fn collect_tsql_grouping_tuple_nodes(expr: &Expression) -> HashSet<*const Expression> {
5678 let mut tuples = HashSet::new();
5679
5680 for node in expr.dfs() {
5681 let Expression::Select(select) = node else {
5682 continue;
5683 };
5684 let Some(group_by) = &select.group_by else {
5685 continue;
5686 };
5687
5688 for expression in &group_by.expressions {
5689 Self::collect_tsql_grouping_element_tuples(expression, &mut tuples);
5690 }
5691 }
5692
5693 tuples
5694 }
5695
5696 fn collect_tsql_grouping_element_tuples(
5697 expr: &Expression,
5698 tuples: &mut HashSet<*const Expression>,
5699 ) {
5700 match expr {
5701 Expression::GroupingSets(grouping_sets) => {
5702 for expression in &grouping_sets.expressions {
5703 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5704 }
5705 }
5706 Expression::Rollup(rollup) => {
5707 for expression in &rollup.expressions {
5708 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5709 }
5710 }
5711 Expression::Cube(cube) => {
5712 for expression in &cube.expressions {
5713 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5714 }
5715 }
5716 Expression::Function(function)
5717 if !function.quoted
5718 && (function.name.eq_ignore_ascii_case("GROUPING SETS")
5719 || function.name.eq_ignore_ascii_case("ROLLUP")
5720 || function.name.eq_ignore_ascii_case("CUBE")) =>
5721 {
5722 for expression in &function.args {
5723 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5724 }
5725 }
5726 _ => {}
5727 }
5728 }
5729
5730 fn collect_tsql_grouping_unit_tuples(
5731 expr: &Expression,
5732 tuples: &mut HashSet<*const Expression>,
5733 ) {
5734 match expr {
5735 Expression::Tuple(tuple) => {
5736 tuples.insert(expr as *const Expression);
5737 for expression in &tuple.expressions {
5738 match expression {
5739 Expression::Tuple(_) | Expression::Paren(_) => {
5740 Self::collect_tsql_grouping_unit_tuples(expression, tuples);
5741 }
5742 Expression::GroupingSets(_)
5743 | Expression::Rollup(_)
5744 | Expression::Cube(_) => {
5745 Self::collect_tsql_grouping_element_tuples(expression, tuples);
5746 }
5747 Expression::Function(function)
5748 if !function.quoted
5749 && (function.name.eq_ignore_ascii_case("GROUPING SETS")
5750 || function.name.eq_ignore_ascii_case("ROLLUP")
5751 || function.name.eq_ignore_ascii_case("CUBE")) =>
5752 {
5753 Self::collect_tsql_grouping_element_tuples(expression, tuples);
5754 }
5755 _ => {}
5756 }
5757 }
5758 }
5759 Expression::Paren(paren) => {
5760 Self::collect_tsql_grouping_unit_tuples(&paren.this, tuples);
5761 }
5762 Expression::GroupingSets(_) | Expression::Rollup(_) | Expression::Cube(_) => {
5763 Self::collect_tsql_grouping_element_tuples(expr, tuples);
5764 }
5765 Expression::Function(function)
5766 if !function.quoted
5767 && (function.name.eq_ignore_ascii_case("GROUPING SETS")
5768 || function.name.eq_ignore_ascii_case("ROLLUP")
5769 || function.name.eq_ignore_ascii_case("CUBE")) =>
5770 {
5771 Self::collect_tsql_grouping_element_tuples(expr, tuples);
5772 }
5773 _ => {}
5774 }
5775 }
5776
5777 fn postgres_tsql_unsupported_composite_semantics(
5778 expr: &Expression,
5779 structural_grouping_tuple: bool,
5780 ) -> Option<&'static str> {
5781 match expr {
5782 Expression::Tuple(_) if !structural_grouping_tuple => Some("row/composite values"),
5783 Expression::Struct(_) | Expression::StructFunc(_) => Some("row/composite values"),
5784 Expression::Function(function)
5785 if !function.quoted && function.name.eq_ignore_ascii_case("ROW") =>
5786 {
5787 Some("row/composite values")
5788 }
5789 Expression::StructExtract(_) => Some("row/composite field access"),
5790 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) if matches!(&cast.this, Expression::Star(star) if star.table.is_some()) => {
5791 Some("qualified whole-row casts")
5792 }
5793 _ => None,
5794 }
5795 }
5796
5797 fn node_is_postgres_unknown_cast(expr: &Expression) -> bool {
5798 match expr {
5799 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
5800 normalization::is_postgres_unknown_type(&cast.to)
5801 }
5802 _ => false,
5803 }
5804 }
5805
5806 fn postgres_tsql_unsupported_array_semantics(expr: &Expression) -> Option<&'static str> {
5807 match expr {
5808 Expression::Array(_) | Expression::ArrayFunc(_) => Some("array literals"),
5809 Expression::Subscript(_) => Some("array subscripts"),
5810 Expression::ArraySlice(_) => Some("array slices"),
5811 Expression::DataType(DataType::Array { .. }) => Some("array data types"),
5812 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
5813 if matches!(&cast.to, DataType::Array { .. }) =>
5814 {
5815 Some("array data types")
5816 }
5817 Expression::ArrayLength(_) | Expression::ArraySize(_) => Some("ARRAY_LENGTH"),
5818 Expression::Cardinality(_) => Some("CARDINALITY"),
5819 Expression::ArrayToString(_) | Expression::ArrayJoin(_) => Some("ARRAY_TO_STRING"),
5820 Expression::StringToArray(_) => Some("STRING_TO_ARRAY"),
5821 Expression::ArrayContains(_)
5822 | Expression::ArrayPosition(_)
5823 | Expression::ArrayAppend(_)
5824 | Expression::ArrayPrepend(_)
5825 | Expression::ArrayConcat(_)
5826 | Expression::ArraySort(_)
5827 | Expression::ArrayReverse(_)
5828 | Expression::ArrayDistinct(_)
5829 | Expression::ArrayFilter(_)
5830 | Expression::ArrayTransform(_)
5831 | Expression::ArrayFlatten(_)
5832 | Expression::ArrayCompact(_)
5833 | Expression::ArrayIntersect(_)
5834 | Expression::ArrayUnion(_)
5835 | Expression::ArrayExcept(_)
5836 | Expression::ArrayRemove(_)
5837 | Expression::ArrayZip(_)
5838 | Expression::ArrayAll(_)
5839 | Expression::ArrayAny(_)
5840 | Expression::ArrayConstructCompact(_)
5841 | Expression::ArraySum(_) => Some("array functions"),
5842 Expression::ArrayContainsAll(_)
5843 | Expression::ArrayContainedBy(_)
5844 | Expression::ArrayOverlaps(_) => Some("array operators"),
5845 Expression::Function(function) => {
5846 Self::postgres_tsql_unsupported_array_function_name_str(&function.name)
5847 }
5848 Expression::AggregateFunction(function) => {
5849 Self::postgres_tsql_unsupported_array_function_name_str(&function.name)
5850 }
5851 _ => None,
5852 }
5853 }
5854
5855 fn postgres_tsql_unsupported_array_function_name_str(name: &str) -> Option<&'static str> {
5856 if name.eq_ignore_ascii_case("ARRAY") {
5857 Some("array literals")
5858 } else if name.eq_ignore_ascii_case("ARRAY_LENGTH")
5859 || name.eq_ignore_ascii_case("ARRAY_SIZE")
5860 {
5861 Some("ARRAY_LENGTH")
5862 } else if name.eq_ignore_ascii_case("CARDINALITY") {
5863 Some("CARDINALITY")
5864 } else if name.eq_ignore_ascii_case("ARRAY_TO_STRING")
5865 || name.eq_ignore_ascii_case("ARRAY_JOIN")
5866 {
5867 Some("ARRAY_TO_STRING")
5868 } else if name.eq_ignore_ascii_case("STRING_TO_ARRAY") {
5869 Some("STRING_TO_ARRAY")
5870 } else {
5871 None
5872 }
5873 }
5874
5875 fn node_is_regex_predicate(expr: &Expression) -> bool {
5876 matches!(
5877 expr,
5878 Expression::SimilarTo(_) | Expression::RegexpLike(_) | Expression::RegexpILike(_)
5879 ) || Self::node_is_function_named(expr, "REGEXP_LIKE")
5880 || Self::node_is_function_named(expr, "REGEXP_I_LIKE")
5881 || Self::node_is_function_named(expr, "REGEXP_ILIKE")
5882 }
5883
5884 fn node_is_non_subquery_any(expr: &Expression) -> bool {
5885 matches!(
5886 expr,
5887 Expression::Any(q) if !Self::quantified_rhs_is_subquery(&q.subquery)
5888 )
5889 }
5890
5891 fn quantified_rhs_is_subquery(expr: &Expression) -> bool {
5892 match expr {
5893 Expression::Select(_) | Expression::Subquery(_) => true,
5894 Expression::Paren(paren) => Self::quantified_rhs_is_subquery(&paren.this),
5895 _ => false,
5896 }
5897 }
5898
5899 fn node_is_row_value_subquery_comparison(expr: &Expression) -> bool {
5900 match expr {
5901 Expression::In(in_expr) => {
5902 Self::in_rhs_is_subquery_like(in_expr) && Self::expr_is_row_value(&in_expr.this)
5903 }
5904 Expression::Eq(op) | Expression::Neq(op) => {
5905 (Self::expr_is_row_value(&op.left) && Self::expr_is_subquery_like(&op.right))
5906 || (Self::expr_is_row_value(&op.right) && Self::expr_is_subquery_like(&op.left))
5907 }
5908 _ => false,
5909 }
5910 }
5911
5912 fn node_is_row_value_values_membership(expr: &Expression) -> bool {
5913 matches!(
5914 expr,
5915 Expression::In(in_expr)
5916 if Self::expr_is_row_value(&in_expr.this)
5917 && Self::in_rhs_is_values_like(in_expr)
5918 )
5919 }
5920
5921 fn expr_is_row_value(expr: &Expression) -> bool {
5922 match expr {
5923 Expression::Tuple(tuple) => tuple.expressions.len() > 1,
5924 Expression::Function(function) if function.name.eq_ignore_ascii_case("ROW") => {
5925 function.args.len() > 1
5926 }
5927 Expression::Paren(paren) => Self::expr_is_row_value(&paren.this),
5928 _ => false,
5929 }
5930 }
5931
5932 fn expr_is_subquery_like(expr: &Expression) -> bool {
5933 match expr {
5934 Expression::Select(_) | Expression::Subquery(_) => true,
5935 Expression::Paren(paren) => Self::expr_is_subquery_like(&paren.this),
5936 _ => false,
5937 }
5938 }
5939
5940 fn in_rhs_is_subquery_like(in_expr: &crate::expressions::In) -> bool {
5941 if in_expr
5942 .query
5943 .as_ref()
5944 .is_some_and(Self::expr_is_subquery_like)
5945 {
5946 return true;
5947 }
5948
5949 in_expr.expressions.len() == 1 && Self::expr_is_subquery_like(&in_expr.expressions[0])
5950 }
5951
5952 fn in_rhs_is_values_like(in_expr: &crate::expressions::In) -> bool {
5953 if in_expr
5954 .query
5955 .as_ref()
5956 .is_some_and(Self::expr_is_values_like)
5957 {
5958 return true;
5959 }
5960
5961 (in_expr.expressions.len() == 1
5962 && Self::expr_is_values_like(&in_expr.expressions[0]))
5963 || in_expr.expressions.first().is_some_and(|expr| {
5964 matches!(expr, Expression::Function(function) if function.name.eq_ignore_ascii_case("VALUES"))
5965 })
5966 }
5967
5968 fn expr_is_values_like(expr: &Expression) -> bool {
5969 match expr {
5970 Expression::Values(_) => true,
5971 Expression::Paren(paren) => Self::expr_is_values_like(&paren.this),
5972 Expression::Subquery(subquery) => Self::expr_is_values_like(&subquery.this),
5973 _ => false,
5974 }
5975 }
5976
5977 fn normalize_tsql_fetch_overlaps_date_bin(expr: Expression) -> Result<Expression> {
5978 transform_recursive(expr, &|e| match e {
5979 Expression::Select(mut select) => {
5980 if select.top.is_none() && select.offset.is_none() {
5981 if let Some(fetch) = select.fetch.take() {
5982 if let Some(top) = Self::fetch_with_ties_to_top(fetch.clone()) {
5983 select.top = Some(top);
5984 } else {
5985 select.fetch = Some(fetch);
5986 }
5987 }
5988 }
5989 Self::rewrite_tsql_overlaps_in_select_predicates(&mut select)?;
5990 Ok(Expression::Select(select))
5991 }
5992 Expression::DateBin(date_bin) => {
5993 let date_bin = *date_bin;
5994 if let Some(rewritten) = Self::date_bin_to_date_bucket(date_bin.clone()) {
5995 Ok(rewritten)
5996 } else {
5997 Ok(Expression::DateBin(Box::new(date_bin)))
5998 }
5999 }
6000 Expression::Function(function) => {
6001 let function = *function;
6002 if function.name.eq_ignore_ascii_case("DATE_BIN") {
6003 if let Some(rewritten) = Self::date_bin_function_to_date_bucket(&function) {
6004 Ok(rewritten)
6005 } else {
6006 Ok(Expression::Function(Box::new(function)))
6007 }
6008 } else {
6009 Ok(Expression::Function(Box::new(function)))
6010 }
6011 }
6012 _ => Ok(e),
6013 })
6014 }
6015
6016 fn rewrite_tsql_overlaps_in_select_predicates(
6017 select: &mut crate::expressions::Select,
6018 ) -> Result<()> {
6019 if let Some(where_clause) = &mut select.where_clause {
6020 where_clause.this = Self::rewrite_tsql_overlaps_predicate(where_clause.this.clone())?;
6021 }
6022 if let Some(having) = &mut select.having {
6023 having.this = Self::rewrite_tsql_overlaps_predicate(having.this.clone())?;
6024 }
6025 if let Some(qualify) = &mut select.qualify {
6026 qualify.this = Self::rewrite_tsql_overlaps_predicate(qualify.this.clone())?;
6027 }
6028 for join in &mut select.joins {
6029 if let Some(on) = join.on.take() {
6030 join.on = Some(Self::rewrite_tsql_overlaps_predicate(on)?);
6031 }
6032 if let Some(match_condition) = join.match_condition.take() {
6033 join.match_condition =
6034 Some(Self::rewrite_tsql_overlaps_predicate(match_condition)?);
6035 }
6036 }
6037 Ok(())
6038 }
6039
6040 fn rewrite_tsql_overlaps_predicate(expr: Expression) -> Result<Expression> {
6041 transform_recursive(expr, &|e| match e {
6042 Expression::Overlaps(overlaps) => {
6043 let overlaps = *overlaps;
6044 if let Some(rewritten) = Self::rewrite_full_overlaps_for_tsql(&overlaps) {
6045 Ok(rewritten)
6046 } else {
6047 Ok(Expression::Overlaps(Box::new(overlaps)))
6048 }
6049 }
6050 _ => Ok(e),
6051 })
6052 }
6053
6054 fn fetch_with_ties_to_top(fetch: Fetch) -> Option<Top> {
6055 if !fetch.with_ties {
6056 return None;
6057 }
6058
6059 fetch.count.map(|count| Top {
6060 this: count,
6061 percent: fetch.percent,
6062 with_ties: true,
6063 parenthesized: true,
6064 })
6065 }
6066
6067 fn rewrite_full_overlaps_for_tsql(
6068 overlaps: &crate::expressions::OverlapsExpr,
6069 ) -> Option<Expression> {
6070 let (left_start, left_end, right_start, right_end) =
6071 if let (Some(left_start), Some(left_end), Some(right_start), Some(right_end)) = (
6072 overlaps.left_start.as_ref(),
6073 overlaps.left_end.as_ref(),
6074 overlaps.right_start.as_ref(),
6075 overlaps.right_end.as_ref(),
6076 ) {
6077 (left_start, left_end, right_start, right_end)
6078 } else if let (
6079 Some(Expression::Tuple(left_tuple)),
6080 Some(Expression::Tuple(right_tuple)),
6081 ) = (&overlaps.this, &overlaps.expression)
6082 {
6083 if left_tuple.expressions.len() != 2 || right_tuple.expressions.len() != 2 {
6084 return None;
6085 }
6086 (
6087 &left_tuple.expressions[0],
6088 &left_tuple.expressions[1],
6089 &right_tuple.expressions[0],
6090 &right_tuple.expressions[1],
6091 )
6092 } else {
6093 return None;
6094 };
6095
6096 let left_min = Self::case_min(left_start.clone(), left_end.clone());
6097 let left_max = Self::case_max(left_start.clone(), left_end.clone());
6098 let right_min = Self::case_min(right_start.clone(), right_end.clone());
6099 let right_max = Self::case_max(right_start.clone(), right_end.clone());
6100
6101 Some(Expression::And(Box::new(BinaryOp::new(
6102 Expression::Lte(Box::new(BinaryOp::new(left_min, right_max))),
6103 Expression::Lte(Box::new(BinaryOp::new(right_min, left_max))),
6104 ))))
6105 }
6106
6107 fn case_min(left: Expression, right: Expression) -> Expression {
6108 Expression::Case(Box::new(Case {
6109 operand: None,
6110 whens: vec![(
6111 Expression::Lte(Box::new(BinaryOp::new(left.clone(), right.clone()))),
6112 left,
6113 )],
6114 else_: Some(right),
6115 comments: Vec::new(),
6116 inferred_type: None,
6117 }))
6118 }
6119
6120 fn case_max(left: Expression, right: Expression) -> Expression {
6121 Expression::Case(Box::new(Case {
6122 operand: None,
6123 whens: vec![(
6124 Expression::Gte(Box::new(BinaryOp::new(left.clone(), right.clone()))),
6125 left,
6126 )],
6127 else_: Some(right),
6128 comments: Vec::new(),
6129 inferred_type: None,
6130 }))
6131 }
6132
6133 fn date_bin_to_date_bucket(date_bin: DateBin) -> Option<Expression> {
6134 if date_bin.unit.is_some() || date_bin.zone.is_some() {
6135 return None;
6136 }
6137
6138 let (datepart, number) = Self::date_bucket_parts(&date_bin.this)?;
6139 let mut args = vec![
6140 Self::date_bucket_datepart(datepart),
6141 number,
6142 *date_bin.expression,
6143 ];
6144 if let Some(origin) = date_bin.origin {
6145 args.push(*origin);
6146 }
6147
6148 Some(Expression::Function(Box::new(Function::new(
6149 "DATE_BUCKET".to_string(),
6150 args,
6151 ))))
6152 }
6153
6154 fn date_bin_function_to_date_bucket(function: &Function) -> Option<Expression> {
6155 if !(2..=3).contains(&function.args.len()) {
6156 return None;
6157 }
6158
6159 let (datepart, number) = Self::date_bucket_parts(&function.args[0])?;
6160 let mut args = vec![
6161 Self::date_bucket_datepart(datepart),
6162 number,
6163 function.args[1].clone(),
6164 ];
6165 if let Some(origin) = function.args.get(2) {
6166 args.push(origin.clone());
6167 }
6168
6169 Some(Expression::Function(Box::new(Function::new(
6170 "DATE_BUCKET".to_string(),
6171 args,
6172 ))))
6173 }
6174
6175 fn date_bucket_parts(stride: &Expression) -> Option<(&'static str, Expression)> {
6176 match stride {
6177 Expression::Literal(lit) => match lit.as_ref() {
6178 Literal::String(value) => Self::date_bucket_parts_from_string(value),
6179 _ => None,
6180 },
6181 Expression::Interval(interval) => Self::date_bucket_parts_from_interval(interval),
6182 _ => None,
6183 }
6184 }
6185
6186 fn date_bucket_parts_from_interval(interval: &Interval) -> Option<(&'static str, Expression)> {
6187 match &interval.unit {
6188 Some(IntervalUnitSpec::Simple { unit, .. }) => {
6189 let datepart = Self::date_bucket_datepart_from_unit(*unit)?;
6190 let amount = interval
6191 .this
6192 .as_ref()
6193 .and_then(Self::date_bucket_amount_expr)?;
6194 Some((datepart, amount))
6195 }
6196 None => interval.this.as_ref().and_then(|expr| match expr {
6197 Expression::Literal(lit) => match lit.as_ref() {
6198 Literal::String(value) => Self::date_bucket_parts_from_string(value),
6199 _ => None,
6200 },
6201 _ => None,
6202 }),
6203 _ => None,
6204 }
6205 }
6206
6207 fn date_bucket_parts_from_string(value: &str) -> Option<(&'static str, Expression)> {
6208 let mut parts = value.split_whitespace();
6209 let amount = parts.next()?;
6210 let unit = parts.next()?;
6211 if parts.next().is_some() {
6212 return None;
6213 }
6214
6215 Some((
6216 Self::date_bucket_datepart_from_name(unit)?,
6217 Self::positive_integer_expr(amount)?,
6218 ))
6219 }
6220
6221 fn date_bucket_amount_expr(expr: &Expression) -> Option<Expression> {
6222 match expr {
6223 Expression::Literal(lit) => match lit.as_ref() {
6224 Literal::Number(value) => Self::positive_integer_expr(value),
6225 Literal::String(value) => Self::positive_integer_expr(value),
6226 _ => None,
6227 },
6228 _ => Some(expr.clone()),
6229 }
6230 }
6231
6232 fn positive_integer_expr(value: &str) -> Option<Expression> {
6233 let parsed = value.trim().parse::<i64>().ok()?;
6234 (parsed > 0).then(|| Expression::number(parsed))
6235 }
6236
6237 fn date_bucket_datepart(datepart: &str) -> Expression {
6238 Expression::Var(Box::new(Var {
6239 this: datepart.to_string(),
6240 }))
6241 }
6242
6243 fn date_bucket_datepart_from_unit(unit: IntervalUnit) -> Option<&'static str> {
6244 match unit {
6245 IntervalUnit::Week => Some("WEEK"),
6246 IntervalUnit::Day => Some("DAY"),
6247 IntervalUnit::Hour => Some("HOUR"),
6248 IntervalUnit::Minute => Some("MINUTE"),
6249 IntervalUnit::Second => Some("SECOND"),
6250 IntervalUnit::Millisecond => Some("MILLISECOND"),
6251 _ => None,
6252 }
6253 }
6254
6255 fn date_bucket_datepart_from_name(unit: &str) -> Option<&'static str> {
6256 match unit.trim().to_ascii_uppercase().as_str() {
6257 "WEEK" | "WEEKS" | "W" | "WK" | "WKS" | "WW" => Some("WEEK"),
6258 "DAY" | "DAYS" | "D" | "DD" => Some("DAY"),
6259 "HOUR" | "HOURS" | "H" | "HH" | "HR" | "HRS" => Some("HOUR"),
6260 "MINUTE" | "MINUTES" | "MI" | "MIN" | "MINS" | "N" => Some("MINUTE"),
6261 "SECOND" | "SECONDS" | "S" | "SEC" | "SECS" | "SS" => Some("SECOND"),
6262 "MILLISECOND" | "MILLISECONDS" | "MS" | "MSEC" | "MSECS" | "MILLISEC" | "MILLISECS" => {
6263 Some("MILLISECOND")
6264 }
6265 _ => None,
6266 }
6267 }
6268
6269 fn node_has_fetch_with_ties(expr: &Expression) -> bool {
6270 matches!(
6271 expr,
6272 Expression::Select(select)
6273 if select
6274 .fetch
6275 .as_ref()
6276 .is_some_and(|fetch| fetch.with_ties)
6277 )
6278 }
6279
6280 fn node_is_overlaps(expr: &Expression) -> bool {
6281 matches!(expr, Expression::Overlaps(_))
6282 }
6283
6284 fn node_is_date_bin(expr: &Expression) -> bool {
6285 matches!(expr, Expression::DateBin(_)) || Self::node_is_function_named(expr, "DATE_BIN")
6286 }
6287
6288 fn node_is_function_named(expr: &Expression, name: &str) -> bool {
6289 match expr {
6290 Expression::Function(function) => function.name.eq_ignore_ascii_case(name),
6291 Expression::AggregateFunction(function) => function.name.eq_ignore_ascii_case(name),
6292 _ => false,
6293 }
6294 }
6295
6296 fn node_is_postgres_json_build_object(expr: &Expression) -> bool {
6297 match expr {
6298 Expression::Function(function) => {
6299 function.name.eq_ignore_ascii_case("JSON_BUILD_OBJECT")
6300 || function.name.eq_ignore_ascii_case("JSONB_BUILD_OBJECT")
6301 }
6302 _ => false,
6303 }
6304 }
6305
6306 fn postgres_json_build_object_can_lower_to_json_object(expr: &Expression) -> bool {
6307 matches!(
6308 expr,
6309 Expression::Function(function)
6310 if (function.name.eq_ignore_ascii_case("JSON_BUILD_OBJECT")
6311 || function.name.eq_ignore_ascii_case("JSONB_BUILD_OBJECT"))
6312 && !function.distinct
6313 && function.args.len() % 2 == 0
6314 )
6315 }
6316
6317 fn node_is_postgres_json_array_elements(expr: &Expression) -> bool {
6318 matches!(
6319 expr,
6320 Expression::Function(function)
6321 if function.name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS")
6322 || function.name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS")
6323 || function.name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS_TEXT")
6324 || function.name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS_TEXT")
6325 )
6326 }
6327
6328 fn postgres_tsql_unsupported_function_name(
6329 expr: &Expression,
6330 target: DialectType,
6331 ) -> Option<&'static str> {
6332 match expr {
6333 Expression::Lpad(_) => Some("LPAD"),
6334 Expression::Rpad(_) => Some("RPAD"),
6335 Expression::SplitPart(_) => Some("SPLIT_PART"),
6336 Expression::Initcap(_) => Some("INITCAP"),
6337 Expression::RegexpReplace(_) => Some("REGEXP_REPLACE"),
6338 Expression::RegexpInstr(_) => Some("REGEXP_INSTR"),
6339 Expression::RegexpCount(_) => Some("REGEXP_COUNT"),
6340 Expression::RegexpSplit(_) => Some("REGEXP_SPLIT"),
6341 Expression::DecodeCase(_) => Some("DECODE"),
6342 Expression::ToJson(_) => Some("TO_JSON"),
6343 Expression::JSONBObjectAgg(_) => Some("JSONB_OBJECT_AGG"),
6344 Expression::ToNumber(_) => Some("TO_NUMBER"),
6345 Expression::WidthBucket(_) => Some("WIDTH_BUCKET"),
6346 Expression::BitwiseAndAgg(_) => Some("BIT_AND"),
6347 Expression::BitwiseOrAgg(_) => Some("BIT_OR"),
6348 Expression::BitwiseXorAgg(_) => Some("BIT_XOR"),
6349 Expression::Corr(_) => Some("CORR"),
6350 Expression::CovarPop(_) => Some("COVAR_POP"),
6351 Expression::CovarSamp(_) => Some("COVAR_SAMP"),
6352 Expression::RegrAvgx(_) => Some("REGR_AVGX"),
6353 Expression::RegrAvgy(_) => Some("REGR_AVGY"),
6354 Expression::RegrCount(_) => Some("REGR_COUNT"),
6355 Expression::RegrIntercept(_) => Some("REGR_INTERCEPT"),
6356 Expression::RegrR2(_) => Some("REGR_R2"),
6357 Expression::RegrSlope(_) => Some("REGR_SLOPE"),
6358 Expression::RegrSxx(_) => Some("REGR_SXX"),
6359 Expression::RegrSxy(_) => Some("REGR_SXY"),
6360 Expression::RegrSyy(_) => Some("REGR_SYY"),
6361 Expression::Function(function) => {
6362 Self::postgres_tsql_unsupported_function_name_str(&function.name, target)
6363 }
6364 Expression::AggregateFunction(function) => {
6365 Self::postgres_tsql_unsupported_function_name_str(&function.name, target)
6366 }
6367 _ => None,
6368 }
6369 }
6370
6371 fn postgres_tsql_unsupported_function_name_str(
6372 name: &str,
6373 target: DialectType,
6374 ) -> Option<&'static str> {
6375 if name.eq_ignore_ascii_case("LPAD") {
6376 Some("LPAD")
6377 } else if name.eq_ignore_ascii_case("RPAD") {
6378 Some("RPAD")
6379 } else if name.eq_ignore_ascii_case("SPLIT_PART") {
6380 Some("SPLIT_PART")
6381 } else if name.eq_ignore_ascii_case("INITCAP") {
6382 Some("INITCAP")
6383 } else if name.eq_ignore_ascii_case("TO_JSON") {
6384 Some("TO_JSON")
6385 } else if name.eq_ignore_ascii_case("TO_JSONB") {
6386 Some("TO_JSONB")
6387 } else if name.eq_ignore_ascii_case("JSONB_OBJECT_AGG") {
6388 Some("JSONB_OBJECT_AGG")
6389 } else if name.eq_ignore_ascii_case("ROW_TO_JSON") {
6390 Some("ROW_TO_JSON")
6391 } else if name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS") {
6392 Some("JSON_ARRAY_ELEMENTS")
6393 } else if name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS") {
6394 Some("JSONB_ARRAY_ELEMENTS")
6395 } else if name.eq_ignore_ascii_case("JSON_ARRAY_ELEMENTS_TEXT") {
6396 Some("JSON_ARRAY_ELEMENTS_TEXT")
6397 } else if name.eq_ignore_ascii_case("JSONB_ARRAY_ELEMENTS_TEXT") {
6398 Some("JSONB_ARRAY_ELEMENTS_TEXT")
6399 } else if name.eq_ignore_ascii_case("ENCODE") {
6400 Some("ENCODE")
6401 } else if name.eq_ignore_ascii_case("DECODE") {
6402 Some("DECODE")
6403 } else if name.eq_ignore_ascii_case("REGEXP_REPLACE") {
6404 Some("REGEXP_REPLACE")
6405 } else if name.eq_ignore_ascii_case("REGEXP_COUNT") {
6406 Some("REGEXP_COUNT")
6407 } else if name.eq_ignore_ascii_case("REGEXP_INSTR") {
6408 Some("REGEXP_INSTR")
6409 } else if name.eq_ignore_ascii_case("REGEXP_SUBSTR") {
6410 Some("REGEXP_SUBSTR")
6411 } else if name.eq_ignore_ascii_case("REGEXP_SPLIT") {
6412 Some("REGEXP_SPLIT")
6413 } else if name.eq_ignore_ascii_case("REGEXP_SPLIT_TO_ARRAY") {
6414 Some("REGEXP_SPLIT_TO_ARRAY")
6415 } else if name.eq_ignore_ascii_case("REGEXP_SPLIT_TO_TABLE") {
6416 Some("REGEXP_SPLIT_TO_TABLE")
6417 } else if name.eq_ignore_ascii_case("SHA224") {
6418 Some("SHA224")
6419 } else if name.eq_ignore_ascii_case("SHA384") {
6420 Some("SHA384")
6421 } else if name.eq_ignore_ascii_case("TO_BIN") {
6422 Some("TO_BIN")
6423 } else if name.eq_ignore_ascii_case("TO_OCT") {
6424 Some("TO_OCT")
6425 } else if target == DialectType::TSQL && name.eq_ignore_ascii_case("UNISTR") {
6426 Some("UNISTR")
6427 } else if name.eq_ignore_ascii_case("AGE") {
6428 Some("AGE")
6429 } else if name.eq_ignore_ascii_case("ERF") {
6430 Some("ERF")
6431 } else if name.eq_ignore_ascii_case("SINH") {
6432 Some("SINH")
6433 } else if name.eq_ignore_ascii_case("COSH") {
6434 Some("COSH")
6435 } else if name.eq_ignore_ascii_case("TANH") {
6436 Some("TANH")
6437 } else if name.eq_ignore_ascii_case("ASINH") {
6438 Some("ASINH")
6439 } else if name.eq_ignore_ascii_case("ACOSH") {
6440 Some("ACOSH")
6441 } else if name.eq_ignore_ascii_case("ATANH") {
6442 Some("ATANH")
6443 } else if name.eq_ignore_ascii_case("GCD") {
6444 Some("GCD")
6445 } else if name.eq_ignore_ascii_case("LCM") {
6446 Some("LCM")
6447 } else if name.eq_ignore_ascii_case("QUOTE_LITERAL") {
6448 Some("QUOTE_LITERAL")
6449 } else if name.eq_ignore_ascii_case("WIDTH_BUCKET") {
6450 Some("WIDTH_BUCKET")
6451 } else if name.eq_ignore_ascii_case("SCALE") {
6452 Some("SCALE")
6453 } else if name.eq_ignore_ascii_case("TRIM_SCALE") {
6454 Some("TRIM_SCALE")
6455 } else if name.eq_ignore_ascii_case("MIN_SCALE") {
6456 Some("MIN_SCALE")
6457 } else if name.eq_ignore_ascii_case("FACTORIAL") {
6458 Some("FACTORIAL")
6459 } else if name.eq_ignore_ascii_case("PG_LSN") {
6460 Some("PG_LSN")
6461 } else if name.eq_ignore_ascii_case("TO_CHAR") {
6462 Some("TO_CHAR")
6463 } else if name.eq_ignore_ascii_case("PG_TYPEOF") {
6464 Some("PG_TYPEOF")
6465 } else if name.eq_ignore_ascii_case("BIT_AND") {
6466 Some("BIT_AND")
6467 } else if name.eq_ignore_ascii_case("BIT_OR") {
6468 Some("BIT_OR")
6469 } else if name.eq_ignore_ascii_case("BIT_XOR") {
6470 Some("BIT_XOR")
6471 } else if name.eq_ignore_ascii_case("CORR") {
6472 Some("CORR")
6473 } else if name.eq_ignore_ascii_case("COVAR_POP") {
6474 Some("COVAR_POP")
6475 } else if name.eq_ignore_ascii_case("COVAR_SAMP") {
6476 Some("COVAR_SAMP")
6477 } else if name.eq_ignore_ascii_case("REGR_AVGX") {
6478 Some("REGR_AVGX")
6479 } else if name.eq_ignore_ascii_case("REGR_AVGY") {
6480 Some("REGR_AVGY")
6481 } else if name.eq_ignore_ascii_case("REGR_COUNT") {
6482 Some("REGR_COUNT")
6483 } else if name.eq_ignore_ascii_case("REGR_INTERCEPT") {
6484 Some("REGR_INTERCEPT")
6485 } else if name.eq_ignore_ascii_case("REGR_R2") {
6486 Some("REGR_R2")
6487 } else if name.eq_ignore_ascii_case("REGR_SLOPE") {
6488 Some("REGR_SLOPE")
6489 } else if name.eq_ignore_ascii_case("REGR_SXX") {
6490 Some("REGR_SXX")
6491 } else if name.eq_ignore_ascii_case("REGR_SXY") {
6492 Some("REGR_SXY")
6493 } else if name.eq_ignore_ascii_case("REGR_SYY") {
6494 Some("REGR_SYY")
6495 } else if name.eq_ignore_ascii_case("FLOAT8_ACCUM") {
6496 Some("FLOAT8_ACCUM")
6497 } else if name.eq_ignore_ascii_case("FLOAT8_REGR_ACCUM") {
6498 Some("FLOAT8_REGR_ACCUM")
6499 } else if name.eq_ignore_ascii_case("FLOAT8_COMBINE") {
6500 Some("FLOAT8_COMBINE")
6501 } else if name.eq_ignore_ascii_case("FLOAT8_REGR_COMBINE") {
6502 Some("FLOAT8_REGR_COMBINE")
6503 } else if name.eq_ignore_ascii_case("BOOLAND_STATEFUNC") {
6504 Some("BOOLAND_STATEFUNC")
6505 } else if name.eq_ignore_ascii_case("BOOLOR_STATEFUNC") {
6506 Some("BOOLOR_STATEFUNC")
6507 } else {
6508 None
6509 }
6510 }
6511
6512 fn normalize_postgres_trim_for_tsql(expr: Expression) -> Result<Expression> {
6513 transform_recursive(expr, &|e| match e {
6514 Expression::Trim(trim) => {
6515 let mut trim = *trim;
6516 trim.characters = trim.characters.map(Self::strip_postgres_text_literal_cast);
6517 match trim.position {
6518 crate::expressions::TrimPosition::Both
6519 if trim.position_explicit && trim.characters.is_some() =>
6520 {
6521 trim.position_explicit = false;
6522 trim.sql_standard_syntax = true;
6523 Ok(Expression::Trim(Box::new(trim)))
6524 }
6525 crate::expressions::TrimPosition::Leading if trim.characters.is_some() => {
6526 let characters = trim.characters.take().expect("checked above");
6527 Ok(Expression::Function(Box::new(Function::new(
6528 "LTRIM",
6529 vec![trim.this, characters],
6530 ))))
6531 }
6532 crate::expressions::TrimPosition::Trailing if trim.characters.is_some() => {
6533 let characters = trim.characters.take().expect("checked above");
6534 Ok(Expression::Function(Box::new(Function::new(
6535 "RTRIM",
6536 vec![trim.this, characters],
6537 ))))
6538 }
6539 _ => Ok(Expression::Trim(Box::new(trim))),
6540 }
6541 }
6542 other => Ok(other),
6543 })
6544 }
6545
6546 fn normalize_postgres_string_semantics_for_tsql(expr: Expression) -> Result<Expression> {
6547 transform_recursive(expr, &|e| match e {
6548 Expression::Like(mut op) => {
6549 Self::recover_postgres_like_escape(&mut op);
6550 Ok(Expression::Like(op))
6551 }
6552 Expression::ILike(mut op) => {
6553 Self::recover_postgres_like_escape(&mut op);
6554 Ok(Expression::ILike(op))
6555 }
6556 Expression::Substring(mut substring)
6557 if substring.length.is_none()
6558 && Self::is_explicitly_numeric_expression(&substring.start) =>
6559 {
6560 substring.length = Some(Expression::number(i32::MAX as i64));
6561 Ok(Expression::Substring(substring))
6562 }
6563 Expression::Trim(mut trim) => {
6564 trim.characters = trim.characters.map(Self::strip_postgres_text_literal_cast);
6565 Ok(Expression::Trim(trim))
6566 }
6567 Expression::Function(mut function)
6568 if !function.quoted
6569 && matches!(
6570 function.name.to_ascii_uppercase().as_str(),
6571 "BTRIM" | "LTRIM" | "RTRIM"
6572 )
6573 && function.args.len() == 2 =>
6574 {
6575 function.args[1] = Self::strip_postgres_text_literal_cast(function.args[1].clone());
6576 Ok(Expression::Function(function))
6577 }
6578 Expression::Translate(translate) => {
6579 Ok(Self::normalize_postgres_translate_for_tsql(*translate))
6580 }
6581 Expression::Function(function)
6582 if !function.quoted
6583 && function.name.eq_ignore_ascii_case("TRANSLATE")
6584 && function.args.len() == 3 =>
6585 {
6586 Ok(Self::normalize_postgres_translate_function_for_tsql(
6587 *function,
6588 ))
6589 }
6590 other => Ok(other),
6591 })
6592 }
6593
6594 fn normalize_postgres_bytea_literals_for_tsql(expr: Expression) -> Result<Expression> {
6595 transform_recursive(expr, &|e| match e {
6596 Expression::Cast(cast) if Self::is_postgres_bytea_data_type(&cast.to) => {
6597 let Some(value) = Self::postgres_plain_string_literal_value(&cast.this) else {
6598 return Ok(Expression::Cast(cast));
6599 };
6600 let Some(hex) = Self::postgres_bytea_hex_payload(value) else {
6601 return Ok(Expression::Cast(cast));
6602 };
6603
6604 Ok(Expression::Literal(Box::new(Literal::HexString(hex))))
6608 }
6609 other => Ok(other),
6610 })
6611 }
6612
6613 fn postgres_plain_string_literal_value(expr: &Expression) -> Option<&str> {
6614 match expr {
6615 Expression::Literal(literal) => match literal.as_ref() {
6616 Literal::String(value) => Some(value),
6617 _ => None,
6618 },
6619 Expression::Paren(paren) => Self::postgres_plain_string_literal_value(&paren.this),
6620 _ => None,
6621 }
6622 }
6623
6624 fn postgres_bytea_hex_payload(value: &str) -> Option<String> {
6625 let payload = value.strip_prefix("\\x")?;
6626 if payload.is_empty() {
6627 return Some(String::new());
6628 }
6629
6630 let mut chars = payload.chars().peekable();
6631 let mut hex = String::with_capacity(payload.len());
6632 loop {
6633 let high = chars.next()?;
6634 let low = chars.next()?;
6635 if !high.is_ascii_hexdigit() || !low.is_ascii_hexdigit() {
6636 return None;
6637 }
6638 hex.push(high);
6639 hex.push(low);
6640
6641 let Some(next) = chars.peek().copied() else {
6642 return Some(hex);
6643 };
6644 if next.is_ascii_whitespace() {
6645 while chars
6646 .peek()
6647 .is_some_and(|character| character.is_ascii_whitespace())
6648 {
6649 chars.next();
6650 }
6651 chars.peek()?;
6654 }
6655 }
6656 }
6657
6658 fn is_postgres_bytea_data_type(data_type: &DataType) -> bool {
6659 match data_type {
6660 DataType::VarBinary { length: None } => true,
6661 DataType::Custom { name } => name.trim().eq_ignore_ascii_case("BYTEA"),
6662 _ => false,
6663 }
6664 }
6665
6666 fn postgres_tsql_unsupported_binary_semantics(expr: &Expression) -> Option<&'static str> {
6667 let cast = match expr {
6668 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
6669 if Self::is_postgres_bytea_data_type(&cast.to) =>
6670 {
6671 cast
6672 }
6673 _ => return None,
6674 };
6675
6676 let literal = match &cast.this {
6677 Expression::Literal(literal) => literal.as_ref(),
6678 Expression::Paren(paren) => match &paren.this {
6679 Expression::Literal(literal) => literal.as_ref(),
6680 _ => return None,
6681 },
6682 _ => return None,
6683 };
6684 let value = match literal {
6685 Literal::String(value) | Literal::EscapeString(value) => value,
6686 _ => return None,
6687 };
6688
6689 if value.starts_with("\\x") {
6690 Some("bytea hex literals with invalid or unsupported formatting")
6691 } else if value.contains('\\') {
6692 Some("bytea escape-format literals")
6693 } else {
6694 None
6695 }
6696 }
6697
6698 fn recover_postgres_like_escape(op: &mut crate::expressions::LikeOp) {
6699 if op.escape.is_some() {
6700 return;
6701 }
6702
6703 let Expression::Function(function) = &op.right else {
6704 return;
6705 };
6706 if function.quoted
6707 || function.distinct
6708 || !function.name.eq_ignore_ascii_case("LIKE_ESCAPE")
6709 || function.args.len() != 2
6710 {
6711 return;
6712 }
6713
6714 let pattern = function.args[0].clone();
6715 let escape = function.args[1].clone();
6716 op.right = Self::strip_postgres_text_literal_cast(pattern);
6717 op.escape = Some(Self::strip_postgres_text_literal_cast(escape));
6718 }
6719
6720 fn normalize_postgres_translate_for_tsql(
6721 mut translate: crate::expressions::Translate,
6722 ) -> Expression {
6723 let (Some(from), Some(to)) = (&translate.from_, &translate.to) else {
6724 return Expression::Translate(Box::new(translate));
6725 };
6726
6727 let (Some(from_value), Some(to_value)) = (
6728 Self::postgres_text_literal_value(from),
6729 Self::postgres_text_literal_value(to),
6730 ) else {
6731 return Expression::Translate(Box::new(translate));
6732 };
6733 let from_value = from_value.to_string();
6734 let to_value = to_value.to_string();
6735
6736 if from_value.chars().count() > to_value.chars().count() {
6737 if let Some(input) = Self::postgres_text_literal_value(&translate.this) {
6738 return Expression::string(Self::translate_postgres_literal(
6739 input,
6740 &from_value,
6741 &to_value,
6742 ));
6743 }
6744 return Expression::Translate(Box::new(translate));
6745 }
6746
6747 translate.from_ = Some(Box::new(Self::strip_postgres_text_literal_cast(
6748 *translate.from_.expect("checked above"),
6749 )));
6750 let normalized_to = if from_value.chars().count() < to_value.chars().count() {
6751 Expression::string(
6752 to_value
6753 .chars()
6754 .take(from_value.chars().count())
6755 .collect::<String>(),
6756 )
6757 } else {
6758 Self::strip_postgres_text_literal_cast(*translate.to.expect("checked above"))
6759 };
6760 translate.to = Some(Box::new(normalized_to));
6761 Expression::Translate(Box::new(translate))
6762 }
6763
6764 fn normalize_postgres_translate_function_for_tsql(mut function: Function) -> Expression {
6765 let from = Self::postgres_text_literal_value(&function.args[1]);
6766 let to = Self::postgres_text_literal_value(&function.args[2]);
6767 let (Some(from), Some(to)) = (from, to) else {
6768 return Expression::Function(Box::new(function));
6769 };
6770 let from = from.to_string();
6771 let to = to.to_string();
6772
6773 if from.chars().count() > to.chars().count() {
6774 if let Some(input) = Self::postgres_text_literal_value(&function.args[0]) {
6775 return Expression::string(Self::translate_postgres_literal(input, &from, &to));
6776 }
6777 return Expression::Function(Box::new(function));
6778 }
6779
6780 function.args[1] = Self::strip_postgres_text_literal_cast(function.args[1].clone());
6781 function.args[2] = if from.chars().count() < to.chars().count() {
6782 Expression::string(to.chars().take(from.chars().count()).collect::<String>())
6783 } else {
6784 Self::strip_postgres_text_literal_cast(function.args[2].clone())
6785 };
6786 Expression::Function(Box::new(function))
6787 }
6788
6789 fn translate_postgres_literal(input: &str, from: &str, to: &str) -> String {
6790 let from = from.chars().collect::<Vec<_>>();
6791 let to = to.chars().collect::<Vec<_>>();
6792 let mut output = String::with_capacity(input.len());
6793
6794 for ch in input.chars() {
6795 match from.iter().position(|candidate| *candidate == ch) {
6796 Some(index) if index < to.len() => output.push(to[index]),
6797 Some(_) => {}
6798 None => output.push(ch),
6799 }
6800 }
6801
6802 output
6803 }
6804
6805 fn postgres_tsql_unsupported_string_semantics(expr: &Expression) -> Option<&'static str> {
6806 match expr {
6807 Expression::Substring(substring) if substring.length.is_none() => {
6808 if Self::postgres_text_literal_value(&substring.start).is_some() {
6809 Some("regular-expression SUBSTRING")
6810 } else {
6811 Some("SUBSTRING without a statically numeric start position")
6812 }
6813 }
6814 Expression::Translate(translate) => {
6815 let from = translate
6816 .from_
6817 .as_deref()
6818 .and_then(Self::postgres_text_literal_value);
6819 let to = translate
6820 .to
6821 .as_deref()
6822 .and_then(Self::postgres_text_literal_value);
6823 match (from, to) {
6824 (Some(from), Some(to)) if from.chars().count() == to.chars().count() => None,
6825 _ => Some("TRANSLATE with source and replacement lengths that differ or cannot be proven equal"),
6826 }
6827 }
6828 Expression::Function(function)
6829 if !function.quoted && function.name.eq_ignore_ascii_case("LIKE_ESCAPE") =>
6830 {
6831 Some("LIKE_ESCAPE helper outside a LIKE predicate")
6832 }
6833 Expression::Function(function)
6834 if !function.quoted
6835 && function.name.eq_ignore_ascii_case("TRANSLATE")
6836 && function.args.len() == 3 =>
6837 {
6838 let from = Self::postgres_text_literal_value(&function.args[1]);
6839 let to = Self::postgres_text_literal_value(&function.args[2]);
6840 match (from, to) {
6841 (Some(from), Some(to)) if from.chars().count() == to.chars().count() => None,
6842 _ => Some("TRANSLATE with source and replacement lengths that differ or cannot be proven equal"),
6843 }
6844 }
6845 Expression::Trim(trim)
6846 if trim
6847 .characters
6848 .as_ref()
6849 .is_some_and(Self::is_unbounded_text_cast) =>
6850 {
6851 Some("TRIM character set cast to an unbounded text type")
6852 }
6853 Expression::Function(function)
6854 if !function.quoted
6855 && matches!(
6856 function.name.to_ascii_uppercase().as_str(),
6857 "LTRIM" | "RTRIM"
6858 )
6859 && function.args.len() == 2
6860 && Self::is_unbounded_text_cast(&function.args[1]) =>
6861 {
6862 Some("TRIM character set cast to an unbounded text type")
6863 }
6864 _ => None,
6865 }
6866 }
6867
6868 fn strip_postgres_text_literal_cast(expr: Expression) -> Expression {
6869 match expr {
6870 Expression::Cast(cast)
6871 if Self::is_text_data_type(&cast.to)
6872 && Self::postgres_text_literal_value(&cast.this).is_some() =>
6873 {
6874 Self::strip_postgres_text_literal_cast(cast.this)
6875 }
6876 Expression::TryCast(cast)
6877 if Self::is_text_data_type(&cast.to)
6878 && Self::postgres_text_literal_value(&cast.this).is_some() =>
6879 {
6880 Self::strip_postgres_text_literal_cast(cast.this)
6881 }
6882 Expression::SafeCast(cast)
6883 if Self::is_text_data_type(&cast.to)
6884 && Self::postgres_text_literal_value(&cast.this).is_some() =>
6885 {
6886 Self::strip_postgres_text_literal_cast(cast.this)
6887 }
6888 Expression::Paren(mut paren)
6889 if Self::postgres_text_literal_value(&paren.this).is_some() =>
6890 {
6891 paren.this = Self::strip_postgres_text_literal_cast(paren.this);
6892 Expression::Paren(paren)
6893 }
6894 other => other,
6895 }
6896 }
6897
6898 fn postgres_text_literal_value(expr: &Expression) -> Option<&str> {
6899 match expr {
6900 Expression::Literal(literal) if literal.is_string() => Some(literal.value_str()),
6901 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
6902 if Self::is_text_data_type(&cast.to) =>
6903 {
6904 Self::postgres_text_literal_value(&cast.this)
6905 }
6906 Expression::Alias(alias) => Self::postgres_text_literal_value(&alias.this),
6907 Expression::Paren(paren) => Self::postgres_text_literal_value(&paren.this),
6908 _ => None,
6909 }
6910 }
6911
6912 fn is_text_data_type(data_type: &DataType) -> bool {
6913 match data_type {
6914 DataType::Char { .. }
6915 | DataType::VarChar { .. }
6916 | DataType::String { .. }
6917 | DataType::Text
6918 | DataType::TextWithLength { .. } => true,
6919 DataType::Custom { name } => {
6920 let base = name
6921 .split_once('(')
6922 .map_or(name.as_str(), |(base, _)| base)
6923 .trim();
6924 matches!(
6925 base.to_ascii_uppercase().as_str(),
6926 "CHAR"
6927 | "NCHAR"
6928 | "VARCHAR"
6929 | "NVARCHAR"
6930 | "TEXT"
6931 | "NTEXT"
6932 | "STRING"
6933 | "CHARACTER VARYING"
6934 )
6935 }
6936 _ => false,
6937 }
6938 }
6939
6940 fn is_unbounded_text_cast(expr: &Expression) -> bool {
6941 let data_type = match expr {
6942 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
6943 &cast.to
6944 }
6945 Expression::Paren(paren) => return Self::is_unbounded_text_cast(&paren.this),
6946 _ => return false,
6947 };
6948
6949 match data_type {
6950 DataType::Text => true,
6951 DataType::VarChar { length: None, .. } | DataType::String { length: None } => true,
6952 DataType::Custom { name } => name.to_ascii_uppercase().contains("(MAX)"),
6953 _ => false,
6954 }
6955 }
6956
6957 fn is_explicitly_numeric_expression(expr: &Expression) -> bool {
6958 if expr.inferred_type().is_some_and(Self::is_numeric_data_type) {
6959 return true;
6960 }
6961
6962 match expr {
6963 Expression::Literal(literal) => literal.is_number(),
6964 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
6965 Self::is_numeric_data_type(&cast.to)
6966 }
6967 Expression::Alias(alias) => Self::is_explicitly_numeric_expression(&alias.this),
6968 Expression::Paren(paren) => Self::is_explicitly_numeric_expression(&paren.this),
6969 Expression::Neg(unary) => Self::is_explicitly_numeric_expression(&unary.this),
6970 _ => false,
6971 }
6972 }
6973
6974 fn is_numeric_data_type(data_type: &DataType) -> bool {
6975 match data_type {
6976 DataType::TinyInt { .. }
6977 | DataType::SmallInt { .. }
6978 | DataType::Int { .. }
6979 | DataType::BigInt { .. }
6980 | DataType::Float { .. }
6981 | DataType::Double { .. }
6982 | DataType::Decimal { .. } => true,
6983 DataType::Custom { name } => {
6984 let base = name
6985 .split_once('(')
6986 .map_or(name.as_str(), |(base, _)| base)
6987 .trim();
6988 matches!(
6989 base.to_ascii_uppercase().as_str(),
6990 "TINYINT"
6991 | "SMALLINT"
6992 | "INT"
6993 | "INTEGER"
6994 | "BIGINT"
6995 | "DECIMAL"
6996 | "NUMERIC"
6997 | "REAL"
6998 | "FLOAT"
6999 | "MONEY"
7000 | "SMALLMONEY"
7001 )
7002 }
7003 _ => false,
7004 }
7005 }
7006
7007 fn normalize_postgres_only_for_tsql(expr: Expression) -> Result<Expression> {
7008 transform_recursive(expr, &|e| match e {
7009 Expression::Table(mut table) if table.only => {
7010 table.only = false;
7011 Ok(Expression::Table(table))
7012 }
7013 other => Ok(other),
7014 })
7015 }
7016
7017 fn rewrite_postgres_json_array_elements_select_for_tsql(
7018 expr: Expression,
7019 ) -> Result<Expression> {
7020 let Expression::Select(select) = expr else {
7021 return Ok(expr);
7022 };
7023 let mut select = *select;
7024 if !Self::is_plain_single_projection_select(&select) {
7025 return Ok(Expression::Select(Box::new(select)));
7026 }
7027
7028 let Some(json_arg) =
7029 Self::postgres_json_array_elements_projection_arg(&select.expressions[0])
7030 else {
7031 return Ok(Expression::Select(Box::new(select)));
7032 };
7033
7034 select.expressions = vec![Expression::column("value")];
7035 select.from = Some(From {
7036 expressions: vec![Expression::OpenJSON(Box::new(
7037 crate::expressions::OpenJSON {
7038 this: Box::new(json_arg),
7039 path: None,
7040 expressions: Vec::new(),
7041 },
7042 ))],
7043 });
7044
7045 Ok(Expression::Select(Box::new(select)))
7046 }
7047
7048 fn is_plain_single_projection_select(select: &crate::expressions::Select) -> bool {
7049 select.expressions.len() == 1
7050 && select.from.is_none()
7051 && select.joins.is_empty()
7052 && select.lateral_views.is_empty()
7053 && select.prewhere.is_none()
7054 && select.where_clause.is_none()
7055 && select.group_by.is_none()
7056 && select.having.is_none()
7057 && select.qualify.is_none()
7058 && select.order_by.is_none()
7059 && select.distribute_by.is_none()
7060 && select.cluster_by.is_none()
7061 && select.sort_by.is_none()
7062 && select.limit.is_none()
7063 && select.offset.is_none()
7064 && select.limit_by.is_none()
7065 && select.fetch.is_none()
7066 && !select.distinct
7067 && select.distinct_on.is_none()
7068 && select.top.is_none()
7069 && select.with.is_none()
7070 && select.sample.is_none()
7071 && select.into.is_none()
7072 && select.locks.is_empty()
7073 && select.for_xml.is_empty()
7074 && select.for_json.is_empty()
7075 && select.exclude.is_none()
7076 }
7077
7078 fn postgres_json_array_elements_projection_arg(expr: &Expression) -> Option<Expression> {
7079 match expr {
7080 Expression::Function(function)
7081 if Self::node_is_postgres_json_array_elements(expr) && function.args.len() == 1 =>
7082 {
7083 Some(function.args[0].clone())
7084 }
7085 Expression::Alias(alias) => {
7086 Self::postgres_json_array_elements_projection_arg(&alias.this)
7087 }
7088 _ => None,
7089 }
7090 }
7091
7092 fn normalize_postgres_type_function_casts(
7093 expr: Expression,
7094 target: DialectType,
7095 ) -> Result<Expression> {
7096 transform_recursive(expr, &|e| match e {
7097 Expression::Function(function) => {
7098 let mut function = *function;
7099 if function.args.len() == 1
7100 && !function.distinct
7101 && !function.quoted
7102 && !function.use_bracket_syntax
7103 && !function.name.contains('.')
7104 {
7105 if let Some(to) = Self::postgres_type_function_data_type(&function.name) {
7106 let this = function.args.remove(0);
7107 let cast = Cast {
7108 this,
7109 to,
7110 trailing_comments: function.trailing_comments,
7111 double_colon_syntax: false,
7112 format: None,
7113 default: None,
7114 inferred_type: function.inferred_type,
7115 };
7116 return Ok(
7117 if matches!(target, DialectType::TSQL | DialectType::Fabric) {
7118 normalization::rewrite_postgres_float_to_integer_cast(cast)
7119 } else {
7120 Expression::Cast(Box::new(cast))
7121 },
7122 );
7123 }
7124 }
7125 Ok(Expression::Function(Box::new(function)))
7126 }
7127 _ => Ok(e),
7128 })
7129 }
7130
7131 fn node_is_postgres_type_function_cast(expr: &Expression) -> bool {
7132 matches!(
7133 expr,
7134 Expression::Function(function)
7135 if !function.quoted
7136 && !function.use_bracket_syntax
7137 && !function.name.contains('.')
7138 && Self::postgres_type_function_data_type(&function.name).is_some()
7139 )
7140 }
7141
7142 fn postgres_type_function_data_type(name: &str) -> Option<DataType> {
7143 match name.to_ascii_uppercase().as_str() {
7144 "NUMERIC" | "DECIMAL" | "DEC" => Some(DataType::Decimal {
7145 precision: None,
7146 scale: None,
7147 }),
7148 "INT2" | "SMALLINT" => Some(DataType::SmallInt { length: None }),
7149 "INT4" | "INT" => Some(DataType::Int {
7150 length: None,
7151 integer_spelling: false,
7152 }),
7153 "INTEGER" => Some(DataType::Int {
7154 length: None,
7155 integer_spelling: true,
7156 }),
7157 "INT8" | "BIGINT" => Some(DataType::BigInt { length: None }),
7158 "FLOAT4" | "REAL" => Some(DataType::Float {
7159 precision: None,
7160 scale: None,
7161 real_spelling: true,
7162 }),
7163 "FLOAT8" => Some(DataType::Double {
7164 precision: None,
7165 scale: None,
7166 }),
7167 "BOOL" | "BOOLEAN" => Some(DataType::Boolean),
7168 "TEXT" => Some(DataType::Text),
7169 "VARCHAR" => Some(DataType::VarChar {
7170 length: None,
7171 parenthesized_length: false,
7172 }),
7173 "UUID" => Some(DataType::Uuid),
7174 _ => None,
7175 }
7176 }
7177
7178 fn rewrite_boolean_values_for_tsql(expr: Expression) -> Result<Expression> {
7179 match expr {
7180 Expression::Select(select) => Self::rewrite_boolean_values_in_tsql_select(select),
7181 Expression::Subquery(mut subquery) => {
7182 subquery.this = Self::rewrite_boolean_values_for_tsql(subquery.this)?;
7183 Ok(Expression::Subquery(subquery))
7184 }
7185 Expression::Union(mut union) => {
7186 let left = std::mem::replace(&mut union.left, Expression::null());
7187 let right = std::mem::replace(&mut union.right, Expression::null());
7188 union.left = Self::rewrite_boolean_values_for_tsql(left)?;
7189 union.right = Self::rewrite_boolean_values_for_tsql(right)?;
7190 if let Some(mut with) = union.with.take() {
7191 with.ctes = with
7192 .ctes
7193 .into_iter()
7194 .map(|mut cte| {
7195 cte.this = Self::rewrite_boolean_values_for_tsql(cte.this)?;
7196 Ok(cte)
7197 })
7198 .collect::<Result<Vec<_>>>()?;
7199 union.with = Some(with);
7200 }
7201 Ok(Expression::Union(union))
7202 }
7203 Expression::Intersect(mut intersect) => {
7204 let left = std::mem::replace(&mut intersect.left, Expression::null());
7205 let right = std::mem::replace(&mut intersect.right, Expression::null());
7206 intersect.left = Self::rewrite_boolean_values_for_tsql(left)?;
7207 intersect.right = Self::rewrite_boolean_values_for_tsql(right)?;
7208 Ok(Expression::Intersect(intersect))
7209 }
7210 Expression::Except(mut except) => {
7211 let left = std::mem::replace(&mut except.left, Expression::null());
7212 let right = std::mem::replace(&mut except.right, Expression::null());
7213 except.left = Self::rewrite_boolean_values_for_tsql(left)?;
7214 except.right = Self::rewrite_boolean_values_for_tsql(right)?;
7215 Ok(Expression::Except(except))
7216 }
7217 other => Self::rewrite_tsql_boolean_nested_contexts(other),
7218 }
7219 }
7220
7221 fn rewrite_postgres_row_value_equality_for_tsql(expr: Expression) -> Result<Expression> {
7222 transform_recursive(expr, &|e| match e {
7223 Expression::Eq(op) => {
7224 let op = *op;
7225 Ok(Self::postgres_row_value_equality_to_tsql_scalar(&op)
7226 .unwrap_or_else(|| Expression::Eq(Box::new(op))))
7227 }
7228 other => Ok(other),
7229 })
7230 }
7231
7232 fn postgres_row_value_equality_to_tsql_scalar(op: &BinaryOp) -> Option<Expression> {
7233 let (row, query) =
7234 if Self::expr_is_row_value(&op.left) && Self::expr_is_subquery_like(&op.right) {
7235 (&op.left, &op.right)
7236 } else if Self::expr_is_row_value(&op.right) && Self::expr_is_subquery_like(&op.left) {
7237 (&op.right, &op.left)
7238 } else {
7239 return None;
7240 };
7241
7242 let row_values = Self::row_value_expressions(row)?;
7243 let projection_count = Self::subquery_projection_count(query)?;
7244 if row_values.is_empty() || row_values.len() != projection_count {
7245 return None;
7246 }
7247
7248 let mut taken_names = HashSet::new();
7253 Self::collect_generated_alias_conflicts(row, &mut taken_names);
7254 Self::collect_generated_alias_conflicts(query, &mut taken_names);
7255
7256 let source_alias = find_new_name(&taken_names, "_polyglot_row");
7257 taken_names.insert(source_alias.to_ascii_lowercase());
7258 let column_aliases = (1..=row_values.len())
7259 .map(|index| {
7260 let name = find_new_name(&taken_names, &format!("_polyglot_row_value_{index}"));
7261 taken_names.insert(name.to_ascii_lowercase());
7262 Identifier::new(name)
7263 })
7264 .collect::<Vec<_>>();
7265 let source = Self::subquery_as_derived_table(
7266 query,
7267 Identifier::new(&source_alias),
7268 column_aliases.clone(),
7269 )?;
7270
7271 let mut equal_components = Vec::with_capacity(row_values.len());
7272 let mut unequal_components = Vec::with_capacity(row_values.len());
7273 for (column, row_value) in column_aliases.into_iter().zip(row_values) {
7274 let projected = Expression::qualified_column(source_alias.clone(), column.name);
7275 equal_components.push(Expression::Eq(Box::new(BinaryOp::new(
7276 projected.clone(),
7277 row_value.clone(),
7278 ))));
7279 unequal_components.push(Expression::Neq(Box::new(BinaryOp::new(
7280 projected, row_value,
7281 ))));
7282 }
7283
7284 let all_equal = equal_components
7285 .into_iter()
7286 .reduce(|left, right| Expression::And(Box::new(BinaryOp::new(left, right))))?;
7287 let any_unequal = unequal_components
7288 .into_iter()
7289 .reduce(|left, right| Expression::Or(Box::new(BinaryOp::new(left, right))))?;
7290 let comparison = Expression::Case(Box::new(Case {
7291 operand: None,
7292 whens: vec![
7293 (all_equal, Expression::number(1)),
7294 (any_unequal, Expression::number(0)),
7295 ],
7296 else_: Some(Expression::null()),
7297 comments: Vec::new(),
7298 inferred_type: None,
7299 }));
7300
7301 let scalar_select = Select::new().column(comparison).from(source);
7302 let scalar_subquery = Expression::Subquery(Box::new(Subquery {
7303 this: Expression::Select(Box::new(scalar_select)),
7304 alias: None,
7305 column_aliases: Vec::new(),
7306 alias_explicit_as: false,
7307 alias_keyword: None,
7308 order_by: None,
7309 limit: None,
7310 offset: None,
7311 distribute_by: None,
7312 sort_by: None,
7313 cluster_by: None,
7314 lateral: false,
7315 modifiers_inside: false,
7316 trailing_comments: Vec::new(),
7317 inferred_type: Some(DataType::Boolean),
7318 }));
7319
7320 Some(Expression::Cast(Box::new(Cast {
7321 this: scalar_subquery,
7322 to: DataType::Boolean,
7323 trailing_comments: Vec::new(),
7324 double_colon_syntax: false,
7325 format: None,
7326 default: None,
7327 inferred_type: Some(DataType::Boolean),
7328 })))
7329 }
7330
7331 fn row_value_expressions(expr: &Expression) -> Option<Vec<Expression>> {
7332 match expr {
7333 Expression::Tuple(tuple) => Some(tuple.expressions.clone()),
7334 Expression::Function(function) if function.name.eq_ignore_ascii_case("ROW") => {
7335 Some(function.args.clone())
7336 }
7337 Expression::Paren(paren) => Self::row_value_expressions(&paren.this),
7338 _ => None,
7339 }
7340 }
7341
7342 fn subquery_projection_count(expr: &Expression) -> Option<usize> {
7343 match expr {
7344 Expression::Select(select) => Some(select.expressions.len()),
7345 Expression::Subquery(subquery) => Self::subquery_projection_count(&subquery.this),
7346 Expression::Paren(paren) => Self::subquery_projection_count(&paren.this),
7347 _ => None,
7348 }
7349 }
7350
7351 fn subquery_as_derived_table(
7352 expr: &Expression,
7353 alias: Identifier,
7354 column_aliases: Vec<Identifier>,
7355 ) -> Option<Expression> {
7356 match expr.clone() {
7357 Expression::Subquery(mut subquery) => {
7358 subquery.alias = Some(alias);
7359 subquery.column_aliases = column_aliases;
7360 subquery.alias_explicit_as = true;
7361 subquery.alias_keyword = None;
7362 Some(Expression::Subquery(subquery))
7363 }
7364 Expression::Select(_) | Expression::Paren(_) => {
7365 Some(Expression::Subquery(Box::new(Subquery {
7366 this: expr.clone(),
7367 alias: Some(alias),
7368 column_aliases,
7369 alias_explicit_as: true,
7370 alias_keyword: None,
7371 order_by: None,
7372 limit: None,
7373 offset: None,
7374 distribute_by: None,
7375 sort_by: None,
7376 cluster_by: None,
7377 lateral: false,
7378 modifiers_inside: false,
7379 trailing_comments: Vec::new(),
7380 inferred_type: None,
7381 })))
7382 }
7383 _ => None,
7384 }
7385 }
7386
7387 fn collect_generated_alias_conflicts(expr: &Expression, names: &mut HashSet<String>) {
7388 fn insert(names: &mut HashSet<String>, identifier: &Identifier) {
7389 if !identifier.name.is_empty() {
7390 names.insert(identifier.name.to_ascii_lowercase());
7391 }
7392 }
7393
7394 for node in expr.dfs() {
7395 match node {
7396 Expression::Identifier(identifier) => insert(names, identifier),
7397 Expression::Column(column) => {
7398 insert(names, &column.name);
7399 if let Some(table) = &column.table {
7400 insert(names, table);
7401 }
7402 }
7403 Expression::Table(table) => {
7404 insert(names, &table.name);
7405 if let Some(schema) = &table.schema {
7406 insert(names, schema);
7407 }
7408 if let Some(catalog) = &table.catalog {
7409 insert(names, catalog);
7410 }
7411 if let Some(alias) = &table.alias {
7412 insert(names, alias);
7413 }
7414 for alias in &table.column_aliases {
7415 insert(names, alias);
7416 }
7417 }
7418 Expression::Alias(alias) => {
7419 insert(names, &alias.alias);
7420 for column_alias in &alias.column_aliases {
7421 insert(names, column_alias);
7422 }
7423 }
7424 Expression::Subquery(subquery) => {
7425 if let Some(alias) = &subquery.alias {
7426 insert(names, alias);
7427 }
7428 for column_alias in &subquery.column_aliases {
7429 insert(names, column_alias);
7430 }
7431 }
7432 Expression::Cte(cte) => {
7433 insert(names, &cte.alias);
7434 for column in &cte.columns {
7435 insert(names, column);
7436 }
7437 for key in &cte.key_expressions {
7438 insert(names, key);
7439 }
7440 }
7441 Expression::Values(values) => {
7442 if let Some(alias) = &values.alias {
7443 insert(names, alias);
7444 }
7445 for column_alias in &values.column_aliases {
7446 insert(names, column_alias);
7447 }
7448 }
7449 Expression::Unnest(unnest) => {
7450 if let Some(alias) = &unnest.alias {
7451 insert(names, alias);
7452 }
7453 if let Some(offset_alias) = &unnest.offset_alias {
7454 insert(names, offset_alias);
7455 }
7456 }
7457 _ => {}
7458 }
7459 }
7460 }
7461
7462 fn rewrite_postgres_format_for_tsql(
7463 expr: Expression,
7464 target: DialectType,
7465 ) -> Result<Expression> {
7466 transform_recursive(expr, &|e| match e {
7467 Expression::Function(f) if f.name.eq_ignore_ascii_case("FORMAT") => {
7468 Self::postgres_format_function_to_tsql(*f, target)
7469 }
7470 other => Ok(other),
7471 })
7472 }
7473
7474 fn postgres_format_function_to_tsql(f: Function, target: DialectType) -> Result<Expression> {
7475 let Some(format_expr) = f.args.first() else {
7476 return Err(Self::unsupported_postgres_format_for_tsql(
7477 target,
7478 "missing format string",
7479 ));
7480 };
7481
7482 let format = match format_expr {
7483 Expression::Literal(lit) if lit.is_string() => lit.value_str(),
7484 _ => {
7485 return Err(Self::unsupported_postgres_format_for_tsql(
7486 target,
7487 "dynamic format strings",
7488 ))
7489 }
7490 };
7491
7492 let value_args = &f.args[1..];
7493 let mut arg_index = 0usize;
7494 let mut literal = String::new();
7495 let mut segments = Vec::new();
7496 let mut chars = format.chars();
7497
7498 while let Some(ch) = chars.next() {
7499 if ch != '%' {
7500 literal.push(ch);
7501 continue;
7502 }
7503
7504 let Some(specifier) = chars.next() else {
7505 return Err(Self::unsupported_postgres_format_for_tsql(
7506 target,
7507 "unterminated format specifier",
7508 ));
7509 };
7510
7511 match specifier {
7512 '%' => literal.push('%'),
7513 's' => {
7514 if !literal.is_empty() {
7515 segments.push(Expression::string(std::mem::take(&mut literal)));
7516 }
7517 let Some(arg) = value_args.get(arg_index) else {
7518 return Err(Self::unsupported_postgres_format_for_tsql(
7519 target,
7520 "not enough arguments",
7521 ));
7522 };
7523 segments.push(arg.clone());
7524 arg_index += 1;
7525 }
7526 other => {
7527 return Err(Self::unsupported_postgres_format_for_tsql(
7528 target,
7529 format!("unsupported format specifier %{other}"),
7530 ))
7531 }
7532 }
7533 }
7534
7535 if !literal.is_empty() {
7536 segments.push(Expression::string(literal));
7537 }
7538
7539 if arg_index != value_args.len() {
7540 return Err(Self::unsupported_postgres_format_for_tsql(
7541 target,
7542 "unused format arguments",
7543 ));
7544 }
7545
7546 Ok(Self::postgres_format_segments_to_tsql_concat(segments))
7547 }
7548
7549 fn postgres_format_segments_to_tsql_concat(mut segments: Vec<Expression>) -> Expression {
7550 if segments.is_empty() {
7551 return Expression::string("");
7552 }
7553
7554 if segments.len() == 1 {
7555 let only = segments.pop().expect("one segment");
7556 if matches!(&only, Expression::Literal(lit) if lit.is_string()) {
7557 return only;
7558 }
7559
7560 return Expression::Function(Box::new(Function::new(
7561 "CONCAT".to_string(),
7562 vec![only, Expression::string("")],
7563 )));
7564 }
7565
7566 Expression::Function(Box::new(Function::new("CONCAT".to_string(), segments)))
7567 }
7568
7569 fn unsupported_postgres_format_for_tsql(
7570 target: DialectType,
7571 reason: impl Into<String>,
7572 ) -> crate::error::Error {
7573 crate::error::Error::unsupported(
7574 format!("PostgreSQL format() ({})", reason.into()),
7575 target.to_string(),
7576 )
7577 }
7578
7579 fn rewrite_boolean_values_in_tsql_select(
7580 mut select: Box<crate::expressions::Select>,
7581 ) -> Result<Expression> {
7582 if let Some(mut with) = select.with.take() {
7583 with.ctes = with
7584 .ctes
7585 .into_iter()
7586 .map(|mut cte| {
7587 cte.this = Self::rewrite_boolean_values_for_tsql(cte.this)?;
7588 Ok(cte)
7589 })
7590 .collect::<Result<Vec<_>>>()?;
7591 select.with = Some(with);
7592 }
7593
7594 select.expressions = select
7595 .expressions
7596 .into_iter()
7597 .map(Self::rewrite_tsql_boolean_scalar_value)
7598 .collect::<Result<Vec<_>>>()?;
7599
7600 if let Some(mut from) = select.from.take() {
7601 from.expressions = from
7602 .expressions
7603 .into_iter()
7604 .map(Self::rewrite_tsql_boolean_nested_contexts)
7605 .collect::<Result<Vec<_>>>()?;
7606 select.from = Some(from);
7607 }
7608
7609 select.joins = select
7610 .joins
7611 .into_iter()
7612 .map(|mut join| {
7613 join.this = Self::rewrite_tsql_boolean_nested_contexts(join.this)?;
7614 if let Some(on) = join.on.take() {
7615 join.on = Some(Self::rewrite_tsql_boolean_predicate_context(on)?);
7616 }
7617 if let Some(match_condition) = join.match_condition.take() {
7618 join.match_condition = Some(Self::rewrite_tsql_boolean_predicate_context(
7619 match_condition,
7620 )?);
7621 }
7622 join.pivots = join
7623 .pivots
7624 .into_iter()
7625 .map(Self::rewrite_tsql_boolean_nested_contexts)
7626 .collect::<Result<Vec<_>>>()?;
7627 Ok(join)
7628 })
7629 .collect::<Result<Vec<_>>>()?;
7630
7631 select.lateral_views = select
7632 .lateral_views
7633 .into_iter()
7634 .map(|mut lateral_view| {
7635 lateral_view.this = Self::rewrite_tsql_boolean_nested_contexts(lateral_view.this)?;
7636 Ok(lateral_view)
7637 })
7638 .collect::<Result<Vec<_>>>()?;
7639
7640 if let Some(prewhere) = select.prewhere.take() {
7641 select.prewhere = Some(Self::rewrite_tsql_boolean_predicate_context(prewhere)?);
7642 }
7643
7644 if let Some(mut where_clause) = select.where_clause.take() {
7645 where_clause.this = Self::rewrite_tsql_boolean_predicate_context(where_clause.this)?;
7646 select.where_clause = Some(where_clause);
7647 }
7648
7649 if let Some(mut group_by) = select.group_by.take() {
7650 group_by.expressions = group_by
7651 .expressions
7652 .into_iter()
7653 .map(Self::rewrite_tsql_boolean_scalar_value)
7654 .collect::<Result<Vec<_>>>()?;
7655 select.group_by = Some(group_by);
7656 }
7657
7658 if let Some(mut having) = select.having.take() {
7659 having.this = Self::rewrite_tsql_boolean_predicate_context(having.this)?;
7660 select.having = Some(having);
7661 }
7662
7663 if let Some(mut qualify) = select.qualify.take() {
7664 qualify.this = Self::rewrite_tsql_boolean_predicate_context(qualify.this)?;
7665 select.qualify = Some(qualify);
7666 }
7667
7668 if let Some(mut order_by) = select.order_by.take() {
7669 order_by.expressions = Self::rewrite_tsql_boolean_ordered_values(order_by.expressions)?;
7670 select.order_by = Some(order_by);
7671 }
7672
7673 if let Some(mut distribute_by) = select.distribute_by.take() {
7674 distribute_by.expressions = distribute_by
7675 .expressions
7676 .into_iter()
7677 .map(Self::rewrite_tsql_boolean_scalar_value)
7678 .collect::<Result<Vec<_>>>()?;
7679 select.distribute_by = Some(distribute_by);
7680 }
7681
7682 if let Some(mut cluster_by) = select.cluster_by.take() {
7683 cluster_by.expressions =
7684 Self::rewrite_tsql_boolean_ordered_values(cluster_by.expressions)?;
7685 select.cluster_by = Some(cluster_by);
7686 }
7687
7688 if let Some(mut sort_by) = select.sort_by.take() {
7689 sort_by.expressions = Self::rewrite_tsql_boolean_ordered_values(sort_by.expressions)?;
7690 select.sort_by = Some(sort_by);
7691 }
7692
7693 if let Some(limit_by) = select.limit_by.take() {
7694 select.limit_by = Some(
7695 limit_by
7696 .into_iter()
7697 .map(Self::rewrite_tsql_boolean_scalar_value)
7698 .collect::<Result<Vec<_>>>()?,
7699 );
7700 }
7701
7702 if let Some(distinct_on) = select.distinct_on.take() {
7703 select.distinct_on = Some(
7704 distinct_on
7705 .into_iter()
7706 .map(Self::rewrite_tsql_boolean_scalar_value)
7707 .collect::<Result<Vec<_>>>()?,
7708 );
7709 }
7710
7711 if let Some(mut sample) = select.sample.take() {
7712 sample.size = Self::rewrite_tsql_boolean_nested_contexts(sample.size)?;
7713 if let Some(offset) = sample.offset.take() {
7714 sample.offset = Some(Self::rewrite_tsql_boolean_nested_contexts(offset)?);
7715 }
7716 if let Some(bucket_numerator) = sample.bucket_numerator.take() {
7717 sample.bucket_numerator = Some(Box::new(
7718 Self::rewrite_tsql_boolean_nested_contexts(*bucket_numerator)?,
7719 ));
7720 }
7721 if let Some(bucket_denominator) = sample.bucket_denominator.take() {
7722 sample.bucket_denominator = Some(Box::new(
7723 Self::rewrite_tsql_boolean_nested_contexts(*bucket_denominator)?,
7724 ));
7725 }
7726 if let Some(bucket_field) = sample.bucket_field.take() {
7727 sample.bucket_field = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7728 *bucket_field,
7729 )?));
7730 }
7731 select.sample = Some(sample);
7732 }
7733
7734 if let Some(settings) = select.settings.take() {
7735 select.settings = Some(
7736 settings
7737 .into_iter()
7738 .map(Self::rewrite_tsql_boolean_nested_contexts)
7739 .collect::<Result<Vec<_>>>()?,
7740 );
7741 }
7742
7743 if let Some(format) = select.format.take() {
7744 select.format = Some(Self::rewrite_tsql_boolean_nested_contexts(format)?);
7745 }
7746
7747 if let Some(mut windows) = select.windows.take() {
7748 for window in windows.iter_mut() {
7749 Self::rewrite_tsql_boolean_over_values(&mut window.spec)?;
7750 }
7751 select.windows = Some(windows);
7752 }
7753
7754 Ok(Expression::Select(select))
7755 }
7756
7757 fn normalize_postgres_boolean_semantics_for_tsql(expr: Expression) -> Result<Expression> {
7758 transform_recursive(expr, &|e| match e {
7759 Expression::Function(function)
7760 if function.args.len() == 2
7761 && (function.name.eq_ignore_ascii_case("BOOLEQ")
7762 || function.name.eq_ignore_ascii_case("BOOLNE")) =>
7763 {
7764 let is_equal = function.name.eq_ignore_ascii_case("BOOLEQ");
7765 let mut args = function.args.into_iter();
7766 let op = BinaryOp {
7767 left: args.next().expect("checked boolean operator arity"),
7768 right: args.next().expect("checked boolean operator arity"),
7769 left_comments: Vec::new(),
7770 operator_comments: Vec::new(),
7771 trailing_comments: function.trailing_comments,
7772 inferred_type: None,
7773 };
7774 if is_equal {
7775 Ok(Expression::Eq(Box::new(op)))
7776 } else {
7777 Ok(Expression::Neq(Box::new(op)))
7778 }
7779 }
7780 Expression::Cast(cast)
7781 if matches!(cast.to, DataType::Text)
7782 && Self::is_known_postgres_boolean_expression(&cast.this) =>
7783 {
7784 Ok(Self::postgres_boolean_text_value(cast.this))
7785 }
7786 other => Ok(other),
7787 })
7788 }
7789
7790 fn is_known_postgres_boolean_expression(expr: &Expression) -> bool {
7791 match expr {
7792 Expression::Boolean(_) => true,
7793 Expression::Cast(cast) => matches!(cast.to, DataType::Boolean),
7794 Expression::Paren(paren) => Self::is_known_postgres_boolean_expression(&paren.this),
7795 other => Self::is_tsql_boolean_value_expression(other),
7796 }
7797 }
7798
7799 fn postgres_boolean_text_value(predicate: Expression) -> Expression {
7800 if let Expression::Boolean(boolean) = predicate {
7801 return Expression::string(if boolean.value { "true" } else { "false" });
7802 }
7803
7804 Self::three_valued_boolean_case(
7805 predicate,
7806 Expression::string("true"),
7807 Expression::string("false"),
7808 )
7809 }
7810
7811 fn rewrite_tsql_boolean_scalar_value(expr: Expression) -> Result<Expression> {
7812 if let Expression::Boolean(boolean) = expr {
7813 return Ok(Expression::Cast(Box::new(Cast {
7814 this: Expression::Boolean(boolean),
7815 to: DataType::Boolean,
7816 trailing_comments: Vec::new(),
7817 double_colon_syntax: false,
7818 format: None,
7819 default: None,
7820 inferred_type: None,
7821 })));
7822 }
7823
7824 if Self::is_tsql_boolean_value_expression(&expr) {
7825 let can_be_unknown = Self::tsql_boolean_expression_can_be_unknown(&expr)
7828 && !Self::node_is_row_value_subquery_comparison(&expr);
7829 let predicate = Self::rewrite_tsql_boolean_predicate_context(expr)?;
7830 return Ok(Self::tsql_boolean_value_case(predicate, can_be_unknown));
7831 }
7832
7833 match expr {
7834 Expression::Alias(mut alias) => {
7835 alias.this = Self::rewrite_tsql_boolean_scalar_value(alias.this)?;
7836 Ok(Expression::Alias(alias))
7837 }
7838 Expression::Paren(mut paren) => {
7839 paren.this = Self::rewrite_tsql_boolean_scalar_value(paren.this)?;
7840 Ok(Expression::Paren(paren))
7841 }
7842 Expression::Cast(mut cast) => {
7843 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
7844 if let Some(format) = cast.format.take() {
7845 cast.format = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7846 *format,
7847 )?));
7848 }
7849 if let Some(default) = cast.default.take() {
7850 cast.default =
7851 Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*default)?));
7852 }
7853 Ok(Expression::Cast(cast))
7854 }
7855 Expression::TryCast(mut cast) => {
7856 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
7857 if let Some(format) = cast.format.take() {
7858 cast.format = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7859 *format,
7860 )?));
7861 }
7862 if let Some(default) = cast.default.take() {
7863 cast.default =
7864 Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*default)?));
7865 }
7866 Ok(Expression::TryCast(cast))
7867 }
7868 Expression::SafeCast(mut cast) => {
7869 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
7870 if let Some(format) = cast.format.take() {
7871 cast.format = Some(Box::new(Self::rewrite_tsql_boolean_nested_contexts(
7872 *format,
7873 )?));
7874 }
7875 if let Some(default) = cast.default.take() {
7876 cast.default =
7877 Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*default)?));
7878 }
7879 Ok(Expression::SafeCast(cast))
7880 }
7881 Expression::Case(mut case) => {
7882 let is_simple_case = case.operand.is_some();
7883 if let Some(operand) = case.operand.take() {
7884 case.operand = Some(Self::rewrite_tsql_boolean_scalar_value(operand)?);
7885 }
7886 case.whens = case
7887 .whens
7888 .into_iter()
7889 .map(|(condition, result)| {
7890 let condition = if is_simple_case {
7891 Self::rewrite_tsql_boolean_scalar_value(condition)?
7892 } else {
7893 Self::rewrite_tsql_boolean_predicate_context(condition)?
7894 };
7895 Ok((condition, Self::rewrite_tsql_boolean_scalar_value(result)?))
7896 })
7897 .collect::<Result<Vec<_>>>()?;
7898 if let Some(else_) = case.else_.take() {
7899 case.else_ = Some(Self::rewrite_tsql_boolean_scalar_value(else_)?);
7900 }
7901 Ok(Expression::Case(case))
7902 }
7903 Expression::IfFunc(mut if_func) => {
7904 if_func.condition =
7905 Self::rewrite_tsql_boolean_predicate_context(if_func.condition)?;
7906 if_func.true_value = Self::rewrite_tsql_boolean_scalar_value(if_func.true_value)?;
7907 if let Some(false_value) = if_func.false_value.take() {
7908 if_func.false_value =
7909 Some(Self::rewrite_tsql_boolean_scalar_value(false_value)?);
7910 }
7911 Ok(Expression::IfFunc(if_func))
7912 }
7913 Expression::WindowFunction(mut window_function) => {
7914 window_function.this =
7915 Self::rewrite_tsql_boolean_nested_contexts(window_function.this)?;
7916 Self::rewrite_tsql_boolean_over_values(&mut window_function.over)?;
7917 if let Some(mut keep) = window_function.keep.take() {
7918 keep.order_by = Self::rewrite_tsql_boolean_ordered_values(keep.order_by)?;
7919 window_function.keep = Some(keep);
7920 }
7921 Ok(Expression::WindowFunction(window_function))
7922 }
7923 Expression::WithinGroup(mut within_group) => {
7924 within_group.this = Self::rewrite_tsql_boolean_nested_contexts(within_group.this)?;
7925 within_group.order_by =
7926 Self::rewrite_tsql_boolean_ordered_values(within_group.order_by)?;
7927 Ok(Expression::WithinGroup(within_group))
7928 }
7929 Expression::Subquery(mut subquery) => {
7930 subquery.this = Self::rewrite_boolean_values_for_tsql(subquery.this)?;
7931 Ok(Expression::Subquery(subquery))
7932 }
7933 Expression::Select(select) => Self::rewrite_boolean_values_in_tsql_select(select),
7934 other => Self::rewrite_tsql_boolean_nested_contexts(other),
7935 }
7936 }
7937
7938 fn rewrite_tsql_boolean_predicate_context(expr: Expression) -> Result<Expression> {
7939 let expr = Self::rewrite_tsql_boolean_nested_contexts(expr)?;
7940 Ok(crate::transforms::ensure_bool_condition(expr))
7941 }
7942
7943 fn rewrite_tsql_boolean_nested_contexts(expr: Expression) -> Result<Expression> {
7944 transform_recursive(expr, &|e| match e {
7945 Expression::Select(select) => Self::rewrite_boolean_values_in_tsql_select(select),
7946 Expression::Subquery(mut subquery) => {
7947 subquery.this = Self::rewrite_boolean_values_for_tsql(subquery.this)?;
7948 Ok(Expression::Subquery(subquery))
7949 }
7950 Expression::Union(_) | Expression::Intersect(_) | Expression::Except(_) => {
7951 Self::rewrite_boolean_values_for_tsql(e)
7952 }
7953 other => Self::rewrite_tsql_boolean_cast_operand(other),
7954 })
7955 }
7956
7957 fn rewrite_tsql_boolean_cast_operand(expr: Expression) -> Result<Expression> {
7958 macro_rules! rewrite_cast_operand {
7959 ($variant:ident, $cast:expr) => {{
7960 let mut cast = $cast;
7961 if Self::is_tsql_boolean_value_expression(&cast.this) {
7962 cast.this = Self::rewrite_tsql_boolean_scalar_value(cast.this)?;
7963 }
7964 Ok(Expression::$variant(cast))
7965 }};
7966 }
7967
7968 match expr {
7969 Expression::Cast(cast) => rewrite_cast_operand!(Cast, cast),
7970 Expression::TryCast(cast) => rewrite_cast_operand!(TryCast, cast),
7971 Expression::SafeCast(cast) => rewrite_cast_operand!(SafeCast, cast),
7972 other => Ok(other),
7973 }
7974 }
7975
7976 fn rewrite_tsql_boolean_ordered_values(
7977 ordered: Vec<crate::expressions::Ordered>,
7978 ) -> Result<Vec<crate::expressions::Ordered>> {
7979 ordered
7980 .into_iter()
7981 .map(|mut ordered| {
7982 ordered.this = Self::rewrite_tsql_boolean_scalar_value(ordered.this)?;
7983 if let Some(with_fill) = ordered.with_fill.take() {
7984 ordered.with_fill = Some(Box::new(
7985 Self::rewrite_tsql_boolean_with_fill_values(*with_fill)?,
7986 ));
7987 }
7988 Ok(ordered)
7989 })
7990 .collect()
7991 }
7992
7993 fn rewrite_tsql_boolean_with_fill_values(
7994 mut with_fill: crate::expressions::WithFill,
7995 ) -> Result<crate::expressions::WithFill> {
7996 if let Some(from) = with_fill.from_.take() {
7997 with_fill.from_ = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*from)?));
7998 }
7999 if let Some(to) = with_fill.to.take() {
8000 with_fill.to = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*to)?));
8001 }
8002 if let Some(step) = with_fill.step.take() {
8003 with_fill.step = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(*step)?));
8004 }
8005 if let Some(staleness) = with_fill.staleness.take() {
8006 with_fill.staleness = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(
8007 *staleness,
8008 )?));
8009 }
8010 if let Some(interpolate) = with_fill.interpolate.take() {
8011 with_fill.interpolate = Some(Box::new(Self::rewrite_tsql_boolean_scalar_value(
8012 *interpolate,
8013 )?));
8014 }
8015 Ok(with_fill)
8016 }
8017
8018 fn rewrite_tsql_boolean_over_values(over: &mut crate::expressions::Over) -> Result<()> {
8019 over.partition_by = std::mem::take(&mut over.partition_by)
8020 .into_iter()
8021 .map(Self::rewrite_tsql_boolean_scalar_value)
8022 .collect::<Result<Vec<_>>>()?;
8023 over.order_by =
8024 Self::rewrite_tsql_boolean_ordered_values(std::mem::take(&mut over.order_by))?;
8025 Ok(())
8026 }
8027
8028 fn is_tsql_boolean_value_expression(expr: &Expression) -> bool {
8029 match expr {
8030 Expression::Paren(paren) => Self::is_tsql_boolean_value_expression(&paren.this),
8031 Expression::Eq(_)
8032 | Expression::Neq(_)
8033 | Expression::Lt(_)
8034 | Expression::Lte(_)
8035 | Expression::Gt(_)
8036 | Expression::Gte(_)
8037 | Expression::Is(_)
8038 | Expression::IsNull(_)
8039 | Expression::IsTrue(_)
8040 | Expression::IsFalse(_)
8041 | Expression::Like(_)
8042 | Expression::ILike(_)
8043 | Expression::StartsWith(_)
8044 | Expression::SimilarTo(_)
8045 | Expression::Glob(_)
8046 | Expression::RegexpLike(_)
8047 | Expression::In(_)
8048 | Expression::Between(_)
8049 | Expression::Exists(_)
8050 | Expression::And(_)
8051 | Expression::Or(_)
8052 | Expression::Not(_)
8053 | Expression::Any(_)
8054 | Expression::All(_)
8055 | Expression::NullSafeEq(_)
8056 | Expression::NullSafeNeq(_)
8057 | Expression::EqualNull(_) => true,
8058 _ => false,
8059 }
8060 }
8061
8062 fn tsql_boolean_expression_can_be_unknown(expr: &Expression) -> bool {
8063 match expr {
8064 Expression::Boolean(_)
8065 | Expression::IsNull(_)
8066 | Expression::IsTrue(_)
8067 | Expression::IsFalse(_)
8068 | Expression::Exists(_)
8069 | Expression::NullSafeEq(_)
8070 | Expression::NullSafeNeq(_)
8071 | Expression::EqualNull(_) => false,
8072 Expression::Paren(paren) => Self::tsql_boolean_expression_can_be_unknown(&paren.this),
8073 Expression::Not(op) => Self::tsql_boolean_expression_can_be_unknown(&op.this),
8074 Expression::And(op) | Expression::Or(op) => {
8075 Self::tsql_boolean_expression_can_be_unknown(&op.left)
8076 || Self::tsql_boolean_expression_can_be_unknown(&op.right)
8077 }
8078 _ => true,
8079 }
8080 }
8081
8082 fn tsql_boolean_value_case(predicate: Expression, can_be_unknown: bool) -> Expression {
8083 let case = if can_be_unknown {
8084 Self::three_valued_boolean_case(predicate, Expression::number(1), Expression::number(0))
8085 } else {
8086 Expression::Case(Box::new(crate::expressions::Case {
8087 operand: None,
8088 whens: vec![(predicate, Expression::number(1))],
8089 else_: Some(Expression::number(0)),
8090 comments: Vec::new(),
8091 inferred_type: None,
8092 }))
8093 };
8094
8095 Expression::Cast(Box::new(Cast {
8096 this: case,
8097 to: DataType::Boolean,
8098 trailing_comments: Vec::new(),
8099 double_colon_syntax: false,
8100 format: None,
8101 default: None,
8102 inferred_type: None,
8103 }))
8104 }
8105
8106 fn three_valued_boolean_case(
8107 predicate: Expression,
8108 true_value: Expression,
8109 false_value: Expression,
8110 ) -> Expression {
8111 let false_operand = if matches!(predicate, Expression::And(_) | Expression::Or(_)) {
8112 Expression::Paren(Box::new(crate::expressions::Paren {
8113 this: predicate.clone(),
8114 trailing_comments: Vec::new(),
8115 }))
8116 } else {
8117 predicate.clone()
8118 };
8119 let false_predicate = Expression::Not(Box::new(crate::expressions::UnaryOp {
8120 this: false_operand,
8121 inferred_type: None,
8122 }));
8123
8124 Expression::Case(Box::new(crate::expressions::Case {
8125 operand: None,
8126 whens: vec![(predicate, true_value), (false_predicate, false_value)],
8127 else_: Some(Expression::null()),
8128 comments: Vec::new(),
8129 inferred_type: None,
8130 }))
8131 }
8132
8133 fn rewrite_aggregate_filters_for_tsql(expr: Expression) -> Result<Expression> {
8134 transform_recursive(expr, &|e| Self::rewrite_aggregate_filter_for_tsql(e))
8135 }
8136
8137 fn rewrite_aggregate_filter_for_tsql(expr: Expression) -> Result<Expression> {
8138 macro_rules! rewrite_agg_filter {
8139 ($variant:ident, $agg:expr) => {{
8140 let mut agg = $agg;
8141 if let Some(filter) = agg.filter.take() {
8142 let this = std::mem::replace(&mut agg.this, Expression::null());
8143 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8144 }
8145 Ok(Expression::$variant(agg))
8146 }};
8147 }
8148
8149 match expr {
8150 Expression::Filter(filter) => {
8151 let condition = match *filter.expression {
8152 Expression::Where(where_) => where_.this,
8153 other => other,
8154 };
8155 Ok(Self::push_filter_into_tsql_aggregate(
8156 *filter.this,
8157 condition,
8158 ))
8159 }
8160 Expression::AggregateFunction(mut agg) => {
8161 if let Some(filter) = agg.filter.take() {
8162 Self::rewrite_generic_aggregate_filter_for_tsql(&mut agg, filter);
8163 }
8164 Ok(Expression::AggregateFunction(agg))
8165 }
8166 Expression::Count(mut count) => {
8167 if let Some(filter) = count.filter.take() {
8168 let value = if count.star {
8169 Expression::number(1)
8170 } else {
8171 count.this.take().unwrap_or_else(|| Expression::number(1))
8172 };
8173 count.star = false;
8174 count.this = Some(Self::conditional_aggregate_value_for_tsql(filter, value));
8175 }
8176 Ok(Expression::Count(count))
8177 }
8178 Expression::Sum(agg) => rewrite_agg_filter!(Sum, agg),
8179 Expression::Avg(agg) => rewrite_agg_filter!(Avg, agg),
8180 Expression::Min(agg) => rewrite_agg_filter!(Min, agg),
8181 Expression::Max(agg) => rewrite_agg_filter!(Max, agg),
8182 Expression::ArrayAgg(agg) => rewrite_agg_filter!(ArrayAgg, agg),
8183 Expression::CountIf(agg) => Ok(Expression::CountIf(agg)),
8184 Expression::Stddev(agg) => rewrite_agg_filter!(Stddev, agg),
8185 Expression::StddevPop(agg) => rewrite_agg_filter!(StddevPop, agg),
8186 Expression::StddevSamp(agg) => rewrite_agg_filter!(StddevSamp, agg),
8187 Expression::Variance(agg) => rewrite_agg_filter!(Variance, agg),
8188 Expression::VarPop(agg) => rewrite_agg_filter!(VarPop, agg),
8189 Expression::VarSamp(agg) => rewrite_agg_filter!(VarSamp, agg),
8190 Expression::Median(agg) => rewrite_agg_filter!(Median, agg),
8191 Expression::Mode(agg) => rewrite_agg_filter!(Mode, agg),
8192 Expression::First(agg) => rewrite_agg_filter!(First, agg),
8193 Expression::Last(agg) => rewrite_agg_filter!(Last, agg),
8194 Expression::AnyValue(agg) => rewrite_agg_filter!(AnyValue, agg),
8195 Expression::ApproxDistinct(agg) => rewrite_agg_filter!(ApproxDistinct, agg),
8196 Expression::ApproxCountDistinct(agg) => {
8197 rewrite_agg_filter!(ApproxCountDistinct, agg)
8198 }
8199 Expression::LogicalAnd(agg) => rewrite_agg_filter!(LogicalAnd, agg),
8200 Expression::LogicalOr(agg) => rewrite_agg_filter!(LogicalOr, agg),
8201 Expression::Skewness(agg) => rewrite_agg_filter!(Skewness, agg),
8202 Expression::ArrayConcatAgg(agg) => rewrite_agg_filter!(ArrayConcatAgg, agg),
8203 Expression::ArrayUniqueAgg(agg) => rewrite_agg_filter!(ArrayUniqueAgg, agg),
8204 Expression::BoolXorAgg(agg) => rewrite_agg_filter!(BoolXorAgg, agg),
8205 Expression::BitwiseAndAgg(agg) => rewrite_agg_filter!(BitwiseAndAgg, agg),
8206 Expression::BitwiseOrAgg(agg) => rewrite_agg_filter!(BitwiseOrAgg, agg),
8207 Expression::BitwiseXorAgg(agg) => rewrite_agg_filter!(BitwiseXorAgg, agg),
8208 Expression::StringAgg(mut agg) => {
8209 if let Some(filter) = agg.filter.take() {
8210 let this = std::mem::replace(&mut agg.this, Expression::null());
8211 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8212 }
8213 Ok(Expression::StringAgg(agg))
8214 }
8215 Expression::GroupConcat(mut agg) => {
8216 if let Some(filter) = agg.filter.take() {
8217 let this = std::mem::replace(&mut agg.this, Expression::null());
8218 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8219 }
8220 Ok(Expression::GroupConcat(agg))
8221 }
8222 Expression::ListAgg(mut agg) => {
8223 if let Some(filter) = agg.filter.take() {
8224 let this = std::mem::replace(&mut agg.this, Expression::null());
8225 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8226 }
8227 Ok(Expression::ListAgg(agg))
8228 }
8229 Expression::WithinGroup(mut within_group) => {
8230 within_group.this = Self::rewrite_aggregate_filters_for_tsql(within_group.this)?;
8231 Ok(Expression::WithinGroup(within_group))
8232 }
8233 other => Ok(other),
8234 }
8235 }
8236
8237 fn push_filter_into_tsql_aggregate(expr: Expression, filter: Expression) -> Expression {
8238 macro_rules! push_agg_filter {
8239 ($variant:ident, $agg:expr) => {{
8240 let mut agg = $agg;
8241 let this = std::mem::replace(&mut agg.this, Expression::null());
8242 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8243 agg.filter = None;
8244 Expression::$variant(agg)
8245 }};
8246 }
8247
8248 match expr {
8249 Expression::AggregateFunction(mut agg) => {
8250 Self::rewrite_generic_aggregate_filter_for_tsql(&mut agg, filter);
8251 Expression::AggregateFunction(agg)
8252 }
8253 Expression::Count(mut count) => {
8254 let value = if count.star {
8255 Expression::number(1)
8256 } else {
8257 count.this.take().unwrap_or_else(|| Expression::number(1))
8258 };
8259 count.star = false;
8260 count.filter = None;
8261 count.this = Some(Self::conditional_aggregate_value_for_tsql(filter, value));
8262 Expression::Count(count)
8263 }
8264 Expression::Sum(agg) => push_agg_filter!(Sum, agg),
8265 Expression::Avg(agg) => push_agg_filter!(Avg, agg),
8266 Expression::Min(agg) => push_agg_filter!(Min, agg),
8267 Expression::Max(agg) => push_agg_filter!(Max, agg),
8268 Expression::ArrayAgg(agg) => push_agg_filter!(ArrayAgg, agg),
8269 Expression::CountIf(mut agg) => {
8270 agg.filter = Some(filter);
8271 Expression::CountIf(agg)
8272 }
8273 Expression::Stddev(agg) => push_agg_filter!(Stddev, agg),
8274 Expression::StddevPop(agg) => push_agg_filter!(StddevPop, agg),
8275 Expression::StddevSamp(agg) => push_agg_filter!(StddevSamp, agg),
8276 Expression::Variance(agg) => push_agg_filter!(Variance, agg),
8277 Expression::VarPop(agg) => push_agg_filter!(VarPop, agg),
8278 Expression::VarSamp(agg) => push_agg_filter!(VarSamp, agg),
8279 Expression::Median(agg) => push_agg_filter!(Median, agg),
8280 Expression::Mode(agg) => push_agg_filter!(Mode, agg),
8281 Expression::First(agg) => push_agg_filter!(First, agg),
8282 Expression::Last(agg) => push_agg_filter!(Last, agg),
8283 Expression::AnyValue(agg) => push_agg_filter!(AnyValue, agg),
8284 Expression::ApproxDistinct(agg) => push_agg_filter!(ApproxDistinct, agg),
8285 Expression::ApproxCountDistinct(agg) => {
8286 push_agg_filter!(ApproxCountDistinct, agg)
8287 }
8288 Expression::LogicalAnd(agg) => push_agg_filter!(LogicalAnd, agg),
8289 Expression::LogicalOr(agg) => push_agg_filter!(LogicalOr, agg),
8290 Expression::Skewness(agg) => push_agg_filter!(Skewness, agg),
8291 Expression::ArrayConcatAgg(agg) => push_agg_filter!(ArrayConcatAgg, agg),
8292 Expression::ArrayUniqueAgg(agg) => push_agg_filter!(ArrayUniqueAgg, agg),
8293 Expression::BoolXorAgg(agg) => push_agg_filter!(BoolXorAgg, agg),
8294 Expression::BitwiseAndAgg(agg) => push_agg_filter!(BitwiseAndAgg, agg),
8295 Expression::BitwiseOrAgg(agg) => push_agg_filter!(BitwiseOrAgg, agg),
8296 Expression::BitwiseXorAgg(agg) => push_agg_filter!(BitwiseXorAgg, agg),
8297 Expression::StringAgg(mut agg) => {
8298 let this = std::mem::replace(&mut agg.this, Expression::null());
8299 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8300 agg.filter = None;
8301 Expression::StringAgg(agg)
8302 }
8303 Expression::GroupConcat(mut agg) => {
8304 let this = std::mem::replace(&mut agg.this, Expression::null());
8305 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8306 agg.filter = None;
8307 Expression::GroupConcat(agg)
8308 }
8309 Expression::ListAgg(mut agg) => {
8310 let this = std::mem::replace(&mut agg.this, Expression::null());
8311 agg.this = Self::conditional_aggregate_value_for_tsql(filter, this);
8312 agg.filter = None;
8313 Expression::ListAgg(agg)
8314 }
8315 Expression::WithinGroup(mut within_group) => {
8316 within_group.this =
8317 Self::push_filter_into_tsql_aggregate(within_group.this, filter);
8318 Expression::WithinGroup(within_group)
8319 }
8320 other => Expression::Filter(Box::new(crate::expressions::Filter {
8321 this: Box::new(other),
8322 expression: Box::new(filter),
8323 })),
8324 }
8325 }
8326
8327 fn rewrite_generic_aggregate_filter_for_tsql(
8328 agg: &mut crate::expressions::AggregateFunction,
8329 filter: Expression,
8330 ) {
8331 let is_count =
8332 agg.name.eq_ignore_ascii_case("COUNT") || agg.name.eq_ignore_ascii_case("COUNT_BIG");
8333 let is_count_star = is_count
8334 && (agg.args.is_empty()
8335 || (agg.args.len() == 1 && matches!(agg.args[0], Expression::Star(_))));
8336
8337 if is_count_star {
8338 agg.args = vec![Self::conditional_aggregate_value_for_tsql(
8339 filter,
8340 Expression::number(1),
8341 )];
8342 } else if !agg.args.is_empty() {
8343 agg.args = agg
8344 .args
8345 .drain(..)
8346 .map(|arg| Self::conditional_aggregate_value_for_tsql(filter.clone(), arg))
8347 .collect();
8348 } else {
8349 agg.filter = Some(filter);
8350 }
8351 }
8352
8353 fn conditional_aggregate_value_for_tsql(filter: Expression, value: Expression) -> Expression {
8354 let filter = crate::transforms::ensure_bool_condition(filter);
8355 Expression::Case(Box::new(crate::expressions::Case {
8356 operand: None,
8357 whens: vec![(filter, value)],
8358 else_: None,
8359 comments: Vec::new(),
8360 inferred_type: None,
8361 }))
8362 }
8363
8364 fn reject_pgvector_distance_operators_for_sqlite(&self, sql: &str) -> Result<()> {
8365 let tokens = self.tokenize(sql)?;
8366 for (i, token) in tokens.iter().enumerate() {
8367 if token.token_type == TokenType::NullsafeEq {
8368 return Err(crate::error::Error::unsupported(
8369 "PostgreSQL pgvector cosine distance operator <=>",
8370 "SQLite",
8371 ));
8372 }
8373 if token.token_type == TokenType::Lt
8374 && tokens
8375 .get(i + 1)
8376 .is_some_and(|token| token.token_type == TokenType::Tilde)
8377 && tokens
8378 .get(i + 2)
8379 .is_some_and(|token| token.token_type == TokenType::Gt)
8380 {
8381 return Err(crate::error::Error::unsupported(
8382 "PostgreSQL pgvector Hamming distance operator <~>",
8383 "SQLite",
8384 ));
8385 }
8386 }
8387 Ok(())
8388 }
8389
8390 fn normalize_sqlite_double_quoted_defaults(expr: Expression) -> Result<Expression> {
8391 fn normalize_default_expr(expr: Expression) -> Result<Expression> {
8392 transform_recursive(expr, &|e| match e {
8393 Expression::Column(col)
8394 if col.table.is_none() && col.name.quoted && !col.join_mark =>
8395 {
8396 Ok(Expression::Literal(Box::new(Literal::String(
8397 col.name.name,
8398 ))))
8399 }
8400 Expression::Identifier(id) if id.quoted => {
8401 Ok(Expression::Literal(Box::new(Literal::String(id.name))))
8402 }
8403 _ => Ok(e),
8404 })
8405 }
8406
8407 fn normalize_column_default(col: &mut crate::expressions::ColumnDef) -> Result<()> {
8408 if let Some(default) = col.default.take() {
8409 col.default = Some(normalize_default_expr(default)?);
8410 }
8411
8412 for constraint in &mut col.constraints {
8413 if let ColumnConstraint::Default(default) = constraint {
8414 *default = normalize_default_expr(default.clone())?;
8415 }
8416 }
8417
8418 Ok(())
8419 }
8420
8421 transform_recursive(expr, &|e| match e {
8422 Expression::CreateTable(mut ct) => {
8423 for column in &mut ct.columns {
8424 normalize_column_default(column)?;
8425 }
8426 Ok(Expression::CreateTable(ct))
8427 }
8428 Expression::ColumnDef(mut col) => {
8429 normalize_column_default(&mut col)?;
8430 Ok(Expression::ColumnDef(col))
8431 }
8432 _ => Ok(e),
8433 })
8434 }
8435
8436 fn normalize_postgres_to_sqlite_types(expr: Expression) -> Result<Expression> {
8437 fn sqlite_type(dt: crate::expressions::DataType) -> crate::expressions::DataType {
8438 use crate::expressions::DataType;
8439
8440 match dt {
8441 DataType::Bit { .. } => DataType::Int {
8442 length: None,
8443 integer_spelling: true,
8444 },
8445 DataType::TextWithLength { .. } => DataType::Text,
8446 DataType::VarChar { .. } => DataType::Text,
8447 DataType::Char { .. } => DataType::Text,
8448 DataType::Timestamp { timezone: true, .. } => DataType::Text,
8449 DataType::Custom { name } => {
8450 let base = name
8451 .split_once('(')
8452 .map_or(name.as_str(), |(base, _)| base)
8453 .trim();
8454 if base.eq_ignore_ascii_case("TSVECTOR")
8455 || base.eq_ignore_ascii_case("TIMESTAMPTZ")
8456 || base.eq_ignore_ascii_case("TIMESTAMP WITH TIME ZONE")
8457 || base.eq_ignore_ascii_case("NVARCHAR")
8458 || base.eq_ignore_ascii_case("NCHAR")
8459 {
8460 DataType::Text
8461 } else {
8462 DataType::Custom { name }
8463 }
8464 }
8465 _ => dt,
8466 }
8467 }
8468
8469 transform_recursive(expr, &|e| match e {
8470 Expression::DataType(dt) => Ok(Expression::DataType(sqlite_type(dt))),
8471 Expression::CreateTable(mut ct) => {
8472 for column in &mut ct.columns {
8473 column.data_type = sqlite_type(column.data_type.clone());
8474 }
8475 Ok(Expression::CreateTable(ct))
8476 }
8477 _ => Ok(e),
8478 })
8479 }
8480
8481 fn normalize_postgres_to_fabric_types(expr: Expression) -> Result<Expression> {
8482 fn fabric_type(dt: crate::expressions::DataType) -> crate::expressions::DataType {
8483 use crate::expressions::DataType;
8484
8485 match dt {
8486 DataType::Decimal {
8487 precision: None,
8488 scale: None,
8489 } => DataType::Decimal {
8490 precision: Some(38),
8491 scale: Some(10),
8492 },
8493 DataType::Json | DataType::JsonB => DataType::Custom {
8494 name: "VARCHAR(MAX)".to_string(),
8495 },
8496 _ => dt,
8497 }
8498 }
8499
8500 transform_recursive(expr, &|e| match e {
8501 Expression::DataType(dt) => Ok(Expression::DataType(fabric_type(dt))),
8502 Expression::CreateTable(mut ct) => {
8503 for column in &mut ct.columns {
8504 column.data_type = fabric_type(column.data_type.clone());
8505 }
8506 Ok(Expression::CreateTable(ct))
8507 }
8508 Expression::ColumnDef(mut col) => {
8509 col.data_type = fabric_type(col.data_type);
8510 Ok(Expression::ColumnDef(col))
8511 }
8512 _ => Ok(e),
8513 })
8514 }
8515
8516 fn seq_rownum_to_range(expr: Expression) -> Result<Expression> {
8520 if let Expression::Select(mut select) = expr {
8521 let has_range_from = if let Some(ref from) = select.from {
8523 from.expressions.iter().any(|e| {
8524 match e {
8526 Expression::Function(f) => f.name.eq_ignore_ascii_case("RANGE"),
8527 Expression::Alias(a) => {
8528 matches!(&a.this, Expression::Function(f) if f.name.eq_ignore_ascii_case("RANGE"))
8529 }
8530 _ => false,
8531 }
8532 })
8533 } else {
8534 false
8535 };
8536
8537 if has_range_from {
8538 select.expressions = select
8540 .expressions
8541 .into_iter()
8542 .map(|e| Self::replace_rownum_with_range(e))
8543 .collect();
8544 }
8545
8546 Ok(Expression::Select(select))
8547 } else {
8548 Ok(expr)
8549 }
8550 }
8551
8552 fn replace_rownum_with_range(expr: Expression) -> Expression {
8554 match expr {
8555 Expression::Mod(op) => {
8557 let new_left = Self::try_replace_rownum_paren(&op.left);
8558 Expression::Mod(Box::new(crate::expressions::BinaryOp {
8559 left: new_left,
8560 right: op.right,
8561 left_comments: op.left_comments,
8562 operator_comments: op.operator_comments,
8563 trailing_comments: op.trailing_comments,
8564 inferred_type: op.inferred_type,
8565 }))
8566 }
8567 Expression::Paren(p) => {
8569 let inner = Self::replace_rownum_with_range(p.this);
8570 Expression::Paren(Box::new(crate::expressions::Paren {
8571 this: inner,
8572 trailing_comments: p.trailing_comments,
8573 }))
8574 }
8575 Expression::Case(mut c) => {
8576 c.whens = c
8578 .whens
8579 .into_iter()
8580 .map(|(cond, then)| {
8581 (
8582 Self::replace_rownum_with_range(cond),
8583 Self::replace_rownum_with_range(then),
8584 )
8585 })
8586 .collect();
8587 if let Some(else_) = c.else_ {
8588 c.else_ = Some(Self::replace_rownum_with_range(else_));
8589 }
8590 Expression::Case(c)
8591 }
8592 Expression::Gte(op) => Expression::Gte(Box::new(crate::expressions::BinaryOp {
8593 left: Self::replace_rownum_with_range(op.left),
8594 right: op.right,
8595 left_comments: op.left_comments,
8596 operator_comments: op.operator_comments,
8597 trailing_comments: op.trailing_comments,
8598 inferred_type: op.inferred_type,
8599 })),
8600 Expression::Sub(op) => Expression::Sub(Box::new(crate::expressions::BinaryOp {
8601 left: Self::replace_rownum_with_range(op.left),
8602 right: op.right,
8603 left_comments: op.left_comments,
8604 operator_comments: op.operator_comments,
8605 trailing_comments: op.trailing_comments,
8606 inferred_type: op.inferred_type,
8607 })),
8608 Expression::Alias(mut a) => {
8609 a.this = Self::replace_rownum_with_range(a.this);
8610 Expression::Alias(a)
8611 }
8612 other => other,
8613 }
8614 }
8615
8616 fn try_replace_rownum_paren(expr: &Expression) -> Expression {
8618 if let Expression::Paren(ref p) = expr {
8619 if let Expression::Sub(ref sub) = p.this {
8620 if let Expression::WindowFunction(ref wf) = sub.left {
8621 if let Expression::Function(ref f) = wf.this {
8622 if f.name.eq_ignore_ascii_case("ROW_NUMBER") {
8623 if let Expression::Literal(ref lit) = sub.right {
8624 if let crate::expressions::Literal::Number(ref n) = lit.as_ref() {
8625 if n == "1" {
8626 return Expression::column("range");
8627 }
8628 }
8629 }
8630 }
8631 }
8632 }
8633 }
8634 }
8635 expr.clone()
8636 }
8637
8638 fn transform_generate_date_array_snowflake(expr: Expression) -> Result<Expression> {
8645 use crate::expressions::*;
8646 transform_recursive(expr, &|e| {
8647 if let Expression::ArraySize(ref af) = e {
8649 if let Expression::Function(ref f) = af.this {
8650 if f.name.eq_ignore_ascii_case("GENERATE_DATE_ARRAY") && f.args.len() >= 2 {
8651 let result = Self::convert_array_size_gda_snowflake(f)?;
8652 return Ok(result);
8653 }
8654 }
8655 }
8656
8657 let Expression::Select(mut sel) = e else {
8658 return Ok(e);
8659 };
8660
8661 let mut gda_info: Option<(String, Expression, Expression, String)> = None; let mut gda_join_idx: Option<usize> = None;
8664
8665 for (idx, join) in sel.joins.iter().enumerate() {
8666 let (unnest_ref, alias_name) = match &join.this {
8670 Expression::Unnest(ref unnest) => {
8671 let alias = unnest.alias.as_ref().map(|id| id.name.clone());
8672 (Some(unnest.as_ref()), alias)
8673 }
8674 Expression::Alias(ref a) => {
8675 if let Expression::Unnest(ref unnest) = a.this {
8676 (Some(unnest.as_ref()), Some(a.alias.name.clone()))
8677 } else {
8678 (None, None)
8679 }
8680 }
8681 _ => (None, None),
8682 };
8683
8684 if let (Some(unnest), Some(alias)) = (unnest_ref, alias_name) {
8685 if let Expression::Function(ref f) = unnest.this {
8687 if f.name.eq_ignore_ascii_case("GENERATE_DATE_ARRAY") && f.args.len() >= 2 {
8688 let start_expr = f.args[0].clone();
8689 let end_expr = f.args[1].clone();
8690 let step = f.args.get(2).cloned();
8691
8692 let unit = if let Some(Expression::Interval(ref iv)) = step {
8694 if let Some(IntervalUnitSpec::Simple { ref unit, .. }) = iv.unit {
8695 Some(format!("{:?}", unit).to_ascii_uppercase())
8696 } else if let Some(ref this) = iv.this {
8697 if let Expression::Literal(lit) = this {
8699 if let Literal::String(ref s) = lit.as_ref() {
8700 let parts: Vec<&str> = s.split_whitespace().collect();
8701 if parts.len() == 2 {
8702 Some(parts[1].to_ascii_uppercase())
8703 } else if parts.len() == 1 {
8704 let upper = parts[0].to_ascii_uppercase();
8706 if matches!(
8707 upper.as_str(),
8708 "YEAR"
8709 | "QUARTER"
8710 | "MONTH"
8711 | "WEEK"
8712 | "DAY"
8713 | "HOUR"
8714 | "MINUTE"
8715 | "SECOND"
8716 ) {
8717 Some(upper)
8718 } else {
8719 None
8720 }
8721 } else {
8722 None
8723 }
8724 } else {
8725 None
8726 }
8727 } else {
8728 None
8729 }
8730 } else {
8731 None
8732 }
8733 } else {
8734 None
8735 };
8736
8737 if let Some(unit_str) = unit {
8738 gda_info = Some((alias, start_expr, end_expr, unit_str));
8739 gda_join_idx = Some(idx);
8740 }
8741 }
8742 }
8743 }
8744 if gda_info.is_some() {
8745 break;
8746 }
8747 }
8748
8749 let Some((alias_name, start_expr, end_expr, unit_str)) = gda_info else {
8750 let result = Self::try_transform_from_gda_snowflake(sel);
8753 return result;
8754 };
8755 let join_idx = gda_join_idx.unwrap();
8756
8757 let datediff = Expression::Function(Box::new(Function::new(
8761 "DATEDIFF".to_string(),
8762 vec![
8763 Expression::boxed_column(Column {
8764 name: Identifier::new(&unit_str),
8765 table: None,
8766 join_mark: false,
8767 trailing_comments: vec![],
8768 span: None,
8769 inferred_type: None,
8770 }),
8771 start_expr.clone(),
8772 end_expr.clone(),
8773 ],
8774 )));
8775 let datediff_plus_one = Expression::Add(Box::new(BinaryOp {
8776 left: datediff,
8777 right: Expression::Literal(Box::new(Literal::Number("1".to_string()))),
8778 left_comments: vec![],
8779 operator_comments: vec![],
8780 trailing_comments: vec![],
8781 inferred_type: None,
8782 }));
8783
8784 let array_gen_range = Expression::Function(Box::new(Function::new(
8785 "ARRAY_GENERATE_RANGE".to_string(),
8786 vec![
8787 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
8788 datediff_plus_one,
8789 ],
8790 )));
8791
8792 let flatten_input = Expression::NamedArgument(Box::new(NamedArgument {
8794 name: Identifier::new("INPUT"),
8795 value: array_gen_range,
8796 separator: crate::expressions::NamedArgSeparator::DArrow,
8797 }));
8798 let flatten = Expression::Function(Box::new(Function::new(
8799 "FLATTEN".to_string(),
8800 vec![flatten_input],
8801 )));
8802
8803 let alias_table = Alias {
8805 this: flatten,
8806 alias: Identifier::new("_t0"),
8807 column_aliases: vec![
8808 Identifier::new("seq"),
8809 Identifier::new("key"),
8810 Identifier::new("path"),
8811 Identifier::new("index"),
8812 Identifier::new(&alias_name),
8813 Identifier::new("this"),
8814 ],
8815 alias_explicit_as: false,
8816 alias_keyword: None,
8817 pre_alias_comments: vec![],
8818 trailing_comments: vec![],
8819 inferred_type: None,
8820 };
8821 let lateral_expr = Expression::Lateral(Box::new(Lateral {
8822 this: Box::new(Expression::Alias(Box::new(alias_table))),
8823 view: None,
8824 outer: None,
8825 alias: None,
8826 alias_quoted: false,
8827 cross_apply: None,
8828 ordinality: None,
8829 column_aliases: vec![],
8830 }));
8831
8832 sel.joins.remove(join_idx);
8834 if let Some(ref mut from) = sel.from {
8835 from.expressions.push(lateral_expr);
8836 }
8837
8838 let dateadd_expr = Expression::Function(Box::new(Function::new(
8840 "DATEADD".to_string(),
8841 vec![
8842 Expression::boxed_column(Column {
8843 name: Identifier::new(&unit_str),
8844 table: None,
8845 join_mark: false,
8846 trailing_comments: vec![],
8847 span: None,
8848 inferred_type: None,
8849 }),
8850 Expression::Cast(Box::new(Cast {
8851 this: Expression::boxed_column(Column {
8852 name: Identifier::new(&alias_name),
8853 table: None,
8854 join_mark: false,
8855 trailing_comments: vec![],
8856 span: None,
8857 inferred_type: None,
8858 }),
8859 to: DataType::Int {
8860 length: None,
8861 integer_spelling: false,
8862 },
8863 trailing_comments: vec![],
8864 double_colon_syntax: false,
8865 format: None,
8866 default: None,
8867 inferred_type: None,
8868 })),
8869 Expression::Cast(Box::new(Cast {
8870 this: start_expr.clone(),
8871 to: DataType::Date,
8872 trailing_comments: vec![],
8873 double_colon_syntax: false,
8874 format: None,
8875 default: None,
8876 inferred_type: None,
8877 })),
8878 ],
8879 )));
8880
8881 let new_exprs: Vec<Expression> = sel
8883 .expressions
8884 .iter()
8885 .map(|expr| Self::replace_column_ref_with_dateadd(expr, &alias_name, &dateadd_expr))
8886 .collect();
8887 sel.expressions = new_exprs;
8888
8889 Ok(Expression::Select(sel))
8890 })
8891 }
8892
8893 fn replace_column_ref_with_dateadd(
8895 expr: &Expression,
8896 alias_name: &str,
8897 dateadd: &Expression,
8898 ) -> Expression {
8899 use crate::expressions::*;
8900 match expr {
8901 Expression::Column(c) if c.name.name == alias_name && c.table.is_none() => {
8902 Expression::Alias(Box::new(Alias {
8904 this: dateadd.clone(),
8905 alias: Identifier::new(alias_name),
8906 column_aliases: vec![],
8907 alias_explicit_as: false,
8908 alias_keyword: None,
8909 pre_alias_comments: vec![],
8910 trailing_comments: vec![],
8911 inferred_type: None,
8912 }))
8913 }
8914 Expression::Alias(a) => {
8915 let new_this = Self::replace_column_ref_inner(&a.this, alias_name, dateadd);
8917 Expression::Alias(Box::new(Alias {
8918 this: new_this,
8919 alias: a.alias.clone(),
8920 column_aliases: a.column_aliases.clone(),
8921 alias_explicit_as: false,
8922 alias_keyword: None,
8923 pre_alias_comments: a.pre_alias_comments.clone(),
8924 trailing_comments: a.trailing_comments.clone(),
8925 inferred_type: None,
8926 }))
8927 }
8928 _ => expr.clone(),
8929 }
8930 }
8931
8932 fn replace_column_ref_inner(
8934 expr: &Expression,
8935 alias_name: &str,
8936 dateadd: &Expression,
8937 ) -> Expression {
8938 use crate::expressions::*;
8939 match expr {
8940 Expression::Column(c) if c.name.name == alias_name && c.table.is_none() => {
8941 dateadd.clone()
8942 }
8943 Expression::Add(op) => {
8944 let left = Self::replace_column_ref_inner(&op.left, alias_name, dateadd);
8945 let right = Self::replace_column_ref_inner(&op.right, alias_name, dateadd);
8946 Expression::Add(Box::new(BinaryOp {
8947 left,
8948 right,
8949 left_comments: op.left_comments.clone(),
8950 operator_comments: op.operator_comments.clone(),
8951 trailing_comments: op.trailing_comments.clone(),
8952 inferred_type: None,
8953 }))
8954 }
8955 Expression::Sub(op) => {
8956 let left = Self::replace_column_ref_inner(&op.left, alias_name, dateadd);
8957 let right = Self::replace_column_ref_inner(&op.right, alias_name, dateadd);
8958 Expression::Sub(Box::new(BinaryOp {
8959 left,
8960 right,
8961 left_comments: op.left_comments.clone(),
8962 operator_comments: op.operator_comments.clone(),
8963 trailing_comments: op.trailing_comments.clone(),
8964 inferred_type: None,
8965 }))
8966 }
8967 Expression::Mul(op) => {
8968 let left = Self::replace_column_ref_inner(&op.left, alias_name, dateadd);
8969 let right = Self::replace_column_ref_inner(&op.right, alias_name, dateadd);
8970 Expression::Mul(Box::new(BinaryOp {
8971 left,
8972 right,
8973 left_comments: op.left_comments.clone(),
8974 operator_comments: op.operator_comments.clone(),
8975 trailing_comments: op.trailing_comments.clone(),
8976 inferred_type: None,
8977 }))
8978 }
8979 _ => expr.clone(),
8980 }
8981 }
8982
8983 fn try_transform_from_gda_snowflake(
8986 mut sel: Box<crate::expressions::Select>,
8987 ) -> Result<Expression> {
8988 use crate::expressions::*;
8989
8990 let mut gda_info: Option<(
8992 usize,
8993 String,
8994 Expression,
8995 Expression,
8996 String,
8997 Option<(String, Vec<Identifier>)>,
8998 )> = None; if let Some(ref from) = sel.from {
9001 for (idx, table_expr) in from.expressions.iter().enumerate() {
9002 let (unnest_opt, outer_alias_info) = match table_expr {
9005 Expression::Unnest(ref unnest) => (Some(unnest.as_ref()), None),
9006 Expression::Alias(ref a) => {
9007 if let Expression::Unnest(ref unnest) = a.this {
9008 let alias_info = (a.alias.name.clone(), a.column_aliases.clone());
9009 (Some(unnest.as_ref()), Some(alias_info))
9010 } else {
9011 (None, None)
9012 }
9013 }
9014 _ => (None, None),
9015 };
9016
9017 if let Some(unnest) = unnest_opt {
9018 let func_opt = match &unnest.this {
9020 Expression::Function(ref f)
9021 if f.name.eq_ignore_ascii_case("GENERATE_DATE_ARRAY")
9022 && f.args.len() >= 2 =>
9023 {
9024 Some(f)
9025 }
9026 _ => None,
9028 };
9029
9030 if let Some(f) = func_opt {
9031 let start_expr = f.args[0].clone();
9032 let end_expr = f.args[1].clone();
9033 let step = f.args.get(2).cloned();
9034
9035 let unit = Self::extract_interval_unit_str(&step);
9037 let col_name = outer_alias_info
9038 .as_ref()
9039 .and_then(|(_, cols)| cols.first().map(|id| id.name.clone()))
9040 .unwrap_or_else(|| "value".to_string());
9041
9042 if let Some(unit_str) = unit {
9043 gda_info = Some((
9044 idx,
9045 col_name,
9046 start_expr,
9047 end_expr,
9048 unit_str,
9049 outer_alias_info,
9050 ));
9051 break;
9052 }
9053 }
9054 }
9055 }
9056 }
9057
9058 let Some((from_idx, col_name, start_expr, end_expr, unit_str, outer_alias_info)) = gda_info
9059 else {
9060 return Ok(Expression::Select(sel));
9061 };
9062
9063 let datediff = Expression::Function(Box::new(Function::new(
9069 "DATEDIFF".to_string(),
9070 vec![
9071 Expression::boxed_column(Column {
9072 name: Identifier::new(&unit_str),
9073 table: None,
9074 join_mark: false,
9075 trailing_comments: vec![],
9076 span: None,
9077 inferred_type: None,
9078 }),
9079 start_expr.clone(),
9080 end_expr.clone(),
9081 ],
9082 )));
9083 let datediff_plus_one = Expression::Add(Box::new(BinaryOp {
9085 left: datediff,
9086 right: Expression::Literal(Box::new(Literal::Number("1".to_string()))),
9087 left_comments: vec![],
9088 operator_comments: vec![],
9089 trailing_comments: vec![],
9090 inferred_type: None,
9091 }));
9092
9093 let array_gen_range = Expression::Function(Box::new(Function::new(
9094 "ARRAY_GENERATE_RANGE".to_string(),
9095 vec![
9096 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
9097 datediff_plus_one,
9098 ],
9099 )));
9100
9101 let flatten_input = Expression::NamedArgument(Box::new(NamedArgument {
9103 name: Identifier::new("INPUT"),
9104 value: array_gen_range,
9105 separator: crate::expressions::NamedArgSeparator::DArrow,
9106 }));
9107 let flatten = Expression::Function(Box::new(Function::new(
9108 "FLATTEN".to_string(),
9109 vec![flatten_input],
9110 )));
9111
9112 let table_alias_name = outer_alias_info
9114 .as_ref()
9115 .map(|(name, _)| name.clone())
9116 .unwrap_or_else(|| "_t0".to_string());
9117
9118 let table_func =
9120 Expression::Function(Box::new(Function::new("TABLE".to_string(), vec![flatten])));
9121 let flatten_aliased = Expression::Alias(Box::new(Alias {
9122 this: table_func,
9123 alias: Identifier::new(&table_alias_name),
9124 column_aliases: vec![
9125 Identifier::new("seq"),
9126 Identifier::new("key"),
9127 Identifier::new("path"),
9128 Identifier::new("index"),
9129 Identifier::new(&col_name),
9130 Identifier::new("this"),
9131 ],
9132 alias_explicit_as: false,
9133 alias_keyword: None,
9134 pre_alias_comments: vec![],
9135 trailing_comments: vec![],
9136 inferred_type: None,
9137 }));
9138
9139 let dateadd_expr = Expression::Function(Box::new(Function::new(
9141 "DATEADD".to_string(),
9142 vec![
9143 Expression::boxed_column(Column {
9144 name: Identifier::new(&unit_str),
9145 table: None,
9146 join_mark: false,
9147 trailing_comments: vec![],
9148 span: None,
9149 inferred_type: None,
9150 }),
9151 Expression::Cast(Box::new(Cast {
9152 this: Expression::boxed_column(Column {
9153 name: Identifier::new(&col_name),
9154 table: None,
9155 join_mark: false,
9156 trailing_comments: vec![],
9157 span: None,
9158 inferred_type: None,
9159 }),
9160 to: DataType::Int {
9161 length: None,
9162 integer_spelling: false,
9163 },
9164 trailing_comments: vec![],
9165 double_colon_syntax: false,
9166 format: None,
9167 default: None,
9168 inferred_type: None,
9169 })),
9170 start_expr.clone(),
9172 ],
9173 )));
9174 let dateadd_aliased = Expression::Alias(Box::new(Alias {
9175 this: dateadd_expr,
9176 alias: Identifier::new(&col_name),
9177 column_aliases: vec![],
9178 alias_explicit_as: false,
9179 alias_keyword: None,
9180 pre_alias_comments: vec![],
9181 trailing_comments: vec![],
9182 inferred_type: None,
9183 }));
9184
9185 let mut inner_select = Select::new();
9187 inner_select.expressions = vec![dateadd_aliased];
9188 inner_select.from = Some(From {
9189 expressions: vec![flatten_aliased],
9190 });
9191
9192 let inner_select_expr = Expression::Select(Box::new(inner_select));
9193 let subquery = Expression::Subquery(Box::new(Subquery {
9194 this: inner_select_expr,
9195 alias: None,
9196 column_aliases: vec![],
9197 alias_explicit_as: false,
9198 alias_keyword: None,
9199 order_by: None,
9200 limit: None,
9201 offset: None,
9202 distribute_by: None,
9203 sort_by: None,
9204 cluster_by: None,
9205 lateral: false,
9206 modifiers_inside: false,
9207 trailing_comments: vec![],
9208 inferred_type: None,
9209 }));
9210
9211 let replacement = if let Some((alias_name, col_aliases)) = outer_alias_info {
9213 Expression::Alias(Box::new(Alias {
9214 this: subquery,
9215 alias: Identifier::new(&alias_name),
9216 column_aliases: col_aliases,
9217 alias_explicit_as: false,
9218 alias_keyword: None,
9219 pre_alias_comments: vec![],
9220 trailing_comments: vec![],
9221 inferred_type: None,
9222 }))
9223 } else {
9224 subquery
9225 };
9226
9227 if let Some(ref mut from) = sel.from {
9229 from.expressions[from_idx] = replacement;
9230 }
9231
9232 Ok(Expression::Select(sel))
9233 }
9234
9235 fn convert_array_size_gda_snowflake(f: &crate::expressions::Function) -> Result<Expression> {
9239 use crate::expressions::*;
9240
9241 let start_expr = f.args[0].clone();
9242 let end_expr = f.args[1].clone();
9243 let step = f.args.get(2).cloned();
9244 let unit_str = Self::extract_interval_unit_str(&step).unwrap_or_else(|| "DAY".to_string());
9245 let col_name = "value";
9246
9247 let datediff = Expression::Function(Box::new(Function::new(
9249 "DATEDIFF".to_string(),
9250 vec![
9251 Expression::boxed_column(Column {
9252 name: Identifier::new(&unit_str),
9253 table: None,
9254 join_mark: false,
9255 trailing_comments: vec![],
9256 span: None,
9257 inferred_type: None,
9258 }),
9259 start_expr.clone(),
9260 end_expr.clone(),
9261 ],
9262 )));
9263 let datediff_plus_one = Expression::Add(Box::new(BinaryOp {
9265 left: datediff,
9266 right: Expression::Literal(Box::new(Literal::Number("1".to_string()))),
9267 left_comments: vec![],
9268 operator_comments: vec![],
9269 trailing_comments: vec![],
9270 inferred_type: None,
9271 }));
9272
9273 let array_gen_range = Expression::Function(Box::new(Function::new(
9274 "ARRAY_GENERATE_RANGE".to_string(),
9275 vec![
9276 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
9277 datediff_plus_one,
9278 ],
9279 )));
9280
9281 let flatten_input = Expression::NamedArgument(Box::new(NamedArgument {
9282 name: Identifier::new("INPUT"),
9283 value: array_gen_range,
9284 separator: crate::expressions::NamedArgSeparator::DArrow,
9285 }));
9286 let flatten = Expression::Function(Box::new(Function::new(
9287 "FLATTEN".to_string(),
9288 vec![flatten_input],
9289 )));
9290
9291 let table_func =
9292 Expression::Function(Box::new(Function::new("TABLE".to_string(), vec![flatten])));
9293 let flatten_aliased = Expression::Alias(Box::new(Alias {
9294 this: table_func,
9295 alias: Identifier::new("_t0"),
9296 column_aliases: vec![
9297 Identifier::new("seq"),
9298 Identifier::new("key"),
9299 Identifier::new("path"),
9300 Identifier::new("index"),
9301 Identifier::new(col_name),
9302 Identifier::new("this"),
9303 ],
9304 alias_explicit_as: false,
9305 alias_keyword: None,
9306 pre_alias_comments: vec![],
9307 trailing_comments: vec![],
9308 inferred_type: None,
9309 }));
9310
9311 let dateadd_expr = Expression::Function(Box::new(Function::new(
9312 "DATEADD".to_string(),
9313 vec![
9314 Expression::boxed_column(Column {
9315 name: Identifier::new(&unit_str),
9316 table: None,
9317 join_mark: false,
9318 trailing_comments: vec![],
9319 span: None,
9320 inferred_type: None,
9321 }),
9322 Expression::Cast(Box::new(Cast {
9323 this: Expression::boxed_column(Column {
9324 name: Identifier::new(col_name),
9325 table: None,
9326 join_mark: false,
9327 trailing_comments: vec![],
9328 span: None,
9329 inferred_type: None,
9330 }),
9331 to: DataType::Int {
9332 length: None,
9333 integer_spelling: false,
9334 },
9335 trailing_comments: vec![],
9336 double_colon_syntax: false,
9337 format: None,
9338 default: None,
9339 inferred_type: None,
9340 })),
9341 start_expr.clone(),
9342 ],
9343 )));
9344 let dateadd_aliased = Expression::Alias(Box::new(Alias {
9345 this: dateadd_expr,
9346 alias: Identifier::new(col_name),
9347 column_aliases: vec![],
9348 alias_explicit_as: false,
9349 alias_keyword: None,
9350 pre_alias_comments: vec![],
9351 trailing_comments: vec![],
9352 inferred_type: None,
9353 }));
9354
9355 let mut inner_select = Select::new();
9357 inner_select.expressions = vec![dateadd_aliased];
9358 inner_select.from = Some(From {
9359 expressions: vec![flatten_aliased],
9360 });
9361
9362 let inner_subquery = Expression::Subquery(Box::new(Subquery {
9364 this: Expression::Select(Box::new(inner_select)),
9365 alias: None,
9366 column_aliases: vec![],
9367 alias_explicit_as: false,
9368 alias_keyword: None,
9369 order_by: None,
9370 limit: None,
9371 offset: None,
9372 distribute_by: None,
9373 sort_by: None,
9374 cluster_by: None,
9375 lateral: false,
9376 modifiers_inside: false,
9377 trailing_comments: vec![],
9378 inferred_type: None,
9379 }));
9380
9381 let star = Expression::Star(Star {
9383 table: None,
9384 except: None,
9385 replace: None,
9386 rename: None,
9387 trailing_comments: vec![],
9388 span: None,
9389 });
9390 let array_agg = Expression::ArrayAgg(Box::new(AggFunc {
9391 this: star,
9392 distinct: false,
9393 filter: None,
9394 order_by: vec![],
9395 name: Some("ARRAY_AGG".to_string()),
9396 ignore_nulls: None,
9397 having_max: None,
9398 limit: None,
9399 inferred_type: None,
9400 }));
9401
9402 let mut outer_select = Select::new();
9403 outer_select.expressions = vec![array_agg];
9404 outer_select.from = Some(From {
9405 expressions: vec![inner_subquery],
9406 });
9407
9408 let outer_subquery = Expression::Subquery(Box::new(Subquery {
9410 this: Expression::Select(Box::new(outer_select)),
9411 alias: None,
9412 column_aliases: vec![],
9413 alias_explicit_as: false,
9414 alias_keyword: None,
9415 order_by: None,
9416 limit: None,
9417 offset: None,
9418 distribute_by: None,
9419 sort_by: None,
9420 cluster_by: None,
9421 lateral: false,
9422 modifiers_inside: false,
9423 trailing_comments: vec![],
9424 inferred_type: None,
9425 }));
9426
9427 Ok(Expression::ArraySize(Box::new(UnaryFunc::new(
9429 outer_subquery,
9430 ))))
9431 }
9432
9433 fn extract_interval_unit_str(step: &Option<Expression>) -> Option<String> {
9435 use crate::expressions::*;
9436 if let Some(Expression::Interval(ref iv)) = step {
9437 if let Some(IntervalUnitSpec::Simple { ref unit, .. }) = iv.unit {
9438 return Some(format!("{:?}", unit).to_ascii_uppercase());
9439 }
9440 if let Some(ref this) = iv.this {
9441 if let Expression::Literal(lit) = this {
9442 if let Literal::String(ref s) = lit.as_ref() {
9443 let parts: Vec<&str> = s.split_whitespace().collect();
9444 if parts.len() == 2 {
9445 return Some(parts[1].to_ascii_uppercase());
9446 } else if parts.len() == 1 {
9447 let upper = parts[0].to_ascii_uppercase();
9448 if matches!(
9449 upper.as_str(),
9450 "YEAR"
9451 | "QUARTER"
9452 | "MONTH"
9453 | "WEEK"
9454 | "DAY"
9455 | "HOUR"
9456 | "MINUTE"
9457 | "SECOND"
9458 ) {
9459 return Some(upper);
9460 }
9461 }
9462 }
9463 }
9464 }
9465 }
9466 if step.is_none() {
9468 return Some("DAY".to_string());
9469 }
9470 None
9471 }
9472
9473 fn normalize_snowflake_pretty(mut sql: String) -> String {
9474 if sql.contains("LATERAL IFF(_u.pos = _u_2.pos_2, _u_2.entity, NULL) AS datasource(SEQ, KEY, PATH, INDEX, VALUE, THIS)")
9475 && sql.contains("ARRAY_GENERATE_RANGE(0, (GREATEST(ARRAY_SIZE(INPUT => PARSE_JSON(flags))) - 1) + 1)")
9476 {
9477 sql = sql.replace(
9478 "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')",
9479 "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 )",
9480 );
9481
9482 sql = sql.replace(
9483 "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)",
9484 "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)",
9485 );
9486
9487 sql = sql.replace(
9488 "OR (_u.pos > (ARRAY_SIZE(INPUT => PARSE_JSON(flags)) - 1)\n AND _u_2.pos_2 = (ARRAY_SIZE(INPUT => PARSE_JSON(flags)) - 1))",
9489 "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 )",
9490 );
9491 }
9492
9493 sql
9494 }
9495
9496 #[cfg(feature = "transpile")]
9497 fn wrap_tsql_top_level_values(expr: Expression) -> Expression {
9498 match expr {
9499 Expression::Values(values) => Self::tsql_values_as_select(*values),
9500 Expression::Union(mut union) => {
9501 let left = std::mem::replace(&mut union.left, Expression::Null(Null));
9502 let right = std::mem::replace(&mut union.right, Expression::Null(Null));
9503 union.left = Self::wrap_tsql_values_set_operand(left);
9504 union.right = Self::wrap_tsql_values_set_operand(right);
9505 Expression::Union(union)
9506 }
9507 Expression::Intersect(mut intersect) => {
9508 let left = std::mem::replace(&mut intersect.left, Expression::Null(Null));
9509 let right = std::mem::replace(&mut intersect.right, Expression::Null(Null));
9510 intersect.left = Self::wrap_tsql_values_set_operand(left);
9511 intersect.right = Self::wrap_tsql_values_set_operand(right);
9512 Expression::Intersect(intersect)
9513 }
9514 Expression::Except(mut except) => {
9515 let left = std::mem::replace(&mut except.left, Expression::Null(Null));
9516 let right = std::mem::replace(&mut except.right, Expression::Null(Null));
9517 except.left = Self::wrap_tsql_values_set_operand(left);
9518 except.right = Self::wrap_tsql_values_set_operand(right);
9519 Expression::Except(except)
9520 }
9521 other => other,
9522 }
9523 }
9524
9525 #[cfg(feature = "transpile")]
9526 fn wrap_tsql_values_set_operand(expr: Expression) -> Expression {
9527 match expr {
9528 Expression::Values(values) => Self::tsql_values_as_select(*values),
9529 Expression::Select(mut select)
9530 if Self::is_parser_wrapped_values_set_operand(&select) =>
9531 {
9532 let mut from = select.from.take().expect("checked as present");
9533 let Expression::Values(values) = from
9534 .expressions
9535 .pop()
9536 .expect("checked as a single VALUES source")
9537 else {
9538 unreachable!("checked as a VALUES source");
9539 };
9540 Self::tsql_values_as_select(*values)
9541 }
9542 Expression::Annotated(mut annotated) => {
9543 annotated.this = Self::wrap_tsql_values_set_operand(annotated.this);
9544 Expression::Annotated(annotated)
9545 }
9546 Expression::Union(mut union) => {
9547 let left = std::mem::replace(&mut union.left, Expression::Null(Null));
9548 let right = std::mem::replace(&mut union.right, Expression::Null(Null));
9549 union.left = Self::wrap_tsql_values_set_operand(left);
9550 union.right = Self::wrap_tsql_values_set_operand(right);
9551 Expression::Union(union)
9552 }
9553 Expression::Intersect(mut intersect) => {
9554 let left = std::mem::replace(&mut intersect.left, Expression::Null(Null));
9555 let right = std::mem::replace(&mut intersect.right, Expression::Null(Null));
9556 intersect.left = Self::wrap_tsql_values_set_operand(left);
9557 intersect.right = Self::wrap_tsql_values_set_operand(right);
9558 Expression::Intersect(intersect)
9559 }
9560 Expression::Except(mut except) => {
9561 let left = std::mem::replace(&mut except.left, Expression::Null(Null));
9562 let right = std::mem::replace(&mut except.right, Expression::Null(Null));
9563 except.left = Self::wrap_tsql_values_set_operand(left);
9564 except.right = Self::wrap_tsql_values_set_operand(right);
9565 Expression::Except(except)
9566 }
9567 other => other,
9568 }
9569 }
9570
9571 #[cfg(feature = "transpile")]
9572 fn is_parser_wrapped_values_set_operand(select: &Select) -> bool {
9573 let Some(from) = &select.from else {
9574 return false;
9575 };
9576 let [Expression::Values(values)] = from.expressions.as_slice() else {
9577 return false;
9578 };
9579 if !values
9580 .alias
9581 .as_ref()
9582 .is_some_and(|alias| alias.name == "_values")
9583 {
9584 return false;
9585 }
9586
9587 let mut parser_wrapper = Select::new();
9588 parser_wrapper.expressions = vec![Expression::star()];
9589 parser_wrapper.from = Some(from.clone());
9590 select == &parser_wrapper
9591 }
9592
9593 #[cfg(feature = "transpile")]
9594 fn tsql_values_as_select(mut values: crate::expressions::Values) -> Expression {
9595 let column_aliases = if values.column_aliases.is_empty() {
9596 let column_count = values
9597 .expressions
9598 .first()
9599 .map(|row| row.expressions.len())
9600 .unwrap_or(0);
9601 (1..=column_count)
9602 .map(|index| Identifier::new(format!("column{index}")))
9603 .collect()
9604 } else {
9605 std::mem::take(&mut values.column_aliases)
9606 };
9607
9608 values.alias = None;
9609
9610 let values_subquery = Expression::Subquery(Box::new(crate::expressions::Subquery {
9611 this: Expression::Values(Box::new(values)),
9612 alias: Some(Identifier::new("_v")),
9613 column_aliases,
9614 alias_explicit_as: false,
9615 alias_keyword: None,
9616 order_by: None,
9617 limit: None,
9618 offset: None,
9619 distribute_by: None,
9620 sort_by: None,
9621 cluster_by: None,
9622 lateral: false,
9623 modifiers_inside: false,
9624 trailing_comments: Vec::new(),
9625 inferred_type: None,
9626 }));
9627
9628 let mut select = crate::expressions::Select::new();
9629 select.expressions = vec![Expression::star()];
9630 select.from = Some(From {
9631 expressions: vec![values_subquery],
9632 });
9633
9634 Expression::Select(Box::new(select))
9635 }
9636
9637 fn extract_interval_parts(
9638 interval_expr: &Expression,
9639 ) -> Option<(Expression, crate::expressions::IntervalUnit)> {
9640 use crate::expressions::{DataType, IntervalUnit, IntervalUnitSpec, Literal};
9641
9642 fn unit_from_str(unit: &str) -> Option<IntervalUnit> {
9643 match unit.trim().to_ascii_uppercase().as_str() {
9644 "YEAR" | "YEARS" | "Y" | "YR" | "YRS" | "YY" | "YYYY" => Some(IntervalUnit::Year),
9645 "QUARTER" | "QUARTERS" | "Q" | "QTR" | "QTRS" | "QQ" => Some(IntervalUnit::Quarter),
9646 "MONTH" | "MONTHS" | "MON" | "MONS" | "MM" => Some(IntervalUnit::Month),
9647 "WEEK" | "WEEKS" | "W" | "WK" | "WKS" | "WW" | "ISOWEEK" => {
9648 Some(IntervalUnit::Week)
9649 }
9650 "DAY" | "DAYS" | "D" | "DD" => Some(IntervalUnit::Day),
9651 "HOUR" | "HOURS" | "H" | "HH" | "HR" | "HRS" => Some(IntervalUnit::Hour),
9652 "MINUTE" | "MINUTES" | "MI" | "MIN" | "MINS" | "N" => Some(IntervalUnit::Minute),
9653 "SECOND" | "SECONDS" | "S" | "SEC" | "SECS" | "SS" => Some(IntervalUnit::Second),
9654 "MILLISECOND" | "MILLISECONDS" | "MS" | "MSEC" | "MSECS" | "MSECOND"
9655 | "MSECONDS" | "MILLISEC" | "MILLISECS" | "MILLISECON" => {
9656 Some(IntervalUnit::Millisecond)
9657 }
9658 "MICROSECOND" | "MICROSECONDS" | "US" | "USEC" | "USECS" | "USECOND"
9659 | "USECONDS" | "MICROSEC" | "MICROSECS" | "MCS" => Some(IntervalUnit::Microsecond),
9660 "NANOSECOND" | "NANOSECONDS" | "NS" | "NSEC" | "NSECS" | "NSECOND" | "NSECONDS"
9661 | "NANOSEC" | "NANOSECS" => Some(IntervalUnit::Nanosecond),
9662 _ => None,
9663 }
9664 }
9665
9666 fn parts_from_literal_string(s: &str) -> Option<(Expression, IntervalUnit)> {
9667 let mut parts = s.split_whitespace();
9668 let value = parts.next()?;
9669 let unit = unit_from_str(parts.next()?)?;
9670 Some((
9671 Expression::Literal(Box::new(Literal::String(value.to_string()))),
9672 unit,
9673 ))
9674 }
9675
9676 fn unit_from_spec(unit: &IntervalUnitSpec) -> Option<IntervalUnit> {
9677 match unit {
9678 IntervalUnitSpec::Simple { unit, .. } => Some(*unit),
9679 IntervalUnitSpec::Expr(expr) => match expr.as_ref() {
9680 Expression::Day(_) => Some(IntervalUnit::Day),
9681 Expression::Month(_) => Some(IntervalUnit::Month),
9682 Expression::Year(_) => Some(IntervalUnit::Year),
9683 Expression::Identifier(id) => unit_from_str(&id.name),
9684 Expression::Var(v) => unit_from_str(&v.this),
9685 Expression::Column(col) => unit_from_str(&col.name.name),
9686 _ => None,
9687 },
9688 _ => None,
9689 }
9690 }
9691
9692 match interval_expr {
9693 Expression::Interval(iv) => {
9694 let val = iv.this.clone().unwrap_or(Expression::number(0));
9695 if let Expression::Literal(lit) = &val {
9696 if let Literal::String(s) = lit.as_ref() {
9697 if let Some(parts) = parts_from_literal_string(s) {
9698 return Some(parts);
9699 }
9700 }
9701 }
9702 let unit = iv
9703 .unit
9704 .as_ref()
9705 .and_then(unit_from_spec)
9706 .unwrap_or(IntervalUnit::Day);
9707 Some((val, unit))
9708 }
9709 Expression::Cast(cast) if matches!(cast.to, DataType::Interval { .. }) => {
9710 if let Expression::Literal(lit) = &cast.this {
9711 if let Literal::String(s) = lit.as_ref() {
9712 if let Some(parts) = parts_from_literal_string(s) {
9713 return Some(parts);
9714 }
9715 }
9716 }
9717 let unit = match &cast.to {
9718 DataType::Interval {
9719 unit: Some(unit), ..
9720 } => unit_from_str(unit).unwrap_or(IntervalUnit::Day),
9721 _ => IntervalUnit::Day,
9722 };
9723 Some((cast.this.clone(), unit))
9724 }
9725 _ => None,
9726 }
9727 }
9728
9729 fn data_type_is_interval(dt: &DataType) -> bool {
9730 match dt {
9731 DataType::Interval { .. } => true,
9732 DataType::Custom { name } => name.trim().eq_ignore_ascii_case("INTERVAL"),
9733 _ => false,
9734 }
9735 }
9736
9737 fn node_is_interval_cast(node: &Expression) -> bool {
9738 match node {
9739 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
9740 Self::data_type_is_interval(&c.to)
9741 }
9742 _ => false,
9743 }
9744 }
9745
9746 fn reject_tsql_interval_casts(
9747 expr: &Expression,
9748 target: DialectType,
9749 opts: &TranspileOptions,
9750 ) -> Result<()> {
9751 if !matches!(
9752 opts.unsupported_level,
9753 UnsupportedLevel::Raise | UnsupportedLevel::Immediate
9754 ) {
9755 return Ok(());
9756 }
9757
9758 if expr.dfs().any(Self::node_is_interval_cast) {
9759 return Err(crate::error::Error::unsupported(
9760 "INTERVAL casts",
9761 target.to_string(),
9762 ));
9763 }
9764
9765 Ok(())
9766 }
9767
9768 fn tsql_varchar_max_type() -> DataType {
9769 DataType::Custom {
9770 name: "VARCHAR(MAX)".to_string(),
9771 }
9772 }
9773
9774 fn rewrite_tsql_interval_casts_to_varchar(expr: Expression) -> Result<Expression> {
9775 transform_recursive(expr, &|e| match e {
9776 Expression::Cast(mut cast) if Self::data_type_is_interval(&cast.to) => {
9777 cast.to = Self::tsql_varchar_max_type();
9778 cast.double_colon_syntax = false;
9779 Ok(Expression::Cast(cast))
9780 }
9781 Expression::TryCast(mut cast) if Self::data_type_is_interval(&cast.to) => {
9782 cast.to = Self::tsql_varchar_max_type();
9783 cast.double_colon_syntax = false;
9784 Ok(Expression::TryCast(cast))
9785 }
9786 Expression::SafeCast(mut cast) if Self::data_type_is_interval(&cast.to) => {
9787 cast.to = Self::tsql_varchar_max_type();
9788 cast.double_colon_syntax = false;
9789 Ok(Expression::SafeCast(cast))
9790 }
9791 _ => Ok(e),
9792 })
9793 }
9794
9795 fn rewrite_tsql_interval_arithmetic_legacy(
9796 expr: &Expression,
9797 source: DialectType,
9798 ) -> Option<Expression> {
9799 match expr {
9800 Expression::Add(op) => {
9801 if Self::extract_interval_parts(&op.right).is_some() {
9802 return Some(Self::build_tsql_dateadd_from_interval(
9803 op.left.clone(),
9804 &op.right,
9805 false,
9806 ));
9807 }
9808
9809 if Self::is_postgres_family_source(source) {
9810 if Self::is_explicit_date_expr(&op.left)
9811 && Self::is_integer_day_offset_expr(&op.right)
9812 {
9813 return Some(Self::build_tsql_dateadd_days(
9814 op.left.clone(),
9815 op.right.clone(),
9816 false,
9817 ));
9818 }
9819
9820 if Self::is_integer_day_offset_expr(&op.left)
9821 && Self::is_explicit_date_expr(&op.right)
9822 {
9823 return Some(Self::build_tsql_dateadd_days(
9824 op.right.clone(),
9825 op.left.clone(),
9826 false,
9827 ));
9828 }
9829 }
9830
9831 None
9832 }
9833 Expression::Sub(op) => {
9834 if Self::extract_interval_parts(&op.right).is_some() {
9835 return Some(Self::build_tsql_dateadd_from_interval(
9836 op.left.clone(),
9837 &op.right,
9838 true,
9839 ));
9840 }
9841
9842 if Self::is_postgres_family_source(source) {
9843 if Self::is_explicit_date_expr(&op.left)
9844 && Self::is_explicit_date_expr(&op.right)
9845 {
9846 return Some(Self::build_tsql_datediff_days(
9847 op.right.clone(),
9848 op.left.clone(),
9849 ));
9850 }
9851
9852 if Self::is_explicit_date_expr(&op.left)
9853 && Self::is_integer_day_offset_expr(&op.right)
9854 {
9855 return Some(Self::build_tsql_dateadd_days(
9856 op.left.clone(),
9857 op.right.clone(),
9858 true,
9859 ));
9860 }
9861 }
9862
9863 None
9864 }
9865 _ => None,
9866 }
9867 }
9868
9869 fn is_postgres_family_source(source: DialectType) -> bool {
9870 matches!(
9871 source,
9872 DialectType::PostgreSQL
9873 | DialectType::Redshift
9874 | DialectType::Materialize
9875 | DialectType::RisingWave
9876 | DialectType::CockroachDB
9877 )
9878 }
9879
9880 fn is_explicit_date_expr(expr: &Expression) -> bool {
9881 use crate::expressions::Literal;
9882
9883 match expr {
9884 Expression::Literal(lit) => matches!(lit.as_ref(), Literal::Date(_)),
9885 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
9886 matches!(c.to, crate::expressions::DataType::Date)
9887 }
9888 Expression::Paren(p) => Self::is_explicit_date_expr(&p.this),
9889 Expression::CurrentDate(_)
9890 | Expression::Date(_)
9891 | Expression::MakeDate(_)
9892 | Expression::ToDate(_)
9893 | Expression::DateStrToDate(_) => true,
9894 _ => false,
9895 }
9896 }
9897
9898 fn is_integer_day_offset_expr(expr: &Expression) -> bool {
9899 use crate::expressions::Literal;
9900
9901 match expr {
9902 Expression::Literal(lit) => match lit.as_ref() {
9903 Literal::Number(n) => n.parse::<i64>().is_ok(),
9904 _ => false,
9905 },
9906 Expression::Parameter(_) | Expression::Placeholder(_) => true,
9907 Expression::Neg(op) => Self::is_integer_day_offset_expr(&op.this),
9908 Expression::Paren(p) => Self::is_integer_day_offset_expr(&p.this),
9909 _ => false,
9910 }
9911 }
9912
9913 fn build_tsql_datediff_days(start: Expression, end: Expression) -> Expression {
9914 Expression::Function(Box::new(Function::new(
9915 "DATEDIFF".to_string(),
9916 vec![Expression::Identifier(Identifier::new("DAY")), start, end],
9917 )))
9918 }
9919
9920 fn build_tsql_dateadd_days(date: Expression, amount: Expression, subtract: bool) -> Expression {
9921 Expression::Function(Box::new(Function::new(
9922 "DATEADD".to_string(),
9923 vec![
9924 Expression::Identifier(Identifier::new("DAY")),
9925 Self::tsql_dateadd_amount(amount, subtract),
9926 date,
9927 ],
9928 )))
9929 }
9930
9931 fn build_tsql_dateadd_from_interval(
9932 date: Expression,
9933 interval: &Expression,
9934 subtract: bool,
9935 ) -> Expression {
9936 let (value, unit) = Self::extract_interval_parts(interval)
9937 .unwrap_or_else(|| (interval.clone(), crate::expressions::IntervalUnit::Day));
9938 let unit = normalization::temporal::interval_unit_to_string(&unit);
9939 let amount = Self::tsql_dateadd_amount(value, subtract);
9940
9941 Expression::Function(Box::new(Function::new(
9942 "DATEADD".to_string(),
9943 vec![Expression::Identifier(Identifier::new(unit)), amount, date],
9944 )))
9945 }
9946
9947 fn tsql_dateadd_amount(value: Expression, negate: bool) -> Expression {
9948 use crate::expressions::{Parameter, ParameterStyle, UnaryOp};
9949
9950 fn numeric_literal_value(value: &Expression) -> Option<&str> {
9951 match value {
9952 Expression::Literal(lit) => match lit.as_ref() {
9953 crate::expressions::Literal::Number(n)
9954 | crate::expressions::Literal::String(n) => Some(n.as_str()),
9955 _ => None,
9956 },
9957 _ => None,
9958 }
9959 }
9960
9961 fn colon_parameter(value: &Expression) -> Option<Expression> {
9962 let Expression::Literal(lit) = value else {
9963 return None;
9964 };
9965 let crate::expressions::Literal::String(s) = lit.as_ref() else {
9966 return None;
9967 };
9968 let name = s.strip_prefix(':')?;
9969 if name.is_empty()
9970 || !name
9971 .chars()
9972 .all(|ch| ch.is_ascii_alphanumeric() || ch == '_')
9973 {
9974 return None;
9975 }
9976
9977 Some(Expression::Parameter(Box::new(Parameter {
9978 name: if name.chars().all(|ch| ch.is_ascii_digit()) {
9979 None
9980 } else {
9981 Some(name.to_string())
9982 },
9983 index: name.parse::<u32>().ok(),
9984 style: ParameterStyle::Colon,
9985 quoted: false,
9986 string_quoted: false,
9987 expression: None,
9988 })))
9989 }
9990
9991 let value = colon_parameter(&value).unwrap_or(value);
9992
9993 if let Some(n) = numeric_literal_value(&value) {
9994 if let Ok(parsed) = n.parse::<f64>() {
9995 let normalized = if negate { -parsed } else { parsed };
9996 let rendered = if normalized.fract() == 0.0 {
9997 format!("{}", normalized as i64)
9998 } else {
9999 normalized.to_string()
10000 };
10001 return Expression::Literal(Box::new(crate::expressions::Literal::Number(
10002 rendered,
10003 )));
10004 }
10005 }
10006
10007 if !negate {
10008 return value;
10009 }
10010
10011 match value {
10012 Expression::Neg(op) => op.this,
10013 other => Expression::Neg(Box::new(UnaryOp {
10014 this: other,
10015 inferred_type: None,
10016 })),
10017 }
10018 }
10019
10020 const PRESERVED_TO_DATE: &'static str = "_POLYGLOT_TO_DATE";
10024}
10025
10026#[cfg(test)]
10027mod tests {
10028 use super::*;
10029
10030 #[test]
10031 fn built_in_dialect_instances_share_tokenizer_config() {
10032 let first = Dialect::get(DialectType::PostgreSQL);
10033 let second = Dialect::get(DialectType::PostgreSQL);
10034
10035 assert!(first.tokenizer.shares_config_with(&second.tokenizer));
10036 }
10037
10038 #[test]
10039 fn test_dialect_type_from_str() {
10040 assert_eq!(
10041 "postgres".parse::<DialectType>().unwrap(),
10042 DialectType::PostgreSQL
10043 );
10044 assert_eq!(
10045 "postgresql".parse::<DialectType>().unwrap(),
10046 DialectType::PostgreSQL
10047 );
10048 assert_eq!("mysql".parse::<DialectType>().unwrap(), DialectType::MySQL);
10049 assert_eq!(
10050 "bigquery".parse::<DialectType>().unwrap(),
10051 DialectType::BigQuery
10052 );
10053 }
10054
10055 #[test]
10056 fn test_basic_transpile() {
10057 let dialect = Dialect::get(DialectType::Generic);
10058 let result = dialect
10059 .transpile("SELECT 1", DialectType::PostgreSQL)
10060 .unwrap();
10061 assert_eq!(result.len(), 1);
10062 assert_eq!(result[0], "SELECT 1");
10063 }
10064
10065 #[test]
10066 fn test_sqlite_double_quoted_column_defaults_to_postgres_strings() {
10067 let sqlite = Dialect::get(DialectType::SQLite);
10068 let result = sqlite
10069 .transpile(
10070 r#"CREATE TABLE "_collections" (
10071 "type" TEXT DEFAULT "base" NOT NULL,
10072 "fields" JSON DEFAULT "[]" NOT NULL,
10073 "options" JSON DEFAULT "{}" NOT NULL
10074 )"#,
10075 DialectType::PostgreSQL,
10076 )
10077 .unwrap();
10078
10079 assert!(result[0].contains(r#""type" TEXT DEFAULT 'base' NOT NULL"#));
10080 assert!(result[0].contains(r#""fields" JSON DEFAULT '[]' NOT NULL"#));
10081 assert!(result[0].contains(r#""options" JSON DEFAULT '{}' NOT NULL"#));
10082 }
10083
10084 #[test]
10085 fn test_sqlite_identity_preserves_double_quoted_column_defaults() {
10086 let sqlite = Dialect::get(DialectType::SQLite);
10087 let result = sqlite
10088 .transpile(
10089 r#"CREATE TABLE "_collections" ("type" TEXT DEFAULT "base" NOT NULL)"#,
10090 DialectType::SQLite,
10091 )
10092 .unwrap();
10093
10094 assert_eq!(
10095 result[0],
10096 r#"CREATE TABLE "_collections" ("type" TEXT DEFAULT "base" NOT NULL)"#
10097 );
10098 }
10099
10100 #[test]
10101 fn test_function_transformation_mysql() {
10102 let dialect = Dialect::get(DialectType::Generic);
10104 let result = dialect
10105 .transpile("SELECT NVL(a, b)", DialectType::MySQL)
10106 .unwrap();
10107 assert_eq!(result[0], "SELECT IFNULL(a, b)");
10108 }
10109
10110 #[test]
10111 fn test_get_path_duckdb() {
10112 let snowflake = Dialect::get(DialectType::Snowflake);
10114
10115 let result_sf_sf = snowflake
10117 .transpile(
10118 "SELECT PARSE_JSON('{\"fruit\":\"banana\"}'):fruit",
10119 DialectType::Snowflake,
10120 )
10121 .unwrap();
10122 eprintln!("Snowflake->Snowflake colon: {}", result_sf_sf[0]);
10123
10124 let result_sf_dk = snowflake
10126 .transpile(
10127 "SELECT PARSE_JSON('{\"fruit\":\"banana\"}'):fruit",
10128 DialectType::DuckDB,
10129 )
10130 .unwrap();
10131 eprintln!("Snowflake->DuckDB colon: {}", result_sf_dk[0]);
10132
10133 let result_gp = snowflake
10135 .transpile(
10136 "SELECT GET_PATH(PARSE_JSON('{\"fruit\":\"banana\"}'), 'fruit')",
10137 DialectType::DuckDB,
10138 )
10139 .unwrap();
10140 eprintln!("Snowflake->DuckDB explicit GET_PATH: {}", result_gp[0]);
10141 }
10142
10143 #[test]
10144 fn test_function_transformation_postgres() {
10145 let dialect = Dialect::get(DialectType::Generic);
10147 let result = dialect
10148 .transpile("SELECT IFNULL(a, b)", DialectType::PostgreSQL)
10149 .unwrap();
10150 assert_eq!(result[0], "SELECT COALESCE(a, b)");
10151
10152 let result = dialect
10154 .transpile("SELECT NVL(a, b)", DialectType::PostgreSQL)
10155 .unwrap();
10156 assert_eq!(result[0], "SELECT COALESCE(a, b)");
10157 }
10158
10159 #[test]
10160 fn test_hive_cast_to_trycast() {
10161 let hive = Dialect::get(DialectType::Hive);
10163 let result = hive
10164 .transpile("CAST(1 AS INT)", DialectType::DuckDB)
10165 .unwrap();
10166 assert_eq!(result[0], "TRY_CAST(1 AS INT)");
10167
10168 let result = hive
10169 .transpile("CAST(1 AS INT)", DialectType::Presto)
10170 .unwrap();
10171 assert_eq!(result[0], "TRY_CAST(1 AS INTEGER)");
10172 }
10173
10174 #[test]
10175 fn test_hive_array_identity() {
10176 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')";
10178 let hive = Dialect::get(DialectType::Hive);
10179
10180 let result = hive.transpile(sql, DialectType::Hive).unwrap();
10182 eprintln!("Hive ARRAY via transpile: {}", result[0]);
10183 assert!(
10184 result[0].contains("ARRAY<DATE>"),
10185 "transpile: Expected ARRAY<DATE>, got: {}",
10186 result[0]
10187 );
10188
10189 let ast = hive.parse(sql).unwrap();
10191 let transformed = hive.transform(ast[0].clone()).unwrap();
10192 let output = hive.generate(&transformed).unwrap();
10193 eprintln!("Hive ARRAY via identity path: {}", output);
10194 assert!(
10195 output.contains("ARRAY<DATE>"),
10196 "identity path: Expected ARRAY<DATE>, got: {}",
10197 output
10198 );
10199 }
10200
10201 #[test]
10202 fn test_starrocks_delete_between_expansion() {
10203 let dialect = Dialect::get(DialectType::Generic);
10205
10206 let result = dialect
10208 .transpile(
10209 "DELETE FROM t WHERE a BETWEEN b AND c",
10210 DialectType::StarRocks,
10211 )
10212 .unwrap();
10213 assert_eq!(result[0], "DELETE FROM t WHERE a >= b AND a <= c");
10214
10215 let result = dialect
10217 .transpile(
10218 "DELETE FROM t WHERE a NOT BETWEEN b AND c",
10219 DialectType::StarRocks,
10220 )
10221 .unwrap();
10222 assert_eq!(result[0], "DELETE FROM t WHERE a < b OR a > c");
10223
10224 let result = dialect
10226 .transpile(
10227 "SELECT * FROM t WHERE a BETWEEN b AND c",
10228 DialectType::StarRocks,
10229 )
10230 .unwrap();
10231 assert!(
10232 result[0].contains("BETWEEN"),
10233 "BETWEEN should be preserved in SELECT"
10234 );
10235 }
10236
10237 #[test]
10238 fn test_snowflake_ltrim_rtrim_parse() {
10239 let sf = Dialect::get(DialectType::Snowflake);
10240 let sql = "SELECT LTRIM(RTRIM(col)) FROM t1";
10241 let result = sf.transpile(sql, DialectType::DuckDB);
10242 match &result {
10243 Ok(r) => eprintln!("LTRIM/RTRIM result: {}", r[0]),
10244 Err(e) => eprintln!("LTRIM/RTRIM error: {}", e),
10245 }
10246 assert!(
10247 result.is_ok(),
10248 "Expected successful parse of LTRIM(RTRIM(col)), got error: {:?}",
10249 result.err()
10250 );
10251 }
10252
10253 #[test]
10254 fn test_duckdb_count_if_parse() {
10255 let duck = Dialect::get(DialectType::DuckDB);
10256 let sql = "COUNT_IF(x)";
10257 let result = duck.transpile(sql, DialectType::DuckDB);
10258 match &result {
10259 Ok(r) => eprintln!("COUNT_IF result: {}", r[0]),
10260 Err(e) => eprintln!("COUNT_IF error: {}", e),
10261 }
10262 assert!(
10263 result.is_ok(),
10264 "Expected successful parse of COUNT_IF(x), got error: {:?}",
10265 result.err()
10266 );
10267 }
10268
10269 #[test]
10270 fn test_tsql_cast_tinyint_parse() {
10271 let tsql = Dialect::get(DialectType::TSQL);
10272 let sql = "CAST(X AS TINYINT)";
10273 let result = tsql.transpile(sql, DialectType::DuckDB);
10274 match &result {
10275 Ok(r) => eprintln!("TSQL CAST TINYINT result: {}", r[0]),
10276 Err(e) => eprintln!("TSQL CAST TINYINT error: {}", e),
10277 }
10278 assert!(
10279 result.is_ok(),
10280 "Expected successful transpile, got error: {:?}",
10281 result.err()
10282 );
10283 }
10284
10285 #[test]
10286 fn test_pg_hash_bitwise_xor() {
10287 let dialect = Dialect::get(DialectType::PostgreSQL);
10288 let result = dialect.transpile("x # y", DialectType::PostgreSQL).unwrap();
10289 assert_eq!(result[0], "x # y");
10290 }
10291
10292 #[test]
10293 fn test_pg_array_to_duckdb() {
10294 let dialect = Dialect::get(DialectType::PostgreSQL);
10295 let result = dialect
10296 .transpile("SELECT ARRAY[1, 2, 3] @> ARRAY[1, 2]", DialectType::DuckDB)
10297 .unwrap();
10298 assert_eq!(result[0], "SELECT [1, 2, 3] @> [1, 2]");
10299 }
10300
10301 #[test]
10302 fn test_array_remove_bigquery() {
10303 let dialect = Dialect::get(DialectType::Generic);
10304 let result = dialect
10305 .transpile("ARRAY_REMOVE(the_array, target)", DialectType::BigQuery)
10306 .unwrap();
10307 assert_eq!(
10308 result[0],
10309 "ARRAY(SELECT _u FROM UNNEST(the_array) AS _u WHERE _u <> target)"
10310 );
10311 }
10312
10313 #[test]
10314 fn test_map_clickhouse_case() {
10315 let dialect = Dialect::get(DialectType::Generic);
10316 let parsed = dialect
10317 .parse("CAST(MAP('a', '1') AS MAP(TEXT, TEXT))")
10318 .unwrap();
10319 eprintln!("MAP parsed: {:?}", parsed);
10320 let result = dialect
10321 .transpile(
10322 "CAST(MAP('a', '1') AS MAP(TEXT, TEXT))",
10323 DialectType::ClickHouse,
10324 )
10325 .unwrap();
10326 eprintln!("MAP result: {}", result[0]);
10327 }
10328
10329 #[test]
10330 fn test_generate_date_array_presto() {
10331 let dialect = Dialect::get(DialectType::Generic);
10332 let result = dialect.transpile(
10333 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10334 DialectType::Presto,
10335 ).unwrap();
10336 eprintln!("GDA -> Presto: {}", result[0]);
10337 assert_eq!(result[0], "SELECT * FROM UNNEST(SEQUENCE(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), (1 * INTERVAL '7' DAY)))");
10338 }
10339
10340 #[test]
10341 fn test_generate_date_array_postgres() {
10342 let dialect = Dialect::get(DialectType::Generic);
10343 let result = dialect.transpile(
10344 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10345 DialectType::PostgreSQL,
10346 ).unwrap();
10347 eprintln!("GDA -> PostgreSQL: {}", result[0]);
10348 }
10349
10350 #[test]
10351 fn test_generate_date_array_snowflake() {
10352 let dialect = Dialect::get(DialectType::Generic);
10353 let result = dialect
10354 .transpile(
10355 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10356 DialectType::Snowflake,
10357 )
10358 .unwrap();
10359 eprintln!("GDA -> Snowflake: {}", result[0]);
10360 }
10361
10362 #[test]
10363 fn test_array_length_generate_date_array_snowflake() {
10364 let dialect = Dialect::get(DialectType::Generic);
10365 let result = dialect.transpile(
10366 "SELECT ARRAY_LENGTH(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10367 DialectType::Snowflake,
10368 ).unwrap();
10369 eprintln!("ARRAY_LENGTH(GDA) -> Snowflake: {}", result[0]);
10370 }
10371
10372 #[test]
10373 fn test_generate_date_array_mysql() {
10374 let dialect = Dialect::get(DialectType::Generic);
10375 let result = dialect.transpile(
10376 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10377 DialectType::MySQL,
10378 ).unwrap();
10379 eprintln!("GDA -> MySQL: {}", result[0]);
10380 }
10381
10382 #[test]
10383 fn test_generate_date_array_redshift() {
10384 let dialect = Dialect::get(DialectType::Generic);
10385 let result = dialect.transpile(
10386 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10387 DialectType::Redshift,
10388 ).unwrap();
10389 eprintln!("GDA -> Redshift: {}", result[0]);
10390 }
10391
10392 #[test]
10393 fn test_generate_date_array_tsql() {
10394 let dialect = Dialect::get(DialectType::Generic);
10395 let result = dialect.transpile(
10396 "SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))",
10397 DialectType::TSQL,
10398 ).unwrap();
10399 eprintln!("GDA -> TSQL: {}", result[0]);
10400 }
10401
10402 #[test]
10403 fn test_struct_colon_syntax() {
10404 let dialect = Dialect::get(DialectType::Generic);
10405 let result = dialect.transpile(
10407 "CAST((1, 2, 3, 4) AS STRUCT<a TINYINT, b SMALLINT, c INT, d BIGINT>)",
10408 DialectType::ClickHouse,
10409 );
10410 match result {
10411 Ok(r) => eprintln!("STRUCT no colon -> ClickHouse: {}", r[0]),
10412 Err(e) => eprintln!("STRUCT no colon error: {}", e),
10413 }
10414 let result = dialect.transpile(
10416 "CAST((1, 2, 3, 4) AS STRUCT<a: TINYINT, b: SMALLINT, c: INT, d: BIGINT>)",
10417 DialectType::ClickHouse,
10418 );
10419 match result {
10420 Ok(r) => eprintln!("STRUCT colon -> ClickHouse: {}", r[0]),
10421 Err(e) => eprintln!("STRUCT colon error: {}", e),
10422 }
10423 }
10424
10425 #[test]
10426 fn test_generate_date_array_cte_wrapped_mysql() {
10427 let dialect = Dialect::get(DialectType::Generic);
10428 let result = dialect.transpile(
10429 "WITH dates AS (SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))) SELECT * FROM dates",
10430 DialectType::MySQL,
10431 ).unwrap();
10432 eprintln!("GDA CTE -> MySQL: {}", result[0]);
10433 }
10434
10435 #[test]
10436 fn test_generate_date_array_cte_wrapped_tsql() {
10437 let dialect = Dialect::get(DialectType::Generic);
10438 let result = dialect.transpile(
10439 "WITH dates AS (SELECT * FROM UNNEST(GENERATE_DATE_ARRAY(DATE '2020-01-01', DATE '2020-02-01', INTERVAL 1 WEEK))) SELECT * FROM dates",
10440 DialectType::TSQL,
10441 ).unwrap();
10442 eprintln!("GDA CTE -> TSQL: {}", result[0]);
10443 }
10444
10445 #[test]
10446 fn test_decode_literal_no_null_check() {
10447 let dialect = Dialect::get(DialectType::Oracle);
10449 let result = dialect
10450 .transpile("SELECT decode(1,2,3,4)", DialectType::DuckDB)
10451 .unwrap();
10452 assert_eq!(
10453 result[0], "SELECT CASE WHEN 1 = 2 THEN 3 ELSE 4 END",
10454 "Literal DECODE should not have IS NULL checks"
10455 );
10456 }
10457
10458 #[test]
10459 fn test_decode_column_vs_literal_no_null_check() {
10460 let dialect = Dialect::get(DialectType::Oracle);
10462 let result = dialect
10463 .transpile("SELECT decode(col, 2, 3, 4) FROM t", DialectType::DuckDB)
10464 .unwrap();
10465 assert_eq!(
10466 result[0], "SELECT CASE WHEN col = 2 THEN 3 ELSE 4 END FROM t",
10467 "Column vs literal DECODE should not have IS NULL checks"
10468 );
10469 }
10470
10471 #[test]
10472 fn test_decode_column_vs_column_keeps_null_check() {
10473 let dialect = Dialect::get(DialectType::Oracle);
10475 let result = dialect
10476 .transpile("SELECT decode(col, col2, 3, 4) FROM t", DialectType::DuckDB)
10477 .unwrap();
10478 assert!(
10479 result[0].contains("IS NULL"),
10480 "Column vs column DECODE should have IS NULL checks, got: {}",
10481 result[0]
10482 );
10483 }
10484
10485 #[test]
10486 fn test_decode_null_search() {
10487 let dialect = Dialect::get(DialectType::Oracle);
10489 let result = dialect
10490 .transpile("SELECT decode(col, NULL, 3, 4) FROM t", DialectType::DuckDB)
10491 .unwrap();
10492 assert_eq!(
10493 result[0],
10494 "SELECT CASE WHEN col IS NULL THEN 3 ELSE 4 END FROM t",
10495 );
10496 }
10497
10498 #[test]
10503 fn test_regexp_substr_snowflake_to_duckdb_2arg() {
10504 let dialect = Dialect::get(DialectType::Snowflake);
10505 let result = dialect
10506 .transpile("SELECT REGEXP_SUBSTR(s, 'pattern')", DialectType::DuckDB)
10507 .unwrap();
10508 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10509 }
10510
10511 #[test]
10512 fn test_regexp_substr_snowflake_to_duckdb_3arg_pos1() {
10513 let dialect = Dialect::get(DialectType::Snowflake);
10514 let result = dialect
10515 .transpile("SELECT REGEXP_SUBSTR(s, 'pattern', 1)", DialectType::DuckDB)
10516 .unwrap();
10517 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10518 }
10519
10520 #[test]
10521 fn test_regexp_substr_snowflake_to_duckdb_3arg_pos_gt1() {
10522 let dialect = Dialect::get(DialectType::Snowflake);
10523 let result = dialect
10524 .transpile("SELECT REGEXP_SUBSTR(s, 'pattern', 3)", DialectType::DuckDB)
10525 .unwrap();
10526 assert_eq!(
10527 result[0],
10528 "SELECT REGEXP_EXTRACT(NULLIF(SUBSTRING(s, 3), ''), 'pattern')"
10529 );
10530 }
10531
10532 #[test]
10533 fn test_regexp_substr_snowflake_to_duckdb_4arg_occ_gt1() {
10534 let dialect = Dialect::get(DialectType::Snowflake);
10535 let result = dialect
10536 .transpile(
10537 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 3)",
10538 DialectType::DuckDB,
10539 )
10540 .unwrap();
10541 assert_eq!(
10542 result[0],
10543 "SELECT ARRAY_EXTRACT(REGEXP_EXTRACT_ALL(s, 'pattern'), 3)"
10544 );
10545 }
10546
10547 #[test]
10548 fn test_regexp_substr_snowflake_to_duckdb_5arg_e_flag() {
10549 let dialect = Dialect::get(DialectType::Snowflake);
10550 let result = dialect
10551 .transpile(
10552 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e')",
10553 DialectType::DuckDB,
10554 )
10555 .unwrap();
10556 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10557 }
10558
10559 #[test]
10560 fn test_regexp_substr_snowflake_to_duckdb_6arg_group0() {
10561 let dialect = Dialect::get(DialectType::Snowflake);
10562 let result = dialect
10563 .transpile(
10564 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e', 0)",
10565 DialectType::DuckDB,
10566 )
10567 .unwrap();
10568 assert_eq!(result[0], "SELECT REGEXP_EXTRACT(s, 'pattern')");
10569 }
10570
10571 #[test]
10572 fn test_regexp_substr_snowflake_identity_strip_group0() {
10573 let dialect = Dialect::get(DialectType::Snowflake);
10574 let result = dialect
10575 .transpile(
10576 "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e', 0)",
10577 DialectType::Snowflake,
10578 )
10579 .unwrap();
10580 assert_eq!(result[0], "SELECT REGEXP_SUBSTR(s, 'pattern', 1, 1, 'e')");
10581 }
10582
10583 #[test]
10584 fn test_regexp_substr_all_snowflake_to_duckdb_2arg() {
10585 let dialect = Dialect::get(DialectType::Snowflake);
10586 let result = dialect
10587 .transpile(
10588 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern')",
10589 DialectType::DuckDB,
10590 )
10591 .unwrap();
10592 assert_eq!(result[0], "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')");
10593 }
10594
10595 #[test]
10596 fn test_regexp_substr_all_snowflake_to_duckdb_3arg_pos_gt1() {
10597 let dialect = Dialect::get(DialectType::Snowflake);
10598 let result = dialect
10599 .transpile(
10600 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 3)",
10601 DialectType::DuckDB,
10602 )
10603 .unwrap();
10604 assert_eq!(
10605 result[0],
10606 "SELECT REGEXP_EXTRACT_ALL(SUBSTRING(s, 3), 'pattern')"
10607 );
10608 }
10609
10610 #[test]
10611 fn test_regexp_substr_all_snowflake_to_duckdb_5arg_e_flag() {
10612 let dialect = Dialect::get(DialectType::Snowflake);
10613 let result = dialect
10614 .transpile(
10615 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e')",
10616 DialectType::DuckDB,
10617 )
10618 .unwrap();
10619 assert_eq!(result[0], "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')");
10620 }
10621
10622 #[test]
10623 fn test_regexp_substr_all_snowflake_to_duckdb_6arg_group0() {
10624 let dialect = Dialect::get(DialectType::Snowflake);
10625 let result = dialect
10626 .transpile(
10627 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e', 0)",
10628 DialectType::DuckDB,
10629 )
10630 .unwrap();
10631 assert_eq!(result[0], "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')");
10632 }
10633
10634 #[test]
10635 fn test_regexp_substr_all_snowflake_identity_strip_group0() {
10636 let dialect = Dialect::get(DialectType::Snowflake);
10637 let result = dialect
10638 .transpile(
10639 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e', 0)",
10640 DialectType::Snowflake,
10641 )
10642 .unwrap();
10643 assert_eq!(
10644 result[0],
10645 "SELECT REGEXP_SUBSTR_ALL(s, 'pattern', 1, 1, 'e')"
10646 );
10647 }
10648
10649 #[test]
10650 fn test_regexp_count_snowflake_to_duckdb_2arg() {
10651 let dialect = Dialect::get(DialectType::Snowflake);
10652 let result = dialect
10653 .transpile("SELECT REGEXP_COUNT(s, 'pattern')", DialectType::DuckDB)
10654 .unwrap();
10655 assert_eq!(
10656 result[0],
10657 "SELECT CASE WHEN 'pattern' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(s, 'pattern')) END"
10658 );
10659 }
10660
10661 #[test]
10662 fn test_regexp_count_snowflake_to_duckdb_3arg() {
10663 let dialect = Dialect::get(DialectType::Snowflake);
10664 let result = dialect
10665 .transpile("SELECT REGEXP_COUNT(s, 'pattern', 3)", DialectType::DuckDB)
10666 .unwrap();
10667 assert_eq!(
10668 result[0],
10669 "SELECT CASE WHEN 'pattern' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(SUBSTRING(s, 3), 'pattern')) END"
10670 );
10671 }
10672
10673 #[test]
10674 fn test_regexp_count_snowflake_to_duckdb_4arg_flags() {
10675 let dialect = Dialect::get(DialectType::Snowflake);
10676 let result = dialect
10677 .transpile(
10678 "SELECT REGEXP_COUNT(s, 'pattern', 1, 'i')",
10679 DialectType::DuckDB,
10680 )
10681 .unwrap();
10682 assert_eq!(
10683 result[0],
10684 "SELECT CASE WHEN '(?i)' || 'pattern' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(SUBSTRING(s, 1), '(?i)' || 'pattern')) END"
10685 );
10686 }
10687
10688 #[test]
10689 fn test_regexp_count_snowflake_to_duckdb_4arg_flags_literal_string() {
10690 let dialect = Dialect::get(DialectType::Snowflake);
10691 let result = dialect
10692 .transpile(
10693 "SELECT REGEXP_COUNT('Hello World', 'L', 1, 'im')",
10694 DialectType::DuckDB,
10695 )
10696 .unwrap();
10697 assert_eq!(
10698 result[0],
10699 "SELECT CASE WHEN '(?im)' || 'L' = '' THEN 0 ELSE LENGTH(REGEXP_EXTRACT_ALL(SUBSTRING('Hello World', 1), '(?im)' || 'L')) END"
10700 );
10701 }
10702
10703 #[test]
10704 fn test_regexp_replace_snowflake_to_duckdb_5arg_pos1_occ1() {
10705 let dialect = Dialect::get(DialectType::Snowflake);
10706 let result = dialect
10707 .transpile(
10708 "SELECT REGEXP_REPLACE(s, 'pattern', 'repl', 1, 1)",
10709 DialectType::DuckDB,
10710 )
10711 .unwrap();
10712 assert_eq!(result[0], "SELECT REGEXP_REPLACE(s, 'pattern', 'repl')");
10713 }
10714
10715 #[test]
10716 fn test_regexp_replace_snowflake_to_duckdb_5arg_pos_gt1_occ0() {
10717 let dialect = Dialect::get(DialectType::Snowflake);
10718 let result = dialect
10719 .transpile(
10720 "SELECT REGEXP_REPLACE(s, 'pattern', 'repl', 3, 0)",
10721 DialectType::DuckDB,
10722 )
10723 .unwrap();
10724 assert_eq!(
10725 result[0],
10726 "SELECT SUBSTRING(s, 1, 2) || REGEXP_REPLACE(SUBSTRING(s, 3), 'pattern', 'repl', 'g')"
10727 );
10728 }
10729
10730 #[test]
10731 fn test_regexp_replace_snowflake_to_duckdb_5arg_pos_gt1_occ1() {
10732 let dialect = Dialect::get(DialectType::Snowflake);
10733 let result = dialect
10734 .transpile(
10735 "SELECT REGEXP_REPLACE(s, 'pattern', 'repl', 3, 1)",
10736 DialectType::DuckDB,
10737 )
10738 .unwrap();
10739 assert_eq!(
10740 result[0],
10741 "SELECT SUBSTRING(s, 1, 2) || REGEXP_REPLACE(SUBSTRING(s, 3), 'pattern', 'repl')"
10742 );
10743 }
10744
10745 #[test]
10746 fn test_rlike_snowflake_to_duckdb_2arg() {
10747 let dialect = Dialect::get(DialectType::Snowflake);
10748 let result = dialect
10749 .transpile("SELECT RLIKE(a, b)", DialectType::DuckDB)
10750 .unwrap();
10751 assert_eq!(result[0], "SELECT REGEXP_FULL_MATCH(a, b)");
10752 }
10753
10754 #[test]
10755 fn test_rlike_snowflake_to_duckdb_3arg_flags() {
10756 let dialect = Dialect::get(DialectType::Snowflake);
10757 let result = dialect
10758 .transpile("SELECT RLIKE(a, b, 'i')", DialectType::DuckDB)
10759 .unwrap();
10760 assert_eq!(result[0], "SELECT REGEXP_FULL_MATCH(a, b, 'i')");
10761 }
10762
10763 #[test]
10764 fn test_regexp_extract_all_bigquery_to_snowflake_no_capture() {
10765 let dialect = Dialect::get(DialectType::BigQuery);
10766 let result = dialect
10767 .transpile(
10768 "SELECT REGEXP_EXTRACT_ALL(s, 'pattern')",
10769 DialectType::Snowflake,
10770 )
10771 .unwrap();
10772 assert_eq!(result[0], "SELECT REGEXP_SUBSTR_ALL(s, 'pattern')");
10773 }
10774
10775 #[test]
10776 fn test_regexp_extract_all_bigquery_to_snowflake_with_capture() {
10777 let dialect = Dialect::get(DialectType::BigQuery);
10778 let result = dialect
10779 .transpile(
10780 "SELECT REGEXP_EXTRACT_ALL(s, '(a)[0-9]')",
10781 DialectType::Snowflake,
10782 )
10783 .unwrap();
10784 assert_eq!(
10785 result[0],
10786 "SELECT REGEXP_SUBSTR_ALL(s, '(a)[0-9]', 1, 1, 'c', 1)"
10787 );
10788 }
10789
10790 #[test]
10791 fn test_regexp_instr_snowflake_to_duckdb_2arg() {
10792 let dialect = Dialect::get(DialectType::Snowflake);
10793 let result = dialect
10794 .transpile("SELECT REGEXP_INSTR(s, 'pattern')", DialectType::DuckDB)
10795 .unwrap();
10796 assert!(
10797 result[0].contains("CASE WHEN"),
10798 "Expected CASE WHEN in result: {}",
10799 result[0]
10800 );
10801 assert!(
10802 result[0].contains("LIST_SUM"),
10803 "Expected LIST_SUM in result: {}",
10804 result[0]
10805 );
10806 }
10807
10808 #[test]
10809 fn test_array_except_generic_to_duckdb() {
10810 let dialect = Dialect::get(DialectType::Generic);
10811 let result = dialect
10812 .transpile(
10813 "SELECT ARRAY_EXCEPT(ARRAY(1, 2, 3), ARRAY(2))",
10814 DialectType::DuckDB,
10815 )
10816 .unwrap();
10817 eprintln!("ARRAY_EXCEPT Generic->DuckDB: {}", result[0]);
10818 assert!(
10819 result[0].contains("CASE WHEN"),
10820 "Expected CASE WHEN: {}",
10821 result[0]
10822 );
10823 assert!(
10824 result[0].contains("LIST_FILTER"),
10825 "Expected LIST_FILTER: {}",
10826 result[0]
10827 );
10828 assert!(
10829 result[0].contains("LIST_DISTINCT"),
10830 "Expected LIST_DISTINCT: {}",
10831 result[0]
10832 );
10833 assert!(
10834 result[0].contains("IS NOT DISTINCT FROM"),
10835 "Expected IS NOT DISTINCT FROM: {}",
10836 result[0]
10837 );
10838 assert!(
10839 result[0].contains("= 0"),
10840 "Expected = 0 filter: {}",
10841 result[0]
10842 );
10843 }
10844
10845 #[test]
10846 fn test_array_except_generic_to_snowflake() {
10847 let dialect = Dialect::get(DialectType::Generic);
10848 let result = dialect
10849 .transpile(
10850 "SELECT ARRAY_EXCEPT(ARRAY(1, 2, 3), ARRAY(2))",
10851 DialectType::Snowflake,
10852 )
10853 .unwrap();
10854 eprintln!("ARRAY_EXCEPT Generic->Snowflake: {}", result[0]);
10855 assert_eq!(result[0], "SELECT ARRAY_EXCEPT([1, 2, 3], [2])");
10856 }
10857
10858 #[test]
10859 fn test_array_except_generic_to_presto() {
10860 let dialect = Dialect::get(DialectType::Generic);
10861 let result = dialect
10862 .transpile(
10863 "SELECT ARRAY_EXCEPT(ARRAY(1, 2, 3), ARRAY(2))",
10864 DialectType::Presto,
10865 )
10866 .unwrap();
10867 eprintln!("ARRAY_EXCEPT Generic->Presto: {}", result[0]);
10868 assert_eq!(result[0], "SELECT ARRAY_EXCEPT(ARRAY[1, 2, 3], ARRAY[2])");
10869 }
10870
10871 #[test]
10872 fn test_array_except_snowflake_to_duckdb() {
10873 let dialect = Dialect::get(DialectType::Snowflake);
10874 let result = dialect
10875 .transpile("SELECT ARRAY_EXCEPT([1, 2, 3], [2])", DialectType::DuckDB)
10876 .unwrap();
10877 eprintln!("ARRAY_EXCEPT Snowflake->DuckDB: {}", result[0]);
10878 assert!(
10879 result[0].contains("CASE WHEN"),
10880 "Expected CASE WHEN: {}",
10881 result[0]
10882 );
10883 assert!(
10884 result[0].contains("LIST_TRANSFORM"),
10885 "Expected LIST_TRANSFORM: {}",
10886 result[0]
10887 );
10888 }
10889
10890 #[test]
10891 fn test_array_contains_snowflake_to_snowflake() {
10892 let dialect = Dialect::get(DialectType::Snowflake);
10893 let result = dialect
10894 .transpile(
10895 "SELECT ARRAY_CONTAINS(x, [1, NULL, 3])",
10896 DialectType::Snowflake,
10897 )
10898 .unwrap();
10899 eprintln!("ARRAY_CONTAINS Snowflake->Snowflake: {}", result[0]);
10900 assert_eq!(result[0], "SELECT ARRAY_CONTAINS(x, [1, NULL, 3])");
10901 }
10902
10903 #[test]
10904 fn test_array_contains_snowflake_to_duckdb() {
10905 let dialect = Dialect::get(DialectType::Snowflake);
10906 let result = dialect
10907 .transpile(
10908 "SELECT ARRAY_CONTAINS(x, [1, NULL, 3])",
10909 DialectType::DuckDB,
10910 )
10911 .unwrap();
10912 eprintln!("ARRAY_CONTAINS 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("NULLIF"),
10920 "Expected NULLIF: {}",
10921 result[0]
10922 );
10923 assert!(
10924 result[0].contains("ARRAY_CONTAINS"),
10925 "Expected ARRAY_CONTAINS: {}",
10926 result[0]
10927 );
10928 }
10929
10930 #[test]
10931 fn test_array_distinct_snowflake_to_duckdb() {
10932 let dialect = Dialect::get(DialectType::Snowflake);
10933 let result = dialect
10934 .transpile(
10935 "SELECT ARRAY_DISTINCT([1, 2, 2, 3, 1])",
10936 DialectType::DuckDB,
10937 )
10938 .unwrap();
10939 eprintln!("ARRAY_DISTINCT Snowflake->DuckDB: {}", result[0]);
10940 assert!(
10941 result[0].contains("CASE WHEN"),
10942 "Expected CASE WHEN: {}",
10943 result[0]
10944 );
10945 assert!(
10946 result[0].contains("LIST_DISTINCT"),
10947 "Expected LIST_DISTINCT: {}",
10948 result[0]
10949 );
10950 assert!(
10951 result[0].contains("LIST_APPEND"),
10952 "Expected LIST_APPEND: {}",
10953 result[0]
10954 );
10955 assert!(
10956 result[0].contains("LIST_FILTER"),
10957 "Expected LIST_FILTER: {}",
10958 result[0]
10959 );
10960 }
10961}