1use super::{DialectImpl, DialectType};
14use crate::error::Result;
15use crate::expressions::{
16 Alias, Cast, Cte, DataType, Expression, Function, Identifier, In, Join, JoinKind, LikeOp,
17 Literal, Null, QuantifiedOp, StringAggFunc, Subquery, UnaryFunc,
18};
19#[cfg(feature = "generate")]
20use crate::generator::GeneratorConfig;
21use crate::tokens::TokenizerConfig;
22
23pub struct TSQLDialect;
25
26impl DialectImpl for TSQLDialect {
27 fn dialect_type(&self) -> DialectType {
28 DialectType::TSQL
29 }
30
31 fn tokenizer_config(&self) -> TokenizerConfig {
32 let mut config = TokenizerConfig::default();
33 config.identifiers.insert('[', ']');
35 config.identifiers.insert('"', '"');
37 config
38 }
39
40 #[cfg(feature = "generate")]
41
42 fn generator_config(&self) -> GeneratorConfig {
43 use crate::generator::IdentifierQuoteStyle;
44 GeneratorConfig {
45 identifier_quote: '[',
47 identifier_quote_style: IdentifierQuoteStyle::BRACKET,
48 dialect: Some(DialectType::TSQL),
49 limit_fetch_style: crate::generator::LimitFetchStyle::FetchFirst,
52 null_ordering_supported: false,
54 supports_select_into: true,
56 alter_table_include_column_keyword: false,
58 computed_column_with_type: false,
60 cte_recursive_keyword_required: false,
62 ensure_bools: true,
64 supports_single_arg_concat: false,
66 tablesample_seed_keyword: "REPEATABLE",
68 json_path_bracketed_key_supported: false,
70 supports_to_number: false,
72 set_op_modifiers: false,
74 copy_params_eq_required: true,
76 except_intersect_support_all_clause: false,
78 alter_set_wrapped: true,
80 try_supported: true,
82 nvl2_supported: false,
84 parameter_default_equals: true,
86 supports_window_exclude: false,
88 multi_arg_distinct: false,
90 locking_reads_supported: false,
92 ..Default::default()
93 }
94 }
95
96 #[cfg(feature = "transpile")]
97
98 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
99 if let Expression::CreateTable(mut ct) = expr {
101 for col in &mut ct.columns {
102 if let Ok(Expression::DataType(new_dt)) =
103 self.transform_data_type(col.data_type.clone())
104 {
105 col.data_type = new_dt;
106 }
107 }
108 return Ok(Expression::CreateTable(ct));
109 }
110
111 match expr {
112 Expression::Select(mut select) => {
117 select.expressions = select
118 .expressions
119 .into_iter()
120 .map(|e| {
121 match e {
122 Expression::Eq(op) => {
123 match &op.left {
126 Expression::Column(col)
127 if col.table.is_none()
128 && !col.name.name.starts_with('@') =>
129 {
130 Expression::Alias(Box::new(Alias {
131 this: op.right,
132 alias: col.name.clone(),
133 column_aliases: Vec::new(),
134 alias_explicit_as: false,
135 alias_keyword: None,
136 pre_alias_comments: Vec::new(),
137 trailing_comments: Vec::new(),
138 inferred_type: None,
139 }))
140 }
141 Expression::Identifier(ident)
142 if !ident.name.starts_with('@') =>
143 {
144 Expression::Alias(Box::new(Alias {
145 this: op.right,
146 alias: ident.clone(),
147 column_aliases: Vec::new(),
148 alias_explicit_as: false,
149 alias_keyword: None,
150 pre_alias_comments: Vec::new(),
151 trailing_comments: Vec::new(),
152 inferred_type: None,
153 }))
154 }
155 _ => Expression::Eq(op),
156 }
157 }
158 other => other,
159 }
160 })
161 .collect();
162
163 if let Some(ref mut with) = select.with {
165 with.ctes = with
166 .ctes
167 .drain(..)
168 .map(|cte| self.transform_cte_inner(cte))
169 .collect();
170 }
171
172 Ok(Expression::Select(select))
173 }
174
175 Expression::DataType(dt) => self.transform_data_type(dt),
177
178 Expression::IsTrue(it) => {
181 let one = Expression::Literal(Box::new(crate::expressions::Literal::Number(
182 "1".to_string(),
183 )));
184 if it.not {
185 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
187 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
188 left: it.this,
189 right: one,
190 left_comments: vec![],
191 operator_comments: vec![],
192 trailing_comments: vec![],
193 inferred_type: None,
194 })),
195 inferred_type: None,
196 })))
197 } else {
198 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
200 left: it.this,
201 right: one,
202 left_comments: vec![],
203 operator_comments: vec![],
204 trailing_comments: vec![],
205 inferred_type: None,
206 })))
207 }
208 }
209 Expression::IsFalse(it) => {
210 let zero = Expression::Literal(Box::new(crate::expressions::Literal::Number(
211 "0".to_string(),
212 )));
213 if it.not {
214 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
216 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
217 left: it.this,
218 right: zero,
219 left_comments: vec![],
220 operator_comments: vec![],
221 trailing_comments: vec![],
222 inferred_type: None,
223 })),
224 inferred_type: None,
225 })))
226 } else {
227 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
229 left: it.this,
230 right: zero,
231 left_comments: vec![],
232 operator_comments: vec![],
233 trailing_comments: vec![],
234 inferred_type: None,
235 })))
236 }
237 }
238
239 Expression::In(mut in_expr) if in_expr.not => {
243 in_expr.not = false;
244 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
245 this: Expression::In(in_expr),
246 inferred_type: None,
247 })))
248 }
249
250 Expression::Coalesce(f) if f.expressions.len() == 2 => Ok(Expression::Function(
253 Box::new(Function::new("ISNULL".to_string(), f.expressions)),
254 )),
255
256 Expression::Nvl(f) => Ok(Expression::Function(Box::new(Function::new(
258 "ISNULL".to_string(),
259 vec![f.this, f.expression],
260 )))),
261
262 Expression::GroupConcat(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
264 this: f.this,
265 separator: f.separator,
266 order_by: f.order_by,
267 distinct: f.distinct,
268 filter: f.filter,
269 limit: None,
270 inferred_type: None,
271 }))),
272
273 Expression::ListAgg(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
275 this: f.this,
276 separator: f.separator,
277 order_by: f.order_by,
278 distinct: f.distinct,
279 filter: f.filter,
280 limit: None,
281 inferred_type: None,
282 }))),
283
284 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
286
287 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
289
290 Expression::ILike(op) => {
292 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
295 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
296 Ok(Expression::Like(Box::new(LikeOp {
297 left: lower_left,
298 right: lower_right,
299 escape: op.escape,
300 quantifier: op.quantifier,
301 inferred_type: None,
302 })))
303 }
304
305 Expression::Concat(op) => {
308 Ok(Expression::Add(op))
310 }
311
312 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
314 seed: None,
315 lower: None,
316 upper: None,
317 }))),
318
319 Expression::Unnest(f) => {
321 Ok(Expression::Function(Box::new(Function::new(
324 "OPENJSON".to_string(),
325 vec![f.this],
326 ))))
327 }
328
329 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
331 "OPENJSON".to_string(),
332 vec![f.this],
333 )))),
334
335 Expression::Join(join) if join.kind == JoinKind::Lateral => {
337 Ok(Expression::Join(Box::new(Join {
338 this: join.this,
339 on: None,
340 using: join.using,
341 kind: JoinKind::CrossApply,
342 use_inner_keyword: false,
343 use_outer_keyword: false,
344 deferred_condition: false,
345 join_hint: None,
346 match_condition: None,
347 pivots: join.pivots,
348 comments: join.comments,
349 nesting_group: 0,
350 directed: false,
351 })))
352 }
353
354 Expression::Join(join) if join.kind == JoinKind::LeftLateral => {
356 Ok(Expression::Join(Box::new(Join {
357 this: join.this,
358 on: None, using: join.using,
360 kind: JoinKind::OuterApply,
361 use_inner_keyword: false,
362 use_outer_keyword: false,
363 deferred_condition: false,
364 join_hint: None,
365 match_condition: None,
366 pivots: join.pivots,
367 comments: join.comments,
368 nesting_group: 0,
369 directed: false,
370 })))
371 }
372
373 Expression::Length(f) => Ok(Expression::Function(Box::new(Function::new(
375 "LEN".to_string(),
376 vec![f.this],
377 )))),
378
379 Expression::Stddev(f) => Ok(Expression::Function(Box::new(Function::new(
381 "STDEV".to_string(),
382 vec![f.this],
383 )))),
384
385 Expression::Boolean(b) => {
387 let value = if b.value { 1 } else { 0 };
388 Ok(Expression::Literal(Box::new(
389 crate::expressions::Literal::Number(value.to_string()),
390 )))
391 }
392
393 Expression::Ln(f) => Ok(Expression::Function(Box::new(Function::new(
395 "LOG".to_string(),
396 vec![f.this],
397 )))),
398
399 Expression::CurrentDate(_) => {
402 let getdate =
403 Expression::Function(Box::new(Function::new("GETDATE".to_string(), vec![])));
404 Ok(Expression::Cast(Box::new(crate::expressions::Cast {
405 this: getdate,
406 to: crate::expressions::DataType::Date,
407 trailing_comments: Vec::new(),
408 double_colon_syntax: false,
409 format: None,
410 default: None,
411 inferred_type: None,
412 })))
413 }
414
415 Expression::CurrentTimestamp(_) => Ok(Expression::Function(Box::new(Function::new(
417 "GETDATE".to_string(),
418 vec![],
419 )))),
420
421 Expression::DateDiff(f) => {
423 let unit_str = match f.unit {
425 Some(crate::expressions::IntervalUnit::Year) => "YEAR",
426 Some(crate::expressions::IntervalUnit::Quarter) => "QUARTER",
427 Some(crate::expressions::IntervalUnit::Month) => "MONTH",
428 Some(crate::expressions::IntervalUnit::Week) => "WEEK",
429 Some(crate::expressions::IntervalUnit::Day) => "DAY",
430 Some(crate::expressions::IntervalUnit::Hour) => "HOUR",
431 Some(crate::expressions::IntervalUnit::Minute) => "MINUTE",
432 Some(crate::expressions::IntervalUnit::Second) => "SECOND",
433 Some(crate::expressions::IntervalUnit::Millisecond) => "MILLISECOND",
434 Some(crate::expressions::IntervalUnit::Microsecond) => "MICROSECOND",
435 Some(crate::expressions::IntervalUnit::Nanosecond) => "NANOSECOND",
436 None => "DAY",
437 };
438 let unit = Expression::Identifier(crate::expressions::Identifier {
439 name: unit_str.to_string(),
440 quoted: false,
441 trailing_comments: Vec::new(),
442 span: None,
443 });
444 Ok(Expression::Function(Box::new(Function::new(
445 "DATEDIFF".to_string(),
446 vec![unit, f.expression, f.this], ))))
448 }
449
450 Expression::DateAdd(f) => {
452 let unit_str = match f.unit {
453 crate::expressions::IntervalUnit::Year => "YEAR",
454 crate::expressions::IntervalUnit::Quarter => "QUARTER",
455 crate::expressions::IntervalUnit::Month => "MONTH",
456 crate::expressions::IntervalUnit::Week => "WEEK",
457 crate::expressions::IntervalUnit::Day => "DAY",
458 crate::expressions::IntervalUnit::Hour => "HOUR",
459 crate::expressions::IntervalUnit::Minute => "MINUTE",
460 crate::expressions::IntervalUnit::Second => "SECOND",
461 crate::expressions::IntervalUnit::Millisecond => "MILLISECOND",
462 crate::expressions::IntervalUnit::Microsecond => "MICROSECOND",
463 crate::expressions::IntervalUnit::Nanosecond => "NANOSECOND",
464 };
465 let unit = Expression::Identifier(crate::expressions::Identifier {
466 name: unit_str.to_string(),
467 quoted: false,
468 trailing_comments: Vec::new(),
469 span: None,
470 });
471 Ok(Expression::Function(Box::new(Function::new(
472 "DATEADD".to_string(),
473 vec![unit, f.interval, f.this],
474 ))))
475 }
476
477 Expression::Uuid(_) => Ok(Expression::Function(Box::new(Function::new(
480 "NEWID".to_string(),
481 vec![],
482 )))),
483
484 Expression::IfFunc(f) => {
487 let false_val = f
488 .false_value
489 .unwrap_or(Expression::Null(crate::expressions::Null));
490 Ok(Expression::Function(Box::new(Function::new(
491 "IIF".to_string(),
492 vec![f.condition, f.true_value, false_val],
493 ))))
494 }
495
496 Expression::StringAgg(f) => Ok(Expression::StringAgg(f)),
499
500 Expression::LastDay(f) => Ok(Expression::Function(Box::new(Function::new(
502 "EOMONTH".to_string(),
503 vec![f.this.clone()],
504 )))),
505
506 Expression::Ceil(f) => Ok(Expression::Function(Box::new(Function::new(
508 "CEILING".to_string(),
509 vec![f.this],
510 )))),
511
512 Expression::Repeat(f) => Ok(Expression::Function(Box::new(Function::new(
514 "REPLICATE".to_string(),
515 vec![f.this, f.times],
516 )))),
517
518 Expression::Chr(f) => Ok(Expression::Function(Box::new(Function::new(
520 "CHAR".to_string(),
521 vec![f.this],
522 )))),
523
524 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
527 "VARP".to_string(),
528 vec![f.this],
529 )))),
530
531 Expression::Variance(f) => Ok(Expression::Function(Box::new(Function::new(
533 "VAR".to_string(),
534 vec![f.this],
535 )))),
536
537 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
540 "HASHBYTES".to_string(),
541 vec![Expression::string("MD5"), *f.this],
542 )))),
543
544 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
546 "HASHBYTES".to_string(),
547 vec![Expression::string("SHA1"), f.this],
548 )))),
549
550 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
552 "HASHBYTES".to_string(),
553 vec![Expression::string("SHA1"), f.this],
554 )))),
555
556 Expression::ArrayToString(f) => Ok(Expression::Function(Box::new(Function::new(
559 "STRING_AGG".to_string(),
560 vec![f.this],
561 )))),
562
563 Expression::AutoIncrementColumnConstraint(_) => Ok(Expression::Function(Box::new(
566 Function::new("IDENTITY".to_string(), vec![]),
567 ))),
568
569 Expression::CreateView(mut view) => {
573 view.name.catalog = None;
575 Ok(Expression::CreateView(view))
576 }
577
578 Expression::DropView(mut view) => {
579 view.name.catalog = None;
581 Ok(Expression::DropView(view))
582 }
583
584 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
588 let path = match *e.expression {
589 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
590 let Literal::String(s) = lit.as_ref() else {
591 unreachable!()
592 };
593 let normalized = if s.starts_with('$') {
594 s.clone()
595 } else if s.starts_with('[') {
596 format!("${}", s)
597 } else {
598 format!("$.{}", s)
599 };
600 Expression::Literal(Box::new(Literal::String(normalized)))
601 }
602 other => other,
603 };
604 let json_query = Expression::Function(Box::new(Function::new(
605 "JSON_QUERY".to_string(),
606 vec![(*e.this).clone(), path.clone()],
607 )));
608 let json_value = Expression::Function(Box::new(Function::new(
609 "JSON_VALUE".to_string(),
610 vec![*e.this, path],
611 )));
612 Ok(Expression::Function(Box::new(Function::new(
613 "ISNULL".to_string(),
614 vec![json_query, json_value],
615 ))))
616 }
617
618 Expression::Function(f) => self.transform_function(*f),
620
621 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
623
624 Expression::Cte(cte) => self.transform_cte(*cte),
627
628 Expression::Subquery(subquery) => self.transform_subquery(*subquery),
631
632 Expression::JsonQuery(f) => {
634 let json_query = Expression::Function(Box::new(Function::new(
635 "JSON_QUERY".to_string(),
636 vec![f.this.clone(), f.path.clone()],
637 )));
638 let json_value = Expression::Function(Box::new(Function::new(
639 "JSON_VALUE".to_string(),
640 vec![f.this, f.path],
641 )));
642 Ok(Expression::Function(Box::new(Function::new(
643 "ISNULL".to_string(),
644 vec![json_query, json_value],
645 ))))
646 }
647 Expression::JsonValue(f) => Ok(Expression::Function(Box::new(Function::new(
649 "JSON_VALUE".to_string(),
650 vec![f.this, f.path],
651 )))),
652
653 Expression::Any(ref q) if matches!(&q.op, Some(QuantifiedOp::Eq)) => {
656 let values: Option<Vec<Expression>> = match &q.subquery {
657 Expression::ArrayFunc(a) => Some(a.expressions.clone()),
658 Expression::Array(a) => Some(a.expressions.clone()),
659 Expression::Tuple(t) => Some(t.expressions.clone()),
660 _ => None,
661 };
662
663 match values {
664 Some(expressions) if expressions.is_empty() => {
665 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp::new(
666 Expression::Literal(Box::new(Literal::Number("1".to_string()))),
667 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
668 ))))
669 }
670 Some(expressions) => Ok(Expression::In(Box::new(In {
671 this: q.this.clone(),
672 expressions,
673 query: None,
674 not: false,
675 global: false,
676 unnest: None,
677 is_field: false,
678 }))),
679 None => Ok(expr.clone()),
680 }
681 }
682
683 _ => Ok(expr),
685 }
686 }
687}
688
689#[cfg(feature = "transpile")]
690impl TSQLDialect {
691 pub(super) fn transform_data_type(
693 &self,
694 dt: crate::expressions::DataType,
695 ) -> Result<Expression> {
696 use crate::expressions::DataType;
697 let transformed = match dt {
698 DataType::Boolean => DataType::Custom {
700 name: "BIT".to_string(),
701 },
702 DataType::Int { .. } => dt,
704 DataType::Decimal { precision, scale } => DataType::Custom {
707 name: if let (Some(p), Some(s)) = (&precision, &scale) {
708 format!("NUMERIC({}, {})", p, s)
709 } else if let Some(p) = &precision {
710 format!("NUMERIC({})", p)
711 } else {
712 "NUMERIC".to_string()
713 },
714 },
715 DataType::Text => DataType::Custom {
717 name: "VARCHAR(MAX)".to_string(),
718 },
719 DataType::Timestamp { .. } => DataType::Custom {
721 name: "DATETIME2".to_string(),
722 },
723 DataType::Uuid => DataType::Custom {
725 name: "UNIQUEIDENTIFIER".to_string(),
726 },
727 DataType::Custom { ref name } => {
729 let upper = name.trim().to_uppercase();
730 let (base_name, precision, _scale) = Self::parse_type_precision_and_scale(&upper);
731 match base_name.as_str() {
732 "BPCHAR" => {
734 if let Some(len) = precision {
735 DataType::Char { length: Some(len) }
736 } else {
737 DataType::Char { length: None }
738 }
739 }
740 _ => dt,
741 }
742 }
743 other => other,
745 };
746 Ok(Expression::DataType(transformed))
747 }
748
749 pub(super) fn parse_type_precision_and_scale(name: &str) -> (String, Option<u32>, Option<u32>) {
751 if let Some(paren_pos) = name.find('(') {
752 let base = name[..paren_pos].to_string();
753 let rest = &name[paren_pos + 1..];
754 if let Some(close_pos) = rest.find(')') {
755 let args = &rest[..close_pos];
756 let parts: Vec<&str> = args.split(',').map(|s| s.trim()).collect();
757 let precision = parts.first().and_then(|s| s.parse::<u32>().ok());
758 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
759 return (base, precision, scale);
760 }
761 (base, None, None)
762 } else {
763 (name.to_string(), None, None)
764 }
765 }
766
767 fn transform_function(&self, f: Function) -> Result<Expression> {
768 let name_upper = f.name.to_uppercase();
769 match name_upper.as_str() {
770 "COALESCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
772 "ISNULL".to_string(),
773 f.args,
774 )))),
775
776 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
778 "ISNULL".to_string(),
779 f.args,
780 )))),
781
782 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
784 Function::new("STRING_AGG".to_string(), f.args),
785 ))),
786
787 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
789
790 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
792 "STRING_AGG".to_string(),
793 f.args,
794 )))),
795
796 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
798 "SUBSTRING".to_string(),
799 f.args,
800 )))),
801
802 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
804 "LEN".to_string(),
805 f.args,
806 )))),
807
808 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
810 seed: None,
811 lower: None,
812 upper: None,
813 }))),
814
815 "NOW" => Ok(Expression::Function(Box::new(Function::new(
817 "GETDATE".to_string(),
818 vec![],
819 )))),
820
821 "CURRENT_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
823 "GETDATE".to_string(),
824 vec![],
825 )))),
826
827 "CURRENT_DATE" => {
829 Ok(Expression::Function(Box::new(Function::new(
831 "CAST".to_string(),
832 vec![
833 Expression::Function(Box::new(Function::new(
834 "GETDATE".to_string(),
835 vec![],
836 ))),
837 Expression::Identifier(crate::expressions::Identifier::new("DATE")),
838 ],
839 ))))
840 }
841
842 "TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
844 "CONVERT".to_string(),
845 f.args,
846 )))),
847
848 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
850 "CONVERT".to_string(),
851 f.args,
852 )))),
853
854 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
856 "FORMAT".to_string(),
857 f.args,
858 )))),
859
860 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
862 "FORMAT".to_string(),
863 f.args,
864 )))),
865
866 "DATE_TRUNC" | "DATETRUNC" => {
869 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
870 if args.len() >= 2 {
872 if let Expression::Literal(lit) = &args[1] {
873 if let Literal::String(_) = lit.as_ref() {
874 args[1] = Expression::Cast(Box::new(Cast {
875 this: args[1].clone(),
876 to: DataType::Custom {
877 name: "DATETIME2".to_string(),
878 },
879 trailing_comments: Vec::new(),
880 double_colon_syntax: false,
881 format: None,
882 default: None,
883 inferred_type: None,
884 }));
885 }
886 }
887 }
888 Ok(Expression::Function(Box::new(Function::new(
889 "DATETRUNC".to_string(),
890 args,
891 ))))
892 }
893
894 "DATEADD" => {
896 let args = Self::uppercase_first_arg_if_identifier(f.args);
897 Ok(Expression::Function(Box::new(Function::new(
898 "DATEADD".to_string(),
899 args,
900 ))))
901 }
902
903 "DATEDIFF" => {
905 let args = Self::uppercase_first_arg_if_identifier(f.args);
906 Ok(Expression::Function(Box::new(Function::new(
907 "DATEDIFF".to_string(),
908 args,
909 ))))
910 }
911
912 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
914 "DATEPART".to_string(),
915 f.args,
916 )))),
917
918 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
920 Ok(Expression::Function(Box::new(Function::new(
922 "CHARINDEX".to_string(),
923 f.args,
924 ))))
925 }
926
927 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
929
930 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
932 Function::new("CEILING".to_string(), f.args),
933 ))),
934
935 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
940 "JSON_VALUE".to_string(),
941 f.args,
942 )))),
943
944 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
946 "JSON_VALUE".to_string(),
947 f.args,
948 )))),
949
950 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
952
953 "GET_PATH" if f.args.len() == 2 => {
955 let mut args = f.args;
956 let this = args.remove(0);
957 let path = args.remove(0);
958 let json_path = match &path {
959 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
960 let Literal::String(s) = lit.as_ref() else {
961 unreachable!()
962 };
963 let normalized = if s.starts_with('$') {
964 s.clone()
965 } else if s.starts_with('[') {
966 format!("${}", s)
967 } else {
968 format!("$.{}", s)
969 };
970 Expression::Literal(Box::new(Literal::String(normalized)))
971 }
972 _ => path,
973 };
974 let json_query = Expression::Function(Box::new(Function::new(
976 "JSON_QUERY".to_string(),
977 vec![this.clone(), json_path.clone()],
978 )));
979 let json_value = Expression::Function(Box::new(Function::new(
980 "JSON_VALUE".to_string(),
981 vec![this, json_path],
982 )));
983 Ok(Expression::Function(Box::new(Function::new(
984 "ISNULL".to_string(),
985 vec![json_query, json_value],
986 ))))
987 }
988
989 "JSON_QUERY" if f.args.len() == 1 => {
992 let this = f.args.into_iter().next().unwrap();
993 let path = Expression::Literal(Box::new(Literal::String("$".to_string())));
994 let json_query = Expression::Function(Box::new(Function::new(
995 "JSON_QUERY".to_string(),
996 vec![this.clone(), path.clone()],
997 )));
998 let json_value = Expression::Function(Box::new(Function::new(
999 "JSON_VALUE".to_string(),
1000 vec![this, path],
1001 )));
1002 Ok(Expression::Function(Box::new(Function::new(
1003 "ISNULL".to_string(),
1004 vec![json_query, json_value],
1005 ))))
1006 }
1007
1008 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
1010 "STRING_SPLIT".to_string(),
1011 f.args,
1012 )))),
1013
1014 "REGEXP_LIKE" => {
1017 Ok(Expression::Function(Box::new(Function::new(
1019 "PATINDEX".to_string(),
1020 f.args,
1021 ))))
1022 }
1023
1024 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1026 "LOG".to_string(),
1027 f.args,
1028 )))),
1029
1030 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1035 "STDEV".to_string(),
1036 f.args,
1037 )))),
1038
1039 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
1041 "STDEVP".to_string(),
1042 f.args,
1043 )))),
1044
1045 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1047 "VAR".to_string(),
1048 f.args,
1049 )))),
1050
1051 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
1053 "VARP".to_string(),
1054 f.args,
1055 )))),
1056
1057 "DATE_ADD" => {
1059 if f.args.len() == 2 {
1060 let mut args = f.args;
1061 let date = args.remove(0);
1062 let interval = args.remove(0);
1063 let unit = Expression::Identifier(crate::expressions::Identifier {
1064 name: "DAY".to_string(),
1065 quoted: false,
1066 trailing_comments: Vec::new(),
1067 span: None,
1068 });
1069 Ok(Expression::Function(Box::new(Function::new(
1070 "DATEADD".to_string(),
1071 vec![unit, interval, date],
1072 ))))
1073 } else {
1074 let args = Self::uppercase_first_arg_if_identifier(f.args);
1075 Ok(Expression::Function(Box::new(Function::new(
1076 "DATEADD".to_string(),
1077 args,
1078 ))))
1079 }
1080 }
1081
1082 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
1084 "STUFF".to_string(),
1085 f.args,
1086 )))),
1087
1088 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
1090 crate::expressions::CurrentUser { this: None },
1091 ))),
1092
1093 _ => Ok(Expression::Function(Box::new(f))),
1095 }
1096 }
1097
1098 fn transform_aggregate_function(
1099 &self,
1100 f: Box<crate::expressions::AggregateFunction>,
1101 ) -> Result<Expression> {
1102 let name_upper = f.name.to_uppercase();
1103 match name_upper.as_str() {
1104 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1106 Function::new("STRING_AGG".to_string(), f.args),
1107 ))),
1108
1109 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1111 "STRING_AGG".to_string(),
1112 f.args,
1113 )))),
1114
1115 "ARRAY_AGG" if !f.args.is_empty() => {
1118 Ok(Expression::Function(Box::new(Function::new(
1120 "STRING_AGG".to_string(),
1121 f.args,
1122 ))))
1123 }
1124
1125 _ => Ok(Expression::AggregateFunction(f)),
1127 }
1128 }
1129
1130 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
1134 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
1135 }
1136
1137 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
1139 if cte.columns.is_empty() {
1142 cte.this = self.qualify_derived_table_outputs(cte.this);
1143 }
1144 cte
1145 }
1146
1147 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
1151 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
1154 subquery.this = self.qualify_derived_table_outputs(subquery.this);
1155 }
1156 Ok(Expression::Subquery(Box::new(subquery)))
1157 }
1158
1159 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
1163 match expr {
1164 Expression::Select(mut select) => {
1165 let has_from = select.from.is_some();
1168 if !has_from {
1169 select.expressions = select
1170 .expressions
1171 .into_iter()
1172 .map(|e| self.maybe_alias_expression(e))
1173 .collect();
1174 }
1175 Expression::Select(select)
1176 }
1177 Expression::Union(mut u) => {
1179 let left = std::mem::replace(&mut u.left, Expression::Null(Null));
1180 u.left = self.qualify_derived_table_outputs(left);
1181 Expression::Union(u)
1182 }
1183 Expression::Intersect(mut i) => {
1184 let left = std::mem::replace(&mut i.left, Expression::Null(Null));
1185 i.left = self.qualify_derived_table_outputs(left);
1186 Expression::Intersect(i)
1187 }
1188 Expression::Except(mut e) => {
1189 let left = std::mem::replace(&mut e.left, Expression::Null(Null));
1190 e.left = self.qualify_derived_table_outputs(left);
1191 Expression::Except(e)
1192 }
1193 Expression::Subquery(mut s) => {
1195 s.this = self.qualify_derived_table_outputs(s.this);
1196 Expression::Subquery(s)
1197 }
1198 other => other,
1200 }
1201 }
1202
1203 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
1208 match &expr {
1209 Expression::Alias(_) => expr,
1211 Expression::Aliases(_) => expr,
1213 Expression::Star(_) => expr,
1215 _ => {
1220 if let Some(output_name) = self.get_output_name(&expr) {
1221 Expression::Alias(Box::new(Alias {
1222 this: expr,
1223 alias: Identifier {
1224 name: output_name,
1225 quoted: true, trailing_comments: Vec::new(),
1227 span: None,
1228 },
1229 column_aliases: Vec::new(),
1230 alias_explicit_as: false,
1231 alias_keyword: None,
1232 pre_alias_comments: Vec::new(),
1233 trailing_comments: Vec::new(),
1234 inferred_type: None,
1235 }))
1236 } else {
1237 expr
1239 }
1240 }
1241 }
1242 }
1243
1244 fn get_output_name(&self, expr: &Expression) -> Option<String> {
1248 match expr {
1249 Expression::Literal(lit) => match lit.as_ref() {
1251 Literal::Number(n) => Some(n.clone()),
1252 Literal::String(s) => Some(s.clone()),
1253 Literal::HexString(h) => Some(format!("0x{}", h)),
1254 Literal::HexNumber(h) => Some(format!("0x{}", h)),
1255 Literal::BitString(b) => Some(format!("b{}", b)),
1256 Literal::ByteString(b) => Some(format!("b'{}'", b)),
1257 Literal::NationalString(s) => Some(format!("N'{}'", s)),
1258 Literal::Date(d) => Some(d.clone()),
1259 Literal::Time(t) => Some(t.clone()),
1260 Literal::Timestamp(ts) => Some(ts.clone()),
1261 Literal::Datetime(dt) => Some(dt.clone()),
1262 Literal::TripleQuotedString(s, _) => Some(s.clone()),
1263 Literal::EscapeString(s) => Some(s.clone()),
1264 Literal::DollarString(s) => Some(s.clone()),
1265 Literal::RawString(s) => Some(s.clone()),
1266 },
1267 Expression::Column(col) => Some(col.name.name.clone()),
1269 Expression::Identifier(ident) => Some(ident.name.clone()),
1271 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
1273 Expression::Null(_) => Some("NULL".to_string()),
1275 Expression::Function(f) => Some(f.name.clone()),
1277 Expression::AggregateFunction(f) => Some(f.name.clone()),
1279 _ => Some(format!("_col_{}", 0)),
1281 }
1282 }
1283
1284 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
1286 use crate::expressions::Identifier;
1287 if !args.is_empty() {
1288 match &args[0] {
1289 Expression::Identifier(id) => {
1290 args[0] = Expression::Identifier(Identifier {
1291 name: id.name.to_uppercase(),
1292 quoted: id.quoted,
1293 trailing_comments: id.trailing_comments.clone(),
1294 span: None,
1295 });
1296 }
1297 Expression::Var(v) => {
1298 args[0] = Expression::Identifier(Identifier {
1299 name: v.this.to_uppercase(),
1300 quoted: false,
1301 trailing_comments: Vec::new(),
1302 span: None,
1303 });
1304 }
1305 Expression::Column(col) if col.table.is_none() => {
1306 args[0] = Expression::Identifier(Identifier {
1307 name: col.name.name.to_uppercase(),
1308 quoted: col.name.quoted,
1309 trailing_comments: col.name.trailing_comments.clone(),
1310 span: None,
1311 });
1312 }
1313 _ => {}
1314 }
1315 }
1316 args
1317 }
1318}
1319
1320#[cfg(test)]
1321mod tests {
1322 use super::*;
1323 use crate::dialects::Dialect;
1324
1325 fn transpile_to_tsql(sql: &str) -> String {
1326 let dialect = Dialect::get(DialectType::Generic);
1327 let result = dialect
1328 .transpile(sql, DialectType::TSQL)
1329 .expect("Transpile failed");
1330 result[0].clone()
1331 }
1332
1333 #[test]
1334 fn test_nvl_to_isnull() {
1335 let result = transpile_to_tsql("SELECT NVL(a, b)");
1336 assert!(
1337 result.contains("ISNULL"),
1338 "Expected ISNULL, got: {}",
1339 result
1340 );
1341 }
1342
1343 #[test]
1344 fn test_coalesce_to_isnull() {
1345 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
1346 assert!(
1347 result.contains("ISNULL"),
1348 "Expected ISNULL, got: {}",
1349 result
1350 );
1351 }
1352
1353 #[test]
1354 fn test_basic_select() {
1355 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
1356 assert!(result.contains("SELECT"));
1357 assert!(result.contains("FROM users"));
1358 }
1359
1360 #[test]
1361 fn test_length_to_len() {
1362 let result = transpile_to_tsql("SELECT LENGTH(name)");
1363 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
1364 }
1365
1366 #[test]
1367 fn test_now_to_getdate() {
1368 let result = transpile_to_tsql("SELECT NOW()");
1369 assert!(
1370 result.contains("GETDATE"),
1371 "Expected GETDATE, got: {}",
1372 result
1373 );
1374 }
1375
1376 #[test]
1377 fn test_group_concat_to_string_agg() {
1378 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
1379 assert!(
1380 result.contains("STRING_AGG"),
1381 "Expected STRING_AGG, got: {}",
1382 result
1383 );
1384 }
1385
1386 #[test]
1387 fn test_listagg_to_string_agg() {
1388 let result = transpile_to_tsql("SELECT LISTAGG(name)");
1389 assert!(
1390 result.contains("STRING_AGG"),
1391 "Expected STRING_AGG, got: {}",
1392 result
1393 );
1394 }
1395
1396 #[test]
1397 fn test_ln_to_log() {
1398 let result = transpile_to_tsql("SELECT LN(x)");
1399 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
1400 }
1401
1402 #[test]
1403 fn test_stddev_to_stdev() {
1404 let result = transpile_to_tsql("SELECT STDDEV(x)");
1405 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
1406 }
1407
1408 #[test]
1409 fn test_bracket_identifiers() {
1410 let dialect = Dialect::get(DialectType::TSQL);
1412 let config = dialect.generator_config();
1413 assert_eq!(config.identifier_quote, '[');
1414 }
1415
1416 #[test]
1417 fn test_json_query_isnull_wrapper_simple() {
1418 let dialect = Dialect::get(DialectType::TSQL);
1420 let result = dialect
1421 .transpile(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
1422 .expect("transpile failed");
1423 assert!(
1424 result[0].contains("ISNULL"),
1425 "JSON_QUERY should be wrapped with ISNULL: {}",
1426 result[0]
1427 );
1428 }
1429
1430 #[test]
1431 fn test_json_query_isnull_wrapper_nested() {
1432 let dialect = Dialect::get(DialectType::TSQL);
1433 let result = dialect
1434 .transpile(
1435 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
1436 DialectType::TSQL,
1437 )
1438 .expect("transpile failed");
1439 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
1440 assert_eq!(
1441 result[0], expected,
1442 "JSON_QUERY should be wrapped with ISNULL"
1443 );
1444 }
1445}