1use super::{DialectImpl, DialectType};
14use crate::error::Result;
15use crate::expressions::{
16 Alias, BinaryOp, Cast, Column, Cte, DataType, Exists, Expression, Function, Identifier, In,
17 Join, JoinKind, LikeOp, Literal, Null, Over, QuantifiedOp, Select, Star, StringAggFunc,
18 Subquery, UnaryFunc, Where,
19};
20#[cfg(feature = "generate")]
21use crate::generator::GeneratorConfig;
22use crate::tokens::TokenizerConfig;
23use std::collections::HashMap;
24
25pub struct TSQLDialect;
27
28impl DialectImpl for TSQLDialect {
29 fn dialect_type(&self) -> DialectType {
30 DialectType::TSQL
31 }
32
33 fn tokenizer_config(&self) -> TokenizerConfig {
34 let mut config = TokenizerConfig::default();
35 config.identifiers.insert('[', ']');
37 config.identifiers.insert('"', '"');
39 config.hex_number_strings = true;
41 config
42 }
43
44 #[cfg(feature = "generate")]
45
46 fn generator_config(&self) -> GeneratorConfig {
47 use crate::generator::IdentifierQuoteStyle;
48 GeneratorConfig {
49 identifier_quote: '[',
51 identifier_quote_style: IdentifierQuoteStyle::BRACKET,
52 dialect: Some(DialectType::TSQL),
53 limit_fetch_style: crate::generator::LimitFetchStyle::FetchFirst,
56 null_ordering_supported: false,
58 aggregate_filter_supported: false,
60 supports_select_into: true,
62 alter_table_include_column_keyword: false,
64 computed_column_with_type: false,
66 cte_recursive_keyword_required: false,
68 ensure_bools: true,
70 supports_single_arg_concat: false,
72 tablesample_seed_keyword: "REPEATABLE",
74 json_path_bracketed_key_supported: false,
76 supports_to_number: false,
78 set_op_modifiers: false,
80 copy_params_eq_required: true,
82 except_intersect_support_all_clause: false,
84 alter_set_wrapped: true,
86 try_supported: true,
88 nvl2_supported: false,
90 parameter_default_equals: true,
92 supports_window_exclude: false,
94 multi_arg_distinct: false,
96 locking_reads_supported: false,
98 ..Default::default()
99 }
100 }
101
102 #[cfg(feature = "transpile")]
103
104 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
105 if let Expression::CreateTable(mut ct) = expr {
107 for col in &mut ct.columns {
108 if let Ok(Expression::DataType(new_dt)) =
109 self.transform_data_type(col.data_type.clone())
110 {
111 col.data_type = new_dt;
112 }
113 }
114 return Ok(Expression::CreateTable(ct));
115 }
116
117 match expr {
118 Expression::Select(mut select) => {
123 select.expressions = select
124 .expressions
125 .into_iter()
126 .map(|e| {
127 match e {
128 Expression::Eq(op) => {
129 match &op.left {
132 Expression::Column(col)
133 if col.table.is_none()
134 && !col.name.name.starts_with('@') =>
135 {
136 Expression::Alias(Box::new(Alias {
137 this: op.right,
138 alias: col.name.clone(),
139 column_aliases: Vec::new(),
140 alias_explicit_as: false,
141 alias_keyword: None,
142 pre_alias_comments: Vec::new(),
143 trailing_comments: Vec::new(),
144 inferred_type: None,
145 }))
146 }
147 Expression::Identifier(ident)
148 if !ident.name.starts_with('@') =>
149 {
150 Expression::Alias(Box::new(Alias {
151 this: op.right,
152 alias: ident.clone(),
153 column_aliases: Vec::new(),
154 alias_explicit_as: false,
155 alias_keyword: None,
156 pre_alias_comments: Vec::new(),
157 trailing_comments: Vec::new(),
158 inferred_type: None,
159 }))
160 }
161 _ => Expression::Eq(op),
162 }
163 }
164 other => other,
165 }
166 })
167 .collect();
168
169 Self::normalize_frame_incompatible_window_functions(&mut select);
170
171 let outer_qualifier = Self::single_select_source_qualifier(&select);
172 if let Some(ref mut where_clause) = select.where_clause {
173 where_clause.this = Self::rewrite_tuple_in_subquery_predicates(
174 std::mem::replace(&mut where_clause.this, Expression::Null(Null)),
175 outer_qualifier.as_ref(),
176 false,
177 );
178 }
179
180 if let Some(ref mut with) = select.with {
182 with.ctes = with
183 .ctes
184 .drain(..)
185 .map(|cte| self.transform_cte_inner(cte))
186 .collect();
187 }
188
189 Self::rewrite_comma_lateral_sources_to_joins(&mut select);
190
191 Ok(Expression::Select(select))
192 }
193
194 Expression::DataType(dt) => self.transform_data_type(dt),
196
197 Expression::IsTrue(it) => Ok(Self::boolean_test_predicate(it.this, true, it.not)),
201 Expression::IsFalse(it) => Ok(Self::boolean_test_predicate(it.this, false, it.not)),
202
203 Expression::In(mut in_expr) if in_expr.not => {
207 in_expr.not = false;
208 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
209 this: Expression::In(in_expr),
210 inferred_type: None,
211 })))
212 }
213
214 Expression::Coalesce(f) if f.expressions.len() == 2 => Ok(Expression::Function(
217 Box::new(Function::new("ISNULL".to_string(), f.expressions)),
218 )),
219
220 Expression::Nvl(f) => Ok(Expression::Function(Box::new(Function::new(
222 "ISNULL".to_string(),
223 vec![f.this, f.expression],
224 )))),
225
226 Expression::GroupConcat(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
228 this: f.this,
229 separator: f.separator,
230 order_by: f.order_by,
231 distinct: f.distinct,
232 filter: f.filter,
233 limit: None,
234 inferred_type: None,
235 }))),
236
237 Expression::ListAgg(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
239 this: f.this,
240 separator: f.separator,
241 order_by: f.order_by,
242 distinct: f.distinct,
243 filter: f.filter,
244 limit: None,
245 inferred_type: None,
246 }))),
247
248 Expression::LogicalAnd(f) => Self::transform_logical_aggregate(f.this, f.filter, "MIN"),
251 Expression::LogicalOr(f) => Self::transform_logical_aggregate(f.this, f.filter, "MAX"),
252
253 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
255
256 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
258
259 Expression::ILike(op) => {
261 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
264 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
265 Ok(Expression::Like(Box::new(LikeOp {
266 left: lower_left,
267 right: lower_right,
268 escape: op.escape,
269 quantifier: op.quantifier,
270 inferred_type: None,
271 })))
272 }
273
274 Expression::Concat(op) => {
277 Ok(Expression::Add(op))
279 }
280
281 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
283 seed: None,
284 lower: None,
285 upper: None,
286 }))),
287
288 Expression::Unnest(f) => {
290 Ok(Expression::Function(Box::new(Function::new(
293 "OPENJSON".to_string(),
294 vec![f.this],
295 ))))
296 }
297
298 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
300 "OPENJSON".to_string(),
301 vec![f.this],
302 )))),
303
304 Expression::Join(join) => Ok(Expression::Join(Box::new(
306 Self::transform_lateral_join_to_apply(*join)?,
307 ))),
308
309 Expression::Length(f) => Ok(Expression::Function(Box::new(Function::new(
311 "LEN".to_string(),
312 vec![f.this],
313 )))),
314
315 Expression::Stddev(f) => Ok(Expression::Function(Box::new(Function::new(
317 "STDEV".to_string(),
318 vec![f.this],
319 )))),
320 Expression::StddevSamp(f) => Ok(Expression::Function(Box::new(Function::new(
321 "STDEV".to_string(),
322 vec![f.this],
323 )))),
324 Expression::StddevPop(f) => Ok(Expression::Function(Box::new(Function::new(
325 "STDEVP".to_string(),
326 vec![f.this],
327 )))),
328
329 Expression::Boolean(b) => {
331 let value = if b.value { 1 } else { 0 };
332 Ok(Expression::Literal(Box::new(
333 crate::expressions::Literal::Number(value.to_string()),
334 )))
335 }
336
337 Expression::Ln(f) => Ok(Expression::Function(Box::new(Function::new(
339 "LOG".to_string(),
340 vec![f.this],
341 )))),
342
343 Expression::CurrentDate(_) => {
346 let getdate =
347 Expression::Function(Box::new(Function::new("GETDATE".to_string(), vec![])));
348 Ok(Expression::Cast(Box::new(crate::expressions::Cast {
349 this: getdate,
350 to: crate::expressions::DataType::Date,
351 trailing_comments: Vec::new(),
352 double_colon_syntax: false,
353 format: None,
354 default: None,
355 inferred_type: None,
356 })))
357 }
358
359 Expression::CurrentTimestamp(_) => Ok(Expression::Function(Box::new(Function::new(
361 "GETDATE".to_string(),
362 vec![],
363 )))),
364
365 Expression::DateDiff(f) => {
367 let unit_str = match f.unit {
369 Some(crate::expressions::IntervalUnit::Year) => "YEAR",
370 Some(crate::expressions::IntervalUnit::Quarter) => "QUARTER",
371 Some(crate::expressions::IntervalUnit::Month) => "MONTH",
372 Some(crate::expressions::IntervalUnit::Week) => "WEEK",
373 Some(crate::expressions::IntervalUnit::Day) => "DAY",
374 Some(crate::expressions::IntervalUnit::Hour) => "HOUR",
375 Some(crate::expressions::IntervalUnit::Minute) => "MINUTE",
376 Some(crate::expressions::IntervalUnit::Second) => "SECOND",
377 Some(crate::expressions::IntervalUnit::Millisecond) => "MILLISECOND",
378 Some(crate::expressions::IntervalUnit::Microsecond) => "MICROSECOND",
379 Some(crate::expressions::IntervalUnit::Nanosecond) => "NANOSECOND",
380 None => "DAY",
381 };
382 let unit = Expression::Identifier(crate::expressions::Identifier {
383 name: unit_str.to_string(),
384 quoted: false,
385 trailing_comments: Vec::new(),
386 span: None,
387 });
388 Ok(Expression::Function(Box::new(Function::new(
389 "DATEDIFF".to_string(),
390 vec![unit, f.expression, f.this], ))))
392 }
393
394 Expression::DateAdd(f) => {
396 let unit_str = match f.unit {
397 crate::expressions::IntervalUnit::Year => "YEAR",
398 crate::expressions::IntervalUnit::Quarter => "QUARTER",
399 crate::expressions::IntervalUnit::Month => "MONTH",
400 crate::expressions::IntervalUnit::Week => "WEEK",
401 crate::expressions::IntervalUnit::Day => "DAY",
402 crate::expressions::IntervalUnit::Hour => "HOUR",
403 crate::expressions::IntervalUnit::Minute => "MINUTE",
404 crate::expressions::IntervalUnit::Second => "SECOND",
405 crate::expressions::IntervalUnit::Millisecond => "MILLISECOND",
406 crate::expressions::IntervalUnit::Microsecond => "MICROSECOND",
407 crate::expressions::IntervalUnit::Nanosecond => "NANOSECOND",
408 };
409 let unit = Expression::Identifier(crate::expressions::Identifier {
410 name: unit_str.to_string(),
411 quoted: false,
412 trailing_comments: Vec::new(),
413 span: None,
414 });
415 Ok(Expression::Function(Box::new(Function::new(
416 "DATEADD".to_string(),
417 vec![unit, f.interval, f.this],
418 ))))
419 }
420
421 Expression::Uuid(_) => Ok(Expression::Function(Box::new(Function::new(
424 "NEWID".to_string(),
425 vec![],
426 )))),
427
428 Expression::IfFunc(f) => {
431 let false_val = f
432 .false_value
433 .unwrap_or(Expression::Null(crate::expressions::Null));
434 Ok(Expression::Function(Box::new(Function::new(
435 "IIF".to_string(),
436 vec![f.condition, f.true_value, false_val],
437 ))))
438 }
439
440 Expression::StringAgg(f) => Ok(Expression::StringAgg(f)),
443
444 Expression::LastDay(f) => Ok(Expression::Function(Box::new(Function::new(
446 "EOMONTH".to_string(),
447 vec![f.this.clone()],
448 )))),
449
450 Expression::Ceil(f) => Ok(Expression::Function(Box::new(Function::new(
452 "CEILING".to_string(),
453 vec![f.this],
454 )))),
455
456 Expression::Repeat(f) => Ok(Expression::Function(Box::new(Function::new(
458 "REPLICATE".to_string(),
459 vec![f.this, f.times],
460 )))),
461
462 Expression::Chr(f) => Ok(Expression::Function(Box::new(Function::new(
464 "CHAR".to_string(),
465 vec![f.this],
466 )))),
467
468 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
471 "VARP".to_string(),
472 vec![f.this],
473 )))),
474
475 Expression::Variance(f) => Ok(Expression::Function(Box::new(Function::new(
477 "VAR".to_string(),
478 vec![f.this],
479 )))),
480 Expression::VarSamp(f) => Ok(Expression::Function(Box::new(Function::new(
481 "VAR".to_string(),
482 vec![f.this],
483 )))),
484
485 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
488 "HASHBYTES".to_string(),
489 vec![Expression::string("MD5"), *f.this],
490 )))),
491
492 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
494 "HASHBYTES".to_string(),
495 vec![Expression::string("SHA1"), f.this],
496 )))),
497
498 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
500 "HASHBYTES".to_string(),
501 vec![Expression::string("SHA1"), f.this],
502 )))),
503
504 Expression::ArrayToString(f) => Ok(Expression::Function(Box::new(Function::new(
507 "STRING_AGG".to_string(),
508 vec![f.this],
509 )))),
510
511 Expression::AutoIncrementColumnConstraint(_) => Ok(Expression::Function(Box::new(
514 Function::new("IDENTITY".to_string(), vec![]),
515 ))),
516
517 Expression::CreateView(mut view) => {
521 view.name.catalog = None;
523 Ok(Expression::CreateView(view))
524 }
525
526 Expression::DropView(mut view) => {
527 view.name.catalog = None;
529 Ok(Expression::DropView(view))
530 }
531
532 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
536 let path = match *e.expression {
537 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
538 let Literal::String(s) = lit.as_ref() else {
539 unreachable!()
540 };
541 let normalized = if s.starts_with('$') {
542 s.clone()
543 } else if s.starts_with('[') {
544 format!("${}", s)
545 } else {
546 format!("$.{}", s)
547 };
548 Expression::Literal(Box::new(Literal::String(normalized)))
549 }
550 other => other,
551 };
552 let json_query = Expression::Function(Box::new(Function::new(
553 "JSON_QUERY".to_string(),
554 vec![(*e.this).clone(), path.clone()],
555 )));
556 let json_value = Expression::Function(Box::new(Function::new(
557 "JSON_VALUE".to_string(),
558 vec![*e.this, path],
559 )));
560 Ok(Expression::Function(Box::new(Function::new(
561 "ISNULL".to_string(),
562 vec![json_query, json_value],
563 ))))
564 }
565
566 Expression::Function(f) => self.transform_function(*f),
568
569 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
571
572 Expression::Cte(cte) => self.transform_cte(*cte),
575
576 Expression::Subquery(subquery) => self.transform_subquery(*subquery),
579
580 Expression::JsonQuery(f) => {
582 let json_query = Expression::Function(Box::new(Function::new(
583 "JSON_QUERY".to_string(),
584 vec![f.this.clone(), f.path.clone()],
585 )));
586 let json_value = Expression::Function(Box::new(Function::new(
587 "JSON_VALUE".to_string(),
588 vec![f.this, f.path],
589 )));
590 Ok(Expression::Function(Box::new(Function::new(
591 "ISNULL".to_string(),
592 vec![json_query, json_value],
593 ))))
594 }
595 Expression::JsonValue(f) => Ok(Expression::Function(Box::new(Function::new(
597 "JSON_VALUE".to_string(),
598 vec![f.this, f.path],
599 )))),
600
601 Expression::Any(ref q) if matches!(&q.op, Some(QuantifiedOp::Eq)) => {
604 match Self::scalar_array_comparison_values(&q.subquery) {
605 Some(expressions) if expressions.is_empty() => {
606 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp::new(
607 Expression::Literal(Box::new(Literal::Number("1".to_string()))),
608 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
609 ))))
610 }
611 Some(expressions) => Ok(Expression::In(Box::new(In {
612 this: q.this.clone(),
613 expressions,
614 query: None,
615 not: false,
616 global: false,
617 unnest: None,
618 is_field: false,
619 }))),
620 None => Ok(expr.clone()),
621 }
622 }
623
624 _ => Ok(expr),
626 }
627 }
628}
629
630#[cfg(feature = "transpile")]
631impl TSQLDialect {
632 fn binary(
633 left: Expression,
634 right: Expression,
635 op: fn(Box<BinaryOp>) -> Expression,
636 ) -> Expression {
637 op(Box::new(BinaryOp {
638 left,
639 right,
640 left_comments: Vec::new(),
641 operator_comments: Vec::new(),
642 trailing_comments: Vec::new(),
643 inferred_type: None,
644 }))
645 }
646
647 fn eq(left: Expression, right: Expression) -> Expression {
648 Self::binary(left, right, Expression::Eq)
649 }
650
651 fn or(left: Expression, right: Expression) -> Expression {
652 Self::binary(left, right, Expression::Or)
653 }
654
655 fn not(this: Expression) -> Expression {
656 Expression::Not(Box::new(crate::expressions::UnaryOp {
657 this,
658 inferred_type: None,
659 }))
660 }
661
662 fn is_null(this: Expression) -> Expression {
663 Expression::IsNull(Box::new(crate::expressions::IsNull {
664 this,
665 not: false,
666 postfix_form: false,
667 }))
668 }
669
670 fn boolean_test_case_for_predicate(
671 predicate: Expression,
672 test_true: bool,
673 negated: bool,
674 ) -> Expression {
675 let condition = match (test_true, negated) {
676 (true, false) => predicate,
677 (false, false) => Self::not(predicate),
678 (true, true) => {
679 return Expression::Case(Box::new(crate::expressions::Case {
680 operand: None,
681 whens: vec![(predicate, Expression::number(0))],
682 else_: Some(Expression::number(1)),
683 comments: Vec::new(),
684 inferred_type: None,
685 }))
686 }
687 (false, true) => {
688 return Expression::Case(Box::new(crate::expressions::Case {
689 operand: None,
690 whens: vec![(Self::not(predicate), Expression::number(0))],
691 else_: Some(Expression::number(1)),
692 comments: Vec::new(),
693 inferred_type: None,
694 }))
695 }
696 };
697
698 Expression::Case(Box::new(crate::expressions::Case {
699 operand: None,
700 whens: vec![(condition, Expression::number(1))],
701 else_: Some(Expression::number(0)),
702 comments: Vec::new(),
703 inferred_type: None,
704 }))
705 }
706
707 fn boolean_test_predicate(operand: Expression, test_true: bool, negated: bool) -> Expression {
708 if Self::is_boolean_predicate_operand(&operand) {
709 return match (test_true, negated) {
710 (true, false) => operand,
711 (false, false) => Self::not(operand),
712 _ => Self::eq(
713 Self::boolean_test_case_for_predicate(operand, test_true, negated),
714 Expression::number(1),
715 ),
716 };
717 }
718
719 match (test_true, negated) {
720 (true, false) => Self::eq(operand, Expression::number(1)),
721 (false, false) => Self::eq(operand, Expression::number(0)),
722 (true, true) => Self::or(
723 Self::eq(operand.clone(), Expression::number(0)),
724 Self::is_null(operand),
725 ),
726 (false, true) => Self::or(
727 Self::eq(operand.clone(), Expression::number(1)),
728 Self::is_null(operand),
729 ),
730 }
731 }
732
733 fn is_boolean_predicate_operand(expr: &Expression) -> bool {
734 match expr {
735 Expression::Paren(paren) => Self::is_boolean_predicate_operand(&paren.this),
736 Expression::Eq(_)
737 | Expression::Neq(_)
738 | Expression::Lt(_)
739 | Expression::Lte(_)
740 | Expression::Gt(_)
741 | Expression::Gte(_)
742 | Expression::Is(_)
743 | Expression::IsNull(_)
744 | Expression::IsTrue(_)
745 | Expression::IsFalse(_)
746 | Expression::Like(_)
747 | Expression::ILike(_)
748 | Expression::SimilarTo(_)
749 | Expression::Glob(_)
750 | Expression::RegexpLike(_)
751 | Expression::In(_)
752 | Expression::Between(_)
753 | Expression::Exists(_)
754 | Expression::And(_)
755 | Expression::Or(_)
756 | Expression::Not(_)
757 | Expression::Any(_)
758 | Expression::All(_)
759 | Expression::EqualNull(_) => true,
760 _ => false,
761 }
762 }
763
764 fn scalar_array_comparison_values(expr: &Expression) -> Option<Vec<Expression>> {
765 let (mut values, element_type) = Self::scalar_array_comparison_values_inner(expr)?;
766 if let Some(to) = element_type {
767 values = values
768 .into_iter()
769 .map(|value| Self::cast_scalar_array_comparison_value(value, to.clone()))
770 .collect();
771 }
772 Some(values)
773 }
774
775 fn scalar_array_comparison_values_inner(
776 expr: &Expression,
777 ) -> Option<(Vec<Expression>, Option<DataType>)> {
778 match expr {
779 Expression::ArrayFunc(a) => Some((a.expressions.clone(), None)),
780 Expression::Array(a) => Some((a.expressions.clone(), None)),
781 Expression::Tuple(t) => Some((t.expressions.clone(), None)),
782 Expression::Paren(p) => Self::scalar_array_comparison_values_inner(&p.this),
783 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
784 let DataType::Array { element_type, .. } = &c.to else {
785 return None;
786 };
787 let (values, _) = Self::scalar_array_comparison_values_inner(&c.this)?;
788 Some((values, Some((**element_type).clone())))
789 }
790 _ => None,
791 }
792 }
793
794 fn cast_scalar_array_comparison_value(value: Expression, to: DataType) -> Expression {
795 if matches!(&value, Expression::Cast(c) if c.to == to) {
796 return value;
797 }
798
799 Expression::Cast(Box::new(Cast {
800 this: value,
801 to,
802 trailing_comments: Vec::new(),
803 double_colon_syntax: false,
804 format: None,
805 default: None,
806 inferred_type: None,
807 }))
808 }
809
810 fn normalize_frame_incompatible_window_functions(select: &mut Select) {
811 let window_map: HashMap<String, Over> = select
812 .windows
813 .as_ref()
814 .map(|windows| {
815 windows
816 .iter()
817 .map(|window| (window.name.name.to_lowercase(), window.spec.clone()))
818 .collect()
819 })
820 .unwrap_or_default();
821
822 for expr in &mut select.expressions {
823 Self::normalize_frame_incompatible_window_expr(expr, &window_map);
824 }
825
826 if let Some(order_by) = &mut select.order_by {
827 for ordered in &mut order_by.expressions {
828 Self::normalize_frame_incompatible_window_expr(&mut ordered.this, &window_map);
829 }
830 }
831
832 if let Some(qualify) = &mut select.qualify {
833 Self::normalize_frame_incompatible_window_expr(&mut qualify.this, &window_map);
834 }
835 }
836
837 fn normalize_frame_incompatible_window_expr(
838 expr: &mut Expression,
839 window_map: &HashMap<String, Over>,
840 ) {
841 match expr {
842 Expression::WindowFunction(wf) => {
843 Self::normalize_frame_incompatible_window_expr(&mut wf.this, window_map);
844
845 if !Self::is_tsql_frame_incompatible_window_function(&wf.this) {
846 return;
847 }
848
849 wf.over.frame = None;
850
851 let Some(window_name) = wf.over.window_name.clone() else {
852 return;
853 };
854 let Some(named_spec) =
855 Self::resolve_named_window_spec(&window_name.name, window_map, &mut Vec::new())
856 else {
857 return;
858 };
859
860 if named_spec.frame.is_none() {
861 return;
862 }
863
864 if wf.over.partition_by.is_empty() {
865 wf.over.partition_by = named_spec.partition_by;
866 }
867 if wf.over.order_by.is_empty() {
868 wf.over.order_by = named_spec.order_by;
869 }
870 wf.over.window_name = None;
871 wf.over.frame = None;
872 }
873 Expression::Alias(alias) => {
874 Self::normalize_frame_incompatible_window_expr(&mut alias.this, window_map);
875 }
876 Expression::Paren(paren) => {
877 Self::normalize_frame_incompatible_window_expr(&mut paren.this, window_map);
878 }
879 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
880 Self::normalize_frame_incompatible_window_expr(&mut cast.this, window_map);
881 }
882 Expression::Function(function) => {
883 for arg in &mut function.args {
884 Self::normalize_frame_incompatible_window_expr(arg, window_map);
885 }
886 }
887 Expression::Case(case) => {
888 if let Some(operand) = &mut case.operand {
889 Self::normalize_frame_incompatible_window_expr(operand, window_map);
890 }
891 for (condition, result) in &mut case.whens {
892 Self::normalize_frame_incompatible_window_expr(condition, window_map);
893 Self::normalize_frame_incompatible_window_expr(result, window_map);
894 }
895 if let Some(else_expr) = &mut case.else_ {
896 Self::normalize_frame_incompatible_window_expr(else_expr, window_map);
897 }
898 }
899 Expression::And(op)
900 | Expression::Or(op)
901 | Expression::Add(op)
902 | Expression::Sub(op)
903 | Expression::Mul(op)
904 | Expression::Div(op)
905 | Expression::Mod(op)
906 | Expression::Eq(op)
907 | Expression::Neq(op)
908 | Expression::Lt(op)
909 | Expression::Lte(op)
910 | Expression::Gt(op)
911 | Expression::Gte(op)
912 | Expression::Match(op)
913 | Expression::BitwiseAnd(op)
914 | Expression::BitwiseOr(op)
915 | Expression::BitwiseXor(op)
916 | Expression::Concat(op)
917 | Expression::Adjacent(op)
918 | Expression::TsMatch(op)
919 | Expression::PropertyEQ(op)
920 | Expression::ArrayContainsAll(op)
921 | Expression::ArrayContainedBy(op)
922 | Expression::ArrayOverlaps(op)
923 | Expression::JSONBContainsAllTopKeys(op)
924 | Expression::JSONBContainsAnyTopKeys(op)
925 | Expression::JSONBDeleteAtPath(op)
926 | Expression::ExtendsLeft(op)
927 | Expression::ExtendsRight(op)
928 | Expression::Is(op)
929 | Expression::MemberOf(op) => {
930 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
931 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
932 }
933 Expression::Like(op) | Expression::ILike(op) => {
934 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
935 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
936 if let Some(escape) = &mut op.escape {
937 Self::normalize_frame_incompatible_window_expr(escape, window_map);
938 }
939 }
940 Expression::Not(op) | Expression::Neg(op) | Expression::BitwiseNot(op) => {
941 Self::normalize_frame_incompatible_window_expr(&mut op.this, window_map);
942 }
943 Expression::In(in_expr) => {
944 Self::normalize_frame_incompatible_window_expr(&mut in_expr.this, window_map);
945 for value in &mut in_expr.expressions {
946 Self::normalize_frame_incompatible_window_expr(value, window_map);
947 }
948 }
949 Expression::Between(between) => {
950 Self::normalize_frame_incompatible_window_expr(&mut between.this, window_map);
951 Self::normalize_frame_incompatible_window_expr(&mut between.low, window_map);
952 Self::normalize_frame_incompatible_window_expr(&mut between.high, window_map);
953 }
954 Expression::IsNull(is_null) => {
955 Self::normalize_frame_incompatible_window_expr(&mut is_null.this, window_map);
956 }
957 Expression::IsTrue(is_true) | Expression::IsFalse(is_true) => {
958 Self::normalize_frame_incompatible_window_expr(&mut is_true.this, window_map);
959 }
960 _ => {}
961 }
962 }
963
964 fn is_tsql_frame_incompatible_window_function(expr: &Expression) -> bool {
965 matches!(
966 expr,
967 Expression::RowNumber(_)
968 | Expression::Rank(_)
969 | Expression::DenseRank(_)
970 | Expression::NTile(_)
971 | Expression::Ntile(_)
972 | Expression::Lead(_)
973 | Expression::Lag(_)
974 | Expression::PercentRank(_)
975 | Expression::CumeDist(_)
976 )
977 }
978
979 fn resolve_named_window_spec(
980 name: &str,
981 window_map: &HashMap<String, Over>,
982 seen: &mut Vec<String>,
983 ) -> Option<Over> {
984 let key = name.to_lowercase();
985 if seen.iter().any(|seen_name| seen_name == &key) {
986 return None;
987 }
988
989 let named_spec = window_map.get(&key)?.clone();
990 seen.push(key);
991
992 let mut resolved = if let Some(base_window) = &named_spec.window_name {
993 Self::resolve_named_window_spec(&base_window.name, window_map, seen)
994 .unwrap_or_else(Self::empty_over)
995 } else {
996 Self::empty_over()
997 };
998
999 if !named_spec.partition_by.is_empty() {
1000 resolved.partition_by = named_spec.partition_by;
1001 }
1002 if !named_spec.order_by.is_empty() {
1003 resolved.order_by = named_spec.order_by;
1004 }
1005 if named_spec.frame.is_some() {
1006 resolved.frame = named_spec.frame;
1007 }
1008
1009 Some(resolved)
1010 }
1011
1012 fn empty_over() -> Over {
1013 Over {
1014 window_name: None,
1015 partition_by: Vec::new(),
1016 order_by: Vec::new(),
1017 frame: None,
1018 alias: None,
1019 }
1020 }
1021
1022 const LATERAL_WRAPPER_SOURCE_ALIAS: &'static str = "_polyglot_lateral_source";
1023 const LATERAL_WRAPPER_OUTPUT_ALIAS: &'static str = "_polyglot_lateral";
1024
1025 fn transform_lateral_join_to_apply(mut join: Join) -> Result<Join> {
1026 let Some(apply_kind) = Self::lateral_apply_kind(&join) else {
1027 return Ok(join);
1028 };
1029
1030 let original_alias = Self::table_expression_alias(&join.this);
1031 let on = join.on.take();
1032 let rhs = Self::remove_lateral_marker(join.this);
1033 join.this = if on
1034 .as_ref()
1035 .is_some_and(|expr| !Self::is_true_condition(expr))
1036 {
1037 Self::wrap_lateral_apply_rhs(rhs, on.expect("checked as Some"), original_alias)?
1038 } else {
1039 rhs
1040 };
1041 join.using.clear();
1042 join.kind = apply_kind;
1043 join.use_inner_keyword = false;
1044 join.use_outer_keyword = false;
1045 join.deferred_condition = false;
1046 join.join_hint = None;
1047 join.match_condition = None;
1048 join.directed = false;
1049 Ok(join)
1050 }
1051
1052 fn rewrite_comma_lateral_sources_to_joins(select: &mut Select) {
1053 let Some(from) = select.from.as_mut() else {
1054 return;
1055 };
1056 if from.expressions.len() < 2
1057 || !from
1058 .expressions
1059 .iter()
1060 .skip(1)
1061 .any(Self::is_lateral_table_expression)
1062 {
1063 return;
1064 }
1065
1066 let mut expressions = std::mem::take(&mut from.expressions).into_iter();
1067 let Some(first) = expressions.next() else {
1068 return;
1069 };
1070 from.expressions = vec![first];
1071
1072 let mut joins = expressions
1073 .map(|source| {
1074 if Self::is_lateral_table_expression(&source) {
1075 Self::new_join(Self::remove_lateral_marker(source), JoinKind::CrossApply)
1076 } else {
1077 Self::new_join(source, JoinKind::Cross)
1078 }
1079 })
1080 .collect::<Vec<_>>();
1081 joins.append(&mut select.joins);
1082 select.joins = joins;
1083 }
1084
1085 fn new_join(this: Expression, kind: JoinKind) -> Join {
1086 Join {
1087 this,
1088 on: None,
1089 using: Vec::new(),
1090 kind,
1091 use_inner_keyword: false,
1092 use_outer_keyword: false,
1093 deferred_condition: false,
1094 join_hint: None,
1095 match_condition: None,
1096 pivots: Vec::new(),
1097 comments: Vec::new(),
1098 nesting_group: 0,
1099 directed: false,
1100 }
1101 }
1102
1103 fn lateral_apply_kind(join: &Join) -> Option<JoinKind> {
1104 if !join.using.is_empty() {
1105 return None;
1106 }
1107
1108 match join.kind {
1109 JoinKind::Lateral => Some(JoinKind::CrossApply),
1110 JoinKind::LeftLateral => Some(JoinKind::OuterApply),
1111 JoinKind::Cross | JoinKind::Inner | JoinKind::Implicit
1112 if Self::is_lateral_table_expression(&join.this) =>
1113 {
1114 Some(JoinKind::CrossApply)
1115 }
1116 JoinKind::Left if Self::is_lateral_table_expression(&join.this) => {
1117 Some(JoinKind::OuterApply)
1118 }
1119 _ => None,
1120 }
1121 }
1122
1123 fn is_true_condition(expr: &Expression) -> bool {
1124 match expr {
1125 Expression::Boolean(boolean) => boolean.value,
1126 Expression::Literal(lit) => {
1127 matches!(lit.as_ref(), Literal::Number(value) if value.trim() == "1")
1128 }
1129 Expression::Eq(op) => {
1130 Self::is_true_condition(&op.left) && Self::is_true_condition(&op.right)
1131 }
1132 Expression::Paren(paren) => Self::is_true_condition(&paren.this),
1133 _ => false,
1134 }
1135 }
1136
1137 fn table_expression_alias(expr: &Expression) -> Option<(Identifier, Vec<Identifier>)> {
1138 match expr {
1139 Expression::Subquery(subquery) => subquery
1140 .alias
1141 .clone()
1142 .map(|alias| (alias, subquery.column_aliases.clone())),
1143 Expression::Alias(alias) if !alias.alias.is_empty() => {
1144 Some((alias.alias.clone(), alias.column_aliases.clone()))
1145 }
1146 Expression::Lateral(lateral) => lateral.alias.as_ref().map(|alias| {
1147 (
1148 if lateral.alias_quoted {
1149 Identifier::quoted(alias)
1150 } else {
1151 Identifier::new(alias)
1152 },
1153 lateral
1154 .column_aliases
1155 .iter()
1156 .map(|column| Identifier::new(column.clone()))
1157 .collect(),
1158 )
1159 }),
1160 _ => None,
1161 }
1162 }
1163
1164 fn wrap_lateral_apply_rhs(
1165 rhs: Expression,
1166 predicate: Expression,
1167 original_alias: Option<(Identifier, Vec<Identifier>)>,
1168 ) -> Result<Expression> {
1169 let (outer_alias, column_aliases) = original_alias.unwrap_or_else(|| {
1170 (
1171 Identifier::new(Self::LATERAL_WRAPPER_OUTPUT_ALIAS),
1172 Vec::new(),
1173 )
1174 });
1175 let inner_alias = Identifier::new(Self::LATERAL_WRAPPER_SOURCE_ALIAS);
1176 let source =
1177 Self::with_table_expression_alias(rhs, inner_alias.clone(), column_aliases.clone());
1178 let predicate = Self::rewrite_column_qualifier(predicate, &outer_alias, &inner_alias)?;
1179
1180 let mut select = Select::new();
1181 select.expressions = vec![Expression::Star(Star {
1182 table: None,
1183 except: None,
1184 replace: None,
1185 rename: None,
1186 trailing_comments: Vec::new(),
1187 span: None,
1188 })];
1189 select.from = Some(crate::expressions::From {
1190 expressions: vec![source],
1191 });
1192 select.where_clause = Some(Where { this: predicate });
1193
1194 Ok(Expression::Subquery(Box::new(Subquery {
1195 this: Expression::Select(Box::new(select)),
1196 alias: Some(outer_alias),
1197 column_aliases,
1198 alias_explicit_as: true,
1199 alias_keyword: None,
1200 order_by: None,
1201 limit: None,
1202 offset: None,
1203 distribute_by: None,
1204 sort_by: None,
1205 cluster_by: None,
1206 lateral: false,
1207 modifiers_inside: false,
1208 trailing_comments: Vec::new(),
1209 inferred_type: None,
1210 })))
1211 }
1212
1213 fn with_table_expression_alias(
1214 expr: Expression,
1215 alias: Identifier,
1216 column_aliases: Vec<Identifier>,
1217 ) -> Expression {
1218 match expr {
1219 Expression::Subquery(mut subquery) => {
1220 subquery.alias = Some(alias);
1221 subquery.column_aliases = column_aliases;
1222 subquery.alias_explicit_as = true;
1223 subquery.alias_keyword = None;
1224 Expression::Subquery(subquery)
1225 }
1226 Expression::Alias(mut aliased) => {
1227 aliased.alias = alias;
1228 aliased.column_aliases = column_aliases;
1229 aliased.alias_explicit_as = true;
1230 aliased.alias_keyword = None;
1231 Expression::Alias(aliased)
1232 }
1233 Expression::Table(mut table) => {
1234 table.alias = Some(alias);
1235 table.alias_explicit_as = true;
1236 table.column_aliases = column_aliases;
1237 Expression::Table(table)
1238 }
1239 other => Expression::Alias(Box::new(Alias {
1240 this: other,
1241 alias,
1242 column_aliases,
1243 alias_explicit_as: true,
1244 alias_keyword: None,
1245 pre_alias_comments: Vec::new(),
1246 trailing_comments: Vec::new(),
1247 inferred_type: None,
1248 })),
1249 }
1250 }
1251
1252 fn rewrite_column_qualifier(
1253 expr: Expression,
1254 from: &Identifier,
1255 to: &Identifier,
1256 ) -> Result<Expression> {
1257 super::transform_recursive(expr, &|expr| {
1258 Ok(match expr {
1259 Expression::Column(mut column)
1260 if column
1261 .table
1262 .as_ref()
1263 .is_some_and(|table| Self::same_identifier(table, from)) =>
1264 {
1265 column.table = Some(to.clone());
1266 Expression::Column(column)
1267 }
1268 other => other,
1269 })
1270 })
1271 }
1272
1273 fn same_identifier(left: &Identifier, right: &Identifier) -> bool {
1274 if left.quoted || right.quoted {
1275 left.quoted == right.quoted && left.name == right.name
1276 } else {
1277 left.name.eq_ignore_ascii_case(&right.name)
1278 }
1279 }
1280
1281 fn is_lateral_table_expression(expr: &Expression) -> bool {
1282 match expr {
1283 Expression::Subquery(subquery) => subquery.lateral,
1284 Expression::Lateral(_) => true,
1285 Expression::Alias(alias) => Self::is_lateral_table_expression(&alias.this),
1286 _ => false,
1287 }
1288 }
1289
1290 fn remove_lateral_marker(expr: Expression) -> Expression {
1291 match expr {
1292 Expression::Subquery(mut subquery) => {
1293 subquery.lateral = false;
1294 Expression::Subquery(subquery)
1295 }
1296 Expression::Lateral(lateral) => Self::lateral_to_table_expression(*lateral),
1297 Expression::Alias(mut alias) => {
1298 alias.this = Self::remove_lateral_marker(alias.this);
1299 Expression::Alias(alias)
1300 }
1301 other => other,
1302 }
1303 }
1304
1305 fn lateral_to_table_expression(lateral: crate::expressions::Lateral) -> Expression {
1306 let expr = *lateral.this;
1307 let Some(alias) = lateral.alias else {
1308 return expr;
1309 };
1310
1311 Expression::Alias(Box::new(Alias {
1312 this: expr,
1313 alias: if lateral.alias_quoted {
1314 Identifier::quoted(alias)
1315 } else {
1316 Identifier::new(alias)
1317 },
1318 column_aliases: lateral
1319 .column_aliases
1320 .into_iter()
1321 .map(Identifier::new)
1322 .collect(),
1323 alias_explicit_as: true,
1324 alias_keyword: None,
1325 pre_alias_comments: Vec::new(),
1326 trailing_comments: Vec::new(),
1327 inferred_type: None,
1328 }))
1329 }
1330
1331 fn rewrite_tuple_in_subquery_predicates(
1332 expr: Expression,
1333 outer_qualifier: Option<&Identifier>,
1334 under_not: bool,
1335 ) -> Expression {
1336 match expr {
1337 Expression::In(in_expr) if !under_not => {
1338 let in_expr = *in_expr;
1339 Self::tuple_in_subquery_to_exists(&in_expr, outer_qualifier)
1340 .unwrap_or_else(|| Expression::In(Box::new(in_expr)))
1341 }
1342 Expression::And(mut op) => {
1343 op.left =
1344 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1345 op.right = Self::rewrite_tuple_in_subquery_predicates(
1346 op.right,
1347 outer_qualifier,
1348 under_not,
1349 );
1350 Expression::And(op)
1351 }
1352 Expression::Or(mut op) => {
1353 op.left =
1354 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1355 op.right = Self::rewrite_tuple_in_subquery_predicates(
1356 op.right,
1357 outer_qualifier,
1358 under_not,
1359 );
1360 Expression::Or(op)
1361 }
1362 Expression::Paren(mut paren) => {
1363 paren.this = Self::rewrite_tuple_in_subquery_predicates(
1364 paren.this,
1365 outer_qualifier,
1366 under_not,
1367 );
1368 Expression::Paren(paren)
1369 }
1370 Expression::Not(mut not) => {
1371 not.this =
1372 Self::rewrite_tuple_in_subquery_predicates(not.this, outer_qualifier, true);
1373 Expression::Not(not)
1374 }
1375 other => other,
1376 }
1377 }
1378
1379 fn tuple_in_subquery_to_exists(
1380 in_expr: &In,
1381 outer_qualifier: Option<&Identifier>,
1382 ) -> Option<Expression> {
1383 if in_expr.not || !in_expr.expressions.is_empty() || in_expr.unnest.is_some() {
1384 return None;
1385 }
1386
1387 let left_expressions = Self::tuple_expressions(&in_expr.this)?;
1388 let mut select = match in_expr.query.as_ref()? {
1389 Expression::Select(select) => (**select).clone(),
1390 _ => return None,
1391 };
1392
1393 if left_expressions.len() != select.expressions.len() || left_expressions.is_empty() {
1394 return None;
1395 }
1396
1397 let inner_qualifier = Self::single_select_source_qualifier(&select);
1398 let mut predicates = Vec::with_capacity(left_expressions.len() + 1);
1399 for (projection, left) in select
1400 .expressions
1401 .iter()
1402 .cloned()
1403 .zip(left_expressions.iter().cloned())
1404 {
1405 let inner = Self::tuple_in_projection_expr(projection, inner_qualifier.as_ref())?;
1406 let outer = Self::qualify_tuple_operand(left, outer_qualifier);
1407 predicates.push(Expression::Eq(Box::new(BinaryOp::new(inner, outer))));
1408 }
1409
1410 if let Some(where_clause) = select.where_clause.take() {
1411 predicates.push(where_clause.this);
1412 }
1413
1414 select.expressions = vec![Expression::number(1)];
1415 select.where_clause = Some(Where {
1416 this: Self::and_all(predicates)?,
1417 });
1418
1419 Some(Expression::Exists(Box::new(Exists {
1420 this: Expression::Select(Box::new(select)),
1421 not: false,
1422 })))
1423 }
1424
1425 fn tuple_expressions(expr: &Expression) -> Option<&[Expression]> {
1426 match expr {
1427 Expression::Tuple(tuple) => Some(&tuple.expressions),
1428 Expression::Paren(paren) => Self::tuple_expressions(&paren.this),
1429 _ => None,
1430 }
1431 }
1432
1433 fn tuple_in_projection_expr(
1434 expr: Expression,
1435 qualifier: Option<&Identifier>,
1436 ) -> Option<Expression> {
1437 match expr {
1438 Expression::Alias(alias) => Self::tuple_in_projection_expr(alias.this, qualifier),
1439 Expression::Column(mut column) => {
1440 if column.table.is_none() {
1441 column.table = qualifier.cloned();
1442 }
1443 Some(Expression::Column(column))
1444 }
1445 Expression::Identifier(identifier) => {
1446 Some(Self::column_from_identifier(identifier, qualifier.cloned()))
1447 }
1448 Expression::Dot(_) => Some(expr),
1449 _ => None,
1450 }
1451 }
1452
1453 fn qualify_tuple_operand(expr: Expression, qualifier: Option<&Identifier>) -> Expression {
1454 match expr {
1455 Expression::Column(mut column) => {
1456 if column.table.is_none() {
1457 column.table = qualifier.cloned();
1458 }
1459 Expression::Column(column)
1460 }
1461 Expression::Identifier(identifier) => {
1462 Self::column_from_identifier(identifier, qualifier.cloned())
1463 }
1464 other => other,
1465 }
1466 }
1467
1468 fn column_from_identifier(identifier: Identifier, table: Option<Identifier>) -> Expression {
1469 Expression::Column(Box::new(Column {
1470 name: identifier,
1471 table,
1472 join_mark: false,
1473 trailing_comments: Vec::new(),
1474 span: None,
1475 inferred_type: None,
1476 }))
1477 }
1478
1479 fn single_select_source_qualifier(select: &Select) -> Option<Identifier> {
1480 if !select.joins.is_empty() {
1481 return None;
1482 }
1483
1484 let from = select.from.as_ref()?;
1485 if from.expressions.len() != 1 {
1486 return None;
1487 }
1488
1489 Self::source_qualifier(&from.expressions[0])
1490 }
1491
1492 fn source_qualifier(source: &Expression) -> Option<Identifier> {
1493 match source {
1494 Expression::Table(table) => table.alias.clone().or_else(|| Some(table.name.clone())),
1495 Expression::Subquery(subquery) => subquery.alias.clone(),
1496 _ => None,
1497 }
1498 }
1499
1500 fn and_all(mut predicates: Vec<Expression>) -> Option<Expression> {
1501 if predicates.is_empty() {
1502 return None;
1503 }
1504
1505 let first = predicates.remove(0);
1506 Some(predicates.into_iter().fold(first, |left, right| {
1507 Expression::And(Box::new(BinaryOp::new(left, right)))
1508 }))
1509 }
1510
1511 pub(super) fn transform_data_type(
1513 &self,
1514 dt: crate::expressions::DataType,
1515 ) -> Result<Expression> {
1516 use crate::expressions::DataType;
1517 let transformed = match dt {
1518 DataType::Boolean => DataType::Custom {
1520 name: "BIT".to_string(),
1521 },
1522 DataType::Int { .. } => dt,
1524 DataType::Decimal { precision, scale } => DataType::Custom {
1527 name: if let (Some(p), Some(s)) = (&precision, &scale) {
1528 format!("NUMERIC({}, {})", p, s)
1529 } else if let Some(p) = &precision {
1530 format!("NUMERIC({})", p)
1531 } else {
1532 "NUMERIC".to_string()
1533 },
1534 },
1535 DataType::Text => DataType::Custom {
1537 name: "VARCHAR(MAX)".to_string(),
1538 },
1539 DataType::Timestamp { .. } => DataType::Custom {
1541 name: "DATETIME2".to_string(),
1542 },
1543 DataType::Uuid => DataType::Custom {
1545 name: "UNIQUEIDENTIFIER".to_string(),
1546 },
1547 DataType::Custom { ref name } => {
1549 let upper = name.trim().to_uppercase();
1550 let (base_name, precision, _scale) = Self::parse_type_precision_and_scale(&upper);
1551 match base_name.as_str() {
1552 "BPCHAR" => {
1554 if let Some(len) = precision {
1555 DataType::Char { length: Some(len) }
1556 } else {
1557 DataType::Char { length: None }
1558 }
1559 }
1560 _ => dt,
1561 }
1562 }
1563 other => other,
1565 };
1566 Ok(Expression::DataType(transformed))
1567 }
1568
1569 pub(super) fn parse_type_precision_and_scale(name: &str) -> (String, Option<u32>, Option<u32>) {
1571 if let Some(paren_pos) = name.find('(') {
1572 let base = name[..paren_pos].to_string();
1573 let rest = &name[paren_pos + 1..];
1574 if let Some(close_pos) = rest.find(')') {
1575 let args = &rest[..close_pos];
1576 let parts: Vec<&str> = args.split(',').map(|s| s.trim()).collect();
1577 let precision = parts.first().and_then(|s| s.parse::<u32>().ok());
1578 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1579 return (base, precision, scale);
1580 }
1581 (base, None, None)
1582 } else {
1583 (name.to_string(), None, None)
1584 }
1585 }
1586
1587 fn transform_logical_aggregate(
1588 condition: Expression,
1589 filter: Option<Expression>,
1590 aggregate_name: &str,
1591 ) -> Result<Expression> {
1592 let false_condition = Expression::Not(Box::new(crate::expressions::UnaryOp {
1593 this: condition.clone(),
1594 inferred_type: None,
1595 }));
1596 let true_condition = Self::apply_aggregate_filter(condition, filter.clone());
1597 let false_condition = Self::apply_aggregate_filter(false_condition, filter);
1598
1599 let case_expr = Expression::Case(Box::new(crate::expressions::Case {
1600 operand: None,
1601 whens: vec![
1602 (true_condition, Expression::number(1)),
1603 (false_condition, Expression::number(0)),
1604 ],
1605 else_: Some(Expression::null()),
1606 comments: Vec::new(),
1607 inferred_type: None,
1608 }));
1609
1610 let case_expr = crate::transforms::ensure_bools(case_expr)?;
1611 let aggregate = Expression::Function(Box::new(Function::new(
1612 aggregate_name.to_string(),
1613 vec![case_expr],
1614 )));
1615
1616 Ok(Expression::Cast(Box::new(Cast {
1617 this: aggregate,
1618 to: DataType::Custom {
1619 name: "BIT".to_string(),
1620 },
1621 trailing_comments: Vec::new(),
1622 double_colon_syntax: false,
1623 format: None,
1624 default: None,
1625 inferred_type: None,
1626 })))
1627 }
1628
1629 fn apply_aggregate_filter(condition: Expression, filter: Option<Expression>) -> Expression {
1630 match filter {
1631 Some(filter) => Expression::And(Box::new(crate::expressions::BinaryOp::new(
1632 filter, condition,
1633 ))),
1634 None => condition,
1635 }
1636 }
1637
1638 fn transform_function(&self, f: Function) -> Result<Expression> {
1639 let name_upper = f.name.to_uppercase();
1640 match name_upper.as_str() {
1641 "COALESCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
1643 "ISNULL".to_string(),
1644 f.args,
1645 )))),
1646
1647 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
1649 "ISNULL".to_string(),
1650 f.args,
1651 )))),
1652
1653 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1655 Function::new("STRING_AGG".to_string(), f.args),
1656 ))),
1657
1658 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
1660
1661 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1663 "STRING_AGG".to_string(),
1664 f.args,
1665 )))),
1666
1667 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1669 "SUBSTRING".to_string(),
1670 f.args,
1671 )))),
1672
1673 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1675 "LEN".to_string(),
1676 f.args,
1677 )))),
1678
1679 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
1681 seed: None,
1682 lower: None,
1683 upper: None,
1684 }))),
1685
1686 "NOW" => Ok(Expression::Function(Box::new(Function::new(
1688 "GETDATE".to_string(),
1689 vec![],
1690 )))),
1691
1692 "CURRENT_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1694 "GETDATE".to_string(),
1695 vec![],
1696 )))),
1697
1698 "CURRENT_DATE" => {
1700 Ok(Expression::Function(Box::new(Function::new(
1702 "CAST".to_string(),
1703 vec![
1704 Expression::Function(Box::new(Function::new(
1705 "GETDATE".to_string(),
1706 vec![],
1707 ))),
1708 Expression::Identifier(crate::expressions::Identifier::new("DATE")),
1709 ],
1710 ))))
1711 }
1712
1713 "TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
1715 "CONVERT".to_string(),
1716 f.args,
1717 )))),
1718
1719 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1721 "CONVERT".to_string(),
1722 f.args,
1723 )))),
1724
1725 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
1727 "FORMAT".to_string(),
1728 f.args,
1729 )))),
1730
1731 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
1733 "FORMAT".to_string(),
1734 f.args,
1735 )))),
1736
1737 "DATE_TRUNC" | "DATETRUNC" => {
1740 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
1741 if args.len() >= 2 {
1743 if let Expression::Literal(lit) = &args[1] {
1744 if let Literal::String(_) = lit.as_ref() {
1745 args[1] = Expression::Cast(Box::new(Cast {
1746 this: args[1].clone(),
1747 to: DataType::Custom {
1748 name: "DATETIME2".to_string(),
1749 },
1750 trailing_comments: Vec::new(),
1751 double_colon_syntax: false,
1752 format: None,
1753 default: None,
1754 inferred_type: None,
1755 }));
1756 }
1757 }
1758 }
1759 Ok(Expression::Function(Box::new(Function::new(
1760 "DATETRUNC".to_string(),
1761 args,
1762 ))))
1763 }
1764
1765 "DATEADD" => {
1767 let args = Self::uppercase_first_arg_if_identifier(f.args);
1768 Ok(Expression::Function(Box::new(Function::new(
1769 "DATEADD".to_string(),
1770 args,
1771 ))))
1772 }
1773
1774 "DATEDIFF" => {
1776 let args = Self::uppercase_first_arg_if_identifier(f.args);
1777 Ok(Expression::Function(Box::new(Function::new(
1778 "DATEDIFF".to_string(),
1779 args,
1780 ))))
1781 }
1782
1783 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
1785 "DATEPART".to_string(),
1786 f.args,
1787 )))),
1788
1789 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
1791 Ok(Expression::Function(Box::new(Function::new(
1793 "CHARINDEX".to_string(),
1794 f.args,
1795 ))))
1796 }
1797
1798 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
1800
1801 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
1803 Function::new("CEILING".to_string(), f.args),
1804 ))),
1805
1806 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
1811 "JSON_VALUE".to_string(),
1812 f.args,
1813 )))),
1814
1815 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
1817 "JSON_VALUE".to_string(),
1818 f.args,
1819 )))),
1820
1821 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
1823
1824 "GET_PATH" if f.args.len() == 2 => {
1826 let mut args = f.args;
1827 let this = args.remove(0);
1828 let path = args.remove(0);
1829 let json_path = match &path {
1830 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
1831 let Literal::String(s) = lit.as_ref() else {
1832 unreachable!()
1833 };
1834 let normalized = if s.starts_with('$') {
1835 s.clone()
1836 } else if s.starts_with('[') {
1837 format!("${}", s)
1838 } else {
1839 format!("$.{}", s)
1840 };
1841 Expression::Literal(Box::new(Literal::String(normalized)))
1842 }
1843 _ => path,
1844 };
1845 let json_query = Expression::Function(Box::new(Function::new(
1847 "JSON_QUERY".to_string(),
1848 vec![this.clone(), json_path.clone()],
1849 )));
1850 let json_value = Expression::Function(Box::new(Function::new(
1851 "JSON_VALUE".to_string(),
1852 vec![this, json_path],
1853 )));
1854 Ok(Expression::Function(Box::new(Function::new(
1855 "ISNULL".to_string(),
1856 vec![json_query, json_value],
1857 ))))
1858 }
1859
1860 "JSON_QUERY" if f.args.len() == 1 => {
1863 let this = f.args.into_iter().next().unwrap();
1864 let path = Expression::Literal(Box::new(Literal::String("$".to_string())));
1865 let json_query = Expression::Function(Box::new(Function::new(
1866 "JSON_QUERY".to_string(),
1867 vec![this.clone(), path.clone()],
1868 )));
1869 let json_value = Expression::Function(Box::new(Function::new(
1870 "JSON_VALUE".to_string(),
1871 vec![this, path],
1872 )));
1873 Ok(Expression::Function(Box::new(Function::new(
1874 "ISNULL".to_string(),
1875 vec![json_query, json_value],
1876 ))))
1877 }
1878
1879 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
1881 "STRING_SPLIT".to_string(),
1882 f.args,
1883 )))),
1884
1885 "REGEXP_LIKE" => {
1888 Ok(Expression::Function(Box::new(Function::new(
1890 "PATINDEX".to_string(),
1891 f.args,
1892 ))))
1893 }
1894
1895 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1897 "LOG".to_string(),
1898 f.args,
1899 )))),
1900
1901 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1906 "STDEV".to_string(),
1907 f.args,
1908 )))),
1909
1910 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
1912 "STDEVP".to_string(),
1913 f.args,
1914 )))),
1915
1916 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1918 "VAR".to_string(),
1919 f.args,
1920 )))),
1921
1922 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
1924 "VARP".to_string(),
1925 f.args,
1926 )))),
1927
1928 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
1930 let mut args = f.args;
1931 Self::transform_logical_aggregate(args.remove(0), None, "MIN")
1932 }
1933 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
1934 let mut args = f.args;
1935 Self::transform_logical_aggregate(args.remove(0), None, "MAX")
1936 }
1937
1938 "DATE_ADD" => {
1940 if f.args.len() == 2 {
1941 let mut args = f.args;
1942 let date = args.remove(0);
1943 let interval = args.remove(0);
1944 let unit = Expression::Identifier(crate::expressions::Identifier {
1945 name: "DAY".to_string(),
1946 quoted: false,
1947 trailing_comments: Vec::new(),
1948 span: None,
1949 });
1950 Ok(Expression::Function(Box::new(Function::new(
1951 "DATEADD".to_string(),
1952 vec![unit, interval, date],
1953 ))))
1954 } else {
1955 let args = Self::uppercase_first_arg_if_identifier(f.args);
1956 Ok(Expression::Function(Box::new(Function::new(
1957 "DATEADD".to_string(),
1958 args,
1959 ))))
1960 }
1961 }
1962
1963 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
1965 "STUFF".to_string(),
1966 f.args,
1967 )))),
1968
1969 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
1971 crate::expressions::CurrentUser { this: None },
1972 ))),
1973
1974 _ => Ok(Expression::Function(Box::new(f))),
1976 }
1977 }
1978
1979 fn transform_aggregate_function(
1980 &self,
1981 f: Box<crate::expressions::AggregateFunction>,
1982 ) -> Result<Expression> {
1983 let name_upper = f.name.to_uppercase();
1984 match name_upper.as_str() {
1985 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1987 Function::new("STRING_AGG".to_string(), f.args),
1988 ))),
1989
1990 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1992 "STRING_AGG".to_string(),
1993 f.args,
1994 )))),
1995
1996 "ARRAY_AGG" if !f.args.is_empty() => {
1999 Ok(Expression::Function(Box::new(Function::new(
2001 "STRING_AGG".to_string(),
2002 f.args,
2003 ))))
2004 }
2005
2006 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
2008 let mut args = f.args;
2009 Self::transform_logical_aggregate(args.remove(0), f.filter, "MIN")
2010 }
2011 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
2012 let mut args = f.args;
2013 Self::transform_logical_aggregate(args.remove(0), f.filter, "MAX")
2014 }
2015
2016 _ => Ok(Expression::AggregateFunction(f)),
2018 }
2019 }
2020
2021 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
2025 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
2026 }
2027
2028 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
2030 if cte.columns.is_empty() {
2033 cte.this = self.qualify_derived_table_outputs(cte.this);
2034 }
2035 cte
2036 }
2037
2038 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
2042 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
2045 subquery.this = self.qualify_derived_table_outputs(subquery.this);
2046 }
2047 Ok(Expression::Subquery(Box::new(subquery)))
2048 }
2049
2050 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
2054 match expr {
2055 Expression::Select(mut select) => {
2056 let has_from = select.from.is_some();
2059 if !has_from {
2060 select.expressions = select
2061 .expressions
2062 .into_iter()
2063 .map(|e| self.maybe_alias_expression(e))
2064 .collect();
2065 }
2066 Expression::Select(select)
2067 }
2068 Expression::Union(mut u) => {
2070 let left = std::mem::replace(&mut u.left, Expression::Null(Null));
2071 u.left = self.qualify_derived_table_outputs(left);
2072 Expression::Union(u)
2073 }
2074 Expression::Intersect(mut i) => {
2075 let left = std::mem::replace(&mut i.left, Expression::Null(Null));
2076 i.left = self.qualify_derived_table_outputs(left);
2077 Expression::Intersect(i)
2078 }
2079 Expression::Except(mut e) => {
2080 let left = std::mem::replace(&mut e.left, Expression::Null(Null));
2081 e.left = self.qualify_derived_table_outputs(left);
2082 Expression::Except(e)
2083 }
2084 Expression::Subquery(mut s) => {
2086 s.this = self.qualify_derived_table_outputs(s.this);
2087 Expression::Subquery(s)
2088 }
2089 other => other,
2091 }
2092 }
2093
2094 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
2099 match &expr {
2100 Expression::Alias(_) => expr,
2102 Expression::Aliases(_) => expr,
2104 Expression::Star(_) => expr,
2106 _ => {
2111 if let Some(output_name) = self.get_output_name(&expr) {
2112 Expression::Alias(Box::new(Alias {
2113 this: expr,
2114 alias: Identifier {
2115 name: output_name,
2116 quoted: true, trailing_comments: Vec::new(),
2118 span: None,
2119 },
2120 column_aliases: Vec::new(),
2121 alias_explicit_as: false,
2122 alias_keyword: None,
2123 pre_alias_comments: Vec::new(),
2124 trailing_comments: Vec::new(),
2125 inferred_type: None,
2126 }))
2127 } else {
2128 expr
2130 }
2131 }
2132 }
2133 }
2134
2135 fn get_output_name(&self, expr: &Expression) -> Option<String> {
2139 match expr {
2140 Expression::Literal(lit) => match lit.as_ref() {
2142 Literal::Number(n) => Some(n.clone()),
2143 Literal::String(s) => Some(s.clone()),
2144 Literal::HexString(h) => Some(format!("0x{}", h)),
2145 Literal::HexNumber(h) => Some(format!("0x{}", h)),
2146 Literal::BitString(b) => Some(format!("b{}", b)),
2147 Literal::ByteString(b) => Some(format!("b'{}'", b)),
2148 Literal::NationalString(s) => Some(format!("N'{}'", s)),
2149 Literal::Date(d) => Some(d.clone()),
2150 Literal::Time(t) => Some(t.clone()),
2151 Literal::Timestamp(ts) => Some(ts.clone()),
2152 Literal::Datetime(dt) => Some(dt.clone()),
2153 Literal::TripleQuotedString(s, _) => Some(s.clone()),
2154 Literal::EscapeString(s) => Some(s.clone()),
2155 Literal::DollarString(s) => Some(s.clone()),
2156 Literal::RawString(s) => Some(s.clone()),
2157 },
2158 Expression::Column(col) => Some(col.name.name.clone()),
2160 Expression::Identifier(ident) => Some(ident.name.clone()),
2162 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
2164 Expression::Null(_) => Some("NULL".to_string()),
2166 Expression::Function(f) => Some(f.name.clone()),
2168 Expression::AggregateFunction(f) => Some(f.name.clone()),
2170 _ => Some(format!("_col_{}", 0)),
2172 }
2173 }
2174
2175 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
2177 use crate::expressions::Identifier;
2178 if !args.is_empty() {
2179 match &args[0] {
2180 Expression::Identifier(id) => {
2181 args[0] = Expression::Identifier(Identifier {
2182 name: id.name.to_uppercase(),
2183 quoted: id.quoted,
2184 trailing_comments: id.trailing_comments.clone(),
2185 span: None,
2186 });
2187 }
2188 Expression::Var(v) => {
2189 args[0] = Expression::Identifier(Identifier {
2190 name: v.this.to_uppercase(),
2191 quoted: false,
2192 trailing_comments: Vec::new(),
2193 span: None,
2194 });
2195 }
2196 Expression::Column(col) if col.table.is_none() => {
2197 args[0] = Expression::Identifier(Identifier {
2198 name: col.name.name.to_uppercase(),
2199 quoted: col.name.quoted,
2200 trailing_comments: col.name.trailing_comments.clone(),
2201 span: None,
2202 });
2203 }
2204 _ => {}
2205 }
2206 }
2207 args
2208 }
2209}
2210
2211#[cfg(test)]
2212mod tests {
2213 use super::*;
2214 use crate::dialects::Dialect;
2215
2216 fn transpile_to_tsql(sql: &str) -> String {
2217 let dialect = Dialect::get(DialectType::Generic);
2218 let result = dialect
2219 .transpile(sql, DialectType::TSQL)
2220 .expect("Transpile failed");
2221 result[0].clone()
2222 }
2223
2224 #[test]
2225 fn test_nvl_to_isnull() {
2226 let result = transpile_to_tsql("SELECT NVL(a, b)");
2227 assert!(
2228 result.contains("ISNULL"),
2229 "Expected ISNULL, got: {}",
2230 result
2231 );
2232 }
2233
2234 #[test]
2235 fn test_coalesce_to_isnull() {
2236 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
2237 assert!(
2238 result.contains("ISNULL"),
2239 "Expected ISNULL, got: {}",
2240 result
2241 );
2242 }
2243
2244 #[test]
2245 fn test_basic_select() {
2246 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
2247 assert!(result.contains("SELECT"));
2248 assert!(result.contains("FROM users"));
2249 }
2250
2251 #[test]
2252 fn test_length_to_len() {
2253 let result = transpile_to_tsql("SELECT LENGTH(name)");
2254 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
2255 }
2256
2257 #[test]
2258 fn test_now_to_getdate() {
2259 let result = transpile_to_tsql("SELECT NOW()");
2260 assert!(
2261 result.contains("GETDATE"),
2262 "Expected GETDATE, got: {}",
2263 result
2264 );
2265 }
2266
2267 #[test]
2268 fn test_group_concat_to_string_agg() {
2269 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
2270 assert!(
2271 result.contains("STRING_AGG"),
2272 "Expected STRING_AGG, got: {}",
2273 result
2274 );
2275 }
2276
2277 #[test]
2278 fn test_listagg_to_string_agg() {
2279 let result = transpile_to_tsql("SELECT LISTAGG(name)");
2280 assert!(
2281 result.contains("STRING_AGG"),
2282 "Expected STRING_AGG, got: {}",
2283 result
2284 );
2285 }
2286
2287 #[test]
2288 fn test_ln_to_log() {
2289 let result = transpile_to_tsql("SELECT LN(x)");
2290 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
2291 }
2292
2293 #[test]
2294 fn test_stddev_to_stdev() {
2295 let result = transpile_to_tsql("SELECT STDDEV(x)");
2296 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
2297 }
2298
2299 #[test]
2300 fn test_bracket_identifiers() {
2301 let dialect = Dialect::get(DialectType::TSQL);
2303 let config = dialect.generator_config();
2304 assert_eq!(config.identifier_quote, '[');
2305 }
2306
2307 #[test]
2308 fn test_json_query_isnull_wrapper_simple() {
2309 let dialect = Dialect::get(DialectType::TSQL);
2311 let result = dialect
2312 .transpile(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
2313 .expect("transpile failed");
2314 assert!(
2315 result[0].contains("ISNULL"),
2316 "JSON_QUERY should be wrapped with ISNULL: {}",
2317 result[0]
2318 );
2319 }
2320
2321 #[test]
2322 fn test_json_query_isnull_wrapper_nested() {
2323 let dialect = Dialect::get(DialectType::TSQL);
2324 let result = dialect
2325 .transpile(
2326 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
2327 DialectType::TSQL,
2328 )
2329 .expect("transpile failed");
2330 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
2331 assert_eq!(
2332 result[0], expected,
2333 "JSON_QUERY should be wrapped with ISNULL"
2334 );
2335 }
2336}