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