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 alias_explicit_as: false,
121 alias_keyword: None,
122 order_by: None,
123 limit: None,
124 offset: None,
125 distribute_by: None,
126 sort_by: None,
127 cluster_by: None,
128 lateral: false,
129 modifiers_inside: false,
130 trailing_comments: Vec::new(),
131 inferred_type: None,
132 }));
133 Ok(Expression::All(Box::new(
134 crate::expressions::QuantifiedExpr {
135 this: in_expr.this,
136 subquery,
137 op: Some(crate::expressions::QuantifiedOp::Neq),
138 },
139 )))
140 }
141
142 Expression::In(in_expr) if in_expr.not => {
144 let in_without_not = crate::expressions::In {
146 this: in_expr.this,
147 expressions: in_expr.expressions,
148 query: in_expr.query,
149 not: false,
150 global: in_expr.global,
151 unnest: in_expr.unnest,
152 is_field: in_expr.is_field,
153 };
154 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
155 this: Expression::In(Box::new(in_without_not)),
156 inferred_type: None,
157 })))
158 }
159
160 Expression::Interval(interval) => self.transform_interval(*interval),
163
164 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
167 original_name: None,
168 expressions: vec![f.this, f.expression],
169 inferred_type: None,
170 }))),
171
172 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
174 original_name: None,
175 expressions: vec![f.this, f.expression],
176 inferred_type: None,
177 }))),
178
179 Expression::Coalesce(mut f) => {
181 f.original_name = None;
182 Ok(Expression::Coalesce(f))
183 }
184
185 Expression::GroupConcat(f) => Ok(Expression::ListAgg(Box::new(ListAggFunc {
187 this: f.this,
188 separator: f.separator,
189 on_overflow: None,
190 order_by: f.order_by,
191 distinct: f.distinct,
192 filter: f.filter,
193 inferred_type: None,
194 }))),
195
196 Expression::Cast(c) => {
200 use crate::expressions::DataType;
201 let transformed_this = self.transform_expr(c.this)?;
203 match &c.to {
204 DataType::Geography { .. } => Ok(Expression::Function(Box::new(
205 Function::new("TO_GEOGRAPHY".to_string(), vec![transformed_this]),
206 ))),
207 DataType::Geometry { .. } => Ok(Expression::Function(Box::new(Function::new(
208 "TO_GEOMETRY".to_string(),
209 vec![transformed_this],
210 )))),
211 _ => {
212 let transformed_dt = match self.transform_data_type(c.to.clone())? {
214 Expression::DataType(dt) => dt,
215 _ => c.to.clone(),
216 };
217 Ok(Expression::Cast(Box::new(Cast {
218 this: transformed_this,
219 to: transformed_dt,
220 double_colon_syntax: false, trailing_comments: c.trailing_comments,
222 format: c.format,
223 default: c.default,
224 inferred_type: None,
225 })))
226 }
227 }
228 }
229
230 Expression::TryCast(c) => {
233 let transformed_this = self.transform_expr(c.this)?;
234 Ok(Expression::TryCast(Box::new(Cast {
235 this: transformed_this,
236 to: c.to,
237 double_colon_syntax: false, trailing_comments: c.trailing_comments,
239 format: c.format,
240 default: c.default,
241 inferred_type: None,
242 })))
243 }
244
245 Expression::SafeCast(c) => {
248 let to = match c.to {
249 DataType::Timestamp { .. } => DataType::Custom {
250 name: "TIMESTAMPTZ".to_string(),
251 },
252 DataType::Custom { name } if name.eq_ignore_ascii_case("TIMESTAMP") => {
253 DataType::Custom {
254 name: "TIMESTAMPTZ".to_string(),
255 }
256 }
257 other => other,
258 };
259 let transformed_this = self.transform_expr(c.this)?;
260 Ok(Expression::Cast(Box::new(Cast {
261 this: transformed_this,
262 to,
263 double_colon_syntax: c.double_colon_syntax,
264 trailing_comments: c.trailing_comments,
265 format: c.format,
266 default: c.default,
267 inferred_type: None,
268 })))
269 }
270
271 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Timestamp(_)) => {
274 let Literal::Timestamp(s) = lit.as_ref() else {
275 unreachable!()
276 };
277 Ok(Expression::Cast(Box::new(Cast {
278 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
279 to: DataType::Timestamp {
280 precision: None,
281 timezone: false,
282 },
283 double_colon_syntax: false,
284 trailing_comments: Vec::new(),
285 format: None,
286 default: None,
287 inferred_type: None,
288 })))
289 }
290
291 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Date(_)) => {
293 let Literal::Date(s) = lit.as_ref() else {
294 unreachable!()
295 };
296 Ok(Expression::Cast(Box::new(Cast {
297 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
298 to: DataType::Date,
299 double_colon_syntax: false,
300 trailing_comments: Vec::new(),
301 format: None,
302 default: None,
303 inferred_type: None,
304 })))
305 }
306
307 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Time(_)) => {
309 let Literal::Time(s) = lit.as_ref() else {
310 unreachable!()
311 };
312 Ok(Expression::Cast(Box::new(Cast {
313 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
314 to: DataType::Time {
315 precision: None,
316 timezone: false,
317 },
318 double_colon_syntax: false,
319 trailing_comments: Vec::new(),
320 format: None,
321 default: None,
322 inferred_type: None,
323 })))
324 }
325
326 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Datetime(_)) => {
328 let Literal::Datetime(s) = lit.as_ref() else {
329 unreachable!()
330 };
331 Ok(Expression::Cast(Box::new(Cast {
332 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
333 to: DataType::Custom {
334 name: "DATETIME".to_string(),
335 },
336 double_colon_syntax: false,
337 trailing_comments: Vec::new(),
338 format: None,
339 default: None,
340 inferred_type: None,
341 })))
342 }
343
344 Expression::ILike(op) => Ok(Expression::ILike(op)),
347
348 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
351 "FLATTEN".to_string(),
352 vec![f.this],
353 )))),
354
355 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
357 "FLATTEN".to_string(),
358 vec![f.this],
359 )))),
360
361 Expression::Unnest(f) => {
363 let input_arg =
365 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
366 name: crate::expressions::Identifier::new("INPUT"),
367 value: f.this,
368 separator: crate::expressions::NamedArgSeparator::DArrow,
369 }));
370
371 let flatten = Expression::Function(Box::new(Function::new(
373 "FLATTEN".to_string(),
374 vec![input_arg],
375 )));
376
377 let table_func =
379 Expression::TableFromRows(Box::new(crate::expressions::TableFromRows {
380 this: Box::new(flatten),
381 alias: None,
382 joins: vec![],
383 pivots: None,
384 sample: None,
385 }));
386
387 Ok(Expression::Alias(Box::new(crate::expressions::Alias {
389 this: table_func,
390 alias: crate::expressions::Identifier::new("_t0"),
391 column_aliases: vec![
392 crate::expressions::Identifier::new("seq"),
393 crate::expressions::Identifier::new("key"),
394 crate::expressions::Identifier::new("path"),
395 crate::expressions::Identifier::new("index"),
396 crate::expressions::Identifier::new("value"),
397 crate::expressions::Identifier::new("this"),
398 ],
399 alias_explicit_as: false,
400 alias_keyword: None,
401 pre_alias_comments: vec![],
402 trailing_comments: vec![],
403 inferred_type: None,
404 })))
405 }
406
407 Expression::ArrayFunc(arr) => {
411 if arr.bracket_notation {
412 Ok(Expression::ArrayFunc(arr))
414 } else {
415 Ok(Expression::Function(Box::new(Function::new(
417 "ARRAY_CONSTRUCT".to_string(),
418 arr.expressions,
419 ))))
420 }
421 }
422
423 Expression::ArrayConcat(f) => Ok(Expression::Function(Box::new(Function::new(
425 "ARRAY_CAT".to_string(),
426 f.expressions,
427 )))),
428
429 Expression::ArrayConcatAgg(f) => Ok(Expression::Function(Box::new(Function::new(
431 "ARRAY_FLATTEN".to_string(),
432 vec![f.this],
433 )))),
434
435 Expression::ArrayContains(f) => Ok(Expression::Function(Box::new(Function::new(
437 "ARRAY_CONTAINS".to_string(),
438 vec![f.this, f.expression],
439 )))),
440
441 Expression::ArrayIntersect(f) => Ok(Expression::Function(Box::new(Function::new(
443 "ARRAY_INTERSECTION".to_string(),
444 f.expressions,
445 )))),
446
447 Expression::ArraySort(f) => Ok(Expression::Function(Box::new(Function::new(
449 "ARRAY_SORT".to_string(),
450 vec![f.this],
451 )))),
452
453 Expression::StringToArray(f) => {
455 let mut args = vec![*f.this];
456 if let Some(expr) = f.expression {
457 args.push(*expr);
458 }
459 Ok(Expression::Function(Box::new(Function::new(
460 "STRTOK_TO_ARRAY".to_string(),
461 args,
462 ))))
463 }
464
465 Expression::BitwiseOr(f) => Ok(Expression::Function(Box::new(Function::new(
468 "BITOR".to_string(),
469 vec![f.left, f.right],
470 )))),
471
472 Expression::BitwiseXor(f) => Ok(Expression::Function(Box::new(Function::new(
474 "BITXOR".to_string(),
475 vec![f.left, f.right],
476 )))),
477
478 Expression::BitwiseAnd(f) => Ok(Expression::Function(Box::new(Function::new(
480 "BITAND".to_string(),
481 vec![f.left, f.right],
482 )))),
483
484 Expression::BitwiseNot(f) => Ok(Expression::Function(Box::new(Function::new(
486 "BITNOT".to_string(),
487 vec![f.this],
488 )))),
489
490 Expression::BitwiseLeftShift(f) => Ok(Expression::Function(Box::new(Function::new(
492 "BITSHIFTLEFT".to_string(),
493 vec![f.left, f.right],
494 )))),
495
496 Expression::BitwiseRightShift(f) => Ok(Expression::Function(Box::new(Function::new(
498 "BITSHIFTRIGHT".to_string(),
499 vec![f.left, f.right],
500 )))),
501
502 Expression::BitwiseAndAgg(f) => Ok(Expression::Function(Box::new(Function::new(
504 "BITAND_AGG".to_string(),
505 vec![f.this],
506 )))),
507
508 Expression::BitwiseOrAgg(f) => Ok(Expression::Function(Box::new(Function::new(
510 "BITOR_AGG".to_string(),
511 vec![f.this],
512 )))),
513
514 Expression::BitwiseXorAgg(f) => Ok(Expression::Function(Box::new(Function::new(
516 "BITXOR_AGG".to_string(),
517 vec![f.this],
518 )))),
519
520 Expression::LogicalAnd(f) => Ok(Expression::Function(Box::new(Function::new(
523 "BOOLAND_AGG".to_string(),
524 vec![f.this],
525 )))),
526
527 Expression::LogicalOr(f) => Ok(Expression::Function(Box::new(Function::new(
529 "BOOLOR_AGG".to_string(),
530 vec![f.this],
531 )))),
532
533 Expression::Booland(f) => Ok(Expression::Function(Box::new(Function::new(
535 "BOOLAND".to_string(),
536 vec![*f.this, *f.expression],
537 )))),
538
539 Expression::Boolor(f) => Ok(Expression::Function(Box::new(Function::new(
541 "BOOLOR".to_string(),
542 vec![*f.this, *f.expression],
543 )))),
544
545 Expression::Xor(f) => {
547 let mut args = Vec::new();
548 if let Some(this) = f.this {
549 args.push(*this);
550 }
551 if let Some(expr) = f.expression {
552 args.push(*expr);
553 }
554 Ok(Expression::Function(Box::new(Function::new(
555 "BOOLXOR".to_string(),
556 args,
557 ))))
558 }
559
560 Expression::DayOfMonth(f) => Ok(Expression::Function(Box::new(Function::new(
563 "DAYOFMONTH".to_string(),
564 vec![f.this],
565 )))),
566
567 Expression::DayOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
569 "DAYOFWEEK".to_string(),
570 vec![f.this],
571 )))),
572
573 Expression::DayOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
575 "DAYOFWEEKISO".to_string(),
576 vec![f.this],
577 )))),
578
579 Expression::DayOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
581 "DAYOFYEAR".to_string(),
582 vec![f.this],
583 )))),
584
585 Expression::WeekOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
587 "WEEK".to_string(),
588 vec![f.this],
589 )))),
590
591 Expression::YearOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
593 "YEAROFWEEK".to_string(),
594 vec![f.this],
595 )))),
596
597 Expression::YearOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
599 "YEAROFWEEKISO".to_string(),
600 vec![f.this],
601 )))),
602
603 Expression::ByteLength(f) => Ok(Expression::Function(Box::new(Function::new(
605 "OCTET_LENGTH".to_string(),
606 vec![f.this],
607 )))),
608
609 Expression::TimestampDiff(f) => {
611 let mut args = vec![];
612 if let Some(ref unit_str) = f.unit {
614 args.push(Expression::Identifier(crate::expressions::Identifier::new(
615 unit_str.clone(),
616 )));
617 args.push(*f.this);
618 args.push(*f.expression);
619 } else {
620 args.push(*f.this);
621 args.push(*f.expression);
622 }
623 Ok(Expression::Function(Box::new(Function::new(
624 "TIMESTAMPDIFF".to_string(),
625 args,
626 ))))
627 }
628
629 Expression::TimestampAdd(f) => {
631 let mut args = vec![];
632 if let Some(ref unit_str) = f.unit {
633 args.push(Expression::Identifier(crate::expressions::Identifier::new(
634 unit_str.clone(),
635 )));
636 args.push(*f.this);
637 args.push(*f.expression);
638 } else {
639 args.push(*f.this);
640 args.push(*f.expression);
641 }
642 Ok(Expression::Function(Box::new(Function::new(
643 "TIMESTAMPADD".to_string(),
644 args,
645 ))))
646 }
647
648 Expression::ToArray(f) => Ok(Expression::Function(Box::new(Function::new(
650 "TO_ARRAY".to_string(),
651 vec![f.this],
652 )))),
653
654 Expression::DateAdd(f) => {
656 let unit_str = interval_unit_to_str(&f.unit);
657 let unit = Expression::Identifier(crate::expressions::Identifier {
658 name: unit_str,
659 quoted: false,
660 trailing_comments: Vec::new(),
661 span: None,
662 });
663 Ok(Expression::Function(Box::new(Function::new(
664 "DATEADD".to_string(),
665 vec![unit, f.interval, f.this],
666 ))))
667 }
668
669 Expression::DateSub(f) => {
671 let unit_str = interval_unit_to_str(&f.unit);
672 let unit = Expression::Identifier(crate::expressions::Identifier {
673 name: unit_str,
674 quoted: false,
675 trailing_comments: Vec::new(),
676 span: None,
677 });
678 let neg_expr = Expression::Mul(Box::new(crate::expressions::BinaryOp::new(
680 f.interval,
681 Expression::Neg(Box::new(crate::expressions::UnaryOp {
682 this: Expression::number(1),
683 inferred_type: None,
684 })),
685 )));
686 Ok(Expression::Function(Box::new(Function::new(
687 "DATEADD".to_string(),
688 vec![unit, neg_expr, f.this],
689 ))))
690 }
691
692 Expression::DateDiff(f) => {
694 let unit_str =
695 interval_unit_to_str(&f.unit.unwrap_or(crate::expressions::IntervalUnit::Day));
696 let unit = Expression::Identifier(crate::expressions::Identifier {
697 name: unit_str,
698 quoted: false,
699 trailing_comments: Vec::new(),
700 span: None,
701 });
702 Ok(Expression::Function(Box::new(Function::new(
703 "DATEDIFF".to_string(),
704 vec![unit, f.expression, f.this],
705 ))))
706 }
707
708 Expression::StringAgg(f) => {
711 let mut args = vec![f.this.clone()];
712 if let Some(separator) = &f.separator {
713 args.push(separator.clone());
714 }
715 Ok(Expression::Function(Box::new(Function::new(
716 "LISTAGG".to_string(),
717 args,
718 ))))
719 }
720
721 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
723 "STARTSWITH".to_string(),
724 vec![f.this, f.expression],
725 )))),
726
727 Expression::EndsWith(f) => Ok(Expression::EndsWith(f)),
729
730 Expression::Stuff(f) => {
732 let mut args = vec![*f.this];
733 if let Some(start) = f.start {
734 args.push(*start);
735 }
736 if let Some(length) = f.length {
737 args.push(Expression::number(length));
738 }
739 args.push(*f.expression);
740 Ok(Expression::Function(Box::new(Function::new(
741 "INSERT".to_string(),
742 args,
743 ))))
744 }
745
746 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
749 "SHA1".to_string(),
750 vec![f.this],
751 )))),
752
753 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
755 "SHA1_BINARY".to_string(),
756 vec![f.this],
757 )))),
758
759 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
761 "SHA2_BINARY".to_string(),
762 vec![*f.this],
763 )))),
764
765 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
767 "MD5_BINARY".to_string(),
768 vec![*f.this],
769 )))),
770
771 Expression::MD5NumberLower64(f) => Ok(Expression::Function(Box::new(Function::new(
773 "MD5_NUMBER_LOWER64".to_string(),
774 vec![f.this],
775 )))),
776
777 Expression::MD5NumberUpper64(f) => Ok(Expression::Function(Box::new(Function::new(
779 "MD5_NUMBER_UPPER64".to_string(),
780 vec![f.this],
781 )))),
782
783 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
786 "VECTOR_COSINE_SIMILARITY".to_string(),
787 vec![*f.this, *f.expression],
788 )))),
789
790 Expression::DotProduct(f) => Ok(Expression::Function(Box::new(Function::new(
792 "VECTOR_INNER_PRODUCT".to_string(),
793 vec![*f.this, *f.expression],
794 )))),
795
796 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
798 "VECTOR_L2_DISTANCE".to_string(),
799 vec![*f.this, *f.expression],
800 )))),
801
802 Expression::ManhattanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
804 "VECTOR_L1_DISTANCE".to_string(),
805 vec![*f.this, *f.expression],
806 )))),
807
808 Expression::JSONFormat(f) => {
811 let mut args = Vec::new();
812 if let Some(this) = f.this {
813 args.push(*this);
814 }
815 Ok(Expression::Function(Box::new(Function::new(
816 "TO_JSON".to_string(),
817 args,
818 ))))
819 }
820
821 Expression::JSONKeys(f) => Ok(Expression::Function(Box::new(Function::new(
823 "OBJECT_KEYS".to_string(),
824 vec![*f.this],
825 )))),
826
827 Expression::GetExtract(f) => Ok(Expression::Function(Box::new(Function::new(
829 "GET".to_string(),
830 vec![*f.this, *f.expression],
831 )))),
832
833 Expression::StarMap(f) => Ok(Expression::Function(Box::new(Function::new(
835 "OBJECT_CONSTRUCT".to_string(),
836 vec![f.this, f.expression],
837 )))),
838
839 Expression::LowerHex(f) => Ok(Expression::Function(Box::new(Function::new(
841 "TO_CHAR".to_string(),
842 vec![f.this],
843 )))),
844
845 Expression::Skewness(f) => Ok(Expression::Function(Box::new(Function::new(
847 "SKEW".to_string(),
848 vec![f.this],
849 )))),
850
851 Expression::StPoint(f) => Ok(Expression::Function(Box::new(Function::new(
853 "ST_MAKEPOINT".to_string(),
854 vec![*f.this, *f.expression],
855 )))),
856
857 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
859 "CONVERT_TIMEZONE".to_string(),
860 vec![*f.this],
861 )))),
862
863 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
866 "HEX_DECODE_BINARY".to_string(),
867 vec![*f.this],
868 )))),
869
870 Expression::UnixToTime(f) => {
872 let mut args = vec![*f.this];
873 if let Some(scale) = f.scale {
874 args.push(Expression::number(scale));
875 }
876 Ok(Expression::Function(Box::new(Function::new(
877 "TO_TIMESTAMP".to_string(),
878 args,
879 ))))
880 }
881
882 Expression::IfFunc(f) => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
885 condition: f.condition,
886 true_value: f.true_value,
887 false_value: Some(
888 f.false_value
889 .unwrap_or(Expression::Null(crate::expressions::Null)),
890 ),
891 original_name: Some("IFF".to_string()),
892 inferred_type: None,
893 }))),
894
895 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
898 "APPROX_COUNT_DISTINCT".to_string(),
899 vec![f.this],
900 )))),
901
902 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
904 "MAX_BY".to_string(),
905 vec![*f.this, *f.expression],
906 )))),
907
908 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
910 "MIN_BY".to_string(),
911 vec![*f.this, *f.expression],
912 )))),
913
914 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
917
918 Expression::Rand(r) => Ok(Expression::Rand(r)),
920
921 Expression::Uuid(u) => Ok(Expression::Uuid(u)),
924
925 Expression::Map(f) => Ok(Expression::Function(Box::new(Function::new(
928 "OBJECT_CONSTRUCT".to_string(),
929 f.keys
930 .into_iter()
931 .zip(f.values.into_iter())
932 .flat_map(|(k, v)| vec![k, v])
933 .collect(),
934 )))),
935
936 Expression::MapFunc(f) => Ok(Expression::Function(Box::new(Function::new(
938 "OBJECT_CONSTRUCT".to_string(),
939 f.keys
940 .into_iter()
941 .zip(f.values.into_iter())
942 .flat_map(|(k, v)| vec![k, v])
943 .collect(),
944 )))),
945
946 Expression::VarMap(f) => Ok(Expression::Function(Box::new(Function::new(
948 "OBJECT_CONSTRUCT".to_string(),
949 f.keys
950 .into_iter()
951 .zip(f.values.into_iter())
952 .flat_map(|(k, v)| vec![k, v])
953 .collect(),
954 )))),
955
956 Expression::JsonObject(f) => Ok(Expression::Function(Box::new(Function::new(
959 "OBJECT_CONSTRUCT_KEEP_NULL".to_string(),
960 f.pairs.into_iter().flat_map(|(k, v)| vec![k, v]).collect(),
961 )))),
962
963 Expression::JsonExtractScalar(f) => Ok(Expression::Function(Box::new(Function::new(
965 "JSON_EXTRACT_PATH_TEXT".to_string(),
966 vec![f.this, f.path],
967 )))),
968
969 Expression::Struct(f) => Ok(Expression::Function(Box::new(Function::new(
972 "OBJECT_CONSTRUCT".to_string(),
973 f.fields
974 .into_iter()
975 .flat_map(|(name, expr)| {
976 let key = match name {
977 Some(n) => Expression::string(n),
978 None => Expression::Null(crate::expressions::Null),
979 };
980 vec![key, expr]
981 })
982 .collect(),
983 )))),
984
985 Expression::JSONPathRoot(_) => Ok(Expression::Literal(Box::new(
988 crate::expressions::Literal::String(String::new()),
989 ))),
990
991 Expression::VarSamp(agg) => Ok(Expression::Variance(agg)),
994
995 Expression::VarPop(agg) => Ok(Expression::VarPop(agg)),
998
999 Expression::Extract(f) => {
1002 use crate::expressions::DateTimeField;
1003 let transformed_this = self.transform_expr(f.this)?;
1005 let field_name = match &f.field {
1006 DateTimeField::Year => "YEAR",
1007 DateTimeField::Month => "MONTH",
1008 DateTimeField::Day => "DAY",
1009 DateTimeField::Hour => "HOUR",
1010 DateTimeField::Minute => "MINUTE",
1011 DateTimeField::Second => "SECOND",
1012 DateTimeField::Millisecond => "MILLISECOND",
1013 DateTimeField::Microsecond => "MICROSECOND",
1014 DateTimeField::Week => "WEEK",
1015 DateTimeField::WeekWithModifier(m) => {
1016 return Ok(Expression::Function(Box::new(Function::new(
1017 "DATE_PART".to_string(),
1018 vec![
1019 Expression::Identifier(crate::expressions::Identifier {
1020 name: format!("WEEK({})", m),
1021 quoted: false,
1022 trailing_comments: Vec::new(),
1023 span: None,
1024 }),
1025 transformed_this,
1026 ],
1027 ))))
1028 }
1029 DateTimeField::DayOfWeek => "DAYOFWEEK",
1030 DateTimeField::DayOfYear => "DAYOFYEAR",
1031 DateTimeField::Quarter => "QUARTER",
1032 DateTimeField::Epoch => "EPOCH",
1033 DateTimeField::Timezone => "TIMEZONE",
1034 DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
1035 DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
1036 DateTimeField::Date => "DATE",
1037 DateTimeField::Time => "TIME",
1038 DateTimeField::Custom(s) => {
1039 match s.to_uppercase().as_str() {
1041 "DAYOFMONTH" => "DAY",
1042 "DOW" => "DAYOFWEEK",
1043 "DOY" => "DAYOFYEAR",
1044 "ISODOW" => "DAYOFWEEKISO",
1045 "EPOCH_SECOND" | "EPOCH_SECONDS" => "EPOCH_SECOND",
1046 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => "EPOCH_MILLISECOND",
1047 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => "EPOCH_MICROSECOND",
1048 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => "EPOCH_NANOSECOND",
1049 _ => {
1050 return {
1051 let field_ident =
1052 Expression::Identifier(crate::expressions::Identifier {
1053 name: s.to_string(),
1054 quoted: false,
1055 trailing_comments: Vec::new(),
1056 span: None,
1057 });
1058 Ok(Expression::Function(Box::new(Function::new(
1059 "DATE_PART".to_string(),
1060 vec![field_ident, transformed_this],
1061 ))))
1062 }
1063 }
1064 }
1065 }
1066 };
1067 let field_ident = Expression::Identifier(crate::expressions::Identifier {
1068 name: field_name.to_string(),
1069 quoted: false,
1070 trailing_comments: Vec::new(),
1071 span: None,
1072 });
1073 Ok(Expression::Function(Box::new(Function::new(
1074 "DATE_PART".to_string(),
1075 vec![field_ident, transformed_this],
1076 ))))
1077 }
1078
1079 Expression::Function(f) => self.transform_function(*f),
1081
1082 Expression::Sum(mut agg) => {
1084 agg.this = self.transform_expr(agg.this)?;
1085 Ok(Expression::Sum(agg))
1086 }
1087
1088 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
1090
1091 Expression::NamedArgument(na) => {
1093 let transformed_value = self.transform_expr(na.value)?;
1094 Ok(Expression::NamedArgument(Box::new(
1095 crate::expressions::NamedArgument {
1096 name: na.name,
1097 value: transformed_value,
1098 separator: na.separator,
1099 },
1100 )))
1101 }
1102
1103 Expression::CreateTable(mut ct) => {
1105 for col in &mut ct.columns {
1106 if let Expression::DataType(new_dt) =
1107 self.transform_data_type(col.data_type.clone())?
1108 {
1109 col.data_type = new_dt;
1110 }
1111 if let Some(default_expr) = col.default.take() {
1113 col.default = Some(self.transform_expr(default_expr)?);
1114 }
1115 for constraint in &mut col.constraints {
1117 if let crate::expressions::ColumnConstraint::ComputedColumn(cc) = constraint
1118 {
1119 let transformed = self.transform_expr(*cc.expression.clone())?;
1120 cc.expression = Box::new(transformed);
1121 }
1122 }
1123 }
1124
1125 if ct.table_modifier.as_deref() == Some("EXTERNAL")
1128 && !ct.with_properties.is_empty()
1129 {
1130 for (key, value) in ct.with_properties.drain(..) {
1131 let formatted = Self::format_external_table_property(&key, &value);
1132 ct.properties
1133 .push(Expression::Raw(crate::expressions::Raw { sql: formatted }));
1134 }
1135 }
1136
1137 Ok(Expression::CreateTable(ct))
1138 }
1139
1140 Expression::AlterTable(mut at) => {
1142 for action in &mut at.actions {
1143 if let crate::expressions::AlterTableAction::AddColumn { column, .. } = action {
1144 if let Expression::DataType(new_dt) =
1145 self.transform_data_type(column.data_type.clone())?
1146 {
1147 column.data_type = new_dt;
1148 }
1149 }
1150 }
1151 Ok(Expression::AlterTable(at))
1152 }
1153
1154 Expression::Table(mut t) => {
1156 if let Some(when) = t.when.take() {
1157 let transformed_expr = self.transform_expr(*when.expression)?;
1159 t.when = Some(Box::new(crate::expressions::HistoricalData {
1160 this: when.this,
1161 kind: when.kind,
1162 expression: Box::new(transformed_expr),
1163 }));
1164 }
1165 Ok(Expression::Table(t))
1166 }
1167
1168 Expression::Subscript(s) => {
1170 let transformed_this = self.transform_expr(s.this)?;
1171 let transformed_index = self.transform_expr(s.index)?;
1172 Ok(Expression::Subscript(Box::new(
1173 crate::expressions::Subscript {
1174 this: transformed_this,
1175 index: transformed_index,
1176 },
1177 )))
1178 }
1179
1180 Expression::Paren(p) => {
1182 let transformed = self.transform_expr(p.this)?;
1183 Ok(Expression::Paren(Box::new(crate::expressions::Paren {
1184 this: transformed,
1185 trailing_comments: p.trailing_comments,
1186 })))
1187 }
1188
1189 Expression::Select(mut select) => {
1193 if let Some(ref mut order) = select.order_by {
1194 for ord in &mut order.expressions {
1195 if ord.nulls_first.is_none() {
1196 ord.nulls_first = Some(ord.desc);
1197 }
1198 }
1199 }
1200 Ok(Expression::Select(select))
1201 }
1202
1203 Expression::WindowFunction(mut wf) => {
1205 for ord in &mut wf.over.order_by {
1206 if ord.nulls_first.is_none() {
1207 ord.nulls_first = Some(ord.desc);
1208 }
1209 }
1210 Ok(Expression::WindowFunction(wf))
1211 }
1212
1213 Expression::Window(mut w) => {
1215 for ord in &mut w.order_by {
1216 if ord.nulls_first.is_none() {
1217 ord.nulls_first = Some(ord.desc);
1218 }
1219 }
1220 Ok(Expression::Window(w))
1221 }
1222
1223 Expression::Lateral(mut lat) => {
1225 let is_flatten = match lat.this.as_ref() {
1227 Expression::Function(f) => f.name.to_uppercase() == "FLATTEN",
1228 _ => false,
1229 };
1230 if is_flatten && lat.column_aliases.is_empty() {
1231 lat.column_aliases = vec![
1233 "SEQ".to_string(),
1234 "KEY".to_string(),
1235 "PATH".to_string(),
1236 "INDEX".to_string(),
1237 "VALUE".to_string(),
1238 "THIS".to_string(),
1239 ];
1240 if lat.alias.is_none() {
1242 lat.alias = Some("_flattened".to_string());
1243 }
1244 }
1245 Ok(Expression::Lateral(lat))
1246 }
1247
1248 _ => Ok(expr),
1250 }
1251 }
1252}
1253
1254impl SnowflakeDialect {
1255 fn format_external_table_property(key: &str, value: &str) -> String {
1258 let lower_key = key.to_lowercase();
1259 match lower_key.as_str() {
1260 "location" => format!("LOCATION={}", value),
1261 "file_format" => {
1262 let formatted_value = Self::format_file_format_value(value);
1264 format!("FILE_FORMAT={}", formatted_value)
1265 }
1266 _ => format!("{}={}", key, value),
1267 }
1268 }
1269
1270 fn format_file_format_value(value: &str) -> String {
1274 if !value.starts_with('(') {
1275 return value.to_string();
1276 }
1277 let inner = value[1..value.len() - 1].trim();
1279 let mut result = String::from("(");
1281 let mut parts: Vec<String> = Vec::new();
1282 let tokens: Vec<&str> = inner.split_whitespace().collect();
1284 let mut i = 0;
1285 while i < tokens.len() {
1286 let token = tokens[i];
1287 if i + 2 < tokens.len() && tokens[i + 1] == "=" {
1288 let val = Self::format_property_value(tokens[i + 2]);
1290 parts.push(format!("{}={}", token, val));
1291 i += 3;
1292 } else if token.contains('=') {
1293 let eq_pos = token.find('=').unwrap();
1295 let k = &token[..eq_pos];
1296 let v = Self::format_property_value(&token[eq_pos + 1..]);
1297 parts.push(format!("{}={}", k, v));
1298 i += 1;
1299 } else {
1300 parts.push(token.to_string());
1301 i += 1;
1302 }
1303 }
1304 result.push_str(&parts.join(" "));
1305 result.push(')');
1306 result
1307 }
1308
1309 fn format_property_value(value: &str) -> String {
1311 match value.to_lowercase().as_str() {
1312 "true" => "TRUE".to_string(),
1313 "false" => "FALSE".to_string(),
1314 _ => value.to_string(),
1315 }
1316 }
1317
1318 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1320 use crate::expressions::DataType;
1321 let transformed = match dt {
1322 DataType::Text => DataType::VarChar {
1324 length: None,
1325 parenthesized_length: false,
1326 },
1327 DataType::Struct { fields, .. } => {
1329 let _ = fields; DataType::Custom {
1332 name: "OBJECT".to_string(),
1333 }
1334 }
1335 DataType::Custom { name } => {
1337 let upper_name = name.to_uppercase();
1338 match upper_name.as_str() {
1339 "NVARCHAR" | "NCHAR" | "NATIONAL CHARACTER VARYING" | "NATIONAL CHAR" => {
1341 DataType::VarChar {
1342 length: None,
1343 parenthesized_length: false,
1344 }
1345 }
1346 "STRING" => DataType::VarChar {
1348 length: None,
1349 parenthesized_length: false,
1350 },
1351 "BIGDECIMAL" => DataType::Double {
1353 precision: None,
1354 scale: None,
1355 },
1356 "NESTED" => DataType::Custom {
1358 name: "OBJECT".to_string(),
1359 },
1360 "BYTEINT" => DataType::Int {
1362 length: None,
1363 integer_spelling: false,
1364 },
1365 "CHAR VARYING" | "CHARACTER VARYING" => DataType::VarChar {
1367 length: None,
1368 parenthesized_length: false,
1369 },
1370 "SQL_DOUBLE" => DataType::Double {
1372 precision: None,
1373 scale: None,
1374 },
1375 "SQL_VARCHAR" => DataType::VarChar {
1377 length: None,
1378 parenthesized_length: false,
1379 },
1380 "TIMESTAMP_NTZ" => DataType::Custom {
1382 name: "TIMESTAMPNTZ".to_string(),
1383 },
1384 "TIMESTAMP_LTZ" => DataType::Custom {
1386 name: "TIMESTAMPLTZ".to_string(),
1387 },
1388 "TIMESTAMP_TZ" => DataType::Custom {
1390 name: "TIMESTAMPTZ".to_string(),
1391 },
1392 "NCHAR VARYING" => DataType::VarChar {
1394 length: None,
1395 parenthesized_length: false,
1396 },
1397 "NUMBER" => DataType::Decimal {
1399 precision: Some(38),
1400 scale: Some(0),
1401 },
1402 _ if name.starts_with("NUMBER(") => {
1403 let inner = &name[7..name.len() - 1]; let parts: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1407 let precision = parts.first().and_then(|p| p.parse::<u32>().ok());
1408 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1409 DataType::Decimal { precision, scale }
1410 }
1411 _ => DataType::Custom { name },
1412 }
1413 }
1414 DataType::Decimal {
1416 precision: None,
1417 scale: None,
1418 } => DataType::Decimal {
1419 precision: Some(38),
1420 scale: Some(0),
1421 },
1422 DataType::Float { .. } => DataType::Double {
1424 precision: None,
1425 scale: None,
1426 },
1427 other => other,
1429 };
1430 Ok(Expression::DataType(transformed))
1431 }
1432
1433 fn map_date_part(abbr: &str) -> Option<&'static str> {
1435 match abbr.to_uppercase().as_str() {
1436 "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some("YEAR"),
1438 "MM" | "MON" | "MONS" | "MONTHS" => Some("MONTH"),
1440 "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some("DAY"),
1442 "DAY OF WEEK" | "WEEKDAY" | "DOW" | "DW" => Some("DAYOFWEEK"),
1444 "WEEKDAY_ISO" | "DOW_ISO" | "DW_ISO" | "DAYOFWEEK_ISO" => Some("DAYOFWEEKISO"),
1445 "DAY OF YEAR" | "DOY" | "DY" => Some("DAYOFYEAR"),
1447 "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY" => Some("WEEK"),
1449 "WEEK_ISO" | "WEEKOFYEARISO" | "WEEKOFYEAR_ISO" => Some("WEEKISO"),
1450 "Q" | "QTR" | "QTRS" | "QUARTERS" => Some("QUARTER"),
1452 "H" | "HH" | "HR" | "HOURS" | "HRS" => Some("HOUR"),
1454 "MI" | "MIN" | "MINUTES" | "MINS" => Some("MINUTE"),
1456 "S" | "SEC" | "SECONDS" | "SECS" => Some("SECOND"),
1458 "MS" | "MSEC" | "MSECS" | "MSECOND" | "MSECONDS" | "MILLISEC" | "MILLISECS"
1460 | "MILLISECON" | "MILLISECONDS" => Some("MILLISECOND"),
1461 "US" | "USEC" | "USECS" | "MICROSEC" | "MICROSECS" | "USECOND" | "USECONDS"
1463 | "MICROSECONDS" => Some("MICROSECOND"),
1464 "NS" | "NSEC" | "NANOSEC" | "NSECOND" | "NSECONDS" | "NANOSECS" => Some("NANOSECOND"),
1466 "EPOCH_SECOND" | "EPOCH_SECONDS" => Some("EPOCH_SECOND"),
1468 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Some("EPOCH_MILLISECOND"),
1469 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Some("EPOCH_MICROSECOND"),
1470 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Some("EPOCH_NANOSECOND"),
1471 "TZH" => Some("TIMEZONE_HOUR"),
1473 "TZM" => Some("TIMEZONE_MINUTE"),
1474 "DEC" | "DECS" | "DECADES" => Some("DECADE"),
1476 "MIL" | "MILS" | "MILLENIA" => Some("MILLENNIUM"),
1478 "C" | "CENT" | "CENTS" | "CENTURIES" => Some("CENTURY"),
1480 _ => None,
1482 }
1483 }
1484
1485 fn transform_date_part_arg(&self, expr: Expression) -> Expression {
1487 match &expr {
1488 Expression::Literal(lit)
1490 if matches!(lit.as_ref(), crate::expressions::Literal::String(_)) =>
1491 {
1492 let crate::expressions::Literal::String(s) = lit.as_ref() else {
1493 unreachable!()
1494 };
1495 Expression::Identifier(crate::expressions::Identifier {
1496 name: s.clone(),
1497 quoted: false,
1498 trailing_comments: Vec::new(),
1499 span: None,
1500 })
1501 }
1502 Expression::Identifier(id) => {
1504 if let Some(canonical) = Self::map_date_part(&id.name) {
1505 Expression::Identifier(crate::expressions::Identifier {
1506 name: canonical.to_string(),
1507 quoted: false,
1508 trailing_comments: Vec::new(),
1509 span: None,
1510 })
1511 } else {
1512 expr
1514 }
1515 }
1516 Expression::Var(v) => {
1517 if let Some(canonical) = Self::map_date_part(&v.this) {
1518 Expression::Identifier(crate::expressions::Identifier {
1519 name: canonical.to_string(),
1520 quoted: false,
1521 trailing_comments: Vec::new(),
1522 span: None,
1523 })
1524 } else {
1525 expr
1526 }
1527 }
1528 Expression::Column(col) if col.table.is_none() => {
1530 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1531 Expression::Identifier(crate::expressions::Identifier {
1532 name: canonical.to_string(),
1533 quoted: false,
1534 trailing_comments: Vec::new(),
1535 span: None,
1536 })
1537 } else {
1538 expr
1540 }
1541 }
1542 _ => expr,
1543 }
1544 }
1545
1546 fn transform_date_part_arg_identifiers_only(&self, expr: Expression) -> Expression {
1549 match &expr {
1550 Expression::Identifier(id) => {
1551 if let Some(canonical) = Self::map_date_part(&id.name) {
1552 Expression::Identifier(crate::expressions::Identifier {
1553 name: canonical.to_string(),
1554 quoted: false,
1555 trailing_comments: Vec::new(),
1556 span: None,
1557 })
1558 } else {
1559 expr
1560 }
1561 }
1562 Expression::Var(v) => {
1563 if let Some(canonical) = Self::map_date_part(&v.this) {
1564 Expression::Identifier(crate::expressions::Identifier {
1565 name: canonical.to_string(),
1566 quoted: false,
1567 trailing_comments: Vec::new(),
1568 span: None,
1569 })
1570 } else {
1571 expr
1572 }
1573 }
1574 Expression::Column(col) if col.table.is_none() => {
1575 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1576 Expression::Identifier(crate::expressions::Identifier {
1577 name: canonical.to_string(),
1578 quoted: false,
1579 trailing_comments: Vec::new(),
1580 span: None,
1581 })
1582 } else {
1583 expr
1584 }
1585 }
1586 _ => expr,
1587 }
1588 }
1589
1590 fn transform_json_path(path: &str) -> String {
1594 fn is_safe_identifier(s: &str) -> bool {
1597 if s.is_empty() {
1598 return false;
1599 }
1600 let mut chars = s.chars();
1601 match chars.next() {
1602 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
1603 _ => return false,
1604 }
1605 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
1606 }
1607
1608 if !path.contains('.') && !path.contains('[') && !path.contains(':') {
1611 if is_safe_identifier(path) {
1612 return path.to_string();
1613 } else {
1614 return format!("[\"{}\"]", path);
1616 }
1617 }
1618
1619 let result = path.replace(':', ".");
1622 result
1623 }
1624
1625 fn transform_interval(&self, interval: crate::expressions::Interval) -> Result<Expression> {
1627 use crate::expressions::{Interval, Literal};
1628
1629 fn expand_unit(abbr: &str) -> &'static str {
1631 match abbr.to_uppercase().as_str() {
1632 "D" => "DAY",
1633 "H" => "HOUR",
1634 "M" => "MINUTE",
1635 "MS" => "MILLISECOND",
1636 "NS" => "NANOSECOND",
1637 "Q" => "QUARTER",
1638 "S" => "SECOND",
1639 "US" => "MICROSECOND",
1640 "W" => "WEEK",
1641 "Y" => "YEAR",
1642 "WEEK" | "WEEKS" => "WEEK",
1644 "DAY" | "DAYS" => "DAY",
1645 "HOUR" | "HOURS" => "HOUR",
1646 "MINUTE" | "MINUTES" => "MINUTE",
1647 "SECOND" | "SECONDS" => "SECOND",
1648 "MONTH" | "MONTHS" => "MONTH",
1649 "YEAR" | "YEARS" => "YEAR",
1650 "QUARTER" | "QUARTERS" => "QUARTER",
1651 "MILLISECOND" | "MILLISECONDS" => "MILLISECOND",
1652 "MICROSECOND" | "MICROSECONDS" => "MICROSECOND",
1653 "NANOSECOND" | "NANOSECONDS" => "NANOSECOND",
1654 _ => "", }
1656 }
1657
1658 fn parse_interval_string(s: &str) -> Option<(&str, &str)> {
1660 let s = s.trim();
1661
1662 let mut num_end = 0;
1665 let mut chars = s.chars().peekable();
1666
1667 if chars.peek() == Some(&'-') {
1669 chars.next();
1670 num_end += 1;
1671 }
1672
1673 while let Some(&c) = chars.peek() {
1675 if c.is_ascii_digit() {
1676 chars.next();
1677 num_end += 1;
1678 } else {
1679 break;
1680 }
1681 }
1682
1683 if chars.peek() == Some(&'.') {
1685 chars.next();
1686 num_end += 1;
1687 while let Some(&c) = chars.peek() {
1688 if c.is_ascii_digit() {
1689 chars.next();
1690 num_end += 1;
1691 } else {
1692 break;
1693 }
1694 }
1695 }
1696
1697 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1698 return None; }
1700
1701 let value = &s[..num_end];
1702 let rest = s[num_end..].trim();
1703
1704 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1706 return None;
1707 }
1708
1709 Some((value, rest))
1710 }
1711
1712 if let Some(Expression::Literal(ref lit)) = interval.this {
1714 if let Literal::String(ref s) = lit.as_ref() {
1715 if let Some((value, unit)) = parse_interval_string(s) {
1716 let expanded = expand_unit(unit);
1717 if !expanded.is_empty() {
1718 let new_value = format!("{} {}", value, expanded);
1720
1721 return Ok(Expression::Interval(Box::new(Interval {
1722 this: Some(Expression::Literal(Box::new(Literal::String(new_value)))),
1723 unit: None, })));
1725 }
1726 }
1727 }
1728 }
1729
1730 Ok(Expression::Interval(Box::new(interval)))
1732 }
1733
1734 fn transform_function(&self, f: Function) -> Result<Expression> {
1735 let transformed_args: Vec<Expression> = f
1737 .args
1738 .into_iter()
1739 .map(|arg| self.transform_expr(arg))
1740 .collect::<Result<Vec<_>>>()?;
1741
1742 let f = Function {
1743 name: f.name,
1744 args: transformed_args,
1745 distinct: f.distinct,
1746 trailing_comments: f.trailing_comments,
1747 use_bracket_syntax: f.use_bracket_syntax,
1748 no_parens: f.no_parens,
1749 quoted: f.quoted,
1750 span: None,
1751 inferred_type: None,
1752 };
1753
1754 let name_upper = f.name.to_uppercase();
1755 match name_upper.as_str() {
1756 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1758 original_name: None,
1759 expressions: f.args,
1760 inferred_type: None,
1761 }))),
1762
1763 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1765 original_name: None,
1766 expressions: f.args,
1767 inferred_type: None,
1768 }))),
1769
1770 "NVL2" => Ok(Expression::Function(Box::new(f))),
1772
1773 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1775 Function::new("LISTAGG".to_string(), f.args),
1776 ))),
1777
1778 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1780 Function::new("LISTAGG".to_string(), f.args),
1781 ))),
1782
1783 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1785 "SUBSTRING".to_string(),
1786 f.args,
1787 )))),
1788
1789 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
1791 "FLATTEN".to_string(),
1792 f.args,
1793 )))),
1794
1795 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1797 "FLATTEN".to_string(),
1798 f.args,
1799 )))),
1800
1801 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1803
1804 "NOW" => Ok(Expression::Function(Box::new(Function {
1806 name: "CURRENT_TIMESTAMP".to_string(),
1807 args: f.args,
1808 distinct: false,
1809 trailing_comments: Vec::new(),
1810 use_bracket_syntax: false,
1811 no_parens: f.no_parens,
1812 quoted: false,
1813 span: None,
1814 inferred_type: None,
1815 }))),
1816
1817 "GETDATE" => Ok(Expression::Function(Box::new(Function {
1819 name: "CURRENT_TIMESTAMP".to_string(),
1820 args: f.args,
1821 distinct: false,
1822 trailing_comments: Vec::new(),
1823 use_bracket_syntax: false,
1824 no_parens: f.no_parens,
1825 quoted: false,
1826 span: None,
1827 inferred_type: None,
1828 }))),
1829
1830 "CURRENT_TIMESTAMP" if f.args.is_empty() => {
1834 Ok(Expression::Function(Box::new(Function {
1835 name: "CURRENT_TIMESTAMP".to_string(),
1836 args: Vec::new(),
1837 distinct: false,
1838 trailing_comments: Vec::new(),
1839 use_bracket_syntax: false,
1840 no_parens: false, quoted: false,
1842 span: None,
1843 inferred_type: None,
1844 })))
1845 }
1846
1847 "TO_DATE" => {
1851 if f.args.len() == 1 {
1852 if let Expression::Literal(lit) = &f.args[0] {
1853 if let crate::expressions::Literal::String(s) = lit.as_ref() {
1854 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
1856 return Ok(Expression::Cast(Box::new(Cast {
1857 this: f.args.into_iter().next().unwrap(),
1858 to: crate::expressions::DataType::Date,
1859 double_colon_syntax: false,
1860 trailing_comments: Vec::new(),
1861 format: None,
1862 default: None,
1863 inferred_type: None,
1864 })));
1865 }
1866 }
1867 }
1868 }
1869 let mut args = f.args;
1871 if args.len() >= 2 {
1872 args[1] = Self::normalize_format_arg(args[1].clone());
1873 }
1874 Ok(Expression::Function(Box::new(Function::new(
1875 "TO_DATE".to_string(),
1876 args,
1877 ))))
1878 }
1879
1880 "TO_TIME" => {
1882 if f.args.len() == 1 {
1883 if let Expression::Literal(lit) = &f.args[0] {
1884 if let crate::expressions::Literal::String(_) = lit.as_ref() {
1885 return Ok(Expression::Cast(Box::new(Cast {
1886 this: f.args.into_iter().next().unwrap(),
1887 to: crate::expressions::DataType::Time {
1888 precision: None,
1889 timezone: false,
1890 },
1891 double_colon_syntax: false,
1892 trailing_comments: Vec::new(),
1893 format: None,
1894 default: None,
1895 inferred_type: None,
1896 })));
1897 }
1898 }
1899 }
1900 let mut args = f.args;
1902 if args.len() >= 2 {
1903 args[1] = Self::normalize_format_arg(args[1].clone());
1904 }
1905 Ok(Expression::Function(Box::new(Function::new(
1906 "TO_TIME".to_string(),
1907 args,
1908 ))))
1909 }
1910
1911 "TO_TIMESTAMP" => {
1918 let args = f.args;
1919 if args.len() == 1 {
1920 let arg = &args[0];
1921 match arg {
1922 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_datetime(s)) =>
1923 {
1924 let Literal::String(_) = lit.as_ref() else {
1925 unreachable!()
1926 };
1927 return Ok(Expression::Cast(Box::new(Cast {
1929 this: args.into_iter().next().unwrap(),
1930 to: DataType::Timestamp {
1931 precision: None,
1932 timezone: false,
1933 },
1934 double_colon_syntax: false,
1935 trailing_comments: vec![],
1936 format: None,
1937 default: None,
1938 inferred_type: None,
1939 })));
1940 }
1941 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_epoch(s)) =>
1942 {
1943 let Literal::String(_) = lit.as_ref() else {
1944 unreachable!()
1945 };
1946 return Ok(Expression::UnixToTime(Box::new(
1948 crate::expressions::UnixToTime {
1949 this: Box::new(args.into_iter().next().unwrap()),
1950 scale: None,
1951 zone: None,
1952 hours: None,
1953 minutes: None,
1954 format: None,
1955 target_type: None,
1956 },
1957 )));
1958 }
1959 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1960 return Ok(Expression::UnixToTime(Box::new(
1962 crate::expressions::UnixToTime {
1963 this: Box::new(args.into_iter().next().unwrap()),
1964 scale: None,
1965 zone: None,
1966 hours: None,
1967 minutes: None,
1968 format: None,
1969 target_type: None,
1970 },
1971 )));
1972 }
1973 Expression::Neg(_) => {
1974 return Ok(Expression::UnixToTime(Box::new(
1976 crate::expressions::UnixToTime {
1977 this: Box::new(args.into_iter().next().unwrap()),
1978 scale: None,
1979 zone: None,
1980 hours: None,
1981 minutes: None,
1982 format: None,
1983 target_type: None,
1984 },
1985 )));
1986 }
1987 _ => {
1988 return Ok(Expression::Function(Box::new(Function::new(
1990 "TO_TIMESTAMP".to_string(),
1991 args,
1992 ))));
1993 }
1994 }
1995 } else if args.len() == 2 {
1996 let second_arg = &args[1];
1997 let is_int_scale = match second_arg {
1999 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
2000 let Literal::Number(n) = lit.as_ref() else {
2001 unreachable!()
2002 };
2003 n.parse::<i64>().is_ok()
2004 }
2005 _ => false,
2006 };
2007
2008 if is_int_scale {
2009 let mut args_iter = args.into_iter();
2011 let value = args_iter.next().unwrap();
2012 let scale_expr = args_iter.next().unwrap();
2013 let scale = if let Expression::Literal(lit) = &scale_expr {
2014 if let Literal::Number(n) = lit.as_ref() {
2015 n.parse::<i64>().ok()
2016 } else {
2017 None
2018 }
2019 } else {
2020 None
2021 };
2022 return Ok(Expression::UnixToTime(Box::new(
2023 crate::expressions::UnixToTime {
2024 this: Box::new(value),
2025 scale,
2026 zone: None,
2027 hours: None,
2028 minutes: None,
2029 format: None,
2030 target_type: None,
2031 },
2032 )));
2033 } else {
2034 let mut args_iter = args.into_iter();
2036 let value = args_iter.next().unwrap();
2037 let format_expr = args_iter.next().unwrap();
2038 let format_str = match &format_expr {
2039 Expression::Literal(lit)
2040 if matches!(lit.as_ref(), Literal::String(_)) =>
2041 {
2042 let Literal::String(s) = lit.as_ref() else {
2043 unreachable!()
2044 };
2045 s.clone()
2046 }
2047 _ => {
2048 return Ok(Expression::Function(Box::new(Function::new(
2050 "TO_TIMESTAMP".to_string(),
2051 vec![value, format_expr],
2052 ))));
2053 }
2054 };
2055 let normalized_format = Self::normalize_snowflake_format(&format_str);
2057 return Ok(Expression::StrToTime(Box::new(
2058 crate::expressions::StrToTime {
2059 this: Box::new(value),
2060 format: normalized_format,
2061 zone: None,
2062 safe: None,
2063 target_type: None,
2064 },
2065 )));
2066 }
2067 }
2068 Ok(Expression::Function(Box::new(Function::new(
2070 "TO_TIMESTAMP".to_string(),
2071 args,
2072 ))))
2073 }
2074
2075 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
2077
2078 "ROUND"
2081 if f.args
2082 .iter()
2083 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
2084 {
2085 let mut expr_val = None;
2086 let mut scale_val = None;
2087 let mut rounding_mode_val = None;
2088 for arg in &f.args {
2089 if let Expression::NamedArgument(na) = arg {
2090 match na.name.name.to_uppercase().as_str() {
2091 "EXPR" => expr_val = Some(na.value.clone()),
2092 "SCALE" => scale_val = Some(na.value.clone()),
2093 "ROUNDING_MODE" => rounding_mode_val = Some(na.value.clone()),
2094 _ => {}
2095 }
2096 }
2097 }
2098 if let Some(expr) = expr_val {
2099 let mut args = vec![expr];
2100 if let Some(scale) = scale_val {
2101 args.push(scale);
2102 }
2103 if let Some(mode) = rounding_mode_val {
2104 args.push(mode);
2105 }
2106 Ok(Expression::Function(Box::new(Function::new(
2107 "ROUND".to_string(),
2108 args,
2109 ))))
2110 } else {
2111 Ok(Expression::Function(Box::new(f)))
2112 }
2113 }
2114
2115 "DATE_FORMAT" => {
2118 let mut args = f.args;
2119 if !args.is_empty() {
2121 if matches!(&args[0], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)))
2122 {
2123 args[0] = Expression::Cast(Box::new(crate::expressions::Cast {
2124 this: args[0].clone(),
2125 to: DataType::Timestamp {
2126 precision: None,
2127 timezone: false,
2128 },
2129 trailing_comments: Vec::new(),
2130 double_colon_syntax: false,
2131 format: None,
2132 default: None,
2133 inferred_type: None,
2134 }));
2135 }
2136 }
2137 if args.len() >= 2 {
2139 if let Expression::Literal(ref lit) = args[1] {
2140 if let Literal::String(ref fmt) = lit.as_ref() {
2141 let sf_fmt = strftime_to_snowflake_format(fmt);
2142 args[1] = Expression::Literal(Box::new(Literal::String(sf_fmt)));
2143 }
2144 }
2145 }
2146 Ok(Expression::Function(Box::new(Function::new(
2147 "TO_CHAR".to_string(),
2148 args,
2149 ))))
2150 }
2151
2152 "ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2154 "ARRAY_CONSTRUCT".to_string(),
2155 f.args,
2156 )))),
2157
2158 "STRUCT" => {
2161 let mut oc_args = Vec::new();
2162 for arg in f.args {
2163 match arg {
2164 Expression::Alias(a) => {
2165 oc_args.push(Expression::Literal(Box::new(
2167 crate::expressions::Literal::String(a.alias.name.clone()),
2168 )));
2169 oc_args.push(a.this);
2170 }
2171 other => {
2172 oc_args.push(other);
2174 }
2175 }
2176 }
2177 Ok(Expression::Function(Box::new(Function::new(
2178 "OBJECT_CONSTRUCT".to_string(),
2179 oc_args,
2180 ))))
2181 }
2182
2183 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2185 "GET_PATH".to_string(),
2186 f.args,
2187 )))),
2188
2189 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2191 "JSON_EXTRACT_PATH_TEXT".to_string(),
2192 f.args,
2193 )))),
2194
2195 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2197 f.args.into_iter().next().unwrap(),
2198 )))),
2199
2200 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2202 this: f.args.into_iter().next().unwrap(),
2203 decimals: None,
2204 to: None,
2205 }))),
2206
2207 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2209
2210 "SPLIT" => Ok(Expression::Function(Box::new(f))),
2212
2213 "ARRAY_AGG" => Ok(Expression::Function(Box::new(f))),
2215
2216 "JSON_PARSE" | "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2218 "PARSE_JSON".to_string(),
2219 f.args,
2220 )))),
2221
2222 "RAND" => {
2224 let seed = f.args.first().cloned().map(Box::new);
2225 Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2226 seed,
2227 lower: None,
2228 upper: None,
2229 })))
2230 }
2231
2232 "SHA" => Ok(Expression::Function(Box::new(Function::new(
2234 "SHA1".to_string(),
2235 f.args,
2236 )))),
2237
2238 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
2240 "APPROX_COUNT_DISTINCT".to_string(),
2241 f.args,
2242 )))),
2243
2244 "GEN_RANDOM_UUID" | "UUID" => {
2246 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2247 this: None,
2248 name: None,
2249 is_string: None,
2250 })))
2251 }
2252
2253 "NEWID" => Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2255 this: None,
2256 name: None,
2257 is_string: None,
2258 }))),
2259
2260 "UUID_STRING" => {
2262 if f.args.is_empty() {
2263 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2264 this: None,
2265 name: None,
2266 is_string: None,
2267 })))
2268 } else {
2269 Ok(Expression::Function(Box::new(Function::new(
2270 "UUID_STRING".to_string(),
2271 f.args,
2272 ))))
2273 }
2274 }
2275
2276 "IF" if f.args.len() >= 2 => {
2278 let mut args = f.args;
2279 let condition = args.remove(0);
2280 let true_val = args.remove(0);
2281 let false_val = if !args.is_empty() {
2282 Some(args.remove(0))
2283 } else {
2284 None
2285 };
2286 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2287 condition,
2288 true_value: true_val,
2289 false_value: Some(
2290 false_val.unwrap_or(Expression::Null(crate::expressions::Null)),
2291 ),
2292 original_name: Some("IFF".to_string()),
2293 inferred_type: None,
2294 })))
2295 }
2296
2297 "SQUARE" if f.args.len() == 1 => {
2299 let x = f.args.into_iter().next().unwrap();
2300 Ok(Expression::Power(Box::new(
2301 crate::expressions::BinaryFunc {
2302 original_name: None,
2303 this: x,
2304 expression: Expression::number(2),
2305 inferred_type: None,
2306 },
2307 )))
2308 }
2309
2310 "POW" if f.args.len() == 2 => {
2312 let mut args = f.args.into_iter();
2313 let x = args.next().unwrap();
2314 let y = args.next().unwrap();
2315 Ok(Expression::Power(Box::new(
2316 crate::expressions::BinaryFunc {
2317 original_name: None,
2318 this: x,
2319 expression: y,
2320 inferred_type: None,
2321 },
2322 )))
2323 }
2324
2325 "MOD" if f.args.len() == 2 => {
2327 let mut args = f.args.into_iter();
2328 let x = args.next().unwrap();
2329 let y = args.next().unwrap();
2330 Ok(Expression::Mod(Box::new(crate::expressions::BinaryOp {
2331 left: x,
2332 right: y,
2333 left_comments: Vec::new(),
2334 operator_comments: Vec::new(),
2335 trailing_comments: Vec::new(),
2336 inferred_type: None,
2337 })))
2338 }
2339
2340 "APPROXIMATE_JACCARD_INDEX" => Ok(Expression::Function(Box::new(Function::new(
2342 "APPROXIMATE_SIMILARITY".to_string(),
2343 f.args,
2344 )))),
2345
2346 "ARRAY_CONSTRUCT" => Ok(Expression::ArrayFunc(Box::new(
2348 crate::expressions::ArrayConstructor {
2349 expressions: f.args,
2350 bracket_notation: true,
2351 use_list_keyword: false,
2352 },
2353 ))),
2354
2355 "APPROX_TOP_K" if f.args.len() == 1 => {
2357 let mut args = f.args;
2358 args.push(Expression::number(1));
2359 Ok(Expression::Function(Box::new(Function::new(
2360 "APPROX_TOP_K".to_string(),
2361 args,
2362 ))))
2363 }
2364
2365 "TO_DECIMAL" | "TO_NUMERIC" => Ok(Expression::Function(Box::new(Function::new(
2367 "TO_NUMBER".to_string(),
2368 f.args,
2369 )))),
2370
2371 "TRY_TO_DECIMAL" | "TRY_TO_NUMERIC" => Ok(Expression::Function(Box::new(
2373 Function::new("TRY_TO_NUMBER".to_string(), f.args),
2374 ))),
2375
2376 "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2378 "STDDEV".to_string(),
2379 f.args,
2380 )))),
2381
2382 "STRTOK" if f.args.len() >= 1 => {
2384 let mut args = f.args;
2385 if args.len() == 1 {
2387 args.push(Expression::string(" ".to_string()));
2388 }
2389 if args.len() == 2 {
2391 args.push(Expression::number(1));
2392 }
2393 Ok(Expression::Function(Box::new(Function::new(
2394 "STRTOK".to_string(),
2395 args,
2396 ))))
2397 }
2398
2399 "STRTOK_TO_ARRAY" if f.args.len() == 1 => {
2400 let mut args = f.args;
2401 args.push(Expression::string(" ".to_string()));
2402 Ok(Expression::Function(Box::new(Function::new(
2403 "STRTOK_TO_ARRAY".to_string(),
2404 args,
2405 ))))
2406 }
2407
2408 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2410 "WEEK".to_string(),
2411 f.args,
2412 )))),
2413
2414 "LIKE" if f.args.len() >= 2 => {
2416 let mut args = f.args.into_iter();
2417 let left = args.next().unwrap();
2418 let right = args.next().unwrap();
2419 let escape = args.next();
2420 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2421 left,
2422 right,
2423 escape,
2424 quantifier: None,
2425 inferred_type: None,
2426 })))
2427 }
2428
2429 "ILIKE" if f.args.len() >= 2 => {
2431 let mut args = f.args.into_iter();
2432 let left = args.next().unwrap();
2433 let right = args.next().unwrap();
2434 let escape = args.next();
2435 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2436 left,
2437 right,
2438 escape,
2439 quantifier: None,
2440 inferred_type: None,
2441 })))
2442 }
2443
2444 "RLIKE" if f.args.len() >= 2 => {
2446 let mut args = f.args.into_iter();
2447 let left = args.next().unwrap();
2448 let pattern = args.next().unwrap();
2449 let flags = args.next();
2450 Ok(Expression::RegexpLike(Box::new(
2451 crate::expressions::RegexpFunc {
2452 this: left,
2453 pattern,
2454 flags,
2455 },
2456 )))
2457 }
2458
2459 "IFF" if f.args.len() >= 2 => {
2461 let mut args = f.args;
2462 let condition = args.remove(0);
2463 let true_value = args.remove(0);
2464 let false_value = if !args.is_empty() {
2465 Some(args.remove(0))
2466 } else {
2467 None
2468 };
2469 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2470 condition,
2471 true_value,
2472 false_value,
2473 original_name: Some("IFF".to_string()),
2474 inferred_type: None,
2475 })))
2476 }
2477
2478 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2480 Ok(Expression::Function(Box::new(Function::new(
2481 "TIMESTAMP_FROM_PARTS".to_string(),
2482 f.args,
2483 ))))
2484 }
2485
2486 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2488 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2489 f.args,
2490 )))),
2491
2492 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2494 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2495 f.args,
2496 )))),
2497
2498 "DATEADD" if f.args.len() >= 1 => {
2500 let mut args = f.args;
2501 args[0] = self.transform_date_part_arg(args[0].clone());
2502 Ok(Expression::Function(Box::new(Function::new(
2503 "DATEADD".to_string(),
2504 args,
2505 ))))
2506 }
2507
2508 "DATEDIFF" if f.args.len() >= 1 => {
2511 let mut args = f.args;
2512 args[0] = self.transform_date_part_arg(args[0].clone());
2513 for i in 1..args.len() {
2516 if let Expression::Function(ref func) = args[i] {
2517 if func.name == "_POLYGLOT_TO_DATE" {
2518 let inner_args = func.args.clone();
2519 args[i] = Expression::Function(Box::new(Function::new(
2520 "TO_DATE".to_string(),
2521 inner_args,
2522 )));
2523 }
2524 }
2525 }
2526 Ok(Expression::Function(Box::new(Function::new(
2527 "DATEDIFF".to_string(),
2528 args,
2529 ))))
2530 }
2531
2532 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2534 "DATEDIFF".to_string(),
2535 f.args,
2536 )))),
2537
2538 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2540 "DATEDIFF".to_string(),
2541 f.args,
2542 )))),
2543
2544 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2546 "DATEADD".to_string(),
2547 f.args,
2548 )))),
2549
2550 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2552
2553 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2555 "DATE_FROM_PARTS".to_string(),
2556 f.args,
2557 )))),
2558
2559 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2561 "TIME_FROM_PARTS".to_string(),
2562 f.args,
2563 )))),
2564
2565 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2567
2568 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2570
2571 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2573
2574 "MONTHNAME" if f.args.len() == 1 => {
2577 let arg = f.args.into_iter().next().unwrap();
2578 Ok(Expression::Monthname(Box::new(
2579 crate::expressions::Monthname {
2580 this: Box::new(arg),
2581 abbreviated: Some(Box::new(Expression::Literal(Box::new(
2582 Literal::String("true".to_string()),
2583 )))),
2584 },
2585 )))
2586 }
2587
2588 "DAYNAME" if f.args.len() == 1 => {
2591 let arg = f.args.into_iter().next().unwrap();
2592 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2593 this: Box::new(arg),
2594 abbreviated: Some(Box::new(Expression::Literal(Box::new(Literal::String(
2595 "true".to_string(),
2596 ))))),
2597 })))
2598 }
2599
2600 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2602 let arg = f.args.into_iter().next().unwrap();
2603 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2604 this: arg,
2605 distinct: false,
2606 filter: None,
2607 order_by: Vec::new(),
2608 name: Some("BOOLAND_AGG".to_string()),
2609 ignore_nulls: None,
2610 having_max: None,
2611 limit: None,
2612 inferred_type: None,
2613 })))
2614 }
2615
2616 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2618 let arg = f.args.into_iter().next().unwrap();
2619 Ok(Expression::LogicalOr(Box::new(AggFunc {
2620 this: arg,
2621 distinct: false,
2622 filter: None,
2623 order_by: Vec::new(),
2624 name: Some("BOOLOR_AGG".to_string()),
2625 ignore_nulls: None,
2626 having_max: None,
2627 limit: None,
2628 inferred_type: None,
2629 })))
2630 }
2631
2632 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2634 let arg = f.args.into_iter().next().unwrap();
2635 Ok(Expression::Skewness(Box::new(AggFunc {
2636 this: arg,
2637 distinct: false,
2638 filter: None,
2639 order_by: Vec::new(),
2640 name: Some("SKEW".to_string()),
2641 ignore_nulls: None,
2642 having_max: None,
2643 limit: None,
2644 inferred_type: None,
2645 })))
2646 }
2647
2648 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2650 "VARIANCE".to_string(),
2651 f.args,
2652 )))),
2653
2654 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2656 "VARIANCE_POP".to_string(),
2657 f.args,
2658 )))),
2659
2660 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2662 "TO_DATE".to_string(),
2663 f.args,
2664 )))),
2665 "DATE" if f.args.len() >= 2 => {
2669 let mut args = f.args;
2670 args[1] = Self::normalize_format_arg(args[1].clone());
2671 Ok(Expression::Function(Box::new(Function::new(
2672 "TO_DATE".to_string(),
2673 args,
2674 ))))
2675 }
2676 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2679 let mut args = f.args;
2680 args[1] = Self::normalize_format_arg(args[1].clone());
2681 Ok(Expression::Function(Box::new(Function::new(
2682 "DATE".to_string(),
2683 args,
2684 ))))
2685 }
2686
2687 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2689
2690 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2692 "MD5".to_string(),
2693 f.args,
2694 )))),
2695
2696 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2698 "SHA1".to_string(),
2699 f.args,
2700 )))),
2701
2702 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2704 "SHA2".to_string(),
2705 f.args,
2706 )))),
2707
2708 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2710 "EDITDISTANCE".to_string(),
2711 f.args,
2712 )))),
2713
2714 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2716 "BITNOT".to_string(),
2717 f.args,
2718 )))),
2719
2720 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2722 "BITAND".to_string(),
2723 f.args,
2724 )))),
2725
2726 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2728 "BITOR".to_string(),
2729 f.args,
2730 )))),
2731
2732 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2734 "BITXOR".to_string(),
2735 f.args,
2736 )))),
2737
2738 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2740 Function::new("BITSHIFTLEFT".to_string(), f.args),
2741 ))),
2742
2743 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2745 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2746 ))),
2747
2748 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2750 name: "CURRENT_TIMESTAMP".to_string(),
2751 args: f.args,
2752 distinct: false,
2753 trailing_comments: Vec::new(),
2754 use_bracket_syntax: false,
2755 no_parens: f.no_parens,
2756 quoted: false,
2757 span: None,
2758 inferred_type: None,
2759 }))),
2760
2761 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2763 name: "CURRENT_TIMESTAMP".to_string(),
2764 args: f.args,
2765 distinct: false,
2766 trailing_comments: Vec::new(),
2767 use_bracket_syntax: false,
2768 no_parens: f.no_parens,
2769 quoted: false,
2770 span: None,
2771 inferred_type: None,
2772 }))),
2773
2774 "SPACE" if f.args.len() == 1 => {
2776 let arg = f.args.into_iter().next().unwrap();
2777 Ok(Expression::Function(Box::new(Function::new(
2778 "REPEAT".to_string(),
2779 vec![
2780 Expression::Literal(Box::new(Literal::String(" ".to_string()))),
2781 arg,
2782 ],
2783 ))))
2784 }
2785
2786 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2788 "CEIL".to_string(),
2789 f.args,
2790 )))),
2791
2792 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2794 "LN".to_string(),
2795 f.args,
2796 )))),
2797
2798 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(f))),
2800
2801 "GET_PATH" if f.args.len() >= 2 => {
2805 let mut args = f.args;
2806 if let Expression::Literal(lit) = &args[1] {
2808 if let crate::expressions::Literal::String(path) = lit.as_ref() {
2809 let transformed = Self::transform_json_path(path);
2810 args[1] = Expression::Literal(Box::new(
2811 crate::expressions::Literal::String(transformed),
2812 ));
2813 }
2814 }
2815 Ok(Expression::Function(Box::new(Function::new(
2816 "GET_PATH".to_string(),
2817 args,
2818 ))))
2819 }
2820 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2821
2822 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2824
2825 "DATE_TRUNC" if f.args.len() >= 1 => {
2828 let mut args = f.args;
2829 let unit_name = match &args[0] {
2831 Expression::Identifier(id) => Some(id.name.as_str()),
2832 Expression::Var(v) => Some(v.this.as_str()),
2833 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2834 _ => None,
2835 };
2836 if let Some(name) = unit_name {
2837 let canonical = Self::map_date_part(name).unwrap_or(name);
2838 args[0] = Expression::Literal(Box::new(crate::expressions::Literal::String(
2839 canonical.to_uppercase(),
2840 )));
2841 }
2842 Ok(Expression::Function(Box::new(Function::new(
2843 "DATE_TRUNC".to_string(),
2844 args,
2845 ))))
2846 }
2847
2848 "DATE_PART" if f.args.len() >= 1 => {
2854 let mut args = f.args;
2855 let from_typed_literal = args.len() >= 2
2856 && matches!(
2857 &args[1],
2858 Expression::Literal(lit) if matches!(lit.as_ref(),
2859 crate::expressions::Literal::Timestamp(_)
2860 | crate::expressions::Literal::Date(_)
2861 | crate::expressions::Literal::Time(_)
2862 | crate::expressions::Literal::Datetime(_)
2863 )
2864 );
2865 if from_typed_literal {
2866 args[0] = self.transform_date_part_arg(args[0].clone());
2867 } else {
2868 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2871 }
2872 Ok(Expression::Function(Box::new(Function::new(
2873 "DATE_PART".to_string(),
2874 args,
2875 ))))
2876 }
2877
2878 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2880
2881 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2883
2884 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2886 "DESCRIBE".to_string(),
2887 f.args,
2888 )))),
2889
2890 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2892 "REGEXP_LIKE".to_string(),
2893 f.args,
2894 )))),
2895
2896 "TRANSFORM" => {
2901 let transformed_args: Vec<Expression> = f
2902 .args
2903 .into_iter()
2904 .map(|arg| {
2905 if let Expression::Lambda(lambda) = arg {
2906 self.transform_typed_lambda(*lambda)
2907 } else {
2908 arg
2909 }
2910 })
2911 .collect();
2912 Ok(Expression::Function(Box::new(Function::new(
2913 "TRANSFORM".to_string(),
2914 transformed_args,
2915 ))))
2916 }
2917
2918 "SEARCH" if f.args.len() >= 2 => {
2920 let mut args = f.args.into_iter();
2921 let this = Box::new(args.next().unwrap());
2922 let expression = Box::new(args.next().unwrap());
2923
2924 let mut analyzer: Option<Box<Expression>> = None;
2925 let mut search_mode: Option<Box<Expression>> = None;
2926
2927 for arg in args {
2929 if let Expression::NamedArgument(na) = &arg {
2930 let name_upper = na.name.name.to_uppercase();
2931 match name_upper.as_str() {
2932 "ANALYZER" => analyzer = Some(Box::new(arg)),
2933 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2934 _ => {}
2935 }
2936 }
2937 }
2938
2939 Ok(Expression::Search(Box::new(crate::expressions::Search {
2940 this,
2941 expression,
2942 json_scope: None,
2943 analyzer,
2944 analyzer_options: None,
2945 search_mode,
2946 })))
2947 }
2948
2949 "CONVERT" if f.args.len() == 2 => {
2952 let value = f.args.get(0).cloned().unwrap();
2953 let type_arg = f.args.get(1).cloned().unwrap();
2954
2955 if let Expression::Column(col) = &type_arg {
2957 let type_name = col.name.name.to_uppercase();
2958 let data_type = match type_name.as_str() {
2959 "SQL_DOUBLE" => Some(DataType::Double {
2960 precision: None,
2961 scale: None,
2962 }),
2963 "SQL_VARCHAR" => Some(DataType::VarChar {
2964 length: None,
2965 parenthesized_length: false,
2966 }),
2967 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2968 length: None,
2969 integer_spelling: false,
2970 }),
2971 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2972 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2973 "SQL_FLOAT" => Some(DataType::Float {
2974 precision: None,
2975 scale: None,
2976 real_spelling: false,
2977 }),
2978 "SQL_REAL" => Some(DataType::Float {
2979 precision: None,
2980 scale: None,
2981 real_spelling: true,
2982 }),
2983 "SQL_DECIMAL" => Some(DataType::Decimal {
2984 precision: None,
2985 scale: None,
2986 }),
2987 "SQL_DATE" => Some(DataType::Date),
2988 "SQL_TIME" => Some(DataType::Time {
2989 precision: None,
2990 timezone: false,
2991 }),
2992 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
2993 precision: None,
2994 timezone: false,
2995 }),
2996 _ => None,
2997 };
2998
2999 if let Some(dt) = data_type {
3000 return Ok(Expression::Cast(Box::new(Cast {
3001 this: value,
3002 to: dt,
3003 double_colon_syntax: false,
3004 trailing_comments: vec![],
3005 format: None,
3006 default: None,
3007 inferred_type: None,
3008 })));
3009 }
3010 }
3011 Ok(Expression::Function(Box::new(f)))
3013 }
3014
3015 "TO_TIMESTAMP_TZ" => {
3018 if f.args.len() == 1 {
3019 if let Expression::Literal(lit) = &f.args[0] {
3020 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3021 return Ok(Expression::Cast(Box::new(Cast {
3022 this: f.args.into_iter().next().unwrap(),
3023 to: DataType::Custom {
3024 name: "TIMESTAMPTZ".to_string(),
3025 },
3026 double_colon_syntax: false,
3027 trailing_comments: vec![],
3028 format: None,
3029 default: None,
3030 inferred_type: None,
3031 })));
3032 }
3033 }
3034 }
3035 Ok(Expression::Function(Box::new(f)))
3036 }
3037
3038 "TO_TIMESTAMP_NTZ" => {
3040 if f.args.len() == 1 {
3041 if let Expression::Literal(lit) = &f.args[0] {
3042 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3043 return Ok(Expression::Cast(Box::new(Cast {
3044 this: f.args.into_iter().next().unwrap(),
3045 to: DataType::Custom {
3046 name: "TIMESTAMPNTZ".to_string(),
3047 },
3048 double_colon_syntax: false,
3049 trailing_comments: vec![],
3050 format: None,
3051 default: None,
3052 inferred_type: None,
3053 })));
3054 }
3055 }
3056 }
3057 Ok(Expression::Function(Box::new(f)))
3058 }
3059
3060 "TO_TIMESTAMP_LTZ" => {
3062 if f.args.len() == 1 {
3063 if let Expression::Literal(lit) = &f.args[0] {
3064 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3065 return Ok(Expression::Cast(Box::new(Cast {
3066 this: f.args.into_iter().next().unwrap(),
3067 to: DataType::Custom {
3068 name: "TIMESTAMPLTZ".to_string(),
3069 },
3070 double_colon_syntax: false,
3071 trailing_comments: vec![],
3072 format: None,
3073 default: None,
3074 inferred_type: None,
3075 })));
3076 }
3077 }
3078 }
3079 Ok(Expression::Function(Box::new(f)))
3080 }
3081
3082 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
3084
3085 "REPLACE" if f.args.len() == 2 => {
3087 let mut args = f.args;
3088 args.push(Expression::Literal(Box::new(
3089 crate::expressions::Literal::String(String::new()),
3090 )));
3091 Ok(Expression::Function(Box::new(Function::new(
3092 "REPLACE".to_string(),
3093 args,
3094 ))))
3095 }
3096
3097 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
3099 "ANY_VALUE".to_string(),
3100 f.args,
3101 )))),
3102
3103 "SAFE_DIVIDE" if f.args.len() == 2 => {
3105 let mut args = f.args;
3106 let x = args.remove(0);
3107 let y = args.remove(0);
3108 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3109 condition: Expression::Neq(Box::new(BinaryOp {
3110 left: y.clone(),
3111 right: Expression::number(0),
3112 left_comments: Vec::new(),
3113 operator_comments: Vec::new(),
3114 trailing_comments: Vec::new(),
3115 inferred_type: None,
3116 })),
3117 true_value: Expression::Div(Box::new(BinaryOp {
3118 left: x,
3119 right: y,
3120 left_comments: Vec::new(),
3121 operator_comments: Vec::new(),
3122 trailing_comments: Vec::new(),
3123 inferred_type: None,
3124 })),
3125 false_value: Some(Expression::Null(crate::expressions::Null)),
3126 original_name: Some("IFF".to_string()),
3127 inferred_type: None,
3128 })))
3129 }
3130
3131 "TIMESTAMP" if f.args.len() == 1 => {
3133 let arg = f.args.into_iter().next().unwrap();
3134 Ok(Expression::Cast(Box::new(Cast {
3135 this: arg,
3136 to: DataType::Custom {
3137 name: "TIMESTAMPTZ".to_string(),
3138 },
3139 trailing_comments: Vec::new(),
3140 double_colon_syntax: false,
3141 format: None,
3142 default: None,
3143 inferred_type: None,
3144 })))
3145 }
3146
3147 "TIMESTAMP" if f.args.len() == 2 => {
3149 let mut args = f.args;
3150 let value = args.remove(0);
3151 let tz = args.remove(0);
3152 Ok(Expression::Function(Box::new(Function::new(
3153 "CONVERT_TIMEZONE".to_string(),
3154 vec![
3155 tz,
3156 Expression::Cast(Box::new(Cast {
3157 this: value,
3158 to: DataType::Timestamp {
3159 precision: None,
3160 timezone: false,
3161 },
3162 trailing_comments: Vec::new(),
3163 double_colon_syntax: false,
3164 format: None,
3165 default: None,
3166 inferred_type: None,
3167 })),
3168 ],
3169 ))))
3170 }
3171
3172 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3174 "TIME_FROM_PARTS".to_string(),
3175 f.args,
3176 )))),
3177
3178 "DIV0" if f.args.len() == 2 => {
3180 let mut args = f.args;
3181 let x = args.remove(0);
3182 let y = args.remove(0);
3183 let x_expr = Self::maybe_paren(x.clone());
3185 let y_expr = Self::maybe_paren(y.clone());
3186 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3187 condition: Expression::And(Box::new(BinaryOp::new(
3188 Expression::Eq(Box::new(BinaryOp::new(
3189 y_expr.clone(),
3190 Expression::number(0),
3191 ))),
3192 Expression::Not(Box::new(crate::expressions::UnaryOp {
3193 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3194 this: x_expr.clone(),
3195 not: false,
3196 postfix_form: false,
3197 })),
3198 inferred_type: None,
3199 })),
3200 ))),
3201 true_value: Expression::number(0),
3202 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3203 original_name: Some("IFF".to_string()),
3204 inferred_type: None,
3205 })))
3206 }
3207
3208 "DIV0NULL" if f.args.len() == 2 => {
3210 let mut args = f.args;
3211 let x = args.remove(0);
3212 let y = args.remove(0);
3213 let x_expr = Self::maybe_paren(x.clone());
3214 let y_expr = Self::maybe_paren(y.clone());
3215 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3216 condition: Expression::Or(Box::new(BinaryOp::new(
3217 Expression::Eq(Box::new(BinaryOp::new(
3218 y_expr.clone(),
3219 Expression::number(0),
3220 ))),
3221 Expression::IsNull(Box::new(crate::expressions::IsNull {
3222 this: y_expr.clone(),
3223 not: false,
3224 postfix_form: false,
3225 })),
3226 ))),
3227 true_value: Expression::number(0),
3228 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3229 original_name: Some("IFF".to_string()),
3230 inferred_type: None,
3231 })))
3232 }
3233
3234 "ZEROIFNULL" if f.args.len() == 1 => {
3236 let x = f.args.into_iter().next().unwrap();
3237 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3238 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3239 this: x.clone(),
3240 not: false,
3241 postfix_form: false,
3242 })),
3243 true_value: Expression::number(0),
3244 false_value: Some(x),
3245 original_name: Some("IFF".to_string()),
3246 inferred_type: None,
3247 })))
3248 }
3249
3250 "NULLIFZERO" if f.args.len() == 1 => {
3252 let x = f.args.into_iter().next().unwrap();
3253 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3254 condition: Expression::Eq(Box::new(BinaryOp::new(
3255 x.clone(),
3256 Expression::number(0),
3257 ))),
3258 true_value: Expression::Null(crate::expressions::Null),
3259 false_value: Some(x),
3260 original_name: Some("IFF".to_string()),
3261 inferred_type: None,
3262 })))
3263 }
3264
3265 "TRY_TO_TIME" => {
3267 if f.args.len() == 1 {
3268 if let Expression::Literal(lit) = &f.args[0] {
3269 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3270 return Ok(Expression::TryCast(Box::new(Cast {
3271 this: f.args.into_iter().next().unwrap(),
3272 to: crate::expressions::DataType::Time {
3273 precision: None,
3274 timezone: false,
3275 },
3276 double_colon_syntax: false,
3277 trailing_comments: Vec::new(),
3278 format: None,
3279 default: None,
3280 inferred_type: None,
3281 })));
3282 }
3283 }
3284 }
3285 let mut args = f.args;
3287 if args.len() >= 2 {
3288 args[1] = Self::normalize_format_arg(args[1].clone());
3289 }
3290 Ok(Expression::Function(Box::new(Function::new(
3291 "TRY_TO_TIME".to_string(),
3292 args,
3293 ))))
3294 }
3295
3296 "TRY_TO_TIMESTAMP" => {
3299 if f.args.len() == 1 {
3300 if let Expression::Literal(lit) = &f.args[0] {
3301 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3302 if !Self::looks_like_epoch(s) {
3303 return Ok(Expression::TryCast(Box::new(Cast {
3304 this: f.args.into_iter().next().unwrap(),
3305 to: DataType::Timestamp {
3306 precision: None,
3307 timezone: false,
3308 },
3309 double_colon_syntax: false,
3310 trailing_comments: Vec::new(),
3311 format: None,
3312 default: None,
3313 inferred_type: None,
3314 })));
3315 }
3316 }
3317 }
3318 }
3319 let mut args = f.args;
3321 if args.len() >= 2 {
3322 args[1] = Self::normalize_format_arg(args[1].clone());
3323 }
3324 Ok(Expression::Function(Box::new(Function::new(
3325 "TRY_TO_TIMESTAMP".to_string(),
3326 args,
3327 ))))
3328 }
3329
3330 "TRY_TO_DATE" => {
3332 if f.args.len() == 1 {
3333 if let Expression::Literal(lit) = &f.args[0] {
3334 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3335 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3337 return Ok(Expression::TryCast(Box::new(Cast {
3338 this: f.args.into_iter().next().unwrap(),
3339 to: crate::expressions::DataType::Date,
3340 double_colon_syntax: false,
3341 trailing_comments: Vec::new(),
3342 format: None,
3343 default: None,
3344 inferred_type: None,
3345 })));
3346 }
3347 }
3348 }
3349 }
3350 let mut args = f.args;
3352 if args.len() >= 2 {
3353 args[1] = Self::normalize_format_arg(args[1].clone());
3354 }
3355 Ok(Expression::Function(Box::new(Function::new(
3356 "TRY_TO_DATE".to_string(),
3357 args,
3358 ))))
3359 }
3360
3361 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3363
3364 "REGEXP_REPLACE" if f.args.len() == 2 => {
3366 let mut args = f.args;
3367 args.push(Expression::Literal(Box::new(
3368 crate::expressions::Literal::String(String::new()),
3369 )));
3370 Ok(Expression::Function(Box::new(Function::new(
3371 "REGEXP_REPLACE".to_string(),
3372 args,
3373 ))))
3374 }
3375
3376 "LAST_DAY" if f.args.len() == 2 => {
3378 let mut args = f.args;
3379 let date = args.remove(0);
3380 let unit = args.remove(0);
3381 let unit_str = match &unit {
3382 Expression::Column(c) => c.name.name.to_uppercase(),
3383 Expression::Identifier(i) => i.name.to_uppercase(),
3384 _ => String::new(),
3385 };
3386 if unit_str == "MONTH" {
3387 Ok(Expression::Function(Box::new(Function::new(
3388 "LAST_DAY".to_string(),
3389 vec![date],
3390 ))))
3391 } else {
3392 Ok(Expression::Function(Box::new(Function::new(
3393 "LAST_DAY".to_string(),
3394 vec![date, unit],
3395 ))))
3396 }
3397 }
3398
3399 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3401 "DATE_PART".to_string(),
3402 f.args,
3403 )))),
3404
3405 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3407 let mut args = f.args;
3408 let this = args.remove(0);
3409 let expr = args.remove(0);
3410 Ok(Expression::EndsWith(Box::new(
3411 crate::expressions::BinaryFunc {
3412 original_name: None,
3413 this,
3414 expression: expr,
3415 inferred_type: None,
3416 },
3417 )))
3418 }
3419
3420 _ => Ok(Expression::Function(Box::new(f))),
3422 }
3423 }
3424
3425 fn looks_like_datetime(s: &str) -> bool {
3427 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3430 }
3431
3432 fn looks_like_epoch(s: &str) -> bool {
3434 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3435 }
3436
3437 fn maybe_paren(expr: Expression) -> Expression {
3439 match &expr {
3440 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3441 Expression::Paren(Box::new(crate::expressions::Paren {
3442 this: expr,
3443 trailing_comments: Vec::new(),
3444 }))
3445 }
3446 _ => expr,
3447 }
3448 }
3449
3450 fn normalize_snowflake_format(format: &str) -> String {
3454 let mut result = String::new();
3455 let chars: Vec<char> = format.chars().collect();
3456 let mut i = 0;
3457 while i < chars.len() {
3458 if chars[i] == '"' {
3460 i += 1;
3461 while i < chars.len() && chars[i] != '"' {
3462 result.push(chars[i]);
3463 i += 1;
3464 }
3465 if i < chars.len() {
3466 i += 1; }
3468 continue;
3469 }
3470
3471 let remaining = &format[i..];
3472 let remaining_upper = remaining.to_uppercase();
3473
3474 if remaining_upper.starts_with("YYYY") {
3476 result.push_str("yyyy");
3477 i += 4;
3478 } else if remaining_upper.starts_with("YY") {
3479 result.push_str("yy");
3480 i += 2;
3481 } else if remaining_upper.starts_with("MMMM") {
3482 result.push_str("mmmm");
3483 i += 4;
3484 } else if remaining_upper.starts_with("MON") {
3485 result.push_str("mon");
3486 i += 3;
3487 } else if remaining_upper.starts_with("MM") {
3488 result.push_str("mm");
3489 i += 2;
3490 } else if remaining_upper.starts_with("DD") {
3491 result.push_str("DD");
3492 i += 2;
3493 } else if remaining_upper.starts_with("DY") {
3494 result.push_str("dy");
3495 i += 2;
3496 } else if remaining_upper.starts_with("HH24") {
3497 result.push_str("hh24");
3498 i += 4;
3499 } else if remaining_upper.starts_with("HH12") {
3500 result.push_str("hh12");
3501 i += 4;
3502 } else if remaining_upper.starts_with("HH") {
3503 result.push_str("hh");
3504 i += 2;
3505 } else if remaining_upper.starts_with("MISS") {
3506 result.push_str("miss");
3508 i += 4;
3509 } else if remaining_upper.starts_with("MI") {
3510 result.push_str("mi");
3511 i += 2;
3512 } else if remaining_upper.starts_with("SS") {
3513 result.push_str("ss");
3514 i += 2;
3515 } else if remaining_upper.starts_with("FF") {
3516 let ff_len = 2;
3518 let digit = if i + ff_len < chars.len() && chars[i + ff_len].is_ascii_digit() {
3519 let d = chars[i + ff_len];
3520 Some(d)
3521 } else {
3522 None
3523 };
3524 if let Some(d) = digit {
3525 result.push_str("ff");
3526 result.push(d);
3527 i += 3;
3528 } else {
3529 result.push_str("ff9");
3531 i += 2;
3532 }
3533 } else if remaining_upper.starts_with("AM") || remaining_upper.starts_with("PM") {
3534 result.push_str("pm");
3535 i += 2;
3536 } else if remaining_upper.starts_with("TZH") {
3537 result.push_str("tzh");
3538 i += 3;
3539 } else if remaining_upper.starts_with("TZM") {
3540 result.push_str("tzm");
3541 i += 3;
3542 } else {
3543 result.push(chars[i]);
3545 i += 1;
3546 }
3547 }
3548 result
3549 }
3550
3551 fn normalize_format_arg(expr: Expression) -> Expression {
3553 if let Expression::Literal(lit) = &expr {
3554 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3555 let normalized = Self::normalize_snowflake_format(s);
3556 Expression::Literal(Box::new(crate::expressions::Literal::String(normalized)))
3557 } else {
3558 expr.clone()
3559 }
3560 } else {
3561 expr
3562 }
3563 }
3564
3565 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3568 use crate::expressions::{DataType, LambdaExpr};
3569 use std::collections::HashMap;
3570
3571 let mut param_types: HashMap<String, DataType> = HashMap::new();
3573 for (i, param) in lambda.parameters.iter().enumerate() {
3574 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3575 param_types.insert(param.name.to_uppercase(), dt.clone());
3576 }
3577 }
3578
3579 if param_types.is_empty() {
3581 return Expression::Lambda(Box::new(lambda));
3582 }
3583
3584 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3586
3587 Expression::Lambda(Box::new(LambdaExpr {
3589 parameters: lambda.parameters,
3590 body: transformed_body,
3591 colon: lambda.colon,
3592 parameter_types: Vec::new(), }))
3594 }
3595
3596 fn replace_lambda_params_with_cast(
3598 &self,
3599 expr: Expression,
3600 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3601 ) -> Expression {
3602 use crate::expressions::{BinaryOp, Cast, Paren};
3603
3604 match expr {
3605 Expression::Column(col) if col.table.is_none() => {
3607 let name_upper = col.name.name.to_uppercase();
3608 if let Some(dt) = param_types.get(&name_upper) {
3609 Expression::Cast(Box::new(Cast {
3611 this: Expression::Column(col),
3612 to: dt.clone(),
3613 double_colon_syntax: false,
3614 trailing_comments: Vec::new(),
3615 format: None,
3616 default: None,
3617 inferred_type: None,
3618 }))
3619 } else {
3620 Expression::Column(col)
3621 }
3622 }
3623
3624 Expression::Identifier(id) => {
3626 let name_upper = id.name.to_uppercase();
3627 if let Some(dt) = param_types.get(&name_upper) {
3628 Expression::Cast(Box::new(Cast {
3630 this: Expression::Identifier(id),
3631 to: dt.clone(),
3632 double_colon_syntax: false,
3633 trailing_comments: Vec::new(),
3634 format: None,
3635 default: None,
3636 inferred_type: None,
3637 }))
3638 } else {
3639 Expression::Identifier(id)
3640 }
3641 }
3642
3643 Expression::Add(op) => Expression::Add(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::Sub(op) => Expression::Sub(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::Mul(op) => Expression::Mul(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::Div(op) => Expression::Div(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 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3661 self.replace_lambda_params_with_cast(op.left, param_types),
3662 self.replace_lambda_params_with_cast(op.right, param_types),
3663 ))),
3664
3665 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3667 this: self.replace_lambda_params_with_cast(p.this, param_types),
3668 trailing_comments: p.trailing_comments,
3669 })),
3670
3671 Expression::Function(mut f) => {
3673 f.args = f
3674 .args
3675 .into_iter()
3676 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3677 .collect();
3678 Expression::Function(f)
3679 }
3680
3681 Expression::Eq(op) => Expression::Eq(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::Neq(op) => Expression::Neq(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::Lt(op) => Expression::Lt(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::Lte(op) => Expression::Lte(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::Gt(op) => Expression::Gt(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 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3703 self.replace_lambda_params_with_cast(op.left, param_types),
3704 self.replace_lambda_params_with_cast(op.right, param_types),
3705 ))),
3706
3707 Expression::And(op) => Expression::And(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 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3713 self.replace_lambda_params_with_cast(op.left, param_types),
3714 self.replace_lambda_params_with_cast(op.right, param_types),
3715 ))),
3716
3717 other => other,
3719 }
3720 }
3721
3722 fn transform_aggregate_function(
3723 &self,
3724 f: Box<crate::expressions::AggregateFunction>,
3725 ) -> Result<Expression> {
3726 let name_upper = f.name.to_uppercase();
3727 match name_upper.as_str() {
3728 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3730 Function::new("LISTAGG".to_string(), f.args),
3731 ))),
3732
3733 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3735 Function::new("LISTAGG".to_string(), f.args),
3736 ))),
3737
3738 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3740 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3741 ))),
3742
3743 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3745 "BITAND_AGG".to_string(),
3746 f.args,
3747 )))),
3748
3749 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3751 "BITOR_AGG".to_string(),
3752 f.args,
3753 )))),
3754
3755 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3757 "BITXOR_AGG".to_string(),
3758 f.args,
3759 )))),
3760
3761 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3763 let arg = f.args.into_iter().next().unwrap();
3764 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3765 this: arg,
3766 distinct: f.distinct,
3767 filter: f.filter,
3768 order_by: Vec::new(),
3769 name: Some("BOOLAND_AGG".to_string()),
3770 ignore_nulls: None,
3771 having_max: None,
3772 limit: None,
3773 inferred_type: None,
3774 })))
3775 }
3776
3777 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3779 let arg = f.args.into_iter().next().unwrap();
3780 Ok(Expression::LogicalOr(Box::new(AggFunc {
3781 this: arg,
3782 distinct: f.distinct,
3783 filter: f.filter,
3784 order_by: Vec::new(),
3785 name: Some("BOOLOR_AGG".to_string()),
3786 ignore_nulls: None,
3787 having_max: None,
3788 limit: None,
3789 inferred_type: None,
3790 })))
3791 }
3792
3793 "APPROX_TOP_K" if f.args.len() == 1 => {
3795 let mut args = f.args;
3796 args.push(Expression::number(1));
3797 Ok(Expression::AggregateFunction(Box::new(
3798 crate::expressions::AggregateFunction {
3799 name: "APPROX_TOP_K".to_string(),
3800 args,
3801 distinct: f.distinct,
3802 filter: f.filter,
3803 order_by: Vec::new(),
3804 limit: None,
3805 ignore_nulls: None,
3806 inferred_type: None,
3807 },
3808 )))
3809 }
3810
3811 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3813 let arg = f.args.into_iter().next().unwrap();
3814 Ok(Expression::Skewness(Box::new(AggFunc {
3815 this: arg,
3816 distinct: f.distinct,
3817 filter: f.filter,
3818 order_by: Vec::new(),
3819 name: Some("SKEW".to_string()),
3820 ignore_nulls: None,
3821 having_max: None,
3822 limit: None,
3823 inferred_type: None,
3824 })))
3825 }
3826
3827 _ => Ok(Expression::AggregateFunction(f)),
3829 }
3830 }
3831}
3832
3833fn strftime_to_snowflake_format(fmt: &str) -> String {
3835 let mut result = String::new();
3836 let chars: Vec<char> = fmt.chars().collect();
3837 let mut i = 0;
3838 while i < chars.len() {
3839 if chars[i] == '%' && i + 1 < chars.len() {
3840 match chars[i + 1] {
3841 'Y' => {
3842 result.push_str("yyyy");
3843 i += 2;
3844 }
3845 'y' => {
3846 result.push_str("yy");
3847 i += 2;
3848 }
3849 'm' => {
3850 result.push_str("mm");
3851 i += 2;
3852 }
3853 'd' => {
3854 result.push_str("DD");
3855 i += 2;
3856 }
3857 'H' => {
3858 result.push_str("hh24");
3859 i += 2;
3860 }
3861 'M' => {
3862 result.push_str("mmmm");
3863 i += 2;
3864 } 'i' => {
3866 result.push_str("mi");
3867 i += 2;
3868 }
3869 'S' | 's' => {
3870 result.push_str("ss");
3871 i += 2;
3872 }
3873 'f' => {
3874 result.push_str("ff");
3875 i += 2;
3876 }
3877 'w' => {
3878 result.push_str("dy");
3879 i += 2;
3880 } 'a' => {
3882 result.push_str("DY");
3883 i += 2;
3884 } 'b' => {
3886 result.push_str("mon");
3887 i += 2;
3888 } 'T' => {
3890 result.push_str("hh24:mi:ss");
3891 i += 2;
3892 } _ => {
3894 result.push(chars[i]);
3895 result.push(chars[i + 1]);
3896 i += 2;
3897 }
3898 }
3899 } else {
3900 result.push(chars[i]);
3901 i += 1;
3902 }
3903 }
3904 result
3905}
3906
3907#[cfg(test)]
3908mod tests {
3909 use super::*;
3910 use crate::dialects::Dialect;
3911
3912 fn transpile_to_snowflake(sql: &str) -> String {
3913 let dialect = Dialect::get(DialectType::Generic);
3914 let result = dialect
3915 .transpile(sql, DialectType::Snowflake)
3916 .expect("Transpile failed");
3917 result[0].clone()
3918 }
3919
3920 #[test]
3921 fn test_ifnull_to_coalesce() {
3922 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
3923 assert!(
3924 result.contains("COALESCE"),
3925 "Expected COALESCE, got: {}",
3926 result
3927 );
3928 }
3929
3930 #[test]
3931 fn test_basic_select() {
3932 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
3933 assert!(result.contains("SELECT"));
3934 assert!(result.contains("FROM users"));
3935 }
3936
3937 #[test]
3938 fn test_snowflake_scripting_cursor_declare_block_roundtrip() {
3939 let sql = "DECLARE
3940 emp CURSOR FOR SELECT salary FROM employees;
3941BEGIN
3942 RETURN 1;
3943END";
3944
3945 let dialect = Dialect::get(DialectType::Snowflake);
3946 let ast = dialect.parse(sql).expect("Parse failed");
3947 let output = dialect.generate(&ast[0]).expect("Generate failed");
3948
3949 assert_eq!(output, sql);
3950 }
3951
3952 #[test]
3953 fn test_snowflake_scripting_cursor_return_table_roundtrip() {
3954 let sql = "DECLARE
3955 c1 CURSOR FOR SELECT * FROM invoices;
3956BEGIN
3957 OPEN c1;
3958 RETURN TABLE(RESULTSET_FROM_CURSOR(c1));
3959END";
3960
3961 let dialect = Dialect::get(DialectType::Snowflake);
3962 let ast = dialect.parse(sql).expect("Parse failed");
3963 let output = dialect.generate(&ast[0]).expect("Generate failed");
3964
3965 assert_eq!(output, sql);
3966 }
3967
3968 #[test]
3969 fn test_group_concat_to_listagg() {
3970 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
3971 assert!(
3972 result.contains("LISTAGG"),
3973 "Expected LISTAGG, got: {}",
3974 result
3975 );
3976 }
3977
3978 #[test]
3979 fn test_string_agg_to_listagg() {
3980 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
3981 assert!(
3982 result.contains("LISTAGG"),
3983 "Expected LISTAGG, got: {}",
3984 result
3985 );
3986 }
3987
3988 #[test]
3989 fn test_array_to_array_construct() {
3990 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
3991 assert!(
3993 result.contains("[1, 2, 3]"),
3994 "Expected [1, 2, 3], got: {}",
3995 result
3996 );
3997 }
3998
3999 #[test]
4000 fn test_double_quote_identifiers() {
4001 let dialect = SnowflakeDialect;
4003 let config = dialect.generator_config();
4004 assert_eq!(config.identifier_quote, '"');
4005 }
4006}