1use super::{DialectImpl, DialectType};
13#[cfg(feature = "transpile")]
14use crate::error::Result;
15#[cfg(feature = "transpile")]
16use crate::expressions::{
17 AggFunc, BinaryOp, Cast, CeilFunc, DataType, Expression, Function, IntervalUnit, ListAggFunc,
18 Literal, UnaryFunc, VarArgFunc,
19};
20#[cfg(feature = "generate")]
21use crate::generator::GeneratorConfig;
22use crate::tokens::TokenizerConfig;
23
24#[cfg(feature = "transpile")]
26fn interval_unit_to_str(unit: &IntervalUnit) -> String {
27 match unit {
28 IntervalUnit::Year => "YEAR".to_string(),
29 IntervalUnit::Quarter => "QUARTER".to_string(),
30 IntervalUnit::Month => "MONTH".to_string(),
31 IntervalUnit::Week => "WEEK".to_string(),
32 IntervalUnit::Day => "DAY".to_string(),
33 IntervalUnit::Hour => "HOUR".to_string(),
34 IntervalUnit::Minute => "MINUTE".to_string(),
35 IntervalUnit::Second => "SECOND".to_string(),
36 IntervalUnit::Millisecond => "MILLISECOND".to_string(),
37 IntervalUnit::Microsecond => "MICROSECOND".to_string(),
38 IntervalUnit::Nanosecond => "NANOSECOND".to_string(),
39 }
40}
41
42pub struct SnowflakeDialect;
44
45impl DialectImpl for SnowflakeDialect {
46 fn dialect_type(&self) -> DialectType {
47 DialectType::Snowflake
48 }
49
50 fn tokenizer_config(&self) -> TokenizerConfig {
51 let mut config = TokenizerConfig::default();
52 config.identifiers.insert('"', '"');
54 config.quotes.insert("$$".to_string(), "$$".to_string());
56 config.string_escapes.push('\\');
58 config.escape_follow_chars = vec![
61 '\'', '"', '\\', 'b', 'f', 'n', 'r', 't', '0', '1', '2', '3', '4', '5', '6', '7', 'x',
62 'u',
63 ];
64 config.nested_comments = false;
66 config.comments.insert("//".to_string(), None);
68 config
69 }
70
71 #[cfg(feature = "generate")]
72
73 fn generator_config(&self) -> GeneratorConfig {
74 use crate::generator::IdentifierQuoteStyle;
75 GeneratorConfig {
76 identifier_quote: '"',
77 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
78 dialect: Some(DialectType::Snowflake),
79 parameter_token: "$",
81 matched_by_source: false,
82 single_string_interval: true,
83 join_hints: false,
84 table_hints: false,
85 query_hints: false,
86 aggregate_filter_supported: false,
87 supports_table_copy: false,
88 collate_is_func: true,
89 limit_only_literals: true,
90 json_key_value_pair_sep: ",",
91 insert_overwrite: " OVERWRITE INTO",
92 struct_delimiter: ("(", ")"),
93 copy_params_are_wrapped: false,
94 copy_params_eq_required: true,
95 star_except: "EXCLUDE",
96 supports_exploding_projections: false,
97 array_concat_is_var_len: false,
98 supports_convert_timezone: true,
99 except_intersect_support_all_clause: false,
100 supports_median: true,
101 array_size_name: "ARRAY_SIZE",
102 supports_decode_case: true,
103 is_bool_allowed: false,
104 try_supported: true,
106 nvl2_supported: true,
108 unnest_with_ordinality: false,
110 quantified_no_paren_space: false,
112 array_bracket_only: true,
114 ..Default::default()
115 }
116 }
117
118 #[cfg(feature = "transpile")]
119
120 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
121 match expr {
122 Expression::DataType(dt) => self.transform_data_type(dt),
124
125 Expression::In(in_expr) if in_expr.not && in_expr.query.is_some() => {
129 let inner = in_expr.query.unwrap();
131 let subquery = Expression::Subquery(Box::new(crate::expressions::Subquery {
133 this: inner,
134 alias: None,
135 column_aliases: Vec::new(),
136 alias_explicit_as: false,
137 alias_keyword: None,
138 order_by: None,
139 limit: None,
140 offset: None,
141 distribute_by: None,
142 sort_by: None,
143 cluster_by: None,
144 lateral: false,
145 modifiers_inside: false,
146 trailing_comments: Vec::new(),
147 inferred_type: None,
148 }));
149 Ok(Expression::All(Box::new(
150 crate::expressions::QuantifiedExpr {
151 this: in_expr.this,
152 subquery,
153 op: Some(crate::expressions::QuantifiedOp::Neq),
154 },
155 )))
156 }
157
158 Expression::In(in_expr) if in_expr.not => {
160 let in_without_not = crate::expressions::In {
162 this: in_expr.this,
163 expressions: in_expr.expressions,
164 query: in_expr.query,
165 not: false,
166 global: in_expr.global,
167 unnest: in_expr.unnest,
168 is_field: in_expr.is_field,
169 };
170 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
171 this: Expression::In(Box::new(in_without_not)),
172 inferred_type: None,
173 })))
174 }
175
176 Expression::Interval(interval) => self.transform_interval(*interval),
179
180 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
183 original_name: None,
184 expressions: vec![f.this, f.expression],
185 inferred_type: None,
186 }))),
187
188 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
190 original_name: None,
191 expressions: vec![f.this, f.expression],
192 inferred_type: None,
193 }))),
194
195 Expression::Coalesce(mut f) => {
197 f.original_name = None;
198 Ok(Expression::Coalesce(f))
199 }
200
201 Expression::GroupConcat(f) => Ok(Expression::ListAgg(Box::new(ListAggFunc {
203 source_dialect: None,
204 this: f.this,
205 separator: f.separator,
206 on_overflow: None,
207 max_length: None,
208 order_by: f.order_by,
209 distinct: f.distinct,
210 filter: f.filter,
211 inferred_type: None,
212 }))),
213
214 Expression::Cast(c) => {
218 use crate::expressions::DataType;
219 let transformed_this = self.transform_expr(c.this)?;
221 match &c.to {
222 DataType::Geography { .. } => Ok(Expression::Function(Box::new(
223 Function::new("TO_GEOGRAPHY".to_string(), vec![transformed_this]),
224 ))),
225 DataType::Geometry { .. } => Ok(Expression::Function(Box::new(Function::new(
226 "TO_GEOMETRY".to_string(),
227 vec![transformed_this],
228 )))),
229 _ => {
230 let transformed_dt = match self.transform_data_type(c.to.clone())? {
232 Expression::DataType(dt) => dt,
233 _ => c.to.clone(),
234 };
235 Ok(Expression::Cast(Box::new(Cast {
236 this: transformed_this,
237 to: transformed_dt,
238 double_colon_syntax: false, trailing_comments: c.trailing_comments,
240 format: c.format,
241 default: c.default,
242 inferred_type: None,
243 })))
244 }
245 }
246 }
247
248 Expression::TryCast(c) => {
251 let transformed_this = self.transform_expr(c.this)?;
252 Ok(Expression::TryCast(Box::new(Cast {
253 this: transformed_this,
254 to: c.to,
255 double_colon_syntax: false, trailing_comments: c.trailing_comments,
257 format: c.format,
258 default: c.default,
259 inferred_type: None,
260 })))
261 }
262
263 Expression::SafeCast(c) => {
266 let to = match c.to {
267 DataType::Timestamp { .. } => DataType::Custom {
268 name: "TIMESTAMPTZ".to_string(),
269 },
270 DataType::Custom { name } if name.eq_ignore_ascii_case("TIMESTAMP") => {
271 DataType::Custom {
272 name: "TIMESTAMPTZ".to_string(),
273 }
274 }
275 other => other,
276 };
277 let transformed_this = self.transform_expr(c.this)?;
278 Ok(Expression::Cast(Box::new(Cast {
279 this: transformed_this,
280 to,
281 double_colon_syntax: c.double_colon_syntax,
282 trailing_comments: c.trailing_comments,
283 format: c.format,
284 default: c.default,
285 inferred_type: None,
286 })))
287 }
288
289 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Timestamp(_)) => {
292 let Literal::Timestamp(s) = lit.as_ref() else {
293 unreachable!()
294 };
295 Ok(Expression::Cast(Box::new(Cast {
296 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
297 to: DataType::Timestamp {
298 precision: None,
299 timezone: false,
300 },
301 double_colon_syntax: false,
302 trailing_comments: Vec::new(),
303 format: None,
304 default: None,
305 inferred_type: None,
306 })))
307 }
308
309 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Date(_)) => {
311 let Literal::Date(s) = lit.as_ref() else {
312 unreachable!()
313 };
314 Ok(Expression::Cast(Box::new(Cast {
315 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
316 to: DataType::Date,
317 double_colon_syntax: false,
318 trailing_comments: Vec::new(),
319 format: None,
320 default: None,
321 inferred_type: None,
322 })))
323 }
324
325 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Time(_)) => {
327 let Literal::Time(s) = lit.as_ref() else {
328 unreachable!()
329 };
330 Ok(Expression::Cast(Box::new(Cast {
331 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
332 to: DataType::Time {
333 precision: None,
334 timezone: false,
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::Literal(lit) if matches!(lit.as_ref(), Literal::Datetime(_)) => {
346 let Literal::Datetime(s) = lit.as_ref() else {
347 unreachable!()
348 };
349 Ok(Expression::Cast(Box::new(Cast {
350 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
351 to: DataType::Custom {
352 name: "DATETIME".to_string(),
353 },
354 double_colon_syntax: false,
355 trailing_comments: Vec::new(),
356 format: None,
357 default: None,
358 inferred_type: None,
359 })))
360 }
361
362 Expression::ILike(op) => Ok(Expression::ILike(op)),
365
366 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
369 "FLATTEN".to_string(),
370 vec![f.this],
371 )))),
372
373 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
375 "FLATTEN".to_string(),
376 vec![f.this],
377 )))),
378
379 Expression::Unnest(f) => {
381 let input_arg =
383 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
384 name: crate::expressions::Identifier::new("INPUT"),
385 value: f.this,
386 separator: crate::expressions::NamedArgSeparator::DArrow,
387 }));
388
389 let flatten = Expression::Function(Box::new(Function::new(
391 "FLATTEN".to_string(),
392 vec![input_arg],
393 )));
394
395 let table_func =
397 Expression::TableFromRows(Box::new(crate::expressions::TableFromRows {
398 this: Box::new(flatten),
399 alias: None,
400 joins: vec![],
401 pivots: None,
402 sample: None,
403 }));
404
405 Ok(Expression::Alias(Box::new(crate::expressions::Alias {
407 this: table_func,
408 alias: crate::expressions::Identifier::new("_t0"),
409 column_aliases: vec![
410 crate::expressions::Identifier::new("seq"),
411 crate::expressions::Identifier::new("key"),
412 crate::expressions::Identifier::new("path"),
413 crate::expressions::Identifier::new("index"),
414 crate::expressions::Identifier::new("value"),
415 crate::expressions::Identifier::new("this"),
416 ],
417 alias_explicit_as: false,
418 alias_keyword: None,
419 pre_alias_comments: vec![],
420 trailing_comments: vec![],
421 inferred_type: None,
422 })))
423 }
424
425 Expression::ArrayFunc(arr) => {
429 if arr.bracket_notation {
430 Ok(Expression::ArrayFunc(arr))
432 } else {
433 Ok(Expression::Function(Box::new(Function::new(
435 "ARRAY_CONSTRUCT".to_string(),
436 arr.expressions,
437 ))))
438 }
439 }
440
441 Expression::ArrayConcat(f) => Ok(Expression::Function(Box::new(Function::new(
443 "ARRAY_CAT".to_string(),
444 f.expressions,
445 )))),
446
447 Expression::ArrayConcatAgg(f) => Ok(Expression::Function(Box::new(Function::new(
449 "ARRAY_FLATTEN".to_string(),
450 vec![f.this],
451 )))),
452
453 Expression::ArrayContains(f) => Ok(Expression::Function(Box::new(Function::new(
455 "ARRAY_CONTAINS".to_string(),
456 vec![f.this, f.expression],
457 )))),
458
459 Expression::ArrayIntersect(f) => Ok(Expression::Function(Box::new(Function::new(
461 "ARRAY_INTERSECTION".to_string(),
462 f.expressions,
463 )))),
464
465 Expression::ArraySort(f) => Ok(Expression::Function(Box::new(Function::new(
467 "ARRAY_SORT".to_string(),
468 vec![f.this],
469 )))),
470
471 Expression::StringToArray(f) => {
473 let mut args = vec![*f.this];
474 if let Some(expr) = f.expression {
475 args.push(*expr);
476 }
477 Ok(Expression::Function(Box::new(Function::new(
478 "STRTOK_TO_ARRAY".to_string(),
479 args,
480 ))))
481 }
482
483 Expression::BitwiseOr(f) => Ok(Expression::Function(Box::new(Function::new(
486 "BITOR".to_string(),
487 vec![f.left, f.right],
488 )))),
489
490 Expression::BitwiseXor(f) => Ok(Expression::Function(Box::new(Function::new(
492 "BITXOR".to_string(),
493 vec![f.left, f.right],
494 )))),
495
496 Expression::BitwiseAnd(f) => Ok(Expression::Function(Box::new(Function::new(
498 "BITAND".to_string(),
499 vec![f.left, f.right],
500 )))),
501
502 Expression::BitwiseNot(f) => Ok(Expression::Function(Box::new(Function::new(
504 "BITNOT".to_string(),
505 vec![f.this],
506 )))),
507
508 Expression::BitwiseLeftShift(f) => Ok(Expression::Function(Box::new(Function::new(
510 "BITSHIFTLEFT".to_string(),
511 vec![f.left, f.right],
512 )))),
513
514 Expression::BitwiseRightShift(f) => Ok(Expression::Function(Box::new(Function::new(
516 "BITSHIFTRIGHT".to_string(),
517 vec![f.left, f.right],
518 )))),
519
520 Expression::BitwiseAndAgg(f) => Ok(Expression::Function(Box::new(Function::new(
522 "BITAND_AGG".to_string(),
523 vec![f.this],
524 )))),
525
526 Expression::BitwiseOrAgg(f) => Ok(Expression::Function(Box::new(Function::new(
528 "BITOR_AGG".to_string(),
529 vec![f.this],
530 )))),
531
532 Expression::BitwiseXorAgg(f) => Ok(Expression::Function(Box::new(Function::new(
534 "BITXOR_AGG".to_string(),
535 vec![f.this],
536 )))),
537
538 Expression::LogicalAnd(f) => Ok(Expression::Function(Box::new(Function::new(
541 "BOOLAND_AGG".to_string(),
542 vec![f.this],
543 )))),
544
545 Expression::LogicalOr(f) => Ok(Expression::Function(Box::new(Function::new(
547 "BOOLOR_AGG".to_string(),
548 vec![f.this],
549 )))),
550
551 Expression::Booland(f) => Ok(Expression::Function(Box::new(Function::new(
553 "BOOLAND".to_string(),
554 vec![*f.this, *f.expression],
555 )))),
556
557 Expression::Boolor(f) => Ok(Expression::Function(Box::new(Function::new(
559 "BOOLOR".to_string(),
560 vec![*f.this, *f.expression],
561 )))),
562
563 Expression::Xor(f) => {
565 let mut args = Vec::new();
566 if let Some(this) = f.this {
567 args.push(*this);
568 }
569 if let Some(expr) = f.expression {
570 args.push(*expr);
571 }
572 Ok(Expression::Function(Box::new(Function::new(
573 "BOOLXOR".to_string(),
574 args,
575 ))))
576 }
577
578 Expression::DayOfMonth(f) => Ok(Expression::Function(Box::new(Function::new(
581 "DAYOFMONTH".to_string(),
582 vec![f.this],
583 )))),
584
585 Expression::DayOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
587 "DAYOFWEEK".to_string(),
588 vec![f.this],
589 )))),
590
591 Expression::DayOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
593 "DAYOFWEEKISO".to_string(),
594 vec![f.this],
595 )))),
596
597 Expression::DayOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
599 "DAYOFYEAR".to_string(),
600 vec![f.this],
601 )))),
602
603 Expression::WeekOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
605 "WEEK".to_string(),
606 vec![f.this],
607 )))),
608
609 Expression::YearOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
611 "YEAROFWEEK".to_string(),
612 vec![f.this],
613 )))),
614
615 Expression::YearOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
617 "YEAROFWEEKISO".to_string(),
618 vec![f.this],
619 )))),
620
621 Expression::ByteLength(f) => Ok(Expression::Function(Box::new(Function::new(
623 "OCTET_LENGTH".to_string(),
624 vec![f.this],
625 )))),
626
627 Expression::TimestampDiff(f) => {
629 let mut args = vec![];
630 if let Some(ref unit_str) = f.unit {
632 args.push(Expression::Identifier(crate::expressions::Identifier::new(
633 unit_str.clone(),
634 )));
635 args.push(*f.this);
636 args.push(*f.expression);
637 } else {
638 args.push(*f.this);
639 args.push(*f.expression);
640 }
641 Ok(Expression::Function(Box::new(Function::new(
642 "TIMESTAMPDIFF".to_string(),
643 args,
644 ))))
645 }
646
647 Expression::TimestampAdd(f) => {
649 let mut args = vec![];
650 if let Some(ref unit_str) = f.unit {
651 args.push(Expression::Identifier(crate::expressions::Identifier::new(
652 unit_str.clone(),
653 )));
654 args.push(*f.this);
655 args.push(*f.expression);
656 } else {
657 args.push(*f.this);
658 args.push(*f.expression);
659 }
660 Ok(Expression::Function(Box::new(Function::new(
661 "TIMESTAMPADD".to_string(),
662 args,
663 ))))
664 }
665
666 Expression::ToArray(f) => Ok(Expression::Function(Box::new(Function::new(
668 "TO_ARRAY".to_string(),
669 vec![f.this],
670 )))),
671
672 Expression::DateAdd(f) => {
674 let unit_str = interval_unit_to_str(&f.unit);
675 let unit = Expression::Identifier(crate::expressions::Identifier {
676 name: unit_str,
677 quoted: false,
678 trailing_comments: Vec::new(),
679 span: None,
680 });
681 Ok(Expression::Function(Box::new(Function::new(
682 "DATEADD".to_string(),
683 vec![unit, f.interval, f.this],
684 ))))
685 }
686
687 Expression::DateSub(f) => {
689 let unit_str = interval_unit_to_str(&f.unit);
690 let unit = Expression::Identifier(crate::expressions::Identifier {
691 name: unit_str,
692 quoted: false,
693 trailing_comments: Vec::new(),
694 span: None,
695 });
696 let neg_expr = Expression::Mul(Box::new(crate::expressions::BinaryOp::new(
698 f.interval,
699 Expression::Neg(Box::new(crate::expressions::UnaryOp {
700 this: Expression::number(1),
701 inferred_type: None,
702 })),
703 )));
704 Ok(Expression::Function(Box::new(Function::new(
705 "DATEADD".to_string(),
706 vec![unit, neg_expr, f.this],
707 ))))
708 }
709
710 Expression::DateDiff(f) => {
712 let unit_str =
713 interval_unit_to_str(&f.unit.unwrap_or(crate::expressions::IntervalUnit::Day));
714 let unit = Expression::Identifier(crate::expressions::Identifier {
715 name: unit_str,
716 quoted: false,
717 trailing_comments: Vec::new(),
718 span: None,
719 });
720 Ok(Expression::Function(Box::new(Function::new(
721 "DATEDIFF".to_string(),
722 vec![unit, f.expression, f.this],
723 ))))
724 }
725
726 Expression::StringAgg(f) => {
729 let mut args = vec![f.this.clone()];
730 if let Some(separator) = &f.separator {
731 args.push(separator.clone());
732 }
733 Ok(Expression::Function(Box::new(Function::new(
734 "LISTAGG".to_string(),
735 args,
736 ))))
737 }
738
739 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
741 "STARTSWITH".to_string(),
742 vec![f.this, f.expression],
743 )))),
744
745 Expression::EndsWith(f) => Ok(Expression::EndsWith(f)),
747
748 Expression::Stuff(f) => {
750 let mut args = vec![*f.this];
751 if let Some(start) = f.start {
752 args.push(*start);
753 }
754 if let Some(length) = f.length {
755 args.push(Expression::number(length));
756 }
757 args.push(*f.expression);
758 Ok(Expression::Function(Box::new(Function::new(
759 "INSERT".to_string(),
760 args,
761 ))))
762 }
763
764 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
767 "SHA1".to_string(),
768 vec![f.this],
769 )))),
770
771 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
773 "SHA1_BINARY".to_string(),
774 vec![f.this],
775 )))),
776
777 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
779 "SHA2_BINARY".to_string(),
780 vec![*f.this],
781 )))),
782
783 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
785 "MD5_BINARY".to_string(),
786 vec![*f.this],
787 )))),
788
789 Expression::MD5NumberLower64(f) => Ok(Expression::Function(Box::new(Function::new(
791 "MD5_NUMBER_LOWER64".to_string(),
792 vec![f.this],
793 )))),
794
795 Expression::MD5NumberUpper64(f) => Ok(Expression::Function(Box::new(Function::new(
797 "MD5_NUMBER_UPPER64".to_string(),
798 vec![f.this],
799 )))),
800
801 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
804 "VECTOR_COSINE_SIMILARITY".to_string(),
805 vec![*f.this, *f.expression],
806 )))),
807
808 Expression::DotProduct(f) => Ok(Expression::Function(Box::new(Function::new(
810 "VECTOR_INNER_PRODUCT".to_string(),
811 vec![*f.this, *f.expression],
812 )))),
813
814 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
816 "VECTOR_L2_DISTANCE".to_string(),
817 vec![*f.this, *f.expression],
818 )))),
819
820 Expression::ManhattanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
822 "VECTOR_L1_DISTANCE".to_string(),
823 vec![*f.this, *f.expression],
824 )))),
825
826 Expression::JSONFormat(f) => {
829 let mut args = Vec::new();
830 if let Some(this) = f.this {
831 args.push(*this);
832 }
833 Ok(Expression::Function(Box::new(Function::new(
834 "TO_JSON".to_string(),
835 args,
836 ))))
837 }
838
839 Expression::JSONKeys(f) => Ok(Expression::Function(Box::new(Function::new(
841 "OBJECT_KEYS".to_string(),
842 vec![*f.this],
843 )))),
844
845 Expression::GetExtract(f) => Ok(Expression::Function(Box::new(Function::new(
847 "GET".to_string(),
848 vec![*f.this, *f.expression],
849 )))),
850
851 Expression::StarMap(f) => Ok(Expression::Function(Box::new(Function::new(
853 "OBJECT_CONSTRUCT".to_string(),
854 vec![f.this, f.expression],
855 )))),
856
857 Expression::LowerHex(f) => Ok(Expression::Function(Box::new(Function::new(
859 "TO_CHAR".to_string(),
860 vec![f.this],
861 )))),
862
863 Expression::Skewness(f) => Ok(Expression::Function(Box::new(Function::new(
865 "SKEW".to_string(),
866 vec![f.this],
867 )))),
868
869 Expression::StPoint(f) => Ok(Expression::Function(Box::new(Function::new(
871 "ST_MAKEPOINT".to_string(),
872 vec![*f.this, *f.expression],
873 )))),
874
875 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
877 "CONVERT_TIMEZONE".to_string(),
878 vec![*f.this],
879 )))),
880
881 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
884 "HEX_DECODE_BINARY".to_string(),
885 vec![*f.this],
886 )))),
887
888 Expression::UnixToTime(f) => {
890 let mut args = vec![*f.this];
891 if let Some(scale) = f.scale {
892 args.push(Expression::number(scale));
893 }
894 Ok(Expression::Function(Box::new(Function::new(
895 "TO_TIMESTAMP".to_string(),
896 args,
897 ))))
898 }
899
900 Expression::IfFunc(f) => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
903 condition: f.condition,
904 true_value: f.true_value,
905 false_value: Some(
906 f.false_value
907 .unwrap_or(Expression::Null(crate::expressions::Null)),
908 ),
909 original_name: Some("IFF".to_string()),
910 inferred_type: None,
911 }))),
912
913 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
916 "APPROX_COUNT_DISTINCT".to_string(),
917 vec![f.this],
918 )))),
919
920 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
922 "MAX_BY".to_string(),
923 vec![*f.this, *f.expression],
924 )))),
925
926 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
928 "MIN_BY".to_string(),
929 vec![*f.this, *f.expression],
930 )))),
931
932 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
935
936 Expression::Rand(r) => Ok(Expression::Rand(r)),
938
939 Expression::Uuid(u) => Ok(Expression::Uuid(u)),
942
943 Expression::Map(f) => Ok(Expression::Function(Box::new(Function::new(
946 "OBJECT_CONSTRUCT".to_string(),
947 f.keys
948 .into_iter()
949 .zip(f.values.into_iter())
950 .flat_map(|(k, v)| vec![k, v])
951 .collect(),
952 )))),
953
954 Expression::MapFunc(f) => Ok(Expression::Function(Box::new(Function::new(
956 "OBJECT_CONSTRUCT".to_string(),
957 f.keys
958 .into_iter()
959 .zip(f.values.into_iter())
960 .flat_map(|(k, v)| vec![k, v])
961 .collect(),
962 )))),
963
964 Expression::VarMap(f) => Ok(Expression::Function(Box::new(Function::new(
966 "OBJECT_CONSTRUCT".to_string(),
967 f.keys
968 .into_iter()
969 .zip(f.values.into_iter())
970 .flat_map(|(k, v)| vec![k, v])
971 .collect(),
972 )))),
973
974 Expression::JsonObject(f) => Ok(Expression::Function(Box::new(Function::new(
977 "OBJECT_CONSTRUCT_KEEP_NULL".to_string(),
978 f.pairs.into_iter().flat_map(|(k, v)| vec![k, v]).collect(),
979 )))),
980
981 Expression::JsonExtractScalar(f) => Ok(Expression::Function(Box::new(Function::new(
983 "JSON_EXTRACT_PATH_TEXT".to_string(),
984 vec![f.this, f.path],
985 )))),
986
987 Expression::Struct(f) => Ok(Expression::Function(Box::new(Function::new(
990 "OBJECT_CONSTRUCT".to_string(),
991 f.fields
992 .into_iter()
993 .flat_map(|(name, expr)| {
994 let key = match name {
995 Some(n) => Expression::string(n),
996 None => Expression::Null(crate::expressions::Null),
997 };
998 vec![key, expr]
999 })
1000 .collect(),
1001 )))),
1002
1003 Expression::JSONPathRoot(_) => Ok(Expression::Literal(Box::new(
1006 crate::expressions::Literal::String(String::new()),
1007 ))),
1008
1009 Expression::VarSamp(agg) => Ok(Expression::Variance(agg)),
1012
1013 Expression::VarPop(agg) => Ok(Expression::VarPop(agg)),
1016
1017 Expression::Extract(f) => {
1020 use crate::expressions::DateTimeField;
1021 let transformed_this = self.transform_expr(f.this)?;
1023 let field_name = match &f.field {
1024 DateTimeField::Year => "YEAR",
1025 DateTimeField::Month => "MONTH",
1026 DateTimeField::Day => "DAY",
1027 DateTimeField::Hour => "HOUR",
1028 DateTimeField::Minute => "MINUTE",
1029 DateTimeField::Second => "SECOND",
1030 DateTimeField::Millisecond => "MILLISECOND",
1031 DateTimeField::Microsecond => "MICROSECOND",
1032 DateTimeField::Week => "WEEK",
1033 DateTimeField::WeekWithModifier(m) => {
1034 return Ok(Expression::Function(Box::new(Function::new(
1035 "DATE_PART".to_string(),
1036 vec![
1037 Expression::Identifier(crate::expressions::Identifier {
1038 name: format!("WEEK({})", m),
1039 quoted: false,
1040 trailing_comments: Vec::new(),
1041 span: None,
1042 }),
1043 transformed_this,
1044 ],
1045 ))))
1046 }
1047 DateTimeField::DayOfWeek => "DAYOFWEEK",
1048 DateTimeField::DayOfYear => "DAYOFYEAR",
1049 DateTimeField::Quarter => "QUARTER",
1050 DateTimeField::Epoch => "EPOCH",
1051 DateTimeField::Timezone => "TIMEZONE",
1052 DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
1053 DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
1054 DateTimeField::Date => "DATE",
1055 DateTimeField::Time => "TIME",
1056 DateTimeField::Custom(s) => {
1057 match s.to_uppercase().as_str() {
1059 "DAYOFMONTH" => "DAY",
1060 "DOW" => "DAYOFWEEK",
1061 "DOY" => "DAYOFYEAR",
1062 "ISODOW" => "DAYOFWEEKISO",
1063 "EPOCH_SECOND" | "EPOCH_SECONDS" => "EPOCH_SECOND",
1064 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => "EPOCH_MILLISECOND",
1065 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => "EPOCH_MICROSECOND",
1066 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => "EPOCH_NANOSECOND",
1067 _ => {
1068 return {
1069 let field_ident =
1070 Expression::Identifier(crate::expressions::Identifier {
1071 name: s.to_string(),
1072 quoted: false,
1073 trailing_comments: Vec::new(),
1074 span: None,
1075 });
1076 Ok(Expression::Function(Box::new(Function::new(
1077 "DATE_PART".to_string(),
1078 vec![field_ident, transformed_this],
1079 ))))
1080 }
1081 }
1082 }
1083 }
1084 };
1085 let field_ident = Expression::Identifier(crate::expressions::Identifier {
1086 name: field_name.to_string(),
1087 quoted: false,
1088 trailing_comments: Vec::new(),
1089 span: None,
1090 });
1091 Ok(Expression::Function(Box::new(Function::new(
1092 "DATE_PART".to_string(),
1093 vec![field_ident, transformed_this],
1094 ))))
1095 }
1096
1097 Expression::Function(f) => self.transform_function(*f),
1099
1100 Expression::Sum(mut agg) => {
1102 agg.this = self.transform_expr(agg.this)?;
1103 Ok(Expression::Sum(agg))
1104 }
1105
1106 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
1108
1109 Expression::NamedArgument(na) => {
1111 let transformed_value = self.transform_expr(na.value)?;
1112 Ok(Expression::NamedArgument(Box::new(
1113 crate::expressions::NamedArgument {
1114 name: na.name,
1115 value: transformed_value,
1116 separator: na.separator,
1117 },
1118 )))
1119 }
1120
1121 Expression::CreateTable(mut ct) => {
1123 for col in &mut ct.columns {
1124 if let Expression::DataType(new_dt) =
1125 self.transform_data_type(col.data_type.clone())?
1126 {
1127 col.data_type = new_dt;
1128 }
1129 if let Some(default_expr) = col.default.take() {
1131 col.default = Some(self.transform_expr(default_expr)?);
1132 }
1133 for constraint in &mut col.constraints {
1135 if let crate::expressions::ColumnConstraint::ComputedColumn(cc) = constraint
1136 {
1137 let transformed = self.transform_expr(*cc.expression.clone())?;
1138 cc.expression = Box::new(transformed);
1139 }
1140 }
1141 }
1142
1143 if ct.table_modifier.as_deref() == Some("EXTERNAL")
1146 && !ct.with_properties.is_empty()
1147 {
1148 for (key, value) in ct.with_properties.drain(..) {
1149 let formatted = Self::format_external_table_property(&key, &value);
1150 ct.properties
1151 .push(Expression::Raw(crate::expressions::Raw { sql: formatted }));
1152 }
1153 }
1154
1155 Ok(Expression::CreateTable(ct))
1156 }
1157
1158 Expression::AlterTable(mut at) => {
1160 for action in &mut at.actions {
1161 if let crate::expressions::AlterTableAction::AddColumn { column, .. } = action {
1162 if let Expression::DataType(new_dt) =
1163 self.transform_data_type(column.data_type.clone())?
1164 {
1165 column.data_type = new_dt;
1166 }
1167 }
1168 }
1169 Ok(Expression::AlterTable(at))
1170 }
1171
1172 Expression::Table(mut t) => {
1174 if let Some(when) = t.when.take() {
1175 let transformed_expr = self.transform_expr(*when.expression)?;
1177 t.when = Some(Box::new(crate::expressions::HistoricalData {
1178 this: when.this,
1179 kind: when.kind,
1180 expression: Box::new(transformed_expr),
1181 }));
1182 }
1183 Ok(Expression::Table(t))
1184 }
1185
1186 Expression::Subscript(s) => {
1188 let transformed_this = self.transform_expr(s.this)?;
1189 let transformed_index = self.transform_expr(s.index)?;
1190 Ok(Expression::Subscript(Box::new(
1191 crate::expressions::Subscript {
1192 this: transformed_this,
1193 index: transformed_index,
1194 },
1195 )))
1196 }
1197
1198 Expression::Paren(p) => {
1200 let transformed = self.transform_expr(p.this)?;
1201 Ok(Expression::Paren(Box::new(crate::expressions::Paren {
1202 this: transformed,
1203 trailing_comments: p.trailing_comments,
1204 })))
1205 }
1206
1207 Expression::Lateral(mut lat) => {
1213 let is_flatten = match lat.this.as_ref() {
1215 Expression::Function(f) => f.name.to_uppercase() == "FLATTEN",
1216 _ => false,
1217 };
1218 if is_flatten && lat.column_aliases.is_empty() {
1219 lat.column_aliases = vec![
1221 "SEQ".to_string(),
1222 "KEY".to_string(),
1223 "PATH".to_string(),
1224 "INDEX".to_string(),
1225 "VALUE".to_string(),
1226 "THIS".to_string(),
1227 ];
1228 if lat.alias.is_none() {
1230 lat.alias = Some("_flattened".to_string());
1231 }
1232 }
1233 Ok(Expression::Lateral(lat))
1234 }
1235
1236 _ => Ok(expr),
1238 }
1239 }
1240}
1241
1242#[cfg(feature = "transpile")]
1243impl SnowflakeDialect {
1244 fn format_external_table_property(key: &str, value: &str) -> String {
1247 let lower_key = key.to_lowercase();
1248 match lower_key.as_str() {
1249 "location" => format!("LOCATION={}", value),
1250 "file_format" => {
1251 let formatted_value = Self::format_file_format_value(value);
1253 format!("FILE_FORMAT={}", formatted_value)
1254 }
1255 _ => format!("{}={}", key, value),
1256 }
1257 }
1258
1259 fn format_file_format_value(value: &str) -> String {
1263 if !value.starts_with('(') {
1264 return value.to_string();
1265 }
1266 let inner = value[1..value.len() - 1].trim();
1268 let mut result = String::from("(");
1270 let mut parts: Vec<String> = Vec::new();
1271 let tokens: Vec<&str> = inner.split_whitespace().collect();
1273 let mut i = 0;
1274 while i < tokens.len() {
1275 let token = tokens[i];
1276 if i + 2 < tokens.len() && tokens[i + 1] == "=" {
1277 let val = Self::format_property_value(tokens[i + 2]);
1279 parts.push(format!("{}={}", token, val));
1280 i += 3;
1281 } else if token.contains('=') {
1282 let eq_pos = token.find('=').unwrap();
1284 let k = &token[..eq_pos];
1285 let v = Self::format_property_value(&token[eq_pos + 1..]);
1286 parts.push(format!("{}={}", k, v));
1287 i += 1;
1288 } else {
1289 parts.push(token.to_string());
1290 i += 1;
1291 }
1292 }
1293 result.push_str(&parts.join(" "));
1294 result.push(')');
1295 result
1296 }
1297
1298 fn format_property_value(value: &str) -> String {
1300 match value.to_lowercase().as_str() {
1301 "true" => "TRUE".to_string(),
1302 "false" => "FALSE".to_string(),
1303 _ => value.to_string(),
1304 }
1305 }
1306
1307 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1309 use crate::expressions::DataType;
1310 let transformed = match dt {
1311 DataType::Text => DataType::VarChar {
1313 length: None,
1314 parenthesized_length: false,
1315 },
1316 DataType::Struct { fields, .. } => {
1318 let _ = fields; DataType::Custom {
1321 name: "OBJECT".to_string(),
1322 }
1323 }
1324 DataType::Custom { name } => {
1326 let upper_name = name.to_uppercase();
1327 match upper_name.as_str() {
1328 "NVARCHAR" | "NCHAR" | "NATIONAL CHARACTER VARYING" | "NATIONAL CHAR" => {
1330 DataType::VarChar {
1331 length: None,
1332 parenthesized_length: false,
1333 }
1334 }
1335 "STRING" => DataType::VarChar {
1337 length: None,
1338 parenthesized_length: false,
1339 },
1340 "BIGDECIMAL" => DataType::Double {
1342 precision: None,
1343 scale: None,
1344 },
1345 "NESTED" => DataType::Custom {
1347 name: "OBJECT".to_string(),
1348 },
1349 "BYTEINT" => DataType::Int {
1351 length: None,
1352 integer_spelling: false,
1353 },
1354 "CHAR VARYING" | "CHARACTER VARYING" => DataType::VarChar {
1356 length: None,
1357 parenthesized_length: false,
1358 },
1359 "SQL_DOUBLE" => DataType::Double {
1361 precision: None,
1362 scale: None,
1363 },
1364 "SQL_VARCHAR" => DataType::VarChar {
1366 length: None,
1367 parenthesized_length: false,
1368 },
1369 "TIMESTAMP_NTZ" => DataType::Custom {
1371 name: "TIMESTAMPNTZ".to_string(),
1372 },
1373 "TIMESTAMP_LTZ" => DataType::Custom {
1375 name: "TIMESTAMPLTZ".to_string(),
1376 },
1377 "TIMESTAMP_TZ" => DataType::Custom {
1379 name: "TIMESTAMPTZ".to_string(),
1380 },
1381 "NCHAR VARYING" => DataType::VarChar {
1383 length: None,
1384 parenthesized_length: false,
1385 },
1386 "NUMBER" => DataType::Decimal {
1388 precision: Some(38),
1389 scale: Some(0),
1390 },
1391 _ if name.starts_with("NUMBER(") => {
1392 let inner = &name[7..name.len() - 1]; let parts: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1396 let precision = parts.first().and_then(|p| p.parse::<u32>().ok());
1397 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1398 DataType::Decimal { precision, scale }
1399 }
1400 _ => DataType::Custom { name },
1401 }
1402 }
1403 DataType::Decimal {
1405 precision: None,
1406 scale: None,
1407 } => DataType::Decimal {
1408 precision: Some(38),
1409 scale: Some(0),
1410 },
1411 DataType::Float { .. } => DataType::Double {
1413 precision: None,
1414 scale: None,
1415 },
1416 other => other,
1418 };
1419 Ok(Expression::DataType(transformed))
1420 }
1421
1422 fn map_date_part(abbr: &str) -> Option<&'static str> {
1424 match abbr.to_uppercase().as_str() {
1425 "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some("YEAR"),
1427 "MM" | "MON" | "MONS" | "MONTHS" => Some("MONTH"),
1429 "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some("DAY"),
1431 "DAY OF WEEK" | "WEEKDAY" | "DOW" | "DW" => Some("DAYOFWEEK"),
1433 "WEEKDAY_ISO" | "DOW_ISO" | "DW_ISO" | "DAYOFWEEK_ISO" => Some("DAYOFWEEKISO"),
1434 "DAY OF YEAR" | "DOY" | "DY" => Some("DAYOFYEAR"),
1436 "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY" => Some("WEEK"),
1438 "WEEK_ISO" | "WEEKOFYEARISO" | "WEEKOFYEAR_ISO" => Some("WEEKISO"),
1439 "Q" | "QTR" | "QTRS" | "QUARTERS" => Some("QUARTER"),
1441 "H" | "HH" | "HR" | "HOURS" | "HRS" => Some("HOUR"),
1443 "MI" | "MIN" | "MINUTES" | "MINS" => Some("MINUTE"),
1445 "S" | "SEC" | "SECONDS" | "SECS" => Some("SECOND"),
1447 "MS" | "MSEC" | "MSECS" | "MSECOND" | "MSECONDS" | "MILLISEC" | "MILLISECS"
1449 | "MILLISECON" | "MILLISECONDS" => Some("MILLISECOND"),
1450 "US" | "USEC" | "USECS" | "MICROSEC" | "MICROSECS" | "USECOND" | "USECONDS"
1452 | "MICROSECONDS" => Some("MICROSECOND"),
1453 "NS" | "NSEC" | "NANOSEC" | "NSECOND" | "NSECONDS" | "NANOSECS" => Some("NANOSECOND"),
1455 "EPOCH_SECOND" | "EPOCH_SECONDS" => Some("EPOCH_SECOND"),
1457 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Some("EPOCH_MILLISECOND"),
1458 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Some("EPOCH_MICROSECOND"),
1459 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Some("EPOCH_NANOSECOND"),
1460 "TZH" => Some("TIMEZONE_HOUR"),
1462 "TZM" => Some("TIMEZONE_MINUTE"),
1463 "DEC" | "DECS" | "DECADES" => Some("DECADE"),
1465 "MIL" | "MILS" | "MILLENIA" => Some("MILLENNIUM"),
1467 "C" | "CENT" | "CENTS" | "CENTURIES" => Some("CENTURY"),
1469 _ => None,
1471 }
1472 }
1473
1474 fn transform_date_part_arg(&self, expr: Expression) -> Expression {
1476 match &expr {
1477 Expression::Literal(lit)
1479 if matches!(lit.as_ref(), crate::expressions::Literal::String(_)) =>
1480 {
1481 let crate::expressions::Literal::String(s) = lit.as_ref() else {
1482 unreachable!()
1483 };
1484 Expression::Identifier(crate::expressions::Identifier {
1485 name: s.clone(),
1486 quoted: false,
1487 trailing_comments: Vec::new(),
1488 span: None,
1489 })
1490 }
1491 Expression::Identifier(id) => {
1493 if let Some(canonical) = Self::map_date_part(&id.name) {
1494 Expression::Identifier(crate::expressions::Identifier {
1495 name: canonical.to_string(),
1496 quoted: false,
1497 trailing_comments: Vec::new(),
1498 span: None,
1499 })
1500 } else {
1501 expr
1503 }
1504 }
1505 Expression::Var(v) => {
1506 if let Some(canonical) = Self::map_date_part(&v.this) {
1507 Expression::Identifier(crate::expressions::Identifier {
1508 name: canonical.to_string(),
1509 quoted: false,
1510 trailing_comments: Vec::new(),
1511 span: None,
1512 })
1513 } else {
1514 expr
1515 }
1516 }
1517 Expression::Column(col) if col.table.is_none() => {
1519 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1520 Expression::Identifier(crate::expressions::Identifier {
1521 name: canonical.to_string(),
1522 quoted: false,
1523 trailing_comments: Vec::new(),
1524 span: None,
1525 })
1526 } else {
1527 expr
1529 }
1530 }
1531 _ => expr,
1532 }
1533 }
1534
1535 fn transform_date_part_arg_identifiers_only(&self, expr: Expression) -> Expression {
1538 match &expr {
1539 Expression::Identifier(id) => {
1540 if let Some(canonical) = Self::map_date_part(&id.name) {
1541 Expression::Identifier(crate::expressions::Identifier {
1542 name: canonical.to_string(),
1543 quoted: false,
1544 trailing_comments: Vec::new(),
1545 span: None,
1546 })
1547 } else {
1548 expr
1549 }
1550 }
1551 Expression::Var(v) => {
1552 if let Some(canonical) = Self::map_date_part(&v.this) {
1553 Expression::Identifier(crate::expressions::Identifier {
1554 name: canonical.to_string(),
1555 quoted: false,
1556 trailing_comments: Vec::new(),
1557 span: None,
1558 })
1559 } else {
1560 expr
1561 }
1562 }
1563 Expression::Column(col) if col.table.is_none() => {
1564 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1565 Expression::Identifier(crate::expressions::Identifier {
1566 name: canonical.to_string(),
1567 quoted: false,
1568 trailing_comments: Vec::new(),
1569 span: None,
1570 })
1571 } else {
1572 expr
1573 }
1574 }
1575 _ => expr,
1576 }
1577 }
1578
1579 fn transform_json_path(path: &str) -> String {
1583 fn is_safe_identifier(s: &str) -> bool {
1586 if s.is_empty() {
1587 return false;
1588 }
1589 let mut chars = s.chars();
1590 match chars.next() {
1591 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
1592 _ => return false,
1593 }
1594 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
1595 }
1596
1597 if !path.contains('.') && !path.contains('[') && !path.contains(':') {
1600 if is_safe_identifier(path) {
1601 return path.to_string();
1602 } else {
1603 return format!("[\"{}\"]", path);
1605 }
1606 }
1607
1608 let result = path.replace(':', ".");
1611 result
1612 }
1613
1614 fn transform_interval(&self, interval: crate::expressions::Interval) -> Result<Expression> {
1616 use crate::expressions::{Interval, Literal};
1617
1618 fn expand_unit(abbr: &str) -> &'static str {
1620 match abbr.to_uppercase().as_str() {
1621 "D" => "DAY",
1622 "H" => "HOUR",
1623 "M" => "MINUTE",
1624 "MS" => "MILLISECOND",
1625 "NS" => "NANOSECOND",
1626 "Q" => "QUARTER",
1627 "S" => "SECOND",
1628 "US" => "MICROSECOND",
1629 "W" => "WEEK",
1630 "Y" => "YEAR",
1631 "WEEK" | "WEEKS" => "WEEK",
1633 "DAY" | "DAYS" => "DAY",
1634 "HOUR" | "HOURS" => "HOUR",
1635 "MINUTE" | "MINUTES" => "MINUTE",
1636 "SECOND" | "SECONDS" => "SECOND",
1637 "MONTH" | "MONTHS" => "MONTH",
1638 "YEAR" | "YEARS" => "YEAR",
1639 "QUARTER" | "QUARTERS" => "QUARTER",
1640 "MILLISECOND" | "MILLISECONDS" => "MILLISECOND",
1641 "MICROSECOND" | "MICROSECONDS" => "MICROSECOND",
1642 "NANOSECOND" | "NANOSECONDS" => "NANOSECOND",
1643 _ => "", }
1645 }
1646
1647 fn parse_interval_string(s: &str) -> Option<(&str, &str)> {
1649 let s = s.trim();
1650
1651 let mut num_end = 0;
1654 let mut chars = s.chars().peekable();
1655
1656 if chars.peek() == Some(&'-') {
1658 chars.next();
1659 num_end += 1;
1660 }
1661
1662 while let Some(&c) = chars.peek() {
1664 if c.is_ascii_digit() {
1665 chars.next();
1666 num_end += 1;
1667 } else {
1668 break;
1669 }
1670 }
1671
1672 if chars.peek() == Some(&'.') {
1674 chars.next();
1675 num_end += 1;
1676 while let Some(&c) = chars.peek() {
1677 if c.is_ascii_digit() {
1678 chars.next();
1679 num_end += 1;
1680 } else {
1681 break;
1682 }
1683 }
1684 }
1685
1686 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1687 return None; }
1689
1690 let value = &s[..num_end];
1691 let rest = s[num_end..].trim();
1692
1693 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1695 return None;
1696 }
1697
1698 Some((value, rest))
1699 }
1700
1701 if let Some(Expression::Literal(ref lit)) = interval.this {
1703 if let Literal::String(ref s) = lit.as_ref() {
1704 if let Some((value, unit)) = parse_interval_string(s) {
1705 let expanded = expand_unit(unit);
1706 if !expanded.is_empty() {
1707 let new_value = format!("{} {}", value, expanded);
1709
1710 return Ok(Expression::Interval(Box::new(Interval {
1711 this: Some(Expression::Literal(Box::new(Literal::String(new_value)))),
1712 unit: None, })));
1714 }
1715 }
1716 }
1717 }
1718
1719 Ok(Expression::Interval(Box::new(interval)))
1721 }
1722
1723 fn transform_function(&self, f: Function) -> Result<Expression> {
1724 let transformed_args: Vec<Expression> = f
1726 .args
1727 .into_iter()
1728 .map(|arg| self.transform_expr(arg))
1729 .collect::<Result<Vec<_>>>()?;
1730
1731 let f = Function {
1732 on_error: None,
1733 qualified_name: Vec::new(),
1734 source_dialect: None,
1735
1736 name: f.name,
1737 args: transformed_args,
1738 distinct: f.distinct,
1739 trailing_comments: f.trailing_comments,
1740 use_bracket_syntax: f.use_bracket_syntax,
1741 no_parens: f.no_parens,
1742 quoted: f.quoted,
1743 span: None,
1744 inferred_type: None,
1745 };
1746
1747 let name_upper = f.name.to_uppercase();
1748 match name_upper.as_str() {
1749 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1751 original_name: None,
1752 expressions: f.args,
1753 inferred_type: None,
1754 }))),
1755
1756 "NVL" 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 "NVL2" => Ok(Expression::Function(Box::new(f))),
1765
1766 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1768 Function::new("LISTAGG".to_string(), f.args),
1769 ))),
1770
1771 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1773 Function::new("LISTAGG".to_string(), f.args),
1774 ))),
1775
1776 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1778 "SUBSTRING".to_string(),
1779 f.args,
1780 )))),
1781
1782 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
1784 "FLATTEN".to_string(),
1785 f.args,
1786 )))),
1787
1788 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1790 "FLATTEN".to_string(),
1791 f.args,
1792 )))),
1793
1794 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1796
1797 "NOW" => Ok(Expression::Function(Box::new(Function {
1799 on_error: None,
1800 qualified_name: Vec::new(),
1801 source_dialect: None,
1802
1803 name: "CURRENT_TIMESTAMP".to_string(),
1804 args: f.args,
1805 distinct: false,
1806 trailing_comments: Vec::new(),
1807 use_bracket_syntax: false,
1808 no_parens: f.no_parens,
1809 quoted: false,
1810 span: None,
1811 inferred_type: None,
1812 }))),
1813
1814 "GETDATE" => Ok(Expression::Function(Box::new(Function {
1816 on_error: None,
1817 qualified_name: Vec::new(),
1818 source_dialect: None,
1819
1820 name: "CURRENT_TIMESTAMP".to_string(),
1821 args: f.args,
1822 distinct: false,
1823 trailing_comments: Vec::new(),
1824 use_bracket_syntax: false,
1825 no_parens: f.no_parens,
1826 quoted: false,
1827 span: None,
1828 inferred_type: None,
1829 }))),
1830
1831 "CURRENT_TIMESTAMP" if f.args.is_empty() => {
1835 Ok(Expression::Function(Box::new(Function {
1836 on_error: None,
1837 qualified_name: Vec::new(),
1838 source_dialect: None,
1839
1840 name: "CURRENT_TIMESTAMP".to_string(),
1841 args: Vec::new(),
1842 distinct: false,
1843 trailing_comments: Vec::new(),
1844 use_bracket_syntax: false,
1845 no_parens: false, quoted: false,
1847 span: None,
1848 inferred_type: None,
1849 })))
1850 }
1851
1852 "TO_DATE" => {
1856 if f.args.len() == 1 {
1857 if let Expression::Literal(lit) = &f.args[0] {
1858 if let crate::expressions::Literal::String(s) = lit.as_ref() {
1859 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
1861 return Ok(Expression::Cast(Box::new(Cast {
1862 this: f.args.into_iter().next().unwrap(),
1863 to: crate::expressions::DataType::Date,
1864 double_colon_syntax: false,
1865 trailing_comments: Vec::new(),
1866 format: None,
1867 default: None,
1868 inferred_type: None,
1869 })));
1870 }
1871 }
1872 }
1873 }
1874 let mut args = f.args;
1876 if args.len() >= 2 {
1877 args[1] = Self::normalize_format_arg(args[1].clone());
1878 }
1879 Ok(Expression::Function(Box::new(Function::new(
1880 "TO_DATE".to_string(),
1881 args,
1882 ))))
1883 }
1884
1885 "TO_TIME" => {
1887 if f.args.len() == 1 {
1888 if let Expression::Literal(lit) = &f.args[0] {
1889 if let crate::expressions::Literal::String(_) = lit.as_ref() {
1890 return Ok(Expression::Cast(Box::new(Cast {
1891 this: f.args.into_iter().next().unwrap(),
1892 to: crate::expressions::DataType::Time {
1893 precision: None,
1894 timezone: false,
1895 },
1896 double_colon_syntax: false,
1897 trailing_comments: Vec::new(),
1898 format: None,
1899 default: None,
1900 inferred_type: None,
1901 })));
1902 }
1903 }
1904 }
1905 let mut args = f.args;
1907 if args.len() >= 2 {
1908 args[1] = Self::normalize_format_arg(args[1].clone());
1909 }
1910 Ok(Expression::Function(Box::new(Function::new(
1911 "TO_TIME".to_string(),
1912 args,
1913 ))))
1914 }
1915
1916 "TO_TIMESTAMP" => {
1923 let args = f.args;
1924 if args.len() == 1 {
1925 let arg = &args[0];
1926 match arg {
1927 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_datetime(s)) =>
1928 {
1929 let Literal::String(_) = lit.as_ref() else {
1930 unreachable!()
1931 };
1932 return Ok(Expression::Cast(Box::new(Cast {
1934 this: args.into_iter().next().unwrap(),
1935 to: DataType::Timestamp {
1936 precision: None,
1937 timezone: false,
1938 },
1939 double_colon_syntax: false,
1940 trailing_comments: vec![],
1941 format: None,
1942 default: None,
1943 inferred_type: None,
1944 })));
1945 }
1946 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_epoch(s)) =>
1947 {
1948 let Literal::String(_) = lit.as_ref() else {
1949 unreachable!()
1950 };
1951 return Ok(Expression::UnixToTime(Box::new(
1953 crate::expressions::UnixToTime {
1954 this: Box::new(args.into_iter().next().unwrap()),
1955 scale: None,
1956 zone: None,
1957 hours: None,
1958 minutes: None,
1959 format: None,
1960 target_type: None,
1961 },
1962 )));
1963 }
1964 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1965 return Ok(Expression::UnixToTime(Box::new(
1967 crate::expressions::UnixToTime {
1968 this: Box::new(args.into_iter().next().unwrap()),
1969 scale: None,
1970 zone: None,
1971 hours: None,
1972 minutes: None,
1973 format: None,
1974 target_type: None,
1975 },
1976 )));
1977 }
1978 Expression::Neg(_) => {
1979 return Ok(Expression::UnixToTime(Box::new(
1981 crate::expressions::UnixToTime {
1982 this: Box::new(args.into_iter().next().unwrap()),
1983 scale: None,
1984 zone: None,
1985 hours: None,
1986 minutes: None,
1987 format: None,
1988 target_type: None,
1989 },
1990 )));
1991 }
1992 _ => {
1993 return Ok(Expression::Function(Box::new(Function::new(
1995 "TO_TIMESTAMP".to_string(),
1996 args,
1997 ))));
1998 }
1999 }
2000 } else if args.len() == 2 {
2001 let second_arg = &args[1];
2002 let is_int_scale = match second_arg {
2004 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
2005 let Literal::Number(n) = lit.as_ref() else {
2006 unreachable!()
2007 };
2008 n.parse::<i64>().is_ok()
2009 }
2010 _ => false,
2011 };
2012
2013 if is_int_scale {
2014 let mut args_iter = args.into_iter();
2016 let value = args_iter.next().unwrap();
2017 let scale_expr = args_iter.next().unwrap();
2018 let scale = if let Expression::Literal(lit) = &scale_expr {
2019 if let Literal::Number(n) = lit.as_ref() {
2020 n.parse::<i64>().ok()
2021 } else {
2022 None
2023 }
2024 } else {
2025 None
2026 };
2027 return Ok(Expression::UnixToTime(Box::new(
2028 crate::expressions::UnixToTime {
2029 this: Box::new(value),
2030 scale,
2031 zone: None,
2032 hours: None,
2033 minutes: None,
2034 format: None,
2035 target_type: None,
2036 },
2037 )));
2038 } else {
2039 let mut args_iter = args.into_iter();
2041 let value = args_iter.next().unwrap();
2042 let format_expr = args_iter.next().unwrap();
2043 let format_str = match &format_expr {
2044 Expression::Literal(lit)
2045 if matches!(lit.as_ref(), Literal::String(_)) =>
2046 {
2047 let Literal::String(s) = lit.as_ref() else {
2048 unreachable!()
2049 };
2050 s.clone()
2051 }
2052 _ => {
2053 return Ok(Expression::Function(Box::new(Function::new(
2055 "TO_TIMESTAMP".to_string(),
2056 vec![value, format_expr],
2057 ))));
2058 }
2059 };
2060 let normalized_format = Self::normalize_snowflake_format(&format_str);
2062 return Ok(Expression::StrToTime(Box::new(
2063 crate::expressions::StrToTime {
2064 this: Box::new(value),
2065 format: normalized_format,
2066 zone: None,
2067 safe: None,
2068 target_type: None,
2069 },
2070 )));
2071 }
2072 }
2073 Ok(Expression::Function(Box::new(Function::new(
2075 "TO_TIMESTAMP".to_string(),
2076 args,
2077 ))))
2078 }
2079
2080 "TO_CHAR"
2083 if f.args.len() == 2
2084 && Self::is_temporal_expr(&f.args[0])
2085 && matches!(&f.args[1], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_))) =>
2086 {
2087 let mut args = f.args;
2088 let this = args.remove(0);
2089 let Literal::String(format) = (match args.remove(0) {
2090 Expression::Literal(lit) => *lit,
2091 _ => unreachable!(),
2092 }) else {
2093 unreachable!()
2094 };
2095
2096 Ok(Expression::TimeToStr(Box::new(
2097 crate::expressions::TimeToStr {
2098 this: Box::new(this),
2099 format: Self::normalize_snowflake_format(&format),
2100 culture: None,
2101 zone: None,
2102 },
2103 )))
2104 }
2105
2106 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
2108
2109 "ROUND"
2112 if f.args
2113 .iter()
2114 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
2115 {
2116 let mut expr_val = None;
2117 let mut scale_val = None;
2118 let mut rounding_mode_val = None;
2119 for arg in &f.args {
2120 if let Expression::NamedArgument(na) = arg {
2121 match na.name.name.to_uppercase().as_str() {
2122 "EXPR" => expr_val = Some(na.value.clone()),
2123 "SCALE" => scale_val = Some(na.value.clone()),
2124 "ROUNDING_MODE" => rounding_mode_val = Some(na.value.clone()),
2125 _ => {}
2126 }
2127 }
2128 }
2129 if let Some(expr) = expr_val {
2130 let mut args = vec![expr];
2131 if let Some(scale) = scale_val {
2132 args.push(scale);
2133 }
2134 if let Some(mode) = rounding_mode_val {
2135 args.push(mode);
2136 }
2137 Ok(Expression::Function(Box::new(Function::new(
2138 "ROUND".to_string(),
2139 args,
2140 ))))
2141 } else {
2142 Ok(Expression::Function(Box::new(f)))
2143 }
2144 }
2145
2146 "DATE_FORMAT" => {
2149 let mut args = f.args;
2150 if !args.is_empty() {
2152 if matches!(&args[0], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)))
2153 {
2154 args[0] = Expression::Cast(Box::new(crate::expressions::Cast {
2155 this: args[0].clone(),
2156 to: DataType::Timestamp {
2157 precision: None,
2158 timezone: false,
2159 },
2160 trailing_comments: Vec::new(),
2161 double_colon_syntax: false,
2162 format: None,
2163 default: None,
2164 inferred_type: None,
2165 }));
2166 }
2167 }
2168 if args.len() >= 2 {
2170 if let Expression::Literal(ref lit) = args[1] {
2171 if let Literal::String(ref fmt) = lit.as_ref() {
2172 let sf_fmt = strftime_to_snowflake_format(fmt);
2173 args[1] = Expression::Literal(Box::new(Literal::String(sf_fmt)));
2174 }
2175 }
2176 }
2177 Ok(Expression::Function(Box::new(Function::new(
2178 "TO_CHAR".to_string(),
2179 args,
2180 ))))
2181 }
2182
2183 "ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2185 "ARRAY_CONSTRUCT".to_string(),
2186 f.args,
2187 )))),
2188
2189 "STRUCT" => {
2192 let mut oc_args = Vec::new();
2193 for arg in f.args {
2194 match arg {
2195 Expression::Alias(a) => {
2196 oc_args.push(Expression::Literal(Box::new(
2198 crate::expressions::Literal::String(a.alias.name.clone()),
2199 )));
2200 oc_args.push(a.this);
2201 }
2202 other => {
2203 oc_args.push(other);
2205 }
2206 }
2207 }
2208 Ok(Expression::Function(Box::new(Function::new(
2209 "OBJECT_CONSTRUCT".to_string(),
2210 oc_args,
2211 ))))
2212 }
2213
2214 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2216 "GET_PATH".to_string(),
2217 f.args,
2218 )))),
2219
2220 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2222 "JSON_EXTRACT_PATH_TEXT".to_string(),
2223 f.args,
2224 )))),
2225
2226 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2228 f.args.into_iter().next().unwrap(),
2229 )))),
2230
2231 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2233 this: f.args.into_iter().next().unwrap(),
2234 decimals: None,
2235 to: None,
2236 }))),
2237
2238 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2240
2241 "SPLIT" => Ok(Expression::Function(Box::new(f))),
2243
2244 "ARRAY_AGG" => Ok(Expression::Function(Box::new(f))),
2246
2247 "JSON_PARSE" | "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2249 "PARSE_JSON".to_string(),
2250 f.args,
2251 )))),
2252
2253 "RAND" => {
2255 let seed = f.args.first().cloned().map(Box::new);
2256 Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2257 seed,
2258 lower: None,
2259 upper: None,
2260 })))
2261 }
2262
2263 "SHA" => Ok(Expression::Function(Box::new(Function::new(
2265 "SHA1".to_string(),
2266 f.args,
2267 )))),
2268
2269 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
2271 "APPROX_COUNT_DISTINCT".to_string(),
2272 f.args,
2273 )))),
2274
2275 "GEN_RANDOM_UUID" | "UUID" => {
2277 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2278 this: None,
2279 name: None,
2280 is_string: None,
2281 })))
2282 }
2283
2284 "NEWID" => Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2286 this: None,
2287 name: None,
2288 is_string: None,
2289 }))),
2290
2291 "UUID_STRING" => {
2293 if f.args.is_empty() {
2294 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2295 this: None,
2296 name: None,
2297 is_string: None,
2298 })))
2299 } else {
2300 Ok(Expression::Function(Box::new(Function::new(
2301 "UUID_STRING".to_string(),
2302 f.args,
2303 ))))
2304 }
2305 }
2306
2307 "IF" if f.args.len() >= 2 => {
2309 let mut args = f.args;
2310 let condition = args.remove(0);
2311 let true_val = args.remove(0);
2312 let false_val = if !args.is_empty() {
2313 Some(args.remove(0))
2314 } else {
2315 None
2316 };
2317 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2318 condition,
2319 true_value: true_val,
2320 false_value: Some(
2321 false_val.unwrap_or(Expression::Null(crate::expressions::Null)),
2322 ),
2323 original_name: Some("IFF".to_string()),
2324 inferred_type: None,
2325 })))
2326 }
2327
2328 "SQUARE" if f.args.len() == 1 => {
2330 let x = f.args.into_iter().next().unwrap();
2331 Ok(Expression::Power(Box::new(
2332 crate::expressions::BinaryFunc {
2333 original_name: None,
2334 this: x,
2335 expression: Expression::number(2),
2336 inferred_type: None,
2337 },
2338 )))
2339 }
2340
2341 "POW" if f.args.len() == 2 => {
2343 let mut args = f.args.into_iter();
2344 let x = args.next().unwrap();
2345 let y = args.next().unwrap();
2346 Ok(Expression::Power(Box::new(
2347 crate::expressions::BinaryFunc {
2348 original_name: None,
2349 this: x,
2350 expression: y,
2351 inferred_type: None,
2352 },
2353 )))
2354 }
2355
2356 "MOD" if f.args.len() == 2 => {
2358 let mut args = f.args.into_iter();
2359 let x = args.next().unwrap();
2360 let y = args.next().unwrap();
2361 Ok(Expression::Mod(Box::new(crate::expressions::BinaryOp {
2362 left: x,
2363 right: y,
2364 left_comments: Vec::new(),
2365 operator_comments: Vec::new(),
2366 trailing_comments: Vec::new(),
2367 inferred_type: None,
2368 })))
2369 }
2370
2371 "APPROXIMATE_JACCARD_INDEX" => Ok(Expression::Function(Box::new(Function::new(
2373 "APPROXIMATE_SIMILARITY".to_string(),
2374 f.args,
2375 )))),
2376
2377 "ARRAY_CONSTRUCT" => Ok(Expression::ArrayFunc(Box::new(
2379 crate::expressions::ArrayConstructor {
2380 expressions: f.args,
2381 bracket_notation: true,
2382 use_list_keyword: false,
2383 inferred_type: None,
2384 },
2385 ))),
2386
2387 "APPROX_TOP_K" if f.args.len() == 1 => {
2389 let mut args = f.args;
2390 args.push(Expression::number(1));
2391 Ok(Expression::Function(Box::new(Function::new(
2392 "APPROX_TOP_K".to_string(),
2393 args,
2394 ))))
2395 }
2396
2397 "TO_DECIMAL" | "TO_NUMERIC" => Ok(Expression::Function(Box::new(Function::new(
2399 "TO_NUMBER".to_string(),
2400 f.args,
2401 )))),
2402
2403 "TRY_TO_DECIMAL" | "TRY_TO_NUMERIC" => Ok(Expression::Function(Box::new(
2405 Function::new("TRY_TO_NUMBER".to_string(), f.args),
2406 ))),
2407
2408 "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2410 "STDDEV".to_string(),
2411 f.args,
2412 )))),
2413
2414 "STRTOK" if f.args.len() >= 1 => {
2416 let mut args = f.args;
2417 if args.len() == 1 {
2419 args.push(Expression::string(" ".to_string()));
2420 }
2421 if args.len() == 2 {
2423 args.push(Expression::number(1));
2424 }
2425 Ok(Expression::Function(Box::new(Function::new(
2426 "STRTOK".to_string(),
2427 args,
2428 ))))
2429 }
2430
2431 "STRTOK_TO_ARRAY" if f.args.len() == 1 => {
2432 let mut args = f.args;
2433 args.push(Expression::string(" ".to_string()));
2434 Ok(Expression::Function(Box::new(Function::new(
2435 "STRTOK_TO_ARRAY".to_string(),
2436 args,
2437 ))))
2438 }
2439
2440 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2442 "WEEK".to_string(),
2443 f.args,
2444 )))),
2445
2446 "LIKE" if f.args.len() >= 2 => {
2448 let mut args = f.args.into_iter();
2449 let left = args.next().unwrap();
2450 let right = args.next().unwrap();
2451 let escape = args.next();
2452 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2453 left,
2454 right,
2455 escape,
2456 quantifier: None,
2457 inferred_type: None,
2458 })))
2459 }
2460
2461 "ILIKE" if f.args.len() >= 2 => {
2463 let mut args = f.args.into_iter();
2464 let left = args.next().unwrap();
2465 let right = args.next().unwrap();
2466 let escape = args.next();
2467 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2468 left,
2469 right,
2470 escape,
2471 quantifier: None,
2472 inferred_type: None,
2473 })))
2474 }
2475
2476 "RLIKE" if f.args.len() >= 2 => {
2478 let mut args = f.args.into_iter();
2479 let left = args.next().unwrap();
2480 let pattern = args.next().unwrap();
2481 let flags = args.next();
2482 Ok(Expression::RegexpLike(Box::new(
2483 crate::expressions::RegexpFunc {
2484 options: None,
2485
2486 this: left,
2487 pattern,
2488 flags,
2489 },
2490 )))
2491 }
2492
2493 "IFF" if f.args.len() >= 2 => {
2495 let mut args = f.args;
2496 let condition = args.remove(0);
2497 let true_value = args.remove(0);
2498 let false_value = if !args.is_empty() {
2499 Some(args.remove(0))
2500 } else {
2501 None
2502 };
2503 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2504 condition,
2505 true_value,
2506 false_value,
2507 original_name: Some("IFF".to_string()),
2508 inferred_type: None,
2509 })))
2510 }
2511
2512 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2514 Ok(Expression::Function(Box::new(Function::new(
2515 "TIMESTAMP_FROM_PARTS".to_string(),
2516 f.args,
2517 ))))
2518 }
2519
2520 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2522 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2523 f.args,
2524 )))),
2525
2526 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2528 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2529 f.args,
2530 )))),
2531
2532 "DATEADD" if f.args.len() >= 1 => {
2534 let mut args = f.args;
2535 args[0] = self.transform_date_part_arg(args[0].clone());
2536 Ok(Expression::Function(Box::new(Function::new(
2537 "DATEADD".to_string(),
2538 args,
2539 ))))
2540 }
2541
2542 "DATEDIFF" if f.args.len() >= 1 => {
2545 let mut args = f.args;
2546 args[0] = self.transform_date_part_arg(args[0].clone());
2547 for i in 1..args.len() {
2550 if let Expression::Function(ref func) = args[i] {
2551 if func.name == "_POLYGLOT_TO_DATE" {
2552 let inner_args = func.args.clone();
2553 args[i] = Expression::Function(Box::new(Function::new(
2554 "TO_DATE".to_string(),
2555 inner_args,
2556 )));
2557 }
2558 }
2559 }
2560 Ok(Expression::Function(Box::new(Function::new(
2561 "DATEDIFF".to_string(),
2562 args,
2563 ))))
2564 }
2565
2566 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2568 "DATEDIFF".to_string(),
2569 f.args,
2570 )))),
2571
2572 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2574 "DATEDIFF".to_string(),
2575 f.args,
2576 )))),
2577
2578 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2580 "DATEADD".to_string(),
2581 f.args,
2582 )))),
2583
2584 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2586
2587 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2589 "DATE_FROM_PARTS".to_string(),
2590 f.args,
2591 )))),
2592
2593 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2595 "TIME_FROM_PARTS".to_string(),
2596 f.args,
2597 )))),
2598
2599 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2601
2602 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2604
2605 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2607
2608 "MONTHNAME" if f.args.len() == 1 => {
2611 let arg = f.args.into_iter().next().unwrap();
2612 Ok(Expression::Monthname(Box::new(
2613 crate::expressions::Monthname {
2614 this: Box::new(arg),
2615 abbreviated: Some(Box::new(Expression::Literal(Box::new(
2616 Literal::String("true".to_string()),
2617 )))),
2618 },
2619 )))
2620 }
2621
2622 "DAYNAME" if f.args.len() == 1 => {
2625 let arg = f.args.into_iter().next().unwrap();
2626 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2627 this: Box::new(arg),
2628 abbreviated: Some(Box::new(Expression::Literal(Box::new(Literal::String(
2629 "true".to_string(),
2630 ))))),
2631 })))
2632 }
2633
2634 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2636 let arg = f.args.into_iter().next().unwrap();
2637 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2638 this: arg,
2639 distinct: false,
2640 filter: None,
2641 order_by: Vec::new(),
2642 name: Some("BOOLAND_AGG".to_string()),
2643 ignore_nulls: None,
2644 having_max: None,
2645 limit: None,
2646 inferred_type: None,
2647 })))
2648 }
2649
2650 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2652 let arg = f.args.into_iter().next().unwrap();
2653 Ok(Expression::LogicalOr(Box::new(AggFunc {
2654 this: arg,
2655 distinct: false,
2656 filter: None,
2657 order_by: Vec::new(),
2658 name: Some("BOOLOR_AGG".to_string()),
2659 ignore_nulls: None,
2660 having_max: None,
2661 limit: None,
2662 inferred_type: None,
2663 })))
2664 }
2665
2666 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2668 let arg = f.args.into_iter().next().unwrap();
2669 Ok(Expression::Skewness(Box::new(AggFunc {
2670 this: arg,
2671 distinct: false,
2672 filter: None,
2673 order_by: Vec::new(),
2674 name: Some("SKEW".to_string()),
2675 ignore_nulls: None,
2676 having_max: None,
2677 limit: None,
2678 inferred_type: None,
2679 })))
2680 }
2681
2682 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2684 "VARIANCE".to_string(),
2685 f.args,
2686 )))),
2687
2688 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2690 "VARIANCE_POP".to_string(),
2691 f.args,
2692 )))),
2693
2694 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2696 "TO_DATE".to_string(),
2697 f.args,
2698 )))),
2699 "DATE" if f.args.len() >= 2 => {
2703 let mut args = f.args;
2704 args[1] = Self::normalize_format_arg(args[1].clone());
2705 Ok(Expression::Function(Box::new(Function::new(
2706 "TO_DATE".to_string(),
2707 args,
2708 ))))
2709 }
2710 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2713 let mut args = f.args;
2714 args[1] = Self::normalize_format_arg(args[1].clone());
2715 Ok(Expression::Function(Box::new(Function::new(
2716 "DATE".to_string(),
2717 args,
2718 ))))
2719 }
2720
2721 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2723
2724 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2726 "MD5".to_string(),
2727 f.args,
2728 )))),
2729
2730 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2732 "SHA1".to_string(),
2733 f.args,
2734 )))),
2735
2736 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2738 "SHA2".to_string(),
2739 f.args,
2740 )))),
2741
2742 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2744 "EDITDISTANCE".to_string(),
2745 f.args,
2746 )))),
2747
2748 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2750 "BITNOT".to_string(),
2751 f.args,
2752 )))),
2753
2754 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2756 "BITAND".to_string(),
2757 f.args,
2758 )))),
2759
2760 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2762 "BITOR".to_string(),
2763 f.args,
2764 )))),
2765
2766 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2768 "BITXOR".to_string(),
2769 f.args,
2770 )))),
2771
2772 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2774 Function::new("BITSHIFTLEFT".to_string(), f.args),
2775 ))),
2776
2777 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2779 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2780 ))),
2781
2782 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2784 on_error: None,
2785 qualified_name: Vec::new(),
2786 source_dialect: None,
2787
2788 name: "CURRENT_TIMESTAMP".to_string(),
2789 args: f.args,
2790 distinct: false,
2791 trailing_comments: Vec::new(),
2792 use_bracket_syntax: false,
2793 no_parens: f.no_parens,
2794 quoted: false,
2795 span: None,
2796 inferred_type: None,
2797 }))),
2798
2799 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2801 on_error: None,
2802 qualified_name: Vec::new(),
2803 source_dialect: None,
2804
2805 name: "CURRENT_TIMESTAMP".to_string(),
2806 args: f.args,
2807 distinct: false,
2808 trailing_comments: Vec::new(),
2809 use_bracket_syntax: false,
2810 no_parens: f.no_parens,
2811 quoted: false,
2812 span: None,
2813 inferred_type: None,
2814 }))),
2815
2816 "SPACE" if f.args.len() == 1 => {
2818 let arg = f.args.into_iter().next().unwrap();
2819 Ok(Expression::Function(Box::new(Function::new(
2820 "REPEAT".to_string(),
2821 vec![
2822 Expression::Literal(Box::new(Literal::String(" ".to_string()))),
2823 arg,
2824 ],
2825 ))))
2826 }
2827
2828 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2830 "CEIL".to_string(),
2831 f.args,
2832 )))),
2833
2834 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2836 "LN".to_string(),
2837 f.args,
2838 )))),
2839
2840 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(f))),
2842
2843 "GET_PATH" if f.args.len() >= 2 => {
2847 let mut args = f.args;
2848 if let Expression::Literal(lit) = &args[1] {
2850 if let crate::expressions::Literal::String(path) = lit.as_ref() {
2851 let transformed = Self::transform_json_path(path);
2852 args[1] = Expression::Literal(Box::new(
2853 crate::expressions::Literal::String(transformed),
2854 ));
2855 }
2856 }
2857 Ok(Expression::Function(Box::new(Function::new(
2858 "GET_PATH".to_string(),
2859 args,
2860 ))))
2861 }
2862 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2863
2864 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2866
2867 "DATE_TRUNC" if f.args.len() >= 1 => {
2870 let mut args = f.args;
2871 let unit_name = match &args[0] {
2873 Expression::Identifier(id) => Some(id.name.as_str()),
2874 Expression::Var(v) => Some(v.this.as_str()),
2875 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2876 _ => None,
2877 };
2878 if let Some(name) = unit_name {
2879 let canonical = Self::map_date_part(name).unwrap_or(name);
2880 args[0] = Expression::Literal(Box::new(crate::expressions::Literal::String(
2881 canonical.to_uppercase(),
2882 )));
2883 }
2884 Ok(Expression::Function(Box::new(Function::new(
2885 "DATE_TRUNC".to_string(),
2886 args,
2887 ))))
2888 }
2889
2890 "DATE_PART" if f.args.len() >= 1 => {
2896 let mut args = f.args;
2897 let from_typed_literal = args.len() >= 2
2898 && matches!(
2899 &args[1],
2900 Expression::Literal(lit) if matches!(lit.as_ref(),
2901 crate::expressions::Literal::Timestamp(_)
2902 | crate::expressions::Literal::Date(_)
2903 | crate::expressions::Literal::Time(_)
2904 | crate::expressions::Literal::Datetime(_)
2905 )
2906 );
2907 if from_typed_literal {
2908 args[0] = self.transform_date_part_arg(args[0].clone());
2909 } else {
2910 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2913 }
2914 Ok(Expression::Function(Box::new(Function::new(
2915 "DATE_PART".to_string(),
2916 args,
2917 ))))
2918 }
2919
2920 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2922
2923 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2925
2926 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2928 "DESCRIBE".to_string(),
2929 f.args,
2930 )))),
2931
2932 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2934 "REGEXP_LIKE".to_string(),
2935 f.args,
2936 )))),
2937
2938 "TRANSFORM" => {
2943 let transformed_args: Vec<Expression> = f
2944 .args
2945 .into_iter()
2946 .map(|arg| {
2947 if let Expression::Lambda(lambda) = arg {
2948 self.transform_typed_lambda(*lambda)
2949 } else {
2950 arg
2951 }
2952 })
2953 .collect();
2954 Ok(Expression::Function(Box::new(Function::new(
2955 "TRANSFORM".to_string(),
2956 transformed_args,
2957 ))))
2958 }
2959
2960 "SEARCH" if f.args.len() >= 2 => {
2962 let mut args = f.args.into_iter();
2963 let this = Box::new(args.next().unwrap());
2964 let expression = Box::new(args.next().unwrap());
2965
2966 let mut analyzer: Option<Box<Expression>> = None;
2967 let mut search_mode: Option<Box<Expression>> = None;
2968
2969 for arg in args {
2971 if let Expression::NamedArgument(na) = &arg {
2972 let name_upper = na.name.name.to_uppercase();
2973 match name_upper.as_str() {
2974 "ANALYZER" => analyzer = Some(Box::new(arg)),
2975 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2976 _ => {}
2977 }
2978 }
2979 }
2980
2981 Ok(Expression::Search(Box::new(crate::expressions::Search {
2982 this,
2983 expression,
2984 json_scope: None,
2985 analyzer,
2986 analyzer_options: None,
2987 search_mode,
2988 })))
2989 }
2990
2991 "CONVERT" if f.args.len() == 2 => {
2994 let value = f.args.get(0).cloned().unwrap();
2995 let type_arg = f.args.get(1).cloned().unwrap();
2996
2997 if let Expression::Column(col) = &type_arg {
2999 let type_name = col.name.name.to_uppercase();
3000 let data_type = match type_name.as_str() {
3001 "SQL_DOUBLE" => Some(DataType::Double {
3002 precision: None,
3003 scale: None,
3004 }),
3005 "SQL_VARCHAR" => Some(DataType::VarChar {
3006 length: None,
3007 parenthesized_length: false,
3008 }),
3009 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
3010 length: None,
3011 integer_spelling: false,
3012 }),
3013 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
3014 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
3015 "SQL_FLOAT" => Some(DataType::Float {
3016 precision: None,
3017 scale: None,
3018 real_spelling: false,
3019 }),
3020 "SQL_REAL" => Some(DataType::Float {
3021 precision: None,
3022 scale: None,
3023 real_spelling: true,
3024 }),
3025 "SQL_DECIMAL" => Some(DataType::Decimal {
3026 precision: None,
3027 scale: None,
3028 }),
3029 "SQL_DATE" => Some(DataType::Date),
3030 "SQL_TIME" => Some(DataType::Time {
3031 precision: None,
3032 timezone: false,
3033 }),
3034 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
3035 precision: None,
3036 timezone: false,
3037 }),
3038 _ => None,
3039 };
3040
3041 if let Some(dt) = data_type {
3042 return Ok(Expression::Cast(Box::new(Cast {
3043 this: value,
3044 to: dt,
3045 double_colon_syntax: false,
3046 trailing_comments: vec![],
3047 format: None,
3048 default: None,
3049 inferred_type: None,
3050 })));
3051 }
3052 }
3053 Ok(Expression::Function(Box::new(f)))
3055 }
3056
3057 "TO_TIMESTAMP_TZ" => {
3060 if f.args.len() == 1 {
3061 if let Expression::Literal(lit) = &f.args[0] {
3062 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3063 return Ok(Expression::Cast(Box::new(Cast {
3064 this: f.args.into_iter().next().unwrap(),
3065 to: DataType::Custom {
3066 name: "TIMESTAMPTZ".to_string(),
3067 },
3068 double_colon_syntax: false,
3069 trailing_comments: vec![],
3070 format: None,
3071 default: None,
3072 inferred_type: None,
3073 })));
3074 }
3075 }
3076 }
3077 Ok(Expression::Function(Box::new(f)))
3078 }
3079
3080 "TO_TIMESTAMP_NTZ" => {
3082 if f.args.len() == 1 {
3083 if let Expression::Literal(lit) = &f.args[0] {
3084 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3085 return Ok(Expression::Cast(Box::new(Cast {
3086 this: f.args.into_iter().next().unwrap(),
3087 to: DataType::Custom {
3088 name: "TIMESTAMPNTZ".to_string(),
3089 },
3090 double_colon_syntax: false,
3091 trailing_comments: vec![],
3092 format: None,
3093 default: None,
3094 inferred_type: None,
3095 })));
3096 }
3097 }
3098 }
3099 Ok(Expression::Function(Box::new(f)))
3100 }
3101
3102 "TO_TIMESTAMP_LTZ" => {
3104 if f.args.len() == 1 {
3105 if let Expression::Literal(lit) = &f.args[0] {
3106 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3107 return Ok(Expression::Cast(Box::new(Cast {
3108 this: f.args.into_iter().next().unwrap(),
3109 to: DataType::Custom {
3110 name: "TIMESTAMPLTZ".to_string(),
3111 },
3112 double_colon_syntax: false,
3113 trailing_comments: vec![],
3114 format: None,
3115 default: None,
3116 inferred_type: None,
3117 })));
3118 }
3119 }
3120 }
3121 Ok(Expression::Function(Box::new(f)))
3122 }
3123
3124 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
3126
3127 "REPLACE" if f.args.len() == 2 => {
3129 let mut args = f.args;
3130 args.push(Expression::Literal(Box::new(
3131 crate::expressions::Literal::String(String::new()),
3132 )));
3133 Ok(Expression::Function(Box::new(Function::new(
3134 "REPLACE".to_string(),
3135 args,
3136 ))))
3137 }
3138
3139 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
3141 "ANY_VALUE".to_string(),
3142 f.args,
3143 )))),
3144
3145 "SAFE_DIVIDE" if f.args.len() == 2 => {
3147 let mut args = f.args;
3148 let x = args.remove(0);
3149 let y = args.remove(0);
3150 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3151 condition: Expression::Neq(Box::new(BinaryOp {
3152 left: y.clone(),
3153 right: Expression::number(0),
3154 left_comments: Vec::new(),
3155 operator_comments: Vec::new(),
3156 trailing_comments: Vec::new(),
3157 inferred_type: None,
3158 })),
3159 true_value: Expression::Div(Box::new(BinaryOp {
3160 left: x,
3161 right: y,
3162 left_comments: Vec::new(),
3163 operator_comments: Vec::new(),
3164 trailing_comments: Vec::new(),
3165 inferred_type: None,
3166 })),
3167 false_value: Some(Expression::Null(crate::expressions::Null)),
3168 original_name: Some("IFF".to_string()),
3169 inferred_type: None,
3170 })))
3171 }
3172
3173 "TIMESTAMP" if f.args.len() == 1 => {
3175 let arg = f.args.into_iter().next().unwrap();
3176 Ok(Expression::Cast(Box::new(Cast {
3177 this: arg,
3178 to: DataType::Custom {
3179 name: "TIMESTAMPTZ".to_string(),
3180 },
3181 trailing_comments: Vec::new(),
3182 double_colon_syntax: false,
3183 format: None,
3184 default: None,
3185 inferred_type: None,
3186 })))
3187 }
3188
3189 "TIMESTAMP" if f.args.len() == 2 => {
3191 let mut args = f.args;
3192 let value = args.remove(0);
3193 let tz = args.remove(0);
3194 Ok(Expression::Function(Box::new(Function::new(
3195 "CONVERT_TIMEZONE".to_string(),
3196 vec![
3197 tz,
3198 Expression::Cast(Box::new(Cast {
3199 this: value,
3200 to: DataType::Timestamp {
3201 precision: None,
3202 timezone: false,
3203 },
3204 trailing_comments: Vec::new(),
3205 double_colon_syntax: false,
3206 format: None,
3207 default: None,
3208 inferred_type: None,
3209 })),
3210 ],
3211 ))))
3212 }
3213
3214 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3216 "TIME_FROM_PARTS".to_string(),
3217 f.args,
3218 )))),
3219
3220 "DIV0" if f.args.len() == 2 => {
3222 let mut args = f.args;
3223 let x = args.remove(0);
3224 let y = args.remove(0);
3225 let x_expr = Self::maybe_paren(x.clone());
3227 let y_expr = Self::maybe_paren(y.clone());
3228 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3229 condition: Expression::And(Box::new(BinaryOp::new(
3230 Expression::Eq(Box::new(BinaryOp::new(
3231 y_expr.clone(),
3232 Expression::number(0),
3233 ))),
3234 Expression::Not(Box::new(crate::expressions::UnaryOp {
3235 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3236 this: x_expr.clone(),
3237 not: false,
3238 postfix_form: false,
3239 })),
3240 inferred_type: None,
3241 })),
3242 ))),
3243 true_value: Expression::number(0),
3244 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3245 original_name: Some("IFF".to_string()),
3246 inferred_type: None,
3247 })))
3248 }
3249
3250 "DIV0NULL" if f.args.len() == 2 => {
3252 let mut args = f.args;
3253 let x = args.remove(0);
3254 let y = args.remove(0);
3255 let x_expr = Self::maybe_paren(x.clone());
3256 let y_expr = Self::maybe_paren(y.clone());
3257 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3258 condition: Expression::Or(Box::new(BinaryOp::new(
3259 Expression::Eq(Box::new(BinaryOp::new(
3260 y_expr.clone(),
3261 Expression::number(0),
3262 ))),
3263 Expression::IsNull(Box::new(crate::expressions::IsNull {
3264 this: y_expr.clone(),
3265 not: false,
3266 postfix_form: false,
3267 })),
3268 ))),
3269 true_value: Expression::number(0),
3270 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3271 original_name: Some("IFF".to_string()),
3272 inferred_type: None,
3273 })))
3274 }
3275
3276 "ZEROIFNULL" if f.args.len() == 1 => {
3278 let x = f.args.into_iter().next().unwrap();
3279 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3280 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3281 this: x.clone(),
3282 not: false,
3283 postfix_form: false,
3284 })),
3285 true_value: Expression::number(0),
3286 false_value: Some(x),
3287 original_name: Some("IFF".to_string()),
3288 inferred_type: None,
3289 })))
3290 }
3291
3292 "NULLIFZERO" if f.args.len() == 1 => {
3294 let x = f.args.into_iter().next().unwrap();
3295 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3296 condition: Expression::Eq(Box::new(BinaryOp::new(
3297 x.clone(),
3298 Expression::number(0),
3299 ))),
3300 true_value: Expression::Null(crate::expressions::Null),
3301 false_value: Some(x),
3302 original_name: Some("IFF".to_string()),
3303 inferred_type: None,
3304 })))
3305 }
3306
3307 "TRY_TO_TIME" => {
3309 if f.args.len() == 1 {
3310 if let Expression::Literal(lit) = &f.args[0] {
3311 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3312 return Ok(Expression::TryCast(Box::new(Cast {
3313 this: f.args.into_iter().next().unwrap(),
3314 to: crate::expressions::DataType::Time {
3315 precision: None,
3316 timezone: false,
3317 },
3318 double_colon_syntax: false,
3319 trailing_comments: Vec::new(),
3320 format: None,
3321 default: None,
3322 inferred_type: None,
3323 })));
3324 }
3325 }
3326 }
3327 let mut args = f.args;
3329 if args.len() >= 2 {
3330 args[1] = Self::normalize_format_arg(args[1].clone());
3331 }
3332 Ok(Expression::Function(Box::new(Function::new(
3333 "TRY_TO_TIME".to_string(),
3334 args,
3335 ))))
3336 }
3337
3338 "TRY_TO_TIMESTAMP" => {
3341 if f.args.len() == 1 {
3342 if let Expression::Literal(lit) = &f.args[0] {
3343 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3344 if !Self::looks_like_epoch(s) {
3345 return Ok(Expression::TryCast(Box::new(Cast {
3346 this: f.args.into_iter().next().unwrap(),
3347 to: DataType::Timestamp {
3348 precision: None,
3349 timezone: false,
3350 },
3351 double_colon_syntax: false,
3352 trailing_comments: Vec::new(),
3353 format: None,
3354 default: None,
3355 inferred_type: None,
3356 })));
3357 }
3358 }
3359 }
3360 }
3361 let mut args = f.args;
3363 if args.len() >= 2 {
3364 args[1] = Self::normalize_format_arg(args[1].clone());
3365 }
3366 Ok(Expression::Function(Box::new(Function::new(
3367 "TRY_TO_TIMESTAMP".to_string(),
3368 args,
3369 ))))
3370 }
3371
3372 "TRY_TO_DATE" => {
3374 if f.args.len() == 1 {
3375 if let Expression::Literal(lit) = &f.args[0] {
3376 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3377 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3379 return Ok(Expression::TryCast(Box::new(Cast {
3380 this: f.args.into_iter().next().unwrap(),
3381 to: crate::expressions::DataType::Date,
3382 double_colon_syntax: false,
3383 trailing_comments: Vec::new(),
3384 format: None,
3385 default: None,
3386 inferred_type: None,
3387 })));
3388 }
3389 }
3390 }
3391 }
3392 let mut args = f.args;
3394 if args.len() >= 2 {
3395 args[1] = Self::normalize_format_arg(args[1].clone());
3396 }
3397 Ok(Expression::Function(Box::new(Function::new(
3398 "TRY_TO_DATE".to_string(),
3399 args,
3400 ))))
3401 }
3402
3403 "TRY_TO_DOUBLE" if f.args.len() == 1 => {
3406 let this = f.args.into_iter().next().unwrap();
3407 Ok(Expression::ToDouble(Box::new(
3408 crate::expressions::ToDouble {
3409 this: Box::new(this),
3410 format: None,
3411 safe: Some(Box::new(Expression::Boolean(
3412 crate::expressions::BooleanLiteral { value: true },
3413 ))),
3414 },
3415 )))
3416 }
3417 "TRY_TO_DOUBLE"
3418 if f.args.len() == 2
3419 && matches!(&f.args[1], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_))) =>
3420 {
3421 let mut args = f.args;
3422 let this = args.remove(0);
3423 let Literal::String(format) = (match args.remove(0) {
3424 Expression::Literal(lit) => *lit,
3425 _ => unreachable!(),
3426 }) else {
3427 unreachable!()
3428 };
3429 Ok(Expression::ToDouble(Box::new(
3430 crate::expressions::ToDouble {
3431 this: Box::new(this),
3432 format: Some(format),
3433 safe: Some(Box::new(Expression::Boolean(
3434 crate::expressions::BooleanLiteral { value: true },
3435 ))),
3436 },
3437 )))
3438 }
3439 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3440
3441 "REGEXP_REPLACE" if f.args.len() == 2 => {
3443 let mut args = f.args;
3444 args.push(Expression::Literal(Box::new(
3445 crate::expressions::Literal::String(String::new()),
3446 )));
3447 Ok(Expression::Function(Box::new(Function::new(
3448 "REGEXP_REPLACE".to_string(),
3449 args,
3450 ))))
3451 }
3452
3453 "LAST_DAY" if f.args.len() == 2 => {
3455 let mut args = f.args;
3456 let date = args.remove(0);
3457 let unit = args.remove(0);
3458 let unit_str = match &unit {
3459 Expression::Column(c) => c.name.name.to_uppercase(),
3460 Expression::Identifier(i) => i.name.to_uppercase(),
3461 _ => String::new(),
3462 };
3463 if unit_str == "MONTH" {
3464 Ok(Expression::Function(Box::new(Function::new(
3465 "LAST_DAY".to_string(),
3466 vec![date],
3467 ))))
3468 } else {
3469 Ok(Expression::Function(Box::new(Function::new(
3470 "LAST_DAY".to_string(),
3471 vec![date, unit],
3472 ))))
3473 }
3474 }
3475
3476 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3478 "DATE_PART".to_string(),
3479 f.args,
3480 )))),
3481
3482 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3484 let mut args = f.args;
3485 let this = args.remove(0);
3486 let expr = args.remove(0);
3487 Ok(Expression::EndsWith(Box::new(
3488 crate::expressions::BinaryFunc {
3489 original_name: None,
3490 this,
3491 expression: expr,
3492 inferred_type: None,
3493 },
3494 )))
3495 }
3496
3497 _ => Ok(Expression::Function(Box::new(f))),
3499 }
3500 }
3501
3502 fn looks_like_datetime(s: &str) -> bool {
3504 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3507 }
3508
3509 fn looks_like_epoch(s: &str) -> bool {
3511 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3512 }
3513
3514 fn maybe_paren(expr: Expression) -> Expression {
3516 match &expr {
3517 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3518 Expression::Paren(Box::new(crate::expressions::Paren {
3519 this: expr,
3520 trailing_comments: Vec::new(),
3521 }))
3522 }
3523 _ => expr,
3524 }
3525 }
3526
3527 fn normalize_snowflake_format(format: &str) -> String {
3531 let mut result = String::new();
3532 let mut cursor = crate::format_tokens::FormatTokenCursor::new(format);
3533 while let Some(ch) = cursor.peek() {
3534 if cursor.consume_prefix("\"", false) {
3536 while let Some(literal) = cursor.next_char() {
3537 if literal == '"' {
3538 break;
3539 }
3540 result.push(literal);
3541 }
3542 continue;
3543 }
3544
3545 if cursor.consume_prefix("YYYY", true) {
3547 result.push_str("yyyy");
3548 } else if cursor.consume_prefix("YY", true) {
3549 result.push_str("yy");
3550 } else if cursor.consume_prefix("MMMM", true) {
3551 result.push_str("mmmm");
3552 } else if cursor.consume_prefix("MON", true) {
3553 result.push_str("mon");
3554 } else if cursor.consume_prefix("MM", true) {
3555 result.push_str("mm");
3556 } else if cursor.consume_prefix("DD", true) {
3557 result.push_str("DD");
3558 } else if cursor.consume_prefix("DY", true) {
3559 result.push_str("dy");
3560 } else if cursor.consume_prefix("HH24", true) {
3561 result.push_str("hh24");
3562 } else if cursor.consume_prefix("HH12", true) {
3563 result.push_str("hh12");
3564 } else if cursor.consume_prefix("HH", true) {
3565 result.push_str("hh");
3566 } else if cursor.consume_prefix("MISS", true) {
3567 result.push_str("miss");
3569 } else if cursor.consume_prefix("MI", true) {
3570 result.push_str("mi");
3571 } else if cursor.consume_prefix("SS", true) {
3572 result.push_str("ss");
3573 } else if cursor.consume_prefix("FF", true) {
3574 if let Some(digit) = cursor.peek().filter(|c| c.is_ascii_digit()) {
3575 result.push_str("ff");
3576 result.push(digit);
3577 cursor.next_char();
3578 } else {
3579 result.push_str("ff9");
3581 }
3582 } else if cursor.consume_prefix("AM", true) || cursor.consume_prefix("PM", true) {
3583 result.push_str("pm");
3584 } else if cursor.consume_prefix("TZH", true) {
3585 result.push_str("tzh");
3586 } else if cursor.consume_prefix("TZM", true) {
3587 result.push_str("tzm");
3588 } else {
3589 result.push(ch);
3591 cursor.next_char();
3592 }
3593 }
3594 result
3595 }
3596
3597 fn is_temporal_expr(expr: &Expression) -> bool {
3598 match expr {
3599 Expression::CurrentDate(_)
3600 | Expression::CurrentTime(_)
3601 | Expression::CurrentTimestamp(_)
3602 | Expression::CurrentTimestampLTZ(_)
3603 | Expression::CurrentDatetime(_)
3604 | Expression::Localtime(_)
3605 | Expression::Localtimestamp(_)
3606 | Expression::Systimestamp(_)
3607 | Expression::UtcTime(_)
3608 | Expression::UtcTimestamp(_)
3609 | Expression::Date(_)
3610 | Expression::Time(_)
3611 | Expression::ToDate(_)
3612 | Expression::ToTimestamp(_)
3613 | Expression::DateStrToDate(_)
3614 | Expression::TimeStrToTime(_)
3615 | Expression::StrToTime(_) => true,
3616 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
3617 matches!(
3618 cast.to,
3619 DataType::Date | DataType::Time { .. } | DataType::Timestamp { .. }
3620 )
3621 }
3622 Expression::Paren(paren) => Self::is_temporal_expr(&paren.this),
3623 other => matches!(
3624 other.inferred_type(),
3625 Some(DataType::Date | DataType::Time { .. } | DataType::Timestamp { .. })
3626 ),
3627 }
3628 }
3629
3630 fn normalize_format_arg(expr: Expression) -> Expression {
3632 if let Expression::Literal(lit) = &expr {
3633 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3634 let normalized = Self::normalize_snowflake_format(s);
3635 Expression::Literal(Box::new(crate::expressions::Literal::String(normalized)))
3636 } else {
3637 expr.clone()
3638 }
3639 } else {
3640 expr
3641 }
3642 }
3643
3644 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3647 use crate::expressions::{DataType, LambdaExpr};
3648 use std::collections::HashMap;
3649
3650 let mut param_types: HashMap<String, DataType> = HashMap::new();
3652 for (i, param) in lambda.parameters.iter().enumerate() {
3653 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3654 param_types.insert(param.name.to_uppercase(), dt.clone());
3655 }
3656 }
3657
3658 if param_types.is_empty() {
3660 return Expression::Lambda(Box::new(lambda));
3661 }
3662
3663 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3665
3666 Expression::Lambda(Box::new(LambdaExpr {
3668 parameters: lambda.parameters,
3669 body: transformed_body,
3670 colon: lambda.colon,
3671 parameter_types: Vec::new(), }))
3673 }
3674
3675 fn replace_lambda_params_with_cast(
3677 &self,
3678 expr: Expression,
3679 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3680 ) -> Expression {
3681 use crate::expressions::{BinaryOp, Cast, Paren};
3682
3683 match expr {
3684 Expression::Column(col) if col.table.is_none() => {
3686 let name_upper = col.name.name.to_uppercase();
3687 if let Some(dt) = param_types.get(&name_upper) {
3688 Expression::Cast(Box::new(Cast {
3690 this: Expression::Column(col),
3691 to: dt.clone(),
3692 double_colon_syntax: false,
3693 trailing_comments: Vec::new(),
3694 format: None,
3695 default: None,
3696 inferred_type: None,
3697 }))
3698 } else {
3699 Expression::Column(col)
3700 }
3701 }
3702
3703 Expression::Identifier(id) => {
3705 let name_upper = id.name.to_uppercase();
3706 if let Some(dt) = param_types.get(&name_upper) {
3707 Expression::Cast(Box::new(Cast {
3709 this: Expression::Identifier(id),
3710 to: dt.clone(),
3711 double_colon_syntax: false,
3712 trailing_comments: Vec::new(),
3713 format: None,
3714 default: None,
3715 inferred_type: None,
3716 }))
3717 } else {
3718 Expression::Identifier(id)
3719 }
3720 }
3721
3722 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3724 self.replace_lambda_params_with_cast(op.left, param_types),
3725 self.replace_lambda_params_with_cast(op.right, param_types),
3726 ))),
3727 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3728 self.replace_lambda_params_with_cast(op.left, param_types),
3729 self.replace_lambda_params_with_cast(op.right, param_types),
3730 ))),
3731 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3732 self.replace_lambda_params_with_cast(op.left, param_types),
3733 self.replace_lambda_params_with_cast(op.right, param_types),
3734 ))),
3735 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3736 self.replace_lambda_params_with_cast(op.left, param_types),
3737 self.replace_lambda_params_with_cast(op.right, param_types),
3738 ))),
3739 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3740 self.replace_lambda_params_with_cast(op.left, param_types),
3741 self.replace_lambda_params_with_cast(op.right, param_types),
3742 ))),
3743
3744 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3746 this: self.replace_lambda_params_with_cast(p.this, param_types),
3747 trailing_comments: p.trailing_comments,
3748 })),
3749
3750 Expression::Function(mut f) => {
3752 f.args = f
3753 .args
3754 .into_iter()
3755 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3756 .collect();
3757 Expression::Function(f)
3758 }
3759
3760 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3762 self.replace_lambda_params_with_cast(op.left, param_types),
3763 self.replace_lambda_params_with_cast(op.right, param_types),
3764 ))),
3765 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3766 self.replace_lambda_params_with_cast(op.left, param_types),
3767 self.replace_lambda_params_with_cast(op.right, param_types),
3768 ))),
3769 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3770 self.replace_lambda_params_with_cast(op.left, param_types),
3771 self.replace_lambda_params_with_cast(op.right, param_types),
3772 ))),
3773 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3774 self.replace_lambda_params_with_cast(op.left, param_types),
3775 self.replace_lambda_params_with_cast(op.right, param_types),
3776 ))),
3777 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3778 self.replace_lambda_params_with_cast(op.left, param_types),
3779 self.replace_lambda_params_with_cast(op.right, param_types),
3780 ))),
3781 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3782 self.replace_lambda_params_with_cast(op.left, param_types),
3783 self.replace_lambda_params_with_cast(op.right, param_types),
3784 ))),
3785
3786 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3788 self.replace_lambda_params_with_cast(op.left, param_types),
3789 self.replace_lambda_params_with_cast(op.right, param_types),
3790 ))),
3791 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3792 self.replace_lambda_params_with_cast(op.left, param_types),
3793 self.replace_lambda_params_with_cast(op.right, param_types),
3794 ))),
3795
3796 other => other,
3798 }
3799 }
3800
3801 fn transform_aggregate_function(
3802 &self,
3803 f: Box<crate::expressions::AggregateFunction>,
3804 ) -> Result<Expression> {
3805 let name_upper = f.name.to_uppercase();
3806 match name_upper.as_str() {
3807 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3809 Function::new("LISTAGG".to_string(), f.args),
3810 ))),
3811
3812 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3814 Function::new("LISTAGG".to_string(), f.args),
3815 ))),
3816
3817 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3819 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3820 ))),
3821
3822 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3824 "BITAND_AGG".to_string(),
3825 f.args,
3826 )))),
3827
3828 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3830 "BITOR_AGG".to_string(),
3831 f.args,
3832 )))),
3833
3834 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3836 "BITXOR_AGG".to_string(),
3837 f.args,
3838 )))),
3839
3840 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3842 let arg = f.args.into_iter().next().unwrap();
3843 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3844 this: arg,
3845 distinct: f.distinct,
3846 filter: f.filter,
3847 order_by: Vec::new(),
3848 name: Some("BOOLAND_AGG".to_string()),
3849 ignore_nulls: None,
3850 having_max: None,
3851 limit: None,
3852 inferred_type: None,
3853 })))
3854 }
3855
3856 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3858 let arg = f.args.into_iter().next().unwrap();
3859 Ok(Expression::LogicalOr(Box::new(AggFunc {
3860 this: arg,
3861 distinct: f.distinct,
3862 filter: f.filter,
3863 order_by: Vec::new(),
3864 name: Some("BOOLOR_AGG".to_string()),
3865 ignore_nulls: None,
3866 having_max: None,
3867 limit: None,
3868 inferred_type: None,
3869 })))
3870 }
3871
3872 "APPROX_TOP_K" if f.args.len() == 1 => {
3874 let mut args = f.args;
3875 args.push(Expression::number(1));
3876 Ok(Expression::AggregateFunction(Box::new(
3877 crate::expressions::AggregateFunction {
3878 source_dialect: None,
3879
3880 name: "APPROX_TOP_K".to_string(),
3881 args,
3882 distinct: f.distinct,
3883 filter: f.filter,
3884 order_by: Vec::new(),
3885 limit: None,
3886 ignore_nulls: None,
3887 inferred_type: None,
3888 },
3889 )))
3890 }
3891
3892 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3894 let arg = f.args.into_iter().next().unwrap();
3895 Ok(Expression::Skewness(Box::new(AggFunc {
3896 this: arg,
3897 distinct: f.distinct,
3898 filter: f.filter,
3899 order_by: Vec::new(),
3900 name: Some("SKEW".to_string()),
3901 ignore_nulls: None,
3902 having_max: None,
3903 limit: None,
3904 inferred_type: None,
3905 })))
3906 }
3907
3908 _ => Ok(Expression::AggregateFunction(f)),
3910 }
3911 }
3912}
3913
3914#[cfg(feature = "transpile")]
3916fn strftime_to_snowflake_format(fmt: &str) -> String {
3917 let mut result = String::new();
3918 let chars: Vec<char> = fmt.chars().collect();
3919 let mut i = 0;
3920 while i < chars.len() {
3921 if chars[i] == '%' && i + 1 < chars.len() {
3922 match chars[i + 1] {
3923 'Y' => {
3924 result.push_str("yyyy");
3925 i += 2;
3926 }
3927 'y' => {
3928 result.push_str("yy");
3929 i += 2;
3930 }
3931 'm' => {
3932 result.push_str("mm");
3933 i += 2;
3934 }
3935 'd' => {
3936 result.push_str("DD");
3937 i += 2;
3938 }
3939 'H' => {
3940 result.push_str("hh24");
3941 i += 2;
3942 }
3943 'M' => {
3944 result.push_str("mmmm");
3945 i += 2;
3946 } 'i' => {
3948 result.push_str("mi");
3949 i += 2;
3950 }
3951 'S' | 's' => {
3952 result.push_str("ss");
3953 i += 2;
3954 }
3955 'f' => {
3956 result.push_str("ff");
3957 i += 2;
3958 }
3959 'w' => {
3960 result.push_str("dy");
3961 i += 2;
3962 } 'a' => {
3964 result.push_str("DY");
3965 i += 2;
3966 } 'b' => {
3968 result.push_str("mon");
3969 i += 2;
3970 } 'T' => {
3972 result.push_str("hh24:mi:ss");
3973 i += 2;
3974 } _ => {
3976 result.push(chars[i]);
3977 result.push(chars[i + 1]);
3978 i += 2;
3979 }
3980 }
3981 } else {
3982 result.push(chars[i]);
3983 i += 1;
3984 }
3985 }
3986 result
3987}
3988
3989#[cfg(test)]
3990mod tests {
3991 use super::*;
3992 use crate::dialects::Dialect;
3993
3994 #[test]
3995 fn test_date_time_format_normalization_preserves_unicode() {
3996 for literal in ["é", "年", "🦀", "e\u{301}", "ß", "ſ"] {
3997 assert_eq!(
3998 SnowflakeDialect::normalize_snowflake_format(literal),
3999 literal
4000 );
4001 assert_eq!(
4002 SnowflakeDialect::normalize_snowflake_format(&format!(
4003 "{literal}YYYY{literal}mM{literal}"
4004 )),
4005 format!("{literal}yyyy{literal}mm{literal}")
4006 );
4007 }
4008 for (input, expected) in [
4009 ("", ""),
4010 (
4011 "YYYY YY MMMM MON MM DD DY HH24 HH12 HH MISS MI SS AM PM TZH TZM",
4012 "yyyy yy mmmm mon mm DD dy hh24 hh12 hh miss mi ss pm pm tzh tzm",
4013 ),
4014 (
4015 "FF FF0 FF1 FF6 FF7 FF9 FF69",
4016 "ff9 ff0 ff1 ff6 ff7 ff9 ff69",
4017 ),
4018 ("éFF9年YYYY", "éff9年yyyy"),
4019 ("\"éYYYY🦀\"YYYY", "éYYYY🦀yyyy"),
4020 ("YYYY\"年", "yyyy年"),
4021 ("\"\"YYYY\"T\"HH24", "yyyyThh24"),
4022 ("q %-q %", "q %-q %"),
4023 ] {
4024 assert_eq!(
4025 SnowflakeDialect::normalize_snowflake_format(input),
4026 expected,
4027 "{input}"
4028 );
4029 }
4030 }
4031
4032 fn transpile_to_snowflake(sql: &str) -> String {
4033 let dialect = Dialect::get(DialectType::Generic);
4034 let result = dialect
4035 .transpile(sql, DialectType::Snowflake)
4036 .expect("Transpile failed");
4037 result[0].clone()
4038 }
4039
4040 #[test]
4041 fn test_ifnull_to_coalesce() {
4042 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
4043 assert!(
4044 result.contains("COALESCE"),
4045 "Expected COALESCE, got: {}",
4046 result
4047 );
4048 }
4049
4050 #[test]
4051 fn test_basic_select() {
4052 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
4053 assert!(result.contains("SELECT"));
4054 assert!(result.contains("FROM users"));
4055 }
4056
4057 #[test]
4058 fn test_extract_string_comma_syntax_remains_date_part() {
4059 assert_eq!(
4060 transpile_to_snowflake("SELECT EXTRACT('month', a)"),
4061 "SELECT DATE_PART('month', a)"
4062 );
4063 }
4064
4065 #[test]
4066 fn test_snowflake_scripting_cursor_declare_block_roundtrip() {
4067 let sql = "DECLARE
4068 emp CURSOR FOR SELECT salary FROM employees;
4069BEGIN
4070 RETURN 1;
4071END";
4072
4073 let dialect = Dialect::get(DialectType::Snowflake);
4074 let ast = dialect.parse(sql).expect("Parse failed");
4075 let output = dialect.generate(&ast[0]).expect("Generate failed");
4076
4077 assert_eq!(output, sql);
4078 }
4079
4080 #[test]
4081 fn test_snowflake_scripting_cursor_return_table_roundtrip() {
4082 let sql = "DECLARE
4083 c1 CURSOR FOR SELECT * FROM invoices;
4084BEGIN
4085 OPEN c1;
4086 RETURN TABLE(RESULTSET_FROM_CURSOR(c1));
4087END";
4088
4089 let dialect = Dialect::get(DialectType::Snowflake);
4090 let ast = dialect.parse(sql).expect("Parse failed");
4091 let output = dialect.generate(&ast[0]).expect("Generate failed");
4092
4093 assert_eq!(output, sql);
4094 }
4095
4096 #[test]
4097 fn test_group_concat_to_listagg() {
4098 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
4099 assert!(
4100 result.contains("LISTAGG"),
4101 "Expected LISTAGG, got: {}",
4102 result
4103 );
4104 }
4105
4106 #[test]
4107 fn test_string_agg_to_listagg() {
4108 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
4109 assert!(
4110 result.contains("LISTAGG"),
4111 "Expected LISTAGG, got: {}",
4112 result
4113 );
4114 }
4115
4116 #[test]
4117 fn test_array_to_array_construct() {
4118 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
4119 assert!(
4121 result.contains("[1, 2, 3]"),
4122 "Expected [1, 2, 3], got: {}",
4123 result
4124 );
4125 }
4126
4127 #[test]
4128 fn test_double_quote_identifiers() {
4129 let dialect = SnowflakeDialect;
4131 let config = dialect.generator_config();
4132 assert_eq!(config.identifier_quote, '"');
4133 }
4134}