1use super::{DialectImpl, DialectType};
14use crate::error::Result;
15use crate::expressions::{
16 Alias, BinaryOp, Cast, Column, Cte, DataType, Exists, Expression, Function, Identifier, In,
17 Join, JoinKind, LikeOp, Literal, Null, Over, QuantifiedOp, Select, StringAggFunc, Subquery,
18 UnaryFunc, Where,
19};
20#[cfg(feature = "generate")]
21use crate::generator::GeneratorConfig;
22use crate::tokens::TokenizerConfig;
23use std::collections::HashMap;
24
25pub struct TSQLDialect;
27
28impl DialectImpl for TSQLDialect {
29 fn dialect_type(&self) -> DialectType {
30 DialectType::TSQL
31 }
32
33 fn tokenizer_config(&self) -> TokenizerConfig {
34 let mut config = TokenizerConfig::default();
35 config.identifiers.insert('[', ']');
37 config.identifiers.insert('"', '"');
39 config.hex_number_strings = true;
41 config
42 }
43
44 #[cfg(feature = "generate")]
45
46 fn generator_config(&self) -> GeneratorConfig {
47 use crate::generator::IdentifierQuoteStyle;
48 GeneratorConfig {
49 identifier_quote: '[',
51 identifier_quote_style: IdentifierQuoteStyle::BRACKET,
52 dialect: Some(DialectType::TSQL),
53 limit_fetch_style: crate::generator::LimitFetchStyle::FetchFirst,
56 null_ordering_supported: false,
58 aggregate_filter_supported: false,
60 supports_select_into: true,
62 alter_table_include_column_keyword: false,
64 computed_column_with_type: false,
66 cte_recursive_keyword_required: false,
68 ensure_bools: true,
70 supports_single_arg_concat: false,
72 tablesample_seed_keyword: "REPEATABLE",
74 json_path_bracketed_key_supported: false,
76 supports_to_number: false,
78 set_op_modifiers: false,
80 copy_params_eq_required: true,
82 except_intersect_support_all_clause: false,
84 alter_set_wrapped: true,
86 try_supported: true,
88 nvl2_supported: false,
90 parameter_default_equals: true,
92 supports_window_exclude: false,
94 multi_arg_distinct: false,
96 locking_reads_supported: false,
98 ..Default::default()
99 }
100 }
101
102 #[cfg(feature = "transpile")]
103
104 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
105 if let Expression::CreateTable(mut ct) = expr {
107 for col in &mut ct.columns {
108 if let Ok(Expression::DataType(new_dt)) =
109 self.transform_data_type(col.data_type.clone())
110 {
111 col.data_type = new_dt;
112 }
113 }
114 return Ok(Expression::CreateTable(ct));
115 }
116
117 match expr {
118 Expression::Select(mut select) => {
123 select.expressions = select
124 .expressions
125 .into_iter()
126 .map(|e| {
127 match e {
128 Expression::Eq(op) => {
129 match &op.left {
132 Expression::Column(col)
133 if col.table.is_none()
134 && !col.name.name.starts_with('@') =>
135 {
136 Expression::Alias(Box::new(Alias {
137 this: op.right,
138 alias: col.name.clone(),
139 column_aliases: Vec::new(),
140 alias_explicit_as: false,
141 alias_keyword: None,
142 pre_alias_comments: Vec::new(),
143 trailing_comments: Vec::new(),
144 inferred_type: None,
145 }))
146 }
147 Expression::Identifier(ident)
148 if !ident.name.starts_with('@') =>
149 {
150 Expression::Alias(Box::new(Alias {
151 this: op.right,
152 alias: ident.clone(),
153 column_aliases: Vec::new(),
154 alias_explicit_as: false,
155 alias_keyword: None,
156 pre_alias_comments: Vec::new(),
157 trailing_comments: Vec::new(),
158 inferred_type: None,
159 }))
160 }
161 _ => Expression::Eq(op),
162 }
163 }
164 other => other,
165 }
166 })
167 .collect();
168
169 Self::normalize_frame_incompatible_window_functions(&mut select);
170
171 let outer_qualifier = Self::single_select_source_qualifier(&select);
172 if let Some(ref mut where_clause) = select.where_clause {
173 where_clause.this = Self::rewrite_tuple_in_subquery_predicates(
174 std::mem::replace(&mut where_clause.this, Expression::Null(Null)),
175 outer_qualifier.as_ref(),
176 false,
177 );
178 }
179
180 if let Some(ref mut with) = select.with {
182 with.ctes = with
183 .ctes
184 .drain(..)
185 .map(|cte| self.transform_cte_inner(cte))
186 .collect();
187 }
188
189 Ok(Expression::Select(select))
190 }
191
192 Expression::DataType(dt) => self.transform_data_type(dt),
194
195 Expression::IsTrue(it) => {
198 let one = Expression::Literal(Box::new(crate::expressions::Literal::Number(
199 "1".to_string(),
200 )));
201 if it.not {
202 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
204 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
205 left: it.this,
206 right: one,
207 left_comments: vec![],
208 operator_comments: vec![],
209 trailing_comments: vec![],
210 inferred_type: None,
211 })),
212 inferred_type: None,
213 })))
214 } else {
215 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
217 left: it.this,
218 right: one,
219 left_comments: vec![],
220 operator_comments: vec![],
221 trailing_comments: vec![],
222 inferred_type: None,
223 })))
224 }
225 }
226 Expression::IsFalse(it) => {
227 let zero = Expression::Literal(Box::new(crate::expressions::Literal::Number(
228 "0".to_string(),
229 )));
230 if it.not {
231 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
233 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
234 left: it.this,
235 right: zero,
236 left_comments: vec![],
237 operator_comments: vec![],
238 trailing_comments: vec![],
239 inferred_type: None,
240 })),
241 inferred_type: None,
242 })))
243 } else {
244 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
246 left: it.this,
247 right: zero,
248 left_comments: vec![],
249 operator_comments: vec![],
250 trailing_comments: vec![],
251 inferred_type: None,
252 })))
253 }
254 }
255
256 Expression::In(mut in_expr) if in_expr.not => {
260 in_expr.not = false;
261 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
262 this: Expression::In(in_expr),
263 inferred_type: None,
264 })))
265 }
266
267 Expression::Coalesce(f) if f.expressions.len() == 2 => Ok(Expression::Function(
270 Box::new(Function::new("ISNULL".to_string(), f.expressions)),
271 )),
272
273 Expression::Nvl(f) => Ok(Expression::Function(Box::new(Function::new(
275 "ISNULL".to_string(),
276 vec![f.this, f.expression],
277 )))),
278
279 Expression::GroupConcat(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
281 this: f.this,
282 separator: f.separator,
283 order_by: f.order_by,
284 distinct: f.distinct,
285 filter: f.filter,
286 limit: None,
287 inferred_type: None,
288 }))),
289
290 Expression::ListAgg(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
292 this: f.this,
293 separator: f.separator,
294 order_by: f.order_by,
295 distinct: f.distinct,
296 filter: f.filter,
297 limit: None,
298 inferred_type: None,
299 }))),
300
301 Expression::LogicalAnd(f) => Self::transform_logical_aggregate(f.this, f.filter, "MIN"),
304 Expression::LogicalOr(f) => Self::transform_logical_aggregate(f.this, f.filter, "MAX"),
305
306 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
308
309 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
311
312 Expression::ILike(op) => {
314 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
317 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
318 Ok(Expression::Like(Box::new(LikeOp {
319 left: lower_left,
320 right: lower_right,
321 escape: op.escape,
322 quantifier: op.quantifier,
323 inferred_type: None,
324 })))
325 }
326
327 Expression::Concat(op) => {
330 Ok(Expression::Add(op))
332 }
333
334 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
336 seed: None,
337 lower: None,
338 upper: None,
339 }))),
340
341 Expression::Unnest(f) => {
343 Ok(Expression::Function(Box::new(Function::new(
346 "OPENJSON".to_string(),
347 vec![f.this],
348 ))))
349 }
350
351 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
353 "OPENJSON".to_string(),
354 vec![f.this],
355 )))),
356
357 Expression::Join(join) => Ok(Expression::Join(Box::new(
359 Self::transform_lateral_join_to_apply(*join),
360 ))),
361
362 Expression::Length(f) => Ok(Expression::Function(Box::new(Function::new(
364 "LEN".to_string(),
365 vec![f.this],
366 )))),
367
368 Expression::Stddev(f) => Ok(Expression::Function(Box::new(Function::new(
370 "STDEV".to_string(),
371 vec![f.this],
372 )))),
373 Expression::StddevSamp(f) => Ok(Expression::Function(Box::new(Function::new(
374 "STDEV".to_string(),
375 vec![f.this],
376 )))),
377 Expression::StddevPop(f) => Ok(Expression::Function(Box::new(Function::new(
378 "STDEVP".to_string(),
379 vec![f.this],
380 )))),
381
382 Expression::Boolean(b) => {
384 let value = if b.value { 1 } else { 0 };
385 Ok(Expression::Literal(Box::new(
386 crate::expressions::Literal::Number(value.to_string()),
387 )))
388 }
389
390 Expression::Ln(f) => Ok(Expression::Function(Box::new(Function::new(
392 "LOG".to_string(),
393 vec![f.this],
394 )))),
395
396 Expression::CurrentDate(_) => {
399 let getdate =
400 Expression::Function(Box::new(Function::new("GETDATE".to_string(), vec![])));
401 Ok(Expression::Cast(Box::new(crate::expressions::Cast {
402 this: getdate,
403 to: crate::expressions::DataType::Date,
404 trailing_comments: Vec::new(),
405 double_colon_syntax: false,
406 format: None,
407 default: None,
408 inferred_type: None,
409 })))
410 }
411
412 Expression::CurrentTimestamp(_) => Ok(Expression::Function(Box::new(Function::new(
414 "GETDATE".to_string(),
415 vec![],
416 )))),
417
418 Expression::DateDiff(f) => {
420 let unit_str = match f.unit {
422 Some(crate::expressions::IntervalUnit::Year) => "YEAR",
423 Some(crate::expressions::IntervalUnit::Quarter) => "QUARTER",
424 Some(crate::expressions::IntervalUnit::Month) => "MONTH",
425 Some(crate::expressions::IntervalUnit::Week) => "WEEK",
426 Some(crate::expressions::IntervalUnit::Day) => "DAY",
427 Some(crate::expressions::IntervalUnit::Hour) => "HOUR",
428 Some(crate::expressions::IntervalUnit::Minute) => "MINUTE",
429 Some(crate::expressions::IntervalUnit::Second) => "SECOND",
430 Some(crate::expressions::IntervalUnit::Millisecond) => "MILLISECOND",
431 Some(crate::expressions::IntervalUnit::Microsecond) => "MICROSECOND",
432 Some(crate::expressions::IntervalUnit::Nanosecond) => "NANOSECOND",
433 None => "DAY",
434 };
435 let unit = Expression::Identifier(crate::expressions::Identifier {
436 name: unit_str.to_string(),
437 quoted: false,
438 trailing_comments: Vec::new(),
439 span: None,
440 });
441 Ok(Expression::Function(Box::new(Function::new(
442 "DATEDIFF".to_string(),
443 vec![unit, f.expression, f.this], ))))
445 }
446
447 Expression::DateAdd(f) => {
449 let unit_str = match f.unit {
450 crate::expressions::IntervalUnit::Year => "YEAR",
451 crate::expressions::IntervalUnit::Quarter => "QUARTER",
452 crate::expressions::IntervalUnit::Month => "MONTH",
453 crate::expressions::IntervalUnit::Week => "WEEK",
454 crate::expressions::IntervalUnit::Day => "DAY",
455 crate::expressions::IntervalUnit::Hour => "HOUR",
456 crate::expressions::IntervalUnit::Minute => "MINUTE",
457 crate::expressions::IntervalUnit::Second => "SECOND",
458 crate::expressions::IntervalUnit::Millisecond => "MILLISECOND",
459 crate::expressions::IntervalUnit::Microsecond => "MICROSECOND",
460 crate::expressions::IntervalUnit::Nanosecond => "NANOSECOND",
461 };
462 let unit = Expression::Identifier(crate::expressions::Identifier {
463 name: unit_str.to_string(),
464 quoted: false,
465 trailing_comments: Vec::new(),
466 span: None,
467 });
468 Ok(Expression::Function(Box::new(Function::new(
469 "DATEADD".to_string(),
470 vec![unit, f.interval, f.this],
471 ))))
472 }
473
474 Expression::Uuid(_) => Ok(Expression::Function(Box::new(Function::new(
477 "NEWID".to_string(),
478 vec![],
479 )))),
480
481 Expression::IfFunc(f) => {
484 let false_val = f
485 .false_value
486 .unwrap_or(Expression::Null(crate::expressions::Null));
487 Ok(Expression::Function(Box::new(Function::new(
488 "IIF".to_string(),
489 vec![f.condition, f.true_value, false_val],
490 ))))
491 }
492
493 Expression::StringAgg(f) => Ok(Expression::StringAgg(f)),
496
497 Expression::LastDay(f) => Ok(Expression::Function(Box::new(Function::new(
499 "EOMONTH".to_string(),
500 vec![f.this.clone()],
501 )))),
502
503 Expression::Ceil(f) => Ok(Expression::Function(Box::new(Function::new(
505 "CEILING".to_string(),
506 vec![f.this],
507 )))),
508
509 Expression::Repeat(f) => Ok(Expression::Function(Box::new(Function::new(
511 "REPLICATE".to_string(),
512 vec![f.this, f.times],
513 )))),
514
515 Expression::Chr(f) => Ok(Expression::Function(Box::new(Function::new(
517 "CHAR".to_string(),
518 vec![f.this],
519 )))),
520
521 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
524 "VARP".to_string(),
525 vec![f.this],
526 )))),
527
528 Expression::Variance(f) => Ok(Expression::Function(Box::new(Function::new(
530 "VAR".to_string(),
531 vec![f.this],
532 )))),
533 Expression::VarSamp(f) => Ok(Expression::Function(Box::new(Function::new(
534 "VAR".to_string(),
535 vec![f.this],
536 )))),
537
538 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
541 "HASHBYTES".to_string(),
542 vec![Expression::string("MD5"), *f.this],
543 )))),
544
545 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
547 "HASHBYTES".to_string(),
548 vec![Expression::string("SHA1"), f.this],
549 )))),
550
551 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
553 "HASHBYTES".to_string(),
554 vec![Expression::string("SHA1"), f.this],
555 )))),
556
557 Expression::ArrayToString(f) => Ok(Expression::Function(Box::new(Function::new(
560 "STRING_AGG".to_string(),
561 vec![f.this],
562 )))),
563
564 Expression::AutoIncrementColumnConstraint(_) => Ok(Expression::Function(Box::new(
567 Function::new("IDENTITY".to_string(), vec![]),
568 ))),
569
570 Expression::CreateView(mut view) => {
574 view.name.catalog = None;
576 Ok(Expression::CreateView(view))
577 }
578
579 Expression::DropView(mut view) => {
580 view.name.catalog = None;
582 Ok(Expression::DropView(view))
583 }
584
585 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
589 let path = match *e.expression {
590 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
591 let Literal::String(s) = lit.as_ref() else {
592 unreachable!()
593 };
594 let normalized = if s.starts_with('$') {
595 s.clone()
596 } else if s.starts_with('[') {
597 format!("${}", s)
598 } else {
599 format!("$.{}", s)
600 };
601 Expression::Literal(Box::new(Literal::String(normalized)))
602 }
603 other => other,
604 };
605 let json_query = Expression::Function(Box::new(Function::new(
606 "JSON_QUERY".to_string(),
607 vec![(*e.this).clone(), path.clone()],
608 )));
609 let json_value = Expression::Function(Box::new(Function::new(
610 "JSON_VALUE".to_string(),
611 vec![*e.this, path],
612 )));
613 Ok(Expression::Function(Box::new(Function::new(
614 "ISNULL".to_string(),
615 vec![json_query, json_value],
616 ))))
617 }
618
619 Expression::Function(f) => self.transform_function(*f),
621
622 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
624
625 Expression::Cte(cte) => self.transform_cte(*cte),
628
629 Expression::Subquery(subquery) => self.transform_subquery(*subquery),
632
633 Expression::JsonQuery(f) => {
635 let json_query = Expression::Function(Box::new(Function::new(
636 "JSON_QUERY".to_string(),
637 vec![f.this.clone(), f.path.clone()],
638 )));
639 let json_value = Expression::Function(Box::new(Function::new(
640 "JSON_VALUE".to_string(),
641 vec![f.this, f.path],
642 )));
643 Ok(Expression::Function(Box::new(Function::new(
644 "ISNULL".to_string(),
645 vec![json_query, json_value],
646 ))))
647 }
648 Expression::JsonValue(f) => Ok(Expression::Function(Box::new(Function::new(
650 "JSON_VALUE".to_string(),
651 vec![f.this, f.path],
652 )))),
653
654 Expression::Any(ref q) if matches!(&q.op, Some(QuantifiedOp::Eq)) => {
657 let values: Option<Vec<Expression>> = match &q.subquery {
658 Expression::ArrayFunc(a) => Some(a.expressions.clone()),
659 Expression::Array(a) => Some(a.expressions.clone()),
660 Expression::Tuple(t) => Some(t.expressions.clone()),
661 _ => None,
662 };
663
664 match values {
665 Some(expressions) if expressions.is_empty() => {
666 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp::new(
667 Expression::Literal(Box::new(Literal::Number("1".to_string()))),
668 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
669 ))))
670 }
671 Some(expressions) => Ok(Expression::In(Box::new(In {
672 this: q.this.clone(),
673 expressions,
674 query: None,
675 not: false,
676 global: false,
677 unnest: None,
678 is_field: false,
679 }))),
680 None => Ok(expr.clone()),
681 }
682 }
683
684 _ => Ok(expr),
686 }
687 }
688}
689
690#[cfg(feature = "transpile")]
691impl TSQLDialect {
692 fn normalize_frame_incompatible_window_functions(select: &mut Select) {
693 let window_map: HashMap<String, Over> = select
694 .windows
695 .as_ref()
696 .map(|windows| {
697 windows
698 .iter()
699 .map(|window| (window.name.name.to_lowercase(), window.spec.clone()))
700 .collect()
701 })
702 .unwrap_or_default();
703
704 for expr in &mut select.expressions {
705 Self::normalize_frame_incompatible_window_expr(expr, &window_map);
706 }
707
708 if let Some(order_by) = &mut select.order_by {
709 for ordered in &mut order_by.expressions {
710 Self::normalize_frame_incompatible_window_expr(&mut ordered.this, &window_map);
711 }
712 }
713
714 if let Some(qualify) = &mut select.qualify {
715 Self::normalize_frame_incompatible_window_expr(&mut qualify.this, &window_map);
716 }
717 }
718
719 fn normalize_frame_incompatible_window_expr(
720 expr: &mut Expression,
721 window_map: &HashMap<String, Over>,
722 ) {
723 match expr {
724 Expression::WindowFunction(wf) => {
725 Self::normalize_frame_incompatible_window_expr(&mut wf.this, window_map);
726
727 if !Self::is_tsql_frame_incompatible_window_function(&wf.this) {
728 return;
729 }
730
731 wf.over.frame = None;
732
733 let Some(window_name) = wf.over.window_name.clone() else {
734 return;
735 };
736 let Some(named_spec) =
737 Self::resolve_named_window_spec(&window_name.name, window_map, &mut Vec::new())
738 else {
739 return;
740 };
741
742 if named_spec.frame.is_none() {
743 return;
744 }
745
746 if wf.over.partition_by.is_empty() {
747 wf.over.partition_by = named_spec.partition_by;
748 }
749 if wf.over.order_by.is_empty() {
750 wf.over.order_by = named_spec.order_by;
751 }
752 wf.over.window_name = None;
753 wf.over.frame = None;
754 }
755 Expression::Alias(alias) => {
756 Self::normalize_frame_incompatible_window_expr(&mut alias.this, window_map);
757 }
758 Expression::Paren(paren) => {
759 Self::normalize_frame_incompatible_window_expr(&mut paren.this, window_map);
760 }
761 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
762 Self::normalize_frame_incompatible_window_expr(&mut cast.this, window_map);
763 }
764 Expression::Function(function) => {
765 for arg in &mut function.args {
766 Self::normalize_frame_incompatible_window_expr(arg, window_map);
767 }
768 }
769 Expression::Case(case) => {
770 if let Some(operand) = &mut case.operand {
771 Self::normalize_frame_incompatible_window_expr(operand, window_map);
772 }
773 for (condition, result) in &mut case.whens {
774 Self::normalize_frame_incompatible_window_expr(condition, window_map);
775 Self::normalize_frame_incompatible_window_expr(result, window_map);
776 }
777 if let Some(else_expr) = &mut case.else_ {
778 Self::normalize_frame_incompatible_window_expr(else_expr, window_map);
779 }
780 }
781 Expression::And(op)
782 | Expression::Or(op)
783 | Expression::Add(op)
784 | Expression::Sub(op)
785 | Expression::Mul(op)
786 | Expression::Div(op)
787 | Expression::Mod(op)
788 | Expression::Eq(op)
789 | Expression::Neq(op)
790 | Expression::Lt(op)
791 | Expression::Lte(op)
792 | Expression::Gt(op)
793 | Expression::Gte(op)
794 | Expression::Match(op)
795 | Expression::BitwiseAnd(op)
796 | Expression::BitwiseOr(op)
797 | Expression::BitwiseXor(op)
798 | Expression::Concat(op)
799 | Expression::Adjacent(op)
800 | Expression::TsMatch(op)
801 | Expression::PropertyEQ(op)
802 | Expression::ArrayContainsAll(op)
803 | Expression::ArrayContainedBy(op)
804 | Expression::ArrayOverlaps(op)
805 | Expression::JSONBContainsAllTopKeys(op)
806 | Expression::JSONBContainsAnyTopKeys(op)
807 | Expression::JSONBDeleteAtPath(op)
808 | Expression::ExtendsLeft(op)
809 | Expression::ExtendsRight(op)
810 | Expression::Is(op)
811 | Expression::MemberOf(op) => {
812 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
813 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
814 }
815 Expression::Like(op) | Expression::ILike(op) => {
816 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
817 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
818 if let Some(escape) = &mut op.escape {
819 Self::normalize_frame_incompatible_window_expr(escape, window_map);
820 }
821 }
822 Expression::Not(op) | Expression::Neg(op) | Expression::BitwiseNot(op) => {
823 Self::normalize_frame_incompatible_window_expr(&mut op.this, window_map);
824 }
825 Expression::In(in_expr) => {
826 Self::normalize_frame_incompatible_window_expr(&mut in_expr.this, window_map);
827 for value in &mut in_expr.expressions {
828 Self::normalize_frame_incompatible_window_expr(value, window_map);
829 }
830 }
831 Expression::Between(between) => {
832 Self::normalize_frame_incompatible_window_expr(&mut between.this, window_map);
833 Self::normalize_frame_incompatible_window_expr(&mut between.low, window_map);
834 Self::normalize_frame_incompatible_window_expr(&mut between.high, window_map);
835 }
836 Expression::IsNull(is_null) => {
837 Self::normalize_frame_incompatible_window_expr(&mut is_null.this, window_map);
838 }
839 Expression::IsTrue(is_true) | Expression::IsFalse(is_true) => {
840 Self::normalize_frame_incompatible_window_expr(&mut is_true.this, window_map);
841 }
842 _ => {}
843 }
844 }
845
846 fn is_tsql_frame_incompatible_window_function(expr: &Expression) -> bool {
847 matches!(
848 expr,
849 Expression::RowNumber(_)
850 | Expression::Rank(_)
851 | Expression::DenseRank(_)
852 | Expression::NTile(_)
853 | Expression::Ntile(_)
854 | Expression::Lead(_)
855 | Expression::Lag(_)
856 | Expression::PercentRank(_)
857 | Expression::CumeDist(_)
858 )
859 }
860
861 fn resolve_named_window_spec(
862 name: &str,
863 window_map: &HashMap<String, Over>,
864 seen: &mut Vec<String>,
865 ) -> Option<Over> {
866 let key = name.to_lowercase();
867 if seen.iter().any(|seen_name| seen_name == &key) {
868 return None;
869 }
870
871 let named_spec = window_map.get(&key)?.clone();
872 seen.push(key);
873
874 let mut resolved = if let Some(base_window) = &named_spec.window_name {
875 Self::resolve_named_window_spec(&base_window.name, window_map, seen)
876 .unwrap_or_else(Self::empty_over)
877 } else {
878 Self::empty_over()
879 };
880
881 if !named_spec.partition_by.is_empty() {
882 resolved.partition_by = named_spec.partition_by;
883 }
884 if !named_spec.order_by.is_empty() {
885 resolved.order_by = named_spec.order_by;
886 }
887 if named_spec.frame.is_some() {
888 resolved.frame = named_spec.frame;
889 }
890
891 Some(resolved)
892 }
893
894 fn empty_over() -> Over {
895 Over {
896 window_name: None,
897 partition_by: Vec::new(),
898 order_by: Vec::new(),
899 frame: None,
900 alias: None,
901 }
902 }
903
904 fn transform_lateral_join_to_apply(mut join: Join) -> Join {
905 let Some(apply_kind) = Self::lateral_apply_kind(&join) else {
906 return join;
907 };
908
909 join.this = Self::remove_lateral_marker(join.this);
910 join.on = None;
911 join.using.clear();
912 join.kind = apply_kind;
913 join.use_inner_keyword = false;
914 join.use_outer_keyword = false;
915 join.deferred_condition = false;
916 join.join_hint = None;
917 join.match_condition = None;
918 join.directed = false;
919 join
920 }
921
922 fn lateral_apply_kind(join: &Join) -> Option<JoinKind> {
923 let has_apply_condition = join.using.is_empty() && Self::has_no_or_true_on(&join.on);
924
925 match join.kind {
926 JoinKind::Lateral if has_apply_condition => Some(JoinKind::CrossApply),
927 JoinKind::LeftLateral if has_apply_condition => Some(JoinKind::OuterApply),
928 JoinKind::Cross | JoinKind::Inner
929 if has_apply_condition && Self::is_lateral_table_expression(&join.this) =>
930 {
931 Some(JoinKind::CrossApply)
932 }
933 JoinKind::Left
934 if has_apply_condition && Self::is_lateral_table_expression(&join.this) =>
935 {
936 Some(JoinKind::OuterApply)
937 }
938 _ => None,
939 }
940 }
941
942 fn has_no_or_true_on(on: &Option<Expression>) -> bool {
943 match on {
944 None => true,
945 Some(expr) => Self::is_true_condition(expr),
946 }
947 }
948
949 fn is_true_condition(expr: &Expression) -> bool {
950 match expr {
951 Expression::Boolean(boolean) => boolean.value,
952 Expression::Literal(lit) => {
953 matches!(lit.as_ref(), Literal::Number(value) if value.trim() == "1")
954 }
955 Expression::Eq(op) => {
956 Self::is_true_condition(&op.left) && Self::is_true_condition(&op.right)
957 }
958 Expression::Paren(paren) => Self::is_true_condition(&paren.this),
959 _ => false,
960 }
961 }
962
963 fn is_lateral_table_expression(expr: &Expression) -> bool {
964 match expr {
965 Expression::Subquery(subquery) => subquery.lateral,
966 Expression::Lateral(_) => true,
967 Expression::Alias(alias) => Self::is_lateral_table_expression(&alias.this),
968 _ => false,
969 }
970 }
971
972 fn remove_lateral_marker(expr: Expression) -> Expression {
973 match expr {
974 Expression::Subquery(mut subquery) => {
975 subquery.lateral = false;
976 Expression::Subquery(subquery)
977 }
978 Expression::Lateral(lateral) => Self::lateral_to_table_expression(*lateral),
979 Expression::Alias(mut alias) => {
980 alias.this = Self::remove_lateral_marker(alias.this);
981 Expression::Alias(alias)
982 }
983 other => other,
984 }
985 }
986
987 fn lateral_to_table_expression(lateral: crate::expressions::Lateral) -> Expression {
988 let expr = *lateral.this;
989 let Some(alias) = lateral.alias else {
990 return expr;
991 };
992
993 Expression::Alias(Box::new(Alias {
994 this: expr,
995 alias: if lateral.alias_quoted {
996 Identifier::quoted(alias)
997 } else {
998 Identifier::new(alias)
999 },
1000 column_aliases: lateral
1001 .column_aliases
1002 .into_iter()
1003 .map(Identifier::new)
1004 .collect(),
1005 alias_explicit_as: true,
1006 alias_keyword: None,
1007 pre_alias_comments: Vec::new(),
1008 trailing_comments: Vec::new(),
1009 inferred_type: None,
1010 }))
1011 }
1012
1013 fn rewrite_tuple_in_subquery_predicates(
1014 expr: Expression,
1015 outer_qualifier: Option<&Identifier>,
1016 under_not: bool,
1017 ) -> Expression {
1018 match expr {
1019 Expression::In(in_expr) if !under_not => {
1020 let in_expr = *in_expr;
1021 Self::tuple_in_subquery_to_exists(&in_expr, outer_qualifier)
1022 .unwrap_or_else(|| Expression::In(Box::new(in_expr)))
1023 }
1024 Expression::And(mut op) => {
1025 op.left =
1026 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1027 op.right = Self::rewrite_tuple_in_subquery_predicates(
1028 op.right,
1029 outer_qualifier,
1030 under_not,
1031 );
1032 Expression::And(op)
1033 }
1034 Expression::Or(mut op) => {
1035 op.left =
1036 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1037 op.right = Self::rewrite_tuple_in_subquery_predicates(
1038 op.right,
1039 outer_qualifier,
1040 under_not,
1041 );
1042 Expression::Or(op)
1043 }
1044 Expression::Paren(mut paren) => {
1045 paren.this = Self::rewrite_tuple_in_subquery_predicates(
1046 paren.this,
1047 outer_qualifier,
1048 under_not,
1049 );
1050 Expression::Paren(paren)
1051 }
1052 Expression::Not(mut not) => {
1053 not.this =
1054 Self::rewrite_tuple_in_subquery_predicates(not.this, outer_qualifier, true);
1055 Expression::Not(not)
1056 }
1057 other => other,
1058 }
1059 }
1060
1061 fn tuple_in_subquery_to_exists(
1062 in_expr: &In,
1063 outer_qualifier: Option<&Identifier>,
1064 ) -> Option<Expression> {
1065 if in_expr.not || !in_expr.expressions.is_empty() || in_expr.unnest.is_some() {
1066 return None;
1067 }
1068
1069 let left_expressions = Self::tuple_expressions(&in_expr.this)?;
1070 let mut select = match in_expr.query.as_ref()? {
1071 Expression::Select(select) => (**select).clone(),
1072 _ => return None,
1073 };
1074
1075 if left_expressions.len() != select.expressions.len() || left_expressions.is_empty() {
1076 return None;
1077 }
1078
1079 let inner_qualifier = Self::single_select_source_qualifier(&select);
1080 let mut predicates = Vec::with_capacity(left_expressions.len() + 1);
1081 for (projection, left) in select
1082 .expressions
1083 .iter()
1084 .cloned()
1085 .zip(left_expressions.iter().cloned())
1086 {
1087 let inner = Self::tuple_in_projection_expr(projection, inner_qualifier.as_ref())?;
1088 let outer = Self::qualify_tuple_operand(left, outer_qualifier);
1089 predicates.push(Expression::Eq(Box::new(BinaryOp::new(inner, outer))));
1090 }
1091
1092 if let Some(where_clause) = select.where_clause.take() {
1093 predicates.push(where_clause.this);
1094 }
1095
1096 select.expressions = vec![Expression::number(1)];
1097 select.where_clause = Some(Where {
1098 this: Self::and_all(predicates)?,
1099 });
1100
1101 Some(Expression::Exists(Box::new(Exists {
1102 this: Expression::Select(Box::new(select)),
1103 not: false,
1104 })))
1105 }
1106
1107 fn tuple_expressions(expr: &Expression) -> Option<&[Expression]> {
1108 match expr {
1109 Expression::Tuple(tuple) => Some(&tuple.expressions),
1110 Expression::Paren(paren) => Self::tuple_expressions(&paren.this),
1111 _ => None,
1112 }
1113 }
1114
1115 fn tuple_in_projection_expr(
1116 expr: Expression,
1117 qualifier: Option<&Identifier>,
1118 ) -> Option<Expression> {
1119 match expr {
1120 Expression::Alias(alias) => Self::tuple_in_projection_expr(alias.this, qualifier),
1121 Expression::Column(mut column) => {
1122 if column.table.is_none() {
1123 column.table = qualifier.cloned();
1124 }
1125 Some(Expression::Column(column))
1126 }
1127 Expression::Identifier(identifier) => {
1128 Some(Self::column_from_identifier(identifier, qualifier.cloned()))
1129 }
1130 Expression::Dot(_) => Some(expr),
1131 _ => None,
1132 }
1133 }
1134
1135 fn qualify_tuple_operand(expr: Expression, qualifier: Option<&Identifier>) -> Expression {
1136 match expr {
1137 Expression::Column(mut column) => {
1138 if column.table.is_none() {
1139 column.table = qualifier.cloned();
1140 }
1141 Expression::Column(column)
1142 }
1143 Expression::Identifier(identifier) => {
1144 Self::column_from_identifier(identifier, qualifier.cloned())
1145 }
1146 other => other,
1147 }
1148 }
1149
1150 fn column_from_identifier(identifier: Identifier, table: Option<Identifier>) -> Expression {
1151 Expression::Column(Box::new(Column {
1152 name: identifier,
1153 table,
1154 join_mark: false,
1155 trailing_comments: Vec::new(),
1156 span: None,
1157 inferred_type: None,
1158 }))
1159 }
1160
1161 fn single_select_source_qualifier(select: &Select) -> Option<Identifier> {
1162 if !select.joins.is_empty() {
1163 return None;
1164 }
1165
1166 let from = select.from.as_ref()?;
1167 if from.expressions.len() != 1 {
1168 return None;
1169 }
1170
1171 Self::source_qualifier(&from.expressions[0])
1172 }
1173
1174 fn source_qualifier(source: &Expression) -> Option<Identifier> {
1175 match source {
1176 Expression::Table(table) => table.alias.clone().or_else(|| Some(table.name.clone())),
1177 Expression::Subquery(subquery) => subquery.alias.clone(),
1178 _ => None,
1179 }
1180 }
1181
1182 fn and_all(mut predicates: Vec<Expression>) -> Option<Expression> {
1183 if predicates.is_empty() {
1184 return None;
1185 }
1186
1187 let first = predicates.remove(0);
1188 Some(predicates.into_iter().fold(first, |left, right| {
1189 Expression::And(Box::new(BinaryOp::new(left, right)))
1190 }))
1191 }
1192
1193 pub(super) fn transform_data_type(
1195 &self,
1196 dt: crate::expressions::DataType,
1197 ) -> Result<Expression> {
1198 use crate::expressions::DataType;
1199 let transformed = match dt {
1200 DataType::Boolean => DataType::Custom {
1202 name: "BIT".to_string(),
1203 },
1204 DataType::Int { .. } => dt,
1206 DataType::Decimal { precision, scale } => DataType::Custom {
1209 name: if let (Some(p), Some(s)) = (&precision, &scale) {
1210 format!("NUMERIC({}, {})", p, s)
1211 } else if let Some(p) = &precision {
1212 format!("NUMERIC({})", p)
1213 } else {
1214 "NUMERIC".to_string()
1215 },
1216 },
1217 DataType::Text => DataType::Custom {
1219 name: "VARCHAR(MAX)".to_string(),
1220 },
1221 DataType::Timestamp { .. } => DataType::Custom {
1223 name: "DATETIME2".to_string(),
1224 },
1225 DataType::Uuid => DataType::Custom {
1227 name: "UNIQUEIDENTIFIER".to_string(),
1228 },
1229 DataType::Custom { ref name } => {
1231 let upper = name.trim().to_uppercase();
1232 let (base_name, precision, _scale) = Self::parse_type_precision_and_scale(&upper);
1233 match base_name.as_str() {
1234 "BPCHAR" => {
1236 if let Some(len) = precision {
1237 DataType::Char { length: Some(len) }
1238 } else {
1239 DataType::Char { length: None }
1240 }
1241 }
1242 _ => dt,
1243 }
1244 }
1245 other => other,
1247 };
1248 Ok(Expression::DataType(transformed))
1249 }
1250
1251 pub(super) fn parse_type_precision_and_scale(name: &str) -> (String, Option<u32>, Option<u32>) {
1253 if let Some(paren_pos) = name.find('(') {
1254 let base = name[..paren_pos].to_string();
1255 let rest = &name[paren_pos + 1..];
1256 if let Some(close_pos) = rest.find(')') {
1257 let args = &rest[..close_pos];
1258 let parts: Vec<&str> = args.split(',').map(|s| s.trim()).collect();
1259 let precision = parts.first().and_then(|s| s.parse::<u32>().ok());
1260 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1261 return (base, precision, scale);
1262 }
1263 (base, None, None)
1264 } else {
1265 (name.to_string(), None, None)
1266 }
1267 }
1268
1269 fn transform_logical_aggregate(
1270 condition: Expression,
1271 filter: Option<Expression>,
1272 aggregate_name: &str,
1273 ) -> Result<Expression> {
1274 let false_condition = Expression::Not(Box::new(crate::expressions::UnaryOp {
1275 this: condition.clone(),
1276 inferred_type: None,
1277 }));
1278 let true_condition = Self::apply_aggregate_filter(condition, filter.clone());
1279 let false_condition = Self::apply_aggregate_filter(false_condition, filter);
1280
1281 let case_expr = Expression::Case(Box::new(crate::expressions::Case {
1282 operand: None,
1283 whens: vec![
1284 (true_condition, Expression::number(1)),
1285 (false_condition, Expression::number(0)),
1286 ],
1287 else_: Some(Expression::null()),
1288 comments: Vec::new(),
1289 inferred_type: None,
1290 }));
1291
1292 let case_expr = crate::transforms::ensure_bools(case_expr)?;
1293 let aggregate = Expression::Function(Box::new(Function::new(
1294 aggregate_name.to_string(),
1295 vec![case_expr],
1296 )));
1297
1298 Ok(Expression::Cast(Box::new(Cast {
1299 this: aggregate,
1300 to: DataType::Custom {
1301 name: "BIT".to_string(),
1302 },
1303 trailing_comments: Vec::new(),
1304 double_colon_syntax: false,
1305 format: None,
1306 default: None,
1307 inferred_type: None,
1308 })))
1309 }
1310
1311 fn apply_aggregate_filter(condition: Expression, filter: Option<Expression>) -> Expression {
1312 match filter {
1313 Some(filter) => Expression::And(Box::new(crate::expressions::BinaryOp::new(
1314 filter, condition,
1315 ))),
1316 None => condition,
1317 }
1318 }
1319
1320 fn transform_function(&self, f: Function) -> Result<Expression> {
1321 let name_upper = f.name.to_uppercase();
1322 match name_upper.as_str() {
1323 "COALESCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
1325 "ISNULL".to_string(),
1326 f.args,
1327 )))),
1328
1329 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
1331 "ISNULL".to_string(),
1332 f.args,
1333 )))),
1334
1335 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1337 Function::new("STRING_AGG".to_string(), f.args),
1338 ))),
1339
1340 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
1342
1343 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1345 "STRING_AGG".to_string(),
1346 f.args,
1347 )))),
1348
1349 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1351 "SUBSTRING".to_string(),
1352 f.args,
1353 )))),
1354
1355 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1357 "LEN".to_string(),
1358 f.args,
1359 )))),
1360
1361 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
1363 seed: None,
1364 lower: None,
1365 upper: None,
1366 }))),
1367
1368 "NOW" => Ok(Expression::Function(Box::new(Function::new(
1370 "GETDATE".to_string(),
1371 vec![],
1372 )))),
1373
1374 "CURRENT_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1376 "GETDATE".to_string(),
1377 vec![],
1378 )))),
1379
1380 "CURRENT_DATE" => {
1382 Ok(Expression::Function(Box::new(Function::new(
1384 "CAST".to_string(),
1385 vec![
1386 Expression::Function(Box::new(Function::new(
1387 "GETDATE".to_string(),
1388 vec![],
1389 ))),
1390 Expression::Identifier(crate::expressions::Identifier::new("DATE")),
1391 ],
1392 ))))
1393 }
1394
1395 "TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
1397 "CONVERT".to_string(),
1398 f.args,
1399 )))),
1400
1401 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1403 "CONVERT".to_string(),
1404 f.args,
1405 )))),
1406
1407 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
1409 "FORMAT".to_string(),
1410 f.args,
1411 )))),
1412
1413 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
1415 "FORMAT".to_string(),
1416 f.args,
1417 )))),
1418
1419 "DATE_TRUNC" | "DATETRUNC" => {
1422 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
1423 if args.len() >= 2 {
1425 if let Expression::Literal(lit) = &args[1] {
1426 if let Literal::String(_) = lit.as_ref() {
1427 args[1] = Expression::Cast(Box::new(Cast {
1428 this: args[1].clone(),
1429 to: DataType::Custom {
1430 name: "DATETIME2".to_string(),
1431 },
1432 trailing_comments: Vec::new(),
1433 double_colon_syntax: false,
1434 format: None,
1435 default: None,
1436 inferred_type: None,
1437 }));
1438 }
1439 }
1440 }
1441 Ok(Expression::Function(Box::new(Function::new(
1442 "DATETRUNC".to_string(),
1443 args,
1444 ))))
1445 }
1446
1447 "DATEADD" => {
1449 let args = Self::uppercase_first_arg_if_identifier(f.args);
1450 Ok(Expression::Function(Box::new(Function::new(
1451 "DATEADD".to_string(),
1452 args,
1453 ))))
1454 }
1455
1456 "DATEDIFF" => {
1458 let args = Self::uppercase_first_arg_if_identifier(f.args);
1459 Ok(Expression::Function(Box::new(Function::new(
1460 "DATEDIFF".to_string(),
1461 args,
1462 ))))
1463 }
1464
1465 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
1467 "DATEPART".to_string(),
1468 f.args,
1469 )))),
1470
1471 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
1473 Ok(Expression::Function(Box::new(Function::new(
1475 "CHARINDEX".to_string(),
1476 f.args,
1477 ))))
1478 }
1479
1480 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
1482
1483 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
1485 Function::new("CEILING".to_string(), f.args),
1486 ))),
1487
1488 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
1493 "JSON_VALUE".to_string(),
1494 f.args,
1495 )))),
1496
1497 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
1499 "JSON_VALUE".to_string(),
1500 f.args,
1501 )))),
1502
1503 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
1505
1506 "GET_PATH" if f.args.len() == 2 => {
1508 let mut args = f.args;
1509 let this = args.remove(0);
1510 let path = args.remove(0);
1511 let json_path = match &path {
1512 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
1513 let Literal::String(s) = lit.as_ref() else {
1514 unreachable!()
1515 };
1516 let normalized = if s.starts_with('$') {
1517 s.clone()
1518 } else if s.starts_with('[') {
1519 format!("${}", s)
1520 } else {
1521 format!("$.{}", s)
1522 };
1523 Expression::Literal(Box::new(Literal::String(normalized)))
1524 }
1525 _ => path,
1526 };
1527 let json_query = Expression::Function(Box::new(Function::new(
1529 "JSON_QUERY".to_string(),
1530 vec![this.clone(), json_path.clone()],
1531 )));
1532 let json_value = Expression::Function(Box::new(Function::new(
1533 "JSON_VALUE".to_string(),
1534 vec![this, json_path],
1535 )));
1536 Ok(Expression::Function(Box::new(Function::new(
1537 "ISNULL".to_string(),
1538 vec![json_query, json_value],
1539 ))))
1540 }
1541
1542 "JSON_QUERY" if f.args.len() == 1 => {
1545 let this = f.args.into_iter().next().unwrap();
1546 let path = Expression::Literal(Box::new(Literal::String("$".to_string())));
1547 let json_query = Expression::Function(Box::new(Function::new(
1548 "JSON_QUERY".to_string(),
1549 vec![this.clone(), path.clone()],
1550 )));
1551 let json_value = Expression::Function(Box::new(Function::new(
1552 "JSON_VALUE".to_string(),
1553 vec![this, path],
1554 )));
1555 Ok(Expression::Function(Box::new(Function::new(
1556 "ISNULL".to_string(),
1557 vec![json_query, json_value],
1558 ))))
1559 }
1560
1561 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
1563 "STRING_SPLIT".to_string(),
1564 f.args,
1565 )))),
1566
1567 "REGEXP_LIKE" => {
1570 Ok(Expression::Function(Box::new(Function::new(
1572 "PATINDEX".to_string(),
1573 f.args,
1574 ))))
1575 }
1576
1577 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1579 "LOG".to_string(),
1580 f.args,
1581 )))),
1582
1583 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1588 "STDEV".to_string(),
1589 f.args,
1590 )))),
1591
1592 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
1594 "STDEVP".to_string(),
1595 f.args,
1596 )))),
1597
1598 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1600 "VAR".to_string(),
1601 f.args,
1602 )))),
1603
1604 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
1606 "VARP".to_string(),
1607 f.args,
1608 )))),
1609
1610 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
1612 let mut args = f.args;
1613 Self::transform_logical_aggregate(args.remove(0), None, "MIN")
1614 }
1615 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
1616 let mut args = f.args;
1617 Self::transform_logical_aggregate(args.remove(0), None, "MAX")
1618 }
1619
1620 "DATE_ADD" => {
1622 if f.args.len() == 2 {
1623 let mut args = f.args;
1624 let date = args.remove(0);
1625 let interval = args.remove(0);
1626 let unit = Expression::Identifier(crate::expressions::Identifier {
1627 name: "DAY".to_string(),
1628 quoted: false,
1629 trailing_comments: Vec::new(),
1630 span: None,
1631 });
1632 Ok(Expression::Function(Box::new(Function::new(
1633 "DATEADD".to_string(),
1634 vec![unit, interval, date],
1635 ))))
1636 } else {
1637 let args = Self::uppercase_first_arg_if_identifier(f.args);
1638 Ok(Expression::Function(Box::new(Function::new(
1639 "DATEADD".to_string(),
1640 args,
1641 ))))
1642 }
1643 }
1644
1645 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
1647 "STUFF".to_string(),
1648 f.args,
1649 )))),
1650
1651 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
1653 crate::expressions::CurrentUser { this: None },
1654 ))),
1655
1656 _ => Ok(Expression::Function(Box::new(f))),
1658 }
1659 }
1660
1661 fn transform_aggregate_function(
1662 &self,
1663 f: Box<crate::expressions::AggregateFunction>,
1664 ) -> Result<Expression> {
1665 let name_upper = f.name.to_uppercase();
1666 match name_upper.as_str() {
1667 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1669 Function::new("STRING_AGG".to_string(), f.args),
1670 ))),
1671
1672 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1674 "STRING_AGG".to_string(),
1675 f.args,
1676 )))),
1677
1678 "ARRAY_AGG" if !f.args.is_empty() => {
1681 Ok(Expression::Function(Box::new(Function::new(
1683 "STRING_AGG".to_string(),
1684 f.args,
1685 ))))
1686 }
1687
1688 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
1690 let mut args = f.args;
1691 Self::transform_logical_aggregate(args.remove(0), f.filter, "MIN")
1692 }
1693 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
1694 let mut args = f.args;
1695 Self::transform_logical_aggregate(args.remove(0), f.filter, "MAX")
1696 }
1697
1698 _ => Ok(Expression::AggregateFunction(f)),
1700 }
1701 }
1702
1703 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
1707 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
1708 }
1709
1710 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
1712 if cte.columns.is_empty() {
1715 cte.this = self.qualify_derived_table_outputs(cte.this);
1716 }
1717 cte
1718 }
1719
1720 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
1724 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
1727 subquery.this = self.qualify_derived_table_outputs(subquery.this);
1728 }
1729 Ok(Expression::Subquery(Box::new(subquery)))
1730 }
1731
1732 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
1736 match expr {
1737 Expression::Select(mut select) => {
1738 let has_from = select.from.is_some();
1741 if !has_from {
1742 select.expressions = select
1743 .expressions
1744 .into_iter()
1745 .map(|e| self.maybe_alias_expression(e))
1746 .collect();
1747 }
1748 Expression::Select(select)
1749 }
1750 Expression::Union(mut u) => {
1752 let left = std::mem::replace(&mut u.left, Expression::Null(Null));
1753 u.left = self.qualify_derived_table_outputs(left);
1754 Expression::Union(u)
1755 }
1756 Expression::Intersect(mut i) => {
1757 let left = std::mem::replace(&mut i.left, Expression::Null(Null));
1758 i.left = self.qualify_derived_table_outputs(left);
1759 Expression::Intersect(i)
1760 }
1761 Expression::Except(mut e) => {
1762 let left = std::mem::replace(&mut e.left, Expression::Null(Null));
1763 e.left = self.qualify_derived_table_outputs(left);
1764 Expression::Except(e)
1765 }
1766 Expression::Subquery(mut s) => {
1768 s.this = self.qualify_derived_table_outputs(s.this);
1769 Expression::Subquery(s)
1770 }
1771 other => other,
1773 }
1774 }
1775
1776 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
1781 match &expr {
1782 Expression::Alias(_) => expr,
1784 Expression::Aliases(_) => expr,
1786 Expression::Star(_) => expr,
1788 _ => {
1793 if let Some(output_name) = self.get_output_name(&expr) {
1794 Expression::Alias(Box::new(Alias {
1795 this: expr,
1796 alias: Identifier {
1797 name: output_name,
1798 quoted: true, trailing_comments: Vec::new(),
1800 span: None,
1801 },
1802 column_aliases: Vec::new(),
1803 alias_explicit_as: false,
1804 alias_keyword: None,
1805 pre_alias_comments: Vec::new(),
1806 trailing_comments: Vec::new(),
1807 inferred_type: None,
1808 }))
1809 } else {
1810 expr
1812 }
1813 }
1814 }
1815 }
1816
1817 fn get_output_name(&self, expr: &Expression) -> Option<String> {
1821 match expr {
1822 Expression::Literal(lit) => match lit.as_ref() {
1824 Literal::Number(n) => Some(n.clone()),
1825 Literal::String(s) => Some(s.clone()),
1826 Literal::HexString(h) => Some(format!("0x{}", h)),
1827 Literal::HexNumber(h) => Some(format!("0x{}", h)),
1828 Literal::BitString(b) => Some(format!("b{}", b)),
1829 Literal::ByteString(b) => Some(format!("b'{}'", b)),
1830 Literal::NationalString(s) => Some(format!("N'{}'", s)),
1831 Literal::Date(d) => Some(d.clone()),
1832 Literal::Time(t) => Some(t.clone()),
1833 Literal::Timestamp(ts) => Some(ts.clone()),
1834 Literal::Datetime(dt) => Some(dt.clone()),
1835 Literal::TripleQuotedString(s, _) => Some(s.clone()),
1836 Literal::EscapeString(s) => Some(s.clone()),
1837 Literal::DollarString(s) => Some(s.clone()),
1838 Literal::RawString(s) => Some(s.clone()),
1839 },
1840 Expression::Column(col) => Some(col.name.name.clone()),
1842 Expression::Identifier(ident) => Some(ident.name.clone()),
1844 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
1846 Expression::Null(_) => Some("NULL".to_string()),
1848 Expression::Function(f) => Some(f.name.clone()),
1850 Expression::AggregateFunction(f) => Some(f.name.clone()),
1852 _ => Some(format!("_col_{}", 0)),
1854 }
1855 }
1856
1857 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
1859 use crate::expressions::Identifier;
1860 if !args.is_empty() {
1861 match &args[0] {
1862 Expression::Identifier(id) => {
1863 args[0] = Expression::Identifier(Identifier {
1864 name: id.name.to_uppercase(),
1865 quoted: id.quoted,
1866 trailing_comments: id.trailing_comments.clone(),
1867 span: None,
1868 });
1869 }
1870 Expression::Var(v) => {
1871 args[0] = Expression::Identifier(Identifier {
1872 name: v.this.to_uppercase(),
1873 quoted: false,
1874 trailing_comments: Vec::new(),
1875 span: None,
1876 });
1877 }
1878 Expression::Column(col) if col.table.is_none() => {
1879 args[0] = Expression::Identifier(Identifier {
1880 name: col.name.name.to_uppercase(),
1881 quoted: col.name.quoted,
1882 trailing_comments: col.name.trailing_comments.clone(),
1883 span: None,
1884 });
1885 }
1886 _ => {}
1887 }
1888 }
1889 args
1890 }
1891}
1892
1893#[cfg(test)]
1894mod tests {
1895 use super::*;
1896 use crate::dialects::Dialect;
1897
1898 fn transpile_to_tsql(sql: &str) -> String {
1899 let dialect = Dialect::get(DialectType::Generic);
1900 let result = dialect
1901 .transpile(sql, DialectType::TSQL)
1902 .expect("Transpile failed");
1903 result[0].clone()
1904 }
1905
1906 #[test]
1907 fn test_nvl_to_isnull() {
1908 let result = transpile_to_tsql("SELECT NVL(a, b)");
1909 assert!(
1910 result.contains("ISNULL"),
1911 "Expected ISNULL, got: {}",
1912 result
1913 );
1914 }
1915
1916 #[test]
1917 fn test_coalesce_to_isnull() {
1918 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
1919 assert!(
1920 result.contains("ISNULL"),
1921 "Expected ISNULL, got: {}",
1922 result
1923 );
1924 }
1925
1926 #[test]
1927 fn test_basic_select() {
1928 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
1929 assert!(result.contains("SELECT"));
1930 assert!(result.contains("FROM users"));
1931 }
1932
1933 #[test]
1934 fn test_length_to_len() {
1935 let result = transpile_to_tsql("SELECT LENGTH(name)");
1936 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
1937 }
1938
1939 #[test]
1940 fn test_now_to_getdate() {
1941 let result = transpile_to_tsql("SELECT NOW()");
1942 assert!(
1943 result.contains("GETDATE"),
1944 "Expected GETDATE, got: {}",
1945 result
1946 );
1947 }
1948
1949 #[test]
1950 fn test_group_concat_to_string_agg() {
1951 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
1952 assert!(
1953 result.contains("STRING_AGG"),
1954 "Expected STRING_AGG, got: {}",
1955 result
1956 );
1957 }
1958
1959 #[test]
1960 fn test_listagg_to_string_agg() {
1961 let result = transpile_to_tsql("SELECT LISTAGG(name)");
1962 assert!(
1963 result.contains("STRING_AGG"),
1964 "Expected STRING_AGG, got: {}",
1965 result
1966 );
1967 }
1968
1969 #[test]
1970 fn test_ln_to_log() {
1971 let result = transpile_to_tsql("SELECT LN(x)");
1972 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
1973 }
1974
1975 #[test]
1976 fn test_stddev_to_stdev() {
1977 let result = transpile_to_tsql("SELECT STDDEV(x)");
1978 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
1979 }
1980
1981 #[test]
1982 fn test_bracket_identifiers() {
1983 let dialect = Dialect::get(DialectType::TSQL);
1985 let config = dialect.generator_config();
1986 assert_eq!(config.identifier_quote, '[');
1987 }
1988
1989 #[test]
1990 fn test_json_query_isnull_wrapper_simple() {
1991 let dialect = Dialect::get(DialectType::TSQL);
1993 let result = dialect
1994 .transpile(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
1995 .expect("transpile failed");
1996 assert!(
1997 result[0].contains("ISNULL"),
1998 "JSON_QUERY should be wrapped with ISNULL: {}",
1999 result[0]
2000 );
2001 }
2002
2003 #[test]
2004 fn test_json_query_isnull_wrapper_nested() {
2005 let dialect = Dialect::get(DialectType::TSQL);
2006 let result = dialect
2007 .transpile(
2008 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
2009 DialectType::TSQL,
2010 )
2011 .expect("transpile failed");
2012 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
2013 assert_eq!(
2014 result[0], expected,
2015 "JSON_QUERY should be wrapped with ISNULL"
2016 );
2017 }
2018}