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(Box::new(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(Box::new(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(Box::new(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(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
566 let Literal::String(s) = lit.as_ref() else { unreachable!() };
567 let normalized = if s.starts_with('$') {
568 s.clone()
569 } else if s.starts_with('[') {
570 format!("${}", s)
571 } else {
572 format!("$.{}", s)
573 };
574 Expression::Literal(Box::new(Literal::String(normalized)))
575 }
576 other => other,
577 };
578 let json_query = Expression::Function(Box::new(Function::new(
579 "JSON_QUERY".to_string(),
580 vec![(*e.this).clone(), path.clone()],
581 )));
582 let json_value = Expression::Function(Box::new(Function::new(
583 "JSON_VALUE".to_string(),
584 vec![*e.this, path],
585 )));
586 Ok(Expression::Function(Box::new(Function::new(
587 "ISNULL".to_string(),
588 vec![json_query, json_value],
589 ))))
590 }
591
592 Expression::Function(f) => self.transform_function(*f),
594
595 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
597
598 Expression::Cte(cte) => self.transform_cte(*cte),
601
602 Expression::Subquery(subquery) => self.transform_subquery(*subquery),
605
606 Expression::JsonQuery(f) => {
608 let json_query = Expression::Function(Box::new(Function::new(
609 "JSON_QUERY".to_string(),
610 vec![f.this.clone(), f.path.clone()],
611 )));
612 let json_value = Expression::Function(Box::new(Function::new(
613 "JSON_VALUE".to_string(),
614 vec![f.this, f.path],
615 )));
616 Ok(Expression::Function(Box::new(Function::new(
617 "ISNULL".to_string(),
618 vec![json_query, json_value],
619 ))))
620 }
621 Expression::JsonValue(f) => Ok(Expression::Function(Box::new(Function::new(
623 "JSON_VALUE".to_string(),
624 vec![f.this, f.path],
625 )))),
626
627 _ => Ok(expr),
629 }
630 }
631}
632
633impl TSQLDialect {
634 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
636 use crate::expressions::DataType;
637 let transformed = match dt {
638 DataType::Boolean => DataType::Custom {
640 name: "BIT".to_string(),
641 },
642 DataType::Int { .. } => dt,
644 DataType::Decimal { precision, scale } => DataType::Custom {
647 name: if let (Some(p), Some(s)) = (&precision, &scale) {
648 format!("NUMERIC({}, {})", p, s)
649 } else if let Some(p) = &precision {
650 format!("NUMERIC({})", p)
651 } else {
652 "NUMERIC".to_string()
653 },
654 },
655 DataType::Text => DataType::Custom {
657 name: "VARCHAR(MAX)".to_string(),
658 },
659 DataType::Timestamp { .. } => DataType::Custom {
661 name: "DATETIME2".to_string(),
662 },
663 DataType::Uuid => DataType::Custom {
665 name: "UNIQUEIDENTIFIER".to_string(),
666 },
667 other => other,
669 };
670 Ok(Expression::DataType(transformed))
671 }
672
673 fn transform_function(&self, f: Function) -> Result<Expression> {
674 let name_upper = f.name.to_uppercase();
675 match name_upper.as_str() {
676 "COALESCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
678 "ISNULL".to_string(),
679 f.args,
680 )))),
681
682 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
684 "ISNULL".to_string(),
685 f.args,
686 )))),
687
688 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
690 Function::new("STRING_AGG".to_string(), f.args),
691 ))),
692
693 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
695
696 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
698 "STRING_AGG".to_string(),
699 f.args,
700 )))),
701
702 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
704 "SUBSTRING".to_string(),
705 f.args,
706 )))),
707
708 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
710 "LEN".to_string(),
711 f.args,
712 )))),
713
714 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
716 seed: None,
717 lower: None,
718 upper: None,
719 }))),
720
721 "NOW" => Ok(Expression::Function(Box::new(Function::new(
723 "GETDATE".to_string(),
724 vec![],
725 )))),
726
727 "CURRENT_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
729 "GETDATE".to_string(),
730 vec![],
731 )))),
732
733 "CURRENT_DATE" => {
735 Ok(Expression::Function(Box::new(Function::new(
737 "CAST".to_string(),
738 vec![
739 Expression::Function(Box::new(Function::new(
740 "GETDATE".to_string(),
741 vec![],
742 ))),
743 Expression::Identifier(crate::expressions::Identifier::new("DATE")),
744 ],
745 ))))
746 }
747
748 "TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
750 "CONVERT".to_string(),
751 f.args,
752 )))),
753
754 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
756 "CONVERT".to_string(),
757 f.args,
758 )))),
759
760 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
762 "FORMAT".to_string(),
763 f.args,
764 )))),
765
766 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
768 "FORMAT".to_string(),
769 f.args,
770 )))),
771
772 "DATE_TRUNC" | "DATETRUNC" => {
775 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
776 if args.len() >= 2 {
778 if let Expression::Literal(lit) = &args[1] {
779 if let Literal::String(_) = lit.as_ref() {
780 args[1] = Expression::Cast(Box::new(Cast {
781 this: args[1].clone(),
782 to: DataType::Custom {
783 name: "DATETIME2".to_string(),
784 },
785 trailing_comments: Vec::new(),
786 double_colon_syntax: false,
787 format: None,
788 default: None,
789 inferred_type: None,
790 }));
791 }
792 }
793 }
794 Ok(Expression::Function(Box::new(Function::new(
795 "DATETRUNC".to_string(),
796 args,
797 ))))
798 }
799
800 "DATEADD" => {
802 let args = Self::uppercase_first_arg_if_identifier(f.args);
803 Ok(Expression::Function(Box::new(Function::new(
804 "DATEADD".to_string(),
805 args,
806 ))))
807 }
808
809 "DATEDIFF" => {
811 let args = Self::uppercase_first_arg_if_identifier(f.args);
812 Ok(Expression::Function(Box::new(Function::new(
813 "DATEDIFF".to_string(),
814 args,
815 ))))
816 }
817
818 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
820 "DATEPART".to_string(),
821 f.args,
822 )))),
823
824 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
826 Ok(Expression::Function(Box::new(Function::new(
828 "CHARINDEX".to_string(),
829 f.args,
830 ))))
831 }
832
833 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
835
836 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
838 Function::new("CEILING".to_string(), f.args),
839 ))),
840
841 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
846 "JSON_VALUE".to_string(),
847 f.args,
848 )))),
849
850 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
852 "JSON_VALUE".to_string(),
853 f.args,
854 )))),
855
856 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
858
859 "GET_PATH" if f.args.len() == 2 => {
861 let mut args = f.args;
862 let this = args.remove(0);
863 let path = args.remove(0);
864 let json_path = match &path {
865 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
866 let Literal::String(s) = lit.as_ref() else { unreachable!() };
867 let normalized = if s.starts_with('$') {
868 s.clone()
869 } else if s.starts_with('[') {
870 format!("${}", s)
871 } else {
872 format!("$.{}", s)
873 };
874 Expression::Literal(Box::new(Literal::String(normalized)))
875 }
876 _ => path,
877 };
878 let json_query = Expression::Function(Box::new(Function::new(
880 "JSON_QUERY".to_string(),
881 vec![this.clone(), json_path.clone()],
882 )));
883 let json_value = Expression::Function(Box::new(Function::new(
884 "JSON_VALUE".to_string(),
885 vec![this, json_path],
886 )));
887 Ok(Expression::Function(Box::new(Function::new(
888 "ISNULL".to_string(),
889 vec![json_query, json_value],
890 ))))
891 }
892
893 "JSON_QUERY" if f.args.len() == 1 => {
896 let this = f.args.into_iter().next().unwrap();
897 let path = Expression::Literal(Box::new(Literal::String("$".to_string())));
898 let json_query = Expression::Function(Box::new(Function::new(
899 "JSON_QUERY".to_string(),
900 vec![this.clone(), path.clone()],
901 )));
902 let json_value = Expression::Function(Box::new(Function::new(
903 "JSON_VALUE".to_string(),
904 vec![this, path],
905 )));
906 Ok(Expression::Function(Box::new(Function::new(
907 "ISNULL".to_string(),
908 vec![json_query, json_value],
909 ))))
910 }
911
912 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
914 "STRING_SPLIT".to_string(),
915 f.args,
916 )))),
917
918 "REGEXP_LIKE" => {
921 Ok(Expression::Function(Box::new(Function::new(
923 "PATINDEX".to_string(),
924 f.args,
925 ))))
926 }
927
928 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
930 "LOG".to_string(),
931 f.args,
932 )))),
933
934 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
939 "STDEV".to_string(),
940 f.args,
941 )))),
942
943 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
945 "STDEVP".to_string(),
946 f.args,
947 )))),
948
949 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
951 "VAR".to_string(),
952 f.args,
953 )))),
954
955 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
957 "VARP".to_string(),
958 f.args,
959 )))),
960
961 "DATE_ADD" => {
963 if f.args.len() == 2 {
964 let mut args = f.args;
965 let date = args.remove(0);
966 let interval = args.remove(0);
967 let unit = Expression::Identifier(crate::expressions::Identifier {
968 name: "DAY".to_string(),
969 quoted: false,
970 trailing_comments: Vec::new(),
971 span: None,
972 });
973 Ok(Expression::Function(Box::new(Function::new(
974 "DATEADD".to_string(),
975 vec![unit, interval, date],
976 ))))
977 } else {
978 let args = Self::uppercase_first_arg_if_identifier(f.args);
979 Ok(Expression::Function(Box::new(Function::new(
980 "DATEADD".to_string(),
981 args,
982 ))))
983 }
984 }
985
986 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
988 "STUFF".to_string(),
989 f.args,
990 )))),
991
992 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
994 crate::expressions::CurrentUser { this: None },
995 ))),
996
997 _ => Ok(Expression::Function(Box::new(f))),
999 }
1000 }
1001
1002 fn transform_aggregate_function(
1003 &self,
1004 f: Box<crate::expressions::AggregateFunction>,
1005 ) -> Result<Expression> {
1006 let name_upper = f.name.to_uppercase();
1007 match name_upper.as_str() {
1008 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1010 Function::new("STRING_AGG".to_string(), f.args),
1011 ))),
1012
1013 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1015 "STRING_AGG".to_string(),
1016 f.args,
1017 )))),
1018
1019 "ARRAY_AGG" if !f.args.is_empty() => {
1022 Ok(Expression::Function(Box::new(Function::new(
1024 "STRING_AGG".to_string(),
1025 f.args,
1026 ))))
1027 }
1028
1029 _ => Ok(Expression::AggregateFunction(f)),
1031 }
1032 }
1033
1034 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
1038 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
1039 }
1040
1041 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
1043 if cte.columns.is_empty() {
1046 cte.this = self.qualify_derived_table_outputs(cte.this);
1047 }
1048 cte
1049 }
1050
1051 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
1055 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
1058 subquery.this = self.qualify_derived_table_outputs(subquery.this);
1059 }
1060 Ok(Expression::Subquery(Box::new(subquery)))
1061 }
1062
1063 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
1067 match expr {
1068 Expression::Select(mut select) => {
1069 let has_from = select.from.is_some();
1072 if !has_from {
1073 select.expressions = select
1074 .expressions
1075 .into_iter()
1076 .map(|e| self.maybe_alias_expression(e))
1077 .collect();
1078 }
1079 Expression::Select(select)
1080 }
1081 Expression::Union(mut u) => {
1083 u.left = self.qualify_derived_table_outputs(u.left);
1084 Expression::Union(u)
1085 }
1086 Expression::Intersect(mut i) => {
1087 i.left = self.qualify_derived_table_outputs(i.left);
1088 Expression::Intersect(i)
1089 }
1090 Expression::Except(mut e) => {
1091 e.left = self.qualify_derived_table_outputs(e.left);
1092 Expression::Except(e)
1093 }
1094 Expression::Subquery(mut s) => {
1096 s.this = self.qualify_derived_table_outputs(s.this);
1097 Expression::Subquery(s)
1098 }
1099 other => other,
1101 }
1102 }
1103
1104 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
1109 match &expr {
1110 Expression::Alias(_) => expr,
1112 Expression::Aliases(_) => expr,
1114 Expression::Star(_) => expr,
1116 _ => {
1121 if let Some(output_name) = self.get_output_name(&expr) {
1122 Expression::Alias(Box::new(Alias {
1123 this: expr,
1124 alias: Identifier {
1125 name: output_name,
1126 quoted: true, trailing_comments: Vec::new(),
1128 span: None,
1129 },
1130 column_aliases: Vec::new(),
1131 pre_alias_comments: Vec::new(),
1132 trailing_comments: Vec::new(),
1133 inferred_type: None,
1134 }))
1135 } else {
1136 expr
1138 }
1139 }
1140 }
1141 }
1142
1143 fn get_output_name(&self, expr: &Expression) -> Option<String> {
1147 match expr {
1148 Expression::Literal(lit) => match lit.as_ref() {
1150 Literal::Number(n) => Some(n.clone()),
1151 Literal::String(s) => Some(s.clone()),
1152 Literal::HexString(h) => Some(format!("0x{}", h)),
1153 Literal::HexNumber(h) => Some(format!("0x{}", h)),
1154 Literal::BitString(b) => Some(format!("b{}", b)),
1155 Literal::ByteString(b) => Some(format!("b'{}'", b)),
1156 Literal::NationalString(s) => Some(format!("N'{}'", s)),
1157 Literal::Date(d) => Some(d.clone()),
1158 Literal::Time(t) => Some(t.clone()),
1159 Literal::Timestamp(ts) => Some(ts.clone()),
1160 Literal::Datetime(dt) => Some(dt.clone()),
1161 Literal::TripleQuotedString(s, _) => Some(s.clone()),
1162 Literal::EscapeString(s) => Some(s.clone()),
1163 Literal::DollarString(s) => Some(s.clone()),
1164 Literal::RawString(s) => Some(s.clone()),
1165 },
1166 Expression::Column(col) => Some(col.name.name.clone()),
1168 Expression::Identifier(ident) => Some(ident.name.clone()),
1170 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
1172 Expression::Null(_) => Some("NULL".to_string()),
1174 Expression::Function(f) => Some(f.name.clone()),
1176 Expression::AggregateFunction(f) => Some(f.name.clone()),
1178 _ => Some(format!("_col_{}", 0)),
1180 }
1181 }
1182
1183 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
1185 use crate::expressions::Identifier;
1186 if !args.is_empty() {
1187 match &args[0] {
1188 Expression::Identifier(id) => {
1189 args[0] = Expression::Identifier(Identifier {
1190 name: id.name.to_uppercase(),
1191 quoted: id.quoted,
1192 trailing_comments: id.trailing_comments.clone(),
1193 span: None,
1194 });
1195 }
1196 Expression::Column(col) if col.table.is_none() => {
1197 args[0] = Expression::Identifier(Identifier {
1198 name: col.name.name.to_uppercase(),
1199 quoted: col.name.quoted,
1200 trailing_comments: col.name.trailing_comments.clone(),
1201 span: None,
1202 });
1203 }
1204 _ => {}
1205 }
1206 }
1207 args
1208 }
1209}
1210
1211#[cfg(test)]
1212mod tests {
1213 use super::*;
1214 use crate::dialects::Dialect;
1215
1216 fn transpile_to_tsql(sql: &str) -> String {
1217 let dialect = Dialect::get(DialectType::Generic);
1218 let result = dialect
1219 .transpile_to(sql, DialectType::TSQL)
1220 .expect("Transpile failed");
1221 result[0].clone()
1222 }
1223
1224 #[test]
1225 fn test_nvl_to_isnull() {
1226 let result = transpile_to_tsql("SELECT NVL(a, b)");
1227 assert!(
1228 result.contains("ISNULL"),
1229 "Expected ISNULL, got: {}",
1230 result
1231 );
1232 }
1233
1234 #[test]
1235 fn test_coalesce_to_isnull() {
1236 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
1237 assert!(
1238 result.contains("ISNULL"),
1239 "Expected ISNULL, got: {}",
1240 result
1241 );
1242 }
1243
1244 #[test]
1245 fn test_basic_select() {
1246 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
1247 assert!(result.contains("SELECT"));
1248 assert!(result.contains("FROM users"));
1249 }
1250
1251 #[test]
1252 fn test_length_to_len() {
1253 let result = transpile_to_tsql("SELECT LENGTH(name)");
1254 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
1255 }
1256
1257 #[test]
1258 fn test_now_to_getdate() {
1259 let result = transpile_to_tsql("SELECT NOW()");
1260 assert!(
1261 result.contains("GETDATE"),
1262 "Expected GETDATE, got: {}",
1263 result
1264 );
1265 }
1266
1267 #[test]
1268 fn test_group_concat_to_string_agg() {
1269 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
1270 assert!(
1271 result.contains("STRING_AGG"),
1272 "Expected STRING_AGG, got: {}",
1273 result
1274 );
1275 }
1276
1277 #[test]
1278 fn test_listagg_to_string_agg() {
1279 let result = transpile_to_tsql("SELECT LISTAGG(name)");
1280 assert!(
1281 result.contains("STRING_AGG"),
1282 "Expected STRING_AGG, got: {}",
1283 result
1284 );
1285 }
1286
1287 #[test]
1288 fn test_ln_to_log() {
1289 let result = transpile_to_tsql("SELECT LN(x)");
1290 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
1291 }
1292
1293 #[test]
1294 fn test_stddev_to_stdev() {
1295 let result = transpile_to_tsql("SELECT STDDEV(x)");
1296 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
1297 }
1298
1299 #[test]
1300 fn test_bracket_identifiers() {
1301 let dialect = Dialect::get(DialectType::TSQL);
1303 let config = dialect.generator_config();
1304 assert_eq!(config.identifier_quote, '[');
1305 }
1306
1307 #[test]
1308 fn test_json_query_isnull_wrapper_simple() {
1309 let dialect = Dialect::get(DialectType::TSQL);
1311 let result = dialect
1312 .transpile_to(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
1313 .expect("transpile failed");
1314 assert!(
1315 result[0].contains("ISNULL"),
1316 "JSON_QUERY should be wrapped with ISNULL: {}",
1317 result[0]
1318 );
1319 }
1320
1321 #[test]
1322 fn test_json_query_isnull_wrapper_nested() {
1323 std::thread::Builder::new()
1325 .stack_size(16 * 1024 * 1024)
1326 .spawn(|| {
1327 let dialect = Dialect::get(DialectType::TSQL);
1328 let result = dialect.transpile_to(
1329 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
1330 DialectType::TSQL,
1331 ).expect("transpile failed");
1332 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
1333 assert_eq!(result[0], expected, "JSON_QUERY should be wrapped with ISNULL");
1334 })
1335 .expect("Failed to spawn test thread")
1336 .join()
1337 .expect("Test thread panicked");
1338 }
1339}