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::FetchFirst,
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 })))
2607 }
2608
2609 "MD5" if f.args.len() == 1 => {
2611 let mut args = f.args;
2612 Ok(Self::tsql_md5_hex(args.remove(0)))
2613 }
2614
2615 "SHA256" if f.args.len() == 1 => {
2616 let mut args = f.args;
2617 Ok(Self::function(
2618 "HASHBYTES",
2619 vec![Expression::string("SHA2_256"), args.remove(0)],
2620 ))
2621 }
2622
2623 "SHA512" if f.args.len() == 1 => {
2624 let mut args = f.args;
2625 Ok(Self::function(
2626 "HASHBYTES",
2627 vec![Expression::string("SHA2_512"), args.remove(0)],
2628 ))
2629 }
2630
2631 "OCTET_LENGTH" if f.args.len() == 1 => Ok(Self::function("DATALENGTH", f.args)),
2633
2634 "BIT_LENGTH" if f.args.len() == 1 => {
2636 let mut args = f.args;
2637 Ok(Expression::Mul(Box::new(BinaryOp::new(
2638 Self::function("DATALENGTH", vec![args.remove(0)]),
2639 Expression::number(8),
2640 ))))
2641 }
2642
2643 "TO_HEX" if f.args.len() == 1 => {
2647 let mut args = f.args;
2648 Ok(Self::tsql_postgres_to_hex(args.remove(0)))
2649 }
2650
2651 "ENCODE" if f.args.len() == 2 => {
2653 let mut args = f.args;
2654 let this = args.remove(0);
2655 let encoding = args.remove(0);
2656 if Self::literal_string(&encoding)
2657 .is_some_and(|encoding| encoding.eq_ignore_ascii_case("hex"))
2658 {
2659 Ok(Self::tsql_hex_from_varbinary(this))
2660 } else {
2661 Ok(Expression::Function(Box::new(Function::new(
2662 "ENCODE".to_string(),
2663 vec![this, encoding],
2664 ))))
2665 }
2666 }
2667
2668 "DECODE"
2671 if f.args.len() == 2
2672 && Self::literal_string(&f.args[1])
2673 .is_some_and(|format| format.eq_ignore_ascii_case("hex")) =>
2674 {
2675 let mut args = f.args;
2676 Ok(Self::tsql_convert(
2677 DataType::Custom {
2678 name: "VARBINARY(MAX)".to_string(),
2679 },
2680 args.remove(0),
2681 Some(2),
2682 ))
2683 }
2684
2685 "REPEAT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
2687 "REPLICATE".to_string(),
2688 f.args,
2689 )))),
2690
2691 "CHR" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2693 "CHAR".to_string(),
2694 f.args,
2695 )))),
2696
2697 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2699 seed: None,
2700 lower: None,
2701 upper: None,
2702 }))),
2703
2704 "NOW" => Ok(Self::getdate()),
2706
2707 "CURRENT_TIMESTAMP" => Ok(Self::getdate()),
2709
2710 "CURRENT_DATE" => Ok(Self::cast_getdate_to(DataType::Date)),
2712
2713 "CURRENT_TIME" => Ok(Self::cast_getdate_to(DataType::Time {
2715 precision: None,
2716 timezone: false,
2717 })),
2718
2719 "LOCALTIMESTAMP" => Ok(Self::getdate()),
2721
2722 "CLOCK_TIMESTAMP" if f.args.is_empty() => Ok(Self::function("SYSDATETIME", vec![])),
2724
2725 "MAKE_DATE" if f.args.len() == 3 => Ok(Self::function("DATEFROMPARTS", f.args)),
2727
2728 "MAKE_TIME" if f.args.len() == 3 => Ok(Self::make_time(f.args)),
2731
2732 "TO_DATE" if f.args.len() == 2 => {
2736 Self::formatted_str_to_date_or_fallback(f.args, "TO_DATE")
2737 }
2738
2739 "TO_DATE" if f.args.len() == 1 => {
2741 let mut args = f.args;
2742 Ok(Expression::Cast(Box::new(Cast {
2743 this: args.remove(0),
2744 to: DataType::Date,
2745 trailing_comments: Vec::new(),
2746 double_colon_syntax: false,
2747 format: None,
2748 default: None,
2749 inferred_type: None,
2750 })))
2751 }
2752
2753 "TO_TIMESTAMP" if f.args.len() == 2 => {
2756 Self::formatted_str_to_time_or_fallback(f.args, "TO_TIMESTAMP")
2757 }
2758
2759 "TO_TIMESTAMP" if f.args.len() == 1 => {
2761 let mut args = f.args;
2762 Ok(Expression::UnixToTime(Box::new(
2763 crate::expressions::UnixToTime {
2764 this: Box::new(args.remove(0)),
2765 scale: Some(0),
2766 zone: None,
2767 hours: None,
2768 minutes: None,
2769 format: None,
2770 target_type: None,
2771 },
2772 )))
2773 }
2774
2775 "TO_CHAR" if f.args.len() == 2 => {
2778 Self::formatted_time_to_str_or_fallback(f.args, "TO_CHAR")
2779 }
2780
2781 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
2783 "FORMAT".to_string(),
2784 f.args,
2785 )))),
2786
2787 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
2789 "FORMAT".to_string(),
2790 f.args,
2791 )))),
2792
2793 "DATE_TRUNC" | "DATETRUNC" => {
2796 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
2797 if args.len() >= 2 {
2799 if let Expression::Literal(lit) = &args[1] {
2800 if let Literal::String(_) = lit.as_ref() {
2801 args[1] = Expression::Cast(Box::new(Cast {
2802 this: args[1].clone(),
2803 to: DataType::Custom {
2804 name: "DATETIME2".to_string(),
2805 },
2806 trailing_comments: Vec::new(),
2807 double_colon_syntax: false,
2808 format: None,
2809 default: None,
2810 inferred_type: None,
2811 }));
2812 }
2813 }
2814 }
2815 Ok(Expression::Function(Box::new(Function::new(
2816 "DATETRUNC".to_string(),
2817 args,
2818 ))))
2819 }
2820
2821 "DATEADD" => {
2823 let args = Self::uppercase_first_arg_if_identifier(f.args);
2824 Ok(Expression::Function(Box::new(Function::new(
2825 "DATEADD".to_string(),
2826 args,
2827 ))))
2828 }
2829
2830 "DATEDIFF" => {
2832 let args = Self::uppercase_first_arg_if_identifier(f.args);
2833 Ok(Expression::Function(Box::new(Function::new(
2834 "DATEDIFF".to_string(),
2835 args,
2836 ))))
2837 }
2838
2839 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2841 "DATEPART".to_string(),
2842 f.args,
2843 )))),
2844
2845 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
2847 Ok(Expression::Function(Box::new(Function::new(
2849 "CHARINDEX".to_string(),
2850 f.args,
2851 ))))
2852 }
2853
2854 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2856
2857 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
2859 Function::new("CEILING".to_string(), f.args),
2860 ))),
2861
2862 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2867 "JSON_VALUE".to_string(),
2868 f.args,
2869 )))),
2870
2871 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2873 "JSON_VALUE".to_string(),
2874 f.args,
2875 )))),
2876
2877 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
2879
2880 "GET_PATH" if f.args.len() == 2 => {
2882 let mut args = f.args;
2883 let this = args.remove(0);
2884 let path = args.remove(0);
2885 let json_path = match &path {
2886 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
2887 let Literal::String(s) = lit.as_ref() else {
2888 unreachable!()
2889 };
2890 let normalized = if s.starts_with('$') {
2891 s.clone()
2892 } else if s.starts_with('[') {
2893 format!("${}", s)
2894 } else {
2895 format!("$.{}", s)
2896 };
2897 Expression::Literal(Box::new(Literal::String(normalized)))
2898 }
2899 _ => path,
2900 };
2901 let json_query = Expression::Function(Box::new(Function::new(
2903 "JSON_QUERY".to_string(),
2904 vec![this.clone(), json_path.clone()],
2905 )));
2906 let json_value = Expression::Function(Box::new(Function::new(
2907 "JSON_VALUE".to_string(),
2908 vec![this, json_path],
2909 )));
2910 Ok(Expression::Function(Box::new(Function::new(
2911 "ISNULL".to_string(),
2912 vec![json_query, json_value],
2913 ))))
2914 }
2915
2916 "JSON_QUERY" if f.args.len() == 1 => {
2919 let this = f.args.into_iter().next().unwrap();
2920 let path = Expression::Literal(Box::new(Literal::String("$".to_string())));
2921 let json_query = Expression::Function(Box::new(Function::new(
2922 "JSON_QUERY".to_string(),
2923 vec![this.clone(), path.clone()],
2924 )));
2925 let json_value = Expression::Function(Box::new(Function::new(
2926 "JSON_VALUE".to_string(),
2927 vec![this, path],
2928 )));
2929 Ok(Expression::Function(Box::new(Function::new(
2930 "ISNULL".to_string(),
2931 vec![json_query, json_value],
2932 ))))
2933 }
2934
2935 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
2937 "STRING_SPLIT".to_string(),
2938 f.args,
2939 )))),
2940
2941 "REGEXP_LIKE" => {
2944 Ok(Expression::Function(Box::new(Function::new(
2946 "PATINDEX".to_string(),
2947 f.args,
2948 ))))
2949 }
2950
2951 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2953 "LOG".to_string(),
2954 f.args,
2955 )))),
2956
2957 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2962 "STDEV".to_string(),
2963 f.args,
2964 )))),
2965
2966 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
2968 "STDEVP".to_string(),
2969 f.args,
2970 )))),
2971
2972 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2974 "VAR".to_string(),
2975 f.args,
2976 )))),
2977
2978 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2980 "VARP".to_string(),
2981 f.args,
2982 )))),
2983
2984 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
2986 let mut args = f.args;
2987 Self::transform_logical_aggregate(args.remove(0), None, "MIN")
2988 }
2989 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
2990 let mut args = f.args;
2991 Self::transform_logical_aggregate(args.remove(0), None, "MAX")
2992 }
2993
2994 "DATE_ADD" => {
2996 if f.args.len() == 2 {
2997 let mut args = f.args;
2998 let date = args.remove(0);
2999 let interval = args.remove(0);
3000 let unit = Expression::Identifier(crate::expressions::Identifier {
3001 name: "DAY".to_string(),
3002 quoted: false,
3003 trailing_comments: Vec::new(),
3004 span: None,
3005 });
3006 Ok(Expression::Function(Box::new(Function::new(
3007 "DATEADD".to_string(),
3008 vec![unit, interval, date],
3009 ))))
3010 } else {
3011 let args = Self::uppercase_first_arg_if_identifier(f.args);
3012 Ok(Expression::Function(Box::new(Function::new(
3013 "DATEADD".to_string(),
3014 args,
3015 ))))
3016 }
3017 }
3018
3019 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
3021 "STUFF".to_string(),
3022 f.args,
3023 )))),
3024
3025 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
3027 crate::expressions::CurrentUser { this: None },
3028 ))),
3029
3030 _ => Ok(Expression::Function(Box::new(f))),
3032 }
3033 }
3034
3035 fn literal_string(expr: &Expression) -> Option<&str> {
3036 match expr {
3037 Expression::Literal(lit) => match lit.as_ref() {
3038 Literal::String(s) => Some(s),
3039 _ => None,
3040 },
3041 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast)
3042 if Self::is_text_data_type(&cast.to) =>
3043 {
3044 Self::literal_string(&cast.this)
3045 }
3046 _ => None,
3047 }
3048 }
3049
3050 fn is_text_data_type(data_type: &DataType) -> bool {
3051 match data_type {
3052 DataType::Char { .. }
3053 | DataType::VarChar { .. }
3054 | DataType::String { .. }
3055 | DataType::Text
3056 | DataType::TextWithLength { .. } => true,
3057 DataType::Custom { name } => {
3058 let base = name
3059 .split_once('(')
3060 .map_or(name.as_str(), |(base, _)| base)
3061 .trim();
3062 matches!(
3063 base.to_ascii_uppercase().as_str(),
3064 "CHAR"
3065 | "NCHAR"
3066 | "VARCHAR"
3067 | "NVARCHAR"
3068 | "TEXT"
3069 | "NTEXT"
3070 | "STRING"
3071 | "CHARACTER VARYING"
3072 )
3073 }
3074 _ => false,
3075 }
3076 }
3077
3078 fn is_numeric_data_type(data_type: &DataType) -> bool {
3079 match data_type {
3080 DataType::TinyInt { .. }
3081 | DataType::SmallInt { .. }
3082 | DataType::Int { .. }
3083 | DataType::BigInt { .. }
3084 | DataType::Float { .. }
3085 | DataType::Double { .. }
3086 | DataType::Decimal { .. } => true,
3087 DataType::Custom { name } => {
3088 let base = name
3089 .split_once('(')
3090 .map_or(name.as_str(), |(base, _)| base)
3091 .trim();
3092 matches!(
3093 base.to_ascii_uppercase().as_str(),
3094 "TINYINT"
3095 | "SMALLINT"
3096 | "INT"
3097 | "INTEGER"
3098 | "BIGINT"
3099 | "DECIMAL"
3100 | "NUMERIC"
3101 | "REAL"
3102 | "FLOAT"
3103 | "MONEY"
3104 | "SMALLMONEY"
3105 )
3106 }
3107 _ => false,
3108 }
3109 }
3110
3111 fn is_explicitly_numeric_expression(expr: &Expression) -> bool {
3112 if expr.inferred_type().is_some_and(Self::is_numeric_data_type) {
3113 return true;
3114 }
3115
3116 match expr {
3117 Expression::Literal(literal) => matches!(literal.as_ref(), Literal::Number(_)),
3118 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
3119 Self::is_numeric_data_type(&cast.to)
3120 }
3121 Expression::Alias(alias) => Self::is_explicitly_numeric_expression(&alias.this),
3122 Expression::Paren(paren) => Self::is_explicitly_numeric_expression(&paren.this),
3123 Expression::Neg(unary) => Self::is_explicitly_numeric_expression(&unary.this),
3124 _ => false,
3125 }
3126 }
3127
3128 fn postgres_format_to_strftime(format: &str) -> String {
3129 const POSTGRES_FORMAT_TO_STRFTIME: &[(&str, &str)] = &[
3130 ("FMHH24", "%-H"),
3131 ("FMHH12", "%-I"),
3132 ("FMDDD", "%-j"),
3133 ("TMMonth", "%B"),
3134 ("TMMon", "%b"),
3135 ("TMDay", "%A"),
3136 ("TMDy", "%a"),
3137 ("YYYY", "%Y"),
3138 ("yyyy", "%Y"),
3139 ("HH24", "%H"),
3140 ("HH12", "%I"),
3141 ("FMDD", "%-d"),
3142 ("FMMM", "%-m"),
3143 ("FMMI", "%-M"),
3144 ("FMSS", "%-S"),
3145 ("DDD", "%j"),
3146 ("ddd", "%j"),
3147 ("YY", "%y"),
3148 ("yy", "%y"),
3149 ("MM", "%m"),
3150 ("mm", "%m"),
3151 ("DD", "%d"),
3152 ("dd", "%d"),
3153 ("MI", "%M"),
3154 ("mi", "%M"),
3155 ("SS", "%S"),
3156 ("ss", "%S"),
3157 ("US", "%f"),
3158 ("OF", "%z"),
3159 ("TZ", "%Z"),
3160 ("WW", "%U"),
3161 ("ww", "%U"),
3162 ("D", "%u"),
3163 ("d", "%u"),
3164 ];
3165 crate::format_tokens::convert_format_tokens(format, POSTGRES_FORMAT_TO_STRFTIME)
3166 .unwrap_or_else(|| format.to_string())
3167 }
3168
3169 fn formatted_str_to_time_or_fallback(
3170 mut args: Vec<Expression>,
3171 original_name: &str,
3172 ) -> Result<Expression> {
3173 let this = args.remove(0);
3174 let format = args.remove(0);
3175 if let Some(format) = Self::literal_string(&format) {
3176 Ok(Expression::StrToTime(Box::new(
3177 crate::expressions::StrToTime {
3178 this: Box::new(this),
3179 format: Self::postgres_format_to_strftime(format),
3180 zone: None,
3181 safe: None,
3182 target_type: Some(Box::new(Expression::DataType(DataType::Custom {
3183 name: "DATETIME2".to_string(),
3184 }))),
3185 },
3186 )))
3187 } else {
3188 Ok(Expression::Function(Box::new(Function::new(
3189 original_name.to_string(),
3190 vec![this, format],
3191 ))))
3192 }
3193 }
3194
3195 fn formatted_str_to_date_or_fallback(
3196 mut args: Vec<Expression>,
3197 original_name: &str,
3198 ) -> Result<Expression> {
3199 let this = args.remove(0);
3200 let format = args.remove(0);
3201 if let Some(format) = Self::literal_string(&format) {
3202 Ok(Expression::StrToDate(Box::new(
3203 crate::expressions::StrToDate {
3204 this: Box::new(this),
3205 format: Some(Self::postgres_format_to_strftime(format)),
3206 safe: None,
3207 },
3208 )))
3209 } else {
3210 Ok(Expression::Function(Box::new(Function::new(
3211 original_name.to_string(),
3212 vec![this, format],
3213 ))))
3214 }
3215 }
3216
3217 fn push_postgres_to_char_literal(result: &mut String, ch: char) {
3218 if matches!(
3219 ch,
3220 'F' | 'H'
3221 | 'K'
3222 | 'M'
3223 | 'd'
3224 | 'f'
3225 | 'g'
3226 | 'h'
3227 | 'm'
3228 | 's'
3229 | 't'
3230 | 'y'
3231 | 'z'
3232 | '%'
3233 | ':'
3234 | '/'
3235 | '"'
3236 | '\''
3237 | '\\'
3238 ) {
3239 result.push('\\');
3240 }
3241 result.push(ch);
3242 }
3243
3244 fn classify_postgres_to_char_format(format: &str) -> PostgresToCharFormat {
3245 const SUPPORTED: &[(&str, &str, bool)] = &[
3246 ("FMHH24", "%-H", false),
3247 ("FMHH12", "%-I", false),
3248 ("FMHH", "%-I", false),
3249 ("FMMonth", "%B", true),
3250 ("FMMon", "%b", true),
3251 ("FMDay", "%A", true),
3252 ("FMDy", "%a", true),
3253 ("TMMonth", "%B", false),
3254 ("TMMon", "%b", false),
3255 ("TMDay", "%A", false),
3256 ("TMDy", "%a", false),
3257 ("YYYY", "%Y", false),
3258 ("yyyy", "%Y", false),
3259 ("HH24", "%H", false),
3260 ("HH12", "%I", false),
3261 ("FMDD", "%-d", false),
3262 ("FMMM", "%-m", false),
3263 ("FMMI", "%-M", false),
3264 ("FMSS", "%-S", false),
3265 ("HH", "%I", false),
3266 ("YY", "%y", false),
3267 ("yy", "%y", false),
3268 ("MM", "%m", false),
3269 ("mm", "%m", false),
3270 ("DD", "%d", false),
3271 ("dd", "%d", false),
3272 ("MI", "%M", false),
3273 ("mi", "%M", false),
3274 ("SS", "%S", false),
3275 ("ss", "%S", false),
3276 ("US", "%f", false),
3277 ("Dy", "%a", true),
3278 ("Mon", "%b", true),
3279 ];
3280 const POSTGRES_TOKENS: &[&str] = &[
3281 "SSSSS", "SSSS", "IYYY", "IDDD", "MONTH", "Month", "month", "HH24", "HH12", "FMMONTH",
3282 "FMMonth", "FMmonth", "FMDAY", "FMDay", "FMday", "FMMON", "FMMon", "FMmon", "FMDY",
3283 "FMDy", "FMdy", "TMMonth", "TMMon", "TMDay", "TMDy", "Y,YYY", "A.M.", "a.m.", "P.M.",
3284 "p.m.", "FMRM", "FMrm", "IYY", "YYY", "yyyy", "YYYY", "DDD", "ddd", "DAY", "Day",
3285 "day", "MON", "Mon", "mon", "DY", "Dy", "dy", "TZH", "TZM", "FF1", "FF2", "FF3", "FF4",
3286 "FF5", "FF6", "FMHH24", "FMHH12", "FMHH", "FMDDD", "FMDD", "FMMM", "FMMI", "FMSS",
3287 "HH", "IY", "YY", "yy", "MM", "mm", "DD", "dd", "MI", "mi", "SS", "ss", "MS", "US",
3288 "AM", "am", "PM", "pm", "BC", "bc", "AD", "ad", "B.C.", "b.c.", "A.D.", "a.d.", "ID",
3289 "WW", "ww", "IW", "CC", "RM", "rm", "TZ", "tz", "OF", "I", "Y", "y", "D", "d", "W",
3290 "J", "Q",
3291 ];
3292
3293 fn longest_token_at(input: &str, index: usize) -> Option<usize> {
3294 POSTGRES_TOKENS
3295 .iter()
3296 .filter(|token| input[index..].starts_with(**token))
3297 .map(|token| token.len())
3298 .max()
3299 }
3300
3301 let mut result = String::with_capacity(format.len() * 2);
3302 let mut index = 0;
3303 let mut requires_english_culture = false;
3304
3305 while index < format.len() {
3306 if format[index..].starts_with('\\') {
3307 index += 1;
3308 if format[index..].starts_with('"') {
3309 Self::push_postgres_to_char_literal(&mut result, '"');
3310 index += 1;
3311 } else {
3312 Self::push_postgres_to_char_literal(&mut result, '\\');
3315 }
3316 continue;
3317 }
3318
3319 if format[index..].starts_with('"') {
3320 index += 1;
3321 let mut closed = false;
3322 while index < format.len() {
3323 let Some(ch) = format[index..].chars().next() else {
3324 return PostgresToCharFormat::Unsupported;
3325 };
3326 index += ch.len_utf8();
3327 if ch == '"' {
3328 closed = true;
3329 break;
3330 }
3331 if ch == '\\' && index < format.len() {
3332 let Some(escaped) = format[index..].chars().next() else {
3333 return PostgresToCharFormat::Unsupported;
3334 };
3335 index += escaped.len_utf8();
3336 Self::push_postgres_to_char_literal(&mut result, escaped);
3337 } else {
3338 Self::push_postgres_to_char_literal(&mut result, ch);
3339 }
3340 }
3341 if !closed {
3342 return PostgresToCharFormat::Unsupported;
3343 }
3344 continue;
3345 }
3346
3347 let remaining = &format[index..];
3348 let ch = remaining
3349 .chars()
3350 .next()
3351 .expect("format index should be on a character boundary");
3352 if matches!(ch, '9' | '0')
3353 || ["PR", "SG", "PL", "RN", "EEEE"].iter().any(|token| {
3354 remaining
3355 .get(..token.len())
3356 .is_some_and(|prefix| prefix.eq_ignore_ascii_case(token))
3357 })
3358 {
3359 return PostgresToCharFormat::Numeric;
3360 }
3361
3362 let supported = SUPPORTED
3363 .iter()
3364 .filter(|(token, _, _)| format[index..].starts_with(token))
3365 .max_by_key(|(token, _, _)| token.len());
3366 let recognized_len =
3367 if format[index..].starts_with("FM") || format[index..].starts_with("TM") {
3368 longest_token_at(format, index + 2).map(|len| len + 2)
3369 } else {
3370 longest_token_at(format, index)
3371 };
3372
3373 if let Some((token, replacement, english_culture)) = supported {
3374 if recognized_len.is_some_and(|len| len > token.len()) {
3375 return PostgresToCharFormat::Unsupported;
3376 }
3377 let end = index + token.len();
3378 if format[end..].starts_with("TH")
3379 || format[end..].starts_with("th")
3380 || format[end..].starts_with("SP")
3381 {
3382 return PostgresToCharFormat::Unsupported;
3383 }
3384 result.push_str(replacement);
3385 requires_english_culture |= english_culture;
3386 index = end;
3387 continue;
3388 }
3389
3390 if recognized_len.is_some() || format[index..].starts_with("FX") {
3391 return PostgresToCharFormat::Unsupported;
3392 }
3393
3394 Self::push_postgres_to_char_literal(&mut result, ch);
3395 index += ch.len_utf8();
3396 }
3397
3398 PostgresToCharFormat::Temporal {
3399 strftime: result,
3400 requires_english_culture,
3401 }
3402 }
3403
3404 fn formatted_time_to_str_or_fallback(
3405 mut args: Vec<Expression>,
3406 original_name: &str,
3407 ) -> Result<Expression> {
3408 let this = args.remove(0);
3409 let format = args.remove(0);
3410 if let Some(format_string) = Self::literal_string(&format).map(str::to_owned) {
3411 if Self::is_explicitly_numeric_expression(&this) {
3412 return Ok(Expression::Function(Box::new(Function::new(
3413 original_name.to_string(),
3414 vec![this, format],
3415 ))));
3416 }
3417
3418 let (format_string, requires_english_culture) =
3419 match Self::classify_postgres_to_char_format(&format_string) {
3420 PostgresToCharFormat::Temporal {
3421 strftime,
3422 requires_english_culture,
3423 } => (strftime, requires_english_culture),
3424 PostgresToCharFormat::Numeric | PostgresToCharFormat::Unsupported => {
3425 return Ok(Expression::Function(Box::new(Function::new(
3426 original_name.to_string(),
3427 vec![this, format],
3428 ))));
3429 }
3430 };
3431
3432 Ok(Expression::TimeToStr(Box::new(
3433 crate::expressions::TimeToStr {
3434 this: Box::new(this),
3435 format: format_string,
3436 culture: requires_english_culture
3437 .then(|| Box::new(Expression::string("en-US"))),
3438 zone: None,
3439 },
3440 )))
3441 } else {
3442 Ok(Expression::Function(Box::new(Function::new(
3443 original_name.to_string(),
3444 vec![this, format],
3445 ))))
3446 }
3447 }
3448
3449 fn transform_aggregate_function(
3450 &self,
3451 mut f: Box<crate::expressions::AggregateFunction>,
3452 ) -> Result<Expression> {
3453 let name_upper = f.name.to_uppercase();
3454 if matches!(
3455 name_upper.as_str(),
3456 "SUM"
3457 | "AVG"
3458 | "MIN"
3459 | "MAX"
3460 | "COUNT"
3461 | "COUNT_BIG"
3462 | "ANY_VALUE"
3463 | "APPROX_COUNT_DISTINCT"
3464 | "STDEV"
3465 | "STDEVP"
3466 | "VAR"
3467 | "VARP"
3468 | "BOOL_AND"
3469 | "BOOL_OR"
3470 | "LOGICAL_AND"
3471 | "LOGICAL_OR"
3472 | "BIT_AND"
3473 | "BIT_OR"
3474 | "BIT_XOR"
3475 ) {
3476 f.order_by.clear();
3477 }
3478
3479 match name_upper.as_str() {
3480 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3482 Function::new("STRING_AGG".to_string(), f.args),
3483 ))),
3484
3485 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3487 "STRING_AGG".to_string(),
3488 f.args,
3489 )))),
3490
3491 "ARRAY_AGG" if !f.args.is_empty() => {
3494 Ok(Expression::Function(Box::new(Function::new(
3496 "STRING_AGG".to_string(),
3497 f.args,
3498 ))))
3499 }
3500
3501 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
3503 let mut args = f.args;
3504 Self::transform_logical_aggregate(args.remove(0), f.filter, "MIN")
3505 }
3506 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
3507 let mut args = f.args;
3508 Self::transform_logical_aggregate(args.remove(0), f.filter, "MAX")
3509 }
3510
3511 _ => Ok(Expression::AggregateFunction(f)),
3513 }
3514 }
3515
3516 fn without_inert_ordering(
3517 mut aggregate: Box<crate::expressions::AggFunc>,
3518 ) -> Box<crate::expressions::AggFunc> {
3519 aggregate.order_by.clear();
3520 aggregate
3521 }
3522
3523 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
3527 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
3528 }
3529
3530 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
3532 if cte.columns.is_empty() {
3535 cte.this = self.qualify_derived_table_outputs(cte.this);
3536 }
3537 cte
3538 }
3539
3540 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
3544 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
3547 subquery.this = self.qualify_derived_table_outputs(subquery.this);
3548 }
3549 Ok(Expression::Subquery(Box::new(subquery)))
3550 }
3551
3552 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
3556 match expr {
3557 Expression::Select(mut select) => {
3558 let has_from = select.from.is_some();
3561 if !has_from {
3562 select.expressions = select
3563 .expressions
3564 .into_iter()
3565 .map(|e| self.maybe_alias_expression(e))
3566 .collect();
3567 }
3568 Expression::Select(select)
3569 }
3570 Expression::Union(mut u) => {
3572 let left = std::mem::replace(&mut u.left, Expression::Null(Null));
3573 u.left = self.qualify_derived_table_outputs(left);
3574 Expression::Union(u)
3575 }
3576 Expression::Intersect(mut i) => {
3577 let left = std::mem::replace(&mut i.left, Expression::Null(Null));
3578 i.left = self.qualify_derived_table_outputs(left);
3579 Expression::Intersect(i)
3580 }
3581 Expression::Except(mut e) => {
3582 let left = std::mem::replace(&mut e.left, Expression::Null(Null));
3583 e.left = self.qualify_derived_table_outputs(left);
3584 Expression::Except(e)
3585 }
3586 Expression::Subquery(mut s) => {
3588 s.this = self.qualify_derived_table_outputs(s.this);
3589 Expression::Subquery(s)
3590 }
3591 other => other,
3593 }
3594 }
3595
3596 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
3601 match &expr {
3602 Expression::Alias(_) => expr,
3604 Expression::Aliases(_) => expr,
3606 Expression::Star(_) => expr,
3608 _ => {
3613 if let Some(output_name) = self.get_output_name(&expr) {
3614 Expression::Alias(Box::new(Alias {
3615 this: expr,
3616 alias: Identifier {
3617 name: output_name,
3618 quoted: true, trailing_comments: Vec::new(),
3620 span: None,
3621 },
3622 column_aliases: Vec::new(),
3623 alias_explicit_as: false,
3624 alias_keyword: None,
3625 pre_alias_comments: Vec::new(),
3626 trailing_comments: Vec::new(),
3627 inferred_type: None,
3628 }))
3629 } else {
3630 expr
3632 }
3633 }
3634 }
3635 }
3636
3637 fn get_output_name(&self, expr: &Expression) -> Option<String> {
3641 match expr {
3642 Expression::Literal(lit) => match lit.as_ref() {
3644 Literal::Number(n) => Some(n.clone()),
3645 Literal::String(s) => Some(s.clone()),
3646 Literal::HexString(h) => Some(format!("0x{}", h)),
3647 Literal::HexNumber(h) => Some(format!("0x{}", h)),
3648 Literal::BitString(b) => Some(format!("b{}", b)),
3649 Literal::ByteString(b) => Some(format!("b'{}'", b)),
3650 Literal::NationalString(s) => Some(format!("N'{}'", s)),
3651 Literal::Date(d) => Some(d.clone()),
3652 Literal::Time(t) => Some(t.clone()),
3653 Literal::Timestamp(ts) => Some(ts.clone()),
3654 Literal::Datetime(dt) => Some(dt.clone()),
3655 Literal::TripleQuotedString(s, _) => Some(s.clone()),
3656 Literal::EscapeString(s) => Some(s.clone()),
3657 Literal::DollarString(s) => Some(s.clone()),
3658 Literal::RawString(s) => Some(s.clone()),
3659 },
3660 Expression::Column(col) => Some(col.name.name.clone()),
3662 Expression::Identifier(ident) => Some(ident.name.clone()),
3664 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
3666 Expression::Null(_) => Some("NULL".to_string()),
3668 Expression::Function(f) => Some(f.name.clone()),
3670 Expression::AggregateFunction(f) => Some(f.name.clone()),
3672 _ => Some(format!("_col_{}", 0)),
3674 }
3675 }
3676
3677 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
3679 use crate::expressions::Identifier;
3680 if !args.is_empty() {
3681 match &args[0] {
3682 Expression::Identifier(id) => {
3683 args[0] = Expression::Identifier(Identifier {
3684 name: id.name.to_uppercase(),
3685 quoted: id.quoted,
3686 trailing_comments: id.trailing_comments.clone(),
3687 span: None,
3688 });
3689 }
3690 Expression::Var(v) => {
3691 args[0] = Expression::Identifier(Identifier {
3692 name: v.this.to_uppercase(),
3693 quoted: false,
3694 trailing_comments: Vec::new(),
3695 span: None,
3696 });
3697 }
3698 Expression::Column(col) if col.table.is_none() => {
3699 args[0] = Expression::Identifier(Identifier {
3700 name: col.name.name.to_uppercase(),
3701 quoted: col.name.quoted,
3702 trailing_comments: col.name.trailing_comments.clone(),
3703 span: None,
3704 });
3705 }
3706 _ => {}
3707 }
3708 }
3709 args
3710 }
3711}
3712
3713#[cfg(test)]
3714mod tests {
3715 use super::*;
3716 use crate::dialects::Dialect;
3717
3718 fn transpile_to_tsql(sql: &str) -> String {
3719 let dialect = Dialect::get(DialectType::Generic);
3720 let result = dialect
3721 .transpile(sql, DialectType::TSQL)
3722 .expect("Transpile failed");
3723 result[0].clone()
3724 }
3725
3726 #[test]
3727 fn test_nvl_to_isnull() {
3728 let result = transpile_to_tsql("SELECT NVL(a, b)");
3729 assert!(
3730 result.contains("ISNULL"),
3731 "Expected ISNULL, got: {}",
3732 result
3733 );
3734 }
3735
3736 #[test]
3737 fn test_coalesce_to_isnull() {
3738 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
3739 assert!(
3740 result.contains("ISNULL"),
3741 "Expected ISNULL, got: {}",
3742 result
3743 );
3744 }
3745
3746 #[test]
3747 fn test_basic_select() {
3748 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
3749 assert!(result.contains("SELECT"));
3750 assert!(result.contains("FROM users"));
3751 }
3752
3753 #[test]
3754 fn test_length_to_len() {
3755 let result = transpile_to_tsql("SELECT LENGTH(name)");
3756 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
3757 }
3758
3759 #[test]
3760 fn test_issue_374_tsql_parse_then_generate_uses_len() {
3761 let sql = "SELECT LEN(table.col1) - LEN(table.col2) FROM table";
3762 let ast = Dialect::get(DialectType::TSQL)
3763 .parse(sql)
3764 .expect("T-SQL should parse");
3765 let expression = &ast[0];
3766
3767 for target in [DialectType::TSQL, DialectType::Fabric] {
3768 let generated = Dialect::get(target)
3769 .generate(expression)
3770 .expect("AST should generate");
3771 assert_eq!(generated, sql, "failed for target {target:?}");
3772 }
3773
3774 let standard_sql = "SELECT LENGTH(table.col1) - LENGTH(table.col2) FROM table";
3775 for target in [DialectType::Generic, DialectType::PostgreSQL] {
3776 let generated = Dialect::get(target)
3777 .generate(expression)
3778 .expect("AST should generate");
3779 assert_eq!(generated, standard_sql, "failed for target {target:?}");
3780 }
3781 }
3782
3783 #[test]
3784 fn test_now_to_getdate() {
3785 let result = transpile_to_tsql("SELECT NOW()");
3786 assert!(
3787 result.contains("GETDATE"),
3788 "Expected GETDATE, got: {}",
3789 result
3790 );
3791 }
3792
3793 #[test]
3794 fn test_group_concat_to_string_agg() {
3795 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
3796 assert!(
3797 result.contains("STRING_AGG"),
3798 "Expected STRING_AGG, got: {}",
3799 result
3800 );
3801 }
3802
3803 #[test]
3804 fn test_listagg_to_string_agg() {
3805 let result = transpile_to_tsql("SELECT LISTAGG(name)");
3806 assert!(
3807 result.contains("STRING_AGG"),
3808 "Expected STRING_AGG, got: {}",
3809 result
3810 );
3811 }
3812
3813 #[test]
3814 fn test_ln_to_log() {
3815 let result = transpile_to_tsql("SELECT LN(x)");
3816 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
3817 }
3818
3819 #[test]
3820 fn test_stddev_to_stdev() {
3821 let result = transpile_to_tsql("SELECT STDDEV(x)");
3822 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
3823 }
3824
3825 #[test]
3826 fn test_bracket_identifiers() {
3827 let dialect = Dialect::get(DialectType::TSQL);
3829 let config = dialect.generator_config();
3830 assert_eq!(config.identifier_quote, '[');
3831 }
3832
3833 #[test]
3834 fn test_json_query_isnull_wrapper_simple() {
3835 let dialect = Dialect::get(DialectType::TSQL);
3837 let result = dialect
3838 .transpile(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
3839 .expect("transpile failed");
3840 assert!(
3841 result[0].contains("ISNULL"),
3842 "JSON_QUERY should be wrapped with ISNULL: {}",
3843 result[0]
3844 );
3845 }
3846
3847 #[test]
3848 fn test_json_query_isnull_wrapper_nested() {
3849 let dialect = Dialect::get(DialectType::TSQL);
3850 let result = dialect
3851 .transpile(
3852 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
3853 DialectType::TSQL,
3854 )
3855 .expect("transpile failed");
3856 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
3857 assert_eq!(
3858 result[0], expected,
3859 "JSON_QUERY should be wrapped with ISNULL"
3860 );
3861 }
3862}