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) => {
200 let one = Expression::Literal(Box::new(crate::expressions::Literal::Number(
201 "1".to_string(),
202 )));
203 if it.not {
204 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
206 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
207 left: it.this,
208 right: one,
209 left_comments: vec![],
210 operator_comments: vec![],
211 trailing_comments: vec![],
212 inferred_type: None,
213 })),
214 inferred_type: None,
215 })))
216 } else {
217 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
219 left: it.this,
220 right: one,
221 left_comments: vec![],
222 operator_comments: vec![],
223 trailing_comments: vec![],
224 inferred_type: None,
225 })))
226 }
227 }
228 Expression::IsFalse(it) => {
229 let zero = Expression::Literal(Box::new(crate::expressions::Literal::Number(
230 "0".to_string(),
231 )));
232 if it.not {
233 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
235 this: Expression::Eq(Box::new(crate::expressions::BinaryOp {
236 left: it.this,
237 right: zero,
238 left_comments: vec![],
239 operator_comments: vec![],
240 trailing_comments: vec![],
241 inferred_type: None,
242 })),
243 inferred_type: None,
244 })))
245 } else {
246 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp {
248 left: it.this,
249 right: zero,
250 left_comments: vec![],
251 operator_comments: vec![],
252 trailing_comments: vec![],
253 inferred_type: None,
254 })))
255 }
256 }
257
258 Expression::In(mut in_expr) if in_expr.not => {
262 in_expr.not = false;
263 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
264 this: Expression::In(in_expr),
265 inferred_type: None,
266 })))
267 }
268
269 Expression::Coalesce(f) if f.expressions.len() == 2 => Ok(Expression::Function(
272 Box::new(Function::new("ISNULL".to_string(), f.expressions)),
273 )),
274
275 Expression::Nvl(f) => Ok(Expression::Function(Box::new(Function::new(
277 "ISNULL".to_string(),
278 vec![f.this, f.expression],
279 )))),
280
281 Expression::GroupConcat(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
283 this: f.this,
284 separator: f.separator,
285 order_by: f.order_by,
286 distinct: f.distinct,
287 filter: f.filter,
288 limit: None,
289 inferred_type: None,
290 }))),
291
292 Expression::ListAgg(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
294 this: f.this,
295 separator: f.separator,
296 order_by: f.order_by,
297 distinct: f.distinct,
298 filter: f.filter,
299 limit: None,
300 inferred_type: None,
301 }))),
302
303 Expression::LogicalAnd(f) => Self::transform_logical_aggregate(f.this, f.filter, "MIN"),
306 Expression::LogicalOr(f) => Self::transform_logical_aggregate(f.this, f.filter, "MAX"),
307
308 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
310
311 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
313
314 Expression::ILike(op) => {
316 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
319 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
320 Ok(Expression::Like(Box::new(LikeOp {
321 left: lower_left,
322 right: lower_right,
323 escape: op.escape,
324 quantifier: op.quantifier,
325 inferred_type: None,
326 })))
327 }
328
329 Expression::Concat(op) => {
332 Ok(Expression::Add(op))
334 }
335
336 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
338 seed: None,
339 lower: None,
340 upper: None,
341 }))),
342
343 Expression::Unnest(f) => {
345 Ok(Expression::Function(Box::new(Function::new(
348 "OPENJSON".to_string(),
349 vec![f.this],
350 ))))
351 }
352
353 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
355 "OPENJSON".to_string(),
356 vec![f.this],
357 )))),
358
359 Expression::Join(join) => Ok(Expression::Join(Box::new(
361 Self::transform_lateral_join_to_apply(*join)?,
362 ))),
363
364 Expression::Length(f) => Ok(Expression::Function(Box::new(Function::new(
366 "LEN".to_string(),
367 vec![f.this],
368 )))),
369
370 Expression::Stddev(f) => Ok(Expression::Function(Box::new(Function::new(
372 "STDEV".to_string(),
373 vec![f.this],
374 )))),
375 Expression::StddevSamp(f) => Ok(Expression::Function(Box::new(Function::new(
376 "STDEV".to_string(),
377 vec![f.this],
378 )))),
379 Expression::StddevPop(f) => Ok(Expression::Function(Box::new(Function::new(
380 "STDEVP".to_string(),
381 vec![f.this],
382 )))),
383
384 Expression::Boolean(b) => {
386 let value = if b.value { 1 } else { 0 };
387 Ok(Expression::Literal(Box::new(
388 crate::expressions::Literal::Number(value.to_string()),
389 )))
390 }
391
392 Expression::Ln(f) => Ok(Expression::Function(Box::new(Function::new(
394 "LOG".to_string(),
395 vec![f.this],
396 )))),
397
398 Expression::CurrentDate(_) => {
401 let getdate =
402 Expression::Function(Box::new(Function::new("GETDATE".to_string(), vec![])));
403 Ok(Expression::Cast(Box::new(crate::expressions::Cast {
404 this: getdate,
405 to: crate::expressions::DataType::Date,
406 trailing_comments: Vec::new(),
407 double_colon_syntax: false,
408 format: None,
409 default: None,
410 inferred_type: None,
411 })))
412 }
413
414 Expression::CurrentTimestamp(_) => Ok(Expression::Function(Box::new(Function::new(
416 "GETDATE".to_string(),
417 vec![],
418 )))),
419
420 Expression::DateDiff(f) => {
422 let unit_str = match f.unit {
424 Some(crate::expressions::IntervalUnit::Year) => "YEAR",
425 Some(crate::expressions::IntervalUnit::Quarter) => "QUARTER",
426 Some(crate::expressions::IntervalUnit::Month) => "MONTH",
427 Some(crate::expressions::IntervalUnit::Week) => "WEEK",
428 Some(crate::expressions::IntervalUnit::Day) => "DAY",
429 Some(crate::expressions::IntervalUnit::Hour) => "HOUR",
430 Some(crate::expressions::IntervalUnit::Minute) => "MINUTE",
431 Some(crate::expressions::IntervalUnit::Second) => "SECOND",
432 Some(crate::expressions::IntervalUnit::Millisecond) => "MILLISECOND",
433 Some(crate::expressions::IntervalUnit::Microsecond) => "MICROSECOND",
434 Some(crate::expressions::IntervalUnit::Nanosecond) => "NANOSECOND",
435 None => "DAY",
436 };
437 let unit = Expression::Identifier(crate::expressions::Identifier {
438 name: unit_str.to_string(),
439 quoted: false,
440 trailing_comments: Vec::new(),
441 span: None,
442 });
443 Ok(Expression::Function(Box::new(Function::new(
444 "DATEDIFF".to_string(),
445 vec![unit, f.expression, f.this], ))))
447 }
448
449 Expression::DateAdd(f) => {
451 let unit_str = match f.unit {
452 crate::expressions::IntervalUnit::Year => "YEAR",
453 crate::expressions::IntervalUnit::Quarter => "QUARTER",
454 crate::expressions::IntervalUnit::Month => "MONTH",
455 crate::expressions::IntervalUnit::Week => "WEEK",
456 crate::expressions::IntervalUnit::Day => "DAY",
457 crate::expressions::IntervalUnit::Hour => "HOUR",
458 crate::expressions::IntervalUnit::Minute => "MINUTE",
459 crate::expressions::IntervalUnit::Second => "SECOND",
460 crate::expressions::IntervalUnit::Millisecond => "MILLISECOND",
461 crate::expressions::IntervalUnit::Microsecond => "MICROSECOND",
462 crate::expressions::IntervalUnit::Nanosecond => "NANOSECOND",
463 };
464 let unit = Expression::Identifier(crate::expressions::Identifier {
465 name: unit_str.to_string(),
466 quoted: false,
467 trailing_comments: Vec::new(),
468 span: None,
469 });
470 Ok(Expression::Function(Box::new(Function::new(
471 "DATEADD".to_string(),
472 vec![unit, f.interval, f.this],
473 ))))
474 }
475
476 Expression::Uuid(_) => Ok(Expression::Function(Box::new(Function::new(
479 "NEWID".to_string(),
480 vec![],
481 )))),
482
483 Expression::IfFunc(f) => {
486 let false_val = f
487 .false_value
488 .unwrap_or(Expression::Null(crate::expressions::Null));
489 Ok(Expression::Function(Box::new(Function::new(
490 "IIF".to_string(),
491 vec![f.condition, f.true_value, false_val],
492 ))))
493 }
494
495 Expression::StringAgg(f) => Ok(Expression::StringAgg(f)),
498
499 Expression::LastDay(f) => Ok(Expression::Function(Box::new(Function::new(
501 "EOMONTH".to_string(),
502 vec![f.this.clone()],
503 )))),
504
505 Expression::Ceil(f) => Ok(Expression::Function(Box::new(Function::new(
507 "CEILING".to_string(),
508 vec![f.this],
509 )))),
510
511 Expression::Repeat(f) => Ok(Expression::Function(Box::new(Function::new(
513 "REPLICATE".to_string(),
514 vec![f.this, f.times],
515 )))),
516
517 Expression::Chr(f) => Ok(Expression::Function(Box::new(Function::new(
519 "CHAR".to_string(),
520 vec![f.this],
521 )))),
522
523 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
526 "VARP".to_string(),
527 vec![f.this],
528 )))),
529
530 Expression::Variance(f) => Ok(Expression::Function(Box::new(Function::new(
532 "VAR".to_string(),
533 vec![f.this],
534 )))),
535 Expression::VarSamp(f) => Ok(Expression::Function(Box::new(Function::new(
536 "VAR".to_string(),
537 vec![f.this],
538 )))),
539
540 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
543 "HASHBYTES".to_string(),
544 vec![Expression::string("MD5"), *f.this],
545 )))),
546
547 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
549 "HASHBYTES".to_string(),
550 vec![Expression::string("SHA1"), f.this],
551 )))),
552
553 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
555 "HASHBYTES".to_string(),
556 vec![Expression::string("SHA1"), f.this],
557 )))),
558
559 Expression::ArrayToString(f) => Ok(Expression::Function(Box::new(Function::new(
562 "STRING_AGG".to_string(),
563 vec![f.this],
564 )))),
565
566 Expression::AutoIncrementColumnConstraint(_) => Ok(Expression::Function(Box::new(
569 Function::new("IDENTITY".to_string(), vec![]),
570 ))),
571
572 Expression::CreateView(mut view) => {
576 view.name.catalog = None;
578 Ok(Expression::CreateView(view))
579 }
580
581 Expression::DropView(mut view) => {
582 view.name.catalog = None;
584 Ok(Expression::DropView(view))
585 }
586
587 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
591 let path = match *e.expression {
592 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
593 let Literal::String(s) = lit.as_ref() else {
594 unreachable!()
595 };
596 let normalized = if s.starts_with('$') {
597 s.clone()
598 } else if s.starts_with('[') {
599 format!("${}", s)
600 } else {
601 format!("$.{}", s)
602 };
603 Expression::Literal(Box::new(Literal::String(normalized)))
604 }
605 other => other,
606 };
607 let json_query = Expression::Function(Box::new(Function::new(
608 "JSON_QUERY".to_string(),
609 vec![(*e.this).clone(), path.clone()],
610 )));
611 let json_value = Expression::Function(Box::new(Function::new(
612 "JSON_VALUE".to_string(),
613 vec![*e.this, path],
614 )));
615 Ok(Expression::Function(Box::new(Function::new(
616 "ISNULL".to_string(),
617 vec![json_query, json_value],
618 ))))
619 }
620
621 Expression::Function(f) => self.transform_function(*f),
623
624 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
626
627 Expression::Cte(cte) => self.transform_cte(*cte),
630
631 Expression::Subquery(subquery) => self.transform_subquery(*subquery),
634
635 Expression::JsonQuery(f) => {
637 let json_query = Expression::Function(Box::new(Function::new(
638 "JSON_QUERY".to_string(),
639 vec![f.this.clone(), f.path.clone()],
640 )));
641 let json_value = Expression::Function(Box::new(Function::new(
642 "JSON_VALUE".to_string(),
643 vec![f.this, f.path],
644 )));
645 Ok(Expression::Function(Box::new(Function::new(
646 "ISNULL".to_string(),
647 vec![json_query, json_value],
648 ))))
649 }
650 Expression::JsonValue(f) => Ok(Expression::Function(Box::new(Function::new(
652 "JSON_VALUE".to_string(),
653 vec![f.this, f.path],
654 )))),
655
656 Expression::Any(ref q) if matches!(&q.op, Some(QuantifiedOp::Eq)) => {
659 match Self::scalar_array_comparison_values(&q.subquery) {
660 Some(expressions) if expressions.is_empty() => {
661 Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp::new(
662 Expression::Literal(Box::new(Literal::Number("1".to_string()))),
663 Expression::Literal(Box::new(Literal::Number("0".to_string()))),
664 ))))
665 }
666 Some(expressions) => Ok(Expression::In(Box::new(In {
667 this: q.this.clone(),
668 expressions,
669 query: None,
670 not: false,
671 global: false,
672 unnest: None,
673 is_field: false,
674 }))),
675 None => Ok(expr.clone()),
676 }
677 }
678
679 _ => Ok(expr),
681 }
682 }
683}
684
685#[cfg(feature = "transpile")]
686impl TSQLDialect {
687 fn scalar_array_comparison_values(expr: &Expression) -> Option<Vec<Expression>> {
688 let (mut values, element_type) = Self::scalar_array_comparison_values_inner(expr)?;
689 if let Some(to) = element_type {
690 values = values
691 .into_iter()
692 .map(|value| Self::cast_scalar_array_comparison_value(value, to.clone()))
693 .collect();
694 }
695 Some(values)
696 }
697
698 fn scalar_array_comparison_values_inner(
699 expr: &Expression,
700 ) -> Option<(Vec<Expression>, Option<DataType>)> {
701 match expr {
702 Expression::ArrayFunc(a) => Some((a.expressions.clone(), None)),
703 Expression::Array(a) => Some((a.expressions.clone(), None)),
704 Expression::Tuple(t) => Some((t.expressions.clone(), None)),
705 Expression::Paren(p) => Self::scalar_array_comparison_values_inner(&p.this),
706 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
707 let DataType::Array { element_type, .. } = &c.to else {
708 return None;
709 };
710 let (values, _) = Self::scalar_array_comparison_values_inner(&c.this)?;
711 Some((values, Some((**element_type).clone())))
712 }
713 _ => None,
714 }
715 }
716
717 fn cast_scalar_array_comparison_value(value: Expression, to: DataType) -> Expression {
718 if matches!(&value, Expression::Cast(c) if c.to == to) {
719 return value;
720 }
721
722 Expression::Cast(Box::new(Cast {
723 this: value,
724 to,
725 trailing_comments: Vec::new(),
726 double_colon_syntax: false,
727 format: None,
728 default: None,
729 inferred_type: None,
730 }))
731 }
732
733 fn normalize_frame_incompatible_window_functions(select: &mut Select) {
734 let window_map: HashMap<String, Over> = select
735 .windows
736 .as_ref()
737 .map(|windows| {
738 windows
739 .iter()
740 .map(|window| (window.name.name.to_lowercase(), window.spec.clone()))
741 .collect()
742 })
743 .unwrap_or_default();
744
745 for expr in &mut select.expressions {
746 Self::normalize_frame_incompatible_window_expr(expr, &window_map);
747 }
748
749 if let Some(order_by) = &mut select.order_by {
750 for ordered in &mut order_by.expressions {
751 Self::normalize_frame_incompatible_window_expr(&mut ordered.this, &window_map);
752 }
753 }
754
755 if let Some(qualify) = &mut select.qualify {
756 Self::normalize_frame_incompatible_window_expr(&mut qualify.this, &window_map);
757 }
758 }
759
760 fn normalize_frame_incompatible_window_expr(
761 expr: &mut Expression,
762 window_map: &HashMap<String, Over>,
763 ) {
764 match expr {
765 Expression::WindowFunction(wf) => {
766 Self::normalize_frame_incompatible_window_expr(&mut wf.this, window_map);
767
768 if !Self::is_tsql_frame_incompatible_window_function(&wf.this) {
769 return;
770 }
771
772 wf.over.frame = None;
773
774 let Some(window_name) = wf.over.window_name.clone() else {
775 return;
776 };
777 let Some(named_spec) =
778 Self::resolve_named_window_spec(&window_name.name, window_map, &mut Vec::new())
779 else {
780 return;
781 };
782
783 if named_spec.frame.is_none() {
784 return;
785 }
786
787 if wf.over.partition_by.is_empty() {
788 wf.over.partition_by = named_spec.partition_by;
789 }
790 if wf.over.order_by.is_empty() {
791 wf.over.order_by = named_spec.order_by;
792 }
793 wf.over.window_name = None;
794 wf.over.frame = None;
795 }
796 Expression::Alias(alias) => {
797 Self::normalize_frame_incompatible_window_expr(&mut alias.this, window_map);
798 }
799 Expression::Paren(paren) => {
800 Self::normalize_frame_incompatible_window_expr(&mut paren.this, window_map);
801 }
802 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
803 Self::normalize_frame_incompatible_window_expr(&mut cast.this, window_map);
804 }
805 Expression::Function(function) => {
806 for arg in &mut function.args {
807 Self::normalize_frame_incompatible_window_expr(arg, window_map);
808 }
809 }
810 Expression::Case(case) => {
811 if let Some(operand) = &mut case.operand {
812 Self::normalize_frame_incompatible_window_expr(operand, window_map);
813 }
814 for (condition, result) in &mut case.whens {
815 Self::normalize_frame_incompatible_window_expr(condition, window_map);
816 Self::normalize_frame_incompatible_window_expr(result, window_map);
817 }
818 if let Some(else_expr) = &mut case.else_ {
819 Self::normalize_frame_incompatible_window_expr(else_expr, window_map);
820 }
821 }
822 Expression::And(op)
823 | Expression::Or(op)
824 | Expression::Add(op)
825 | Expression::Sub(op)
826 | Expression::Mul(op)
827 | Expression::Div(op)
828 | Expression::Mod(op)
829 | Expression::Eq(op)
830 | Expression::Neq(op)
831 | Expression::Lt(op)
832 | Expression::Lte(op)
833 | Expression::Gt(op)
834 | Expression::Gte(op)
835 | Expression::Match(op)
836 | Expression::BitwiseAnd(op)
837 | Expression::BitwiseOr(op)
838 | Expression::BitwiseXor(op)
839 | Expression::Concat(op)
840 | Expression::Adjacent(op)
841 | Expression::TsMatch(op)
842 | Expression::PropertyEQ(op)
843 | Expression::ArrayContainsAll(op)
844 | Expression::ArrayContainedBy(op)
845 | Expression::ArrayOverlaps(op)
846 | Expression::JSONBContainsAllTopKeys(op)
847 | Expression::JSONBContainsAnyTopKeys(op)
848 | Expression::JSONBDeleteAtPath(op)
849 | Expression::ExtendsLeft(op)
850 | Expression::ExtendsRight(op)
851 | Expression::Is(op)
852 | Expression::MemberOf(op) => {
853 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
854 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
855 }
856 Expression::Like(op) | Expression::ILike(op) => {
857 Self::normalize_frame_incompatible_window_expr(&mut op.left, window_map);
858 Self::normalize_frame_incompatible_window_expr(&mut op.right, window_map);
859 if let Some(escape) = &mut op.escape {
860 Self::normalize_frame_incompatible_window_expr(escape, window_map);
861 }
862 }
863 Expression::Not(op) | Expression::Neg(op) | Expression::BitwiseNot(op) => {
864 Self::normalize_frame_incompatible_window_expr(&mut op.this, window_map);
865 }
866 Expression::In(in_expr) => {
867 Self::normalize_frame_incompatible_window_expr(&mut in_expr.this, window_map);
868 for value in &mut in_expr.expressions {
869 Self::normalize_frame_incompatible_window_expr(value, window_map);
870 }
871 }
872 Expression::Between(between) => {
873 Self::normalize_frame_incompatible_window_expr(&mut between.this, window_map);
874 Self::normalize_frame_incompatible_window_expr(&mut between.low, window_map);
875 Self::normalize_frame_incompatible_window_expr(&mut between.high, window_map);
876 }
877 Expression::IsNull(is_null) => {
878 Self::normalize_frame_incompatible_window_expr(&mut is_null.this, window_map);
879 }
880 Expression::IsTrue(is_true) | Expression::IsFalse(is_true) => {
881 Self::normalize_frame_incompatible_window_expr(&mut is_true.this, window_map);
882 }
883 _ => {}
884 }
885 }
886
887 fn is_tsql_frame_incompatible_window_function(expr: &Expression) -> bool {
888 matches!(
889 expr,
890 Expression::RowNumber(_)
891 | Expression::Rank(_)
892 | Expression::DenseRank(_)
893 | Expression::NTile(_)
894 | Expression::Ntile(_)
895 | Expression::Lead(_)
896 | Expression::Lag(_)
897 | Expression::PercentRank(_)
898 | Expression::CumeDist(_)
899 )
900 }
901
902 fn resolve_named_window_spec(
903 name: &str,
904 window_map: &HashMap<String, Over>,
905 seen: &mut Vec<String>,
906 ) -> Option<Over> {
907 let key = name.to_lowercase();
908 if seen.iter().any(|seen_name| seen_name == &key) {
909 return None;
910 }
911
912 let named_spec = window_map.get(&key)?.clone();
913 seen.push(key);
914
915 let mut resolved = if let Some(base_window) = &named_spec.window_name {
916 Self::resolve_named_window_spec(&base_window.name, window_map, seen)
917 .unwrap_or_else(Self::empty_over)
918 } else {
919 Self::empty_over()
920 };
921
922 if !named_spec.partition_by.is_empty() {
923 resolved.partition_by = named_spec.partition_by;
924 }
925 if !named_spec.order_by.is_empty() {
926 resolved.order_by = named_spec.order_by;
927 }
928 if named_spec.frame.is_some() {
929 resolved.frame = named_spec.frame;
930 }
931
932 Some(resolved)
933 }
934
935 fn empty_over() -> Over {
936 Over {
937 window_name: None,
938 partition_by: Vec::new(),
939 order_by: Vec::new(),
940 frame: None,
941 alias: None,
942 }
943 }
944
945 const LATERAL_WRAPPER_SOURCE_ALIAS: &'static str = "_polyglot_lateral_source";
946 const LATERAL_WRAPPER_OUTPUT_ALIAS: &'static str = "_polyglot_lateral";
947
948 fn transform_lateral_join_to_apply(mut join: Join) -> Result<Join> {
949 let Some(apply_kind) = Self::lateral_apply_kind(&join) else {
950 return Ok(join);
951 };
952
953 let original_alias = Self::table_expression_alias(&join.this);
954 let on = join.on.take();
955 let rhs = Self::remove_lateral_marker(join.this);
956 join.this = if on
957 .as_ref()
958 .is_some_and(|expr| !Self::is_true_condition(expr))
959 {
960 Self::wrap_lateral_apply_rhs(rhs, on.expect("checked as Some"), original_alias)?
961 } else {
962 rhs
963 };
964 join.using.clear();
965 join.kind = apply_kind;
966 join.use_inner_keyword = false;
967 join.use_outer_keyword = false;
968 join.deferred_condition = false;
969 join.join_hint = None;
970 join.match_condition = None;
971 join.directed = false;
972 Ok(join)
973 }
974
975 fn rewrite_comma_lateral_sources_to_joins(select: &mut Select) {
976 let Some(from) = select.from.as_mut() else {
977 return;
978 };
979 if from.expressions.len() < 2
980 || !from
981 .expressions
982 .iter()
983 .skip(1)
984 .any(Self::is_lateral_table_expression)
985 {
986 return;
987 }
988
989 let mut expressions = std::mem::take(&mut from.expressions).into_iter();
990 let Some(first) = expressions.next() else {
991 return;
992 };
993 from.expressions = vec![first];
994
995 let mut joins = expressions
996 .map(|source| {
997 if Self::is_lateral_table_expression(&source) {
998 Self::new_join(Self::remove_lateral_marker(source), JoinKind::CrossApply)
999 } else {
1000 Self::new_join(source, JoinKind::Cross)
1001 }
1002 })
1003 .collect::<Vec<_>>();
1004 joins.append(&mut select.joins);
1005 select.joins = joins;
1006 }
1007
1008 fn new_join(this: Expression, kind: JoinKind) -> Join {
1009 Join {
1010 this,
1011 on: None,
1012 using: Vec::new(),
1013 kind,
1014 use_inner_keyword: false,
1015 use_outer_keyword: false,
1016 deferred_condition: false,
1017 join_hint: None,
1018 match_condition: None,
1019 pivots: Vec::new(),
1020 comments: Vec::new(),
1021 nesting_group: 0,
1022 directed: false,
1023 }
1024 }
1025
1026 fn lateral_apply_kind(join: &Join) -> Option<JoinKind> {
1027 if !join.using.is_empty() {
1028 return None;
1029 }
1030
1031 match join.kind {
1032 JoinKind::Lateral => Some(JoinKind::CrossApply),
1033 JoinKind::LeftLateral => Some(JoinKind::OuterApply),
1034 JoinKind::Cross | JoinKind::Inner | JoinKind::Implicit
1035 if Self::is_lateral_table_expression(&join.this) =>
1036 {
1037 Some(JoinKind::CrossApply)
1038 }
1039 JoinKind::Left if Self::is_lateral_table_expression(&join.this) => {
1040 Some(JoinKind::OuterApply)
1041 }
1042 _ => None,
1043 }
1044 }
1045
1046 fn is_true_condition(expr: &Expression) -> bool {
1047 match expr {
1048 Expression::Boolean(boolean) => boolean.value,
1049 Expression::Literal(lit) => {
1050 matches!(lit.as_ref(), Literal::Number(value) if value.trim() == "1")
1051 }
1052 Expression::Eq(op) => {
1053 Self::is_true_condition(&op.left) && Self::is_true_condition(&op.right)
1054 }
1055 Expression::Paren(paren) => Self::is_true_condition(&paren.this),
1056 _ => false,
1057 }
1058 }
1059
1060 fn table_expression_alias(expr: &Expression) -> Option<(Identifier, Vec<Identifier>)> {
1061 match expr {
1062 Expression::Subquery(subquery) => subquery
1063 .alias
1064 .clone()
1065 .map(|alias| (alias, subquery.column_aliases.clone())),
1066 Expression::Alias(alias) if !alias.alias.is_empty() => {
1067 Some((alias.alias.clone(), alias.column_aliases.clone()))
1068 }
1069 Expression::Lateral(lateral) => lateral.alias.as_ref().map(|alias| {
1070 (
1071 if lateral.alias_quoted {
1072 Identifier::quoted(alias)
1073 } else {
1074 Identifier::new(alias)
1075 },
1076 lateral
1077 .column_aliases
1078 .iter()
1079 .map(|column| Identifier::new(column.clone()))
1080 .collect(),
1081 )
1082 }),
1083 _ => None,
1084 }
1085 }
1086
1087 fn wrap_lateral_apply_rhs(
1088 rhs: Expression,
1089 predicate: Expression,
1090 original_alias: Option<(Identifier, Vec<Identifier>)>,
1091 ) -> Result<Expression> {
1092 let (outer_alias, column_aliases) = original_alias.unwrap_or_else(|| {
1093 (
1094 Identifier::new(Self::LATERAL_WRAPPER_OUTPUT_ALIAS),
1095 Vec::new(),
1096 )
1097 });
1098 let inner_alias = Identifier::new(Self::LATERAL_WRAPPER_SOURCE_ALIAS);
1099 let source =
1100 Self::with_table_expression_alias(rhs, inner_alias.clone(), column_aliases.clone());
1101 let predicate = Self::rewrite_column_qualifier(predicate, &outer_alias, &inner_alias)?;
1102
1103 let mut select = Select::new();
1104 select.expressions = vec![Expression::Star(Star {
1105 table: None,
1106 except: None,
1107 replace: None,
1108 rename: None,
1109 trailing_comments: Vec::new(),
1110 span: None,
1111 })];
1112 select.from = Some(crate::expressions::From {
1113 expressions: vec![source],
1114 });
1115 select.where_clause = Some(Where { this: predicate });
1116
1117 Ok(Expression::Subquery(Box::new(Subquery {
1118 this: Expression::Select(Box::new(select)),
1119 alias: Some(outer_alias),
1120 column_aliases,
1121 alias_explicit_as: true,
1122 alias_keyword: None,
1123 order_by: None,
1124 limit: None,
1125 offset: None,
1126 distribute_by: None,
1127 sort_by: None,
1128 cluster_by: None,
1129 lateral: false,
1130 modifiers_inside: false,
1131 trailing_comments: Vec::new(),
1132 inferred_type: None,
1133 })))
1134 }
1135
1136 fn with_table_expression_alias(
1137 expr: Expression,
1138 alias: Identifier,
1139 column_aliases: Vec<Identifier>,
1140 ) -> Expression {
1141 match expr {
1142 Expression::Subquery(mut subquery) => {
1143 subquery.alias = Some(alias);
1144 subquery.column_aliases = column_aliases;
1145 subquery.alias_explicit_as = true;
1146 subquery.alias_keyword = None;
1147 Expression::Subquery(subquery)
1148 }
1149 Expression::Alias(mut aliased) => {
1150 aliased.alias = alias;
1151 aliased.column_aliases = column_aliases;
1152 aliased.alias_explicit_as = true;
1153 aliased.alias_keyword = None;
1154 Expression::Alias(aliased)
1155 }
1156 Expression::Table(mut table) => {
1157 table.alias = Some(alias);
1158 table.alias_explicit_as = true;
1159 table.column_aliases = column_aliases;
1160 Expression::Table(table)
1161 }
1162 other => Expression::Alias(Box::new(Alias {
1163 this: other,
1164 alias,
1165 column_aliases,
1166 alias_explicit_as: true,
1167 alias_keyword: None,
1168 pre_alias_comments: Vec::new(),
1169 trailing_comments: Vec::new(),
1170 inferred_type: None,
1171 })),
1172 }
1173 }
1174
1175 fn rewrite_column_qualifier(
1176 expr: Expression,
1177 from: &Identifier,
1178 to: &Identifier,
1179 ) -> Result<Expression> {
1180 super::transform_recursive(expr, &|expr| {
1181 Ok(match expr {
1182 Expression::Column(mut column)
1183 if column
1184 .table
1185 .as_ref()
1186 .is_some_and(|table| Self::same_identifier(table, from)) =>
1187 {
1188 column.table = Some(to.clone());
1189 Expression::Column(column)
1190 }
1191 other => other,
1192 })
1193 })
1194 }
1195
1196 fn same_identifier(left: &Identifier, right: &Identifier) -> bool {
1197 if left.quoted || right.quoted {
1198 left.quoted == right.quoted && left.name == right.name
1199 } else {
1200 left.name.eq_ignore_ascii_case(&right.name)
1201 }
1202 }
1203
1204 fn is_lateral_table_expression(expr: &Expression) -> bool {
1205 match expr {
1206 Expression::Subquery(subquery) => subquery.lateral,
1207 Expression::Lateral(_) => true,
1208 Expression::Alias(alias) => Self::is_lateral_table_expression(&alias.this),
1209 _ => false,
1210 }
1211 }
1212
1213 fn remove_lateral_marker(expr: Expression) -> Expression {
1214 match expr {
1215 Expression::Subquery(mut subquery) => {
1216 subquery.lateral = false;
1217 Expression::Subquery(subquery)
1218 }
1219 Expression::Lateral(lateral) => Self::lateral_to_table_expression(*lateral),
1220 Expression::Alias(mut alias) => {
1221 alias.this = Self::remove_lateral_marker(alias.this);
1222 Expression::Alias(alias)
1223 }
1224 other => other,
1225 }
1226 }
1227
1228 fn lateral_to_table_expression(lateral: crate::expressions::Lateral) -> Expression {
1229 let expr = *lateral.this;
1230 let Some(alias) = lateral.alias else {
1231 return expr;
1232 };
1233
1234 Expression::Alias(Box::new(Alias {
1235 this: expr,
1236 alias: if lateral.alias_quoted {
1237 Identifier::quoted(alias)
1238 } else {
1239 Identifier::new(alias)
1240 },
1241 column_aliases: lateral
1242 .column_aliases
1243 .into_iter()
1244 .map(Identifier::new)
1245 .collect(),
1246 alias_explicit_as: true,
1247 alias_keyword: None,
1248 pre_alias_comments: Vec::new(),
1249 trailing_comments: Vec::new(),
1250 inferred_type: None,
1251 }))
1252 }
1253
1254 fn rewrite_tuple_in_subquery_predicates(
1255 expr: Expression,
1256 outer_qualifier: Option<&Identifier>,
1257 under_not: bool,
1258 ) -> Expression {
1259 match expr {
1260 Expression::In(in_expr) if !under_not => {
1261 let in_expr = *in_expr;
1262 Self::tuple_in_subquery_to_exists(&in_expr, outer_qualifier)
1263 .unwrap_or_else(|| Expression::In(Box::new(in_expr)))
1264 }
1265 Expression::And(mut op) => {
1266 op.left =
1267 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1268 op.right = Self::rewrite_tuple_in_subquery_predicates(
1269 op.right,
1270 outer_qualifier,
1271 under_not,
1272 );
1273 Expression::And(op)
1274 }
1275 Expression::Or(mut op) => {
1276 op.left =
1277 Self::rewrite_tuple_in_subquery_predicates(op.left, outer_qualifier, under_not);
1278 op.right = Self::rewrite_tuple_in_subquery_predicates(
1279 op.right,
1280 outer_qualifier,
1281 under_not,
1282 );
1283 Expression::Or(op)
1284 }
1285 Expression::Paren(mut paren) => {
1286 paren.this = Self::rewrite_tuple_in_subquery_predicates(
1287 paren.this,
1288 outer_qualifier,
1289 under_not,
1290 );
1291 Expression::Paren(paren)
1292 }
1293 Expression::Not(mut not) => {
1294 not.this =
1295 Self::rewrite_tuple_in_subquery_predicates(not.this, outer_qualifier, true);
1296 Expression::Not(not)
1297 }
1298 other => other,
1299 }
1300 }
1301
1302 fn tuple_in_subquery_to_exists(
1303 in_expr: &In,
1304 outer_qualifier: Option<&Identifier>,
1305 ) -> Option<Expression> {
1306 if in_expr.not || !in_expr.expressions.is_empty() || in_expr.unnest.is_some() {
1307 return None;
1308 }
1309
1310 let left_expressions = Self::tuple_expressions(&in_expr.this)?;
1311 let mut select = match in_expr.query.as_ref()? {
1312 Expression::Select(select) => (**select).clone(),
1313 _ => return None,
1314 };
1315
1316 if left_expressions.len() != select.expressions.len() || left_expressions.is_empty() {
1317 return None;
1318 }
1319
1320 let inner_qualifier = Self::single_select_source_qualifier(&select);
1321 let mut predicates = Vec::with_capacity(left_expressions.len() + 1);
1322 for (projection, left) in select
1323 .expressions
1324 .iter()
1325 .cloned()
1326 .zip(left_expressions.iter().cloned())
1327 {
1328 let inner = Self::tuple_in_projection_expr(projection, inner_qualifier.as_ref())?;
1329 let outer = Self::qualify_tuple_operand(left, outer_qualifier);
1330 predicates.push(Expression::Eq(Box::new(BinaryOp::new(inner, outer))));
1331 }
1332
1333 if let Some(where_clause) = select.where_clause.take() {
1334 predicates.push(where_clause.this);
1335 }
1336
1337 select.expressions = vec![Expression::number(1)];
1338 select.where_clause = Some(Where {
1339 this: Self::and_all(predicates)?,
1340 });
1341
1342 Some(Expression::Exists(Box::new(Exists {
1343 this: Expression::Select(Box::new(select)),
1344 not: false,
1345 })))
1346 }
1347
1348 fn tuple_expressions(expr: &Expression) -> Option<&[Expression]> {
1349 match expr {
1350 Expression::Tuple(tuple) => Some(&tuple.expressions),
1351 Expression::Paren(paren) => Self::tuple_expressions(&paren.this),
1352 _ => None,
1353 }
1354 }
1355
1356 fn tuple_in_projection_expr(
1357 expr: Expression,
1358 qualifier: Option<&Identifier>,
1359 ) -> Option<Expression> {
1360 match expr {
1361 Expression::Alias(alias) => Self::tuple_in_projection_expr(alias.this, qualifier),
1362 Expression::Column(mut column) => {
1363 if column.table.is_none() {
1364 column.table = qualifier.cloned();
1365 }
1366 Some(Expression::Column(column))
1367 }
1368 Expression::Identifier(identifier) => {
1369 Some(Self::column_from_identifier(identifier, qualifier.cloned()))
1370 }
1371 Expression::Dot(_) => Some(expr),
1372 _ => None,
1373 }
1374 }
1375
1376 fn qualify_tuple_operand(expr: Expression, qualifier: Option<&Identifier>) -> Expression {
1377 match expr {
1378 Expression::Column(mut column) => {
1379 if column.table.is_none() {
1380 column.table = qualifier.cloned();
1381 }
1382 Expression::Column(column)
1383 }
1384 Expression::Identifier(identifier) => {
1385 Self::column_from_identifier(identifier, qualifier.cloned())
1386 }
1387 other => other,
1388 }
1389 }
1390
1391 fn column_from_identifier(identifier: Identifier, table: Option<Identifier>) -> Expression {
1392 Expression::Column(Box::new(Column {
1393 name: identifier,
1394 table,
1395 join_mark: false,
1396 trailing_comments: Vec::new(),
1397 span: None,
1398 inferred_type: None,
1399 }))
1400 }
1401
1402 fn single_select_source_qualifier(select: &Select) -> Option<Identifier> {
1403 if !select.joins.is_empty() {
1404 return None;
1405 }
1406
1407 let from = select.from.as_ref()?;
1408 if from.expressions.len() != 1 {
1409 return None;
1410 }
1411
1412 Self::source_qualifier(&from.expressions[0])
1413 }
1414
1415 fn source_qualifier(source: &Expression) -> Option<Identifier> {
1416 match source {
1417 Expression::Table(table) => table.alias.clone().or_else(|| Some(table.name.clone())),
1418 Expression::Subquery(subquery) => subquery.alias.clone(),
1419 _ => None,
1420 }
1421 }
1422
1423 fn and_all(mut predicates: Vec<Expression>) -> Option<Expression> {
1424 if predicates.is_empty() {
1425 return None;
1426 }
1427
1428 let first = predicates.remove(0);
1429 Some(predicates.into_iter().fold(first, |left, right| {
1430 Expression::And(Box::new(BinaryOp::new(left, right)))
1431 }))
1432 }
1433
1434 pub(super) fn transform_data_type(
1436 &self,
1437 dt: crate::expressions::DataType,
1438 ) -> Result<Expression> {
1439 use crate::expressions::DataType;
1440 let transformed = match dt {
1441 DataType::Boolean => DataType::Custom {
1443 name: "BIT".to_string(),
1444 },
1445 DataType::Int { .. } => dt,
1447 DataType::Decimal { precision, scale } => DataType::Custom {
1450 name: if let (Some(p), Some(s)) = (&precision, &scale) {
1451 format!("NUMERIC({}, {})", p, s)
1452 } else if let Some(p) = &precision {
1453 format!("NUMERIC({})", p)
1454 } else {
1455 "NUMERIC".to_string()
1456 },
1457 },
1458 DataType::Text => DataType::Custom {
1460 name: "VARCHAR(MAX)".to_string(),
1461 },
1462 DataType::Timestamp { .. } => DataType::Custom {
1464 name: "DATETIME2".to_string(),
1465 },
1466 DataType::Uuid => DataType::Custom {
1468 name: "UNIQUEIDENTIFIER".to_string(),
1469 },
1470 DataType::Custom { ref name } => {
1472 let upper = name.trim().to_uppercase();
1473 let (base_name, precision, _scale) = Self::parse_type_precision_and_scale(&upper);
1474 match base_name.as_str() {
1475 "BPCHAR" => {
1477 if let Some(len) = precision {
1478 DataType::Char { length: Some(len) }
1479 } else {
1480 DataType::Char { length: None }
1481 }
1482 }
1483 _ => dt,
1484 }
1485 }
1486 other => other,
1488 };
1489 Ok(Expression::DataType(transformed))
1490 }
1491
1492 pub(super) fn parse_type_precision_and_scale(name: &str) -> (String, Option<u32>, Option<u32>) {
1494 if let Some(paren_pos) = name.find('(') {
1495 let base = name[..paren_pos].to_string();
1496 let rest = &name[paren_pos + 1..];
1497 if let Some(close_pos) = rest.find(')') {
1498 let args = &rest[..close_pos];
1499 let parts: Vec<&str> = args.split(',').map(|s| s.trim()).collect();
1500 let precision = parts.first().and_then(|s| s.parse::<u32>().ok());
1501 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1502 return (base, precision, scale);
1503 }
1504 (base, None, None)
1505 } else {
1506 (name.to_string(), None, None)
1507 }
1508 }
1509
1510 fn transform_logical_aggregate(
1511 condition: Expression,
1512 filter: Option<Expression>,
1513 aggregate_name: &str,
1514 ) -> Result<Expression> {
1515 let false_condition = Expression::Not(Box::new(crate::expressions::UnaryOp {
1516 this: condition.clone(),
1517 inferred_type: None,
1518 }));
1519 let true_condition = Self::apply_aggregate_filter(condition, filter.clone());
1520 let false_condition = Self::apply_aggregate_filter(false_condition, filter);
1521
1522 let case_expr = Expression::Case(Box::new(crate::expressions::Case {
1523 operand: None,
1524 whens: vec![
1525 (true_condition, Expression::number(1)),
1526 (false_condition, Expression::number(0)),
1527 ],
1528 else_: Some(Expression::null()),
1529 comments: Vec::new(),
1530 inferred_type: None,
1531 }));
1532
1533 let case_expr = crate::transforms::ensure_bools(case_expr)?;
1534 let aggregate = Expression::Function(Box::new(Function::new(
1535 aggregate_name.to_string(),
1536 vec![case_expr],
1537 )));
1538
1539 Ok(Expression::Cast(Box::new(Cast {
1540 this: aggregate,
1541 to: DataType::Custom {
1542 name: "BIT".to_string(),
1543 },
1544 trailing_comments: Vec::new(),
1545 double_colon_syntax: false,
1546 format: None,
1547 default: None,
1548 inferred_type: None,
1549 })))
1550 }
1551
1552 fn apply_aggregate_filter(condition: Expression, filter: Option<Expression>) -> Expression {
1553 match filter {
1554 Some(filter) => Expression::And(Box::new(crate::expressions::BinaryOp::new(
1555 filter, condition,
1556 ))),
1557 None => condition,
1558 }
1559 }
1560
1561 fn transform_function(&self, f: Function) -> Result<Expression> {
1562 let name_upper = f.name.to_uppercase();
1563 match name_upper.as_str() {
1564 "COALESCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
1566 "ISNULL".to_string(),
1567 f.args,
1568 )))),
1569
1570 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
1572 "ISNULL".to_string(),
1573 f.args,
1574 )))),
1575
1576 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1578 Function::new("STRING_AGG".to_string(), f.args),
1579 ))),
1580
1581 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
1583
1584 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1586 "STRING_AGG".to_string(),
1587 f.args,
1588 )))),
1589
1590 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1592 "SUBSTRING".to_string(),
1593 f.args,
1594 )))),
1595
1596 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1598 "LEN".to_string(),
1599 f.args,
1600 )))),
1601
1602 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
1604 seed: None,
1605 lower: None,
1606 upper: None,
1607 }))),
1608
1609 "NOW" => Ok(Expression::Function(Box::new(Function::new(
1611 "GETDATE".to_string(),
1612 vec![],
1613 )))),
1614
1615 "CURRENT_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1617 "GETDATE".to_string(),
1618 vec![],
1619 )))),
1620
1621 "CURRENT_DATE" => {
1623 Ok(Expression::Function(Box::new(Function::new(
1625 "CAST".to_string(),
1626 vec![
1627 Expression::Function(Box::new(Function::new(
1628 "GETDATE".to_string(),
1629 vec![],
1630 ))),
1631 Expression::Identifier(crate::expressions::Identifier::new("DATE")),
1632 ],
1633 ))))
1634 }
1635
1636 "TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
1638 "CONVERT".to_string(),
1639 f.args,
1640 )))),
1641
1642 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1644 "CONVERT".to_string(),
1645 f.args,
1646 )))),
1647
1648 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
1650 "FORMAT".to_string(),
1651 f.args,
1652 )))),
1653
1654 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
1656 "FORMAT".to_string(),
1657 f.args,
1658 )))),
1659
1660 "DATE_TRUNC" | "DATETRUNC" => {
1663 let mut args = Self::uppercase_first_arg_if_identifier(f.args);
1664 if args.len() >= 2 {
1666 if let Expression::Literal(lit) = &args[1] {
1667 if let Literal::String(_) = lit.as_ref() {
1668 args[1] = Expression::Cast(Box::new(Cast {
1669 this: args[1].clone(),
1670 to: DataType::Custom {
1671 name: "DATETIME2".to_string(),
1672 },
1673 trailing_comments: Vec::new(),
1674 double_colon_syntax: false,
1675 format: None,
1676 default: None,
1677 inferred_type: None,
1678 }));
1679 }
1680 }
1681 }
1682 Ok(Expression::Function(Box::new(Function::new(
1683 "DATETRUNC".to_string(),
1684 args,
1685 ))))
1686 }
1687
1688 "DATEADD" => {
1690 let args = Self::uppercase_first_arg_if_identifier(f.args);
1691 Ok(Expression::Function(Box::new(Function::new(
1692 "DATEADD".to_string(),
1693 args,
1694 ))))
1695 }
1696
1697 "DATEDIFF" => {
1699 let args = Self::uppercase_first_arg_if_identifier(f.args);
1700 Ok(Expression::Function(Box::new(Function::new(
1701 "DATEDIFF".to_string(),
1702 args,
1703 ))))
1704 }
1705
1706 "EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
1708 "DATEPART".to_string(),
1709 f.args,
1710 )))),
1711
1712 "STRPOS" | "POSITION" if f.args.len() >= 2 => {
1714 Ok(Expression::Function(Box::new(Function::new(
1716 "CHARINDEX".to_string(),
1717 f.args,
1718 ))))
1719 }
1720
1721 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
1723
1724 "CEILING" | "CEIL" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
1726 Function::new("CEILING".to_string(), f.args),
1727 ))),
1728
1729 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
1734 "JSON_VALUE".to_string(),
1735 f.args,
1736 )))),
1737
1738 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
1740 "JSON_VALUE".to_string(),
1741 f.args,
1742 )))),
1743
1744 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
1746
1747 "GET_PATH" if f.args.len() == 2 => {
1749 let mut args = f.args;
1750 let this = args.remove(0);
1751 let path = args.remove(0);
1752 let json_path = match &path {
1753 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
1754 let Literal::String(s) = lit.as_ref() else {
1755 unreachable!()
1756 };
1757 let normalized = if s.starts_with('$') {
1758 s.clone()
1759 } else if s.starts_with('[') {
1760 format!("${}", s)
1761 } else {
1762 format!("$.{}", s)
1763 };
1764 Expression::Literal(Box::new(Literal::String(normalized)))
1765 }
1766 _ => path,
1767 };
1768 let json_query = Expression::Function(Box::new(Function::new(
1770 "JSON_QUERY".to_string(),
1771 vec![this.clone(), json_path.clone()],
1772 )));
1773 let json_value = Expression::Function(Box::new(Function::new(
1774 "JSON_VALUE".to_string(),
1775 vec![this, json_path],
1776 )));
1777 Ok(Expression::Function(Box::new(Function::new(
1778 "ISNULL".to_string(),
1779 vec![json_query, json_value],
1780 ))))
1781 }
1782
1783 "JSON_QUERY" if f.args.len() == 1 => {
1786 let this = f.args.into_iter().next().unwrap();
1787 let path = Expression::Literal(Box::new(Literal::String("$".to_string())));
1788 let json_query = Expression::Function(Box::new(Function::new(
1789 "JSON_QUERY".to_string(),
1790 vec![this.clone(), path.clone()],
1791 )));
1792 let json_value = Expression::Function(Box::new(Function::new(
1793 "JSON_VALUE".to_string(),
1794 vec![this, path],
1795 )));
1796 Ok(Expression::Function(Box::new(Function::new(
1797 "ISNULL".to_string(),
1798 vec![json_query, json_value],
1799 ))))
1800 }
1801
1802 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
1804 "STRING_SPLIT".to_string(),
1805 f.args,
1806 )))),
1807
1808 "REGEXP_LIKE" => {
1811 Ok(Expression::Function(Box::new(Function::new(
1813 "PATINDEX".to_string(),
1814 f.args,
1815 ))))
1816 }
1817
1818 "LN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1820 "LOG".to_string(),
1821 f.args,
1822 )))),
1823
1824 "STDDEV" | "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1829 "STDEV".to_string(),
1830 f.args,
1831 )))),
1832
1833 "STDDEV_POP" => Ok(Expression::Function(Box::new(Function::new(
1835 "STDEVP".to_string(),
1836 f.args,
1837 )))),
1838
1839 "VARIANCE" | "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
1841 "VAR".to_string(),
1842 f.args,
1843 )))),
1844
1845 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
1847 "VARP".to_string(),
1848 f.args,
1849 )))),
1850
1851 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
1853 let mut args = f.args;
1854 Self::transform_logical_aggregate(args.remove(0), None, "MIN")
1855 }
1856 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
1857 let mut args = f.args;
1858 Self::transform_logical_aggregate(args.remove(0), None, "MAX")
1859 }
1860
1861 "DATE_ADD" => {
1863 if f.args.len() == 2 {
1864 let mut args = f.args;
1865 let date = args.remove(0);
1866 let interval = args.remove(0);
1867 let unit = Expression::Identifier(crate::expressions::Identifier {
1868 name: "DAY".to_string(),
1869 quoted: false,
1870 trailing_comments: Vec::new(),
1871 span: None,
1872 });
1873 Ok(Expression::Function(Box::new(Function::new(
1874 "DATEADD".to_string(),
1875 vec![unit, interval, date],
1876 ))))
1877 } else {
1878 let args = Self::uppercase_first_arg_if_identifier(f.args);
1879 Ok(Expression::Function(Box::new(Function::new(
1880 "DATEADD".to_string(),
1881 args,
1882 ))))
1883 }
1884 }
1885
1886 "INSERT" => Ok(Expression::Function(Box::new(Function::new(
1888 "STUFF".to_string(),
1889 f.args,
1890 )))),
1891
1892 "SUSER_NAME" | "SUSER_SNAME" | "SYSTEM_USER" => Ok(Expression::CurrentUser(Box::new(
1894 crate::expressions::CurrentUser { this: None },
1895 ))),
1896
1897 _ => Ok(Expression::Function(Box::new(f))),
1899 }
1900 }
1901
1902 fn transform_aggregate_function(
1903 &self,
1904 f: Box<crate::expressions::AggregateFunction>,
1905 ) -> Result<Expression> {
1906 let name_upper = f.name.to_uppercase();
1907 match name_upper.as_str() {
1908 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1910 Function::new("STRING_AGG".to_string(), f.args),
1911 ))),
1912
1913 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
1915 "STRING_AGG".to_string(),
1916 f.args,
1917 )))),
1918
1919 "ARRAY_AGG" if !f.args.is_empty() => {
1922 Ok(Expression::Function(Box::new(Function::new(
1924 "STRING_AGG".to_string(),
1925 f.args,
1926 ))))
1927 }
1928
1929 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" | "EVERY" if f.args.len() == 1 => {
1931 let mut args = f.args;
1932 Self::transform_logical_aggregate(args.remove(0), f.filter, "MIN")
1933 }
1934 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if f.args.len() == 1 => {
1935 let mut args = f.args;
1936 Self::transform_logical_aggregate(args.remove(0), f.filter, "MAX")
1937 }
1938
1939 _ => Ok(Expression::AggregateFunction(f)),
1941 }
1942 }
1943
1944 fn transform_cte(&self, cte: Cte) -> Result<Expression> {
1948 Ok(Expression::Cte(Box::new(self.transform_cte_inner(cte))))
1949 }
1950
1951 fn transform_cte_inner(&self, mut cte: Cte) -> Cte {
1953 if cte.columns.is_empty() {
1956 cte.this = self.qualify_derived_table_outputs(cte.this);
1957 }
1958 cte
1959 }
1960
1961 fn transform_subquery(&self, mut subquery: Subquery) -> Result<Expression> {
1965 if subquery.alias.is_some() && subquery.column_aliases.is_empty() {
1968 subquery.this = self.qualify_derived_table_outputs(subquery.this);
1969 }
1970 Ok(Expression::Subquery(Box::new(subquery)))
1971 }
1972
1973 fn qualify_derived_table_outputs(&self, expr: Expression) -> Expression {
1977 match expr {
1978 Expression::Select(mut select) => {
1979 let has_from = select.from.is_some();
1982 if !has_from {
1983 select.expressions = select
1984 .expressions
1985 .into_iter()
1986 .map(|e| self.maybe_alias_expression(e))
1987 .collect();
1988 }
1989 Expression::Select(select)
1990 }
1991 Expression::Union(mut u) => {
1993 let left = std::mem::replace(&mut u.left, Expression::Null(Null));
1994 u.left = self.qualify_derived_table_outputs(left);
1995 Expression::Union(u)
1996 }
1997 Expression::Intersect(mut i) => {
1998 let left = std::mem::replace(&mut i.left, Expression::Null(Null));
1999 i.left = self.qualify_derived_table_outputs(left);
2000 Expression::Intersect(i)
2001 }
2002 Expression::Except(mut e) => {
2003 let left = std::mem::replace(&mut e.left, Expression::Null(Null));
2004 e.left = self.qualify_derived_table_outputs(left);
2005 Expression::Except(e)
2006 }
2007 Expression::Subquery(mut s) => {
2009 s.this = self.qualify_derived_table_outputs(s.this);
2010 Expression::Subquery(s)
2011 }
2012 other => other,
2014 }
2015 }
2016
2017 fn maybe_alias_expression(&self, expr: Expression) -> Expression {
2022 match &expr {
2023 Expression::Alias(_) => expr,
2025 Expression::Aliases(_) => expr,
2027 Expression::Star(_) => expr,
2029 _ => {
2034 if let Some(output_name) = self.get_output_name(&expr) {
2035 Expression::Alias(Box::new(Alias {
2036 this: expr,
2037 alias: Identifier {
2038 name: output_name,
2039 quoted: true, trailing_comments: Vec::new(),
2041 span: None,
2042 },
2043 column_aliases: Vec::new(),
2044 alias_explicit_as: false,
2045 alias_keyword: None,
2046 pre_alias_comments: Vec::new(),
2047 trailing_comments: Vec::new(),
2048 inferred_type: None,
2049 }))
2050 } else {
2051 expr
2053 }
2054 }
2055 }
2056 }
2057
2058 fn get_output_name(&self, expr: &Expression) -> Option<String> {
2062 match expr {
2063 Expression::Literal(lit) => match lit.as_ref() {
2065 Literal::Number(n) => Some(n.clone()),
2066 Literal::String(s) => Some(s.clone()),
2067 Literal::HexString(h) => Some(format!("0x{}", h)),
2068 Literal::HexNumber(h) => Some(format!("0x{}", h)),
2069 Literal::BitString(b) => Some(format!("b{}", b)),
2070 Literal::ByteString(b) => Some(format!("b'{}'", b)),
2071 Literal::NationalString(s) => Some(format!("N'{}'", s)),
2072 Literal::Date(d) => Some(d.clone()),
2073 Literal::Time(t) => Some(t.clone()),
2074 Literal::Timestamp(ts) => Some(ts.clone()),
2075 Literal::Datetime(dt) => Some(dt.clone()),
2076 Literal::TripleQuotedString(s, _) => Some(s.clone()),
2077 Literal::EscapeString(s) => Some(s.clone()),
2078 Literal::DollarString(s) => Some(s.clone()),
2079 Literal::RawString(s) => Some(s.clone()),
2080 },
2081 Expression::Column(col) => Some(col.name.name.clone()),
2083 Expression::Identifier(ident) => Some(ident.name.clone()),
2085 Expression::Boolean(b) => Some(if b.value { "1" } else { "0" }.to_string()),
2087 Expression::Null(_) => Some("NULL".to_string()),
2089 Expression::Function(f) => Some(f.name.clone()),
2091 Expression::AggregateFunction(f) => Some(f.name.clone()),
2093 _ => Some(format!("_col_{}", 0)),
2095 }
2096 }
2097
2098 fn uppercase_first_arg_if_identifier(mut args: Vec<Expression>) -> Vec<Expression> {
2100 use crate::expressions::Identifier;
2101 if !args.is_empty() {
2102 match &args[0] {
2103 Expression::Identifier(id) => {
2104 args[0] = Expression::Identifier(Identifier {
2105 name: id.name.to_uppercase(),
2106 quoted: id.quoted,
2107 trailing_comments: id.trailing_comments.clone(),
2108 span: None,
2109 });
2110 }
2111 Expression::Var(v) => {
2112 args[0] = Expression::Identifier(Identifier {
2113 name: v.this.to_uppercase(),
2114 quoted: false,
2115 trailing_comments: Vec::new(),
2116 span: None,
2117 });
2118 }
2119 Expression::Column(col) if col.table.is_none() => {
2120 args[0] = Expression::Identifier(Identifier {
2121 name: col.name.name.to_uppercase(),
2122 quoted: col.name.quoted,
2123 trailing_comments: col.name.trailing_comments.clone(),
2124 span: None,
2125 });
2126 }
2127 _ => {}
2128 }
2129 }
2130 args
2131 }
2132}
2133
2134#[cfg(test)]
2135mod tests {
2136 use super::*;
2137 use crate::dialects::Dialect;
2138
2139 fn transpile_to_tsql(sql: &str) -> String {
2140 let dialect = Dialect::get(DialectType::Generic);
2141 let result = dialect
2142 .transpile(sql, DialectType::TSQL)
2143 .expect("Transpile failed");
2144 result[0].clone()
2145 }
2146
2147 #[test]
2148 fn test_nvl_to_isnull() {
2149 let result = transpile_to_tsql("SELECT NVL(a, b)");
2150 assert!(
2151 result.contains("ISNULL"),
2152 "Expected ISNULL, got: {}",
2153 result
2154 );
2155 }
2156
2157 #[test]
2158 fn test_coalesce_to_isnull() {
2159 let result = transpile_to_tsql("SELECT COALESCE(a, b)");
2160 assert!(
2161 result.contains("ISNULL"),
2162 "Expected ISNULL, got: {}",
2163 result
2164 );
2165 }
2166
2167 #[test]
2168 fn test_basic_select() {
2169 let result = transpile_to_tsql("SELECT a, b FROM users WHERE id = 1");
2170 assert!(result.contains("SELECT"));
2171 assert!(result.contains("FROM users"));
2172 }
2173
2174 #[test]
2175 fn test_length_to_len() {
2176 let result = transpile_to_tsql("SELECT LENGTH(name)");
2177 assert!(result.contains("LEN"), "Expected LEN, got: {}", result);
2178 }
2179
2180 #[test]
2181 fn test_now_to_getdate() {
2182 let result = transpile_to_tsql("SELECT NOW()");
2183 assert!(
2184 result.contains("GETDATE"),
2185 "Expected GETDATE, got: {}",
2186 result
2187 );
2188 }
2189
2190 #[test]
2191 fn test_group_concat_to_string_agg() {
2192 let result = transpile_to_tsql("SELECT GROUP_CONCAT(name)");
2193 assert!(
2194 result.contains("STRING_AGG"),
2195 "Expected STRING_AGG, got: {}",
2196 result
2197 );
2198 }
2199
2200 #[test]
2201 fn test_listagg_to_string_agg() {
2202 let result = transpile_to_tsql("SELECT LISTAGG(name)");
2203 assert!(
2204 result.contains("STRING_AGG"),
2205 "Expected STRING_AGG, got: {}",
2206 result
2207 );
2208 }
2209
2210 #[test]
2211 fn test_ln_to_log() {
2212 let result = transpile_to_tsql("SELECT LN(x)");
2213 assert!(result.contains("LOG"), "Expected LOG, got: {}", result);
2214 }
2215
2216 #[test]
2217 fn test_stddev_to_stdev() {
2218 let result = transpile_to_tsql("SELECT STDDEV(x)");
2219 assert!(result.contains("STDEV"), "Expected STDEV, got: {}", result);
2220 }
2221
2222 #[test]
2223 fn test_bracket_identifiers() {
2224 let dialect = Dialect::get(DialectType::TSQL);
2226 let config = dialect.generator_config();
2227 assert_eq!(config.identifier_quote, '[');
2228 }
2229
2230 #[test]
2231 fn test_json_query_isnull_wrapper_simple() {
2232 let dialect = Dialect::get(DialectType::TSQL);
2234 let result = dialect
2235 .transpile(r#"JSON_QUERY(x, '$')"#, DialectType::TSQL)
2236 .expect("transpile failed");
2237 assert!(
2238 result[0].contains("ISNULL"),
2239 "JSON_QUERY should be wrapped with ISNULL: {}",
2240 result[0]
2241 );
2242 }
2243
2244 #[test]
2245 fn test_json_query_isnull_wrapper_nested() {
2246 let dialect = Dialect::get(DialectType::TSQL);
2247 let result = dialect
2248 .transpile(
2249 r#"JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'))"#,
2250 DialectType::TSQL,
2251 )
2252 .expect("transpile failed");
2253 let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
2254 assert_eq!(
2255 result[0], expected,
2256 "JSON_QUERY should be wrapped with ISNULL"
2257 );
2258 }
2259}