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 "STRTOK_TO_ARRAY" if f.args.len() == 1 => {
2396 let mut args = f.args;
2397 args.push(Expression::string(" ".to_string()));
2398 Ok(Expression::Function(Box::new(Function::new(
2399 "STRTOK_TO_ARRAY".to_string(),
2400 args,
2401 ))))
2402 }
2403
2404 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2406 "WEEK".to_string(),
2407 f.args,
2408 )))),
2409
2410 "LIKE" if f.args.len() >= 2 => {
2412 let mut args = f.args.into_iter();
2413 let left = args.next().unwrap();
2414 let right = args.next().unwrap();
2415 let escape = args.next();
2416 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2417 left,
2418 right,
2419 escape,
2420 quantifier: None,
2421 inferred_type: None,
2422 })))
2423 }
2424
2425 "ILIKE" if f.args.len() >= 2 => {
2427 let mut args = f.args.into_iter();
2428 let left = args.next().unwrap();
2429 let right = args.next().unwrap();
2430 let escape = args.next();
2431 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2432 left,
2433 right,
2434 escape,
2435 quantifier: None,
2436 inferred_type: None,
2437 })))
2438 }
2439
2440 "RLIKE" if f.args.len() >= 2 => {
2442 let mut args = f.args.into_iter();
2443 let left = args.next().unwrap();
2444 let pattern = args.next().unwrap();
2445 let flags = args.next();
2446 Ok(Expression::RegexpLike(Box::new(
2447 crate::expressions::RegexpFunc {
2448 this: left,
2449 pattern,
2450 flags,
2451 },
2452 )))
2453 }
2454
2455 "IFF" if f.args.len() >= 2 => {
2457 let mut args = f.args;
2458 let condition = args.remove(0);
2459 let true_value = args.remove(0);
2460 let false_value = if !args.is_empty() {
2461 Some(args.remove(0))
2462 } else {
2463 None
2464 };
2465 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2466 condition,
2467 true_value,
2468 false_value,
2469 original_name: Some("IFF".to_string()),
2470 inferred_type: None,
2471 })))
2472 }
2473
2474 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2476 Ok(Expression::Function(Box::new(Function::new(
2477 "TIMESTAMP_FROM_PARTS".to_string(),
2478 f.args,
2479 ))))
2480 }
2481
2482 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2484 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2485 f.args,
2486 )))),
2487
2488 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2490 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2491 f.args,
2492 )))),
2493
2494 "DATEADD" if f.args.len() >= 1 => {
2496 let mut args = f.args;
2497 args[0] = self.transform_date_part_arg(args[0].clone());
2498 Ok(Expression::Function(Box::new(Function::new(
2499 "DATEADD".to_string(),
2500 args,
2501 ))))
2502 }
2503
2504 "DATEDIFF" if f.args.len() >= 1 => {
2507 let mut args = f.args;
2508 args[0] = self.transform_date_part_arg(args[0].clone());
2509 for i in 1..args.len() {
2512 if let Expression::Function(ref func) = args[i] {
2513 if func.name == "_POLYGLOT_TO_DATE" {
2514 let inner_args = func.args.clone();
2515 args[i] = Expression::Function(Box::new(Function::new(
2516 "TO_DATE".to_string(),
2517 inner_args,
2518 )));
2519 }
2520 }
2521 }
2522 Ok(Expression::Function(Box::new(Function::new(
2523 "DATEDIFF".to_string(),
2524 args,
2525 ))))
2526 }
2527
2528 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2530 "DATEDIFF".to_string(),
2531 f.args,
2532 )))),
2533
2534 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2536 "DATEDIFF".to_string(),
2537 f.args,
2538 )))),
2539
2540 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2542 "DATEADD".to_string(),
2543 f.args,
2544 )))),
2545
2546 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2548
2549 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2551 "DATE_FROM_PARTS".to_string(),
2552 f.args,
2553 )))),
2554
2555 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2557 "TIME_FROM_PARTS".to_string(),
2558 f.args,
2559 )))),
2560
2561 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2563
2564 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2566
2567 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2569
2570 "MONTHNAME" if f.args.len() == 1 => {
2573 let arg = f.args.into_iter().next().unwrap();
2574 Ok(Expression::Monthname(Box::new(
2575 crate::expressions::Monthname {
2576 this: Box::new(arg),
2577 abbreviated: Some(Box::new(Expression::Literal(Box::new(
2578 Literal::String("true".to_string()),
2579 )))),
2580 },
2581 )))
2582 }
2583
2584 "DAYNAME" if f.args.len() == 1 => {
2587 let arg = f.args.into_iter().next().unwrap();
2588 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2589 this: Box::new(arg),
2590 abbreviated: Some(Box::new(Expression::Literal(Box::new(Literal::String(
2591 "true".to_string(),
2592 ))))),
2593 })))
2594 }
2595
2596 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2598 let arg = f.args.into_iter().next().unwrap();
2599 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2600 this: arg,
2601 distinct: false,
2602 filter: None,
2603 order_by: Vec::new(),
2604 name: Some("BOOLAND_AGG".to_string()),
2605 ignore_nulls: None,
2606 having_max: None,
2607 limit: None,
2608 inferred_type: None,
2609 })))
2610 }
2611
2612 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2614 let arg = f.args.into_iter().next().unwrap();
2615 Ok(Expression::LogicalOr(Box::new(AggFunc {
2616 this: arg,
2617 distinct: false,
2618 filter: None,
2619 order_by: Vec::new(),
2620 name: Some("BOOLOR_AGG".to_string()),
2621 ignore_nulls: None,
2622 having_max: None,
2623 limit: None,
2624 inferred_type: None,
2625 })))
2626 }
2627
2628 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2630 let arg = f.args.into_iter().next().unwrap();
2631 Ok(Expression::Skewness(Box::new(AggFunc {
2632 this: arg,
2633 distinct: false,
2634 filter: None,
2635 order_by: Vec::new(),
2636 name: Some("SKEW".to_string()),
2637 ignore_nulls: None,
2638 having_max: None,
2639 limit: None,
2640 inferred_type: None,
2641 })))
2642 }
2643
2644 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2646 "VARIANCE".to_string(),
2647 f.args,
2648 )))),
2649
2650 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2652 "VARIANCE_POP".to_string(),
2653 f.args,
2654 )))),
2655
2656 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2658 "TO_DATE".to_string(),
2659 f.args,
2660 )))),
2661 "DATE" if f.args.len() >= 2 => {
2665 let mut args = f.args;
2666 args[1] = Self::normalize_format_arg(args[1].clone());
2667 Ok(Expression::Function(Box::new(Function::new(
2668 "TO_DATE".to_string(),
2669 args,
2670 ))))
2671 }
2672 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2675 let mut args = f.args;
2676 args[1] = Self::normalize_format_arg(args[1].clone());
2677 Ok(Expression::Function(Box::new(Function::new(
2678 "DATE".to_string(),
2679 args,
2680 ))))
2681 }
2682
2683 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2685
2686 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2688 "MD5".to_string(),
2689 f.args,
2690 )))),
2691
2692 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2694 "SHA1".to_string(),
2695 f.args,
2696 )))),
2697
2698 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2700 "SHA2".to_string(),
2701 f.args,
2702 )))),
2703
2704 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2706 "EDITDISTANCE".to_string(),
2707 f.args,
2708 )))),
2709
2710 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2712 "BITNOT".to_string(),
2713 f.args,
2714 )))),
2715
2716 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2718 "BITAND".to_string(),
2719 f.args,
2720 )))),
2721
2722 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2724 "BITOR".to_string(),
2725 f.args,
2726 )))),
2727
2728 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2730 "BITXOR".to_string(),
2731 f.args,
2732 )))),
2733
2734 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2736 Function::new("BITSHIFTLEFT".to_string(), f.args),
2737 ))),
2738
2739 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2741 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2742 ))),
2743
2744 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2746 name: "CURRENT_TIMESTAMP".to_string(),
2747 args: f.args,
2748 distinct: false,
2749 trailing_comments: Vec::new(),
2750 use_bracket_syntax: false,
2751 no_parens: f.no_parens,
2752 quoted: false,
2753 span: None,
2754 inferred_type: None,
2755 }))),
2756
2757 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2759 name: "CURRENT_TIMESTAMP".to_string(),
2760 args: f.args,
2761 distinct: false,
2762 trailing_comments: Vec::new(),
2763 use_bracket_syntax: false,
2764 no_parens: f.no_parens,
2765 quoted: false,
2766 span: None,
2767 inferred_type: None,
2768 }))),
2769
2770 "SPACE" if f.args.len() == 1 => {
2772 let arg = f.args.into_iter().next().unwrap();
2773 Ok(Expression::Function(Box::new(Function::new(
2774 "REPEAT".to_string(),
2775 vec![
2776 Expression::Literal(Box::new(Literal::String(" ".to_string()))),
2777 arg,
2778 ],
2779 ))))
2780 }
2781
2782 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2784 "CEIL".to_string(),
2785 f.args,
2786 )))),
2787
2788 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2790 "LN".to_string(),
2791 f.args,
2792 )))),
2793
2794 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(f))),
2796
2797 "GET_PATH" if f.args.len() >= 2 => {
2801 let mut args = f.args;
2802 if let Expression::Literal(lit) = &args[1] {
2804 if let crate::expressions::Literal::String(path) = lit.as_ref() {
2805 let transformed = Self::transform_json_path(path);
2806 args[1] = Expression::Literal(Box::new(
2807 crate::expressions::Literal::String(transformed),
2808 ));
2809 }
2810 }
2811 Ok(Expression::Function(Box::new(Function::new(
2812 "GET_PATH".to_string(),
2813 args,
2814 ))))
2815 }
2816 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2817
2818 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2820
2821 "DATE_TRUNC" if f.args.len() >= 1 => {
2824 let mut args = f.args;
2825 let unit_name = match &args[0] {
2827 Expression::Identifier(id) => Some(id.name.as_str()),
2828 Expression::Var(v) => Some(v.this.as_str()),
2829 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2830 _ => None,
2831 };
2832 if let Some(name) = unit_name {
2833 let canonical = Self::map_date_part(name).unwrap_or(name);
2834 args[0] = Expression::Literal(Box::new(crate::expressions::Literal::String(
2835 canonical.to_uppercase(),
2836 )));
2837 }
2838 Ok(Expression::Function(Box::new(Function::new(
2839 "DATE_TRUNC".to_string(),
2840 args,
2841 ))))
2842 }
2843
2844 "DATE_PART" if f.args.len() >= 1 => {
2850 let mut args = f.args;
2851 let from_typed_literal = args.len() >= 2
2852 && matches!(
2853 &args[1],
2854 Expression::Literal(lit) if matches!(lit.as_ref(),
2855 crate::expressions::Literal::Timestamp(_)
2856 | crate::expressions::Literal::Date(_)
2857 | crate::expressions::Literal::Time(_)
2858 | crate::expressions::Literal::Datetime(_)
2859 )
2860 );
2861 if from_typed_literal {
2862 args[0] = self.transform_date_part_arg(args[0].clone());
2863 } else {
2864 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2867 }
2868 Ok(Expression::Function(Box::new(Function::new(
2869 "DATE_PART".to_string(),
2870 args,
2871 ))))
2872 }
2873
2874 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2876
2877 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2879
2880 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2882 "DESCRIBE".to_string(),
2883 f.args,
2884 )))),
2885
2886 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2888 "REGEXP_LIKE".to_string(),
2889 f.args,
2890 )))),
2891
2892 "TRANSFORM" => {
2897 let transformed_args: Vec<Expression> = f
2898 .args
2899 .into_iter()
2900 .map(|arg| {
2901 if let Expression::Lambda(lambda) = arg {
2902 self.transform_typed_lambda(*lambda)
2903 } else {
2904 arg
2905 }
2906 })
2907 .collect();
2908 Ok(Expression::Function(Box::new(Function::new(
2909 "TRANSFORM".to_string(),
2910 transformed_args,
2911 ))))
2912 }
2913
2914 "SEARCH" if f.args.len() >= 2 => {
2916 let mut args = f.args.into_iter();
2917 let this = Box::new(args.next().unwrap());
2918 let expression = Box::new(args.next().unwrap());
2919
2920 let mut analyzer: Option<Box<Expression>> = None;
2921 let mut search_mode: Option<Box<Expression>> = None;
2922
2923 for arg in args {
2925 if let Expression::NamedArgument(na) = &arg {
2926 let name_upper = na.name.name.to_uppercase();
2927 match name_upper.as_str() {
2928 "ANALYZER" => analyzer = Some(Box::new(arg)),
2929 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2930 _ => {}
2931 }
2932 }
2933 }
2934
2935 Ok(Expression::Search(Box::new(crate::expressions::Search {
2936 this,
2937 expression,
2938 json_scope: None,
2939 analyzer,
2940 analyzer_options: None,
2941 search_mode,
2942 })))
2943 }
2944
2945 "CONVERT" if f.args.len() == 2 => {
2948 let value = f.args.get(0).cloned().unwrap();
2949 let type_arg = f.args.get(1).cloned().unwrap();
2950
2951 if let Expression::Column(col) = &type_arg {
2953 let type_name = col.name.name.to_uppercase();
2954 let data_type = match type_name.as_str() {
2955 "SQL_DOUBLE" => Some(DataType::Double {
2956 precision: None,
2957 scale: None,
2958 }),
2959 "SQL_VARCHAR" => Some(DataType::VarChar {
2960 length: None,
2961 parenthesized_length: false,
2962 }),
2963 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2964 length: None,
2965 integer_spelling: false,
2966 }),
2967 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2968 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2969 "SQL_FLOAT" => Some(DataType::Float {
2970 precision: None,
2971 scale: None,
2972 real_spelling: false,
2973 }),
2974 "SQL_REAL" => Some(DataType::Float {
2975 precision: None,
2976 scale: None,
2977 real_spelling: true,
2978 }),
2979 "SQL_DECIMAL" => Some(DataType::Decimal {
2980 precision: None,
2981 scale: None,
2982 }),
2983 "SQL_DATE" => Some(DataType::Date),
2984 "SQL_TIME" => Some(DataType::Time {
2985 precision: None,
2986 timezone: false,
2987 }),
2988 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
2989 precision: None,
2990 timezone: false,
2991 }),
2992 _ => None,
2993 };
2994
2995 if let Some(dt) = data_type {
2996 return Ok(Expression::Cast(Box::new(Cast {
2997 this: value,
2998 to: dt,
2999 double_colon_syntax: false,
3000 trailing_comments: vec![],
3001 format: None,
3002 default: None,
3003 inferred_type: None,
3004 })));
3005 }
3006 }
3007 Ok(Expression::Function(Box::new(f)))
3009 }
3010
3011 "TO_TIMESTAMP_TZ" => {
3014 if f.args.len() == 1 {
3015 if let Expression::Literal(lit) = &f.args[0] {
3016 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3017 return Ok(Expression::Cast(Box::new(Cast {
3018 this: f.args.into_iter().next().unwrap(),
3019 to: DataType::Custom {
3020 name: "TIMESTAMPTZ".to_string(),
3021 },
3022 double_colon_syntax: false,
3023 trailing_comments: vec![],
3024 format: None,
3025 default: None,
3026 inferred_type: None,
3027 })));
3028 }
3029 }
3030 }
3031 Ok(Expression::Function(Box::new(f)))
3032 }
3033
3034 "TO_TIMESTAMP_NTZ" => {
3036 if f.args.len() == 1 {
3037 if let Expression::Literal(lit) = &f.args[0] {
3038 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3039 return Ok(Expression::Cast(Box::new(Cast {
3040 this: f.args.into_iter().next().unwrap(),
3041 to: DataType::Custom {
3042 name: "TIMESTAMPNTZ".to_string(),
3043 },
3044 double_colon_syntax: false,
3045 trailing_comments: vec![],
3046 format: None,
3047 default: None,
3048 inferred_type: None,
3049 })));
3050 }
3051 }
3052 }
3053 Ok(Expression::Function(Box::new(f)))
3054 }
3055
3056 "TO_TIMESTAMP_LTZ" => {
3058 if f.args.len() == 1 {
3059 if let Expression::Literal(lit) = &f.args[0] {
3060 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3061 return Ok(Expression::Cast(Box::new(Cast {
3062 this: f.args.into_iter().next().unwrap(),
3063 to: DataType::Custom {
3064 name: "TIMESTAMPLTZ".to_string(),
3065 },
3066 double_colon_syntax: false,
3067 trailing_comments: vec![],
3068 format: None,
3069 default: None,
3070 inferred_type: None,
3071 })));
3072 }
3073 }
3074 }
3075 Ok(Expression::Function(Box::new(f)))
3076 }
3077
3078 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
3080
3081 "REPLACE" if f.args.len() == 2 => {
3083 let mut args = f.args;
3084 args.push(Expression::Literal(Box::new(
3085 crate::expressions::Literal::String(String::new()),
3086 )));
3087 Ok(Expression::Function(Box::new(Function::new(
3088 "REPLACE".to_string(),
3089 args,
3090 ))))
3091 }
3092
3093 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
3095 "ANY_VALUE".to_string(),
3096 f.args,
3097 )))),
3098
3099 "SAFE_DIVIDE" if f.args.len() == 2 => {
3101 let mut args = f.args;
3102 let x = args.remove(0);
3103 let y = args.remove(0);
3104 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3105 condition: Expression::Neq(Box::new(BinaryOp {
3106 left: y.clone(),
3107 right: Expression::number(0),
3108 left_comments: Vec::new(),
3109 operator_comments: Vec::new(),
3110 trailing_comments: Vec::new(),
3111 inferred_type: None,
3112 })),
3113 true_value: Expression::Div(Box::new(BinaryOp {
3114 left: x,
3115 right: y,
3116 left_comments: Vec::new(),
3117 operator_comments: Vec::new(),
3118 trailing_comments: Vec::new(),
3119 inferred_type: None,
3120 })),
3121 false_value: Some(Expression::Null(crate::expressions::Null)),
3122 original_name: Some("IFF".to_string()),
3123 inferred_type: None,
3124 })))
3125 }
3126
3127 "TIMESTAMP" if f.args.len() == 1 => {
3129 let arg = f.args.into_iter().next().unwrap();
3130 Ok(Expression::Cast(Box::new(Cast {
3131 this: arg,
3132 to: DataType::Custom {
3133 name: "TIMESTAMPTZ".to_string(),
3134 },
3135 trailing_comments: Vec::new(),
3136 double_colon_syntax: false,
3137 format: None,
3138 default: None,
3139 inferred_type: None,
3140 })))
3141 }
3142
3143 "TIMESTAMP" if f.args.len() == 2 => {
3145 let mut args = f.args;
3146 let value = args.remove(0);
3147 let tz = args.remove(0);
3148 Ok(Expression::Function(Box::new(Function::new(
3149 "CONVERT_TIMEZONE".to_string(),
3150 vec![
3151 tz,
3152 Expression::Cast(Box::new(Cast {
3153 this: value,
3154 to: DataType::Timestamp {
3155 precision: None,
3156 timezone: false,
3157 },
3158 trailing_comments: Vec::new(),
3159 double_colon_syntax: false,
3160 format: None,
3161 default: None,
3162 inferred_type: None,
3163 })),
3164 ],
3165 ))))
3166 }
3167
3168 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3170 "TIME_FROM_PARTS".to_string(),
3171 f.args,
3172 )))),
3173
3174 "DIV0" if f.args.len() == 2 => {
3176 let mut args = f.args;
3177 let x = args.remove(0);
3178 let y = args.remove(0);
3179 let x_expr = Self::maybe_paren(x.clone());
3181 let y_expr = Self::maybe_paren(y.clone());
3182 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3183 condition: Expression::And(Box::new(BinaryOp::new(
3184 Expression::Eq(Box::new(BinaryOp::new(
3185 y_expr.clone(),
3186 Expression::number(0),
3187 ))),
3188 Expression::Not(Box::new(crate::expressions::UnaryOp {
3189 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3190 this: x_expr.clone(),
3191 not: false,
3192 postfix_form: false,
3193 })),
3194 inferred_type: None,
3195 })),
3196 ))),
3197 true_value: Expression::number(0),
3198 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3199 original_name: Some("IFF".to_string()),
3200 inferred_type: None,
3201 })))
3202 }
3203
3204 "DIV0NULL" if f.args.len() == 2 => {
3206 let mut args = f.args;
3207 let x = args.remove(0);
3208 let y = args.remove(0);
3209 let x_expr = Self::maybe_paren(x.clone());
3210 let y_expr = Self::maybe_paren(y.clone());
3211 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3212 condition: Expression::Or(Box::new(BinaryOp::new(
3213 Expression::Eq(Box::new(BinaryOp::new(
3214 y_expr.clone(),
3215 Expression::number(0),
3216 ))),
3217 Expression::IsNull(Box::new(crate::expressions::IsNull {
3218 this: y_expr.clone(),
3219 not: false,
3220 postfix_form: false,
3221 })),
3222 ))),
3223 true_value: Expression::number(0),
3224 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3225 original_name: Some("IFF".to_string()),
3226 inferred_type: None,
3227 })))
3228 }
3229
3230 "ZEROIFNULL" if f.args.len() == 1 => {
3232 let x = f.args.into_iter().next().unwrap();
3233 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3234 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3235 this: x.clone(),
3236 not: false,
3237 postfix_form: false,
3238 })),
3239 true_value: Expression::number(0),
3240 false_value: Some(x),
3241 original_name: Some("IFF".to_string()),
3242 inferred_type: None,
3243 })))
3244 }
3245
3246 "NULLIFZERO" if f.args.len() == 1 => {
3248 let x = f.args.into_iter().next().unwrap();
3249 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3250 condition: Expression::Eq(Box::new(BinaryOp::new(
3251 x.clone(),
3252 Expression::number(0),
3253 ))),
3254 true_value: Expression::Null(crate::expressions::Null),
3255 false_value: Some(x),
3256 original_name: Some("IFF".to_string()),
3257 inferred_type: None,
3258 })))
3259 }
3260
3261 "TRY_TO_TIME" => {
3263 if f.args.len() == 1 {
3264 if let Expression::Literal(lit) = &f.args[0] {
3265 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3266 return Ok(Expression::TryCast(Box::new(Cast {
3267 this: f.args.into_iter().next().unwrap(),
3268 to: crate::expressions::DataType::Time {
3269 precision: None,
3270 timezone: false,
3271 },
3272 double_colon_syntax: false,
3273 trailing_comments: Vec::new(),
3274 format: None,
3275 default: None,
3276 inferred_type: None,
3277 })));
3278 }
3279 }
3280 }
3281 let mut args = f.args;
3283 if args.len() >= 2 {
3284 args[1] = Self::normalize_format_arg(args[1].clone());
3285 }
3286 Ok(Expression::Function(Box::new(Function::new(
3287 "TRY_TO_TIME".to_string(),
3288 args,
3289 ))))
3290 }
3291
3292 "TRY_TO_TIMESTAMP" => {
3295 if f.args.len() == 1 {
3296 if let Expression::Literal(lit) = &f.args[0] {
3297 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3298 if !Self::looks_like_epoch(s) {
3299 return Ok(Expression::TryCast(Box::new(Cast {
3300 this: f.args.into_iter().next().unwrap(),
3301 to: DataType::Timestamp {
3302 precision: None,
3303 timezone: false,
3304 },
3305 double_colon_syntax: false,
3306 trailing_comments: Vec::new(),
3307 format: None,
3308 default: None,
3309 inferred_type: None,
3310 })));
3311 }
3312 }
3313 }
3314 }
3315 let mut args = f.args;
3317 if args.len() >= 2 {
3318 args[1] = Self::normalize_format_arg(args[1].clone());
3319 }
3320 Ok(Expression::Function(Box::new(Function::new(
3321 "TRY_TO_TIMESTAMP".to_string(),
3322 args,
3323 ))))
3324 }
3325
3326 "TRY_TO_DATE" => {
3328 if f.args.len() == 1 {
3329 if let Expression::Literal(lit) = &f.args[0] {
3330 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3331 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3333 return Ok(Expression::TryCast(Box::new(Cast {
3334 this: f.args.into_iter().next().unwrap(),
3335 to: crate::expressions::DataType::Date,
3336 double_colon_syntax: false,
3337 trailing_comments: Vec::new(),
3338 format: None,
3339 default: None,
3340 inferred_type: None,
3341 })));
3342 }
3343 }
3344 }
3345 }
3346 let mut args = f.args;
3348 if args.len() >= 2 {
3349 args[1] = Self::normalize_format_arg(args[1].clone());
3350 }
3351 Ok(Expression::Function(Box::new(Function::new(
3352 "TRY_TO_DATE".to_string(),
3353 args,
3354 ))))
3355 }
3356
3357 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3359
3360 "REGEXP_REPLACE" if f.args.len() == 2 => {
3362 let mut args = f.args;
3363 args.push(Expression::Literal(Box::new(
3364 crate::expressions::Literal::String(String::new()),
3365 )));
3366 Ok(Expression::Function(Box::new(Function::new(
3367 "REGEXP_REPLACE".to_string(),
3368 args,
3369 ))))
3370 }
3371
3372 "LAST_DAY" if f.args.len() == 2 => {
3374 let mut args = f.args;
3375 let date = args.remove(0);
3376 let unit = args.remove(0);
3377 let unit_str = match &unit {
3378 Expression::Column(c) => c.name.name.to_uppercase(),
3379 Expression::Identifier(i) => i.name.to_uppercase(),
3380 _ => String::new(),
3381 };
3382 if unit_str == "MONTH" {
3383 Ok(Expression::Function(Box::new(Function::new(
3384 "LAST_DAY".to_string(),
3385 vec![date],
3386 ))))
3387 } else {
3388 Ok(Expression::Function(Box::new(Function::new(
3389 "LAST_DAY".to_string(),
3390 vec![date, unit],
3391 ))))
3392 }
3393 }
3394
3395 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3397 "DATE_PART".to_string(),
3398 f.args,
3399 )))),
3400
3401 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3403 let mut args = f.args;
3404 let this = args.remove(0);
3405 let expr = args.remove(0);
3406 Ok(Expression::EndsWith(Box::new(
3407 crate::expressions::BinaryFunc {
3408 original_name: None,
3409 this,
3410 expression: expr,
3411 inferred_type: None,
3412 },
3413 )))
3414 }
3415
3416 _ => Ok(Expression::Function(Box::new(f))),
3418 }
3419 }
3420
3421 fn looks_like_datetime(s: &str) -> bool {
3423 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3426 }
3427
3428 fn looks_like_epoch(s: &str) -> bool {
3430 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3431 }
3432
3433 fn maybe_paren(expr: Expression) -> Expression {
3435 match &expr {
3436 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3437 Expression::Paren(Box::new(crate::expressions::Paren {
3438 this: expr,
3439 trailing_comments: Vec::new(),
3440 }))
3441 }
3442 _ => expr,
3443 }
3444 }
3445
3446 fn normalize_snowflake_format(format: &str) -> String {
3450 let mut result = String::new();
3451 let chars: Vec<char> = format.chars().collect();
3452 let mut i = 0;
3453 while i < chars.len() {
3454 if chars[i] == '"' {
3456 i += 1;
3457 while i < chars.len() && chars[i] != '"' {
3458 result.push(chars[i]);
3459 i += 1;
3460 }
3461 if i < chars.len() {
3462 i += 1; }
3464 continue;
3465 }
3466
3467 let remaining = &format[i..];
3468 let remaining_upper = remaining.to_uppercase();
3469
3470 if remaining_upper.starts_with("YYYY") {
3472 result.push_str("yyyy");
3473 i += 4;
3474 } else if remaining_upper.starts_with("YY") {
3475 result.push_str("yy");
3476 i += 2;
3477 } else if remaining_upper.starts_with("MMMM") {
3478 result.push_str("mmmm");
3479 i += 4;
3480 } else if remaining_upper.starts_with("MON") {
3481 result.push_str("mon");
3482 i += 3;
3483 } else if remaining_upper.starts_with("MM") {
3484 result.push_str("mm");
3485 i += 2;
3486 } else if remaining_upper.starts_with("DD") {
3487 result.push_str("DD");
3488 i += 2;
3489 } else if remaining_upper.starts_with("DY") {
3490 result.push_str("dy");
3491 i += 2;
3492 } else if remaining_upper.starts_with("HH24") {
3493 result.push_str("hh24");
3494 i += 4;
3495 } else if remaining_upper.starts_with("HH12") {
3496 result.push_str("hh12");
3497 i += 4;
3498 } else if remaining_upper.starts_with("HH") {
3499 result.push_str("hh");
3500 i += 2;
3501 } else if remaining_upper.starts_with("MISS") {
3502 result.push_str("miss");
3504 i += 4;
3505 } else if remaining_upper.starts_with("MI") {
3506 result.push_str("mi");
3507 i += 2;
3508 } else if remaining_upper.starts_with("SS") {
3509 result.push_str("ss");
3510 i += 2;
3511 } else if remaining_upper.starts_with("FF") {
3512 let ff_len = 2;
3514 let digit = if i + ff_len < chars.len() && chars[i + ff_len].is_ascii_digit() {
3515 let d = chars[i + ff_len];
3516 Some(d)
3517 } else {
3518 None
3519 };
3520 if let Some(d) = digit {
3521 result.push_str("ff");
3522 result.push(d);
3523 i += 3;
3524 } else {
3525 result.push_str("ff9");
3527 i += 2;
3528 }
3529 } else if remaining_upper.starts_with("AM") || remaining_upper.starts_with("PM") {
3530 result.push_str("pm");
3531 i += 2;
3532 } else if remaining_upper.starts_with("TZH") {
3533 result.push_str("tzh");
3534 i += 3;
3535 } else if remaining_upper.starts_with("TZM") {
3536 result.push_str("tzm");
3537 i += 3;
3538 } else {
3539 result.push(chars[i]);
3541 i += 1;
3542 }
3543 }
3544 result
3545 }
3546
3547 fn normalize_format_arg(expr: Expression) -> Expression {
3549 if let Expression::Literal(lit) = &expr {
3550 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3551 let normalized = Self::normalize_snowflake_format(s);
3552 Expression::Literal(Box::new(crate::expressions::Literal::String(normalized)))
3553 } else {
3554 expr.clone()
3555 }
3556 } else {
3557 expr
3558 }
3559 }
3560
3561 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3564 use crate::expressions::{DataType, LambdaExpr};
3565 use std::collections::HashMap;
3566
3567 let mut param_types: HashMap<String, DataType> = HashMap::new();
3569 for (i, param) in lambda.parameters.iter().enumerate() {
3570 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3571 param_types.insert(param.name.to_uppercase(), dt.clone());
3572 }
3573 }
3574
3575 if param_types.is_empty() {
3577 return Expression::Lambda(Box::new(lambda));
3578 }
3579
3580 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3582
3583 Expression::Lambda(Box::new(LambdaExpr {
3585 parameters: lambda.parameters,
3586 body: transformed_body,
3587 colon: lambda.colon,
3588 parameter_types: Vec::new(), }))
3590 }
3591
3592 fn replace_lambda_params_with_cast(
3594 &self,
3595 expr: Expression,
3596 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3597 ) -> Expression {
3598 use crate::expressions::{BinaryOp, Cast, Paren};
3599
3600 match expr {
3601 Expression::Column(col) if col.table.is_none() => {
3603 let name_upper = col.name.name.to_uppercase();
3604 if let Some(dt) = param_types.get(&name_upper) {
3605 Expression::Cast(Box::new(Cast {
3607 this: Expression::Column(col),
3608 to: dt.clone(),
3609 double_colon_syntax: false,
3610 trailing_comments: Vec::new(),
3611 format: None,
3612 default: None,
3613 inferred_type: None,
3614 }))
3615 } else {
3616 Expression::Column(col)
3617 }
3618 }
3619
3620 Expression::Identifier(id) => {
3622 let name_upper = id.name.to_uppercase();
3623 if let Some(dt) = param_types.get(&name_upper) {
3624 Expression::Cast(Box::new(Cast {
3626 this: Expression::Identifier(id),
3627 to: dt.clone(),
3628 double_colon_syntax: false,
3629 trailing_comments: Vec::new(),
3630 format: None,
3631 default: None,
3632 inferred_type: None,
3633 }))
3634 } else {
3635 Expression::Identifier(id)
3636 }
3637 }
3638
3639 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3641 self.replace_lambda_params_with_cast(op.left, param_types),
3642 self.replace_lambda_params_with_cast(op.right, param_types),
3643 ))),
3644 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3645 self.replace_lambda_params_with_cast(op.left, param_types),
3646 self.replace_lambda_params_with_cast(op.right, param_types),
3647 ))),
3648 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3649 self.replace_lambda_params_with_cast(op.left, param_types),
3650 self.replace_lambda_params_with_cast(op.right, param_types),
3651 ))),
3652 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3653 self.replace_lambda_params_with_cast(op.left, param_types),
3654 self.replace_lambda_params_with_cast(op.right, param_types),
3655 ))),
3656 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3657 self.replace_lambda_params_with_cast(op.left, param_types),
3658 self.replace_lambda_params_with_cast(op.right, param_types),
3659 ))),
3660
3661 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3663 this: self.replace_lambda_params_with_cast(p.this, param_types),
3664 trailing_comments: p.trailing_comments,
3665 })),
3666
3667 Expression::Function(mut f) => {
3669 f.args = f
3670 .args
3671 .into_iter()
3672 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3673 .collect();
3674 Expression::Function(f)
3675 }
3676
3677 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3679 self.replace_lambda_params_with_cast(op.left, param_types),
3680 self.replace_lambda_params_with_cast(op.right, param_types),
3681 ))),
3682 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3683 self.replace_lambda_params_with_cast(op.left, param_types),
3684 self.replace_lambda_params_with_cast(op.right, param_types),
3685 ))),
3686 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3687 self.replace_lambda_params_with_cast(op.left, param_types),
3688 self.replace_lambda_params_with_cast(op.right, param_types),
3689 ))),
3690 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3691 self.replace_lambda_params_with_cast(op.left, param_types),
3692 self.replace_lambda_params_with_cast(op.right, param_types),
3693 ))),
3694 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3695 self.replace_lambda_params_with_cast(op.left, param_types),
3696 self.replace_lambda_params_with_cast(op.right, param_types),
3697 ))),
3698 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3699 self.replace_lambda_params_with_cast(op.left, param_types),
3700 self.replace_lambda_params_with_cast(op.right, param_types),
3701 ))),
3702
3703 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3705 self.replace_lambda_params_with_cast(op.left, param_types),
3706 self.replace_lambda_params_with_cast(op.right, param_types),
3707 ))),
3708 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3709 self.replace_lambda_params_with_cast(op.left, param_types),
3710 self.replace_lambda_params_with_cast(op.right, param_types),
3711 ))),
3712
3713 other => other,
3715 }
3716 }
3717
3718 fn transform_aggregate_function(
3719 &self,
3720 f: Box<crate::expressions::AggregateFunction>,
3721 ) -> Result<Expression> {
3722 let name_upper = f.name.to_uppercase();
3723 match name_upper.as_str() {
3724 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3726 Function::new("LISTAGG".to_string(), f.args),
3727 ))),
3728
3729 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3731 Function::new("LISTAGG".to_string(), f.args),
3732 ))),
3733
3734 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3736 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3737 ))),
3738
3739 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3741 "BITAND_AGG".to_string(),
3742 f.args,
3743 )))),
3744
3745 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3747 "BITOR_AGG".to_string(),
3748 f.args,
3749 )))),
3750
3751 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3753 "BITXOR_AGG".to_string(),
3754 f.args,
3755 )))),
3756
3757 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3759 let arg = f.args.into_iter().next().unwrap();
3760 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3761 this: arg,
3762 distinct: f.distinct,
3763 filter: f.filter,
3764 order_by: Vec::new(),
3765 name: Some("BOOLAND_AGG".to_string()),
3766 ignore_nulls: None,
3767 having_max: None,
3768 limit: None,
3769 inferred_type: None,
3770 })))
3771 }
3772
3773 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3775 let arg = f.args.into_iter().next().unwrap();
3776 Ok(Expression::LogicalOr(Box::new(AggFunc {
3777 this: arg,
3778 distinct: f.distinct,
3779 filter: f.filter,
3780 order_by: Vec::new(),
3781 name: Some("BOOLOR_AGG".to_string()),
3782 ignore_nulls: None,
3783 having_max: None,
3784 limit: None,
3785 inferred_type: None,
3786 })))
3787 }
3788
3789 "APPROX_TOP_K" if f.args.len() == 1 => {
3791 let mut args = f.args;
3792 args.push(Expression::number(1));
3793 Ok(Expression::AggregateFunction(Box::new(
3794 crate::expressions::AggregateFunction {
3795 name: "APPROX_TOP_K".to_string(),
3796 args,
3797 distinct: f.distinct,
3798 filter: f.filter,
3799 order_by: Vec::new(),
3800 limit: None,
3801 ignore_nulls: None,
3802 inferred_type: None,
3803 },
3804 )))
3805 }
3806
3807 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3809 let arg = f.args.into_iter().next().unwrap();
3810 Ok(Expression::Skewness(Box::new(AggFunc {
3811 this: arg,
3812 distinct: f.distinct,
3813 filter: f.filter,
3814 order_by: Vec::new(),
3815 name: Some("SKEW".to_string()),
3816 ignore_nulls: None,
3817 having_max: None,
3818 limit: None,
3819 inferred_type: None,
3820 })))
3821 }
3822
3823 _ => Ok(Expression::AggregateFunction(f)),
3825 }
3826 }
3827}
3828
3829fn strftime_to_snowflake_format(fmt: &str) -> String {
3831 let mut result = String::new();
3832 let chars: Vec<char> = fmt.chars().collect();
3833 let mut i = 0;
3834 while i < chars.len() {
3835 if chars[i] == '%' && i + 1 < chars.len() {
3836 match chars[i + 1] {
3837 'Y' => {
3838 result.push_str("yyyy");
3839 i += 2;
3840 }
3841 'y' => {
3842 result.push_str("yy");
3843 i += 2;
3844 }
3845 'm' => {
3846 result.push_str("mm");
3847 i += 2;
3848 }
3849 'd' => {
3850 result.push_str("DD");
3851 i += 2;
3852 }
3853 'H' => {
3854 result.push_str("hh24");
3855 i += 2;
3856 }
3857 'M' => {
3858 result.push_str("mmmm");
3859 i += 2;
3860 } 'i' => {
3862 result.push_str("mi");
3863 i += 2;
3864 }
3865 'S' | 's' => {
3866 result.push_str("ss");
3867 i += 2;
3868 }
3869 'f' => {
3870 result.push_str("ff");
3871 i += 2;
3872 }
3873 'w' => {
3874 result.push_str("dy");
3875 i += 2;
3876 } 'a' => {
3878 result.push_str("DY");
3879 i += 2;
3880 } 'b' => {
3882 result.push_str("mon");
3883 i += 2;
3884 } 'T' => {
3886 result.push_str("hh24:mi:ss");
3887 i += 2;
3888 } _ => {
3890 result.push(chars[i]);
3891 result.push(chars[i + 1]);
3892 i += 2;
3893 }
3894 }
3895 } else {
3896 result.push(chars[i]);
3897 i += 1;
3898 }
3899 }
3900 result
3901}
3902
3903#[cfg(test)]
3904mod tests {
3905 use super::*;
3906 use crate::dialects::Dialect;
3907
3908 fn transpile_to_snowflake(sql: &str) -> String {
3909 let dialect = Dialect::get(DialectType::Generic);
3910 let result = dialect
3911 .transpile(sql, DialectType::Snowflake)
3912 .expect("Transpile failed");
3913 result[0].clone()
3914 }
3915
3916 #[test]
3917 fn test_ifnull_to_coalesce() {
3918 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
3919 assert!(
3920 result.contains("COALESCE"),
3921 "Expected COALESCE, got: {}",
3922 result
3923 );
3924 }
3925
3926 #[test]
3927 fn test_basic_select() {
3928 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
3929 assert!(result.contains("SELECT"));
3930 assert!(result.contains("FROM users"));
3931 }
3932
3933 #[test]
3934 fn test_snowflake_scripting_cursor_declare_block_roundtrip() {
3935 let sql = "DECLARE
3936 emp CURSOR FOR SELECT salary FROM employees;
3937BEGIN
3938 RETURN 1;
3939END";
3940
3941 let dialect = Dialect::get(DialectType::Snowflake);
3942 let ast = dialect.parse(sql).expect("Parse failed");
3943 let output = dialect.generate(&ast[0]).expect("Generate failed");
3944
3945 assert_eq!(output, sql);
3946 }
3947
3948 #[test]
3949 fn test_snowflake_scripting_cursor_return_table_roundtrip() {
3950 let sql = "DECLARE
3951 c1 CURSOR FOR SELECT * FROM invoices;
3952BEGIN
3953 OPEN c1;
3954 RETURN TABLE(RESULTSET_FROM_CURSOR(c1));
3955END";
3956
3957 let dialect = Dialect::get(DialectType::Snowflake);
3958 let ast = dialect.parse(sql).expect("Parse failed");
3959 let output = dialect.generate(&ast[0]).expect("Generate failed");
3960
3961 assert_eq!(output, sql);
3962 }
3963
3964 #[test]
3965 fn test_group_concat_to_listagg() {
3966 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
3967 assert!(
3968 result.contains("LISTAGG"),
3969 "Expected LISTAGG, got: {}",
3970 result
3971 );
3972 }
3973
3974 #[test]
3975 fn test_string_agg_to_listagg() {
3976 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
3977 assert!(
3978 result.contains("LISTAGG"),
3979 "Expected LISTAGG, got: {}",
3980 result
3981 );
3982 }
3983
3984 #[test]
3985 fn test_array_to_array_construct() {
3986 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
3987 assert!(
3989 result.contains("[1, 2, 3]"),
3990 "Expected [1, 2, 3], got: {}",
3991 result
3992 );
3993 }
3994
3995 #[test]
3996 fn test_double_quote_identifiers() {
3997 let dialect = SnowflakeDialect;
3999 let config = dialect.generator_config();
4000 assert_eq!(config.identifier_quote, '"');
4001 }
4002}