1use super::{DialectImpl, DialectType};
14use crate::error::Result;
15use crate::expressions::{
16 Alias, Cast, Cte, DataType, Expression, Function, Identifier, Join, JoinKind, LikeOp, Literal,
17 StringAggFunc, Subquery, UnaryFunc,
18};
19use crate::generator::GeneratorConfig;
20use crate::tokens::TokenizerConfig;
21
22pub struct TSQLDialect;
24
25impl DialectImpl for TSQLDialect {
26 fn dialect_type(&self) -> DialectType {
27 DialectType::TSQL
28 }
29
30 fn tokenizer_config(&self) -> TokenizerConfig {
31 let mut config = TokenizerConfig::default();
32 config.identifiers.insert('[', ']');
34 config.identifiers.insert('"', '"');
36 config
37 }
38
39 fn generator_config(&self) -> GeneratorConfig {
40 use crate::generator::IdentifierQuoteStyle;
41 GeneratorConfig {
42 identifier_quote: '[',
44 identifier_quote_style: IdentifierQuoteStyle::BRACKET,
45 dialect: Some(DialectType::TSQL),
46 limit_fetch_style: crate::generator::LimitFetchStyle::FetchFirst,
49 null_ordering_supported: false,
51 supports_select_into: true,
53 alter_table_include_column_keyword: false,
55 computed_column_with_type: false,
57 cte_recursive_keyword_required: false,
59 ensure_bools: true,
61 supports_single_arg_concat: false,
63 tablesample_seed_keyword: "REPEATABLE",
65 json_path_bracketed_key_supported: false,
67 supports_to_number: false,
69 set_op_modifiers: false,
71 copy_params_eq_required: true,
73 except_intersect_support_all_clause: false,
75 alter_set_wrapped: true,
77 try_supported: true,
79 nvl2_supported: false,
81 parameter_default_equals: true,
83 supports_window_exclude: false,
85 multi_arg_distinct: false,
87 locking_reads_supported: false,
89 ..Default::default()
90 }
91 }
92
93 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
94 match expr {
95 Expression::Select(mut select) => {
100 select.expressions = select
101 .expressions
102 .into_iter()
103 .map(|e| {
104 match e {
105 Expression::Eq(op) => {
106 match &op.left {
109 Expression::Column(col)
110 if col.table.is_none()
111 && !col.name.name.starts_with('@') =>
112 {
113 Expression::Alias(Box::new(Alias {
114 this: op.right,
115 alias: col.name.clone(),
116 column_aliases: Vec::new(),
117 pre_alias_comments: Vec::new(),
118 trailing_comments: Vec::new(),
119 inferred_type: None,
120 }))
121 }
122 Expression::Identifier(ident)
123 if !ident.name.starts_with('@') =>
124 {
125 Expression::Alias(Box::new(Alias {
126 this: op.right,
127 alias: ident.clone(),
128 column_aliases: Vec::new(),
129 pre_alias_comments: Vec::new(),
130 trailing_comments: Vec::new(),
131 inferred_type: None,
132 }))
133 }
134 _ => Expression::Eq(op),
135 }
136 }
137 other => other,
138 }
139 })
140 .collect();
141
142 if let Some(ref mut with) = select.with {
144 with.ctes = with
145 .ctes
146 .drain(..)
147 .map(|cte| self.transform_cte_inner(cte))
148 .collect();
149 }
150
151 Ok(Expression::Select(select))
152 }
153
154 Expression::DataType(dt) => self.transform_data_type(dt),
156
157 Expression::IsTrue(it) => {
160 let one = Expression::Literal(crate::expressions::Literal::Number("1".to_string()));
161 if it.not {
162 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
164 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
165 left: it.this,
166 right: one,
167 left_comments: vec![],
168 operator_comments: vec![],
169 trailing_comments: vec![],
170 inferred_type: None,
171 })),
172 inferred_type: None,
173 })))
174 } else {
175 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
177 left: it.this,
178 right: one,
179 left_comments: vec![],
180 operator_comments: vec![],
181 trailing_comments: vec![],
182 inferred_type: None,
183 })))
184 }
185 }
186 Expression::IsFalse(it) => {
187 let zero =
188 Expression::Literal(crate::expressions::Literal::Number("0".to_string()));
189 if it.not {
190 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
192 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
193 left: it.this,
194 right: zero,
195 left_comments: vec![],
196 operator_comments: vec![],
197 trailing_comments: vec![],
198 inferred_type: None,
199 })),
200 inferred_type: None,
201 })))
202 } else {
203 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
205 left: it.this,
206 right: zero,
207 left_comments: vec![],
208 operator_comments: vec![],
209 trailing_comments: vec![],
210 inferred_type: None,
211 })))
212 }
213 }
214
215 Expression::In(mut in_expr) if in_expr.not => {
219 in_expr.not = false;
220 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
221 this: Expression::In(in_expr),
222 inferred_type: None,
223 })))
224 }
225
226 Expression::Coalesce(f) if f.expressions.len() == 2 => Ok(Expression::Function(
229 Box::new(Function::new("ISNULL".to_string(), f.expressions)),
230 )),
231
232 Expression::Nvl(f) => Ok(Expression::Function(Box::new(Function::new(
234 "ISNULL".to_string(),
235 vec![f.this, f.expression],
236 )))),
237
238 Expression::GroupConcat(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
240 this: f.this,
241 separator: f.separator,
242 order_by: f.order_by,
243 distinct: f.distinct,
244 filter: f.filter,
245 limit: None,
246 inferred_type: None,
247 }))),
248
249 Expression::ListAgg(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
251 this: f.this,
252 separator: f.separator,
253 order_by: f.order_by,
254 distinct: f.distinct,
255 filter: f.filter,
256 limit: None,
257 inferred_type: None,
258 }))),
259
260 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
262
263 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
265
266 Expression::ILike(op) => {
268 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
271 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
272 Ok(Expression::Like(Box::new(LikeOp {
273 left: lower_left,
274 right: lower_right,
275 escape: op.escape,
276 quantifier: op.quantifier,
277 inferred_type: None,
278 })))
279 }
280
281 Expression::Concat(op) => {
284 Ok(Expression::Add(op))
286 }
287
288 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
290 seed: None,
291 lower: None,
292 upper: None,
293 }))),
294
295 Expression::Unnest(f) => {
297 Ok(Expression::Function(Box::new(Function::new(
300 "OPENJSON".to_string(),
301 vec![f.this],
302 ))))
303 }
304
305 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
307 "OPENJSON".to_string(),
308 vec![f.this],
309 )))),
310
311 Expression::Join(join) if join.kind == JoinKind::Lateral => {
313 Ok(Expression::Join(Box::new(Join {
314 this: join.this,
315 on: None,
316 using: join.using,
317 kind: JoinKind::CrossApply,
318 use_inner_keyword: false,
319 use_outer_keyword: false,
320 deferred_condition: false,
321 join_hint: None,
322 match_condition: None,
323 pivots: join.pivots,
324 comments: join.comments,
325 nesting_group: 0,
326 directed: false,
327 })))
328 }
329
330 Expression::Join(join) if join.kind == JoinKind::LeftLateral => {
332 Ok(Expression::Join(Box::new(Join {
333 this: join.this,
334 on: None, using: join.using,
336 kind: JoinKind::OuterApply,
337 use_inner_keyword: false,
338 use_outer_keyword: false,
339 deferred_condition: false,
340 join_hint: None,
341 match_condition: None,
342 pivots: join.pivots,
343 comments: join.comments,
344 nesting_group: 0,
345 directed: false,
346 })))
347 }
348
349 Expression::Length(f) => Ok(Expression::Function(Box::new(Function::new(
351 "LEN".to_string(),
352 vec![f.this],
353 )))),
354
355 Expression::Stddev(f) => Ok(Expression::Function(Box::new(Function::new(
357 "STDEV".to_string(),
358 vec![f.this],
359 )))),
360
361 Expression::Boolean(b) => {
363 let value = if b.value { 1 } else { 0 };
364 Ok(Expression::Literal(crate::expressions::Literal::Number(
365 value.to_string(),
366 )))
367 }
368
369 Expression::Ln(f) => Ok(Expression::Function(Box::new(Function::new(
371 "LOG".to_string(),
372 vec![f.this],
373 )))),
374
375 Expression::CurrentDate(_) => {
378 let getdate =
379 Expression::Function(Box::new(Function::new("GETDATE".to_string(), vec![])));
380 Ok(Expression::Cast(Box::new(crate::expressions::Cast {
381 this: getdate,
382 to: crate::expressions::DataType::Date,
383 trailing_comments: Vec::new(),
384 double_colon_syntax: false,
385 format: None,
386 default: None,
387 inferred_type: None,
388 })))
389 }
390
391 Expression::CurrentTimestamp(_) => Ok(Expression::Function(Box::new(Function::new(
393 "GETDATE".to_string(),
394 vec![],
395 )))),
396
397 Expression::DateDiff(f) => {
399 let unit_str = match f.unit {
401 Some(crate::expressions::IntervalUnit::Year) => "YEAR",
402 Some(crate::expressions::IntervalUnit::Quarter) => "QUARTER",
403 Some(crate::expressions::IntervalUnit::Month) => "MONTH",
404 Some(crate::expressions::IntervalUnit::Week) => "WEEK",
405 Some(crate::expressions::IntervalUnit::Day) => "DAY",
406 Some(crate::expressions::IntervalUnit::Hour) => "HOUR",
407 Some(crate::expressions::IntervalUnit::Minute) => "MINUTE",
408 Some(crate::expressions::IntervalUnit::Second) => "SECOND",
409 Some(crate::expressions::IntervalUnit::Millisecond) => "MILLISECOND",
410 Some(crate::expressions::IntervalUnit::Microsecond) => "MICROSECOND",
411 Some(crate::expressions::IntervalUnit::Nanosecond) => "NANOSECOND",
412 None => "DAY",
413 };
414 let unit = Expression::Identifier(crate::expressions::Identifier {
415 name: unit_str.to_string(),
416 quoted: false,
417 trailing_comments: Vec::new(),
418 span: None,
419 });
420 Ok(Expression::Function(Box::new(Function::new(
421 "DATEDIFF".to_string(),
422 vec![unit, f.expression, f.this], ))))
424 }
425
426 Expression::DateAdd(f) => {
428 let unit_str = match f.unit {
429 crate::expressions::IntervalUnit::Year => "YEAR",
430 crate::expressions::IntervalUnit::Quarter => "QUARTER",
431 crate::expressions::IntervalUnit::Month => "MONTH",
432 crate::expressions::IntervalUnit::Week => "WEEK",
433 crate::expressions::IntervalUnit::Day => "DAY",
434 crate::expressions::IntervalUnit::Hour => "HOUR",
435 crate::expressions::IntervalUnit::Minute => "MINUTE",
436 crate::expressions::IntervalUnit::Second => "SECOND",
437 crate::expressions::IntervalUnit::Millisecond => "MILLISECOND",
438 crate::expressions::IntervalUnit::Microsecond => "MICROSECOND",
439 crate::expressions::IntervalUnit::Nanosecond => "NANOSECOND",
440 };
441 let unit = Expression::Identifier(crate::expressions::Identifier {
442 name: unit_str.to_string(),
443 quoted: false,
444 trailing_comments: Vec::new(),
445 span: None,
446 });
447 Ok(Expression::Function(Box::new(Function::new(
448 "DATEADD".to_string(),
449 vec![unit, f.interval, f.this],
450 ))))
451 }
452
453 Expression::Uuid(_) => Ok(Expression::Function(Box::new(Function::new(
456 "NEWID".to_string(),
457 vec![],
458 )))),
459
460 Expression::IfFunc(f) => {
463 let false_val = f
464 .false_value
465 .unwrap_or(Expression::Null(crate::expressions::Null));
466 Ok(Expression::Function(Box::new(Function::new(
467 "IIF".to_string(),
468 vec![f.condition, f.true_value, false_val],
469 ))))
470 }
471
472 Expression::StringAgg(f) => Ok(Expression::StringAgg(f)),
475
476 Expression::LastDay(f) => Ok(Expression::Function(Box::new(Function::new(
478 "EOMONTH".to_string(),
479 vec![f.this.clone()],
480 )))),
481
482 Expression::Ceil(f) => Ok(Expression::Function(Box::new(Function::new(
484 "CEILING".to_string(),
485 vec![f.this],
486 )))),
487
488 Expression::Repeat(f) => Ok(Expression::Function(Box::new(Function::new(
490 "REPLICATE".to_string(),
491 vec![f.this, f.times],
492 )))),
493
494 Expression::Chr(f) => Ok(Expression::Function(Box::new(Function::new(
496 "CHAR".to_string(),
497 vec![f.this],
498 )))),
499
500 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
503 "VARP".to_string(),
504 vec![f.this],
505 )))),
506
507 Expression::Variance(f) => Ok(Expression::Function(Box::new(Function::new(
509 "VAR".to_string(),
510 vec![f.this],
511 )))),
512
513 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
516 "HASHBYTES".to_string(),
517 vec![Expression::string("MD5"), *f.this],
518 )))),
519
520 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
522 "HASHBYTES".to_string(),
523 vec![Expression::string("SHA1"), f.this],
524 )))),
525
526 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
528 "HASHBYTES".to_string(),
529 vec![Expression::string("SHA1"), f.this],
530 )))),
531
532 Expression::ArrayToString(f) => Ok(Expression::Function(Box::new(Function::new(
535 "STRING_AGG".to_string(),
536 vec![f.this],
537 )))),
538
539 Expression::AutoIncrementColumnConstraint(_) => Ok(Expression::Function(Box::new(
542 Function::new("IDENTITY".to_string(), vec![]),
543 ))),
544
545 Expression::CreateView(mut view) => {
549 view.name.catalog = None;
551 Ok(Expression::CreateView(view))
552 }
553
554 Expression::DropView(mut view) => {
555 view.name.catalog = None;
557 Ok(Expression::DropView(view))
558 }
559
560 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
564 let path = match *e.expression {
565 Expression::Literal(Literal::String(s)) => {
566 let normalized = if s.starts_with('$') {
567 s
568 } else if s.starts_with('[') {
569 format!("${}", s)
570 } else {
571 format!("$.{}", s)
572 };
573 Expression::Literal(Literal::String(normalized))
574 }
575 other => other,
576 };
577 let json_query = Expression::Function(Box::new(Function::new(
578 "JSON_QUERY".to_string(),
579 vec![(*e.this).clone(), path.clone()],
580 )));
581 let json_value = Expression::Function(Box::new(Function::new(
582 "JSON_VALUE".to_string(),
583 vec![*e.this, path],
584 )));
585 Ok(Expression::Function(Box::new(Function::new(
586 "ISNULL".to_string(),
587 vec![json_query, json_value],
588 ))))
589 }
590
591 Expression::Function(f) => self.transform_function(*f),
593
594 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
596
597 Expression::Cte(cte) => self.transform_cte(*cte),
600
601 Expression::Subquery(subquery) => self.transform_subquery(*subquery),
604
605 Expression::JsonQuery(f) => {
607 let json_query = Expression::Function(Box::new(Function::new(
608 "JSON_QUERY".to_string(),
609 vec![f.this.clone(), f.path.clone()],
610 )));
611 let json_value = Expression::Function(Box::new(Function::new(
612 "JSON_VALUE".to_string(),
613 vec![f.this, f.path],
614 )));
615 Ok(Expression::Function(Box::new(Function::new(
616 "ISNULL".to_string(),
617 vec![json_query, json_value],
618 ))))
619 }
620 Expression::JsonValue(f) => Ok(Expression::Function(Box::new(Function::new(
622 "JSON_VALUE".to_string(),
623 vec![f.this, f.path],
624 )))),
625
626 _ => Ok(expr),
628 }
629 }
630}
631
632impl TSQLDialect {
633 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
635 use crate::expressions::DataType;
636 let transformed = match dt {
637 DataType::Boolean => DataType::Custom {
639 name: "BIT".to_string(),
640 },
641 DataType::Int { .. } => dt,
643 DataType::Decimal { precision, scale } => DataType::Custom {
646 name: if let (Some(p), Some(s)) = (&precision, &scale) {
647 format!("NUMERIC({}, {})", p, s)
648 } else if let Some(p) = &precision {
649 format!("NUMERIC({})", p)
650 } else {
651 "NUMERIC".to_string()
652 },
653 },
654 DataType::Text => DataType::Custom {
656 name: "VARCHAR(MAX)".to_string(),
657 },
658 DataType::Timestamp { .. } => DataType::Custom {
660 name: "DATETIME2".to_string(),
661 },
662 DataType::Uuid => DataType::Custom {
664 name: "UNIQUEIDENTIFIER".to_string(),
665 },
666 other => other,
668 };
669 Ok(Expression::DataType(transformed))
670 }
671
672 fn transform_function(&self, f: Function) -> Result<Expression> {
673 let name_upper = f.name.to_uppercase();
674 match name_upper.as_str() {
675 "COALESCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
677 "ISNULL".to_string(),
678 f.args,
679 )))),
680
681 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
683 "ISNULL".to_string(),
684 f.args,
685 )))),
686
687 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
689 Function::new("STRING_AGG".to_string(), f.args),
690 ))),
691
692 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
694
695 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
697 "STRING_AGG".to_string(),
698 f.args,
699 )))),
700
701 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
703 "SUBSTRING".to_string(),
704 f.args,
705 )))),
706
707 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
709 "LEN".to_string(),
710 f.args,
711 )))),
712
713 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
715 seed: None,
716 lower: None,
717 upper: None,
718 }))),
719
720 "NOW" => Ok(Expression::Function(Box::new(Function::new(
722 "GETDATE".to_string(),
723 vec![],
724 )))),
725
726 "CURRENT_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
728 "GETDATE".to_string(),
729 vec![],
730 )))),
731
732 "CURRENT_DATE" => {
734 Ok(Expression::Function(Box::new(Function::new(
736 "CAST".to_string(),
737 vec![
738 Expression::Function(Box::new(Function::new(
739 "GETDATE".to_string(),
740 vec![],
741 ))),
742 Expression::Identifier(crate::expressions::Identifier::new("DATE")),
743 ],
744 ))))
745 }
746
747 "TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
749 "CONVERT".to_string(),
750 f.args,
751 )))),
752
753 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
755 "CONVERT".to_string(),
756 f.args,
757 )))),
758
759 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
761 "FORMAT".to_string(),
762 f.args,
763 )))),
764
765 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
767 "FORMAT".to_string(),
768 f.args,
769 )))),
770
771 "DATE_TRUNC" | "DATETRUNC" => {
774 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
775 if args.len() >= 2 {
777 if let Expression::Literal(Literal::String(_)) = &args[1] {
778 args[1] = Expression::Cast(Box::new(Cast {
779 this: args[1].clone(),
780 to: DataType::Custom {
781 name: "DATETIME2".to_string(),
782 },
783 trailing_comments: Vec::new(),
784 double_colon_syntax: false,
785 format: None,
786 default: None,
787 inferred_type: None,
788 }));
789 }
790 }
791 Ok(Expression::Function(Box::new(Function::new(
792 "DATETRUNC".to_string(),
793 args,
794 ))))
795 }
796
797 "DATEADD" => {
799 let args = Self::uppercase_first_arg_if_identifier(f.args);
800 Ok(Expression::Function(Box::new(Function::new(
801 "DATEADD".to_string(),
802 args,
803 ))))
804 }
805
806 "DATEDIFF" => {
808 let args = Self::uppercase_first_arg_if_identifier(f.args);
809 Ok(Expression::Function(Box::new(Function::new(
810 "DATEDIFF".to_string(),
811 args,
812 ))))
813 }
814
815 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
817 "DATEPART".to_string(),
818 f.args,
819 )))),
820
821 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
823 Ok(Expression::Function(Box::new(Function::new(
825 "CHARINDEX".to_string(),
826 f.args,
827 ))))
828 }
829
830 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
832
833 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
835 Function::new("CEILING".to_string(), f.args),
836 ))),
837
838 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
843 "JSON_VALUE".to_string(),
844 f.args,
845 )))),
846
847 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
849 "JSON_VALUE".to_string(),
850 f.args,
851 )))),
852
853 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
855
856 "GET_PATH" if f.args.len() == 2 => {
858 let mut args = f.args;
859 let this = args.remove(0);
860 let path = args.remove(0);
861 let json_path = match &path {
862 Expression::Literal(Literal::String(s)) => {
863 let normalized = if s.starts_with('$') {
864 s.clone()
865 } else if s.starts_with('[') {
866 format!("${}", s)
867 } else {
868 format!("$.{}", s)
869 };
870 Expression::Literal(Literal::String(normalized))
871 }
872 _ => path,
873 };
874 let json_query = Expression::Function(Box::new(Function::new(
876 "JSON_QUERY".to_string(),
877 vec![this.clone(), json_path.clone()],
878 )));
879 let json_value = Expression::Function(Box::new(Function::new(
880 "JSON_VALUE".to_string(),
881 vec![this, json_path],
882 )));
883 Ok(Expression::Function(Box::new(Function::new(
884 "ISNULL".to_string(),
885 vec![json_query, json_value],
886 ))))
887 }
888
889 "JSON_QUERY" if f.args.len() == 1 => {
892 let this = f.args.into_iter().next().unwrap();
893 let path = Expression::Literal(Literal::String("$".to_string()));
894 let json_query = Expression::Function(Box::new(Function::new(
895 "JSON_QUERY".to_string(),
896 vec![this.clone(), path.clone()],
897 )));
898 let json_value = Expression::Function(Box::new(Function::new(
899 "JSON_VALUE".to_string(),
900 vec![this, path],
901 )));
902 Ok(Expression::Function(Box::new(Function::new(
903 "ISNULL".to_string(),
904 vec![json_query, json_value],
905 ))))
906 }
907
908 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
910 "STRING_SPLIT".to_string(),
911 f.args,
912 )))),
913
914 "REGEXP_LIKE" => {
917 Ok(Expression::Function(Box::new(Function::new(
919 "PATINDEX".to_string(),
920 f.args,
921 ))))
922 }
923
924 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
926 "LOG".to_string(),
927 f.args,
928 )))),
929
930 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
935 "STDEV".to_string(),
936 f.args,
937 )))),
938
939 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
941 "STDEVP".to_string(),
942 f.args,
943 )))),
944
945 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
947 "VAR".to_string(),
948 f.args,
949 )))),
950
951 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
953 "VARP".to_string(),
954 f.args,
955 )))),
956
957 "DATE_ADD" => {
959 if f.args.len() == 2 {
960 let mut args = f.args;
961 let date = args.remove(0);
962 let interval = args.remove(0);
963 let unit = Expression::Identifier(crate::expressions::Identifier {
964 name: "DAY".to_string(),
965 quoted: false,
966 trailing_comments: Vec::new(),
967 span: None,
968 });
969 Ok(Expression::Function(Box::new(Function::new(
970 "DATEADD".to_string(),
971 vec![unit, interval, date],
972 ))))
973 } else {
974 let args = Self::uppercase_first_arg_if_identifier(f.args);
975 Ok(Expression::Function(Box::new(Function::new(
976 "DATEADD".to_string(),
977 args,
978 ))))
979 }
980 }
981
982 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
984 "STUFF".to_string(),
985 f.args,
986 )))),
987
988 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
990 crate::expressions::CurrentUser { this: None },
991 ))),
992
993 _ => Ok(Expression::Function(Box::new(f))),
995 }
996 }
997
998 fn transform_aggregate_function(
999 &self,
1000 f: Box<crate::expressions::AggregateFunction>,
1001 ) -> Result<Expression> {
1002 let name_upper = f.name.to_uppercase();
1003 match name_upper.as_str() {
1004 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1006 Function::new("STRING_AGG".to_string(), f.args),
1007 ))),
1008
1009 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1011 "STRING_AGG".to_string(),
1012 f.args,
1013 )))),
1014
1015 "ARRAY_AGG" if !f.args.is_empty() => {
1018 Ok(Expression::Function(Box::new(Function::new(
1020 "STRING_AGG".to_string(),
1021 f.args,
1022 ))))
1023 }
1024
1025 _ => Ok(Expression::AggregateFunction(f)),
1027 }
1028 }
1029
1030 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
1034 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
1035 }
1036
1037 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
1039 if cte.columns.is_empty() {
1042 cte.this = self.qualify_derived_table_outputs(cte.this);
1043 }
1044 cte
1045 }
1046
1047 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
1051 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
1054 subquery.this = self.qualify_derived_table_outputs(subquery.this);
1055 }
1056 Ok(Expression::Subquery(Box::new(subquery)))
1057 }
1058
1059 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
1063 match expr {
1064 Expression::Select(mut select) => {
1065 let has_from = select.from.is_some();
1068 if !has_from {
1069 select.expressions = select
1070 .expressions
1071 .into_iter()
1072 .map(|e| self.maybe_alias_expression(e))
1073 .collect();
1074 }
1075 Expression::Select(select)
1076 }
1077 Expression::Union(mut u) => {
1079 u.left = self.qualify_derived_table_outputs(u.left);
1080 Expression::Union(u)
1081 }
1082 Expression::Intersect(mut i) => {
1083 i.left = self.qualify_derived_table_outputs(i.left);
1084 Expression::Intersect(i)
1085 }
1086 Expression::Except(mut e) => {
1087 e.left = self.qualify_derived_table_outputs(e.left);
1088 Expression::Except(e)
1089 }
1090 Expression::Subquery(mut s) => {
1092 s.this = self.qualify_derived_table_outputs(s.this);
1093 Expression::Subquery(s)
1094 }
1095 other => other,
1097 }
1098 }
1099
1100 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
1105 match &expr {
1106 Expression::Alias(_) => expr,
1108 Expression::Aliases(_) => expr,
1110 Expression::Star(_) => expr,
1112 _ => {
1117 if let Some(output_name) = self.get_output_name(&expr) {
1118 Expression::Alias(Box::new(Alias {
1119 this: expr,
1120 alias: Identifier {
1121 name: output_name,
1122 quoted: true, trailing_comments: Vec::new(),
1124 span: None,
1125 },
1126 column_aliases: Vec::new(),
1127 pre_alias_comments: Vec::new(),
1128 trailing_comments: Vec::new(),
1129 inferred_type: None,
1130 }))
1131 } else {
1132 expr
1134 }
1135 }
1136 }
1137 }
1138
1139 fn get_output_name(&self, expr: &Expression) -> Option<String> {
1143 match expr {
1144 Expression::Literal(lit) => match lit {
1146 Literal::Number(n) => Some(n.clone()),
1147 Literal::String(s) => Some(s.clone()),
1148 Literal::HexString(h) => Some(format!("0x{}", h)),
1149 Literal::HexNumber(h) => Some(format!("0x{}", h)),
1150 Literal::BitString(b) => Some(format!("b{}", b)),
1151 Literal::ByteString(b) => Some(format!("b'{}'", b)),
1152 Literal::NationalString(s) => Some(format!("N'{}'", s)),
1153 Literal::Date(d) => Some(d.clone()),
1154 Literal::Time(t) => Some(t.clone()),
1155 Literal::Timestamp(ts) => Some(ts.clone()),
1156 Literal::Datetime(dt) => Some(dt.clone()),
1157 Literal::TripleQuotedString(s, _) => Some(s.clone()),
1158 Literal::EscapeString(s) => Some(s.clone()),
1159 Literal::DollarString(s) => Some(s.clone()),
1160 Literal::RawString(s) => Some(s.clone()),
1161 },
1162 Expression::Column(col) => Some(col.name.name.clone()),
1164 Expression::Identifier(ident) => Some(ident.name.clone()),
1166 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
1168 Expression::Null(_) => Some("NULL".to_string()),
1170 Expression::Function(f) => Some(f.name.clone()),
1172 Expression::AggregateFunction(f) => Some(f.name.clone()),
1174 _ => Some(format!("_col_{}", 0)),
1176 }
1177 }
1178
1179 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
1181 use crate::expressions::Identifier;
1182 if !args.is_empty() {
1183 match &args[0] {
1184 Expression::Identifier(id) => {
1185 args[0] = Expression::Identifier(Identifier {
1186 name: id.name.to_uppercase(),
1187 quoted: id.quoted,
1188 trailing_comments: id.trailing_comments.clone(),
1189 span: None,
1190 });
1191 }
1192 Expression::Column(col) if col.table.is_none() => {
1193 args[0] = Expression::Identifier(Identifier {
1194 name: col.name.name.to_uppercase(),
1195 quoted: col.name.quoted,
1196 trailing_comments: col.name.trailing_comments.clone(),
1197 span: None,
1198 });
1199 }
1200 _ => {}
1201 }
1202 }
1203 args
1204 }
1205}
1206
1207#[cfg(test)]
1208mod tests {
1209 use super::*;
1210 use crate::dialects::Dialect;
1211
1212 fn transpile_to_tsql(sql: &str) -> String {
1213 let dialect = Dialect::get(DialectType::Generic);
1214 let result = dialect
1215 .transpile_to(sql, DialectType::TSQL)
1216 .expect("Transpile failed");
1217 result[0].clone()
1218 }
1219
1220 #[test]
1221 fn test_nvl_to_isnull() {
1222 let result = transpile_to_tsql("SELECT NVL(a, b)");
1223 assert!(
1224 result.contains("ISNULL"),
1225 "Expected ISNULL, got: {}",
1226 result
1227 );
1228 }
1229
1230 #[test]
1231 fn test_coalesce_to_isnull() {
1232 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
1233 assert!(
1234 result.contains("ISNULL"),
1235 "Expected ISNULL, got: {}",
1236 result
1237 );
1238 }
1239
1240 #[test]
1241 fn test_basic_select() {
1242 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
1243 assert!(result.contains("SELECT"));
1244 assert!(result.contains("FROM users"));
1245 }
1246
1247 #[test]
1248 fn test_length_to_len() {
1249 let result = transpile_to_tsql("SELECT LENGTH(name)");
1250 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
1251 }
1252
1253 #[test]
1254 fn test_now_to_getdate() {
1255 let result = transpile_to_tsql("SELECT NOW()");
1256 assert!(
1257 result.contains("GETDATE"),
1258 "Expected GETDATE, got: {}",
1259 result
1260 );
1261 }
1262
1263 #[test]
1264 fn test_group_concat_to_string_agg() {
1265 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
1266 assert!(
1267 result.contains("STRING_AGG"),
1268 "Expected STRING_AGG, got: {}",
1269 result
1270 );
1271 }
1272
1273 #[test]
1274 fn test_listagg_to_string_agg() {
1275 let result = transpile_to_tsql("SELECT LISTAGG(name)");
1276 assert!(
1277 result.contains("STRING_AGG"),
1278 "Expected STRING_AGG, got: {}",
1279 result
1280 );
1281 }
1282
1283 #[test]
1284 fn test_ln_to_log() {
1285 let result = transpile_to_tsql("SELECT LN(x)");
1286 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
1287 }
1288
1289 #[test]
1290 fn test_stddev_to_stdev() {
1291 let result = transpile_to_tsql("SELECT STDDEV(x)");
1292 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
1293 }
1294
1295 #[test]
1296 fn test_bracket_identifiers() {
1297 let dialect = Dialect::get(DialectType::TSQL);
1299 let config = dialect.generator_config();
1300 assert_eq!(config.identifier_quote, '[');
1301 }
1302
1303 #[test]
1304 fn test_json_query_isnull_wrapper_simple() {
1305 let dialect = Dialect::get(DialectType::TSQL);
1307 let result = dialect
1308 .transpile_to(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
1309 .expect("transpile failed");
1310 assert!(
1311 result[0].contains("ISNULL"),
1312 "JSON_QUERY should be wrapped with ISNULL: {}",
1313 result[0]
1314 );
1315 }
1316
1317 #[test]
1318 fn test_json_query_isnull_wrapper_nested() {
1319 std::thread::Builder::new()
1321 .stack_size(16 * 1024 * 1024)
1322 .spawn(|| {
1323 let dialect = Dialect::get(DialectType::TSQL);
1324 let result = dialect.transpile_to(
1325 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
1326 DialectType::TSQL,
1327 ).expect("transpile failed");
1328 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
1329 assert_eq!(result[0], expected, "JSON_QUERY should be wrapped with ISNULL");
1330 })
1331 .expect("Failed to spawn test thread")
1332 .join()
1333 .expect("Test thread panicked");
1334 }
1335}