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