1use super::{DialectImpl, DialectType};
13use crate::error::Result;
14use crate::expressions::{
15 AggFunc, BinaryOp, Cast, CeilFunc, DataType, Expression, Function, IntervalUnit, ListAggFunc,
16 Literal, UnaryFunc, VarArgFunc,
17};
18use crate::generator::GeneratorConfig;
19use crate::tokens::TokenizerConfig;
20
21fn interval_unit_to_str(unit: &IntervalUnit) -> String {
23 match unit {
24 IntervalUnit::Year => "YEAR".to_string(),
25 IntervalUnit::Quarter => "QUARTER".to_string(),
26 IntervalUnit::Month => "MONTH".to_string(),
27 IntervalUnit::Week => "WEEK".to_string(),
28 IntervalUnit::Day => "DAY".to_string(),
29 IntervalUnit::Hour => "HOUR".to_string(),
30 IntervalUnit::Minute => "MINUTE".to_string(),
31 IntervalUnit::Second => "SECOND".to_string(),
32 IntervalUnit::Millisecond => "MILLISECOND".to_string(),
33 IntervalUnit::Microsecond => "MICROSECOND".to_string(),
34 IntervalUnit::Nanosecond => "NANOSECOND".to_string(),
35 }
36}
37
38pub struct SnowflakeDialect;
40
41impl DialectImpl for SnowflakeDialect {
42 fn dialect_type(&self) -> DialectType {
43 DialectType::Snowflake
44 }
45
46 fn tokenizer_config(&self) -> TokenizerConfig {
47 let mut config = TokenizerConfig::default();
48 config.identifiers.insert('"', '"');
50 config.quotes.insert("$$".to_string(), "$$".to_string());
52 config.nested_comments = false;
54 config.comments.insert("//".to_string(), None);
56 config
57 }
58
59 fn generator_config(&self) -> GeneratorConfig {
60 use crate::generator::IdentifierQuoteStyle;
61 GeneratorConfig {
62 identifier_quote: '"',
63 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
64 dialect: Some(DialectType::Snowflake),
65 parameter_token: "$",
67 matched_by_source: false,
68 single_string_interval: true,
69 join_hints: false,
70 table_hints: false,
71 query_hints: false,
72 aggregate_filter_supported: false,
73 supports_table_copy: false,
74 collate_is_func: true,
75 limit_only_literals: true,
76 json_key_value_pair_sep: ",",
77 insert_overwrite: " OVERWRITE INTO",
78 struct_delimiter: ("(", ")"),
79 copy_params_are_wrapped: false,
80 copy_params_eq_required: true,
81 star_except: "EXCLUDE",
82 supports_exploding_projections: false,
83 array_concat_is_var_len: false,
84 supports_convert_timezone: true,
85 except_intersect_support_all_clause: false,
86 supports_median: true,
87 array_size_name: "ARRAY_SIZE",
88 supports_decode_case: true,
89 is_bool_allowed: false,
90 try_supported: true,
92 nvl2_supported: true,
94 unnest_with_ordinality: false,
96 quantified_no_paren_space: false,
98 array_bracket_only: true,
100 ..Default::default()
101 }
102 }
103
104 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
105 match expr {
106 Expression::DataType(dt) => self.transform_data_type(dt),
108
109 Expression::In(in_expr) if in_expr.not && in_expr.query.is_some() => {
113 let inner = in_expr.query.unwrap();
115 let subquery = Expression::Subquery(Box::new(crate::expressions::Subquery {
117 this: inner,
118 alias: None,
119 column_aliases: Vec::new(),
120 order_by: None,
121 limit: None,
122 offset: None,
123 distribute_by: None,
124 sort_by: None,
125 cluster_by: None,
126 lateral: false,
127 modifiers_inside: false,
128 trailing_comments: Vec::new(),
129 inferred_type: None,
130 }));
131 Ok(Expression::All(Box::new(
132 crate::expressions::QuantifiedExpr {
133 this: in_expr.this,
134 subquery,
135 op: Some(crate::expressions::QuantifiedOp::Neq),
136 },
137 )))
138 }
139
140 Expression::In(in_expr) if in_expr.not => {
142 let in_without_not = crate::expressions::In {
144 this: in_expr.this,
145 expressions: in_expr.expressions,
146 query: in_expr.query,
147 not: false,
148 global: in_expr.global,
149 unnest: in_expr.unnest,
150 is_field: in_expr.is_field,
151 };
152 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
153 this: Expression::In(Box::new(in_without_not)),
154 inferred_type: None,
155 })))
156 }
157
158 Expression::Interval(interval) => self.transform_interval(*interval),
161
162 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
165 original_name: None,
166 expressions: vec![f.this, f.expression],
167 inferred_type: None,
168 }))),
169
170 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
172 original_name: None,
173 expressions: vec![f.this, f.expression],
174 inferred_type: None,
175 }))),
176
177 Expression::Coalesce(mut f) => {
179 f.original_name = None;
180 Ok(Expression::Coalesce(f))
181 }
182
183 Expression::GroupConcat(f) => Ok(Expression::ListAgg(Box::new(ListAggFunc {
185 this: f.this,
186 separator: f.separator,
187 on_overflow: None,
188 order_by: f.order_by,
189 distinct: f.distinct,
190 filter: f.filter,
191 inferred_type: None,
192 }))),
193
194 Expression::Cast(c) => {
198 use crate::expressions::DataType;
199 let transformed_this = self.transform_expr(c.this)?;
201 match &c.to {
202 DataType::Geography { .. } => Ok(Expression::Function(Box::new(
203 Function::new("TO_GEOGRAPHY".to_string(), vec![transformed_this]),
204 ))),
205 DataType::Geometry { .. } => Ok(Expression::Function(Box::new(Function::new(
206 "TO_GEOMETRY".to_string(),
207 vec![transformed_this],
208 )))),
209 _ => {
210 let transformed_dt = match self.transform_data_type(c.to.clone())? {
212 Expression::DataType(dt) => dt,
213 _ => c.to.clone(),
214 };
215 Ok(Expression::Cast(Box::new(Cast {
216 this: transformed_this,
217 to: transformed_dt,
218 double_colon_syntax: false, trailing_comments: c.trailing_comments,
220 format: c.format,
221 default: c.default,
222 inferred_type: None,
223 })))
224 }
225 }
226 }
227
228 Expression::TryCast(c) => {
231 let transformed_this = self.transform_expr(c.this)?;
232 Ok(Expression::TryCast(Box::new(Cast {
233 this: transformed_this,
234 to: c.to,
235 double_colon_syntax: false, trailing_comments: c.trailing_comments,
237 format: c.format,
238 default: c.default,
239 inferred_type: None,
240 })))
241 }
242
243 Expression::SafeCast(c) => {
246 let to = match c.to {
247 DataType::Timestamp { .. } => DataType::Custom {
248 name: "TIMESTAMPTZ".to_string(),
249 },
250 DataType::Custom { name } if name.eq_ignore_ascii_case("TIMESTAMP") => {
251 DataType::Custom {
252 name: "TIMESTAMPTZ".to_string(),
253 }
254 }
255 other => other,
256 };
257 let transformed_this = self.transform_expr(c.this)?;
258 Ok(Expression::Cast(Box::new(Cast {
259 this: transformed_this,
260 to,
261 double_colon_syntax: c.double_colon_syntax,
262 trailing_comments: c.trailing_comments,
263 format: c.format,
264 default: c.default,
265 inferred_type: None,
266 })))
267 }
268
269 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Timestamp(_)) => {
272 let Literal::Timestamp(s) = lit.as_ref() else {
273 unreachable!()
274 };
275 Ok(Expression::Cast(Box::new(Cast {
276 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
277 to: DataType::Timestamp {
278 precision: None,
279 timezone: false,
280 },
281 double_colon_syntax: false,
282 trailing_comments: Vec::new(),
283 format: None,
284 default: None,
285 inferred_type: None,
286 })))
287 }
288
289 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Date(_)) => {
291 let Literal::Date(s) = lit.as_ref() else {
292 unreachable!()
293 };
294 Ok(Expression::Cast(Box::new(Cast {
295 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
296 to: DataType::Date,
297 double_colon_syntax: false,
298 trailing_comments: Vec::new(),
299 format: None,
300 default: None,
301 inferred_type: None,
302 })))
303 }
304
305 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Time(_)) => {
307 let Literal::Time(s) = lit.as_ref() else {
308 unreachable!()
309 };
310 Ok(Expression::Cast(Box::new(Cast {
311 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
312 to: DataType::Time {
313 precision: None,
314 timezone: false,
315 },
316 double_colon_syntax: false,
317 trailing_comments: Vec::new(),
318 format: None,
319 default: None,
320 inferred_type: None,
321 })))
322 }
323
324 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Datetime(_)) => {
326 let Literal::Datetime(s) = lit.as_ref() else {
327 unreachable!()
328 };
329 Ok(Expression::Cast(Box::new(Cast {
330 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
331 to: DataType::Custom {
332 name: "DATETIME".to_string(),
333 },
334 double_colon_syntax: false,
335 trailing_comments: Vec::new(),
336 format: None,
337 default: None,
338 inferred_type: None,
339 })))
340 }
341
342 Expression::ILike(op) => Ok(Expression::ILike(op)),
345
346 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
349 "FLATTEN".to_string(),
350 vec![f.this],
351 )))),
352
353 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
355 "FLATTEN".to_string(),
356 vec![f.this],
357 )))),
358
359 Expression::Unnest(f) => {
361 let input_arg =
363 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
364 name: crate::expressions::Identifier::new("INPUT"),
365 value: f.this,
366 separator: crate::expressions::NamedArgSeparator::DArrow,
367 }));
368
369 let flatten = Expression::Function(Box::new(Function::new(
371 "FLATTEN".to_string(),
372 vec![input_arg],
373 )));
374
375 let table_func =
377 Expression::TableFromRows(Box::new(crate::expressions::TableFromRows {
378 this: Box::new(flatten),
379 alias: None,
380 joins: vec![],
381 pivots: None,
382 sample: None,
383 }));
384
385 Ok(Expression::Alias(Box::new(crate::expressions::Alias {
387 this: table_func,
388 alias: crate::expressions::Identifier::new("_t0"),
389 column_aliases: vec![
390 crate::expressions::Identifier::new("seq"),
391 crate::expressions::Identifier::new("key"),
392 crate::expressions::Identifier::new("path"),
393 crate::expressions::Identifier::new("index"),
394 crate::expressions::Identifier::new("value"),
395 crate::expressions::Identifier::new("this"),
396 ],
397 pre_alias_comments: vec![],
398 trailing_comments: vec![],
399 inferred_type: None,
400 })))
401 }
402
403 Expression::ArrayFunc(arr) => {
407 if arr.bracket_notation {
408 Ok(Expression::ArrayFunc(arr))
410 } else {
411 Ok(Expression::Function(Box::new(Function::new(
413 "ARRAY_CONSTRUCT".to_string(),
414 arr.expressions,
415 ))))
416 }
417 }
418
419 Expression::ArrayConcat(f) => Ok(Expression::Function(Box::new(Function::new(
421 "ARRAY_CAT".to_string(),
422 f.expressions,
423 )))),
424
425 Expression::ArrayConcatAgg(f) => Ok(Expression::Function(Box::new(Function::new(
427 "ARRAY_FLATTEN".to_string(),
428 vec![f.this],
429 )))),
430
431 Expression::ArrayContains(f) => Ok(Expression::Function(Box::new(Function::new(
433 "ARRAY_CONTAINS".to_string(),
434 vec![f.this, f.expression],
435 )))),
436
437 Expression::ArrayIntersect(f) => Ok(Expression::Function(Box::new(Function::new(
439 "ARRAY_INTERSECTION".to_string(),
440 f.expressions,
441 )))),
442
443 Expression::ArraySort(f) => Ok(Expression::Function(Box::new(Function::new(
445 "ARRAY_SORT".to_string(),
446 vec![f.this],
447 )))),
448
449 Expression::StringToArray(f) => {
451 let mut args = vec![*f.this];
452 if let Some(expr) = f.expression {
453 args.push(*expr);
454 }
455 Ok(Expression::Function(Box::new(Function::new(
456 "STRTOK_TO_ARRAY".to_string(),
457 args,
458 ))))
459 }
460
461 Expression::BitwiseOr(f) => Ok(Expression::Function(Box::new(Function::new(
464 "BITOR".to_string(),
465 vec![f.left, f.right],
466 )))),
467
468 Expression::BitwiseXor(f) => Ok(Expression::Function(Box::new(Function::new(
470 "BITXOR".to_string(),
471 vec![f.left, f.right],
472 )))),
473
474 Expression::BitwiseAnd(f) => Ok(Expression::Function(Box::new(Function::new(
476 "BITAND".to_string(),
477 vec![f.left, f.right],
478 )))),
479
480 Expression::BitwiseNot(f) => Ok(Expression::Function(Box::new(Function::new(
482 "BITNOT".to_string(),
483 vec![f.this],
484 )))),
485
486 Expression::BitwiseLeftShift(f) => Ok(Expression::Function(Box::new(Function::new(
488 "BITSHIFTLEFT".to_string(),
489 vec![f.left, f.right],
490 )))),
491
492 Expression::BitwiseRightShift(f) => Ok(Expression::Function(Box::new(Function::new(
494 "BITSHIFTRIGHT".to_string(),
495 vec![f.left, f.right],
496 )))),
497
498 Expression::BitwiseAndAgg(f) => Ok(Expression::Function(Box::new(Function::new(
500 "BITAND_AGG".to_string(),
501 vec![f.this],
502 )))),
503
504 Expression::BitwiseOrAgg(f) => Ok(Expression::Function(Box::new(Function::new(
506 "BITOR_AGG".to_string(),
507 vec![f.this],
508 )))),
509
510 Expression::BitwiseXorAgg(f) => Ok(Expression::Function(Box::new(Function::new(
512 "BITXOR_AGG".to_string(),
513 vec![f.this],
514 )))),
515
516 Expression::LogicalAnd(f) => Ok(Expression::Function(Box::new(Function::new(
519 "BOOLAND_AGG".to_string(),
520 vec![f.this],
521 )))),
522
523 Expression::LogicalOr(f) => Ok(Expression::Function(Box::new(Function::new(
525 "BOOLOR_AGG".to_string(),
526 vec![f.this],
527 )))),
528
529 Expression::Booland(f) => Ok(Expression::Function(Box::new(Function::new(
531 "BOOLAND".to_string(),
532 vec![*f.this, *f.expression],
533 )))),
534
535 Expression::Boolor(f) => Ok(Expression::Function(Box::new(Function::new(
537 "BOOLOR".to_string(),
538 vec![*f.this, *f.expression],
539 )))),
540
541 Expression::Xor(f) => {
543 let mut args = Vec::new();
544 if let Some(this) = f.this {
545 args.push(*this);
546 }
547 if let Some(expr) = f.expression {
548 args.push(*expr);
549 }
550 Ok(Expression::Function(Box::new(Function::new(
551 "BOOLXOR".to_string(),
552 args,
553 ))))
554 }
555
556 Expression::DayOfMonth(f) => Ok(Expression::Function(Box::new(Function::new(
559 "DAYOFMONTH".to_string(),
560 vec![f.this],
561 )))),
562
563 Expression::DayOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
565 "DAYOFWEEK".to_string(),
566 vec![f.this],
567 )))),
568
569 Expression::DayOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
571 "DAYOFWEEKISO".to_string(),
572 vec![f.this],
573 )))),
574
575 Expression::DayOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
577 "DAYOFYEAR".to_string(),
578 vec![f.this],
579 )))),
580
581 Expression::WeekOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
583 "WEEK".to_string(),
584 vec![f.this],
585 )))),
586
587 Expression::YearOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
589 "YEAROFWEEK".to_string(),
590 vec![f.this],
591 )))),
592
593 Expression::YearOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
595 "YEAROFWEEKISO".to_string(),
596 vec![f.this],
597 )))),
598
599 Expression::ByteLength(f) => Ok(Expression::Function(Box::new(Function::new(
601 "OCTET_LENGTH".to_string(),
602 vec![f.this],
603 )))),
604
605 Expression::TimestampDiff(f) => {
607 let mut args = vec![];
608 if let Some(ref unit_str) = f.unit {
610 args.push(Expression::Identifier(crate::expressions::Identifier::new(
611 unit_str.clone(),
612 )));
613 args.push(*f.this);
614 args.push(*f.expression);
615 } else {
616 args.push(*f.this);
617 args.push(*f.expression);
618 }
619 Ok(Expression::Function(Box::new(Function::new(
620 "TIMESTAMPDIFF".to_string(),
621 args,
622 ))))
623 }
624
625 Expression::TimestampAdd(f) => {
627 let mut args = vec![];
628 if let Some(ref unit_str) = f.unit {
629 args.push(Expression::Identifier(crate::expressions::Identifier::new(
630 unit_str.clone(),
631 )));
632 args.push(*f.this);
633 args.push(*f.expression);
634 } else {
635 args.push(*f.this);
636 args.push(*f.expression);
637 }
638 Ok(Expression::Function(Box::new(Function::new(
639 "TIMESTAMPADD".to_string(),
640 args,
641 ))))
642 }
643
644 Expression::ToArray(f) => Ok(Expression::Function(Box::new(Function::new(
646 "TO_ARRAY".to_string(),
647 vec![f.this],
648 )))),
649
650 Expression::DateAdd(f) => {
652 let unit_str = interval_unit_to_str(&f.unit);
653 let unit = Expression::Identifier(crate::expressions::Identifier {
654 name: unit_str,
655 quoted: false,
656 trailing_comments: Vec::new(),
657 span: None,
658 });
659 Ok(Expression::Function(Box::new(Function::new(
660 "DATEADD".to_string(),
661 vec![unit, f.interval, f.this],
662 ))))
663 }
664
665 Expression::DateSub(f) => {
667 let unit_str = interval_unit_to_str(&f.unit);
668 let unit = Expression::Identifier(crate::expressions::Identifier {
669 name: unit_str,
670 quoted: false,
671 trailing_comments: Vec::new(),
672 span: None,
673 });
674 let neg_expr = Expression::Mul(Box::new(crate::expressions::BinaryOp::new(
676 f.interval,
677 Expression::Neg(Box::new(crate::expressions::UnaryOp {
678 this: Expression::number(1),
679 inferred_type: None,
680 })),
681 )));
682 Ok(Expression::Function(Box::new(Function::new(
683 "DATEADD".to_string(),
684 vec![unit, neg_expr, f.this],
685 ))))
686 }
687
688 Expression::DateDiff(f) => {
690 let unit_str =
691 interval_unit_to_str(&f.unit.unwrap_or(crate::expressions::IntervalUnit::Day));
692 let unit = Expression::Identifier(crate::expressions::Identifier {
693 name: unit_str,
694 quoted: false,
695 trailing_comments: Vec::new(),
696 span: None,
697 });
698 Ok(Expression::Function(Box::new(Function::new(
699 "DATEDIFF".to_string(),
700 vec![unit, f.expression, f.this],
701 ))))
702 }
703
704 Expression::StringAgg(f) => {
707 let mut args = vec![f.this.clone()];
708 if let Some(separator) = &f.separator {
709 args.push(separator.clone());
710 }
711 Ok(Expression::Function(Box::new(Function::new(
712 "LISTAGG".to_string(),
713 args,
714 ))))
715 }
716
717 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
719 "STARTSWITH".to_string(),
720 vec![f.this, f.expression],
721 )))),
722
723 Expression::EndsWith(f) => Ok(Expression::EndsWith(f)),
725
726 Expression::Stuff(f) => {
728 let mut args = vec![*f.this];
729 if let Some(start) = f.start {
730 args.push(*start);
731 }
732 if let Some(length) = f.length {
733 args.push(Expression::number(length));
734 }
735 args.push(*f.expression);
736 Ok(Expression::Function(Box::new(Function::new(
737 "INSERT".to_string(),
738 args,
739 ))))
740 }
741
742 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
745 "SHA1".to_string(),
746 vec![f.this],
747 )))),
748
749 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
751 "SHA1_BINARY".to_string(),
752 vec![f.this],
753 )))),
754
755 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
757 "SHA2_BINARY".to_string(),
758 vec![*f.this],
759 )))),
760
761 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
763 "MD5_BINARY".to_string(),
764 vec![*f.this],
765 )))),
766
767 Expression::MD5NumberLower64(f) => Ok(Expression::Function(Box::new(Function::new(
769 "MD5_NUMBER_LOWER64".to_string(),
770 vec![f.this],
771 )))),
772
773 Expression::MD5NumberUpper64(f) => Ok(Expression::Function(Box::new(Function::new(
775 "MD5_NUMBER_UPPER64".to_string(),
776 vec![f.this],
777 )))),
778
779 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
782 "VECTOR_COSINE_SIMILARITY".to_string(),
783 vec![*f.this, *f.expression],
784 )))),
785
786 Expression::DotProduct(f) => Ok(Expression::Function(Box::new(Function::new(
788 "VECTOR_INNER_PRODUCT".to_string(),
789 vec![*f.this, *f.expression],
790 )))),
791
792 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
794 "VECTOR_L2_DISTANCE".to_string(),
795 vec![*f.this, *f.expression],
796 )))),
797
798 Expression::ManhattanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
800 "VECTOR_L1_DISTANCE".to_string(),
801 vec![*f.this, *f.expression],
802 )))),
803
804 Expression::JSONFormat(f) => {
807 let mut args = Vec::new();
808 if let Some(this) = f.this {
809 args.push(*this);
810 }
811 Ok(Expression::Function(Box::new(Function::new(
812 "TO_JSON".to_string(),
813 args,
814 ))))
815 }
816
817 Expression::JSONKeys(f) => Ok(Expression::Function(Box::new(Function::new(
819 "OBJECT_KEYS".to_string(),
820 vec![*f.this],
821 )))),
822
823 Expression::GetExtract(f) => Ok(Expression::Function(Box::new(Function::new(
825 "GET".to_string(),
826 vec![*f.this, *f.expression],
827 )))),
828
829 Expression::StarMap(f) => Ok(Expression::Function(Box::new(Function::new(
831 "OBJECT_CONSTRUCT".to_string(),
832 vec![f.this, f.expression],
833 )))),
834
835 Expression::LowerHex(f) => Ok(Expression::Function(Box::new(Function::new(
837 "TO_CHAR".to_string(),
838 vec![f.this],
839 )))),
840
841 Expression::Skewness(f) => Ok(Expression::Function(Box::new(Function::new(
843 "SKEW".to_string(),
844 vec![f.this],
845 )))),
846
847 Expression::StPoint(f) => Ok(Expression::Function(Box::new(Function::new(
849 "ST_MAKEPOINT".to_string(),
850 vec![*f.this, *f.expression],
851 )))),
852
853 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
855 "CONVERT_TIMEZONE".to_string(),
856 vec![*f.this],
857 )))),
858
859 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
862 "HEX_DECODE_BINARY".to_string(),
863 vec![*f.this],
864 )))),
865
866 Expression::UnixToTime(f) => {
868 let mut args = vec![*f.this];
869 if let Some(scale) = f.scale {
870 args.push(Expression::number(scale));
871 }
872 Ok(Expression::Function(Box::new(Function::new(
873 "TO_TIMESTAMP".to_string(),
874 args,
875 ))))
876 }
877
878 Expression::IfFunc(f) => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
881 condition: f.condition,
882 true_value: f.true_value,
883 false_value: Some(
884 f.false_value
885 .unwrap_or(Expression::Null(crate::expressions::Null)),
886 ),
887 original_name: Some("IFF".to_string()),
888 inferred_type: None,
889 }))),
890
891 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
894 "APPROX_COUNT_DISTINCT".to_string(),
895 vec![f.this],
896 )))),
897
898 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
900 "MAX_BY".to_string(),
901 vec![*f.this, *f.expression],
902 )))),
903
904 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
906 "MIN_BY".to_string(),
907 vec![*f.this, *f.expression],
908 )))),
909
910 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
913
914 Expression::Rand(r) => Ok(Expression::Rand(r)),
916
917 Expression::Uuid(u) => Ok(Expression::Uuid(u)),
920
921 Expression::Map(f) => Ok(Expression::Function(Box::new(Function::new(
924 "OBJECT_CONSTRUCT".to_string(),
925 f.keys
926 .into_iter()
927 .zip(f.values.into_iter())
928 .flat_map(|(k, v)| vec![k, v])
929 .collect(),
930 )))),
931
932 Expression::MapFunc(f) => Ok(Expression::Function(Box::new(Function::new(
934 "OBJECT_CONSTRUCT".to_string(),
935 f.keys
936 .into_iter()
937 .zip(f.values.into_iter())
938 .flat_map(|(k, v)| vec![k, v])
939 .collect(),
940 )))),
941
942 Expression::VarMap(f) => Ok(Expression::Function(Box::new(Function::new(
944 "OBJECT_CONSTRUCT".to_string(),
945 f.keys
946 .into_iter()
947 .zip(f.values.into_iter())
948 .flat_map(|(k, v)| vec![k, v])
949 .collect(),
950 )))),
951
952 Expression::JsonObject(f) => Ok(Expression::Function(Box::new(Function::new(
955 "OBJECT_CONSTRUCT_KEEP_NULL".to_string(),
956 f.pairs.into_iter().flat_map(|(k, v)| vec![k, v]).collect(),
957 )))),
958
959 Expression::JsonExtractScalar(f) => Ok(Expression::Function(Box::new(Function::new(
961 "JSON_EXTRACT_PATH_TEXT".to_string(),
962 vec![f.this, f.path],
963 )))),
964
965 Expression::Struct(f) => Ok(Expression::Function(Box::new(Function::new(
968 "OBJECT_CONSTRUCT".to_string(),
969 f.fields
970 .into_iter()
971 .flat_map(|(name, expr)| {
972 let key = match name {
973 Some(n) => Expression::string(n),
974 None => Expression::Null(crate::expressions::Null),
975 };
976 vec![key, expr]
977 })
978 .collect(),
979 )))),
980
981 Expression::JSONPathRoot(_) => Ok(Expression::Literal(Box::new(
984 crate::expressions::Literal::String(String::new()),
985 ))),
986
987 Expression::VarSamp(agg) => Ok(Expression::Variance(agg)),
990
991 Expression::VarPop(agg) => Ok(Expression::VarPop(agg)),
994
995 Expression::Extract(f) => {
998 use crate::expressions::DateTimeField;
999 let transformed_this = self.transform_expr(f.this)?;
1001 let field_name = match &f.field {
1002 DateTimeField::Year => "YEAR",
1003 DateTimeField::Month => "MONTH",
1004 DateTimeField::Day => "DAY",
1005 DateTimeField::Hour => "HOUR",
1006 DateTimeField::Minute => "MINUTE",
1007 DateTimeField::Second => "SECOND",
1008 DateTimeField::Millisecond => "MILLISECOND",
1009 DateTimeField::Microsecond => "MICROSECOND",
1010 DateTimeField::Week => "WEEK",
1011 DateTimeField::WeekWithModifier(m) => {
1012 return Ok(Expression::Function(Box::new(Function::new(
1013 "DATE_PART".to_string(),
1014 vec![
1015 Expression::Identifier(crate::expressions::Identifier {
1016 name: format!("WEEK({})", m),
1017 quoted: false,
1018 trailing_comments: Vec::new(),
1019 span: None,
1020 }),
1021 transformed_this,
1022 ],
1023 ))))
1024 }
1025 DateTimeField::DayOfWeek => "DAYOFWEEK",
1026 DateTimeField::DayOfYear => "DAYOFYEAR",
1027 DateTimeField::Quarter => "QUARTER",
1028 DateTimeField::Epoch => "EPOCH",
1029 DateTimeField::Timezone => "TIMEZONE",
1030 DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
1031 DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
1032 DateTimeField::Date => "DATE",
1033 DateTimeField::Time => "TIME",
1034 DateTimeField::Custom(s) => {
1035 match s.to_uppercase().as_str() {
1037 "DAYOFMONTH" => "DAY",
1038 "DOW" => "DAYOFWEEK",
1039 "DOY" => "DAYOFYEAR",
1040 "ISODOW" => "DAYOFWEEKISO",
1041 "EPOCH_SECOND" | "EPOCH_SECONDS" => "EPOCH_SECOND",
1042 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => "EPOCH_MILLISECOND",
1043 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => "EPOCH_MICROSECOND",
1044 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => "EPOCH_NANOSECOND",
1045 _ => {
1046 return {
1047 let field_ident =
1048 Expression::Identifier(crate::expressions::Identifier {
1049 name: s.to_string(),
1050 quoted: false,
1051 trailing_comments: Vec::new(),
1052 span: None,
1053 });
1054 Ok(Expression::Function(Box::new(Function::new(
1055 "DATE_PART".to_string(),
1056 vec![field_ident, transformed_this],
1057 ))))
1058 }
1059 }
1060 }
1061 }
1062 };
1063 let field_ident = Expression::Identifier(crate::expressions::Identifier {
1064 name: field_name.to_string(),
1065 quoted: false,
1066 trailing_comments: Vec::new(),
1067 span: None,
1068 });
1069 Ok(Expression::Function(Box::new(Function::new(
1070 "DATE_PART".to_string(),
1071 vec![field_ident, transformed_this],
1072 ))))
1073 }
1074
1075 Expression::Function(f) => self.transform_function(*f),
1077
1078 Expression::Sum(mut agg) => {
1080 agg.this = self.transform_expr(agg.this)?;
1081 Ok(Expression::Sum(agg))
1082 }
1083
1084 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
1086
1087 Expression::NamedArgument(na) => {
1089 let transformed_value = self.transform_expr(na.value)?;
1090 Ok(Expression::NamedArgument(Box::new(
1091 crate::expressions::NamedArgument {
1092 name: na.name,
1093 value: transformed_value,
1094 separator: na.separator,
1095 },
1096 )))
1097 }
1098
1099 Expression::CreateTable(mut ct) => {
1101 for col in &mut ct.columns {
1102 if let Expression::DataType(new_dt) =
1103 self.transform_data_type(col.data_type.clone())?
1104 {
1105 col.data_type = new_dt;
1106 }
1107 if let Some(default_expr) = col.default.take() {
1109 col.default = Some(self.transform_expr(default_expr)?);
1110 }
1111 for constraint in &mut col.constraints {
1113 if let crate::expressions::ColumnConstraint::ComputedColumn(cc) = constraint
1114 {
1115 let transformed = self.transform_expr(*cc.expression.clone())?;
1116 cc.expression = Box::new(transformed);
1117 }
1118 }
1119 }
1120
1121 if ct.table_modifier.as_deref() == Some("EXTERNAL")
1124 && !ct.with_properties.is_empty()
1125 {
1126 for (key, value) in ct.with_properties.drain(..) {
1127 let formatted = Self::format_external_table_property(&key, &value);
1128 ct.properties
1129 .push(Expression::Raw(crate::expressions::Raw { sql: formatted }));
1130 }
1131 }
1132
1133 Ok(Expression::CreateTable(ct))
1134 }
1135
1136 Expression::AlterTable(mut at) => {
1138 for action in &mut at.actions {
1139 if let crate::expressions::AlterTableAction::AddColumn { column, .. } = action {
1140 if let Expression::DataType(new_dt) =
1141 self.transform_data_type(column.data_type.clone())?
1142 {
1143 column.data_type = new_dt;
1144 }
1145 }
1146 }
1147 Ok(Expression::AlterTable(at))
1148 }
1149
1150 Expression::Table(mut t) => {
1152 if let Some(when) = t.when.take() {
1153 let transformed_expr = self.transform_expr(*when.expression)?;
1155 t.when = Some(Box::new(crate::expressions::HistoricalData {
1156 this: when.this,
1157 kind: when.kind,
1158 expression: Box::new(transformed_expr),
1159 }));
1160 }
1161 Ok(Expression::Table(t))
1162 }
1163
1164 Expression::Subscript(s) => {
1166 let transformed_this = self.transform_expr(s.this)?;
1167 let transformed_index = self.transform_expr(s.index)?;
1168 Ok(Expression::Subscript(Box::new(
1169 crate::expressions::Subscript {
1170 this: transformed_this,
1171 index: transformed_index,
1172 },
1173 )))
1174 }
1175
1176 Expression::Paren(p) => {
1178 let transformed = self.transform_expr(p.this)?;
1179 Ok(Expression::Paren(Box::new(crate::expressions::Paren {
1180 this: transformed,
1181 trailing_comments: p.trailing_comments,
1182 })))
1183 }
1184
1185 Expression::Select(mut select) => {
1189 if let Some(ref mut order) = select.order_by {
1190 for ord in &mut order.expressions {
1191 if ord.nulls_first.is_none() {
1192 ord.nulls_first = Some(ord.desc);
1193 }
1194 }
1195 }
1196 Ok(Expression::Select(select))
1197 }
1198
1199 Expression::WindowFunction(mut wf) => {
1201 for ord in &mut wf.over.order_by {
1202 if ord.nulls_first.is_none() {
1203 ord.nulls_first = Some(ord.desc);
1204 }
1205 }
1206 Ok(Expression::WindowFunction(wf))
1207 }
1208
1209 Expression::Window(mut w) => {
1211 for ord in &mut w.order_by {
1212 if ord.nulls_first.is_none() {
1213 ord.nulls_first = Some(ord.desc);
1214 }
1215 }
1216 Ok(Expression::Window(w))
1217 }
1218
1219 Expression::Lateral(mut lat) => {
1221 let is_flatten = match lat.this.as_ref() {
1223 Expression::Function(f) => f.name.to_uppercase() == "FLATTEN",
1224 _ => false,
1225 };
1226 if is_flatten && lat.column_aliases.is_empty() {
1227 lat.column_aliases = vec![
1229 "SEQ".to_string(),
1230 "KEY".to_string(),
1231 "PATH".to_string(),
1232 "INDEX".to_string(),
1233 "VALUE".to_string(),
1234 "THIS".to_string(),
1235 ];
1236 if lat.alias.is_none() {
1238 lat.alias = Some("_flattened".to_string());
1239 }
1240 }
1241 Ok(Expression::Lateral(lat))
1242 }
1243
1244 _ => Ok(expr),
1246 }
1247 }
1248}
1249
1250impl SnowflakeDialect {
1251 fn format_external_table_property(key: &str, value: &str) -> String {
1254 let lower_key = key.to_lowercase();
1255 match lower_key.as_str() {
1256 "location" => format!("LOCATION={}", value),
1257 "file_format" => {
1258 let formatted_value = Self::format_file_format_value(value);
1260 format!("FILE_FORMAT={}", formatted_value)
1261 }
1262 _ => format!("{}={}", key, value),
1263 }
1264 }
1265
1266 fn format_file_format_value(value: &str) -> String {
1270 if !value.starts_with('(') {
1271 return value.to_string();
1272 }
1273 let inner = value[1..value.len() - 1].trim();
1275 let mut result = String::from("(");
1277 let mut parts: Vec<String> = Vec::new();
1278 let tokens: Vec<&str> = inner.split_whitespace().collect();
1280 let mut i = 0;
1281 while i < tokens.len() {
1282 let token = tokens[i];
1283 if i + 2 < tokens.len() && tokens[i + 1] == "=" {
1284 let val = Self::format_property_value(tokens[i + 2]);
1286 parts.push(format!("{}={}", token, val));
1287 i += 3;
1288 } else if token.contains('=') {
1289 let eq_pos = token.find('=').unwrap();
1291 let k = &token[..eq_pos];
1292 let v = Self::format_property_value(&token[eq_pos + 1..]);
1293 parts.push(format!("{}={}", k, v));
1294 i += 1;
1295 } else {
1296 parts.push(token.to_string());
1297 i += 1;
1298 }
1299 }
1300 result.push_str(&parts.join(" "));
1301 result.push(')');
1302 result
1303 }
1304
1305 fn format_property_value(value: &str) -> String {
1307 match value.to_lowercase().as_str() {
1308 "true" => "TRUE".to_string(),
1309 "false" => "FALSE".to_string(),
1310 _ => value.to_string(),
1311 }
1312 }
1313
1314 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1316 use crate::expressions::DataType;
1317 let transformed = match dt {
1318 DataType::Text => DataType::VarChar {
1320 length: None,
1321 parenthesized_length: false,
1322 },
1323 DataType::Struct { fields, .. } => {
1325 let _ = fields; DataType::Custom {
1328 name: "OBJECT".to_string(),
1329 }
1330 }
1331 DataType::Custom { name } => {
1333 let upper_name = name.to_uppercase();
1334 match upper_name.as_str() {
1335 "NVARCHAR" | "NCHAR" | "NATIONAL CHARACTER VARYING" | "NATIONAL CHAR" => {
1337 DataType::VarChar {
1338 length: None,
1339 parenthesized_length: false,
1340 }
1341 }
1342 "STRING" => DataType::VarChar {
1344 length: None,
1345 parenthesized_length: false,
1346 },
1347 "BIGDECIMAL" => DataType::Double {
1349 precision: None,
1350 scale: None,
1351 },
1352 "NESTED" => DataType::Custom {
1354 name: "OBJECT".to_string(),
1355 },
1356 "BYTEINT" => DataType::Int {
1358 length: None,
1359 integer_spelling: false,
1360 },
1361 "CHAR VARYING" | "CHARACTER VARYING" => DataType::VarChar {
1363 length: None,
1364 parenthesized_length: false,
1365 },
1366 "SQL_DOUBLE" => DataType::Double {
1368 precision: None,
1369 scale: None,
1370 },
1371 "SQL_VARCHAR" => DataType::VarChar {
1373 length: None,
1374 parenthesized_length: false,
1375 },
1376 "TIMESTAMP_NTZ" => DataType::Custom {
1378 name: "TIMESTAMPNTZ".to_string(),
1379 },
1380 "TIMESTAMP_LTZ" => DataType::Custom {
1382 name: "TIMESTAMPLTZ".to_string(),
1383 },
1384 "TIMESTAMP_TZ" => DataType::Custom {
1386 name: "TIMESTAMPTZ".to_string(),
1387 },
1388 "NCHAR VARYING" => DataType::VarChar {
1390 length: None,
1391 parenthesized_length: false,
1392 },
1393 "NUMBER" => DataType::Decimal {
1395 precision: Some(38),
1396 scale: Some(0),
1397 },
1398 _ if name.starts_with("NUMBER(") => {
1399 let inner = &name[7..name.len() - 1]; let parts: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1403 let precision = parts.first().and_then(|p| p.parse::<u32>().ok());
1404 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1405 DataType::Decimal { precision, scale }
1406 }
1407 _ => DataType::Custom { name },
1408 }
1409 }
1410 DataType::Decimal {
1412 precision: None,
1413 scale: None,
1414 } => DataType::Decimal {
1415 precision: Some(38),
1416 scale: Some(0),
1417 },
1418 DataType::Float { .. } => DataType::Double {
1420 precision: None,
1421 scale: None,
1422 },
1423 other => other,
1425 };
1426 Ok(Expression::DataType(transformed))
1427 }
1428
1429 fn map_date_part(abbr: &str) -> Option<&'static str> {
1431 match abbr.to_uppercase().as_str() {
1432 "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some("YEAR"),
1434 "MM" | "MON" | "MONS" | "MONTHS" => Some("MONTH"),
1436 "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some("DAY"),
1438 "DAY OF WEEK" | "WEEKDAY" | "DOW" | "DW" => Some("DAYOFWEEK"),
1440 "WEEKDAY_ISO" | "DOW_ISO" | "DW_ISO" | "DAYOFWEEK_ISO" => Some("DAYOFWEEKISO"),
1441 "DAY OF YEAR" | "DOY" | "DY" => Some("DAYOFYEAR"),
1443 "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY" => Some("WEEK"),
1445 "WEEK_ISO" | "WEEKOFYEARISO" | "WEEKOFYEAR_ISO" => Some("WEEKISO"),
1446 "Q" | "QTR" | "QTRS" | "QUARTERS" => Some("QUARTER"),
1448 "H" | "HH" | "HR" | "HOURS" | "HRS" => Some("HOUR"),
1450 "MI" | "MIN" | "MINUTES" | "MINS" => Some("MINUTE"),
1452 "S" | "SEC" | "SECONDS" | "SECS" => Some("SECOND"),
1454 "MS" | "MSEC" | "MSECS" | "MSECOND" | "MSECONDS" | "MILLISEC" | "MILLISECS"
1456 | "MILLISECON" | "MILLISECONDS" => Some("MILLISECOND"),
1457 "US" | "USEC" | "USECS" | "MICROSEC" | "MICROSECS" | "USECOND" | "USECONDS"
1459 | "MICROSECONDS" => Some("MICROSECOND"),
1460 "NS" | "NSEC" | "NANOSEC" | "NSECOND" | "NSECONDS" | "NANOSECS" => Some("NANOSECOND"),
1462 "EPOCH_SECOND" | "EPOCH_SECONDS" => Some("EPOCH_SECOND"),
1464 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Some("EPOCH_MILLISECOND"),
1465 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Some("EPOCH_MICROSECOND"),
1466 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Some("EPOCH_NANOSECOND"),
1467 "TZH" => Some("TIMEZONE_HOUR"),
1469 "TZM" => Some("TIMEZONE_MINUTE"),
1470 "DEC" | "DECS" | "DECADES" => Some("DECADE"),
1472 "MIL" | "MILS" | "MILLENIA" => Some("MILLENNIUM"),
1474 "C" | "CENT" | "CENTS" | "CENTURIES" => Some("CENTURY"),
1476 _ => None,
1478 }
1479 }
1480
1481 fn transform_date_part_arg(&self, expr: Expression) -> Expression {
1483 match &expr {
1484 Expression::Literal(lit)
1486 if matches!(lit.as_ref(), crate::expressions::Literal::String(_)) =>
1487 {
1488 let crate::expressions::Literal::String(s) = lit.as_ref() else {
1489 unreachable!()
1490 };
1491 Expression::Identifier(crate::expressions::Identifier {
1492 name: s.clone(),
1493 quoted: false,
1494 trailing_comments: Vec::new(),
1495 span: None,
1496 })
1497 }
1498 Expression::Identifier(id) => {
1500 if let Some(canonical) = Self::map_date_part(&id.name) {
1501 Expression::Identifier(crate::expressions::Identifier {
1502 name: canonical.to_string(),
1503 quoted: false,
1504 trailing_comments: Vec::new(),
1505 span: None,
1506 })
1507 } else {
1508 expr
1510 }
1511 }
1512 Expression::Var(v) => {
1513 if let Some(canonical) = Self::map_date_part(&v.this) {
1514 Expression::Identifier(crate::expressions::Identifier {
1515 name: canonical.to_string(),
1516 quoted: false,
1517 trailing_comments: Vec::new(),
1518 span: None,
1519 })
1520 } else {
1521 expr
1522 }
1523 }
1524 Expression::Column(col) if col.table.is_none() => {
1526 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1527 Expression::Identifier(crate::expressions::Identifier {
1528 name: canonical.to_string(),
1529 quoted: false,
1530 trailing_comments: Vec::new(),
1531 span: None,
1532 })
1533 } else {
1534 expr
1536 }
1537 }
1538 _ => expr,
1539 }
1540 }
1541
1542 fn transform_date_part_arg_identifiers_only(&self, expr: Expression) -> Expression {
1545 match &expr {
1546 Expression::Identifier(id) => {
1547 if let Some(canonical) = Self::map_date_part(&id.name) {
1548 Expression::Identifier(crate::expressions::Identifier {
1549 name: canonical.to_string(),
1550 quoted: false,
1551 trailing_comments: Vec::new(),
1552 span: None,
1553 })
1554 } else {
1555 expr
1556 }
1557 }
1558 Expression::Var(v) => {
1559 if let Some(canonical) = Self::map_date_part(&v.this) {
1560 Expression::Identifier(crate::expressions::Identifier {
1561 name: canonical.to_string(),
1562 quoted: false,
1563 trailing_comments: Vec::new(),
1564 span: None,
1565 })
1566 } else {
1567 expr
1568 }
1569 }
1570 Expression::Column(col) if col.table.is_none() => {
1571 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1572 Expression::Identifier(crate::expressions::Identifier {
1573 name: canonical.to_string(),
1574 quoted: false,
1575 trailing_comments: Vec::new(),
1576 span: None,
1577 })
1578 } else {
1579 expr
1580 }
1581 }
1582 _ => expr,
1583 }
1584 }
1585
1586 fn transform_json_path(path: &str) -> String {
1590 fn is_safe_identifier(s: &str) -> bool {
1593 if s.is_empty() {
1594 return false;
1595 }
1596 let mut chars = s.chars();
1597 match chars.next() {
1598 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
1599 _ => return false,
1600 }
1601 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
1602 }
1603
1604 if !path.contains('.') && !path.contains('[') && !path.contains(':') {
1607 if is_safe_identifier(path) {
1608 return path.to_string();
1609 } else {
1610 return format!("[\"{}\"]", path);
1612 }
1613 }
1614
1615 let result = path.replace(':', ".");
1618 result
1619 }
1620
1621 fn transform_interval(&self, interval: crate::expressions::Interval) -> Result<Expression> {
1623 use crate::expressions::{Interval, Literal};
1624
1625 fn expand_unit(abbr: &str) -> &'static str {
1627 match abbr.to_uppercase().as_str() {
1628 "D" => "DAY",
1629 "H" => "HOUR",
1630 "M" => "MINUTE",
1631 "MS" => "MILLISECOND",
1632 "NS" => "NANOSECOND",
1633 "Q" => "QUARTER",
1634 "S" => "SECOND",
1635 "US" => "MICROSECOND",
1636 "W" => "WEEK",
1637 "Y" => "YEAR",
1638 "WEEK" | "WEEKS" => "WEEK",
1640 "DAY" | "DAYS" => "DAY",
1641 "HOUR" | "HOURS" => "HOUR",
1642 "MINUTE" | "MINUTES" => "MINUTE",
1643 "SECOND" | "SECONDS" => "SECOND",
1644 "MONTH" | "MONTHS" => "MONTH",
1645 "YEAR" | "YEARS" => "YEAR",
1646 "QUARTER" | "QUARTERS" => "QUARTER",
1647 "MILLISECOND" | "MILLISECONDS" => "MILLISECOND",
1648 "MICROSECOND" | "MICROSECONDS" => "MICROSECOND",
1649 "NANOSECOND" | "NANOSECONDS" => "NANOSECOND",
1650 _ => "", }
1652 }
1653
1654 fn parse_interval_string(s: &str) -> Option<(&str, &str)> {
1656 let s = s.trim();
1657
1658 let mut num_end = 0;
1661 let mut chars = s.chars().peekable();
1662
1663 if chars.peek() == Some(&'-') {
1665 chars.next();
1666 num_end += 1;
1667 }
1668
1669 while let Some(&c) = chars.peek() {
1671 if c.is_ascii_digit() {
1672 chars.next();
1673 num_end += 1;
1674 } else {
1675 break;
1676 }
1677 }
1678
1679 if chars.peek() == Some(&'.') {
1681 chars.next();
1682 num_end += 1;
1683 while let Some(&c) = chars.peek() {
1684 if c.is_ascii_digit() {
1685 chars.next();
1686 num_end += 1;
1687 } else {
1688 break;
1689 }
1690 }
1691 }
1692
1693 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1694 return None; }
1696
1697 let value = &s[..num_end];
1698 let rest = s[num_end..].trim();
1699
1700 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1702 return None;
1703 }
1704
1705 Some((value, rest))
1706 }
1707
1708 if let Some(Expression::Literal(ref lit)) = interval.this {
1710 if let Literal::String(ref s) = lit.as_ref() {
1711 if let Some((value, unit)) = parse_interval_string(s) {
1712 let expanded = expand_unit(unit);
1713 if !expanded.is_empty() {
1714 let new_value = format!("{} {}", value, expanded);
1716
1717 return Ok(Expression::Interval(Box::new(Interval {
1718 this: Some(Expression::Literal(Box::new(Literal::String(new_value)))),
1719 unit: None, })));
1721 }
1722 }
1723 }
1724 }
1725
1726 Ok(Expression::Interval(Box::new(interval)))
1728 }
1729
1730 fn transform_function(&self, f: Function) -> Result<Expression> {
1731 let transformed_args: Vec<Expression> = f
1733 .args
1734 .into_iter()
1735 .map(|arg| self.transform_expr(arg))
1736 .collect::<Result<Vec<_>>>()?;
1737
1738 let f = Function {
1739 name: f.name,
1740 args: transformed_args,
1741 distinct: f.distinct,
1742 trailing_comments: f.trailing_comments,
1743 use_bracket_syntax: f.use_bracket_syntax,
1744 no_parens: f.no_parens,
1745 quoted: f.quoted,
1746 span: None,
1747 inferred_type: None,
1748 };
1749
1750 let name_upper = f.name.to_uppercase();
1751 match name_upper.as_str() {
1752 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1754 original_name: None,
1755 expressions: f.args,
1756 inferred_type: None,
1757 }))),
1758
1759 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1761 original_name: None,
1762 expressions: f.args,
1763 inferred_type: None,
1764 }))),
1765
1766 "NVL2" => Ok(Expression::Function(Box::new(f))),
1768
1769 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1771 Function::new("LISTAGG".to_string(), f.args),
1772 ))),
1773
1774 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1776 Function::new("LISTAGG".to_string(), f.args),
1777 ))),
1778
1779 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1781 "SUBSTRING".to_string(),
1782 f.args,
1783 )))),
1784
1785 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
1787 "FLATTEN".to_string(),
1788 f.args,
1789 )))),
1790
1791 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1793 "FLATTEN".to_string(),
1794 f.args,
1795 )))),
1796
1797 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1799
1800 "NOW" => Ok(Expression::Function(Box::new(Function {
1802 name: "CURRENT_TIMESTAMP".to_string(),
1803 args: f.args,
1804 distinct: false,
1805 trailing_comments: Vec::new(),
1806 use_bracket_syntax: false,
1807 no_parens: f.no_parens,
1808 quoted: false,
1809 span: None,
1810 inferred_type: None,
1811 }))),
1812
1813 "GETDATE" => Ok(Expression::Function(Box::new(Function {
1815 name: "CURRENT_TIMESTAMP".to_string(),
1816 args: f.args,
1817 distinct: false,
1818 trailing_comments: Vec::new(),
1819 use_bracket_syntax: false,
1820 no_parens: f.no_parens,
1821 quoted: false,
1822 span: None,
1823 inferred_type: None,
1824 }))),
1825
1826 "CURRENT_TIMESTAMP" if f.args.is_empty() => {
1830 Ok(Expression::Function(Box::new(Function {
1831 name: "CURRENT_TIMESTAMP".to_string(),
1832 args: Vec::new(),
1833 distinct: false,
1834 trailing_comments: Vec::new(),
1835 use_bracket_syntax: false,
1836 no_parens: false, quoted: false,
1838 span: None,
1839 inferred_type: None,
1840 })))
1841 }
1842
1843 "TO_DATE" => {
1847 if f.args.len() == 1 {
1848 if let Expression::Literal(lit) = &f.args[0] {
1849 if let crate::expressions::Literal::String(s) = lit.as_ref() {
1850 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
1852 return Ok(Expression::Cast(Box::new(Cast {
1853 this: f.args.into_iter().next().unwrap(),
1854 to: crate::expressions::DataType::Date,
1855 double_colon_syntax: false,
1856 trailing_comments: Vec::new(),
1857 format: None,
1858 default: None,
1859 inferred_type: None,
1860 })));
1861 }
1862 }
1863 }
1864 }
1865 let mut args = f.args;
1867 if args.len() >= 2 {
1868 args[1] = Self::normalize_format_arg(args[1].clone());
1869 }
1870 Ok(Expression::Function(Box::new(Function::new(
1871 "TO_DATE".to_string(),
1872 args,
1873 ))))
1874 }
1875
1876 "TO_TIME" => {
1878 if f.args.len() == 1 {
1879 if let Expression::Literal(lit) = &f.args[0] {
1880 if let crate::expressions::Literal::String(_) = lit.as_ref() {
1881 return Ok(Expression::Cast(Box::new(Cast {
1882 this: f.args.into_iter().next().unwrap(),
1883 to: crate::expressions::DataType::Time {
1884 precision: None,
1885 timezone: false,
1886 },
1887 double_colon_syntax: false,
1888 trailing_comments: Vec::new(),
1889 format: None,
1890 default: None,
1891 inferred_type: None,
1892 })));
1893 }
1894 }
1895 }
1896 let mut args = f.args;
1898 if args.len() >= 2 {
1899 args[1] = Self::normalize_format_arg(args[1].clone());
1900 }
1901 Ok(Expression::Function(Box::new(Function::new(
1902 "TO_TIME".to_string(),
1903 args,
1904 ))))
1905 }
1906
1907 "TO_TIMESTAMP" => {
1914 let args = f.args;
1915 if args.len() == 1 {
1916 let arg = &args[0];
1917 match arg {
1918 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_datetime(s)) =>
1919 {
1920 let Literal::String(_) = lit.as_ref() else {
1921 unreachable!()
1922 };
1923 return Ok(Expression::Cast(Box::new(Cast {
1925 this: args.into_iter().next().unwrap(),
1926 to: DataType::Timestamp {
1927 precision: None,
1928 timezone: false,
1929 },
1930 double_colon_syntax: false,
1931 trailing_comments: vec![],
1932 format: None,
1933 default: None,
1934 inferred_type: None,
1935 })));
1936 }
1937 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_epoch(s)) =>
1938 {
1939 let Literal::String(_) = lit.as_ref() else {
1940 unreachable!()
1941 };
1942 return Ok(Expression::UnixToTime(Box::new(
1944 crate::expressions::UnixToTime {
1945 this: Box::new(args.into_iter().next().unwrap()),
1946 scale: None,
1947 zone: None,
1948 hours: None,
1949 minutes: None,
1950 format: None,
1951 target_type: None,
1952 },
1953 )));
1954 }
1955 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1956 return Ok(Expression::UnixToTime(Box::new(
1958 crate::expressions::UnixToTime {
1959 this: Box::new(args.into_iter().next().unwrap()),
1960 scale: None,
1961 zone: None,
1962 hours: None,
1963 minutes: None,
1964 format: None,
1965 target_type: None,
1966 },
1967 )));
1968 }
1969 Expression::Neg(_) => {
1970 return Ok(Expression::UnixToTime(Box::new(
1972 crate::expressions::UnixToTime {
1973 this: Box::new(args.into_iter().next().unwrap()),
1974 scale: None,
1975 zone: None,
1976 hours: None,
1977 minutes: None,
1978 format: None,
1979 target_type: None,
1980 },
1981 )));
1982 }
1983 _ => {
1984 return Ok(Expression::Function(Box::new(Function::new(
1986 "TO_TIMESTAMP".to_string(),
1987 args,
1988 ))));
1989 }
1990 }
1991 } else if args.len() == 2 {
1992 let second_arg = &args[1];
1993 let is_int_scale = match second_arg {
1995 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1996 let Literal::Number(n) = lit.as_ref() else {
1997 unreachable!()
1998 };
1999 n.parse::<i64>().is_ok()
2000 }
2001 _ => false,
2002 };
2003
2004 if is_int_scale {
2005 let mut args_iter = args.into_iter();
2007 let value = args_iter.next().unwrap();
2008 let scale_expr = args_iter.next().unwrap();
2009 let scale = if let Expression::Literal(lit) = &scale_expr {
2010 if let Literal::Number(n) = lit.as_ref() {
2011 n.parse::<i64>().ok()
2012 } else {
2013 None
2014 }
2015 } else {
2016 None
2017 };
2018 return Ok(Expression::UnixToTime(Box::new(
2019 crate::expressions::UnixToTime {
2020 this: Box::new(value),
2021 scale,
2022 zone: None,
2023 hours: None,
2024 minutes: None,
2025 format: None,
2026 target_type: None,
2027 },
2028 )));
2029 } else {
2030 let mut args_iter = args.into_iter();
2032 let value = args_iter.next().unwrap();
2033 let format_expr = args_iter.next().unwrap();
2034 let format_str = match &format_expr {
2035 Expression::Literal(lit)
2036 if matches!(lit.as_ref(), Literal::String(_)) =>
2037 {
2038 let Literal::String(s) = lit.as_ref() else {
2039 unreachable!()
2040 };
2041 s.clone()
2042 }
2043 _ => {
2044 return Ok(Expression::Function(Box::new(Function::new(
2046 "TO_TIMESTAMP".to_string(),
2047 vec![value, format_expr],
2048 ))));
2049 }
2050 };
2051 let normalized_format = Self::normalize_snowflake_format(&format_str);
2053 return Ok(Expression::StrToTime(Box::new(
2054 crate::expressions::StrToTime {
2055 this: Box::new(value),
2056 format: normalized_format,
2057 zone: None,
2058 safe: None,
2059 target_type: None,
2060 },
2061 )));
2062 }
2063 }
2064 Ok(Expression::Function(Box::new(Function::new(
2066 "TO_TIMESTAMP".to_string(),
2067 args,
2068 ))))
2069 }
2070
2071 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
2073
2074 "ROUND"
2077 if f.args
2078 .iter()
2079 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
2080 {
2081 let mut expr_val = None;
2082 let mut scale_val = None;
2083 let mut rounding_mode_val = None;
2084 for arg in &f.args {
2085 if let Expression::NamedArgument(na) = arg {
2086 match na.name.name.to_uppercase().as_str() {
2087 "EXPR" => expr_val = Some(na.value.clone()),
2088 "SCALE" => scale_val = Some(na.value.clone()),
2089 "ROUNDING_MODE" => rounding_mode_val = Some(na.value.clone()),
2090 _ => {}
2091 }
2092 }
2093 }
2094 if let Some(expr) = expr_val {
2095 let mut args = vec![expr];
2096 if let Some(scale) = scale_val {
2097 args.push(scale);
2098 }
2099 if let Some(mode) = rounding_mode_val {
2100 args.push(mode);
2101 }
2102 Ok(Expression::Function(Box::new(Function::new(
2103 "ROUND".to_string(),
2104 args,
2105 ))))
2106 } else {
2107 Ok(Expression::Function(Box::new(f)))
2108 }
2109 }
2110
2111 "DATE_FORMAT" => {
2114 let mut args = f.args;
2115 if !args.is_empty() {
2117 if matches!(&args[0], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)))
2118 {
2119 args[0] = Expression::Cast(Box::new(crate::expressions::Cast {
2120 this: args[0].clone(),
2121 to: DataType::Timestamp {
2122 precision: None,
2123 timezone: false,
2124 },
2125 trailing_comments: Vec::new(),
2126 double_colon_syntax: false,
2127 format: None,
2128 default: None,
2129 inferred_type: None,
2130 }));
2131 }
2132 }
2133 if args.len() >= 2 {
2135 if let Expression::Literal(ref lit) = args[1] {
2136 if let Literal::String(ref fmt) = lit.as_ref() {
2137 let sf_fmt = strftime_to_snowflake_format(fmt);
2138 args[1] = Expression::Literal(Box::new(Literal::String(sf_fmt)));
2139 }
2140 }
2141 }
2142 Ok(Expression::Function(Box::new(Function::new(
2143 "TO_CHAR".to_string(),
2144 args,
2145 ))))
2146 }
2147
2148 "ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2150 "ARRAY_CONSTRUCT".to_string(),
2151 f.args,
2152 )))),
2153
2154 "STRUCT" => {
2157 let mut oc_args = Vec::new();
2158 for arg in f.args {
2159 match arg {
2160 Expression::Alias(a) => {
2161 oc_args.push(Expression::Literal(Box::new(
2163 crate::expressions::Literal::String(a.alias.name.clone()),
2164 )));
2165 oc_args.push(a.this);
2166 }
2167 other => {
2168 oc_args.push(other);
2170 }
2171 }
2172 }
2173 Ok(Expression::Function(Box::new(Function::new(
2174 "OBJECT_CONSTRUCT".to_string(),
2175 oc_args,
2176 ))))
2177 }
2178
2179 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2181 "GET_PATH".to_string(),
2182 f.args,
2183 )))),
2184
2185 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2187 "JSON_EXTRACT_PATH_TEXT".to_string(),
2188 f.args,
2189 )))),
2190
2191 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2193 f.args.into_iter().next().unwrap(),
2194 )))),
2195
2196 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2198 this: f.args.into_iter().next().unwrap(),
2199 decimals: None,
2200 to: None,
2201 }))),
2202
2203 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2205
2206 "SPLIT" => Ok(Expression::Function(Box::new(f))),
2208
2209 "ARRAY_AGG" => Ok(Expression::Function(Box::new(f))),
2211
2212 "JSON_PARSE" | "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2214 "PARSE_JSON".to_string(),
2215 f.args,
2216 )))),
2217
2218 "RAND" => {
2220 let seed = f.args.first().cloned().map(Box::new);
2221 Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2222 seed,
2223 lower: None,
2224 upper: None,
2225 })))
2226 }
2227
2228 "SHA" => Ok(Expression::Function(Box::new(Function::new(
2230 "SHA1".to_string(),
2231 f.args,
2232 )))),
2233
2234 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
2236 "APPROX_COUNT_DISTINCT".to_string(),
2237 f.args,
2238 )))),
2239
2240 "GEN_RANDOM_UUID" | "UUID" => {
2242 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2243 this: None,
2244 name: None,
2245 is_string: None,
2246 })))
2247 }
2248
2249 "NEWID" => Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2251 this: None,
2252 name: None,
2253 is_string: None,
2254 }))),
2255
2256 "UUID_STRING" => {
2258 if f.args.is_empty() {
2259 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2260 this: None,
2261 name: None,
2262 is_string: None,
2263 })))
2264 } else {
2265 Ok(Expression::Function(Box::new(Function::new(
2266 "UUID_STRING".to_string(),
2267 f.args,
2268 ))))
2269 }
2270 }
2271
2272 "IF" if f.args.len() >= 2 => {
2274 let mut args = f.args;
2275 let condition = args.remove(0);
2276 let true_val = args.remove(0);
2277 let false_val = if !args.is_empty() {
2278 Some(args.remove(0))
2279 } else {
2280 None
2281 };
2282 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2283 condition,
2284 true_value: true_val,
2285 false_value: Some(
2286 false_val.unwrap_or(Expression::Null(crate::expressions::Null)),
2287 ),
2288 original_name: Some("IFF".to_string()),
2289 inferred_type: None,
2290 })))
2291 }
2292
2293 "SQUARE" if f.args.len() == 1 => {
2295 let x = f.args.into_iter().next().unwrap();
2296 Ok(Expression::Power(Box::new(
2297 crate::expressions::BinaryFunc {
2298 original_name: None,
2299 this: x,
2300 expression: Expression::number(2),
2301 inferred_type: None,
2302 },
2303 )))
2304 }
2305
2306 "POW" if f.args.len() == 2 => {
2308 let mut args = f.args.into_iter();
2309 let x = args.next().unwrap();
2310 let y = args.next().unwrap();
2311 Ok(Expression::Power(Box::new(
2312 crate::expressions::BinaryFunc {
2313 original_name: None,
2314 this: x,
2315 expression: y,
2316 inferred_type: None,
2317 },
2318 )))
2319 }
2320
2321 "MOD" if f.args.len() == 2 => {
2323 let mut args = f.args.into_iter();
2324 let x = args.next().unwrap();
2325 let y = args.next().unwrap();
2326 Ok(Expression::Mod(Box::new(crate::expressions::BinaryOp {
2327 left: x,
2328 right: y,
2329 left_comments: Vec::new(),
2330 operator_comments: Vec::new(),
2331 trailing_comments: Vec::new(),
2332 inferred_type: None,
2333 })))
2334 }
2335
2336 "APPROXIMATE_JACCARD_INDEX" => Ok(Expression::Function(Box::new(Function::new(
2338 "APPROXIMATE_SIMILARITY".to_string(),
2339 f.args,
2340 )))),
2341
2342 "ARRAY_CONSTRUCT" => Ok(Expression::ArrayFunc(Box::new(
2344 crate::expressions::ArrayConstructor {
2345 expressions: f.args,
2346 bracket_notation: true,
2347 use_list_keyword: false,
2348 },
2349 ))),
2350
2351 "APPROX_TOP_K" if f.args.len() == 1 => {
2353 let mut args = f.args;
2354 args.push(Expression::number(1));
2355 Ok(Expression::Function(Box::new(Function::new(
2356 "APPROX_TOP_K".to_string(),
2357 args,
2358 ))))
2359 }
2360
2361 "TO_DECIMAL" | "TO_NUMERIC" => Ok(Expression::Function(Box::new(Function::new(
2363 "TO_NUMBER".to_string(),
2364 f.args,
2365 )))),
2366
2367 "TRY_TO_DECIMAL" | "TRY_TO_NUMERIC" => Ok(Expression::Function(Box::new(
2369 Function::new("TRY_TO_NUMBER".to_string(), f.args),
2370 ))),
2371
2372 "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2374 "STDDEV".to_string(),
2375 f.args,
2376 )))),
2377
2378 "STRTOK" if f.args.len() >= 1 => {
2380 let mut args = f.args;
2381 if args.len() == 1 {
2383 args.push(Expression::string(" ".to_string()));
2384 }
2385 if args.len() == 2 {
2387 args.push(Expression::number(1));
2388 }
2389 Ok(Expression::Function(Box::new(Function::new(
2390 "STRTOK".to_string(),
2391 args,
2392 ))))
2393 }
2394
2395 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2397 "WEEK".to_string(),
2398 f.args,
2399 )))),
2400
2401 "LIKE" if f.args.len() >= 2 => {
2403 let mut args = f.args.into_iter();
2404 let left = args.next().unwrap();
2405 let right = args.next().unwrap();
2406 let escape = args.next();
2407 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2408 left,
2409 right,
2410 escape,
2411 quantifier: None,
2412 inferred_type: None,
2413 })))
2414 }
2415
2416 "ILIKE" if f.args.len() >= 2 => {
2418 let mut args = f.args.into_iter();
2419 let left = args.next().unwrap();
2420 let right = args.next().unwrap();
2421 let escape = args.next();
2422 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2423 left,
2424 right,
2425 escape,
2426 quantifier: None,
2427 inferred_type: None,
2428 })))
2429 }
2430
2431 "RLIKE" if f.args.len() >= 2 => {
2433 let mut args = f.args.into_iter();
2434 let left = args.next().unwrap();
2435 let pattern = args.next().unwrap();
2436 let flags = args.next();
2437 Ok(Expression::RegexpLike(Box::new(
2438 crate::expressions::RegexpFunc {
2439 this: left,
2440 pattern,
2441 flags,
2442 },
2443 )))
2444 }
2445
2446 "IFF" if f.args.len() >= 2 => {
2448 let mut args = f.args;
2449 let condition = args.remove(0);
2450 let true_value = args.remove(0);
2451 let false_value = if !args.is_empty() {
2452 Some(args.remove(0))
2453 } else {
2454 None
2455 };
2456 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2457 condition,
2458 true_value,
2459 false_value,
2460 original_name: Some("IFF".to_string()),
2461 inferred_type: None,
2462 })))
2463 }
2464
2465 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2467 Ok(Expression::Function(Box::new(Function::new(
2468 "TIMESTAMP_FROM_PARTS".to_string(),
2469 f.args,
2470 ))))
2471 }
2472
2473 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2475 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2476 f.args,
2477 )))),
2478
2479 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2481 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2482 f.args,
2483 )))),
2484
2485 "DATEADD" if f.args.len() >= 1 => {
2487 let mut args = f.args;
2488 args[0] = self.transform_date_part_arg(args[0].clone());
2489 Ok(Expression::Function(Box::new(Function::new(
2490 "DATEADD".to_string(),
2491 args,
2492 ))))
2493 }
2494
2495 "DATEDIFF" if f.args.len() >= 1 => {
2498 let mut args = f.args;
2499 args[0] = self.transform_date_part_arg(args[0].clone());
2500 for i in 1..args.len() {
2503 if let Expression::Function(ref func) = args[i] {
2504 if func.name == "_POLYGLOT_TO_DATE" {
2505 let inner_args = func.args.clone();
2506 args[i] = Expression::Function(Box::new(Function::new(
2507 "TO_DATE".to_string(),
2508 inner_args,
2509 )));
2510 }
2511 }
2512 }
2513 Ok(Expression::Function(Box::new(Function::new(
2514 "DATEDIFF".to_string(),
2515 args,
2516 ))))
2517 }
2518
2519 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2521 "DATEDIFF".to_string(),
2522 f.args,
2523 )))),
2524
2525 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2527 "DATEDIFF".to_string(),
2528 f.args,
2529 )))),
2530
2531 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2533 "DATEADD".to_string(),
2534 f.args,
2535 )))),
2536
2537 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2539
2540 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2542 "DATE_FROM_PARTS".to_string(),
2543 f.args,
2544 )))),
2545
2546 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2548 "TIME_FROM_PARTS".to_string(),
2549 f.args,
2550 )))),
2551
2552 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2554
2555 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2557
2558 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2560
2561 "MONTHNAME" if f.args.len() == 1 => {
2564 let arg = f.args.into_iter().next().unwrap();
2565 Ok(Expression::Monthname(Box::new(
2566 crate::expressions::Monthname {
2567 this: Box::new(arg),
2568 abbreviated: Some(Box::new(Expression::Literal(Box::new(
2569 Literal::String("true".to_string()),
2570 )))),
2571 },
2572 )))
2573 }
2574
2575 "DAYNAME" if f.args.len() == 1 => {
2578 let arg = f.args.into_iter().next().unwrap();
2579 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2580 this: Box::new(arg),
2581 abbreviated: Some(Box::new(Expression::Literal(Box::new(Literal::String(
2582 "true".to_string(),
2583 ))))),
2584 })))
2585 }
2586
2587 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2589 let arg = f.args.into_iter().next().unwrap();
2590 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2591 this: arg,
2592 distinct: false,
2593 filter: None,
2594 order_by: Vec::new(),
2595 name: Some("BOOLAND_AGG".to_string()),
2596 ignore_nulls: None,
2597 having_max: None,
2598 limit: None,
2599 inferred_type: None,
2600 })))
2601 }
2602
2603 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2605 let arg = f.args.into_iter().next().unwrap();
2606 Ok(Expression::LogicalOr(Box::new(AggFunc {
2607 this: arg,
2608 distinct: false,
2609 filter: None,
2610 order_by: Vec::new(),
2611 name: Some("BOOLOR_AGG".to_string()),
2612 ignore_nulls: None,
2613 having_max: None,
2614 limit: None,
2615 inferred_type: None,
2616 })))
2617 }
2618
2619 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2621 let arg = f.args.into_iter().next().unwrap();
2622 Ok(Expression::Skewness(Box::new(AggFunc {
2623 this: arg,
2624 distinct: false,
2625 filter: None,
2626 order_by: Vec::new(),
2627 name: Some("SKEW".to_string()),
2628 ignore_nulls: None,
2629 having_max: None,
2630 limit: None,
2631 inferred_type: None,
2632 })))
2633 }
2634
2635 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2637 "VARIANCE".to_string(),
2638 f.args,
2639 )))),
2640
2641 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2643 "VARIANCE_POP".to_string(),
2644 f.args,
2645 )))),
2646
2647 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2649 "TO_DATE".to_string(),
2650 f.args,
2651 )))),
2652 "DATE" if f.args.len() >= 2 => {
2656 let mut args = f.args;
2657 args[1] = Self::normalize_format_arg(args[1].clone());
2658 Ok(Expression::Function(Box::new(Function::new(
2659 "TO_DATE".to_string(),
2660 args,
2661 ))))
2662 }
2663 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2666 let mut args = f.args;
2667 args[1] = Self::normalize_format_arg(args[1].clone());
2668 Ok(Expression::Function(Box::new(Function::new(
2669 "DATE".to_string(),
2670 args,
2671 ))))
2672 }
2673
2674 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2676
2677 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2679 "MD5".to_string(),
2680 f.args,
2681 )))),
2682
2683 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2685 "SHA1".to_string(),
2686 f.args,
2687 )))),
2688
2689 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2691 "SHA2".to_string(),
2692 f.args,
2693 )))),
2694
2695 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2697 "EDITDISTANCE".to_string(),
2698 f.args,
2699 )))),
2700
2701 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2703 "BITNOT".to_string(),
2704 f.args,
2705 )))),
2706
2707 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2709 "BITAND".to_string(),
2710 f.args,
2711 )))),
2712
2713 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2715 "BITOR".to_string(),
2716 f.args,
2717 )))),
2718
2719 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2721 "BITXOR".to_string(),
2722 f.args,
2723 )))),
2724
2725 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2727 Function::new("BITSHIFTLEFT".to_string(), f.args),
2728 ))),
2729
2730 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2732 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2733 ))),
2734
2735 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2737 name: "CURRENT_TIMESTAMP".to_string(),
2738 args: f.args,
2739 distinct: false,
2740 trailing_comments: Vec::new(),
2741 use_bracket_syntax: false,
2742 no_parens: f.no_parens,
2743 quoted: false,
2744 span: None,
2745 inferred_type: None,
2746 }))),
2747
2748 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2750 name: "CURRENT_TIMESTAMP".to_string(),
2751 args: f.args,
2752 distinct: false,
2753 trailing_comments: Vec::new(),
2754 use_bracket_syntax: false,
2755 no_parens: f.no_parens,
2756 quoted: false,
2757 span: None,
2758 inferred_type: None,
2759 }))),
2760
2761 "SPACE" if f.args.len() == 1 => {
2763 let arg = f.args.into_iter().next().unwrap();
2764 Ok(Expression::Function(Box::new(Function::new(
2765 "REPEAT".to_string(),
2766 vec![
2767 Expression::Literal(Box::new(Literal::String(" ".to_string()))),
2768 arg,
2769 ],
2770 ))))
2771 }
2772
2773 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2775 "CEIL".to_string(),
2776 f.args,
2777 )))),
2778
2779 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2781 "LN".to_string(),
2782 f.args,
2783 )))),
2784
2785 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(f))),
2787
2788 "GET_PATH" if f.args.len() >= 2 => {
2792 let mut args = f.args;
2793 if let Expression::Literal(lit) = &args[1] {
2795 if let crate::expressions::Literal::String(path) = lit.as_ref() {
2796 let transformed = Self::transform_json_path(path);
2797 args[1] = Expression::Literal(Box::new(
2798 crate::expressions::Literal::String(transformed),
2799 ));
2800 }
2801 }
2802 Ok(Expression::Function(Box::new(Function::new(
2803 "GET_PATH".to_string(),
2804 args,
2805 ))))
2806 }
2807 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2808
2809 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2811
2812 "DATE_TRUNC" if f.args.len() >= 1 => {
2815 let mut args = f.args;
2816 let unit_name = match &args[0] {
2818 Expression::Identifier(id) => Some(id.name.as_str()),
2819 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2820 _ => None,
2821 };
2822 if let Some(name) = unit_name {
2823 let canonical = Self::map_date_part(name).unwrap_or(name);
2824 args[0] = Expression::Literal(Box::new(crate::expressions::Literal::String(
2825 canonical.to_uppercase(),
2826 )));
2827 }
2828 Ok(Expression::Function(Box::new(Function::new(
2829 "DATE_TRUNC".to_string(),
2830 args,
2831 ))))
2832 }
2833
2834 "DATE_PART" if f.args.len() >= 1 => {
2840 let mut args = f.args;
2841 let from_typed_literal = args.len() >= 2
2842 && matches!(
2843 &args[1],
2844 Expression::Literal(lit) if matches!(lit.as_ref(),
2845 crate::expressions::Literal::Timestamp(_)
2846 | crate::expressions::Literal::Date(_)
2847 | crate::expressions::Literal::Time(_)
2848 | crate::expressions::Literal::Datetime(_)
2849 )
2850 );
2851 if from_typed_literal {
2852 args[0] = self.transform_date_part_arg(args[0].clone());
2853 } else {
2854 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2857 }
2858 Ok(Expression::Function(Box::new(Function::new(
2859 "DATE_PART".to_string(),
2860 args,
2861 ))))
2862 }
2863
2864 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2866
2867 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2869
2870 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2872 "DESCRIBE".to_string(),
2873 f.args,
2874 )))),
2875
2876 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2878 "REGEXP_LIKE".to_string(),
2879 f.args,
2880 )))),
2881
2882 "TRANSFORM" => {
2887 let transformed_args: Vec<Expression> = f
2888 .args
2889 .into_iter()
2890 .map(|arg| {
2891 if let Expression::Lambda(lambda) = arg {
2892 self.transform_typed_lambda(*lambda)
2893 } else {
2894 arg
2895 }
2896 })
2897 .collect();
2898 Ok(Expression::Function(Box::new(Function::new(
2899 "TRANSFORM".to_string(),
2900 transformed_args,
2901 ))))
2902 }
2903
2904 "SEARCH" if f.args.len() >= 2 => {
2906 let mut args = f.args.into_iter();
2907 let this = Box::new(args.next().unwrap());
2908 let expression = Box::new(args.next().unwrap());
2909
2910 let mut analyzer: Option<Box<Expression>> = None;
2911 let mut search_mode: Option<Box<Expression>> = None;
2912
2913 for arg in args {
2915 if let Expression::NamedArgument(na) = &arg {
2916 let name_upper = na.name.name.to_uppercase();
2917 match name_upper.as_str() {
2918 "ANALYZER" => analyzer = Some(Box::new(arg)),
2919 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2920 _ => {}
2921 }
2922 }
2923 }
2924
2925 Ok(Expression::Search(Box::new(crate::expressions::Search {
2926 this,
2927 expression,
2928 json_scope: None,
2929 analyzer,
2930 analyzer_options: None,
2931 search_mode,
2932 })))
2933 }
2934
2935 "CONVERT" if f.args.len() == 2 => {
2938 let value = f.args.get(0).cloned().unwrap();
2939 let type_arg = f.args.get(1).cloned().unwrap();
2940
2941 if let Expression::Column(col) = &type_arg {
2943 let type_name = col.name.name.to_uppercase();
2944 let data_type = match type_name.as_str() {
2945 "SQL_DOUBLE" => Some(DataType::Double {
2946 precision: None,
2947 scale: None,
2948 }),
2949 "SQL_VARCHAR" => Some(DataType::VarChar {
2950 length: None,
2951 parenthesized_length: false,
2952 }),
2953 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2954 length: None,
2955 integer_spelling: false,
2956 }),
2957 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2958 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2959 "SQL_FLOAT" => Some(DataType::Float {
2960 precision: None,
2961 scale: None,
2962 real_spelling: false,
2963 }),
2964 "SQL_REAL" => Some(DataType::Float {
2965 precision: None,
2966 scale: None,
2967 real_spelling: true,
2968 }),
2969 "SQL_DECIMAL" => Some(DataType::Decimal {
2970 precision: None,
2971 scale: None,
2972 }),
2973 "SQL_DATE" => Some(DataType::Date),
2974 "SQL_TIME" => Some(DataType::Time {
2975 precision: None,
2976 timezone: false,
2977 }),
2978 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
2979 precision: None,
2980 timezone: false,
2981 }),
2982 _ => None,
2983 };
2984
2985 if let Some(dt) = data_type {
2986 return Ok(Expression::Cast(Box::new(Cast {
2987 this: value,
2988 to: dt,
2989 double_colon_syntax: false,
2990 trailing_comments: vec![],
2991 format: None,
2992 default: None,
2993 inferred_type: None,
2994 })));
2995 }
2996 }
2997 Ok(Expression::Function(Box::new(f)))
2999 }
3000
3001 "TO_TIMESTAMP_TZ" => {
3004 if f.args.len() == 1 {
3005 if let Expression::Literal(lit) = &f.args[0] {
3006 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3007 return Ok(Expression::Cast(Box::new(Cast {
3008 this: f.args.into_iter().next().unwrap(),
3009 to: DataType::Custom {
3010 name: "TIMESTAMPTZ".to_string(),
3011 },
3012 double_colon_syntax: false,
3013 trailing_comments: vec![],
3014 format: None,
3015 default: None,
3016 inferred_type: None,
3017 })));
3018 }
3019 }
3020 }
3021 Ok(Expression::Function(Box::new(f)))
3022 }
3023
3024 "TO_TIMESTAMP_NTZ" => {
3026 if f.args.len() == 1 {
3027 if let Expression::Literal(lit) = &f.args[0] {
3028 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3029 return Ok(Expression::Cast(Box::new(Cast {
3030 this: f.args.into_iter().next().unwrap(),
3031 to: DataType::Custom {
3032 name: "TIMESTAMPNTZ".to_string(),
3033 },
3034 double_colon_syntax: false,
3035 trailing_comments: vec![],
3036 format: None,
3037 default: None,
3038 inferred_type: None,
3039 })));
3040 }
3041 }
3042 }
3043 Ok(Expression::Function(Box::new(f)))
3044 }
3045
3046 "TO_TIMESTAMP_LTZ" => {
3048 if f.args.len() == 1 {
3049 if let Expression::Literal(lit) = &f.args[0] {
3050 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3051 return Ok(Expression::Cast(Box::new(Cast {
3052 this: f.args.into_iter().next().unwrap(),
3053 to: DataType::Custom {
3054 name: "TIMESTAMPLTZ".to_string(),
3055 },
3056 double_colon_syntax: false,
3057 trailing_comments: vec![],
3058 format: None,
3059 default: None,
3060 inferred_type: None,
3061 })));
3062 }
3063 }
3064 }
3065 Ok(Expression::Function(Box::new(f)))
3066 }
3067
3068 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
3070
3071 "REPLACE" if f.args.len() == 2 => {
3073 let mut args = f.args;
3074 args.push(Expression::Literal(Box::new(
3075 crate::expressions::Literal::String(String::new()),
3076 )));
3077 Ok(Expression::Function(Box::new(Function::new(
3078 "REPLACE".to_string(),
3079 args,
3080 ))))
3081 }
3082
3083 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
3085 "ANY_VALUE".to_string(),
3086 f.args,
3087 )))),
3088
3089 "SAFE_DIVIDE" if f.args.len() == 2 => {
3091 let mut args = f.args;
3092 let x = args.remove(0);
3093 let y = args.remove(0);
3094 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3095 condition: Expression::Neq(Box::new(BinaryOp {
3096 left: y.clone(),
3097 right: Expression::number(0),
3098 left_comments: Vec::new(),
3099 operator_comments: Vec::new(),
3100 trailing_comments: Vec::new(),
3101 inferred_type: None,
3102 })),
3103 true_value: Expression::Div(Box::new(BinaryOp {
3104 left: x,
3105 right: y,
3106 left_comments: Vec::new(),
3107 operator_comments: Vec::new(),
3108 trailing_comments: Vec::new(),
3109 inferred_type: None,
3110 })),
3111 false_value: Some(Expression::Null(crate::expressions::Null)),
3112 original_name: Some("IFF".to_string()),
3113 inferred_type: None,
3114 })))
3115 }
3116
3117 "TIMESTAMP" if f.args.len() == 1 => {
3119 let arg = f.args.into_iter().next().unwrap();
3120 Ok(Expression::Cast(Box::new(Cast {
3121 this: arg,
3122 to: DataType::Custom {
3123 name: "TIMESTAMPTZ".to_string(),
3124 },
3125 trailing_comments: Vec::new(),
3126 double_colon_syntax: false,
3127 format: None,
3128 default: None,
3129 inferred_type: None,
3130 })))
3131 }
3132
3133 "TIMESTAMP" if f.args.len() == 2 => {
3135 let mut args = f.args;
3136 let value = args.remove(0);
3137 let tz = args.remove(0);
3138 Ok(Expression::Function(Box::new(Function::new(
3139 "CONVERT_TIMEZONE".to_string(),
3140 vec![
3141 tz,
3142 Expression::Cast(Box::new(Cast {
3143 this: value,
3144 to: DataType::Timestamp {
3145 precision: None,
3146 timezone: false,
3147 },
3148 trailing_comments: Vec::new(),
3149 double_colon_syntax: false,
3150 format: None,
3151 default: None,
3152 inferred_type: None,
3153 })),
3154 ],
3155 ))))
3156 }
3157
3158 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3160 "TIME_FROM_PARTS".to_string(),
3161 f.args,
3162 )))),
3163
3164 "DIV0" if f.args.len() == 2 => {
3166 let mut args = f.args;
3167 let x = args.remove(0);
3168 let y = args.remove(0);
3169 let x_expr = Self::maybe_paren(x.clone());
3171 let y_expr = Self::maybe_paren(y.clone());
3172 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3173 condition: Expression::And(Box::new(BinaryOp::new(
3174 Expression::Eq(Box::new(BinaryOp::new(
3175 y_expr.clone(),
3176 Expression::number(0),
3177 ))),
3178 Expression::Not(Box::new(crate::expressions::UnaryOp {
3179 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3180 this: x_expr.clone(),
3181 not: false,
3182 postfix_form: false,
3183 })),
3184 inferred_type: None,
3185 })),
3186 ))),
3187 true_value: Expression::number(0),
3188 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3189 original_name: Some("IFF".to_string()),
3190 inferred_type: None,
3191 })))
3192 }
3193
3194 "DIV0NULL" if f.args.len() == 2 => {
3196 let mut args = f.args;
3197 let x = args.remove(0);
3198 let y = args.remove(0);
3199 let x_expr = Self::maybe_paren(x.clone());
3200 let y_expr = Self::maybe_paren(y.clone());
3201 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3202 condition: Expression::Or(Box::new(BinaryOp::new(
3203 Expression::Eq(Box::new(BinaryOp::new(
3204 y_expr.clone(),
3205 Expression::number(0),
3206 ))),
3207 Expression::IsNull(Box::new(crate::expressions::IsNull {
3208 this: y_expr.clone(),
3209 not: false,
3210 postfix_form: false,
3211 })),
3212 ))),
3213 true_value: Expression::number(0),
3214 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3215 original_name: Some("IFF".to_string()),
3216 inferred_type: None,
3217 })))
3218 }
3219
3220 "ZEROIFNULL" if f.args.len() == 1 => {
3222 let x = f.args.into_iter().next().unwrap();
3223 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3224 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3225 this: x.clone(),
3226 not: false,
3227 postfix_form: false,
3228 })),
3229 true_value: Expression::number(0),
3230 false_value: Some(x),
3231 original_name: Some("IFF".to_string()),
3232 inferred_type: None,
3233 })))
3234 }
3235
3236 "NULLIFZERO" if f.args.len() == 1 => {
3238 let x = f.args.into_iter().next().unwrap();
3239 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3240 condition: Expression::Eq(Box::new(BinaryOp::new(
3241 x.clone(),
3242 Expression::number(0),
3243 ))),
3244 true_value: Expression::Null(crate::expressions::Null),
3245 false_value: Some(x),
3246 original_name: Some("IFF".to_string()),
3247 inferred_type: None,
3248 })))
3249 }
3250
3251 "TRY_TO_TIME" => {
3253 if f.args.len() == 1 {
3254 if let Expression::Literal(lit) = &f.args[0] {
3255 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3256 return Ok(Expression::TryCast(Box::new(Cast {
3257 this: f.args.into_iter().next().unwrap(),
3258 to: crate::expressions::DataType::Time {
3259 precision: None,
3260 timezone: false,
3261 },
3262 double_colon_syntax: false,
3263 trailing_comments: Vec::new(),
3264 format: None,
3265 default: None,
3266 inferred_type: None,
3267 })));
3268 }
3269 }
3270 }
3271 let mut args = f.args;
3273 if args.len() >= 2 {
3274 args[1] = Self::normalize_format_arg(args[1].clone());
3275 }
3276 Ok(Expression::Function(Box::new(Function::new(
3277 "TRY_TO_TIME".to_string(),
3278 args,
3279 ))))
3280 }
3281
3282 "TRY_TO_TIMESTAMP" => {
3285 if f.args.len() == 1 {
3286 if let Expression::Literal(lit) = &f.args[0] {
3287 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3288 if !Self::looks_like_epoch(s) {
3289 return Ok(Expression::TryCast(Box::new(Cast {
3290 this: f.args.into_iter().next().unwrap(),
3291 to: DataType::Timestamp {
3292 precision: None,
3293 timezone: false,
3294 },
3295 double_colon_syntax: false,
3296 trailing_comments: Vec::new(),
3297 format: None,
3298 default: None,
3299 inferred_type: None,
3300 })));
3301 }
3302 }
3303 }
3304 }
3305 let mut args = f.args;
3307 if args.len() >= 2 {
3308 args[1] = Self::normalize_format_arg(args[1].clone());
3309 }
3310 Ok(Expression::Function(Box::new(Function::new(
3311 "TRY_TO_TIMESTAMP".to_string(),
3312 args,
3313 ))))
3314 }
3315
3316 "TRY_TO_DATE" => {
3318 if f.args.len() == 1 {
3319 if let Expression::Literal(lit) = &f.args[0] {
3320 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3321 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3323 return Ok(Expression::TryCast(Box::new(Cast {
3324 this: f.args.into_iter().next().unwrap(),
3325 to: crate::expressions::DataType::Date,
3326 double_colon_syntax: false,
3327 trailing_comments: Vec::new(),
3328 format: None,
3329 default: None,
3330 inferred_type: None,
3331 })));
3332 }
3333 }
3334 }
3335 }
3336 let mut args = f.args;
3338 if args.len() >= 2 {
3339 args[1] = Self::normalize_format_arg(args[1].clone());
3340 }
3341 Ok(Expression::Function(Box::new(Function::new(
3342 "TRY_TO_DATE".to_string(),
3343 args,
3344 ))))
3345 }
3346
3347 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3349
3350 "REGEXP_REPLACE" if f.args.len() == 2 => {
3352 let mut args = f.args;
3353 args.push(Expression::Literal(Box::new(
3354 crate::expressions::Literal::String(String::new()),
3355 )));
3356 Ok(Expression::Function(Box::new(Function::new(
3357 "REGEXP_REPLACE".to_string(),
3358 args,
3359 ))))
3360 }
3361
3362 "LAST_DAY" if f.args.len() == 2 => {
3364 let mut args = f.args;
3365 let date = args.remove(0);
3366 let unit = args.remove(0);
3367 let unit_str = match &unit {
3368 Expression::Column(c) => c.name.name.to_uppercase(),
3369 Expression::Identifier(i) => i.name.to_uppercase(),
3370 _ => String::new(),
3371 };
3372 if unit_str == "MONTH" {
3373 Ok(Expression::Function(Box::new(Function::new(
3374 "LAST_DAY".to_string(),
3375 vec![date],
3376 ))))
3377 } else {
3378 Ok(Expression::Function(Box::new(Function::new(
3379 "LAST_DAY".to_string(),
3380 vec![date, unit],
3381 ))))
3382 }
3383 }
3384
3385 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3387 "DATE_PART".to_string(),
3388 f.args,
3389 )))),
3390
3391 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3393 let mut args = f.args;
3394 let this = args.remove(0);
3395 let expr = args.remove(0);
3396 Ok(Expression::EndsWith(Box::new(
3397 crate::expressions::BinaryFunc {
3398 original_name: None,
3399 this,
3400 expression: expr,
3401 inferred_type: None,
3402 },
3403 )))
3404 }
3405
3406 _ => Ok(Expression::Function(Box::new(f))),
3408 }
3409 }
3410
3411 fn looks_like_datetime(s: &str) -> bool {
3413 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3416 }
3417
3418 fn looks_like_epoch(s: &str) -> bool {
3420 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3421 }
3422
3423 fn maybe_paren(expr: Expression) -> Expression {
3425 match &expr {
3426 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3427 Expression::Paren(Box::new(crate::expressions::Paren {
3428 this: expr,
3429 trailing_comments: Vec::new(),
3430 }))
3431 }
3432 _ => expr,
3433 }
3434 }
3435
3436 fn normalize_snowflake_format(format: &str) -> String {
3440 let mut result = String::new();
3441 let chars: Vec<char> = format.chars().collect();
3442 let mut i = 0;
3443 while i < chars.len() {
3444 if chars[i] == '"' {
3446 i += 1;
3447 while i < chars.len() && chars[i] != '"' {
3448 result.push(chars[i]);
3449 i += 1;
3450 }
3451 if i < chars.len() {
3452 i += 1; }
3454 continue;
3455 }
3456
3457 let remaining = &format[i..];
3458 let remaining_upper = remaining.to_uppercase();
3459
3460 if remaining_upper.starts_with("YYYY") {
3462 result.push_str("yyyy");
3463 i += 4;
3464 } else if remaining_upper.starts_with("YY") {
3465 result.push_str("yy");
3466 i += 2;
3467 } else if remaining_upper.starts_with("MMMM") {
3468 result.push_str("mmmm");
3469 i += 4;
3470 } else if remaining_upper.starts_with("MON") {
3471 result.push_str("mon");
3472 i += 3;
3473 } else if remaining_upper.starts_with("MM") {
3474 result.push_str("mm");
3475 i += 2;
3476 } else if remaining_upper.starts_with("DD") {
3477 result.push_str("DD");
3478 i += 2;
3479 } else if remaining_upper.starts_with("DY") {
3480 result.push_str("dy");
3481 i += 2;
3482 } else if remaining_upper.starts_with("HH24") {
3483 result.push_str("hh24");
3484 i += 4;
3485 } else if remaining_upper.starts_with("HH12") {
3486 result.push_str("hh12");
3487 i += 4;
3488 } else if remaining_upper.starts_with("HH") {
3489 result.push_str("hh");
3490 i += 2;
3491 } else if remaining_upper.starts_with("MISS") {
3492 result.push_str("miss");
3494 i += 4;
3495 } else if remaining_upper.starts_with("MI") {
3496 result.push_str("mi");
3497 i += 2;
3498 } else if remaining_upper.starts_with("SS") {
3499 result.push_str("ss");
3500 i += 2;
3501 } else if remaining_upper.starts_with("FF") {
3502 let ff_len = 2;
3504 let digit = if i + ff_len < chars.len() && chars[i + ff_len].is_ascii_digit() {
3505 let d = chars[i + ff_len];
3506 Some(d)
3507 } else {
3508 None
3509 };
3510 if let Some(d) = digit {
3511 result.push_str("ff");
3512 result.push(d);
3513 i += 3;
3514 } else {
3515 result.push_str("ff9");
3517 i += 2;
3518 }
3519 } else if remaining_upper.starts_with("AM") || remaining_upper.starts_with("PM") {
3520 result.push_str("pm");
3521 i += 2;
3522 } else if remaining_upper.starts_with("TZH") {
3523 result.push_str("tzh");
3524 i += 3;
3525 } else if remaining_upper.starts_with("TZM") {
3526 result.push_str("tzm");
3527 i += 3;
3528 } else {
3529 result.push(chars[i]);
3531 i += 1;
3532 }
3533 }
3534 result
3535 }
3536
3537 fn normalize_format_arg(expr: Expression) -> Expression {
3539 if let Expression::Literal(lit) = &expr {
3540 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3541 let normalized = Self::normalize_snowflake_format(s);
3542 Expression::Literal(Box::new(crate::expressions::Literal::String(normalized)))
3543 } else {
3544 expr.clone()
3545 }
3546 } else {
3547 expr
3548 }
3549 }
3550
3551 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3554 use crate::expressions::{DataType, LambdaExpr};
3555 use std::collections::HashMap;
3556
3557 let mut param_types: HashMap<String, DataType> = HashMap::new();
3559 for (i, param) in lambda.parameters.iter().enumerate() {
3560 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3561 param_types.insert(param.name.to_uppercase(), dt.clone());
3562 }
3563 }
3564
3565 if param_types.is_empty() {
3567 return Expression::Lambda(Box::new(lambda));
3568 }
3569
3570 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3572
3573 Expression::Lambda(Box::new(LambdaExpr {
3575 parameters: lambda.parameters,
3576 body: transformed_body,
3577 colon: lambda.colon,
3578 parameter_types: Vec::new(), }))
3580 }
3581
3582 fn replace_lambda_params_with_cast(
3584 &self,
3585 expr: Expression,
3586 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3587 ) -> Expression {
3588 use crate::expressions::{BinaryOp, Cast, Paren};
3589
3590 match expr {
3591 Expression::Column(col) if col.table.is_none() => {
3593 let name_upper = col.name.name.to_uppercase();
3594 if let Some(dt) = param_types.get(&name_upper) {
3595 Expression::Cast(Box::new(Cast {
3597 this: Expression::Column(col),
3598 to: dt.clone(),
3599 double_colon_syntax: false,
3600 trailing_comments: Vec::new(),
3601 format: None,
3602 default: None,
3603 inferred_type: None,
3604 }))
3605 } else {
3606 Expression::Column(col)
3607 }
3608 }
3609
3610 Expression::Identifier(id) => {
3612 let name_upper = id.name.to_uppercase();
3613 if let Some(dt) = param_types.get(&name_upper) {
3614 Expression::Cast(Box::new(Cast {
3616 this: Expression::Identifier(id),
3617 to: dt.clone(),
3618 double_colon_syntax: false,
3619 trailing_comments: Vec::new(),
3620 format: None,
3621 default: None,
3622 inferred_type: None,
3623 }))
3624 } else {
3625 Expression::Identifier(id)
3626 }
3627 }
3628
3629 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3631 self.replace_lambda_params_with_cast(op.left, param_types),
3632 self.replace_lambda_params_with_cast(op.right, param_types),
3633 ))),
3634 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3635 self.replace_lambda_params_with_cast(op.left, param_types),
3636 self.replace_lambda_params_with_cast(op.right, param_types),
3637 ))),
3638 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3639 self.replace_lambda_params_with_cast(op.left, param_types),
3640 self.replace_lambda_params_with_cast(op.right, param_types),
3641 ))),
3642 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3643 self.replace_lambda_params_with_cast(op.left, param_types),
3644 self.replace_lambda_params_with_cast(op.right, param_types),
3645 ))),
3646 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3647 self.replace_lambda_params_with_cast(op.left, param_types),
3648 self.replace_lambda_params_with_cast(op.right, param_types),
3649 ))),
3650
3651 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3653 this: self.replace_lambda_params_with_cast(p.this, param_types),
3654 trailing_comments: p.trailing_comments,
3655 })),
3656
3657 Expression::Function(mut f) => {
3659 f.args = f
3660 .args
3661 .into_iter()
3662 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3663 .collect();
3664 Expression::Function(f)
3665 }
3666
3667 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3669 self.replace_lambda_params_with_cast(op.left, param_types),
3670 self.replace_lambda_params_with_cast(op.right, param_types),
3671 ))),
3672 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3673 self.replace_lambda_params_with_cast(op.left, param_types),
3674 self.replace_lambda_params_with_cast(op.right, param_types),
3675 ))),
3676 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3677 self.replace_lambda_params_with_cast(op.left, param_types),
3678 self.replace_lambda_params_with_cast(op.right, param_types),
3679 ))),
3680 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3681 self.replace_lambda_params_with_cast(op.left, param_types),
3682 self.replace_lambda_params_with_cast(op.right, param_types),
3683 ))),
3684 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3685 self.replace_lambda_params_with_cast(op.left, param_types),
3686 self.replace_lambda_params_with_cast(op.right, param_types),
3687 ))),
3688 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3689 self.replace_lambda_params_with_cast(op.left, param_types),
3690 self.replace_lambda_params_with_cast(op.right, param_types),
3691 ))),
3692
3693 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3695 self.replace_lambda_params_with_cast(op.left, param_types),
3696 self.replace_lambda_params_with_cast(op.right, param_types),
3697 ))),
3698 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3699 self.replace_lambda_params_with_cast(op.left, param_types),
3700 self.replace_lambda_params_with_cast(op.right, param_types),
3701 ))),
3702
3703 other => other,
3705 }
3706 }
3707
3708 fn transform_aggregate_function(
3709 &self,
3710 f: Box<crate::expressions::AggregateFunction>,
3711 ) -> Result<Expression> {
3712 let name_upper = f.name.to_uppercase();
3713 match name_upper.as_str() {
3714 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3716 Function::new("LISTAGG".to_string(), f.args),
3717 ))),
3718
3719 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3721 Function::new("LISTAGG".to_string(), f.args),
3722 ))),
3723
3724 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3726 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3727 ))),
3728
3729 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3731 "BITAND_AGG".to_string(),
3732 f.args,
3733 )))),
3734
3735 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3737 "BITOR_AGG".to_string(),
3738 f.args,
3739 )))),
3740
3741 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3743 "BITXOR_AGG".to_string(),
3744 f.args,
3745 )))),
3746
3747 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3749 let arg = f.args.into_iter().next().unwrap();
3750 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3751 this: arg,
3752 distinct: f.distinct,
3753 filter: f.filter,
3754 order_by: Vec::new(),
3755 name: Some("BOOLAND_AGG".to_string()),
3756 ignore_nulls: None,
3757 having_max: None,
3758 limit: None,
3759 inferred_type: None,
3760 })))
3761 }
3762
3763 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3765 let arg = f.args.into_iter().next().unwrap();
3766 Ok(Expression::LogicalOr(Box::new(AggFunc {
3767 this: arg,
3768 distinct: f.distinct,
3769 filter: f.filter,
3770 order_by: Vec::new(),
3771 name: Some("BOOLOR_AGG".to_string()),
3772 ignore_nulls: None,
3773 having_max: None,
3774 limit: None,
3775 inferred_type: None,
3776 })))
3777 }
3778
3779 "APPROX_TOP_K" if f.args.len() == 1 => {
3781 let mut args = f.args;
3782 args.push(Expression::number(1));
3783 Ok(Expression::AggregateFunction(Box::new(
3784 crate::expressions::AggregateFunction {
3785 name: "APPROX_TOP_K".to_string(),
3786 args,
3787 distinct: f.distinct,
3788 filter: f.filter,
3789 order_by: Vec::new(),
3790 limit: None,
3791 ignore_nulls: None,
3792 inferred_type: None,
3793 },
3794 )))
3795 }
3796
3797 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3799 let arg = f.args.into_iter().next().unwrap();
3800 Ok(Expression::Skewness(Box::new(AggFunc {
3801 this: arg,
3802 distinct: f.distinct,
3803 filter: f.filter,
3804 order_by: Vec::new(),
3805 name: Some("SKEW".to_string()),
3806 ignore_nulls: None,
3807 having_max: None,
3808 limit: None,
3809 inferred_type: None,
3810 })))
3811 }
3812
3813 _ => Ok(Expression::AggregateFunction(f)),
3815 }
3816 }
3817}
3818
3819fn strftime_to_snowflake_format(fmt: &str) -> String {
3821 let mut result = String::new();
3822 let chars: Vec<char> = fmt.chars().collect();
3823 let mut i = 0;
3824 while i < chars.len() {
3825 if chars[i] == '%' && i + 1 < chars.len() {
3826 match chars[i + 1] {
3827 'Y' => {
3828 result.push_str("yyyy");
3829 i += 2;
3830 }
3831 'y' => {
3832 result.push_str("yy");
3833 i += 2;
3834 }
3835 'm' => {
3836 result.push_str("mm");
3837 i += 2;
3838 }
3839 'd' => {
3840 result.push_str("DD");
3841 i += 2;
3842 }
3843 'H' => {
3844 result.push_str("hh24");
3845 i += 2;
3846 }
3847 'M' => {
3848 result.push_str("mmmm");
3849 i += 2;
3850 } 'i' => {
3852 result.push_str("mi");
3853 i += 2;
3854 }
3855 'S' | 's' => {
3856 result.push_str("ss");
3857 i += 2;
3858 }
3859 'f' => {
3860 result.push_str("ff");
3861 i += 2;
3862 }
3863 'w' => {
3864 result.push_str("dy");
3865 i += 2;
3866 } 'a' => {
3868 result.push_str("DY");
3869 i += 2;
3870 } 'b' => {
3872 result.push_str("mon");
3873 i += 2;
3874 } 'T' => {
3876 result.push_str("hh24:mi:ss");
3877 i += 2;
3878 } _ => {
3880 result.push(chars[i]);
3881 result.push(chars[i + 1]);
3882 i += 2;
3883 }
3884 }
3885 } else {
3886 result.push(chars[i]);
3887 i += 1;
3888 }
3889 }
3890 result
3891}
3892
3893#[cfg(test)]
3894mod tests {
3895 use super::*;
3896 use crate::dialects::Dialect;
3897
3898 fn transpile_to_snowflake(sql: &str) -> String {
3899 let dialect = Dialect::get(DialectType::Generic);
3900 let result = dialect
3901 .transpile_to(sql, DialectType::Snowflake)
3902 .expect("Transpile failed");
3903 result[0].clone()
3904 }
3905
3906 #[test]
3907 fn test_ifnull_to_coalesce() {
3908 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
3909 assert!(
3910 result.contains("COALESCE"),
3911 "Expected COALESCE, got: {}",
3912 result
3913 );
3914 }
3915
3916 #[test]
3917 fn test_basic_select() {
3918 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
3919 assert!(result.contains("SELECT"));
3920 assert!(result.contains("FROM users"));
3921 }
3922
3923 #[test]
3924 fn test_group_concat_to_listagg() {
3925 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
3926 assert!(
3927 result.contains("LISTAGG"),
3928 "Expected LISTAGG, got: {}",
3929 result
3930 );
3931 }
3932
3933 #[test]
3934 fn test_string_agg_to_listagg() {
3935 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
3936 assert!(
3937 result.contains("LISTAGG"),
3938 "Expected LISTAGG, got: {}",
3939 result
3940 );
3941 }
3942
3943 #[test]
3944 fn test_array_to_array_construct() {
3945 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
3946 assert!(
3948 result.contains("[1, 2, 3]"),
3949 "Expected [1, 2, 3], got: {}",
3950 result
3951 );
3952 }
3953
3954 #[test]
3955 fn test_double_quote_identifiers() {
3956 let dialect = SnowflakeDialect;
3958 let config = dialect.generator_config();
3959 assert_eq!(config.identifier_quote, '"');
3960 }
3961}