1use super::{DialectImpl, DialectType};
14use crate::error::Result;
15use crate::expressions::{
16 Alias, BinaryOp, Cast, Column, Cte, DataType, Exists, Expression, From, Function, Identifier,
17 In, Join, JoinKind, LikeOp, Literal, Null, Over, Paren, QuantifiedExpr, QuantifiedOp, Select,
18 Star, StringAggFunc, Subquery, TrimFunc, TrimPosition, Tuple, UnaryFunc, Values, Where,
19 WindowFunction,
20};
21#[cfg(feature = "generate")]
22use crate::generator::GeneratorConfig;
23use crate::tokens::TokenizerConfig;
24use std::collections::HashMap;
25
26pub struct TSQLDialect;
28
29enum PostgresToCharFormat {
30 Numeric,
31 Temporal {
32 strftime: String,
33 requires_english_culture: bool,
34 },
35 Unsupported,
36}
37
38impl DialectImpl for TSQLDialect {
39 fn dialect_type(&self) -> DialectType {
40 DialectType::TSQL
41 }
42
43 fn tokenizer_config(&self) -> TokenizerConfig {
44 let mut config = TokenizerConfig::default();
45 config.identifiers.insert('[', ']');
47 config.identifiers.insert('"', '"');
49 config.hex_number_strings = true;
51 config.allow_empty_hex_string = true;
52 config
53 }
54
55 #[cfg(feature = "generate")]
56
57 fn generator_config(&self) -> GeneratorConfig {
58 use crate::generator::IdentifierQuoteStyle;
59 GeneratorConfig {
60 identifier_quote: '[',
62 identifier_quote_style: IdentifierQuoteStyle::BRACKET,
63 dialect: Some(DialectType::TSQL),
64 limit_fetch_style: crate::generator::LimitFetchStyle::Top,
67 null_ordering_supported: false,
69 aggregate_filter_supported: false,
71 supports_select_into: true,
73 alter_table_include_column_keyword: false,
75 computed_column_with_type: false,
77 cte_recursive_keyword_required: false,
79 ensure_bools: true,
81 supports_single_arg_concat: false,
83 tablesample_seed_keyword: "REPEATABLE",
85 json_path_bracketed_key_supported: false,
87 supports_to_number: false,
89 set_op_modifiers: false,
91 copy_params_eq_required: true,
93 except_intersect_support_all_clause: false,
95 alter_set_wrapped: true,
97 try_supported: true,
99 nvl2_supported: false,
101 parameter_default_equals: true,
103 supports_window_exclude: false,
105 multi_arg_distinct: false,
107 locking_reads_supported: false,
109 ..Default::default()
110 }
111 }
112
113 #[cfg(feature = "transpile")]
114
115 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
116 if let Expression::CreateTable(mut ct) = expr {
118 for col in &mut ct.columns {
119 if let Ok(Expression::DataType(new_dt)) =
120 self.transform_data_type(col.data_type.clone())
121 {
122 col.data_type = new_dt;
123 }
124 }
125 return Ok(Expression::CreateTable(ct));
126 }
127
128 match expr {
129 Expression::Select(mut select) => {
134 select.expressions = select
135 .expressions
136 .into_iter()
137 .map(|e| {
138 match e {
139 Expression::Eq(op) => {
140 match &op.left {
143 Expression::Column(col)
144 if col.table.is_none()
145 && !col.name.name.starts_with('@') =>
146 {
147 Expression::Alias(Box::new(Alias {
148 this: op.right,
149 alias: col.name.clone(),
150 column_aliases: Vec::new(),
151 alias_explicit_as: false,
152 alias_keyword: None,
153 pre_alias_comments: Vec::new(),
154 trailing_comments: Vec::new(),
155 inferred_type: None,
156 }))
157 }
158 Expression::Identifier(ident)
159 if !ident.name.starts_with('@') =>
160 {
161 Expression::Alias(Box::new(Alias {
162 this: op.right,
163 alias: ident.clone(),
164 column_aliases: Vec::new(),
165 alias_explicit_as: false,
166 alias_keyword: None,
167 pre_alias_comments: Vec::new(),
168 trailing_comments: Vec::new(),
169 inferred_type: None,
170 }))
171 }
172 _ => Expression::Eq(op),
173 }
174 }
175 other => other,
176 }
177 })
178 .collect();
179
180 Self::normalize_frame_incompatible_window_functions(&mut select);
181
182 let outer_qualifier = Self::single_select_source_qualifier(&select);
183
184 select.expressions = select
185 .expressions
186 .into_iter()
187 .map(|expression| {
188 Self::rewrite_tuple_in_subquery_predicates(
189 expression,
190 outer_qualifier.as_ref(),
191 false,
192 )
193 })
194 .collect();
195
196 for join in &mut select.joins {
197 if let Some(on) = join.on.take() {
198 join.on = Some(Self::rewrite_tuple_in_subquery_predicates(
199 on,
200 outer_qualifier.as_ref(),
201 false,
202 ));
203 }
204 if let Some(match_condition) = join.match_condition.take() {
205 join.match_condition = Some(Self::rewrite_tuple_in_subquery_predicates(
206 match_condition,
207 outer_qualifier.as_ref(),
208 false,
209 ));
210 }
211 }
212
213 if let Some(ref mut prewhere) = select.prewhere {
214 *prewhere = Self::rewrite_tuple_in_subquery_predicates(
215 std::mem::replace(prewhere, Expression::Null(Null)),
216 outer_qualifier.as_ref(),
217 false,
218 );
219 }
220
221 if let Some(ref mut where_clause) = select.where_clause {
222 where_clause.this = Self::rewrite_tuple_in_subquery_predicates(
223 std::mem::replace(&mut where_clause.this, Expression::Null(Null)),
224 outer_qualifier.as_ref(),
225 false,
226 );
227 }
228
229 if let Some(ref mut having) = select.having {
230 having.this = Self::rewrite_tuple_in_subquery_predicates(
231 std::mem::replace(&mut having.this, Expression::Null(Null)),
232 outer_qualifier.as_ref(),
233 false,
234 );
235 }
236
237 if let Some(ref mut qualify) = select.qualify {
238 qualify.this = Self::rewrite_tuple_in_subquery_predicates(
239 std::mem::replace(&mut qualify.this, Expression::Null(Null)),
240 outer_qualifier.as_ref(),
241 false,
242 );
243 }
244
245 if let Some(ref mut with) = select.with {
247 with.ctes = with
248 .ctes
249 .drain(..)
250 .map(|cte| self.transform_cte_inner(cte))
251 .collect();
252 }
253
254 Self::rewrite_comma_lateral_sources_to_joins(&mut select);
255
256 Ok(Expression::Select(select))
257 }
258
259 Expression::DataType(dt) => self.transform_data_type(dt),
261
262 Expression::IsTrue(it) => Ok(Self::boolean_test_predicate(it.this, true, it.not)),
266 Expression::IsFalse(it) => Ok(Self::boolean_test_predicate(it.this, false, it.not)),
267
268 Expression::In(mut in_expr) if in_expr.not => {
272 in_expr.not = false;
273 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
274 this: Expression::In(in_expr),
275 inferred_type: None,
276 })))
277 }
278
279 Expression::Coalesce(f) if f.expressions.len() == 2 => Ok(Expression::Function(
282 Box::new(Function::new("ISNULL".to_string(), f.expressions)),
283 )),
284
285 Expression::Nvl(f) => Ok(Expression::Function(Box::new(Function::new(
287 "ISNULL".to_string(),
288 vec![f.this, f.expression],
289 )))),
290
291 Expression::GroupConcat(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
293 this: f.this,
294 separator: f.separator,
295 order_by: f.order_by,
296 distinct: f.distinct,
297 filter: f.filter,
298 limit: None,
299 inferred_type: None,
300 }))),
301
302 Expression::ListAgg(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
304 this: f.this,
305 separator: f.separator,
306 order_by: f.order_by,
307 distinct: f.distinct,
308 filter: f.filter,
309 limit: None,
310 inferred_type: None,
311 }))),
312
313 Expression::Sum(f) => Ok(Expression::Sum(Self::without_inert_ordering(f))),
317 Expression::Avg(f) => Ok(Expression::Avg(Self::without_inert_ordering(f))),
318 Expression::Min(f) => Ok(Expression::Min(Self::without_inert_ordering(f))),
319 Expression::Max(f) => Ok(Expression::Max(Self::without_inert_ordering(f))),
320 Expression::AnyValue(f) => Ok(Expression::Max(Self::without_inert_ordering(f))),
321 Expression::ApproxCountDistinct(f) => Ok(Expression::ApproxCountDistinct(
322 Self::without_inert_ordering(f),
323 )),
324
325 Expression::LogicalAnd(f) => Self::transform_logical_aggregate(f.this, f.filter, "MIN"),
328 Expression::LogicalOr(f) => Self::transform_logical_aggregate(f.this, f.filter, "MAX"),
329
330 Expression::WindowFunction(f) => Ok(Self::reassociate_logical_aggregate_window(*f)),
334
335 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
337
338 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
340
341 Expression::ILike(op) => {
343 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
346 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
347 Ok(Expression::Like(Box::new(LikeOp {
348 left: lower_left,
349 right: lower_right,
350 escape: op.escape,
351 quantifier: op.quantifier,
352 inferred_type: None,
353 })))
354 }
355
356 Expression::Concat(op) => {
359 Ok(Expression::Add(op))
361 }
362
363 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
365 seed: None,
366 lower: None,
367 upper: None,
368 }))),
369
370 Expression::Unnest(f) => {
372 Ok(Expression::Function(Box::new(Function::new(
375 "OPENJSON".to_string(),
376 vec![f.this],
377 ))))
378 }
379
380 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
382 "OPENJSON".to_string(),
383 vec![f.this],
384 )))),
385
386 Expression::Join(join) => Ok(Expression::Join(Box::new(
388 Self::transform_lateral_join_to_apply(*join)?,
389 ))),
390
391 Expression::Length(f) => Ok(Expression::Function(Box::new(Function::new(
393 "LEN".to_string(),
394 vec![f.this],
395 )))),
396
397 Expression::Stddev(f) => Ok(Expression::Function(Box::new(Function::new(
399 "STDEV".to_string(),
400 vec![f.this],
401 )))),
402 Expression::StddevSamp(f) => Ok(Expression::Function(Box::new(Function::new(
403 "STDEV".to_string(),
404 vec![f.this],
405 )))),
406 Expression::StddevPop(f) => Ok(Expression::Function(Box::new(Function::new(
407 "STDEVP".to_string(),
408 vec![f.this],
409 )))),
410
411 Expression::Boolean(b) => {
413 let value = if b.value { 1 } else { 0 };
414 Ok(Expression::Literal(Box::new(
415 crate::expressions::Literal::Number(value.to_string()),
416 )))
417 }
418
419 Expression::Ln(f) => Ok(Expression::Function(Box::new(Function::new(
421 "LOG".to_string(),
422 vec![f.this],
423 )))),
424
425 Expression::CurrentDate(_) => Ok(Self::cast_getdate_to(DataType::Date)),
428
429 Expression::CurrentTime(_) => Ok(Self::cast_getdate_to(DataType::Time {
431 precision: None,
432 timezone: false,
433 })),
434
435 Expression::CurrentTimestamp(_) => Ok(Self::getdate()),
437
438 Expression::Localtimestamp(_) => Ok(Self::getdate()),
440
441 Expression::MakeDate(f) => Ok(Self::function(
443 "DATEFROMPARTS",
444 vec![f.year, f.month, f.day],
445 )),
446
447 Expression::DateDiff(f) => {
449 let unit_str = match f.unit {
451 Some(crate::expressions::IntervalUnit::Year) => "YEAR",
452 Some(crate::expressions::IntervalUnit::Quarter) => "QUARTER",
453 Some(crate::expressions::IntervalUnit::Month) => "MONTH",
454 Some(crate::expressions::IntervalUnit::Week) => "WEEK",
455 Some(crate::expressions::IntervalUnit::Day) => "DAY",
456 Some(crate::expressions::IntervalUnit::Hour) => "HOUR",
457 Some(crate::expressions::IntervalUnit::Minute) => "MINUTE",
458 Some(crate::expressions::IntervalUnit::Second) => "SECOND",
459 Some(crate::expressions::IntervalUnit::Millisecond) => "MILLISECOND",
460 Some(crate::expressions::IntervalUnit::Microsecond) => "MICROSECOND",
461 Some(crate::expressions::IntervalUnit::Nanosecond) => "NANOSECOND",
462 None => "DAY",
463 };
464 let unit = Expression::Identifier(crate::expressions::Identifier {
465 name: unit_str.to_string(),
466 quoted: false,
467 trailing_comments: Vec::new(),
468 span: None,
469 });
470 Ok(Expression::Function(Box::new(Function::new(
471 "DATEDIFF".to_string(),
472 vec![unit, f.expression, f.this], ))))
474 }
475
476 Expression::DateAdd(f) => {
478 let unit_str = match f.unit {
479 crate::expressions::IntervalUnit::Year => "YEAR",
480 crate::expressions::IntervalUnit::Quarter => "QUARTER",
481 crate::expressions::IntervalUnit::Month => "MONTH",
482 crate::expressions::IntervalUnit::Week => "WEEK",
483 crate::expressions::IntervalUnit::Day => "DAY",
484 crate::expressions::IntervalUnit::Hour => "HOUR",
485 crate::expressions::IntervalUnit::Minute => "MINUTE",
486 crate::expressions::IntervalUnit::Second => "SECOND",
487 crate::expressions::IntervalUnit::Millisecond => "MILLISECOND",
488 crate::expressions::IntervalUnit::Microsecond => "MICROSECOND",
489 crate::expressions::IntervalUnit::Nanosecond => "NANOSECOND",
490 };
491 let unit = Expression::Identifier(crate::expressions::Identifier {
492 name: unit_str.to_string(),
493 quoted: false,
494 trailing_comments: Vec::new(),
495 span: None,
496 });
497 Ok(Expression::Function(Box::new(Function::new(
498 "DATEADD".to_string(),
499 vec![unit, f.interval, f.this],
500 ))))
501 }
502
503 Expression::Uuid(_) => Ok(Expression::Function(Box::new(Function::new(
506 "NEWID".to_string(),
507 vec![],
508 )))),
509
510 Expression::IfFunc(f) => {
513 let false_val = f
514 .false_value
515 .unwrap_or(Expression::Null(crate::expressions::Null));
516 Ok(Expression::Function(Box::new(Function::new(
517 "IIF".to_string(),
518 vec![f.condition, f.true_value, false_val],
519 ))))
520 }
521
522 Expression::StringAgg(f) => Ok(Expression::StringAgg(f)),
525
526 Expression::LastDay(f) => Ok(Expression::Function(Box::new(Function::new(
528 "EOMONTH".to_string(),
529 vec![f.this.clone()],
530 )))),
531
532 Expression::Ceil(f) => Ok(Expression::Function(Box::new(Function::new(
534 "CEILING".to_string(),
535 vec![f.this],
536 )))),
537
538 Expression::Repeat(f) => Ok(Expression::Function(Box::new(Function::new(
540 "REPLICATE".to_string(),
541 vec![f.this, f.times],
542 )))),
543
544 Expression::Chr(f) => Ok(Expression::Function(Box::new(Function::new(
546 "CHAR".to_string(),
547 vec![f.this],
548 )))),
549
550 Expression::Overlay(f) => Ok(Self::overlay_to_stuff(*f)),
552
553 Expression::StartsWith(f) => Ok(Self::starts_with_predicate(f.this, f.expression)),
556
557 Expression::DecodeCase(mut f)
559 if f.expressions.len() == 2
560 && Self::literal_string(&f.expressions[1])
561 .is_some_and(|format| format.eq_ignore_ascii_case("hex")) =>
562 {
563 Ok(Self::tsql_convert(
564 DataType::Custom {
565 name: "VARBINARY(MAX)".to_string(),
566 },
567 f.expressions.remove(0),
568 Some(2),
569 ))
570 }
571
572 Expression::ToNumber(f) => Ok(Self::to_number_or_fallback(*f)),
575
576 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
579 "VARP".to_string(),
580 vec![f.this],
581 )))),
582
583 Expression::Variance(f) => Ok(Expression::Function(Box::new(Function::new(
585 "VAR".to_string(),
586 vec![f.this],
587 )))),
588 Expression::VarSamp(f) => Ok(Expression::Function(Box::new(Function::new(
589 "VAR".to_string(),
590 vec![f.this],
591 )))),
592
593 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
596 "HASHBYTES".to_string(),
597 vec![Expression::string("MD5"), *f.this],
598 )))),
599
600 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
602 "HASHBYTES".to_string(),
603 vec![Expression::string("SHA1"), f.this],
604 )))),
605
606 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
608 "HASHBYTES".to_string(),
609 vec![Expression::string("SHA1"), f.this],
610 )))),
611
612 Expression::ArrayToString(f) => Ok(Expression::Function(Box::new(Function::new(
615 "STRING_AGG".to_string(),
616 vec![f.this],
617 )))),
618
619 Expression::AutoIncrementColumnConstraint(_) => Ok(Expression::Function(Box::new(
622 Function::new("IDENTITY".to_string(), vec![]),
623 ))),
624
625 Expression::CreateView(mut view) => {
629 view.name.catalog = None;
631 Ok(Expression::CreateView(view))
632 }
633
634 Expression::DropView(mut view) => {
635 view.name.catalog = None;
637 Ok(Expression::DropView(view))
638 }
639
640 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
644 let path = match *e.expression {
645 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
646 let Literal::String(s) = lit.as_ref() else {
647 unreachable!()
648 };
649 let normalized = if s.starts_with('$') {
650 s.clone()
651 } else if s.starts_with('[') {
652 format!("${}", s)
653 } else {
654 format!("$.{}", s)
655 };
656 Expression::Literal(Box::new(Literal::String(normalized)))
657 }
658 other => other,
659 };
660 let json_query = Expression::Function(Box::new(Function::new(
661 "JSON_QUERY".to_string(),
662 vec![(*e.this).clone(), path.clone()],
663 )));
664 let json_value = Expression::Function(Box::new(Function::new(
665 "JSON_VALUE".to_string(),
666 vec![*e.this, path],
667 )));
668 Ok(Expression::Function(Box::new(Function::new(
669 "ISNULL".to_string(),
670 vec![json_query, json_value],
671 ))))
672 }
673
674 Expression::Function(f) => self.transform_function(*f),
676
677 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
679
680 Expression::Cte(cte) => self.transform_cte(*cte),
683
684 Expression::Subquery(subquery) => self.transform_subquery(*subquery),
687
688 Expression::JsonQuery(f) => {
690 let json_query = Expression::Function(Box::new(Function::new(
691 "JSON_QUERY".to_string(),
692 vec![f.this.clone(), f.path.clone()],
693 )));
694 let json_value = Expression::Function(Box::new(Function::new(
695 "JSON_VALUE".to_string(),
696 vec![f.this, f.path],
697 )));
698 Ok(Expression::Function(Box::new(Function::new(
699 "ISNULL".to_string(),
700 vec![json_query, json_value],
701 ))))
702 }
703 Expression::JsonValue(f) => Ok(Expression::Function(Box::new(Function::new(
705 "JSON_VALUE".to_string(),
706 vec![f.this, f.path],
707 )))),
708
709 Expression::Any(q) => {
713 Ok(Self::lower_scalar_array_quantifier(&q, true).unwrap_or(Expression::Any(q)))
714 }
715 Expression::All(q) => {
716 Ok(Self::lower_scalar_array_quantifier(&q, false).unwrap_or(Expression::All(q)))
717 }
718
719 _ => Ok(expr),
721 }
722 }
723}
724
725#[cfg(feature = "transpile")]
726impl TSQLDialect {
727 fn getdate() -> Expression {
728 Expression::Function(Box::new(Function::new("GETDATE".to_string(), vec![])))
729 }
730
731 fn cast_getdate_to(to: DataType) -> Expression {
732 Expression::Cast(Box::new(Cast {
733 this: Self::getdate(),
734 to,
735 trailing_comments: Vec::new(),
736 double_colon_syntax: false,
737 format: None,
738 default: None,
739 inferred_type: None,
740 }))
741 }
742
743 fn cast(this: Expression, to: DataType) -> Expression {
744 Expression::Cast(Box::new(Cast {
745 this,
746 to,
747 trailing_comments: Vec::new(),
748 double_colon_syntax: false,
749 format: None,
750 default: None,
751 inferred_type: None,
752 }))
753 }
754
755 fn function(name: impl Into<String>, args: Vec<Expression>) -> Expression {
756 Expression::Function(Box::new(Function::new(name, args)))
757 }
758
759 fn make_time(mut args: Vec<Expression>) -> Expression {
760 let seconds = args.pop().expect("MAKE_TIME has three arguments");
761 let minute = args.pop().expect("MAKE_TIME has three arguments");
762 let hour = args.pop().expect("MAKE_TIME has three arguments");
763
764 if let Some((whole_seconds, microseconds)) = Self::literal_time_parts(&seconds) {
765 let (fractions, precision) = if microseconds == 0 {
766 (Expression::number(0), Expression::number(0))
767 } else {
768 (Expression::number(microseconds), Expression::number(6))
769 };
770
771 return Self::function(
772 "TIMEFROMPARTS",
773 vec![
774 hour,
775 minute,
776 Expression::number(whole_seconds),
777 fractions,
778 precision,
779 ],
780 );
781 }
782
783 let rounded_microseconds = Self::cast(
787 Self::function(
788 "ROUND",
789 vec![
790 Expression::Mul(Box::new(BinaryOp::new(
791 seconds,
792 Expression::number(1_000_000),
793 ))),
794 Expression::number(0),
795 ],
796 ),
797 DataType::BigInt { length: None },
798 );
799
800 Self::function(
801 "TIMEFROMPARTS",
802 vec![
803 hour,
804 minute,
805 Expression::Div(Box::new(BinaryOp::new(
806 rounded_microseconds.clone(),
807 Expression::number(1_000_000),
808 ))),
809 Expression::Mod(Box::new(BinaryOp::new(
810 rounded_microseconds,
811 Expression::number(1_000_000),
812 ))),
813 Expression::number(6),
814 ],
815 )
816 }
817
818 fn literal_time_parts(expr: &Expression) -> Option<(i64, i64)> {
819 let value = match expr {
820 Expression::Literal(lit) => match lit.as_ref() {
821 Literal::Number(value) => value.parse::<f64>().ok()?,
822 _ => return None,
823 },
824 Expression::Paren(paren) => return Self::literal_time_parts(&paren.this),
825 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
826 if Self::is_numeric_data_type(&cast.to) =>
827 {
828 let parts = Self::literal_time_parts(&cast.this);
829 return match (&cast.to, parts) {
830 (_, Some((0, 0))) => Some((0, 0)),
834 (DataType::Float { .. } | DataType::Double { .. }, parts) => parts,
835 _ => None,
836 };
837 }
838 _ => return None,
839 };
840
841 if !value.is_finite() || value < 0.0 || value > i64::MAX as f64 / 1_000_000.0 {
842 return None;
843 }
844
845 let total_microseconds = (value * 1_000_000.0).round() as i64;
846 Some((
847 total_microseconds / 1_000_000,
848 total_microseconds % 1_000_000,
849 ))
850 }
851
852 fn lower(this: Expression) -> Expression {
853 Expression::Lower(Box::new(UnaryFunc::new(this)))
854 }
855
856 fn tsql_convert(to: DataType, expression: Expression, style: Option<i64>) -> Expression {
857 let mut args = vec![Expression::DataType(to), expression];
858 if let Some(style) = style {
859 args.push(Expression::number(style));
860 }
861 Self::function("CONVERT", args)
862 }
863
864 fn tsql_hex_text(expression: Expression, varchar_type: DataType) -> Expression {
865 Self::lower(Self::tsql_convert(varchar_type, expression, Some(2)))
866 }
867
868 fn tsql_hex_from_varbinary(expression: Expression) -> Expression {
869 Self::tsql_hex_text(
870 Self::cast(
871 expression,
872 DataType::Custom {
873 name: "VARBINARY(MAX)".to_string(),
874 },
875 ),
876 DataType::Text,
877 )
878 }
879
880 fn tsql_postgres_to_hex(expression: Expression) -> Expression {
881 let hex = Self::tsql_hex_from_varbinary(expression);
882 let without_leading_zeroes = Self::function("LTRIM", vec![hex, Expression::string("0")]);
883 let non_empty = Self::function(
884 "NULLIF",
885 vec![without_leading_zeroes, Expression::string("")],
886 );
887 Self::function("ISNULL", vec![non_empty, Expression::string("0")])
888 }
889
890 fn tsql_md5_hex(expression: Expression) -> Expression {
891 let hashbytes = Self::function("HASHBYTES", vec![Expression::string("MD5"), expression]);
892 Self::tsql_hex_text(
893 hashbytes,
894 DataType::VarChar {
895 length: Some(32),
896 parenthesized_length: false,
897 },
898 )
899 }
900
901 fn overlay_to_stuff(f: crate::expressions::OverlayFunc) -> Expression {
902 let length = f
903 .length
904 .unwrap_or_else(|| Self::function("LEN", vec![f.replacement.clone()]));
905 Self::function("STUFF", vec![f.this, f.from, length, f.replacement])
906 }
907
908 fn starts_with_predicate(this: Expression, prefix: Expression) -> Expression {
909 let prefix_len = Self::function("LEN", vec![prefix.clone()]);
910 let left_prefix = Self::function("LEFT", vec![this, prefix_len]);
911 Self::eq(left_prefix, prefix)
912 }
913
914 fn to_number_or_fallback(f: crate::expressions::ToNumber) -> Expression {
915 let crate::expressions::ToNumber {
916 this,
917 format,
918 nlsparam,
919 precision,
920 scale,
921 safe,
922 safe_name,
923 } = f;
924
925 if nlsparam.is_none()
926 && precision.is_none()
927 && scale.is_none()
928 && safe.is_none()
929 && safe_name.is_none()
930 {
931 if let Some(format) = format.as_deref() {
932 if let Some(scale) = Self::simple_to_number_scale(format) {
933 return Self::function(
934 "TRY_CONVERT",
935 vec![
936 Expression::DataType(DataType::Decimal {
937 precision: Some(18),
938 scale: Some(scale),
939 }),
940 *this,
941 ],
942 );
943 }
944 }
945 }
946
947 Expression::ToNumber(Box::new(crate::expressions::ToNumber {
948 this,
949 format,
950 nlsparam,
951 precision,
952 scale,
953 safe,
954 safe_name,
955 }))
956 }
957
958 fn simple_to_number_scale(format: &Expression) -> Option<u32> {
959 let format = Self::literal_string(format)?;
960 let format = format.strip_prefix("FM").unwrap_or(format);
961 let mut saw_digit = false;
962 let mut saw_decimal = false;
963 let mut scale = 0u32;
964
965 for ch in format.chars() {
966 match ch {
967 '9' | '0' => {
968 saw_digit = true;
969 if saw_decimal {
970 scale = scale.checked_add(1)?;
971 }
972 }
973 '.' if !saw_decimal => saw_decimal = true,
974 ',' | ' ' => return None,
977 _ => return None,
978 }
979 }
980
981 saw_digit.then_some(scale)
982 }
983
984 fn binary(
985 left: Expression,
986 right: Expression,
987 op: fn(Box<BinaryOp>) -> Expression,
988 ) -> Expression {
989 op(Box::new(BinaryOp {
990 left,
991 right,
992 left_comments: Vec::new(),
993 operator_comments: Vec::new(),
994 trailing_comments: Vec::new(),
995 inferred_type: None,
996 }))
997 }
998
999 fn eq(left: Expression, right: Expression) -> Expression {
1000 Self::binary(left, right, Expression::Eq)
1001 }
1002
1003 fn or(left: Expression, right: Expression) -> Expression {
1004 Self::binary(left, right, Expression::Or)
1005 }
1006
1007 fn not(this: Expression) -> Expression {
1008 Expression::Not(Box::new(crate::expressions::UnaryOp {
1009 this,
1010 inferred_type: None,
1011 }))
1012 }
1013
1014 fn is_null(this: Expression) -> Expression {
1015 Expression::IsNull(Box::new(crate::expressions::IsNull {
1016 this,
1017 not: false,
1018 postfix_form: false,
1019 }))
1020 }
1021
1022 fn paren(this: Expression) -> Expression {
1023 Expression::Paren(Box::new(Paren {
1024 this,
1025 trailing_comments: Vec::new(),
1026 }))
1027 }
1028
1029 fn boolean_test_case_for_predicate(
1030 predicate: Expression,
1031 test_true: bool,
1032 negated: bool,
1033 ) -> Expression {
1034 let condition = match (test_true, negated) {
1035 (true, false) => predicate,
1036 (false, false) => Self::not(predicate),
1037 (true, true) => {
1038 return Expression::Case(Box::new(crate::expressions::Case {
1039 operand: None,
1040 whens: vec![(predicate, Expression::number(0))],
1041 else_: Some(Expression::number(1)),
1042 comments: Vec::new(),
1043 inferred_type: None,
1044 }))
1045 }
1046 (false, true) => {
1047 return Expression::Case(Box::new(crate::expressions::Case {
1048 operand: None,
1049 whens: vec![(Self::not(predicate), Expression::number(0))],
1050 else_: Some(Expression::number(1)),
1051 comments: Vec::new(),
1052 inferred_type: None,
1053 }))
1054 }
1055 };
1056
1057 Expression::Case(Box::new(crate::expressions::Case {
1058 operand: None,
1059 whens: vec![(condition, Expression::number(1))],
1060 else_: Some(Expression::number(0)),
1061 comments: Vec::new(),
1062 inferred_type: None,
1063 }))
1064 }
1065
1066 fn boolean_test_predicate(operand: Expression, test_true: bool, negated: bool) -> Expression {
1067 if Self::is_boolean_predicate_operand(&operand) {
1068 return match (test_true, negated) {
1069 (true, false) => operand,
1070 (false, false) => Self::not(operand),
1071 _ => Self::eq(
1072 Self::boolean_test_case_for_predicate(operand, test_true, negated),
1073 Expression::number(1),
1074 ),
1075 };
1076 }
1077
1078 match (test_true, negated) {
1079 (true, false) => Self::eq(operand, Expression::number(1)),
1080 (false, false) => Self::eq(operand, Expression::number(0)),
1081 (true, true) => Self::or(
1082 Self::eq(operand.clone(), Expression::number(0)),
1083 Self::is_null(operand),
1084 ),
1085 (false, true) => Self::or(
1086 Self::eq(operand.clone(), Expression::number(1)),
1087 Self::is_null(operand),
1088 ),
1089 }
1090 }
1091
1092 fn is_boolean_predicate_operand(expr: &Expression) -> bool {
1093 match expr {
1094 Expression::Paren(paren) => Self::is_boolean_predicate_operand(&paren.this),
1095 Expression::Eq(_)
1096 | Expression::Neq(_)
1097 | Expression::Lt(_)
1098 | Expression::Lte(_)
1099 | Expression::Gt(_)
1100 | Expression::Gte(_)
1101 | Expression::Is(_)
1102 | Expression::IsNull(_)
1103 | Expression::IsTrue(_)
1104 | Expression::IsFalse(_)
1105 | Expression::Like(_)
1106 | Expression::ILike(_)
1107 | Expression::SimilarTo(_)
1108 | Expression::Glob(_)
1109 | Expression::RegexpLike(_)
1110 | Expression::In(_)
1111 | Expression::Between(_)
1112 | Expression::Exists(_)
1113 | Expression::And(_)
1114 | Expression::Or(_)
1115 | Expression::Not(_)
1116 | Expression::Any(_)
1117 | Expression::All(_)
1118 | Expression::EqualNull(_) => true,
1119 _ => false,
1120 }
1121 }
1122
1123 fn scalar_array_comparison_values(expr: &Expression) -> Option<Vec<Expression>> {
1124 let (mut values, element_type) = Self::scalar_array_comparison_values_inner(expr)?;
1125 if let Some(to) = element_type {
1126 values = values
1127 .into_iter()
1128 .map(|value| Self::cast_scalar_array_comparison_value(value, to.clone()))
1129 .collect();
1130 }
1131 Some(values)
1132 }
1133
1134 fn lower_scalar_array_quantifier(
1135 quantified: &QuantifiedExpr,
1136 is_any: bool,
1137 ) -> Option<Expression> {
1138 let op = quantified.op.as_ref()?;
1139 let expressions = Self::scalar_array_comparison_values(&quantified.subquery)?;
1140
1141 if expressions.is_empty() {
1142 return Some(Self::eq(
1143 Expression::number(1),
1144 Expression::number(if is_any { 0 } else { 1 }),
1145 ));
1146 }
1147
1148 if is_any && matches!(op, QuantifiedOp::Eq) {
1149 return Some(Self::in_list(quantified.this.clone(), expressions, false));
1150 }
1151
1152 if !is_any && matches!(op, QuantifiedOp::Neq) {
1153 return Some(Self::in_list(quantified.this.clone(), expressions, true));
1154 }
1155
1156 let mut comparisons = expressions
1157 .into_iter()
1158 .map(|expression| Self::quantified_comparison(quantified.this.clone(), expression, op));
1159 let first = comparisons.next()?;
1160 let combined = comparisons.fold(first, |left, right| {
1161 if is_any {
1162 Expression::Or(Box::new(BinaryOp::new(left, right)))
1163 } else {
1164 Expression::And(Box::new(BinaryOp::new(left, right)))
1165 }
1166 });
1167
1168 Some(Self::paren(combined))
1169 }
1170
1171 fn in_list(this: Expression, expressions: Vec<Expression>, not: bool) -> Expression {
1172 Expression::In(Box::new(In {
1173 this,
1174 expressions,
1175 query: None,
1176 not,
1177 global: false,
1178 unnest: None,
1179 is_field: false,
1180 }))
1181 }
1182
1183 fn quantified_comparison(left: Expression, right: Expression, op: &QuantifiedOp) -> Expression {
1184 let binary = Box::new(BinaryOp::new(left, right));
1185 match op {
1186 QuantifiedOp::Eq => Expression::Eq(binary),
1187 QuantifiedOp::Neq => Expression::Neq(binary),
1188 QuantifiedOp::Lt => Expression::Lt(binary),
1189 QuantifiedOp::Lte => Expression::Lte(binary),
1190 QuantifiedOp::Gt => Expression::Gt(binary),
1191 QuantifiedOp::Gte => Expression::Gte(binary),
1192 }
1193 }
1194
1195 fn scalar_array_comparison_values_inner(
1196 expr: &Expression,
1197 ) -> Option<(Vec<Expression>, Option<DataType>)> {
1198 match expr {
1199 Expression::ArrayFunc(a) => Some((a.expressions.clone(), None)),
1200 Expression::Array(a) => Some((a.expressions.clone(), None)),
1201 Expression::Tuple(t) => Some((t.expressions.clone(), None)),
1202 Expression::Paren(p) => Self::scalar_array_comparison_values_inner(&p.this),
1203 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
1204 let DataType::Array { element_type, .. } = &c.to else {
1205 return None;
1206 };
1207 let (values, _) = Self::scalar_array_comparison_values_inner(&c.this)?;
1208 Some((values, Some((**element_type).clone())))
1209 }
1210 _ => None,
1211 }
1212 }
1213
1214 fn cast_scalar_array_comparison_value(value: Expression, to: DataType) -> Expression {
1215 if matches!(&value, Expression::Cast(c) if c.to == to) {
1216 return value;
1217 }
1218
1219 Expression::Cast(Box::new(Cast {
1220 this: value,
1221 to,
1222 trailing_comments: Vec::new(),
1223 double_colon_syntax: false,
1224 format: None,
1225 default: None,
1226 inferred_type: None,
1227 }))
1228 }
1229
1230 fn normalize_frame_incompatible_window_functions(select: &mut Select) {
1231 let window_map: HashMap<String, Over> = select
1232 .windows
1233 .as_ref()
1234 .map(|windows| {
1235 windows
1236 .iter()
1237 .map(|window| (window.name.name.to_lowercase(), window.spec.clone()))
1238 .collect()
1239 })
1240 .unwrap_or_default();
1241
1242 for expr in &mut select.expressions {
1243 Self::normalize_frame_incompatible_window_expr(expr, &window_map);
1244 }
1245
1246 if let Some(order_by) = &mut select.order_by {
1247 for ordered in &mut order_by.expressions {
1248 Self::normalize_frame_incompatible_window_expr(&mut ordered.this, &window_map);
1249 }
1250 }
1251
1252 if let Some(qualify) = &mut select.qualify {
1253 Self::normalize_frame_incompatible_window_expr(&mut qualify.this, &window_map);
1254 }
1255 }
1256
1257 fn normalize_frame_incompatible_window_expr(
1258 expr: &mut Expression,
1259 window_map: &HashMap<String, Over>,
1260 ) {
1261 match expr {
1262 Expression::WindowFunction(wf) => {
1263 Self::normalize_frame_incompatible_window_expr(&mut wf.this, window_map);
1264
1265 if !Self::is_tsql_frame_incompatible_window_function(&wf.this) {
1266 return;
1267 }
1268
1269 wf.over.frame = None;
1270
1271 let Some(window_name) = wf.over.window_name.clone() else {
1272 return;
1273 };
1274 let Some(named_spec) =
1275 Self::resolve_named_window_spec(&window_name.name, window_map, &mut Vec::new())
1276 else {
1277 return;
1278 };
1279
1280 if named_spec.frame.is_none() {
1281 return;
1282 }
1283
1284 if wf.over.partition_by.is_empty() {
1285 wf.over.partition_by = named_spec.partition_by;
1286 }
1287 if wf.over.order_by.is_empty() {
1288 wf.over.order_by = named_spec.order_by;
1289 }
1290 wf.over.window_name = None;
1291 wf.over.frame = None;
1292 }
1293 Expression::Alias(alias) => {
1294 Self::normalize_frame_incompatible_window_expr(&mut alias.this, window_map);
1295 }
1296 Expression::Paren(paren) => {
1297 Self::normalize_frame_incompatible_window_expr(&mut paren.this, window_map);
1298 }
1299 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
1300 Self::normalize_frame_incompatible_window_expr(&mut cast.this, window_map);
1301 }
1302 Expression::Function(function) => {
1303 for arg in &mut function.args {
1304 Self::normalize_frame_incompatible_window_expr(arg, window_map);
1305 }
1306 }
1307 Expression::Case(case) => {
1308 if let Some(operand) = &mut case.operand {
1309 Self::normalize_frame_incompatible_window_expr(operand, window_map);
1310 }
1311 for (condition, result) in &mut case.whens {
1312 Self::normalize_frame_incompatible_window_expr(condition, window_map);
1313 Self::normalize_frame_incompatible_window_expr(result, window_map);
1314 }
1315 if let Some(else_expr) = &mut case.else_ {
1316 Self::normalize_frame_incompatible_window_expr(else_expr, window_map);
1317 }
1318 }
1319 Expression::And(op)
1320 | Expression::Or(op)
1321 | Expression::Add(op)
1322 | Expression::Sub(op)
1323 | Expression::Mul(op)
1324 | Expression::Div(op)
1325 | Expression::Mod(op)
1326 | Expression::Eq(op)
1327 | Expression::Neq(op)
1328 | Expression::Lt(op)
1329 | Expression::Lte(op)
1330 | Expression::Gt(op)
1331 | Expression::Gte(op)
1332 | Expression::Match(op)
1333 | Expression::BitwiseAnd(op)
1334 | Expression::BitwiseOr(op)
1335 | Expression::BitwiseXor(op)
1336 | Expression::Concat(op)
1337 | Expression::Adjacent(op)
1338 | Expression::TsMatch(op)
1339 | Expression::PropertyEQ(op)
1340 | Expression::ArrayContainsAll(op)
1341 | Expression::ArrayContainedBy(op)
1342 | Expression::ArrayOverlaps(op)
1343 | Expression::JSONBContainsAllTopKeys(op)
1344 | Expression::JSONBContainsAnyTopKeys(op)
1345 | Expression::JSONBDeleteAtPath(op)
1346 | Expression::ExtendsLeft(op)
1347 | Expression::ExtendsRight(op)
1348 | Expression::Is(op)
1349 | Expression::MemberOf(op) => {
1350 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
1351 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
1352 }
1353 Expression::Like(op) | Expression::ILike(op) => {
1354 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
1355 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
1356 if let Some(escape) = &mut op.escape {
1357 Self::normalize_frame_incompatible_window_expr(escape, window_map);
1358 }
1359 }
1360 Expression::Not(op) | Expression::Neg(op) | Expression::BitwiseNot(op) => {
1361 Self::normalize_frame_incompatible_window_expr(&mut op.this, window_map);
1362 }
1363 Expression::In(in_expr) => {
1364 Self::normalize_frame_incompatible_window_expr(&mut in_expr.this, window_map);
1365 for value in &mut in_expr.expressions {
1366 Self::normalize_frame_incompatible_window_expr(value, window_map);
1367 }
1368 }
1369 Expression::Between(between) => {
1370 Self::normalize_frame_incompatible_window_expr(&mut between.this, window_map);
1371 Self::normalize_frame_incompatible_window_expr(&mut between.low, window_map);
1372 Self::normalize_frame_incompatible_window_expr(&mut between.high, window_map);
1373 }
1374 Expression::IsNull(is_null) => {
1375 Self::normalize_frame_incompatible_window_expr(&mut is_null.this, window_map);
1376 }
1377 Expression::IsTrue(is_true) | Expression::IsFalse(is_true) => {
1378 Self::normalize_frame_incompatible_window_expr(&mut is_true.this, window_map);
1379 }
1380 _ => {}
1381 }
1382 }
1383
1384 fn is_tsql_frame_incompatible_window_function(expr: &Expression) -> bool {
1385 matches!(
1386 expr,
1387 Expression::RowNumber(_)
1388 | Expression::Rank(_)
1389 | Expression::DenseRank(_)
1390 | Expression::NTile(_)
1391 | Expression::Ntile(_)
1392 | Expression::Lead(_)
1393 | Expression::Lag(_)
1394 | Expression::PercentRank(_)
1395 | Expression::CumeDist(_)
1396 )
1397 }
1398
1399 fn resolve_named_window_spec(
1400 name: &str,
1401 window_map: &HashMap<String, Over>,
1402 seen: &mut Vec<String>,
1403 ) -> Option<Over> {
1404 let key = name.to_lowercase();
1405 if seen.iter().any(|seen_name| seen_name == &key) {
1406 return None;
1407 }
1408
1409 let named_spec = window_map.get(&key)?.clone();
1410 seen.push(key);
1411
1412 let mut resolved = if let Some(base_window) = &named_spec.window_name {
1413 Self::resolve_named_window_spec(&base_window.name, window_map, seen)
1414 .unwrap_or_else(Self::empty_over)
1415 } else {
1416 Self::empty_over()
1417 };
1418
1419 if !named_spec.partition_by.is_empty() {
1420 resolved.partition_by = named_spec.partition_by;
1421 }
1422 if !named_spec.order_by.is_empty() {
1423 resolved.order_by = named_spec.order_by;
1424 }
1425 if named_spec.frame.is_some() {
1426 resolved.frame = named_spec.frame;
1427 }
1428
1429 Some(resolved)
1430 }
1431
1432 fn empty_over() -> Over {
1433 Over {
1434 window_name: None,
1435 partition_by: Vec::new(),
1436 order_by: Vec::new(),
1437 frame: None,
1438 alias: None,
1439 }
1440 }
1441
1442 const LATERAL_WRAPPER_SOURCE_ALIAS: &'static str = "_polyglot_lateral_source";
1443 const LATERAL_WRAPPER_OUTPUT_ALIAS: &'static str = "_polyglot_lateral";
1444
1445 fn transform_lateral_join_to_apply(mut join: Join) -> Result<Join> {
1446 let Some(apply_kind) = Self::lateral_apply_kind(&join) else {
1447 return Ok(join);
1448 };
1449
1450 let original_alias = Self::table_expression_alias(&join.this);
1451 let on = join.on.take();
1452 let rhs = Self::remove_lateral_marker(join.this);
1453 join.this = if on
1454 .as_ref()
1455 .is_some_and(|expr| !Self::is_true_condition(expr))
1456 {
1457 Self::wrap_lateral_apply_rhs(rhs, on.expect("checked as Some"), original_alias)?
1458 } else {
1459 rhs
1460 };
1461 join.using.clear();
1462 join.kind = apply_kind;
1463 join.use_inner_keyword = false;
1464 join.use_outer_keyword = false;
1465 join.deferred_condition = false;
1466 join.join_hint = None;
1467 join.match_condition = None;
1468 join.directed = false;
1469 Ok(join)
1470 }
1471
1472 fn rewrite_comma_lateral_sources_to_joins(select: &mut Select) {
1473 let Some(from) = select.from.as_mut() else {
1474 return;
1475 };
1476 let has_comma_lateral = from
1477 .expressions
1478 .iter()
1479 .skip(1)
1480 .any(Self::is_lateral_table_expression);
1481 let has_apply_join = select
1482 .joins
1483 .iter()
1484 .any(|join| matches!(join.kind, JoinKind::CrossApply | JoinKind::OuterApply));
1485
1486 if from.expressions.len() < 2 || (!has_comma_lateral && !has_apply_join) {
1487 return;
1488 }
1489
1490 let mut expressions = std::mem::take(&mut from.expressions).into_iter();
1491 let Some(first) = expressions.next() else {
1492 return;
1493 };
1494 from.expressions = vec![first];
1495
1496 let mut joins = expressions
1497 .map(|source| {
1498 if Self::is_lateral_table_expression(&source) {
1499 Self::new_join(Self::remove_lateral_marker(source), JoinKind::CrossApply)
1500 } else {
1501 Self::new_join(source, JoinKind::Cross)
1502 }
1503 })
1504 .collect::<Vec<_>>();
1505 joins.append(&mut select.joins);
1506 select.joins = joins;
1507 }
1508
1509 fn new_join(this: Expression, kind: JoinKind) -> Join {
1510 Join {
1511 this,
1512 on: None,
1513 using: Vec::new(),
1514 kind,
1515 use_inner_keyword: false,
1516 use_outer_keyword: false,
1517 deferred_condition: false,
1518 join_hint: None,
1519 match_condition: None,
1520 pivots: Vec::new(),
1521 comments: Vec::new(),
1522 nesting_group: 0,
1523 directed: false,
1524 }
1525 }
1526
1527 fn lateral_apply_kind(join: &Join) -> Option<JoinKind> {
1528 if !join.using.is_empty() {
1529 return None;
1530 }
1531
1532 match join.kind {
1533 JoinKind::Lateral => Some(JoinKind::CrossApply),
1534 JoinKind::LeftLateral => Some(JoinKind::OuterApply),
1535 JoinKind::Cross | JoinKind::Inner | JoinKind::Implicit
1536 if Self::is_lateral_table_expression(&join.this) =>
1537 {
1538 Some(JoinKind::CrossApply)
1539 }
1540 JoinKind::Left if Self::is_lateral_table_expression(&join.this) => {
1541 Some(JoinKind::OuterApply)
1542 }
1543 _ => None,
1544 }
1545 }
1546
1547 fn is_true_condition(expr: &Expression) -> bool {
1548 match expr {
1549 Expression::Boolean(boolean) => boolean.value,
1550 Expression::Literal(lit) => {
1551 matches!(lit.as_ref(), Literal::Number(value) if value.trim() == "1")
1552 }
1553 Expression::Eq(op) => {
1554 Self::is_true_condition(&op.left) && Self::is_true_condition(&op.right)
1555 }
1556 Expression::Paren(paren) => Self::is_true_condition(&paren.this),
1557 _ => false,
1558 }
1559 }
1560
1561 fn table_expression_alias(expr: &Expression) -> Option<(Identifier, Vec<Identifier>)> {
1562 match expr {
1563 Expression::Subquery(subquery) => subquery
1564 .alias
1565 .clone()
1566 .map(|alias| (alias, subquery.column_aliases.clone())),
1567 Expression::Alias(alias) if !alias.alias.is_empty() => {
1568 Some((alias.alias.clone(), alias.column_aliases.clone()))
1569 }
1570 Expression::Lateral(lateral) => lateral.alias.as_ref().map(|alias| {
1571 (
1572 if lateral.alias_quoted {
1573 Identifier::quoted(alias)
1574 } else {
1575 Identifier::new(alias)
1576 },
1577 lateral
1578 .column_aliases
1579 .iter()
1580 .map(|column| Identifier::new(column.clone()))
1581 .collect(),
1582 )
1583 }),
1584 _ => None,
1585 }
1586 }
1587
1588 fn wrap_lateral_apply_rhs(
1589 rhs: Expression,
1590 predicate: Expression,
1591 original_alias: Option<(Identifier, Vec<Identifier>)>,
1592 ) -> Result<Expression> {
1593 let (outer_alias, column_aliases) = original_alias.unwrap_or_else(|| {
1594 (
1595 Identifier::new(Self::LATERAL_WRAPPER_OUTPUT_ALIAS),
1596 Vec::new(),
1597 )
1598 });
1599 let inner_alias = Identifier::new(Self::LATERAL_WRAPPER_SOURCE_ALIAS);
1600 let source =
1601 Self::with_table_expression_alias(rhs, inner_alias.clone(), column_aliases.clone());
1602 let predicate = Self::rewrite_column_qualifier(predicate, &outer_alias, &inner_alias)?;
1603
1604 let mut select = Select::new();
1605 select.expressions = vec![Expression::Star(Star {
1606 table: None,
1607 except: None,
1608 replace: None,
1609 rename: None,
1610 trailing_comments: Vec::new(),
1611 span: None,
1612 })];
1613 select.from = Some(crate::expressions::From {
1614 expressions: vec![source],
1615 });
1616 select.where_clause = Some(Where { this: predicate });
1617
1618 Ok(Expression::Subquery(Box::new(Subquery {
1619 this: Expression::Select(Box::new(select)),
1620 alias: Some(outer_alias),
1621 column_aliases,
1622 alias_explicit_as: true,
1623 alias_keyword: None,
1624 order_by: None,
1625 limit: None,
1626 offset: None,
1627 distribute_by: None,
1628 sort_by: None,
1629 cluster_by: None,
1630 lateral: false,
1631 modifiers_inside: false,
1632 trailing_comments: Vec::new(),
1633 inferred_type: None,
1634 })))
1635 }
1636
1637 fn with_table_expression_alias(
1638 expr: Expression,
1639 alias: Identifier,
1640 column_aliases: Vec<Identifier>,
1641 ) -> Expression {
1642 match expr {
1643 Expression::Subquery(mut subquery) => {
1644 subquery.alias = Some(alias);
1645 subquery.column_aliases = column_aliases;
1646 subquery.alias_explicit_as = true;
1647 subquery.alias_keyword = None;
1648 Expression::Subquery(subquery)
1649 }
1650 Expression::Alias(mut aliased) => {
1651 aliased.alias = alias;
1652 aliased.column_aliases = column_aliases;
1653 aliased.alias_explicit_as = true;
1654 aliased.alias_keyword = None;
1655 Expression::Alias(aliased)
1656 }
1657 Expression::Table(mut table) => {
1658 table.alias = Some(alias);
1659 table.alias_explicit_as = true;
1660 table.column_aliases = column_aliases;
1661 Expression::Table(table)
1662 }
1663 other => Expression::Alias(Box::new(Alias {
1664 this: other,
1665 alias,
1666 column_aliases,
1667 alias_explicit_as: true,
1668 alias_keyword: None,
1669 pre_alias_comments: Vec::new(),
1670 trailing_comments: Vec::new(),
1671 inferred_type: None,
1672 })),
1673 }
1674 }
1675
1676 fn rewrite_column_qualifier(
1677 expr: Expression,
1678 from: &Identifier,
1679 to: &Identifier,
1680 ) -> Result<Expression> {
1681 super::transform_recursive(expr, &|expr| {
1682 Ok(match expr {
1683 Expression::Column(mut column)
1684 if column
1685 .table
1686 .as_ref()
1687 .is_some_and(|table| Self::same_identifier(table, from)) =>
1688 {
1689 column.table = Some(to.clone());
1690 Expression::Column(column)
1691 }
1692 other => other,
1693 })
1694 })
1695 }
1696
1697 fn same_identifier(left: &Identifier, right: &Identifier) -> bool {
1698 if left.quoted || right.quoted {
1699 left.quoted == right.quoted && left.name == right.name
1700 } else {
1701 left.name.eq_ignore_ascii_case(&right.name)
1702 }
1703 }
1704
1705 fn is_lateral_table_expression(expr: &Expression) -> bool {
1706 match expr {
1707 Expression::Subquery(subquery) => subquery.lateral,
1708 Expression::Lateral(_) => true,
1709 Expression::Alias(alias) => Self::is_lateral_table_expression(&alias.this),
1710 _ => false,
1711 }
1712 }
1713
1714 fn remove_lateral_marker(expr: Expression) -> Expression {
1715 match expr {
1716 Expression::Subquery(mut subquery) => {
1717 subquery.lateral = false;
1718 Expression::Subquery(subquery)
1719 }
1720 Expression::Lateral(lateral) => Self::lateral_to_table_expression(*lateral),
1721 Expression::Alias(mut alias) => {
1722 alias.this = Self::remove_lateral_marker(alias.this);
1723 Expression::Alias(alias)
1724 }
1725 other => other,
1726 }
1727 }
1728
1729 fn lateral_to_table_expression(lateral: crate::expressions::Lateral) -> Expression {
1730 let expr = *lateral.this;
1731 let Some(alias) = lateral.alias else {
1732 return expr;
1733 };
1734
1735 Expression::Alias(Box::new(Alias {
1736 this: expr,
1737 alias: if lateral.alias_quoted {
1738 Identifier::quoted(alias)
1739 } else {
1740 Identifier::new(alias)
1741 },
1742 column_aliases: lateral
1743 .column_aliases
1744 .into_iter()
1745 .map(Identifier::new)
1746 .collect(),
1747 alias_explicit_as: true,
1748 alias_keyword: None,
1749 pre_alias_comments: Vec::new(),
1750 trailing_comments: Vec::new(),
1751 inferred_type: None,
1752 }))
1753 }
1754
1755 fn rewrite_tuple_in_subquery_predicates(
1756 expr: Expression,
1757 outer_qualifier: Option<&Identifier>,
1758 under_not: bool,
1759 ) -> Expression {
1760 match expr {
1761 Expression::In(in_expr) if !under_not => {
1762 let in_expr = *in_expr;
1763 Self::tuple_in_subquery_to_exists(&in_expr, outer_qualifier, in_expr.not)
1764 .unwrap_or_else(|| Expression::In(Box::new(in_expr)))
1765 }
1766 Expression::Eq(op) if !under_not => {
1767 let op = *op;
1768 Self::tuple_subquery_eq_to_exists(&op, outer_qualifier)
1769 .unwrap_or_else(|| Expression::Eq(Box::new(op)))
1770 }
1771 Expression::And(mut op) => {
1772 op.left =
1773 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1774 op.right = Self::rewrite_tuple_in_subquery_predicates(
1775 op.right,
1776 outer_qualifier,
1777 under_not,
1778 );
1779 Expression::And(op)
1780 }
1781 Expression::Or(mut op) => {
1782 op.left =
1783 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1784 op.right = Self::rewrite_tuple_in_subquery_predicates(
1785 op.right,
1786 outer_qualifier,
1787 under_not,
1788 );
1789 Expression::Or(op)
1790 }
1791 Expression::Paren(mut paren) => {
1792 paren.this = Self::rewrite_tuple_in_subquery_predicates(
1793 paren.this,
1794 outer_qualifier,
1795 under_not,
1796 );
1797 Expression::Paren(paren)
1798 }
1799 Expression::Not(mut not) => {
1800 if let Some(rewritten) = Self::direct_tuple_subquery_predicate_to_exists(
1801 ¬.this,
1802 outer_qualifier,
1803 true,
1804 ) {
1805 rewritten
1806 } else {
1807 not.this =
1808 Self::rewrite_tuple_in_subquery_predicates(not.this, outer_qualifier, true);
1809 Expression::Not(not)
1810 }
1811 }
1812 Expression::Alias(mut alias) => {
1813 alias.this = Self::rewrite_tuple_in_subquery_predicates(
1814 alias.this,
1815 outer_qualifier,
1816 under_not,
1817 );
1818 Expression::Alias(alias)
1819 }
1820 Expression::Cast(mut cast) => {
1821 cast.this = Self::rewrite_tuple_in_subquery_predicates(
1822 cast.this,
1823 outer_qualifier,
1824 under_not,
1825 );
1826 if let Some(format) = cast.format.take() {
1827 cast.format = Some(Box::new(Self::rewrite_tuple_in_subquery_predicates(
1828 *format,
1829 outer_qualifier,
1830 under_not,
1831 )));
1832 }
1833 if let Some(default) = cast.default.take() {
1834 cast.default = Some(Box::new(Self::rewrite_tuple_in_subquery_predicates(
1835 *default,
1836 outer_qualifier,
1837 under_not,
1838 )));
1839 }
1840 Expression::Cast(cast)
1841 }
1842 Expression::TryCast(mut cast) => {
1843 cast.this = Self::rewrite_tuple_in_subquery_predicates(
1844 cast.this,
1845 outer_qualifier,
1846 under_not,
1847 );
1848 Expression::TryCast(cast)
1849 }
1850 Expression::SafeCast(mut cast) => {
1851 cast.this = Self::rewrite_tuple_in_subquery_predicates(
1852 cast.this,
1853 outer_qualifier,
1854 under_not,
1855 );
1856 Expression::SafeCast(cast)
1857 }
1858 Expression::Case(mut case) => {
1859 if let Some(operand) = case.operand.take() {
1860 case.operand = Some(Self::rewrite_tuple_in_subquery_predicates(
1861 operand,
1862 outer_qualifier,
1863 under_not,
1864 ));
1865 }
1866 case.whens = case
1867 .whens
1868 .into_iter()
1869 .map(|(condition, result)| {
1870 (
1871 Self::rewrite_tuple_in_subquery_predicates(
1872 condition,
1873 outer_qualifier,
1874 false,
1875 ),
1876 Self::rewrite_tuple_in_subquery_predicates(
1877 result,
1878 outer_qualifier,
1879 under_not,
1880 ),
1881 )
1882 })
1883 .collect();
1884 if let Some(else_) = case.else_.take() {
1885 case.else_ = Some(Self::rewrite_tuple_in_subquery_predicates(
1886 else_,
1887 outer_qualifier,
1888 under_not,
1889 ));
1890 }
1891 Expression::Case(case)
1892 }
1893 Expression::IfFunc(mut if_func) => {
1894 if_func.condition = Self::rewrite_tuple_in_subquery_predicates(
1895 if_func.condition,
1896 outer_qualifier,
1897 false,
1898 );
1899 if_func.true_value = Self::rewrite_tuple_in_subquery_predicates(
1900 if_func.true_value,
1901 outer_qualifier,
1902 under_not,
1903 );
1904 if let Some(false_value) = if_func.false_value.take() {
1905 if_func.false_value = Some(Self::rewrite_tuple_in_subquery_predicates(
1906 false_value,
1907 outer_qualifier,
1908 under_not,
1909 ));
1910 }
1911 Expression::IfFunc(if_func)
1912 }
1913 other => other,
1914 }
1915 }
1916
1917 fn direct_tuple_subquery_predicate_to_exists(
1918 expr: &Expression,
1919 outer_qualifier: Option<&Identifier>,
1920 negated: bool,
1921 ) -> Option<Expression> {
1922 match expr {
1923 Expression::In(in_expr) => {
1924 Self::tuple_in_subquery_to_exists(in_expr, outer_qualifier, negated ^ in_expr.not)
1925 }
1926 Expression::Paren(paren) => Self::direct_tuple_subquery_predicate_to_exists(
1927 &paren.this,
1928 outer_qualifier,
1929 negated,
1930 ),
1931 _ => None,
1932 }
1933 }
1934
1935 fn tuple_in_subquery_to_exists(
1936 in_expr: &In,
1937 outer_qualifier: Option<&Identifier>,
1938 negated: bool,
1939 ) -> Option<Expression> {
1940 if in_expr.unnest.is_some() {
1941 return None;
1942 }
1943
1944 let left_expressions = Self::tuple_expressions(&in_expr.this)?;
1945 let mut select = Self::select_from_in_rhs(in_expr)?;
1946
1947 if left_expressions.len() != select.expressions.len() || left_expressions.is_empty() {
1948 return None;
1949 }
1950
1951 let inner_qualifier = Self::single_select_source_qualifier(&select);
1952 let mut predicates = Vec::with_capacity(left_expressions.len() + 1);
1953 for (projection, left) in select
1954 .expressions
1955 .iter()
1956 .cloned()
1957 .zip(left_expressions.iter().cloned())
1958 {
1959 let inner = Self::tuple_in_projection_expr(projection, inner_qualifier.as_ref())?;
1960 let outer = Self::qualify_tuple_operand(left, outer_qualifier);
1961 predicates.push(if negated {
1962 Self::tuple_component_may_match(inner, outer)
1963 } else {
1964 Expression::Eq(Box::new(BinaryOp::new(inner, outer)))
1965 });
1966 }
1967
1968 if let Some(where_clause) = select.where_clause.take() {
1969 predicates.push(where_clause.this);
1970 }
1971
1972 select.expressions = vec![Expression::number(1)];
1973 select.where_clause = Some(Where {
1974 this: Self::and_all(predicates)?,
1975 });
1976
1977 Some(Expression::Exists(Box::new(Exists {
1978 this: Expression::Select(Box::new(select)),
1979 not: negated,
1980 })))
1981 }
1982
1983 fn tuple_subquery_eq_to_exists(
1984 op: &BinaryOp,
1985 outer_qualifier: Option<&Identifier>,
1986 ) -> Option<Expression> {
1987 if let Some((tuple_expr, query_expr)) = Self::tuple_and_query_operands(&op.left, &op.right)
1988 {
1989 return Self::tuple_subquery_eq_to_exists_inner(
1990 tuple_expr,
1991 query_expr,
1992 outer_qualifier,
1993 );
1994 }
1995
1996 if let Some((tuple_expr, query_expr)) = Self::tuple_and_query_operands(&op.right, &op.left)
1997 {
1998 return Self::tuple_subquery_eq_to_exists_inner(
1999 tuple_expr,
2000 query_expr,
2001 outer_qualifier,
2002 );
2003 }
2004
2005 None
2006 }
2007
2008 fn tuple_subquery_eq_to_exists_inner(
2009 tuple_expr: &Expression,
2010 query_expr: &Expression,
2011 outer_qualifier: Option<&Identifier>,
2012 ) -> Option<Expression> {
2013 let tuple_expressions = Self::tuple_expressions(tuple_expr)?;
2014 let mut select = Self::select_from_query_expression(query_expr)?;
2015
2016 if tuple_expressions.len() != select.expressions.len() || tuple_expressions.is_empty() {
2017 return None;
2018 }
2019
2020 let inner_qualifier = Self::single_select_source_qualifier(&select);
2021 let mut predicates = Vec::with_capacity(tuple_expressions.len() + 1);
2022 for (projection, tuple_operand) in select
2023 .expressions
2024 .iter()
2025 .cloned()
2026 .zip(tuple_expressions.iter().cloned())
2027 {
2028 let inner = Self::tuple_in_projection_expr(projection, inner_qualifier.as_ref())?;
2029 let outer = Self::qualify_tuple_operand(tuple_operand, outer_qualifier);
2030 predicates.push(Expression::Eq(Box::new(BinaryOp::new(inner, outer))));
2031 }
2032
2033 if let Some(where_clause) = select.where_clause.take() {
2034 predicates.push(where_clause.this);
2035 }
2036
2037 select.expressions = vec![Expression::number(1)];
2038 select.where_clause = Some(Where {
2039 this: Self::and_all(predicates)?,
2040 });
2041
2042 Some(Expression::Exists(Box::new(Exists {
2043 this: Expression::Select(Box::new(select)),
2044 not: false,
2045 })))
2046 }
2047
2048 fn tuple_and_query_operands<'a>(
2049 tuple_candidate: &'a Expression,
2050 query_candidate: &'a Expression,
2051 ) -> Option<(&'a Expression, &'a Expression)> {
2052 if Self::tuple_expressions(tuple_candidate).is_some()
2053 && Self::select_from_query_expression(query_candidate).is_some()
2054 {
2055 Some((tuple_candidate, query_candidate))
2056 } else {
2057 None
2058 }
2059 }
2060
2061 fn select_from_query_expression(expr: &Expression) -> Option<Select> {
2062 match expr {
2063 Expression::Select(select) => Some((**select).clone()),
2064 Expression::Subquery(subquery) => Self::select_from_query_expression(&subquery.this),
2065 Expression::Paren(paren) => Self::select_from_query_expression(&paren.this),
2066 _ => None,
2067 }
2068 }
2069
2070 fn select_from_in_rhs(in_expr: &In) -> Option<Select> {
2071 if let Some(values) = Self::values_from_in_rhs(in_expr) {
2072 return Self::select_from_values(&values);
2073 }
2074
2075 if let Some(query) = &in_expr.query {
2076 return if in_expr.expressions.is_empty() {
2077 Self::select_from_query_expression(query)
2078 } else {
2079 None
2080 };
2081 }
2082
2083 if in_expr.expressions.len() == 1 {
2084 Self::select_from_query_expression(&in_expr.expressions[0])
2085 } else {
2086 None
2087 }
2088 }
2089
2090 fn values_from_in_rhs(in_expr: &In) -> Option<Values> {
2091 if let Some(query) = &in_expr.query {
2092 return if in_expr.expressions.is_empty() {
2093 Self::values_from_expression(query)
2094 } else {
2095 None
2096 };
2097 }
2098
2099 if in_expr.expressions.len() == 1 {
2100 if let Some(values) = Self::values_from_expression(&in_expr.expressions[0]) {
2101 return Some(values);
2102 }
2103 }
2104
2105 let Expression::Function(first_row) = in_expr.expressions.first()? else {
2107 return None;
2108 };
2109 if !first_row.name.eq_ignore_ascii_case("VALUES") {
2110 return None;
2111 }
2112
2113 let mut rows = Vec::with_capacity(in_expr.expressions.len());
2114 rows.push(Tuple {
2115 expressions: first_row.args.clone(),
2116 });
2117 for row in &in_expr.expressions[1..] {
2118 rows.push(Self::tuple_from_values_row(row)?);
2119 }
2120
2121 Some(Values {
2122 expressions: rows,
2123 alias: None,
2124 column_aliases: Vec::new(),
2125 })
2126 }
2127
2128 fn values_from_expression(expr: &Expression) -> Option<Values> {
2129 match expr {
2130 Expression::Values(values) => Some((**values).clone()),
2131 Expression::Paren(paren) => Self::values_from_expression(&paren.this),
2132 Expression::Subquery(subquery) => Self::values_from_expression(&subquery.this),
2133 _ => None,
2134 }
2135 }
2136
2137 fn tuple_from_values_row(expr: &Expression) -> Option<Tuple> {
2138 match expr {
2139 Expression::Tuple(tuple) => Some((**tuple).clone()),
2140 Expression::Paren(paren) => match &paren.this {
2141 Expression::Tuple(tuple) => Some((**tuple).clone()),
2142 other => Some(Tuple {
2143 expressions: vec![other.clone()],
2144 }),
2145 },
2146 _ => None,
2147 }
2148 }
2149
2150 fn select_from_values(values: &Values) -> Option<Select> {
2151 let column_count = values.expressions.first()?.expressions.len();
2152 if column_count == 0
2153 || values
2154 .expressions
2155 .iter()
2156 .any(|row| row.expressions.len() != column_count)
2157 {
2158 return None;
2159 }
2160
2161 let source_alias = Identifier::new("_polyglot_values");
2162 let column_aliases = (1..=column_count)
2163 .map(|index| Identifier::new(format!("_polyglot_value_{index}")))
2164 .collect::<Vec<_>>();
2165 let projections = column_aliases
2166 .iter()
2167 .cloned()
2168 .map(|column| Self::column_from_identifier(column, Some(source_alias.clone())))
2169 .collect();
2170
2171 let mut source_values = values.clone();
2172 source_values.alias = None;
2173 source_values.column_aliases.clear();
2174
2175 let source = Expression::Subquery(Box::new(Subquery {
2176 this: Expression::Values(Box::new(source_values)),
2177 alias: Some(source_alias),
2178 column_aliases,
2179 alias_explicit_as: true,
2180 alias_keyword: None,
2181 order_by: None,
2182 limit: None,
2183 offset: None,
2184 distribute_by: None,
2185 sort_by: None,
2186 cluster_by: None,
2187 lateral: false,
2188 modifiers_inside: false,
2189 trailing_comments: Vec::new(),
2190 inferred_type: None,
2191 }));
2192
2193 let mut select = Select::new();
2194 select.expressions = projections;
2195 select.from = Some(From {
2196 expressions: vec![source],
2197 });
2198 Some(select)
2199 }
2200
2201 fn tuple_expressions(expr: &Expression) -> Option<&[Expression]> {
2202 match expr {
2203 Expression::Tuple(tuple) => Some(&tuple.expressions),
2204 Expression::Function(function) if function.name.eq_ignore_ascii_case("ROW") => {
2205 Some(&function.args)
2206 }
2207 Expression::Paren(paren) => Self::tuple_expressions(&paren.this),
2208 _ => None,
2209 }
2210 }
2211
2212 fn tuple_in_projection_expr(
2213 expr: Expression,
2214 qualifier: Option<&Identifier>,
2215 ) -> Option<Expression> {
2216 match expr {
2217 Expression::Alias(alias) => Self::tuple_in_projection_expr(alias.this, qualifier),
2218 Expression::Column(mut column) => {
2219 if column.table.is_none() {
2220 column.table = qualifier.cloned();
2221 }
2222 Some(Expression::Column(column))
2223 }
2224 Expression::Identifier(identifier) => {
2225 Some(Self::column_from_identifier(identifier, qualifier.cloned()))
2226 }
2227 Expression::Dot(_) => Some(expr),
2228 other => Some(Self::qualify_tuple_expression(other, qualifier)),
2229 }
2230 }
2231
2232 fn qualify_tuple_operand(expr: Expression, qualifier: Option<&Identifier>) -> Expression {
2233 Self::qualify_tuple_expression(expr, qualifier)
2234 }
2235
2236 fn qualify_tuple_expression(expr: Expression, qualifier: Option<&Identifier>) -> Expression {
2237 match expr {
2238 Expression::Column(mut column) => {
2239 if column.table.is_none() {
2240 column.table = qualifier.cloned();
2241 }
2242 Expression::Column(column)
2243 }
2244 Expression::Identifier(identifier) => {
2245 Self::column_from_identifier(identifier, qualifier.cloned())
2246 }
2247 Expression::Alias(mut alias) => {
2248 alias.this = Self::qualify_tuple_expression(alias.this, qualifier);
2249 Expression::Alias(alias)
2250 }
2251 Expression::Paren(mut paren) => {
2252 paren.this = Self::qualify_tuple_expression(paren.this, qualifier);
2253 Expression::Paren(paren)
2254 }
2255 Expression::Cast(mut cast) => {
2256 cast.this = Self::qualify_tuple_expression(cast.this, qualifier);
2257 if let Some(format) = cast.format.take() {
2258 cast.format =
2259 Some(Box::new(Self::qualify_tuple_expression(*format, qualifier)));
2260 }
2261 if let Some(default) = cast.default.take() {
2262 cast.default = Some(Box::new(Self::qualify_tuple_expression(
2263 *default, qualifier,
2264 )));
2265 }
2266 Expression::Cast(cast)
2267 }
2268 Expression::TryCast(mut cast) => {
2269 cast.this = Self::qualify_tuple_expression(cast.this, qualifier);
2270 Expression::TryCast(cast)
2271 }
2272 Expression::SafeCast(mut cast) => {
2273 cast.this = Self::qualify_tuple_expression(cast.this, qualifier);
2274 Expression::SafeCast(cast)
2275 }
2276 Expression::Function(mut function) => {
2277 function.args = function
2278 .args
2279 .into_iter()
2280 .map(|arg| Self::qualify_tuple_expression(arg, qualifier))
2281 .collect();
2282 Expression::Function(function)
2283 }
2284 Expression::Add(mut op) => {
2285 op.left = Self::qualify_tuple_expression(op.left, qualifier);
2286 op.right = Self::qualify_tuple_expression(op.right, qualifier);
2287 Expression::Add(op)
2288 }
2289 Expression::Sub(mut op) => {
2290 op.left = Self::qualify_tuple_expression(op.left, qualifier);
2291 op.right = Self::qualify_tuple_expression(op.right, qualifier);
2292 Expression::Sub(op)
2293 }
2294 Expression::Mul(mut op) => {
2295 op.left = Self::qualify_tuple_expression(op.left, qualifier);
2296 op.right = Self::qualify_tuple_expression(op.right, qualifier);
2297 Expression::Mul(op)
2298 }
2299 Expression::Div(mut op) => {
2300 op.left = Self::qualify_tuple_expression(op.left, qualifier);
2301 op.right = Self::qualify_tuple_expression(op.right, qualifier);
2302 Expression::Div(op)
2303 }
2304 Expression::Mod(mut op) => {
2305 op.left = Self::qualify_tuple_expression(op.left, qualifier);
2306 op.right = Self::qualify_tuple_expression(op.right, qualifier);
2307 Expression::Mod(op)
2308 }
2309 other => other,
2310 }
2311 }
2312
2313 fn tuple_component_may_match(inner: Expression, outer: Expression) -> Expression {
2314 Self::paren(
2315 Self::or_all(vec![
2316 Expression::Eq(Box::new(BinaryOp::new(inner.clone(), outer.clone()))),
2317 Self::is_null(inner),
2318 Self::is_null(outer),
2319 ])
2320 .expect("tuple component match condition is non-empty"),
2321 )
2322 }
2323
2324 fn column_from_identifier(identifier: Identifier, table: Option<Identifier>) -> Expression {
2325 Expression::Column(Box::new(Column {
2326 name: identifier,
2327 table,
2328 join_mark: false,
2329 trailing_comments: Vec::new(),
2330 span: None,
2331 inferred_type: None,
2332 }))
2333 }
2334
2335 fn single_select_source_qualifier(select: &Select) -> Option<Identifier> {
2336 if !select.joins.is_empty() {
2337 return None;
2338 }
2339
2340 let from = select.from.as_ref()?;
2341 if from.expressions.len() != 1 {
2342 return None;
2343 }
2344
2345 Self::source_qualifier(&from.expressions[0])
2346 }
2347
2348 fn source_qualifier(source: &Expression) -> Option<Identifier> {
2349 match source {
2350 Expression::Table(table) => table.alias.clone().or_else(|| Some(table.name.clone())),
2351 Expression::Subquery(subquery) => subquery.alias.clone(),
2352 _ => None,
2353 }
2354 }
2355
2356 fn and_all(mut predicates: Vec<Expression>) -> Option<Expression> {
2357 if predicates.is_empty() {
2358 return None;
2359 }
2360
2361 let first = predicates.remove(0);
2362 Some(predicates.into_iter().fold(first, |left, right| {
2363 Expression::And(Box::new(BinaryOp::new(left, right)))
2364 }))
2365 }
2366
2367 fn or_all(mut predicates: Vec<Expression>) -> Option<Expression> {
2368 if predicates.is_empty() {
2369 return None;
2370 }
2371
2372 let first = predicates.remove(0);
2373 Some(predicates.into_iter().fold(first, |left, right| {
2374 Expression::Or(Box::new(BinaryOp::new(left, right)))
2375 }))
2376 }
2377
2378 pub(super) fn transform_data_type(
2380 &self,
2381 dt: crate::expressions::DataType,
2382 ) -> Result<Expression> {
2383 use crate::expressions::DataType;
2384 let transformed = match dt {
2385 DataType::Boolean => DataType::Custom {
2387 name: "BIT".to_string(),
2388 },
2389 DataType::Int { .. } => dt,
2391 DataType::Decimal { precision, scale } => DataType::Custom {
2394 name: if let (Some(p), Some(s)) = (&precision, &scale) {
2395 format!("NUMERIC({}, {})", p, s)
2396 } else if let Some(p) = &precision {
2397 format!("NUMERIC({})", p)
2398 } else {
2399 "NUMERIC".to_string()
2400 },
2401 },
2402 DataType::Text => DataType::Custom {
2404 name: "VARCHAR(MAX)".to_string(),
2405 },
2406 DataType::Timestamp { .. } => DataType::Custom {
2408 name: "DATETIME2".to_string(),
2409 },
2410 DataType::Uuid => DataType::Custom {
2412 name: "UNIQUEIDENTIFIER".to_string(),
2413 },
2414 DataType::Custom { ref name } => {
2416 let upper = name.trim().to_uppercase();
2417 let (base_name, precision, _scale) = Self::parse_type_precision_and_scale(&upper);
2418 match base_name.as_str() {
2419 "DOUBLE PRECISION" => DataType::Custom {
2421 name: "FLOAT".to_string(),
2422 },
2423 "BPCHAR" => {
2425 if let Some(len) = precision {
2426 DataType::Char { length: Some(len) }
2427 } else {
2428 DataType::Char { length: None }
2429 }
2430 }
2431 _ => dt,
2432 }
2433 }
2434 other => other,
2436 };
2437 Ok(Expression::DataType(transformed))
2438 }
2439
2440 pub(super) fn parse_type_precision_and_scale(name: &str) -> (String, Option<u32>, Option<u32>) {
2442 if let Some(paren_pos) = name.find('(') {
2443 let base = name[..paren_pos].to_string();
2444 let rest = &name[paren_pos + 1..];
2445 if let Some(close_pos) = rest.find(')') {
2446 let args = &rest[..close_pos];
2447 let parts: Vec<&str> = args.split(',').map(|s| s.trim()).collect();
2448 let precision = parts.first().and_then(|s| s.parse::<u32>().ok());
2449 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
2450 return (base, precision, scale);
2451 }
2452 (base, None, None)
2453 } else {
2454 (name.to_string(), None, None)
2455 }
2456 }
2457
2458 fn transform_logical_aggregate(
2459 condition: Expression,
2460 filter: Option<Expression>,
2461 aggregate_name: &str,
2462 ) -> Result<Expression> {
2463 let false_condition = Expression::Not(Box::new(crate::expressions::UnaryOp {
2464 this: condition.clone(),
2465 inferred_type: None,
2466 }));
2467 let true_condition = Self::apply_aggregate_filter(condition, filter.clone());
2468 let false_condition = Self::apply_aggregate_filter(false_condition, filter);
2469
2470 let case_expr = Expression::Case(Box::new(crate::expressions::Case {
2471 operand: None,
2472 whens: vec![
2473 (true_condition, Expression::number(1)),
2474 (false_condition, Expression::number(0)),
2475 ],
2476 else_: Some(Expression::null()),
2477 comments: Vec::new(),
2478 inferred_type: None,
2479 }));
2480
2481 let case_expr = crate::transforms::ensure_bools(case_expr)?;
2482 let aggregate = Expression::Function(Box::new(Function::new(
2483 aggregate_name.to_string(),
2484 vec![case_expr],
2485 )));
2486
2487 Ok(Expression::Cast(Box::new(Cast {
2488 this: aggregate,
2489 to: DataType::Custom {
2490 name: "BIT".to_string(),
2491 },
2492 trailing_comments: Vec::new(),
2493 double_colon_syntax: false,
2494 format: None,
2495 default: None,
2496 inferred_type: None,
2497 })))
2498 }
2499
2500 fn reassociate_logical_aggregate_window(mut window: WindowFunction) -> Expression {
2501 let Expression::Cast(mut cast) = window.this else {
2502 return Expression::WindowFunction(Box::new(window));
2503 };
2504
2505 if !Self::is_transformed_logical_aggregate_cast(&cast) {
2506 window.this = Expression::Cast(cast);
2507 return Expression::WindowFunction(Box::new(window));
2508 }
2509
2510 window.this = cast.this;
2511 cast.this = Expression::WindowFunction(Box::new(window));
2512 Expression::Cast(cast)
2513 }
2514
2515 fn is_transformed_logical_aggregate_cast(cast: &Cast) -> bool {
2516 if !matches!(
2517 &cast.to,
2518 DataType::Custom { name } if name.eq_ignore_ascii_case("BIT")
2519 ) {
2520 return false;
2521 }
2522
2523 let Expression::Function(function) = &cast.this else {
2524 return false;
2525 };
2526 if !matches!(function.name.to_ascii_uppercase().as_str(), "MIN" | "MAX")
2527 || function.args.len() != 1
2528 {
2529 return false;
2530 }
2531
2532 matches!(
2533 function.args.first(),
2534 Some(Expression::Case(case))
2535 if case.operand.is_none()
2536 && case.whens.len() == 2
2537 && matches!(case.else_.as_ref(), Some(Expression::Null(_)))
2538 )
2539 }
2540
2541 fn apply_aggregate_filter(condition: Expression, filter: Option<Expression>) -> Expression {
2542 match filter {
2543 Some(filter) => Expression::And(Box::new(crate::expressions::BinaryOp::new(
2544 filter, condition,
2545 ))),
2546 None => condition,
2547 }
2548 }
2549
2550 fn transform_function(&self, f: Function) -> Result<Expression> {
2551 let name_upper = f.name.to_uppercase();
2552 match name_upper.as_str() {
2553 "COALESCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
2555 "ISNULL".to_string(),
2556 f.args,
2557 )))),
2558
2559 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
2561 "ISNULL".to_string(),
2562 f.args,
2563 )))),
2564
2565 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
2567 Function::new("STRING_AGG".to_string(), f.args),
2568 ))),
2569
2570 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
2572
2573 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
2575 "STRING_AGG".to_string(),
2576 f.args,
2577 )))),
2578
2579 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
2581 "SUBSTRING".to_string(),
2582 f.args,
2583 )))),
2584
2585 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2587 "LEN".to_string(),
2588 f.args,
2589 )))),
2590
2591 "BTRIM" if f.args.len() == 1 || f.args.len() == 2 => {
2593 let mut args = f.args;
2594 let this = args.remove(0);
2595 let characters = if args.is_empty() {
2596 None
2597 } else {
2598 Some(args.remove(0))
2599 };
2600 Ok(Expression::Trim(Box::new(TrimFunc {
2601 this,
2602 sql_standard_syntax: characters.is_some(),
2603 characters,
2604 position: TrimPosition::Both,
2605 position_explicit: false,
2606 inferred_type: f.inferred_type,
2607 })))
2608 }
2609
2610 "MD5" if f.args.len() == 1 => {
2612 let mut args = f.args;
2613 Ok(Self::tsql_md5_hex(args.remove(0)))
2614 }
2615
2616 "SHA256" if f.args.len() == 1 => {
2617 let mut args = f.args;
2618 Ok(Self::function(
2619 "HASHBYTES",
2620 vec![Expression::string("SHA2_256"), args.remove(0)],
2621 ))
2622 }
2623
2624 "SHA512" if f.args.len() == 1 => {
2625 let mut args = f.args;
2626 Ok(Self::function(
2627 "HASHBYTES",
2628 vec![Expression::string("SHA2_512"), args.remove(0)],
2629 ))
2630 }
2631
2632 "OCTET_LENGTH" if f.args.len() == 1 => Ok(Self::function("DATALENGTH", f.args)),
2634
2635 "BIT_LENGTH" if f.args.len() == 1 => {
2637 let mut args = f.args;
2638 Ok(Expression::Mul(Box::new(BinaryOp::new(
2639 Self::function("DATALENGTH", vec![args.remove(0)]),
2640 Expression::number(8),
2641 ))))
2642 }
2643
2644 "TO_HEX" if f.args.len() == 1 => {
2648 let mut args = f.args;
2649 Ok(Self::tsql_postgres_to_hex(args.remove(0)))
2650 }
2651
2652 "ENCODE" if f.args.len() == 2 => {
2654 let mut args = f.args;
2655 let this = args.remove(0);
2656 let encoding = args.remove(0);
2657 if Self::literal_string(&encoding)
2658 .is_some_and(|encoding| encoding.eq_ignore_ascii_case("hex"))
2659 {
2660 Ok(Self::tsql_hex_from_varbinary(this))
2661 } else {
2662 Ok(Expression::Function(Box::new(Function::new(
2663 "ENCODE".to_string(),
2664 vec![this, encoding],
2665 ))))
2666 }
2667 }
2668
2669 "DECODE"
2672 if f.args.len() == 2
2673 && Self::literal_string(&f.args[1])
2674 .is_some_and(|format| format.eq_ignore_ascii_case("hex")) =>
2675 {
2676 let mut args = f.args;
2677 Ok(Self::tsql_convert(
2678 DataType::Custom {
2679 name: "VARBINARY(MAX)".to_string(),
2680 },
2681 args.remove(0),
2682 Some(2),
2683 ))
2684 }
2685
2686 "REPEAT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
2688 "REPLICATE".to_string(),
2689 f.args,
2690 )))),
2691
2692 "CHR" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2694 "CHAR".to_string(),
2695 f.args,
2696 )))),
2697
2698 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2700 seed: None,
2701 lower: None,
2702 upper: None,
2703 }))),
2704
2705 "NOW" => Ok(Self::getdate()),
2707
2708 "CURRENT_TIMESTAMP" => Ok(Self::getdate()),
2710
2711 "CURRENT_DATE" => Ok(Self::cast_getdate_to(DataType::Date)),
2713
2714 "CURRENT_TIME" => Ok(Self::cast_getdate_to(DataType::Time {
2716 precision: None,
2717 timezone: false,
2718 })),
2719
2720 "LOCALTIMESTAMP" => Ok(Self::getdate()),
2722
2723 "CLOCK_TIMESTAMP" if f.args.is_empty() => Ok(Self::function("SYSDATETIME", vec![])),
2725
2726 "MAKE_DATE" if f.args.len() == 3 => Ok(Self::function("DATEFROMPARTS", f.args)),
2728
2729 "MAKE_TIME" if f.args.len() == 3 => Ok(Self::make_time(f.args)),
2732
2733 "TO_DATE" if f.args.len() == 2 => {
2737 Self::formatted_str_to_date_or_fallback(f.args, "TO_DATE")
2738 }
2739
2740 "TO_DATE" if f.args.len() == 1 => {
2742 let mut args = f.args;
2743 Ok(Expression::Cast(Box::new(Cast {
2744 this: args.remove(0),
2745 to: DataType::Date,
2746 trailing_comments: Vec::new(),
2747 double_colon_syntax: false,
2748 format: None,
2749 default: None,
2750 inferred_type: None,
2751 })))
2752 }
2753
2754 "TO_TIMESTAMP" if f.args.len() == 2 => {
2757 Self::formatted_str_to_time_or_fallback(f.args, "TO_TIMESTAMP")
2758 }
2759
2760 "TO_TIMESTAMP" if f.args.len() == 1 => {
2762 let mut args = f.args;
2763 Ok(Expression::UnixToTime(Box::new(
2764 crate::expressions::UnixToTime {
2765 this: Box::new(args.remove(0)),
2766 scale: Some(0),
2767 zone: None,
2768 hours: None,
2769 minutes: None,
2770 format: None,
2771 target_type: None,
2772 },
2773 )))
2774 }
2775
2776 "TO_CHAR" if f.args.len() == 2 => {
2779 Self::formatted_time_to_str_or_fallback(f.args, "TO_CHAR")
2780 }
2781
2782 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
2784 "FORMAT".to_string(),
2785 f.args,
2786 )))),
2787
2788 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
2790 "FORMAT".to_string(),
2791 f.args,
2792 )))),
2793
2794 "DATE_TRUNC" | "DATETRUNC" => {
2797 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
2798 if args.len() >= 2 {
2800 if let Expression::Literal(lit) = &args[1] {
2801 if let Literal::String(_) = lit.as_ref() {
2802 args[1] = Expression::Cast(Box::new(Cast {
2803 this: args[1].clone(),
2804 to: DataType::Custom {
2805 name: "DATETIME2".to_string(),
2806 },
2807 trailing_comments: Vec::new(),
2808 double_colon_syntax: false,
2809 format: None,
2810 default: None,
2811 inferred_type: None,
2812 }));
2813 }
2814 }
2815 }
2816 Ok(Expression::Function(Box::new(Function::new(
2817 "DATETRUNC".to_string(),
2818 args,
2819 ))))
2820 }
2821
2822 "DATEADD" => {
2824 let args = Self::uppercase_first_arg_if_identifier(f.args);
2825 Ok(Expression::Function(Box::new(Function::new(
2826 "DATEADD".to_string(),
2827 args,
2828 ))))
2829 }
2830
2831 "DATEDIFF" => {
2833 let args = Self::uppercase_first_arg_if_identifier(f.args);
2834 Ok(Expression::Function(Box::new(Function::new(
2835 "DATEDIFF".to_string(),
2836 args,
2837 ))))
2838 }
2839
2840 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2842 "DATEPART".to_string(),
2843 f.args,
2844 )))),
2845
2846 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
2848 Ok(Expression::Function(Box::new(Function::new(
2850 "CHARINDEX".to_string(),
2851 f.args,
2852 ))))
2853 }
2854
2855 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2857
2858 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
2860 Function::new("CEILING".to_string(), f.args),
2861 ))),
2862
2863 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2868 "JSON_VALUE".to_string(),
2869 f.args,
2870 )))),
2871
2872 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2874 "JSON_VALUE".to_string(),
2875 f.args,
2876 )))),
2877
2878 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
2880
2881 "GET_PATH" if f.args.len() == 2 => {
2883 let mut args = f.args;
2884 let this = args.remove(0);
2885 let path = args.remove(0);
2886 let json_path = match &path {
2887 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
2888 let Literal::String(s) = lit.as_ref() else {
2889 unreachable!()
2890 };
2891 let normalized = if s.starts_with('$') {
2892 s.clone()
2893 } else if s.starts_with('[') {
2894 format!("${}", s)
2895 } else {
2896 format!("$.{}", s)
2897 };
2898 Expression::Literal(Box::new(Literal::String(normalized)))
2899 }
2900 _ => path,
2901 };
2902 let json_query = Expression::Function(Box::new(Function::new(
2904 "JSON_QUERY".to_string(),
2905 vec![this.clone(), json_path.clone()],
2906 )));
2907 let json_value = Expression::Function(Box::new(Function::new(
2908 "JSON_VALUE".to_string(),
2909 vec![this, json_path],
2910 )));
2911 Ok(Expression::Function(Box::new(Function::new(
2912 "ISNULL".to_string(),
2913 vec![json_query, json_value],
2914 ))))
2915 }
2916
2917 "JSON_QUERY" if f.args.len() == 1 => {
2920 let this = f.args.into_iter().next().unwrap();
2921 let path = Expression::Literal(Box::new(Literal::String("$".to_string())));
2922 let json_query = Expression::Function(Box::new(Function::new(
2923 "JSON_QUERY".to_string(),
2924 vec![this.clone(), path.clone()],
2925 )));
2926 let json_value = Expression::Function(Box::new(Function::new(
2927 "JSON_VALUE".to_string(),
2928 vec![this, path],
2929 )));
2930 Ok(Expression::Function(Box::new(Function::new(
2931 "ISNULL".to_string(),
2932 vec![json_query, json_value],
2933 ))))
2934 }
2935
2936 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
2938 "STRING_SPLIT".to_string(),
2939 f.args,
2940 )))),
2941
2942 "REGEXP_LIKE" => {
2945 Ok(Expression::Function(Box::new(Function::new(
2947 "PATINDEX".to_string(),
2948 f.args,
2949 ))))
2950 }
2951
2952 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2954 "LOG".to_string(),
2955 f.args,
2956 )))),
2957
2958 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2963 "STDEV".to_string(),
2964 f.args,
2965 )))),
2966
2967 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
2969 "STDEVP".to_string(),
2970 f.args,
2971 )))),
2972
2973 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2975 "VAR".to_string(),
2976 f.args,
2977 )))),
2978
2979 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2981 "VARP".to_string(),
2982 f.args,
2983 )))),
2984
2985 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
2987 let mut args = f.args;
2988 Self::transform_logical_aggregate(args.remove(0), None, "MIN")
2989 }
2990 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
2991 let mut args = f.args;
2992 Self::transform_logical_aggregate(args.remove(0), None, "MAX")
2993 }
2994
2995 "DATE_ADD" => {
2997 if f.args.len() == 2 {
2998 let mut args = f.args;
2999 let date = args.remove(0);
3000 let interval = args.remove(0);
3001 let unit = Expression::Identifier(crate::expressions::Identifier {
3002 name: "DAY".to_string(),
3003 quoted: false,
3004 trailing_comments: Vec::new(),
3005 span: None,
3006 });
3007 Ok(Expression::Function(Box::new(Function::new(
3008 "DATEADD".to_string(),
3009 vec![unit, interval, date],
3010 ))))
3011 } else {
3012 let args = Self::uppercase_first_arg_if_identifier(f.args);
3013 Ok(Expression::Function(Box::new(Function::new(
3014 "DATEADD".to_string(),
3015 args,
3016 ))))
3017 }
3018 }
3019
3020 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
3022 "STUFF".to_string(),
3023 f.args,
3024 )))),
3025
3026 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
3028 crate::expressions::CurrentUser { this: None },
3029 ))),
3030
3031 _ => Ok(Expression::Function(Box::new(f))),
3033 }
3034 }
3035
3036 fn literal_string(expr: &Expression) -> Option<&str> {
3037 match expr {
3038 Expression::Literal(lit) => match lit.as_ref() {
3039 Literal::String(s) => Some(s),
3040 _ => None,
3041 },
3042 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
3043 if Self::is_text_data_type(&cast.to) =>
3044 {
3045 Self::literal_string(&cast.this)
3046 }
3047 _ => None,
3048 }
3049 }
3050
3051 fn is_text_data_type(data_type: &DataType) -> bool {
3052 match data_type {
3053 DataType::Char { .. }
3054 | DataType::VarChar { .. }
3055 | DataType::String { .. }
3056 | DataType::Text
3057 | DataType::TextWithLength { .. } => true,
3058 DataType::Custom { name } => {
3059 let base = name
3060 .split_once('(')
3061 .map_or(name.as_str(), |(base, _)| base)
3062 .trim();
3063 matches!(
3064 base.to_ascii_uppercase().as_str(),
3065 "CHAR"
3066 | "NCHAR"
3067 | "VARCHAR"
3068 | "NVARCHAR"
3069 | "TEXT"
3070 | "NTEXT"
3071 | "STRING"
3072 | "CHARACTER VARYING"
3073 )
3074 }
3075 _ => false,
3076 }
3077 }
3078
3079 fn is_numeric_data_type(data_type: &DataType) -> bool {
3080 match data_type {
3081 DataType::TinyInt { .. }
3082 | DataType::SmallInt { .. }
3083 | DataType::Int { .. }
3084 | DataType::BigInt { .. }
3085 | DataType::Float { .. }
3086 | DataType::Double { .. }
3087 | DataType::Decimal { .. } => true,
3088 DataType::Custom { name } => {
3089 let base = name
3090 .split_once('(')
3091 .map_or(name.as_str(), |(base, _)| base)
3092 .trim();
3093 matches!(
3094 base.to_ascii_uppercase().as_str(),
3095 "TINYINT"
3096 | "SMALLINT"
3097 | "INT"
3098 | "INTEGER"
3099 | "BIGINT"
3100 | "DECIMAL"
3101 | "NUMERIC"
3102 | "REAL"
3103 | "FLOAT"
3104 | "MONEY"
3105 | "SMALLMONEY"
3106 )
3107 }
3108 _ => false,
3109 }
3110 }
3111
3112 fn is_explicitly_numeric_expression(expr: &Expression) -> bool {
3113 if expr.inferred_type().is_some_and(Self::is_numeric_data_type) {
3114 return true;
3115 }
3116
3117 match expr {
3118 Expression::Literal(literal) => matches!(literal.as_ref(), Literal::Number(_)),
3119 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
3120 Self::is_numeric_data_type(&cast.to)
3121 }
3122 Expression::Alias(alias) => Self::is_explicitly_numeric_expression(&alias.this),
3123 Expression::Paren(paren) => Self::is_explicitly_numeric_expression(&paren.this),
3124 Expression::Neg(unary) => Self::is_explicitly_numeric_expression(&unary.this),
3125 _ => false,
3126 }
3127 }
3128
3129 fn postgres_format_to_strftime(format: &str) -> String {
3130 const POSTGRES_FORMAT_TO_STRFTIME: &[(&str, &str)] = &[
3131 ("FMHH24", "%-H"),
3132 ("FMHH12", "%-I"),
3133 ("FMDDD", "%-j"),
3134 ("TMMonth", "%B"),
3135 ("TMMon", "%b"),
3136 ("TMDay", "%A"),
3137 ("TMDy", "%a"),
3138 ("YYYY", "%Y"),
3139 ("yyyy", "%Y"),
3140 ("HH24", "%H"),
3141 ("HH12", "%I"),
3142 ("FMDD", "%-d"),
3143 ("FMMM", "%-m"),
3144 ("FMMI", "%-M"),
3145 ("FMSS", "%-S"),
3146 ("DDD", "%j"),
3147 ("ddd", "%j"),
3148 ("YY", "%y"),
3149 ("yy", "%y"),
3150 ("MM", "%m"),
3151 ("mm", "%m"),
3152 ("DD", "%d"),
3153 ("dd", "%d"),
3154 ("MI", "%M"),
3155 ("mi", "%M"),
3156 ("SS", "%S"),
3157 ("ss", "%S"),
3158 ("US", "%f"),
3159 ("OF", "%z"),
3160 ("TZ", "%Z"),
3161 ("WW", "%U"),
3162 ("ww", "%U"),
3163 ("D", "%u"),
3164 ("d", "%u"),
3165 ];
3166 crate::format_tokens::convert_format_tokens(format, POSTGRES_FORMAT_TO_STRFTIME)
3167 .unwrap_or_else(|| format.to_string())
3168 }
3169
3170 fn formatted_str_to_time_or_fallback(
3171 mut args: Vec<Expression>,
3172 original_name: &str,
3173 ) -> Result<Expression> {
3174 let this = args.remove(0);
3175 let format = args.remove(0);
3176 if let Some(format) = Self::literal_string(&format) {
3177 Ok(Expression::StrToTime(Box::new(
3178 crate::expressions::StrToTime {
3179 this: Box::new(this),
3180 format: Self::postgres_format_to_strftime(format),
3181 zone: None,
3182 safe: None,
3183 target_type: Some(Box::new(Expression::DataType(DataType::Custom {
3184 name: "DATETIME2".to_string(),
3185 }))),
3186 },
3187 )))
3188 } else {
3189 Ok(Expression::Function(Box::new(Function::new(
3190 original_name.to_string(),
3191 vec![this, format],
3192 ))))
3193 }
3194 }
3195
3196 fn formatted_str_to_date_or_fallback(
3197 mut args: Vec<Expression>,
3198 original_name: &str,
3199 ) -> Result<Expression> {
3200 let this = args.remove(0);
3201 let format = args.remove(0);
3202 if let Some(format) = Self::literal_string(&format) {
3203 Ok(Expression::StrToDate(Box::new(
3204 crate::expressions::StrToDate {
3205 this: Box::new(this),
3206 format: Some(Self::postgres_format_to_strftime(format)),
3207 safe: None,
3208 },
3209 )))
3210 } else {
3211 Ok(Expression::Function(Box::new(Function::new(
3212 original_name.to_string(),
3213 vec![this, format],
3214 ))))
3215 }
3216 }
3217
3218 fn push_postgres_to_char_literal(result: &mut String, ch: char) {
3219 if matches!(
3220 ch,
3221 'F' | 'H'
3222 | 'K'
3223 | 'M'
3224 | 'd'
3225 | 'f'
3226 | 'g'
3227 | 'h'
3228 | 'm'
3229 | 's'
3230 | 't'
3231 | 'y'
3232 | 'z'
3233 | '%'
3234 | ':'
3235 | '/'
3236 | '"'
3237 | '\''
3238 | '\\'
3239 ) {
3240 result.push('\\');
3241 }
3242 result.push(ch);
3243 }
3244
3245 fn classify_postgres_to_char_format(format: &str) -> PostgresToCharFormat {
3246 const SUPPORTED: &[(&str, &str, bool)] = &[
3247 ("FMHH24", "%-H", false),
3248 ("FMHH12", "%-I", false),
3249 ("FMHH", "%-I", false),
3250 ("FMMonth", "%B", true),
3251 ("FMMon", "%b", true),
3252 ("FMDay", "%A", true),
3253 ("FMDy", "%a", true),
3254 ("TMMonth", "%B", false),
3255 ("TMMon", "%b", false),
3256 ("TMDay", "%A", false),
3257 ("TMDy", "%a", false),
3258 ("YYYY", "%Y", false),
3259 ("yyyy", "%Y", false),
3260 ("HH24", "%H", false),
3261 ("HH12", "%I", false),
3262 ("FMDD", "%-d", false),
3263 ("FMMM", "%-m", false),
3264 ("FMMI", "%-M", false),
3265 ("FMSS", "%-S", false),
3266 ("HH", "%I", false),
3267 ("YY", "%y", false),
3268 ("yy", "%y", false),
3269 ("MM", "%m", false),
3270 ("mm", "%m", false),
3271 ("DD", "%d", false),
3272 ("dd", "%d", false),
3273 ("MI", "%M", false),
3274 ("mi", "%M", false),
3275 ("SS", "%S", false),
3276 ("ss", "%S", false),
3277 ("US", "%f", false),
3278 ("Dy", "%a", true),
3279 ("Mon", "%b", true),
3280 ];
3281 const POSTGRES_TOKENS: &[&str] = &[
3282 "SSSSS", "SSSS", "IYYY", "IDDD", "MONTH", "Month", "month", "HH24", "HH12", "FMMONTH",
3283 "FMMonth", "FMmonth", "FMDAY", "FMDay", "FMday", "FMMON", "FMMon", "FMmon", "FMDY",
3284 "FMDy", "FMdy", "TMMonth", "TMMon", "TMDay", "TMDy", "Y,YYY", "A.M.", "a.m.", "P.M.",
3285 "p.m.", "FMRM", "FMrm", "IYY", "YYY", "yyyy", "YYYY", "DDD", "ddd", "DAY", "Day",
3286 "day", "MON", "Mon", "mon", "DY", "Dy", "dy", "TZH", "TZM", "FF1", "FF2", "FF3", "FF4",
3287 "FF5", "FF6", "FMHH24", "FMHH12", "FMHH", "FMDDD", "FMDD", "FMMM", "FMMI", "FMSS",
3288 "HH", "IY", "YY", "yy", "MM", "mm", "DD", "dd", "MI", "mi", "SS", "ss", "MS", "US",
3289 "AM", "am", "PM", "pm", "BC", "bc", "AD", "ad", "B.C.", "b.c.", "A.D.", "a.d.", "ID",
3290 "WW", "ww", "IW", "CC", "RM", "rm", "TZ", "tz", "OF", "I", "Y", "y", "D", "d", "W",
3291 "J", "Q",
3292 ];
3293
3294 fn longest_token_at(input: &str, index: usize) -> Option<usize> {
3295 POSTGRES_TOKENS
3296 .iter()
3297 .filter(|token| input[index..].starts_with(**token))
3298 .map(|token| token.len())
3299 .max()
3300 }
3301
3302 let mut result = String::with_capacity(format.len() * 2);
3303 let mut index = 0;
3304 let mut requires_english_culture = false;
3305
3306 while index < format.len() {
3307 if format[index..].starts_with('\\') {
3308 index += 1;
3309 if format[index..].starts_with('"') {
3310 Self::push_postgres_to_char_literal(&mut result, '"');
3311 index += 1;
3312 } else {
3313 Self::push_postgres_to_char_literal(&mut result, '\\');
3316 }
3317 continue;
3318 }
3319
3320 if format[index..].starts_with('"') {
3321 index += 1;
3322 let mut closed = false;
3323 while index < format.len() {
3324 let Some(ch) = format[index..].chars().next() else {
3325 return PostgresToCharFormat::Unsupported;
3326 };
3327 index += ch.len_utf8();
3328 if ch == '"' {
3329 closed = true;
3330 break;
3331 }
3332 if ch == '\\' && index < format.len() {
3333 let Some(escaped) = format[index..].chars().next() else {
3334 return PostgresToCharFormat::Unsupported;
3335 };
3336 index += escaped.len_utf8();
3337 Self::push_postgres_to_char_literal(&mut result, escaped);
3338 } else {
3339 Self::push_postgres_to_char_literal(&mut result, ch);
3340 }
3341 }
3342 if !closed {
3343 return PostgresToCharFormat::Unsupported;
3344 }
3345 continue;
3346 }
3347
3348 let remaining = &format[index..];
3349 let ch = remaining
3350 .chars()
3351 .next()
3352 .expect("format index should be on a character boundary");
3353 if matches!(ch, '9' | '0')
3354 || ["PR", "SG", "PL", "RN", "EEEE"].iter().any(|token| {
3355 remaining
3356 .get(..token.len())
3357 .is_some_and(|prefix| prefix.eq_ignore_ascii_case(token))
3358 })
3359 {
3360 return PostgresToCharFormat::Numeric;
3361 }
3362
3363 let supported = SUPPORTED
3364 .iter()
3365 .filter(|(token, _, _)| format[index..].starts_with(token))
3366 .max_by_key(|(token, _, _)| token.len());
3367 let recognized_len =
3368 if format[index..].starts_with("FM") || format[index..].starts_with("TM") {
3369 longest_token_at(format, index + 2).map(|len| len + 2)
3370 } else {
3371 longest_token_at(format, index)
3372 };
3373
3374 if let Some((token, replacement, english_culture)) = supported {
3375 if recognized_len.is_some_and(|len| len > token.len()) {
3376 return PostgresToCharFormat::Unsupported;
3377 }
3378 let end = index + token.len();
3379 if format[end..].starts_with("TH")
3380 || format[end..].starts_with("th")
3381 || format[end..].starts_with("SP")
3382 {
3383 return PostgresToCharFormat::Unsupported;
3384 }
3385 result.push_str(replacement);
3386 requires_english_culture |= english_culture;
3387 index = end;
3388 continue;
3389 }
3390
3391 if recognized_len.is_some() || format[index..].starts_with("FX") {
3392 return PostgresToCharFormat::Unsupported;
3393 }
3394
3395 Self::push_postgres_to_char_literal(&mut result, ch);
3396 index += ch.len_utf8();
3397 }
3398
3399 PostgresToCharFormat::Temporal {
3400 strftime: result,
3401 requires_english_culture,
3402 }
3403 }
3404
3405 fn formatted_time_to_str_or_fallback(
3406 mut args: Vec<Expression>,
3407 original_name: &str,
3408 ) -> Result<Expression> {
3409 let this = args.remove(0);
3410 let format = args.remove(0);
3411 if let Some(format_string) = Self::literal_string(&format).map(str::to_owned) {
3412 if Self::is_explicitly_numeric_expression(&this) {
3413 return Ok(Expression::Function(Box::new(Function::new(
3414 original_name.to_string(),
3415 vec![this, format],
3416 ))));
3417 }
3418
3419 let (format_string, requires_english_culture) =
3420 match Self::classify_postgres_to_char_format(&format_string) {
3421 PostgresToCharFormat::Temporal {
3422 strftime,
3423 requires_english_culture,
3424 } => (strftime, requires_english_culture),
3425 PostgresToCharFormat::Numeric | PostgresToCharFormat::Unsupported => {
3426 return Ok(Expression::Function(Box::new(Function::new(
3427 original_name.to_string(),
3428 vec![this, format],
3429 ))));
3430 }
3431 };
3432
3433 Ok(Expression::TimeToStr(Box::new(
3434 crate::expressions::TimeToStr {
3435 this: Box::new(this),
3436 format: format_string,
3437 culture: requires_english_culture
3438 .then(|| Box::new(Expression::string("en-US"))),
3439 zone: None,
3440 },
3441 )))
3442 } else {
3443 Ok(Expression::Function(Box::new(Function::new(
3444 original_name.to_string(),
3445 vec![this, format],
3446 ))))
3447 }
3448 }
3449
3450 fn transform_aggregate_function(
3451 &self,
3452 mut f: Box<crate::expressions::AggregateFunction>,
3453 ) -> Result<Expression> {
3454 let name_upper = f.name.to_uppercase();
3455 if matches!(
3456 name_upper.as_str(),
3457 "SUM"
3458 | "AVG"
3459 | "MIN"
3460 | "MAX"
3461 | "COUNT"
3462 | "COUNT_BIG"
3463 | "ANY_VALUE"
3464 | "APPROX_COUNT_DISTINCT"
3465 | "STDEV"
3466 | "STDEVP"
3467 | "VAR"
3468 | "VARP"
3469 | "BOOL_AND"
3470 | "BOOL_OR"
3471 | "LOGICAL_AND"
3472 | "LOGICAL_OR"
3473 | "BIT_AND"
3474 | "BIT_OR"
3475 | "BIT_XOR"
3476 ) {
3477 f.order_by.clear();
3478 }
3479
3480 match name_upper.as_str() {
3481 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3483 Function::new("STRING_AGG".to_string(), f.args),
3484 ))),
3485
3486 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3488 "STRING_AGG".to_string(),
3489 f.args,
3490 )))),
3491
3492 "ARRAY_AGG" if !f.args.is_empty() => {
3495 Ok(Expression::Function(Box::new(Function::new(
3497 "STRING_AGG".to_string(),
3498 f.args,
3499 ))))
3500 }
3501
3502 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
3504 let mut args = f.args;
3505 Self::transform_logical_aggregate(args.remove(0), f.filter, "MIN")
3506 }
3507 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
3508 let mut args = f.args;
3509 Self::transform_logical_aggregate(args.remove(0), f.filter, "MAX")
3510 }
3511
3512 _ => Ok(Expression::AggregateFunction(f)),
3514 }
3515 }
3516
3517 fn without_inert_ordering(
3518 mut aggregate: Box<crate::expressions::AggFunc>,
3519 ) -> Box<crate::expressions::AggFunc> {
3520 aggregate.order_by.clear();
3521 aggregate
3522 }
3523
3524 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
3528 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
3529 }
3530
3531 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
3533 if cte.columns.is_empty() {
3536 cte.this = self.qualify_derived_table_outputs(cte.this);
3537 }
3538 cte
3539 }
3540
3541 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
3545 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
3548 subquery.this = self.qualify_derived_table_outputs(subquery.this);
3549 }
3550 Ok(Expression::Subquery(Box::new(subquery)))
3551 }
3552
3553 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
3557 match expr {
3558 Expression::Select(mut select) => {
3559 let has_from = select.from.is_some();
3562 if !has_from {
3563 select.expressions = select
3564 .expressions
3565 .into_iter()
3566 .map(|e| self.maybe_alias_expression(e))
3567 .collect();
3568 }
3569 Expression::Select(select)
3570 }
3571 Expression::Union(mut u) => {
3573 let left = std::mem::replace(&mut u.left, Expression::Null(Null));
3574 u.left = self.qualify_derived_table_outputs(left);
3575 Expression::Union(u)
3576 }
3577 Expression::Intersect(mut i) => {
3578 let left = std::mem::replace(&mut i.left, Expression::Null(Null));
3579 i.left = self.qualify_derived_table_outputs(left);
3580 Expression::Intersect(i)
3581 }
3582 Expression::Except(mut e) => {
3583 let left = std::mem::replace(&mut e.left, Expression::Null(Null));
3584 e.left = self.qualify_derived_table_outputs(left);
3585 Expression::Except(e)
3586 }
3587 Expression::Subquery(mut s) => {
3589 s.this = self.qualify_derived_table_outputs(s.this);
3590 Expression::Subquery(s)
3591 }
3592 other => other,
3594 }
3595 }
3596
3597 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
3602 match &expr {
3603 Expression::Alias(_) => expr,
3605 Expression::Aliases(_) => expr,
3607 Expression::Star(_) => expr,
3609 _ => {
3614 if let Some(output_name) = self.get_output_name(&expr) {
3615 Expression::Alias(Box::new(Alias {
3616 this: expr,
3617 alias: Identifier {
3618 name: output_name,
3619 quoted: true, trailing_comments: Vec::new(),
3621 span: None,
3622 },
3623 column_aliases: Vec::new(),
3624 alias_explicit_as: false,
3625 alias_keyword: None,
3626 pre_alias_comments: Vec::new(),
3627 trailing_comments: Vec::new(),
3628 inferred_type: None,
3629 }))
3630 } else {
3631 expr
3633 }
3634 }
3635 }
3636 }
3637
3638 fn get_output_name(&self, expr: &Expression) -> Option<String> {
3642 match expr {
3643 Expression::Literal(lit) => match lit.as_ref() {
3645 Literal::Number(n) => Some(n.clone()),
3646 Literal::String(s) => Some(s.clone()),
3647 Literal::HexString(h) => Some(format!("0x{}", h)),
3648 Literal::HexNumber(h) => Some(format!("0x{}", h)),
3649 Literal::BitString(b) => Some(format!("b{}", b)),
3650 Literal::ByteString(b) => Some(format!("b'{}'", b)),
3651 Literal::NationalString(s) => Some(format!("N'{}'", s)),
3652 Literal::Date(d) => Some(d.clone()),
3653 Literal::Time(t) => Some(t.clone()),
3654 Literal::Timestamp(ts) => Some(ts.clone()),
3655 Literal::Datetime(dt) => Some(dt.clone()),
3656 Literal::TripleQuotedString(s, _) => Some(s.clone()),
3657 Literal::EscapeString(s) => Some(s.clone()),
3658 Literal::DollarString(s) => Some(s.clone()),
3659 Literal::RawString(s) => Some(s.clone()),
3660 },
3661 Expression::Column(col) => Some(col.name.name.clone()),
3663 Expression::Identifier(ident) => Some(ident.name.clone()),
3665 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
3667 Expression::Null(_) => Some("NULL".to_string()),
3669 Expression::Function(f) => Some(f.name.clone()),
3671 Expression::AggregateFunction(f) => Some(f.name.clone()),
3673 _ => Some(format!("_col_{}", 0)),
3675 }
3676 }
3677
3678 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
3680 use crate::expressions::Identifier;
3681 if !args.is_empty() {
3682 match &args[0] {
3683 Expression::Identifier(id) => {
3684 args[0] = Expression::Identifier(Identifier {
3685 name: id.name.to_uppercase(),
3686 quoted: id.quoted,
3687 trailing_comments: id.trailing_comments.clone(),
3688 span: None,
3689 });
3690 }
3691 Expression::Var(v) => {
3692 args[0] = Expression::Identifier(Identifier {
3693 name: v.this.to_uppercase(),
3694 quoted: false,
3695 trailing_comments: Vec::new(),
3696 span: None,
3697 });
3698 }
3699 Expression::Column(col) if col.table.is_none() => {
3700 args[0] = Expression::Identifier(Identifier {
3701 name: col.name.name.to_uppercase(),
3702 quoted: col.name.quoted,
3703 trailing_comments: col.name.trailing_comments.clone(),
3704 span: None,
3705 });
3706 }
3707 _ => {}
3708 }
3709 }
3710 args
3711 }
3712}
3713
3714#[cfg(test)]
3715mod tests {
3716 use super::*;
3717 use crate::dialects::Dialect;
3718
3719 fn transpile_to_tsql(sql: &str) -> String {
3720 let dialect = Dialect::get(DialectType::Generic);
3721 let result = dialect
3722 .transpile(sql, DialectType::TSQL)
3723 .expect("Transpile failed");
3724 result[0].clone()
3725 }
3726
3727 #[test]
3728 fn test_nvl_to_isnull() {
3729 let result = transpile_to_tsql("SELECT NVL(a, b)");
3730 assert!(
3731 result.contains("ISNULL"),
3732 "Expected ISNULL, got: {}",
3733 result
3734 );
3735 }
3736
3737 #[test]
3738 fn test_coalesce_to_isnull() {
3739 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
3740 assert!(
3741 result.contains("ISNULL"),
3742 "Expected ISNULL, got: {}",
3743 result
3744 );
3745 }
3746
3747 #[test]
3748 fn test_basic_select() {
3749 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
3750 assert!(result.contains("SELECT"));
3751 assert!(result.contains("FROM users"));
3752 }
3753
3754 #[test]
3755 fn test_length_to_len() {
3756 let result = transpile_to_tsql("SELECT LENGTH(name)");
3757 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
3758 }
3759
3760 #[test]
3761 fn test_issue_374_tsql_parse_then_generate_uses_len() {
3762 let sql = "SELECT LEN(table.col1) - LEN(table.col2) FROM table";
3763 let ast = Dialect::get(DialectType::TSQL)
3764 .parse(sql)
3765 .expect("T-SQL should parse");
3766 let expression = &ast[0];
3767
3768 for target in [DialectType::TSQL, DialectType::Fabric] {
3769 let generated = Dialect::get(target)
3770 .generate(expression)
3771 .expect("AST should generate");
3772 assert_eq!(generated, sql, "failed for target {target:?}");
3773 }
3774
3775 let standard_sql = "SELECT LENGTH(table.col1) - LENGTH(table.col2) FROM table";
3776 for target in [DialectType::Generic, DialectType::PostgreSQL] {
3777 let generated = Dialect::get(target)
3778 .generate(expression)
3779 .expect("AST should generate");
3780 assert_eq!(generated, standard_sql, "failed for target {target:?}");
3781 }
3782 }
3783
3784 #[test]
3785 fn test_now_to_getdate() {
3786 let result = transpile_to_tsql("SELECT NOW()");
3787 assert!(
3788 result.contains("GETDATE"),
3789 "Expected GETDATE, got: {}",
3790 result
3791 );
3792 }
3793
3794 #[test]
3795 fn test_group_concat_to_string_agg() {
3796 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
3797 assert!(
3798 result.contains("STRING_AGG"),
3799 "Expected STRING_AGG, got: {}",
3800 result
3801 );
3802 }
3803
3804 #[test]
3805 fn test_listagg_to_string_agg() {
3806 let result = transpile_to_tsql("SELECT LISTAGG(name)");
3807 assert!(
3808 result.contains("STRING_AGG"),
3809 "Expected STRING_AGG, got: {}",
3810 result
3811 );
3812 }
3813
3814 #[test]
3815 fn test_ln_to_log() {
3816 let result = transpile_to_tsql("SELECT LN(x)");
3817 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
3818 }
3819
3820 #[test]
3821 fn test_stddev_to_stdev() {
3822 let result = transpile_to_tsql("SELECT STDDEV(x)");
3823 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
3824 }
3825
3826 #[test]
3827 fn test_bracket_identifiers() {
3828 let dialect = Dialect::get(DialectType::TSQL);
3830 let config = dialect.generator_config();
3831 assert_eq!(config.identifier_quote, '[');
3832 }
3833
3834 #[test]
3835 fn test_json_query_isnull_wrapper_simple() {
3836 let dialect = Dialect::get(DialectType::TSQL);
3838 let result = dialect
3839 .transpile(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
3840 .expect("transpile failed");
3841 assert!(
3842 result[0].contains("ISNULL"),
3843 "JSON_QUERY should be wrapped with ISNULL: {}",
3844 result[0]
3845 );
3846 }
3847
3848 #[test]
3849 fn test_json_query_isnull_wrapper_nested() {
3850 let dialect = Dialect::get(DialectType::TSQL);
3851 let result = dialect
3852 .transpile(
3853 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
3854 DialectType::TSQL,
3855 )
3856 .expect("transpile failed");
3857 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
3858 assert_eq!(
3859 result[0], expected,
3860 "JSON_QUERY should be wrapped with ISNULL"
3861 );
3862 }
3863}