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::Var(v) => Some(v.this.as_str()),
2820 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2821 _ => None,
2822 };
2823 if let Some(name) = unit_name {
2824 let canonical = Self::map_date_part(name).unwrap_or(name);
2825 args[0] = Expression::Literal(Box::new(crate::expressions::Literal::String(
2826 canonical.to_uppercase(),
2827 )));
2828 }
2829 Ok(Expression::Function(Box::new(Function::new(
2830 "DATE_TRUNC".to_string(),
2831 args,
2832 ))))
2833 }
2834
2835 "DATE_PART" if f.args.len() >= 1 => {
2841 let mut args = f.args;
2842 let from_typed_literal = args.len() >= 2
2843 && matches!(
2844 &args[1],
2845 Expression::Literal(lit) if matches!(lit.as_ref(),
2846 crate::expressions::Literal::Timestamp(_)
2847 | crate::expressions::Literal::Date(_)
2848 | crate::expressions::Literal::Time(_)
2849 | crate::expressions::Literal::Datetime(_)
2850 )
2851 );
2852 if from_typed_literal {
2853 args[0] = self.transform_date_part_arg(args[0].clone());
2854 } else {
2855 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2858 }
2859 Ok(Expression::Function(Box::new(Function::new(
2860 "DATE_PART".to_string(),
2861 args,
2862 ))))
2863 }
2864
2865 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2867
2868 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2870
2871 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2873 "DESCRIBE".to_string(),
2874 f.args,
2875 )))),
2876
2877 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2879 "REGEXP_LIKE".to_string(),
2880 f.args,
2881 )))),
2882
2883 "TRANSFORM" => {
2888 let transformed_args: Vec<Expression> = f
2889 .args
2890 .into_iter()
2891 .map(|arg| {
2892 if let Expression::Lambda(lambda) = arg {
2893 self.transform_typed_lambda(*lambda)
2894 } else {
2895 arg
2896 }
2897 })
2898 .collect();
2899 Ok(Expression::Function(Box::new(Function::new(
2900 "TRANSFORM".to_string(),
2901 transformed_args,
2902 ))))
2903 }
2904
2905 "SEARCH" if f.args.len() >= 2 => {
2907 let mut args = f.args.into_iter();
2908 let this = Box::new(args.next().unwrap());
2909 let expression = Box::new(args.next().unwrap());
2910
2911 let mut analyzer: Option<Box<Expression>> = None;
2912 let mut search_mode: Option<Box<Expression>> = None;
2913
2914 for arg in args {
2916 if let Expression::NamedArgument(na) = &arg {
2917 let name_upper = na.name.name.to_uppercase();
2918 match name_upper.as_str() {
2919 "ANALYZER" => analyzer = Some(Box::new(arg)),
2920 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2921 _ => {}
2922 }
2923 }
2924 }
2925
2926 Ok(Expression::Search(Box::new(crate::expressions::Search {
2927 this,
2928 expression,
2929 json_scope: None,
2930 analyzer,
2931 analyzer_options: None,
2932 search_mode,
2933 })))
2934 }
2935
2936 "CONVERT" if f.args.len() == 2 => {
2939 let value = f.args.get(0).cloned().unwrap();
2940 let type_arg = f.args.get(1).cloned().unwrap();
2941
2942 if let Expression::Column(col) = &type_arg {
2944 let type_name = col.name.name.to_uppercase();
2945 let data_type = match type_name.as_str() {
2946 "SQL_DOUBLE" => Some(DataType::Double {
2947 precision: None,
2948 scale: None,
2949 }),
2950 "SQL_VARCHAR" => Some(DataType::VarChar {
2951 length: None,
2952 parenthesized_length: false,
2953 }),
2954 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2955 length: None,
2956 integer_spelling: false,
2957 }),
2958 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2959 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2960 "SQL_FLOAT" => Some(DataType::Float {
2961 precision: None,
2962 scale: None,
2963 real_spelling: false,
2964 }),
2965 "SQL_REAL" => Some(DataType::Float {
2966 precision: None,
2967 scale: None,
2968 real_spelling: true,
2969 }),
2970 "SQL_DECIMAL" => Some(DataType::Decimal {
2971 precision: None,
2972 scale: None,
2973 }),
2974 "SQL_DATE" => Some(DataType::Date),
2975 "SQL_TIME" => Some(DataType::Time {
2976 precision: None,
2977 timezone: false,
2978 }),
2979 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
2980 precision: None,
2981 timezone: false,
2982 }),
2983 _ => None,
2984 };
2985
2986 if let Some(dt) = data_type {
2987 return Ok(Expression::Cast(Box::new(Cast {
2988 this: value,
2989 to: dt,
2990 double_colon_syntax: false,
2991 trailing_comments: vec![],
2992 format: None,
2993 default: None,
2994 inferred_type: None,
2995 })));
2996 }
2997 }
2998 Ok(Expression::Function(Box::new(f)))
3000 }
3001
3002 "TO_TIMESTAMP_TZ" => {
3005 if f.args.len() == 1 {
3006 if let Expression::Literal(lit) = &f.args[0] {
3007 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3008 return Ok(Expression::Cast(Box::new(Cast {
3009 this: f.args.into_iter().next().unwrap(),
3010 to: DataType::Custom {
3011 name: "TIMESTAMPTZ".to_string(),
3012 },
3013 double_colon_syntax: false,
3014 trailing_comments: vec![],
3015 format: None,
3016 default: None,
3017 inferred_type: None,
3018 })));
3019 }
3020 }
3021 }
3022 Ok(Expression::Function(Box::new(f)))
3023 }
3024
3025 "TO_TIMESTAMP_NTZ" => {
3027 if f.args.len() == 1 {
3028 if let Expression::Literal(lit) = &f.args[0] {
3029 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3030 return Ok(Expression::Cast(Box::new(Cast {
3031 this: f.args.into_iter().next().unwrap(),
3032 to: DataType::Custom {
3033 name: "TIMESTAMPNTZ".to_string(),
3034 },
3035 double_colon_syntax: false,
3036 trailing_comments: vec![],
3037 format: None,
3038 default: None,
3039 inferred_type: None,
3040 })));
3041 }
3042 }
3043 }
3044 Ok(Expression::Function(Box::new(f)))
3045 }
3046
3047 "TO_TIMESTAMP_LTZ" => {
3049 if f.args.len() == 1 {
3050 if let Expression::Literal(lit) = &f.args[0] {
3051 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3052 return Ok(Expression::Cast(Box::new(Cast {
3053 this: f.args.into_iter().next().unwrap(),
3054 to: DataType::Custom {
3055 name: "TIMESTAMPLTZ".to_string(),
3056 },
3057 double_colon_syntax: false,
3058 trailing_comments: vec![],
3059 format: None,
3060 default: None,
3061 inferred_type: None,
3062 })));
3063 }
3064 }
3065 }
3066 Ok(Expression::Function(Box::new(f)))
3067 }
3068
3069 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
3071
3072 "REPLACE" if f.args.len() == 2 => {
3074 let mut args = f.args;
3075 args.push(Expression::Literal(Box::new(
3076 crate::expressions::Literal::String(String::new()),
3077 )));
3078 Ok(Expression::Function(Box::new(Function::new(
3079 "REPLACE".to_string(),
3080 args,
3081 ))))
3082 }
3083
3084 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
3086 "ANY_VALUE".to_string(),
3087 f.args,
3088 )))),
3089
3090 "SAFE_DIVIDE" if f.args.len() == 2 => {
3092 let mut args = f.args;
3093 let x = args.remove(0);
3094 let y = args.remove(0);
3095 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3096 condition: Expression::Neq(Box::new(BinaryOp {
3097 left: y.clone(),
3098 right: Expression::number(0),
3099 left_comments: Vec::new(),
3100 operator_comments: Vec::new(),
3101 trailing_comments: Vec::new(),
3102 inferred_type: None,
3103 })),
3104 true_value: Expression::Div(Box::new(BinaryOp {
3105 left: x,
3106 right: y,
3107 left_comments: Vec::new(),
3108 operator_comments: Vec::new(),
3109 trailing_comments: Vec::new(),
3110 inferred_type: None,
3111 })),
3112 false_value: Some(Expression::Null(crate::expressions::Null)),
3113 original_name: Some("IFF".to_string()),
3114 inferred_type: None,
3115 })))
3116 }
3117
3118 "TIMESTAMP" if f.args.len() == 1 => {
3120 let arg = f.args.into_iter().next().unwrap();
3121 Ok(Expression::Cast(Box::new(Cast {
3122 this: arg,
3123 to: DataType::Custom {
3124 name: "TIMESTAMPTZ".to_string(),
3125 },
3126 trailing_comments: Vec::new(),
3127 double_colon_syntax: false,
3128 format: None,
3129 default: None,
3130 inferred_type: None,
3131 })))
3132 }
3133
3134 "TIMESTAMP" if f.args.len() == 2 => {
3136 let mut args = f.args;
3137 let value = args.remove(0);
3138 let tz = args.remove(0);
3139 Ok(Expression::Function(Box::new(Function::new(
3140 "CONVERT_TIMEZONE".to_string(),
3141 vec![
3142 tz,
3143 Expression::Cast(Box::new(Cast {
3144 this: value,
3145 to: DataType::Timestamp {
3146 precision: None,
3147 timezone: false,
3148 },
3149 trailing_comments: Vec::new(),
3150 double_colon_syntax: false,
3151 format: None,
3152 default: None,
3153 inferred_type: None,
3154 })),
3155 ],
3156 ))))
3157 }
3158
3159 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3161 "TIME_FROM_PARTS".to_string(),
3162 f.args,
3163 )))),
3164
3165 "DIV0" if f.args.len() == 2 => {
3167 let mut args = f.args;
3168 let x = args.remove(0);
3169 let y = args.remove(0);
3170 let x_expr = Self::maybe_paren(x.clone());
3172 let y_expr = Self::maybe_paren(y.clone());
3173 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3174 condition: Expression::And(Box::new(BinaryOp::new(
3175 Expression::Eq(Box::new(BinaryOp::new(
3176 y_expr.clone(),
3177 Expression::number(0),
3178 ))),
3179 Expression::Not(Box::new(crate::expressions::UnaryOp {
3180 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3181 this: x_expr.clone(),
3182 not: false,
3183 postfix_form: false,
3184 })),
3185 inferred_type: None,
3186 })),
3187 ))),
3188 true_value: Expression::number(0),
3189 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3190 original_name: Some("IFF".to_string()),
3191 inferred_type: None,
3192 })))
3193 }
3194
3195 "DIV0NULL" if f.args.len() == 2 => {
3197 let mut args = f.args;
3198 let x = args.remove(0);
3199 let y = args.remove(0);
3200 let x_expr = Self::maybe_paren(x.clone());
3201 let y_expr = Self::maybe_paren(y.clone());
3202 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3203 condition: Expression::Or(Box::new(BinaryOp::new(
3204 Expression::Eq(Box::new(BinaryOp::new(
3205 y_expr.clone(),
3206 Expression::number(0),
3207 ))),
3208 Expression::IsNull(Box::new(crate::expressions::IsNull {
3209 this: y_expr.clone(),
3210 not: false,
3211 postfix_form: false,
3212 })),
3213 ))),
3214 true_value: Expression::number(0),
3215 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3216 original_name: Some("IFF".to_string()),
3217 inferred_type: None,
3218 })))
3219 }
3220
3221 "ZEROIFNULL" if f.args.len() == 1 => {
3223 let x = f.args.into_iter().next().unwrap();
3224 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3225 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3226 this: x.clone(),
3227 not: false,
3228 postfix_form: false,
3229 })),
3230 true_value: Expression::number(0),
3231 false_value: Some(x),
3232 original_name: Some("IFF".to_string()),
3233 inferred_type: None,
3234 })))
3235 }
3236
3237 "NULLIFZERO" if f.args.len() == 1 => {
3239 let x = f.args.into_iter().next().unwrap();
3240 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3241 condition: Expression::Eq(Box::new(BinaryOp::new(
3242 x.clone(),
3243 Expression::number(0),
3244 ))),
3245 true_value: Expression::Null(crate::expressions::Null),
3246 false_value: Some(x),
3247 original_name: Some("IFF".to_string()),
3248 inferred_type: None,
3249 })))
3250 }
3251
3252 "TRY_TO_TIME" => {
3254 if f.args.len() == 1 {
3255 if let Expression::Literal(lit) = &f.args[0] {
3256 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3257 return Ok(Expression::TryCast(Box::new(Cast {
3258 this: f.args.into_iter().next().unwrap(),
3259 to: crate::expressions::DataType::Time {
3260 precision: None,
3261 timezone: false,
3262 },
3263 double_colon_syntax: false,
3264 trailing_comments: Vec::new(),
3265 format: None,
3266 default: None,
3267 inferred_type: None,
3268 })));
3269 }
3270 }
3271 }
3272 let mut args = f.args;
3274 if args.len() >= 2 {
3275 args[1] = Self::normalize_format_arg(args[1].clone());
3276 }
3277 Ok(Expression::Function(Box::new(Function::new(
3278 "TRY_TO_TIME".to_string(),
3279 args,
3280 ))))
3281 }
3282
3283 "TRY_TO_TIMESTAMP" => {
3286 if f.args.len() == 1 {
3287 if let Expression::Literal(lit) = &f.args[0] {
3288 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3289 if !Self::looks_like_epoch(s) {
3290 return Ok(Expression::TryCast(Box::new(Cast {
3291 this: f.args.into_iter().next().unwrap(),
3292 to: DataType::Timestamp {
3293 precision: None,
3294 timezone: false,
3295 },
3296 double_colon_syntax: false,
3297 trailing_comments: Vec::new(),
3298 format: None,
3299 default: None,
3300 inferred_type: None,
3301 })));
3302 }
3303 }
3304 }
3305 }
3306 let mut args = f.args;
3308 if args.len() >= 2 {
3309 args[1] = Self::normalize_format_arg(args[1].clone());
3310 }
3311 Ok(Expression::Function(Box::new(Function::new(
3312 "TRY_TO_TIMESTAMP".to_string(),
3313 args,
3314 ))))
3315 }
3316
3317 "TRY_TO_DATE" => {
3319 if f.args.len() == 1 {
3320 if let Expression::Literal(lit) = &f.args[0] {
3321 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3322 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3324 return Ok(Expression::TryCast(Box::new(Cast {
3325 this: f.args.into_iter().next().unwrap(),
3326 to: crate::expressions::DataType::Date,
3327 double_colon_syntax: false,
3328 trailing_comments: Vec::new(),
3329 format: None,
3330 default: None,
3331 inferred_type: None,
3332 })));
3333 }
3334 }
3335 }
3336 }
3337 let mut args = f.args;
3339 if args.len() >= 2 {
3340 args[1] = Self::normalize_format_arg(args[1].clone());
3341 }
3342 Ok(Expression::Function(Box::new(Function::new(
3343 "TRY_TO_DATE".to_string(),
3344 args,
3345 ))))
3346 }
3347
3348 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3350
3351 "REGEXP_REPLACE" if f.args.len() == 2 => {
3353 let mut args = f.args;
3354 args.push(Expression::Literal(Box::new(
3355 crate::expressions::Literal::String(String::new()),
3356 )));
3357 Ok(Expression::Function(Box::new(Function::new(
3358 "REGEXP_REPLACE".to_string(),
3359 args,
3360 ))))
3361 }
3362
3363 "LAST_DAY" if f.args.len() == 2 => {
3365 let mut args = f.args;
3366 let date = args.remove(0);
3367 let unit = args.remove(0);
3368 let unit_str = match &unit {
3369 Expression::Column(c) => c.name.name.to_uppercase(),
3370 Expression::Identifier(i) => i.name.to_uppercase(),
3371 _ => String::new(),
3372 };
3373 if unit_str == "MONTH" {
3374 Ok(Expression::Function(Box::new(Function::new(
3375 "LAST_DAY".to_string(),
3376 vec![date],
3377 ))))
3378 } else {
3379 Ok(Expression::Function(Box::new(Function::new(
3380 "LAST_DAY".to_string(),
3381 vec![date, unit],
3382 ))))
3383 }
3384 }
3385
3386 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3388 "DATE_PART".to_string(),
3389 f.args,
3390 )))),
3391
3392 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3394 let mut args = f.args;
3395 let this = args.remove(0);
3396 let expr = args.remove(0);
3397 Ok(Expression::EndsWith(Box::new(
3398 crate::expressions::BinaryFunc {
3399 original_name: None,
3400 this,
3401 expression: expr,
3402 inferred_type: None,
3403 },
3404 )))
3405 }
3406
3407 _ => Ok(Expression::Function(Box::new(f))),
3409 }
3410 }
3411
3412 fn looks_like_datetime(s: &str) -> bool {
3414 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3417 }
3418
3419 fn looks_like_epoch(s: &str) -> bool {
3421 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3422 }
3423
3424 fn maybe_paren(expr: Expression) -> Expression {
3426 match &expr {
3427 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3428 Expression::Paren(Box::new(crate::expressions::Paren {
3429 this: expr,
3430 trailing_comments: Vec::new(),
3431 }))
3432 }
3433 _ => expr,
3434 }
3435 }
3436
3437 fn normalize_snowflake_format(format: &str) -> String {
3441 let mut result = String::new();
3442 let chars: Vec<char> = format.chars().collect();
3443 let mut i = 0;
3444 while i < chars.len() {
3445 if chars[i] == '"' {
3447 i += 1;
3448 while i < chars.len() && chars[i] != '"' {
3449 result.push(chars[i]);
3450 i += 1;
3451 }
3452 if i < chars.len() {
3453 i += 1; }
3455 continue;
3456 }
3457
3458 let remaining = &format[i..];
3459 let remaining_upper = remaining.to_uppercase();
3460
3461 if remaining_upper.starts_with("YYYY") {
3463 result.push_str("yyyy");
3464 i += 4;
3465 } else if remaining_upper.starts_with("YY") {
3466 result.push_str("yy");
3467 i += 2;
3468 } else if remaining_upper.starts_with("MMMM") {
3469 result.push_str("mmmm");
3470 i += 4;
3471 } else if remaining_upper.starts_with("MON") {
3472 result.push_str("mon");
3473 i += 3;
3474 } else if remaining_upper.starts_with("MM") {
3475 result.push_str("mm");
3476 i += 2;
3477 } else if remaining_upper.starts_with("DD") {
3478 result.push_str("DD");
3479 i += 2;
3480 } else if remaining_upper.starts_with("DY") {
3481 result.push_str("dy");
3482 i += 2;
3483 } else if remaining_upper.starts_with("HH24") {
3484 result.push_str("hh24");
3485 i += 4;
3486 } else if remaining_upper.starts_with("HH12") {
3487 result.push_str("hh12");
3488 i += 4;
3489 } else if remaining_upper.starts_with("HH") {
3490 result.push_str("hh");
3491 i += 2;
3492 } else if remaining_upper.starts_with("MISS") {
3493 result.push_str("miss");
3495 i += 4;
3496 } else if remaining_upper.starts_with("MI") {
3497 result.push_str("mi");
3498 i += 2;
3499 } else if remaining_upper.starts_with("SS") {
3500 result.push_str("ss");
3501 i += 2;
3502 } else if remaining_upper.starts_with("FF") {
3503 let ff_len = 2;
3505 let digit = if i + ff_len < chars.len() && chars[i + ff_len].is_ascii_digit() {
3506 let d = chars[i + ff_len];
3507 Some(d)
3508 } else {
3509 None
3510 };
3511 if let Some(d) = digit {
3512 result.push_str("ff");
3513 result.push(d);
3514 i += 3;
3515 } else {
3516 result.push_str("ff9");
3518 i += 2;
3519 }
3520 } else if remaining_upper.starts_with("AM") || remaining_upper.starts_with("PM") {
3521 result.push_str("pm");
3522 i += 2;
3523 } else if remaining_upper.starts_with("TZH") {
3524 result.push_str("tzh");
3525 i += 3;
3526 } else if remaining_upper.starts_with("TZM") {
3527 result.push_str("tzm");
3528 i += 3;
3529 } else {
3530 result.push(chars[i]);
3532 i += 1;
3533 }
3534 }
3535 result
3536 }
3537
3538 fn normalize_format_arg(expr: Expression) -> Expression {
3540 if let Expression::Literal(lit) = &expr {
3541 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3542 let normalized = Self::normalize_snowflake_format(s);
3543 Expression::Literal(Box::new(crate::expressions::Literal::String(normalized)))
3544 } else {
3545 expr.clone()
3546 }
3547 } else {
3548 expr
3549 }
3550 }
3551
3552 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3555 use crate::expressions::{DataType, LambdaExpr};
3556 use std::collections::HashMap;
3557
3558 let mut param_types: HashMap<String, DataType> = HashMap::new();
3560 for (i, param) in lambda.parameters.iter().enumerate() {
3561 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3562 param_types.insert(param.name.to_uppercase(), dt.clone());
3563 }
3564 }
3565
3566 if param_types.is_empty() {
3568 return Expression::Lambda(Box::new(lambda));
3569 }
3570
3571 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3573
3574 Expression::Lambda(Box::new(LambdaExpr {
3576 parameters: lambda.parameters,
3577 body: transformed_body,
3578 colon: lambda.colon,
3579 parameter_types: Vec::new(), }))
3581 }
3582
3583 fn replace_lambda_params_with_cast(
3585 &self,
3586 expr: Expression,
3587 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3588 ) -> Expression {
3589 use crate::expressions::{BinaryOp, Cast, Paren};
3590
3591 match expr {
3592 Expression::Column(col) if col.table.is_none() => {
3594 let name_upper = col.name.name.to_uppercase();
3595 if let Some(dt) = param_types.get(&name_upper) {
3596 Expression::Cast(Box::new(Cast {
3598 this: Expression::Column(col),
3599 to: dt.clone(),
3600 double_colon_syntax: false,
3601 trailing_comments: Vec::new(),
3602 format: None,
3603 default: None,
3604 inferred_type: None,
3605 }))
3606 } else {
3607 Expression::Column(col)
3608 }
3609 }
3610
3611 Expression::Identifier(id) => {
3613 let name_upper = id.name.to_uppercase();
3614 if let Some(dt) = param_types.get(&name_upper) {
3615 Expression::Cast(Box::new(Cast {
3617 this: Expression::Identifier(id),
3618 to: dt.clone(),
3619 double_colon_syntax: false,
3620 trailing_comments: Vec::new(),
3621 format: None,
3622 default: None,
3623 inferred_type: None,
3624 }))
3625 } else {
3626 Expression::Identifier(id)
3627 }
3628 }
3629
3630 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3632 self.replace_lambda_params_with_cast(op.left, param_types),
3633 self.replace_lambda_params_with_cast(op.right, param_types),
3634 ))),
3635 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3636 self.replace_lambda_params_with_cast(op.left, param_types),
3637 self.replace_lambda_params_with_cast(op.right, param_types),
3638 ))),
3639 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3640 self.replace_lambda_params_with_cast(op.left, param_types),
3641 self.replace_lambda_params_with_cast(op.right, param_types),
3642 ))),
3643 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3644 self.replace_lambda_params_with_cast(op.left, param_types),
3645 self.replace_lambda_params_with_cast(op.right, param_types),
3646 ))),
3647 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3648 self.replace_lambda_params_with_cast(op.left, param_types),
3649 self.replace_lambda_params_with_cast(op.right, param_types),
3650 ))),
3651
3652 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3654 this: self.replace_lambda_params_with_cast(p.this, param_types),
3655 trailing_comments: p.trailing_comments,
3656 })),
3657
3658 Expression::Function(mut f) => {
3660 f.args = f
3661 .args
3662 .into_iter()
3663 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3664 .collect();
3665 Expression::Function(f)
3666 }
3667
3668 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3670 self.replace_lambda_params_with_cast(op.left, param_types),
3671 self.replace_lambda_params_with_cast(op.right, param_types),
3672 ))),
3673 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3674 self.replace_lambda_params_with_cast(op.left, param_types),
3675 self.replace_lambda_params_with_cast(op.right, param_types),
3676 ))),
3677 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3678 self.replace_lambda_params_with_cast(op.left, param_types),
3679 self.replace_lambda_params_with_cast(op.right, param_types),
3680 ))),
3681 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3682 self.replace_lambda_params_with_cast(op.left, param_types),
3683 self.replace_lambda_params_with_cast(op.right, param_types),
3684 ))),
3685 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3686 self.replace_lambda_params_with_cast(op.left, param_types),
3687 self.replace_lambda_params_with_cast(op.right, param_types),
3688 ))),
3689 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3690 self.replace_lambda_params_with_cast(op.left, param_types),
3691 self.replace_lambda_params_with_cast(op.right, param_types),
3692 ))),
3693
3694 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3696 self.replace_lambda_params_with_cast(op.left, param_types),
3697 self.replace_lambda_params_with_cast(op.right, param_types),
3698 ))),
3699 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3700 self.replace_lambda_params_with_cast(op.left, param_types),
3701 self.replace_lambda_params_with_cast(op.right, param_types),
3702 ))),
3703
3704 other => other,
3706 }
3707 }
3708
3709 fn transform_aggregate_function(
3710 &self,
3711 f: Box<crate::expressions::AggregateFunction>,
3712 ) -> Result<Expression> {
3713 let name_upper = f.name.to_uppercase();
3714 match name_upper.as_str() {
3715 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3717 Function::new("LISTAGG".to_string(), f.args),
3718 ))),
3719
3720 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3722 Function::new("LISTAGG".to_string(), f.args),
3723 ))),
3724
3725 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3727 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3728 ))),
3729
3730 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3732 "BITAND_AGG".to_string(),
3733 f.args,
3734 )))),
3735
3736 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3738 "BITOR_AGG".to_string(),
3739 f.args,
3740 )))),
3741
3742 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3744 "BITXOR_AGG".to_string(),
3745 f.args,
3746 )))),
3747
3748 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3750 let arg = f.args.into_iter().next().unwrap();
3751 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3752 this: arg,
3753 distinct: f.distinct,
3754 filter: f.filter,
3755 order_by: Vec::new(),
3756 name: Some("BOOLAND_AGG".to_string()),
3757 ignore_nulls: None,
3758 having_max: None,
3759 limit: None,
3760 inferred_type: None,
3761 })))
3762 }
3763
3764 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3766 let arg = f.args.into_iter().next().unwrap();
3767 Ok(Expression::LogicalOr(Box::new(AggFunc {
3768 this: arg,
3769 distinct: f.distinct,
3770 filter: f.filter,
3771 order_by: Vec::new(),
3772 name: Some("BOOLOR_AGG".to_string()),
3773 ignore_nulls: None,
3774 having_max: None,
3775 limit: None,
3776 inferred_type: None,
3777 })))
3778 }
3779
3780 "APPROX_TOP_K" if f.args.len() == 1 => {
3782 let mut args = f.args;
3783 args.push(Expression::number(1));
3784 Ok(Expression::AggregateFunction(Box::new(
3785 crate::expressions::AggregateFunction {
3786 name: "APPROX_TOP_K".to_string(),
3787 args,
3788 distinct: f.distinct,
3789 filter: f.filter,
3790 order_by: Vec::new(),
3791 limit: None,
3792 ignore_nulls: None,
3793 inferred_type: None,
3794 },
3795 )))
3796 }
3797
3798 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3800 let arg = f.args.into_iter().next().unwrap();
3801 Ok(Expression::Skewness(Box::new(AggFunc {
3802 this: arg,
3803 distinct: f.distinct,
3804 filter: f.filter,
3805 order_by: Vec::new(),
3806 name: Some("SKEW".to_string()),
3807 ignore_nulls: None,
3808 having_max: None,
3809 limit: None,
3810 inferred_type: None,
3811 })))
3812 }
3813
3814 _ => Ok(Expression::AggregateFunction(f)),
3816 }
3817 }
3818}
3819
3820fn strftime_to_snowflake_format(fmt: &str) -> String {
3822 let mut result = String::new();
3823 let chars: Vec<char> = fmt.chars().collect();
3824 let mut i = 0;
3825 while i < chars.len() {
3826 if chars[i] == '%' && i + 1 < chars.len() {
3827 match chars[i + 1] {
3828 'Y' => {
3829 result.push_str("yyyy");
3830 i += 2;
3831 }
3832 'y' => {
3833 result.push_str("yy");
3834 i += 2;
3835 }
3836 'm' => {
3837 result.push_str("mm");
3838 i += 2;
3839 }
3840 'd' => {
3841 result.push_str("DD");
3842 i += 2;
3843 }
3844 'H' => {
3845 result.push_str("hh24");
3846 i += 2;
3847 }
3848 'M' => {
3849 result.push_str("mmmm");
3850 i += 2;
3851 } 'i' => {
3853 result.push_str("mi");
3854 i += 2;
3855 }
3856 'S' | 's' => {
3857 result.push_str("ss");
3858 i += 2;
3859 }
3860 'f' => {
3861 result.push_str("ff");
3862 i += 2;
3863 }
3864 'w' => {
3865 result.push_str("dy");
3866 i += 2;
3867 } 'a' => {
3869 result.push_str("DY");
3870 i += 2;
3871 } 'b' => {
3873 result.push_str("mon");
3874 i += 2;
3875 } 'T' => {
3877 result.push_str("hh24:mi:ss");
3878 i += 2;
3879 } _ => {
3881 result.push(chars[i]);
3882 result.push(chars[i + 1]);
3883 i += 2;
3884 }
3885 }
3886 } else {
3887 result.push(chars[i]);
3888 i += 1;
3889 }
3890 }
3891 result
3892}
3893
3894#[cfg(test)]
3895mod tests {
3896 use super::*;
3897 use crate::dialects::Dialect;
3898
3899 fn transpile_to_snowflake(sql: &str) -> String {
3900 let dialect = Dialect::get(DialectType::Generic);
3901 let result = dialect
3902 .transpile_to(sql, DialectType::Snowflake)
3903 .expect("Transpile failed");
3904 result[0].clone()
3905 }
3906
3907 #[test]
3908 fn test_ifnull_to_coalesce() {
3909 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
3910 assert!(
3911 result.contains("COALESCE"),
3912 "Expected COALESCE, got: {}",
3913 result
3914 );
3915 }
3916
3917 #[test]
3918 fn test_basic_select() {
3919 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
3920 assert!(result.contains("SELECT"));
3921 assert!(result.contains("FROM users"));
3922 }
3923
3924 #[test]
3925 fn test_group_concat_to_listagg() {
3926 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
3927 assert!(
3928 result.contains("LISTAGG"),
3929 "Expected LISTAGG, got: {}",
3930 result
3931 );
3932 }
3933
3934 #[test]
3935 fn test_string_agg_to_listagg() {
3936 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
3937 assert!(
3938 result.contains("LISTAGG"),
3939 "Expected LISTAGG, got: {}",
3940 result
3941 );
3942 }
3943
3944 #[test]
3945 fn test_array_to_array_construct() {
3946 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
3947 assert!(
3949 result.contains("[1, 2, 3]"),
3950 "Expected [1, 2, 3], got: {}",
3951 result
3952 );
3953 }
3954
3955 #[test]
3956 fn test_double_quote_identifiers() {
3957 let dialect = SnowflakeDialect;
3959 let config = dialect.generator_config();
3960 assert_eq!(config.identifier_quote, '"');
3961 }
3962}