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 this: f.this,
204 separator: f.separator,
205 on_overflow: None,
206 order_by: f.order_by,
207 distinct: f.distinct,
208 filter: f.filter,
209 inferred_type: None,
210 }))),
211
212 Expression::Cast(c) => {
216 use crate::expressions::DataType;
217 let transformed_this = self.transform_expr(c.this)?;
219 match &c.to {
220 DataType::Geography { .. } => Ok(Expression::Function(Box::new(
221 Function::new("TO_GEOGRAPHY".to_string(), vec![transformed_this]),
222 ))),
223 DataType::Geometry { .. } => Ok(Expression::Function(Box::new(Function::new(
224 "TO_GEOMETRY".to_string(),
225 vec![transformed_this],
226 )))),
227 _ => {
228 let transformed_dt = match self.transform_data_type(c.to.clone())? {
230 Expression::DataType(dt) => dt,
231 _ => c.to.clone(),
232 };
233 Ok(Expression::Cast(Box::new(Cast {
234 this: transformed_this,
235 to: transformed_dt,
236 double_colon_syntax: false, trailing_comments: c.trailing_comments,
238 format: c.format,
239 default: c.default,
240 inferred_type: None,
241 })))
242 }
243 }
244 }
245
246 Expression::TryCast(c) => {
249 let transformed_this = self.transform_expr(c.this)?;
250 Ok(Expression::TryCast(Box::new(Cast {
251 this: transformed_this,
252 to: c.to,
253 double_colon_syntax: false, trailing_comments: c.trailing_comments,
255 format: c.format,
256 default: c.default,
257 inferred_type: None,
258 })))
259 }
260
261 Expression::SafeCast(c) => {
264 let to = match c.to {
265 DataType::Timestamp { .. } => DataType::Custom {
266 name: "TIMESTAMPTZ".to_string(),
267 },
268 DataType::Custom { name } if name.eq_ignore_ascii_case("TIMESTAMP") => {
269 DataType::Custom {
270 name: "TIMESTAMPTZ".to_string(),
271 }
272 }
273 other => other,
274 };
275 let transformed_this = self.transform_expr(c.this)?;
276 Ok(Expression::Cast(Box::new(Cast {
277 this: transformed_this,
278 to,
279 double_colon_syntax: c.double_colon_syntax,
280 trailing_comments: c.trailing_comments,
281 format: c.format,
282 default: c.default,
283 inferred_type: None,
284 })))
285 }
286
287 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Timestamp(_)) => {
290 let Literal::Timestamp(s) = lit.as_ref() else {
291 unreachable!()
292 };
293 Ok(Expression::Cast(Box::new(Cast {
294 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
295 to: DataType::Timestamp {
296 precision: None,
297 timezone: false,
298 },
299 double_colon_syntax: false,
300 trailing_comments: Vec::new(),
301 format: None,
302 default: None,
303 inferred_type: None,
304 })))
305 }
306
307 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Date(_)) => {
309 let Literal::Date(s) = lit.as_ref() else {
310 unreachable!()
311 };
312 Ok(Expression::Cast(Box::new(Cast {
313 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
314 to: DataType::Date,
315 double_colon_syntax: false,
316 trailing_comments: Vec::new(),
317 format: None,
318 default: None,
319 inferred_type: None,
320 })))
321 }
322
323 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Time(_)) => {
325 let Literal::Time(s) = lit.as_ref() else {
326 unreachable!()
327 };
328 Ok(Expression::Cast(Box::new(Cast {
329 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
330 to: DataType::Time {
331 precision: None,
332 timezone: false,
333 },
334 double_colon_syntax: false,
335 trailing_comments: Vec::new(),
336 format: None,
337 default: None,
338 inferred_type: None,
339 })))
340 }
341
342 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Datetime(_)) => {
344 let Literal::Datetime(s) = lit.as_ref() else {
345 unreachable!()
346 };
347 Ok(Expression::Cast(Box::new(Cast {
348 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
349 to: DataType::Custom {
350 name: "DATETIME".to_string(),
351 },
352 double_colon_syntax: false,
353 trailing_comments: Vec::new(),
354 format: None,
355 default: None,
356 inferred_type: None,
357 })))
358 }
359
360 Expression::ILike(op) => Ok(Expression::ILike(op)),
363
364 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
367 "FLATTEN".to_string(),
368 vec![f.this],
369 )))),
370
371 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
373 "FLATTEN".to_string(),
374 vec![f.this],
375 )))),
376
377 Expression::Unnest(f) => {
379 let input_arg =
381 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
382 name: crate::expressions::Identifier::new("INPUT"),
383 value: f.this,
384 separator: crate::expressions::NamedArgSeparator::DArrow,
385 }));
386
387 let flatten = Expression::Function(Box::new(Function::new(
389 "FLATTEN".to_string(),
390 vec![input_arg],
391 )));
392
393 let table_func =
395 Expression::TableFromRows(Box::new(crate::expressions::TableFromRows {
396 this: Box::new(flatten),
397 alias: None,
398 joins: vec![],
399 pivots: None,
400 sample: None,
401 }));
402
403 Ok(Expression::Alias(Box::new(crate::expressions::Alias {
405 this: table_func,
406 alias: crate::expressions::Identifier::new("_t0"),
407 column_aliases: vec![
408 crate::expressions::Identifier::new("seq"),
409 crate::expressions::Identifier::new("key"),
410 crate::expressions::Identifier::new("path"),
411 crate::expressions::Identifier::new("index"),
412 crate::expressions::Identifier::new("value"),
413 crate::expressions::Identifier::new("this"),
414 ],
415 alias_explicit_as: false,
416 alias_keyword: None,
417 pre_alias_comments: vec![],
418 trailing_comments: vec![],
419 inferred_type: None,
420 })))
421 }
422
423 Expression::ArrayFunc(arr) => {
427 if arr.bracket_notation {
428 Ok(Expression::ArrayFunc(arr))
430 } else {
431 Ok(Expression::Function(Box::new(Function::new(
433 "ARRAY_CONSTRUCT".to_string(),
434 arr.expressions,
435 ))))
436 }
437 }
438
439 Expression::ArrayConcat(f) => Ok(Expression::Function(Box::new(Function::new(
441 "ARRAY_CAT".to_string(),
442 f.expressions,
443 )))),
444
445 Expression::ArrayConcatAgg(f) => Ok(Expression::Function(Box::new(Function::new(
447 "ARRAY_FLATTEN".to_string(),
448 vec![f.this],
449 )))),
450
451 Expression::ArrayContains(f) => Ok(Expression::Function(Box::new(Function::new(
453 "ARRAY_CONTAINS".to_string(),
454 vec![f.this, f.expression],
455 )))),
456
457 Expression::ArrayIntersect(f) => Ok(Expression::Function(Box::new(Function::new(
459 "ARRAY_INTERSECTION".to_string(),
460 f.expressions,
461 )))),
462
463 Expression::ArraySort(f) => Ok(Expression::Function(Box::new(Function::new(
465 "ARRAY_SORT".to_string(),
466 vec![f.this],
467 )))),
468
469 Expression::StringToArray(f) => {
471 let mut args = vec![*f.this];
472 if let Some(expr) = f.expression {
473 args.push(*expr);
474 }
475 Ok(Expression::Function(Box::new(Function::new(
476 "STRTOK_TO_ARRAY".to_string(),
477 args,
478 ))))
479 }
480
481 Expression::BitwiseOr(f) => Ok(Expression::Function(Box::new(Function::new(
484 "BITOR".to_string(),
485 vec![f.left, f.right],
486 )))),
487
488 Expression::BitwiseXor(f) => Ok(Expression::Function(Box::new(Function::new(
490 "BITXOR".to_string(),
491 vec![f.left, f.right],
492 )))),
493
494 Expression::BitwiseAnd(f) => Ok(Expression::Function(Box::new(Function::new(
496 "BITAND".to_string(),
497 vec![f.left, f.right],
498 )))),
499
500 Expression::BitwiseNot(f) => Ok(Expression::Function(Box::new(Function::new(
502 "BITNOT".to_string(),
503 vec![f.this],
504 )))),
505
506 Expression::BitwiseLeftShift(f) => Ok(Expression::Function(Box::new(Function::new(
508 "BITSHIFTLEFT".to_string(),
509 vec![f.left, f.right],
510 )))),
511
512 Expression::BitwiseRightShift(f) => Ok(Expression::Function(Box::new(Function::new(
514 "BITSHIFTRIGHT".to_string(),
515 vec![f.left, f.right],
516 )))),
517
518 Expression::BitwiseAndAgg(f) => Ok(Expression::Function(Box::new(Function::new(
520 "BITAND_AGG".to_string(),
521 vec![f.this],
522 )))),
523
524 Expression::BitwiseOrAgg(f) => Ok(Expression::Function(Box::new(Function::new(
526 "BITOR_AGG".to_string(),
527 vec![f.this],
528 )))),
529
530 Expression::BitwiseXorAgg(f) => Ok(Expression::Function(Box::new(Function::new(
532 "BITXOR_AGG".to_string(),
533 vec![f.this],
534 )))),
535
536 Expression::LogicalAnd(f) => Ok(Expression::Function(Box::new(Function::new(
539 "BOOLAND_AGG".to_string(),
540 vec![f.this],
541 )))),
542
543 Expression::LogicalOr(f) => Ok(Expression::Function(Box::new(Function::new(
545 "BOOLOR_AGG".to_string(),
546 vec![f.this],
547 )))),
548
549 Expression::Booland(f) => Ok(Expression::Function(Box::new(Function::new(
551 "BOOLAND".to_string(),
552 vec![*f.this, *f.expression],
553 )))),
554
555 Expression::Boolor(f) => Ok(Expression::Function(Box::new(Function::new(
557 "BOOLOR".to_string(),
558 vec![*f.this, *f.expression],
559 )))),
560
561 Expression::Xor(f) => {
563 let mut args = Vec::new();
564 if let Some(this) = f.this {
565 args.push(*this);
566 }
567 if let Some(expr) = f.expression {
568 args.push(*expr);
569 }
570 Ok(Expression::Function(Box::new(Function::new(
571 "BOOLXOR".to_string(),
572 args,
573 ))))
574 }
575
576 Expression::DayOfMonth(f) => Ok(Expression::Function(Box::new(Function::new(
579 "DAYOFMONTH".to_string(),
580 vec![f.this],
581 )))),
582
583 Expression::DayOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
585 "DAYOFWEEK".to_string(),
586 vec![f.this],
587 )))),
588
589 Expression::DayOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
591 "DAYOFWEEKISO".to_string(),
592 vec![f.this],
593 )))),
594
595 Expression::DayOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
597 "DAYOFYEAR".to_string(),
598 vec![f.this],
599 )))),
600
601 Expression::WeekOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
603 "WEEK".to_string(),
604 vec![f.this],
605 )))),
606
607 Expression::YearOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
609 "YEAROFWEEK".to_string(),
610 vec![f.this],
611 )))),
612
613 Expression::YearOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
615 "YEAROFWEEKISO".to_string(),
616 vec![f.this],
617 )))),
618
619 Expression::ByteLength(f) => Ok(Expression::Function(Box::new(Function::new(
621 "OCTET_LENGTH".to_string(),
622 vec![f.this],
623 )))),
624
625 Expression::TimestampDiff(f) => {
627 let mut args = vec![];
628 if let Some(ref unit_str) = f.unit {
630 args.push(Expression::Identifier(crate::expressions::Identifier::new(
631 unit_str.clone(),
632 )));
633 args.push(*f.this);
634 args.push(*f.expression);
635 } else {
636 args.push(*f.this);
637 args.push(*f.expression);
638 }
639 Ok(Expression::Function(Box::new(Function::new(
640 "TIMESTAMPDIFF".to_string(),
641 args,
642 ))))
643 }
644
645 Expression::TimestampAdd(f) => {
647 let mut args = vec![];
648 if let Some(ref unit_str) = f.unit {
649 args.push(Expression::Identifier(crate::expressions::Identifier::new(
650 unit_str.clone(),
651 )));
652 args.push(*f.this);
653 args.push(*f.expression);
654 } else {
655 args.push(*f.this);
656 args.push(*f.expression);
657 }
658 Ok(Expression::Function(Box::new(Function::new(
659 "TIMESTAMPADD".to_string(),
660 args,
661 ))))
662 }
663
664 Expression::ToArray(f) => Ok(Expression::Function(Box::new(Function::new(
666 "TO_ARRAY".to_string(),
667 vec![f.this],
668 )))),
669
670 Expression::DateAdd(f) => {
672 let unit_str = interval_unit_to_str(&f.unit);
673 let unit = Expression::Identifier(crate::expressions::Identifier {
674 name: unit_str,
675 quoted: false,
676 trailing_comments: Vec::new(),
677 span: None,
678 });
679 Ok(Expression::Function(Box::new(Function::new(
680 "DATEADD".to_string(),
681 vec![unit, f.interval, f.this],
682 ))))
683 }
684
685 Expression::DateSub(f) => {
687 let unit_str = interval_unit_to_str(&f.unit);
688 let unit = Expression::Identifier(crate::expressions::Identifier {
689 name: unit_str,
690 quoted: false,
691 trailing_comments: Vec::new(),
692 span: None,
693 });
694 let neg_expr = Expression::Mul(Box::new(crate::expressions::BinaryOp::new(
696 f.interval,
697 Expression::Neg(Box::new(crate::expressions::UnaryOp {
698 this: Expression::number(1),
699 inferred_type: None,
700 })),
701 )));
702 Ok(Expression::Function(Box::new(Function::new(
703 "DATEADD".to_string(),
704 vec![unit, neg_expr, f.this],
705 ))))
706 }
707
708 Expression::DateDiff(f) => {
710 let unit_str =
711 interval_unit_to_str(&f.unit.unwrap_or(crate::expressions::IntervalUnit::Day));
712 let unit = Expression::Identifier(crate::expressions::Identifier {
713 name: unit_str,
714 quoted: false,
715 trailing_comments: Vec::new(),
716 span: None,
717 });
718 Ok(Expression::Function(Box::new(Function::new(
719 "DATEDIFF".to_string(),
720 vec![unit, f.expression, f.this],
721 ))))
722 }
723
724 Expression::StringAgg(f) => {
727 let mut args = vec![f.this.clone()];
728 if let Some(separator) = &f.separator {
729 args.push(separator.clone());
730 }
731 Ok(Expression::Function(Box::new(Function::new(
732 "LISTAGG".to_string(),
733 args,
734 ))))
735 }
736
737 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
739 "STARTSWITH".to_string(),
740 vec![f.this, f.expression],
741 )))),
742
743 Expression::EndsWith(f) => Ok(Expression::EndsWith(f)),
745
746 Expression::Stuff(f) => {
748 let mut args = vec![*f.this];
749 if let Some(start) = f.start {
750 args.push(*start);
751 }
752 if let Some(length) = f.length {
753 args.push(Expression::number(length));
754 }
755 args.push(*f.expression);
756 Ok(Expression::Function(Box::new(Function::new(
757 "INSERT".to_string(),
758 args,
759 ))))
760 }
761
762 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
765 "SHA1".to_string(),
766 vec![f.this],
767 )))),
768
769 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
771 "SHA1_BINARY".to_string(),
772 vec![f.this],
773 )))),
774
775 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
777 "SHA2_BINARY".to_string(),
778 vec![*f.this],
779 )))),
780
781 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
783 "MD5_BINARY".to_string(),
784 vec![*f.this],
785 )))),
786
787 Expression::MD5NumberLower64(f) => Ok(Expression::Function(Box::new(Function::new(
789 "MD5_NUMBER_LOWER64".to_string(),
790 vec![f.this],
791 )))),
792
793 Expression::MD5NumberUpper64(f) => Ok(Expression::Function(Box::new(Function::new(
795 "MD5_NUMBER_UPPER64".to_string(),
796 vec![f.this],
797 )))),
798
799 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
802 "VECTOR_COSINE_SIMILARITY".to_string(),
803 vec![*f.this, *f.expression],
804 )))),
805
806 Expression::DotProduct(f) => Ok(Expression::Function(Box::new(Function::new(
808 "VECTOR_INNER_PRODUCT".to_string(),
809 vec![*f.this, *f.expression],
810 )))),
811
812 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
814 "VECTOR_L2_DISTANCE".to_string(),
815 vec![*f.this, *f.expression],
816 )))),
817
818 Expression::ManhattanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
820 "VECTOR_L1_DISTANCE".to_string(),
821 vec![*f.this, *f.expression],
822 )))),
823
824 Expression::JSONFormat(f) => {
827 let mut args = Vec::new();
828 if let Some(this) = f.this {
829 args.push(*this);
830 }
831 Ok(Expression::Function(Box::new(Function::new(
832 "TO_JSON".to_string(),
833 args,
834 ))))
835 }
836
837 Expression::JSONKeys(f) => Ok(Expression::Function(Box::new(Function::new(
839 "OBJECT_KEYS".to_string(),
840 vec![*f.this],
841 )))),
842
843 Expression::GetExtract(f) => Ok(Expression::Function(Box::new(Function::new(
845 "GET".to_string(),
846 vec![*f.this, *f.expression],
847 )))),
848
849 Expression::StarMap(f) => Ok(Expression::Function(Box::new(Function::new(
851 "OBJECT_CONSTRUCT".to_string(),
852 vec![f.this, f.expression],
853 )))),
854
855 Expression::LowerHex(f) => Ok(Expression::Function(Box::new(Function::new(
857 "TO_CHAR".to_string(),
858 vec![f.this],
859 )))),
860
861 Expression::Skewness(f) => Ok(Expression::Function(Box::new(Function::new(
863 "SKEW".to_string(),
864 vec![f.this],
865 )))),
866
867 Expression::StPoint(f) => Ok(Expression::Function(Box::new(Function::new(
869 "ST_MAKEPOINT".to_string(),
870 vec![*f.this, *f.expression],
871 )))),
872
873 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
875 "CONVERT_TIMEZONE".to_string(),
876 vec![*f.this],
877 )))),
878
879 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
882 "HEX_DECODE_BINARY".to_string(),
883 vec![*f.this],
884 )))),
885
886 Expression::UnixToTime(f) => {
888 let mut args = vec![*f.this];
889 if let Some(scale) = f.scale {
890 args.push(Expression::number(scale));
891 }
892 Ok(Expression::Function(Box::new(Function::new(
893 "TO_TIMESTAMP".to_string(),
894 args,
895 ))))
896 }
897
898 Expression::IfFunc(f) => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
901 condition: f.condition,
902 true_value: f.true_value,
903 false_value: Some(
904 f.false_value
905 .unwrap_or(Expression::Null(crate::expressions::Null)),
906 ),
907 original_name: Some("IFF".to_string()),
908 inferred_type: None,
909 }))),
910
911 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
914 "APPROX_COUNT_DISTINCT".to_string(),
915 vec![f.this],
916 )))),
917
918 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
920 "MAX_BY".to_string(),
921 vec![*f.this, *f.expression],
922 )))),
923
924 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
926 "MIN_BY".to_string(),
927 vec![*f.this, *f.expression],
928 )))),
929
930 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
933
934 Expression::Rand(r) => Ok(Expression::Rand(r)),
936
937 Expression::Uuid(u) => Ok(Expression::Uuid(u)),
940
941 Expression::Map(f) => Ok(Expression::Function(Box::new(Function::new(
944 "OBJECT_CONSTRUCT".to_string(),
945 f.keys
946 .into_iter()
947 .zip(f.values.into_iter())
948 .flat_map(|(k, v)| vec![k, v])
949 .collect(),
950 )))),
951
952 Expression::MapFunc(f) => Ok(Expression::Function(Box::new(Function::new(
954 "OBJECT_CONSTRUCT".to_string(),
955 f.keys
956 .into_iter()
957 .zip(f.values.into_iter())
958 .flat_map(|(k, v)| vec![k, v])
959 .collect(),
960 )))),
961
962 Expression::VarMap(f) => Ok(Expression::Function(Box::new(Function::new(
964 "OBJECT_CONSTRUCT".to_string(),
965 f.keys
966 .into_iter()
967 .zip(f.values.into_iter())
968 .flat_map(|(k, v)| vec![k, v])
969 .collect(),
970 )))),
971
972 Expression::JsonObject(f) => Ok(Expression::Function(Box::new(Function::new(
975 "OBJECT_CONSTRUCT_KEEP_NULL".to_string(),
976 f.pairs.into_iter().flat_map(|(k, v)| vec![k, v]).collect(),
977 )))),
978
979 Expression::JsonExtractScalar(f) => Ok(Expression::Function(Box::new(Function::new(
981 "JSON_EXTRACT_PATH_TEXT".to_string(),
982 vec![f.this, f.path],
983 )))),
984
985 Expression::Struct(f) => Ok(Expression::Function(Box::new(Function::new(
988 "OBJECT_CONSTRUCT".to_string(),
989 f.fields
990 .into_iter()
991 .flat_map(|(name, expr)| {
992 let key = match name {
993 Some(n) => Expression::string(n),
994 None => Expression::Null(crate::expressions::Null),
995 };
996 vec![key, expr]
997 })
998 .collect(),
999 )))),
1000
1001 Expression::JSONPathRoot(_) => Ok(Expression::Literal(Box::new(
1004 crate::expressions::Literal::String(String::new()),
1005 ))),
1006
1007 Expression::VarSamp(agg) => Ok(Expression::Variance(agg)),
1010
1011 Expression::VarPop(agg) => Ok(Expression::VarPop(agg)),
1014
1015 Expression::Extract(f) => {
1018 use crate::expressions::DateTimeField;
1019 let transformed_this = self.transform_expr(f.this)?;
1021 let field_name = match &f.field {
1022 DateTimeField::Year => "YEAR",
1023 DateTimeField::Month => "MONTH",
1024 DateTimeField::Day => "DAY",
1025 DateTimeField::Hour => "HOUR",
1026 DateTimeField::Minute => "MINUTE",
1027 DateTimeField::Second => "SECOND",
1028 DateTimeField::Millisecond => "MILLISECOND",
1029 DateTimeField::Microsecond => "MICROSECOND",
1030 DateTimeField::Week => "WEEK",
1031 DateTimeField::WeekWithModifier(m) => {
1032 return Ok(Expression::Function(Box::new(Function::new(
1033 "DATE_PART".to_string(),
1034 vec![
1035 Expression::Identifier(crate::expressions::Identifier {
1036 name: format!("WEEK({})", m),
1037 quoted: false,
1038 trailing_comments: Vec::new(),
1039 span: None,
1040 }),
1041 transformed_this,
1042 ],
1043 ))))
1044 }
1045 DateTimeField::DayOfWeek => "DAYOFWEEK",
1046 DateTimeField::DayOfYear => "DAYOFYEAR",
1047 DateTimeField::Quarter => "QUARTER",
1048 DateTimeField::Epoch => "EPOCH",
1049 DateTimeField::Timezone => "TIMEZONE",
1050 DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
1051 DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
1052 DateTimeField::Date => "DATE",
1053 DateTimeField::Time => "TIME",
1054 DateTimeField::Custom(s) => {
1055 match s.to_uppercase().as_str() {
1057 "DAYOFMONTH" => "DAY",
1058 "DOW" => "DAYOFWEEK",
1059 "DOY" => "DAYOFYEAR",
1060 "ISODOW" => "DAYOFWEEKISO",
1061 "EPOCH_SECOND" | "EPOCH_SECONDS" => "EPOCH_SECOND",
1062 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => "EPOCH_MILLISECOND",
1063 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => "EPOCH_MICROSECOND",
1064 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => "EPOCH_NANOSECOND",
1065 _ => {
1066 return {
1067 let field_ident =
1068 Expression::Identifier(crate::expressions::Identifier {
1069 name: s.to_string(),
1070 quoted: false,
1071 trailing_comments: Vec::new(),
1072 span: None,
1073 });
1074 Ok(Expression::Function(Box::new(Function::new(
1075 "DATE_PART".to_string(),
1076 vec![field_ident, transformed_this],
1077 ))))
1078 }
1079 }
1080 }
1081 }
1082 };
1083 let field_ident = Expression::Identifier(crate::expressions::Identifier {
1084 name: field_name.to_string(),
1085 quoted: false,
1086 trailing_comments: Vec::new(),
1087 span: None,
1088 });
1089 Ok(Expression::Function(Box::new(Function::new(
1090 "DATE_PART".to_string(),
1091 vec![field_ident, transformed_this],
1092 ))))
1093 }
1094
1095 Expression::Function(f) => self.transform_function(*f),
1097
1098 Expression::Sum(mut agg) => {
1100 agg.this = self.transform_expr(agg.this)?;
1101 Ok(Expression::Sum(agg))
1102 }
1103
1104 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
1106
1107 Expression::NamedArgument(na) => {
1109 let transformed_value = self.transform_expr(na.value)?;
1110 Ok(Expression::NamedArgument(Box::new(
1111 crate::expressions::NamedArgument {
1112 name: na.name,
1113 value: transformed_value,
1114 separator: na.separator,
1115 },
1116 )))
1117 }
1118
1119 Expression::CreateTable(mut ct) => {
1121 for col in &mut ct.columns {
1122 if let Expression::DataType(new_dt) =
1123 self.transform_data_type(col.data_type.clone())?
1124 {
1125 col.data_type = new_dt;
1126 }
1127 if let Some(default_expr) = col.default.take() {
1129 col.default = Some(self.transform_expr(default_expr)?);
1130 }
1131 for constraint in &mut col.constraints {
1133 if let crate::expressions::ColumnConstraint::ComputedColumn(cc) = constraint
1134 {
1135 let transformed = self.transform_expr(*cc.expression.clone())?;
1136 cc.expression = Box::new(transformed);
1137 }
1138 }
1139 }
1140
1141 if ct.table_modifier.as_deref() == Some("EXTERNAL")
1144 && !ct.with_properties.is_empty()
1145 {
1146 for (key, value) in ct.with_properties.drain(..) {
1147 let formatted = Self::format_external_table_property(&key, &value);
1148 ct.properties
1149 .push(Expression::Raw(crate::expressions::Raw { sql: formatted }));
1150 }
1151 }
1152
1153 Ok(Expression::CreateTable(ct))
1154 }
1155
1156 Expression::AlterTable(mut at) => {
1158 for action in &mut at.actions {
1159 if let crate::expressions::AlterTableAction::AddColumn { column, .. } = action {
1160 if let Expression::DataType(new_dt) =
1161 self.transform_data_type(column.data_type.clone())?
1162 {
1163 column.data_type = new_dt;
1164 }
1165 }
1166 }
1167 Ok(Expression::AlterTable(at))
1168 }
1169
1170 Expression::Table(mut t) => {
1172 if let Some(when) = t.when.take() {
1173 let transformed_expr = self.transform_expr(*when.expression)?;
1175 t.when = Some(Box::new(crate::expressions::HistoricalData {
1176 this: when.this,
1177 kind: when.kind,
1178 expression: Box::new(transformed_expr),
1179 }));
1180 }
1181 Ok(Expression::Table(t))
1182 }
1183
1184 Expression::Subscript(s) => {
1186 let transformed_this = self.transform_expr(s.this)?;
1187 let transformed_index = self.transform_expr(s.index)?;
1188 Ok(Expression::Subscript(Box::new(
1189 crate::expressions::Subscript {
1190 this: transformed_this,
1191 index: transformed_index,
1192 },
1193 )))
1194 }
1195
1196 Expression::Paren(p) => {
1198 let transformed = self.transform_expr(p.this)?;
1199 Ok(Expression::Paren(Box::new(crate::expressions::Paren {
1200 this: transformed,
1201 trailing_comments: p.trailing_comments,
1202 })))
1203 }
1204
1205 Expression::Lateral(mut lat) => {
1211 let is_flatten = match lat.this.as_ref() {
1213 Expression::Function(f) => f.name.to_uppercase() == "FLATTEN",
1214 _ => false,
1215 };
1216 if is_flatten && lat.column_aliases.is_empty() {
1217 lat.column_aliases = vec![
1219 "SEQ".to_string(),
1220 "KEY".to_string(),
1221 "PATH".to_string(),
1222 "INDEX".to_string(),
1223 "VALUE".to_string(),
1224 "THIS".to_string(),
1225 ];
1226 if lat.alias.is_none() {
1228 lat.alias = Some("_flattened".to_string());
1229 }
1230 }
1231 Ok(Expression::Lateral(lat))
1232 }
1233
1234 _ => Ok(expr),
1236 }
1237 }
1238}
1239
1240#[cfg(feature = "transpile")]
1241impl SnowflakeDialect {
1242 fn format_external_table_property(key: &str, value: &str) -> String {
1245 let lower_key = key.to_lowercase();
1246 match lower_key.as_str() {
1247 "location" => format!("LOCATION={}", value),
1248 "file_format" => {
1249 let formatted_value = Self::format_file_format_value(value);
1251 format!("FILE_FORMAT={}", formatted_value)
1252 }
1253 _ => format!("{}={}", key, value),
1254 }
1255 }
1256
1257 fn format_file_format_value(value: &str) -> String {
1261 if !value.starts_with('(') {
1262 return value.to_string();
1263 }
1264 let inner = value[1..value.len() - 1].trim();
1266 let mut result = String::from("(");
1268 let mut parts: Vec<String> = Vec::new();
1269 let tokens: Vec<&str> = inner.split_whitespace().collect();
1271 let mut i = 0;
1272 while i < tokens.len() {
1273 let token = tokens[i];
1274 if i + 2 < tokens.len() && tokens[i + 1] == "=" {
1275 let val = Self::format_property_value(tokens[i + 2]);
1277 parts.push(format!("{}={}", token, val));
1278 i += 3;
1279 } else if token.contains('=') {
1280 let eq_pos = token.find('=').unwrap();
1282 let k = &token[..eq_pos];
1283 let v = Self::format_property_value(&token[eq_pos + 1..]);
1284 parts.push(format!("{}={}", k, v));
1285 i += 1;
1286 } else {
1287 parts.push(token.to_string());
1288 i += 1;
1289 }
1290 }
1291 result.push_str(&parts.join(" "));
1292 result.push(')');
1293 result
1294 }
1295
1296 fn format_property_value(value: &str) -> String {
1298 match value.to_lowercase().as_str() {
1299 "true" => "TRUE".to_string(),
1300 "false" => "FALSE".to_string(),
1301 _ => value.to_string(),
1302 }
1303 }
1304
1305 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1307 use crate::expressions::DataType;
1308 let transformed = match dt {
1309 DataType::Text => DataType::VarChar {
1311 length: None,
1312 parenthesized_length: false,
1313 },
1314 DataType::Struct { fields, .. } => {
1316 let _ = fields; DataType::Custom {
1319 name: "OBJECT".to_string(),
1320 }
1321 }
1322 DataType::Custom { name } => {
1324 let upper_name = name.to_uppercase();
1325 match upper_name.as_str() {
1326 "NVARCHAR" | "NCHAR" | "NATIONAL CHARACTER VARYING" | "NATIONAL CHAR" => {
1328 DataType::VarChar {
1329 length: None,
1330 parenthesized_length: false,
1331 }
1332 }
1333 "STRING" => DataType::VarChar {
1335 length: None,
1336 parenthesized_length: false,
1337 },
1338 "BIGDECIMAL" => DataType::Double {
1340 precision: None,
1341 scale: None,
1342 },
1343 "NESTED" => DataType::Custom {
1345 name: "OBJECT".to_string(),
1346 },
1347 "BYTEINT" => DataType::Int {
1349 length: None,
1350 integer_spelling: false,
1351 },
1352 "CHAR VARYING" | "CHARACTER VARYING" => DataType::VarChar {
1354 length: None,
1355 parenthesized_length: false,
1356 },
1357 "SQL_DOUBLE" => DataType::Double {
1359 precision: None,
1360 scale: None,
1361 },
1362 "SQL_VARCHAR" => DataType::VarChar {
1364 length: None,
1365 parenthesized_length: false,
1366 },
1367 "TIMESTAMP_NTZ" => DataType::Custom {
1369 name: "TIMESTAMPNTZ".to_string(),
1370 },
1371 "TIMESTAMP_LTZ" => DataType::Custom {
1373 name: "TIMESTAMPLTZ".to_string(),
1374 },
1375 "TIMESTAMP_TZ" => DataType::Custom {
1377 name: "TIMESTAMPTZ".to_string(),
1378 },
1379 "NCHAR VARYING" => DataType::VarChar {
1381 length: None,
1382 parenthesized_length: false,
1383 },
1384 "NUMBER" => DataType::Decimal {
1386 precision: Some(38),
1387 scale: Some(0),
1388 },
1389 _ if name.starts_with("NUMBER(") => {
1390 let inner = &name[7..name.len() - 1]; let parts: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1394 let precision = parts.first().and_then(|p| p.parse::<u32>().ok());
1395 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1396 DataType::Decimal { precision, scale }
1397 }
1398 _ => DataType::Custom { name },
1399 }
1400 }
1401 DataType::Decimal {
1403 precision: None,
1404 scale: None,
1405 } => DataType::Decimal {
1406 precision: Some(38),
1407 scale: Some(0),
1408 },
1409 DataType::Float { .. } => DataType::Double {
1411 precision: None,
1412 scale: None,
1413 },
1414 other => other,
1416 };
1417 Ok(Expression::DataType(transformed))
1418 }
1419
1420 fn map_date_part(abbr: &str) -> Option<&'static str> {
1422 match abbr.to_uppercase().as_str() {
1423 "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some("YEAR"),
1425 "MM" | "MON" | "MONS" | "MONTHS" => Some("MONTH"),
1427 "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some("DAY"),
1429 "DAY OF WEEK" | "WEEKDAY" | "DOW" | "DW" => Some("DAYOFWEEK"),
1431 "WEEKDAY_ISO" | "DOW_ISO" | "DW_ISO" | "DAYOFWEEK_ISO" => Some("DAYOFWEEKISO"),
1432 "DAY OF YEAR" | "DOY" | "DY" => Some("DAYOFYEAR"),
1434 "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY" => Some("WEEK"),
1436 "WEEK_ISO" | "WEEKOFYEARISO" | "WEEKOFYEAR_ISO" => Some("WEEKISO"),
1437 "Q" | "QTR" | "QTRS" | "QUARTERS" => Some("QUARTER"),
1439 "H" | "HH" | "HR" | "HOURS" | "HRS" => Some("HOUR"),
1441 "MI" | "MIN" | "MINUTES" | "MINS" => Some("MINUTE"),
1443 "S" | "SEC" | "SECONDS" | "SECS" => Some("SECOND"),
1445 "MS" | "MSEC" | "MSECS" | "MSECOND" | "MSECONDS" | "MILLISEC" | "MILLISECS"
1447 | "MILLISECON" | "MILLISECONDS" => Some("MILLISECOND"),
1448 "US" | "USEC" | "USECS" | "MICROSEC" | "MICROSECS" | "USECOND" | "USECONDS"
1450 | "MICROSECONDS" => Some("MICROSECOND"),
1451 "NS" | "NSEC" | "NANOSEC" | "NSECOND" | "NSECONDS" | "NANOSECS" => Some("NANOSECOND"),
1453 "EPOCH_SECOND" | "EPOCH_SECONDS" => Some("EPOCH_SECOND"),
1455 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Some("EPOCH_MILLISECOND"),
1456 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Some("EPOCH_MICROSECOND"),
1457 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Some("EPOCH_NANOSECOND"),
1458 "TZH" => Some("TIMEZONE_HOUR"),
1460 "TZM" => Some("TIMEZONE_MINUTE"),
1461 "DEC" | "DECS" | "DECADES" => Some("DECADE"),
1463 "MIL" | "MILS" | "MILLENIA" => Some("MILLENNIUM"),
1465 "C" | "CENT" | "CENTS" | "CENTURIES" => Some("CENTURY"),
1467 _ => None,
1469 }
1470 }
1471
1472 fn transform_date_part_arg(&self, expr: Expression) -> Expression {
1474 match &expr {
1475 Expression::Literal(lit)
1477 if matches!(lit.as_ref(), crate::expressions::Literal::String(_)) =>
1478 {
1479 let crate::expressions::Literal::String(s) = lit.as_ref() else {
1480 unreachable!()
1481 };
1482 Expression::Identifier(crate::expressions::Identifier {
1483 name: s.clone(),
1484 quoted: false,
1485 trailing_comments: Vec::new(),
1486 span: None,
1487 })
1488 }
1489 Expression::Identifier(id) => {
1491 if let Some(canonical) = Self::map_date_part(&id.name) {
1492 Expression::Identifier(crate::expressions::Identifier {
1493 name: canonical.to_string(),
1494 quoted: false,
1495 trailing_comments: Vec::new(),
1496 span: None,
1497 })
1498 } else {
1499 expr
1501 }
1502 }
1503 Expression::Var(v) => {
1504 if let Some(canonical) = Self::map_date_part(&v.this) {
1505 Expression::Identifier(crate::expressions::Identifier {
1506 name: canonical.to_string(),
1507 quoted: false,
1508 trailing_comments: Vec::new(),
1509 span: None,
1510 })
1511 } else {
1512 expr
1513 }
1514 }
1515 Expression::Column(col) if col.table.is_none() => {
1517 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1518 Expression::Identifier(crate::expressions::Identifier {
1519 name: canonical.to_string(),
1520 quoted: false,
1521 trailing_comments: Vec::new(),
1522 span: None,
1523 })
1524 } else {
1525 expr
1527 }
1528 }
1529 _ => expr,
1530 }
1531 }
1532
1533 fn transform_date_part_arg_identifiers_only(&self, expr: Expression) -> Expression {
1536 match &expr {
1537 Expression::Identifier(id) => {
1538 if let Some(canonical) = Self::map_date_part(&id.name) {
1539 Expression::Identifier(crate::expressions::Identifier {
1540 name: canonical.to_string(),
1541 quoted: false,
1542 trailing_comments: Vec::new(),
1543 span: None,
1544 })
1545 } else {
1546 expr
1547 }
1548 }
1549 Expression::Var(v) => {
1550 if let Some(canonical) = Self::map_date_part(&v.this) {
1551 Expression::Identifier(crate::expressions::Identifier {
1552 name: canonical.to_string(),
1553 quoted: false,
1554 trailing_comments: Vec::new(),
1555 span: None,
1556 })
1557 } else {
1558 expr
1559 }
1560 }
1561 Expression::Column(col) if col.table.is_none() => {
1562 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1563 Expression::Identifier(crate::expressions::Identifier {
1564 name: canonical.to_string(),
1565 quoted: false,
1566 trailing_comments: Vec::new(),
1567 span: None,
1568 })
1569 } else {
1570 expr
1571 }
1572 }
1573 _ => expr,
1574 }
1575 }
1576
1577 fn transform_json_path(path: &str) -> String {
1581 fn is_safe_identifier(s: &str) -> bool {
1584 if s.is_empty() {
1585 return false;
1586 }
1587 let mut chars = s.chars();
1588 match chars.next() {
1589 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
1590 _ => return false,
1591 }
1592 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
1593 }
1594
1595 if !path.contains('.') && !path.contains('[') && !path.contains(':') {
1598 if is_safe_identifier(path) {
1599 return path.to_string();
1600 } else {
1601 return format!("[\"{}\"]", path);
1603 }
1604 }
1605
1606 let result = path.replace(':', ".");
1609 result
1610 }
1611
1612 fn transform_interval(&self, interval: crate::expressions::Interval) -> Result<Expression> {
1614 use crate::expressions::{Interval, Literal};
1615
1616 fn expand_unit(abbr: &str) -> &'static str {
1618 match abbr.to_uppercase().as_str() {
1619 "D" => "DAY",
1620 "H" => "HOUR",
1621 "M" => "MINUTE",
1622 "MS" => "MILLISECOND",
1623 "NS" => "NANOSECOND",
1624 "Q" => "QUARTER",
1625 "S" => "SECOND",
1626 "US" => "MICROSECOND",
1627 "W" => "WEEK",
1628 "Y" => "YEAR",
1629 "WEEK" | "WEEKS" => "WEEK",
1631 "DAY" | "DAYS" => "DAY",
1632 "HOUR" | "HOURS" => "HOUR",
1633 "MINUTE" | "MINUTES" => "MINUTE",
1634 "SECOND" | "SECONDS" => "SECOND",
1635 "MONTH" | "MONTHS" => "MONTH",
1636 "YEAR" | "YEARS" => "YEAR",
1637 "QUARTER" | "QUARTERS" => "QUARTER",
1638 "MILLISECOND" | "MILLISECONDS" => "MILLISECOND",
1639 "MICROSECOND" | "MICROSECONDS" => "MICROSECOND",
1640 "NANOSECOND" | "NANOSECONDS" => "NANOSECOND",
1641 _ => "", }
1643 }
1644
1645 fn parse_interval_string(s: &str) -> Option<(&str, &str)> {
1647 let s = s.trim();
1648
1649 let mut num_end = 0;
1652 let mut chars = s.chars().peekable();
1653
1654 if chars.peek() == Some(&'-') {
1656 chars.next();
1657 num_end += 1;
1658 }
1659
1660 while let Some(&c) = chars.peek() {
1662 if c.is_ascii_digit() {
1663 chars.next();
1664 num_end += 1;
1665 } else {
1666 break;
1667 }
1668 }
1669
1670 if chars.peek() == Some(&'.') {
1672 chars.next();
1673 num_end += 1;
1674 while let Some(&c) = chars.peek() {
1675 if c.is_ascii_digit() {
1676 chars.next();
1677 num_end += 1;
1678 } else {
1679 break;
1680 }
1681 }
1682 }
1683
1684 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1685 return None; }
1687
1688 let value = &s[..num_end];
1689 let rest = s[num_end..].trim();
1690
1691 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1693 return None;
1694 }
1695
1696 Some((value, rest))
1697 }
1698
1699 if let Some(Expression::Literal(ref lit)) = interval.this {
1701 if let Literal::String(ref s) = lit.as_ref() {
1702 if let Some((value, unit)) = parse_interval_string(s) {
1703 let expanded = expand_unit(unit);
1704 if !expanded.is_empty() {
1705 let new_value = format!("{} {}", value, expanded);
1707
1708 return Ok(Expression::Interval(Box::new(Interval {
1709 this: Some(Expression::Literal(Box::new(Literal::String(new_value)))),
1710 unit: None, })));
1712 }
1713 }
1714 }
1715 }
1716
1717 Ok(Expression::Interval(Box::new(interval)))
1719 }
1720
1721 fn transform_function(&self, f: Function) -> Result<Expression> {
1722 let transformed_args: Vec<Expression> = f
1724 .args
1725 .into_iter()
1726 .map(|arg| self.transform_expr(arg))
1727 .collect::<Result<Vec<_>>>()?;
1728
1729 let f = Function {
1730 name: f.name,
1731 args: transformed_args,
1732 distinct: f.distinct,
1733 trailing_comments: f.trailing_comments,
1734 use_bracket_syntax: f.use_bracket_syntax,
1735 no_parens: f.no_parens,
1736 quoted: f.quoted,
1737 span: None,
1738 inferred_type: None,
1739 };
1740
1741 let name_upper = f.name.to_uppercase();
1742 match name_upper.as_str() {
1743 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1745 original_name: None,
1746 expressions: f.args,
1747 inferred_type: None,
1748 }))),
1749
1750 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1752 original_name: None,
1753 expressions: f.args,
1754 inferred_type: None,
1755 }))),
1756
1757 "NVL2" => Ok(Expression::Function(Box::new(f))),
1759
1760 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1762 Function::new("LISTAGG".to_string(), f.args),
1763 ))),
1764
1765 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1767 Function::new("LISTAGG".to_string(), f.args),
1768 ))),
1769
1770 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1772 "SUBSTRING".to_string(),
1773 f.args,
1774 )))),
1775
1776 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
1778 "FLATTEN".to_string(),
1779 f.args,
1780 )))),
1781
1782 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1784 "FLATTEN".to_string(),
1785 f.args,
1786 )))),
1787
1788 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1790
1791 "NOW" => Ok(Expression::Function(Box::new(Function {
1793 name: "CURRENT_TIMESTAMP".to_string(),
1794 args: f.args,
1795 distinct: false,
1796 trailing_comments: Vec::new(),
1797 use_bracket_syntax: false,
1798 no_parens: f.no_parens,
1799 quoted: false,
1800 span: None,
1801 inferred_type: None,
1802 }))),
1803
1804 "GETDATE" => Ok(Expression::Function(Box::new(Function {
1806 name: "CURRENT_TIMESTAMP".to_string(),
1807 args: f.args,
1808 distinct: false,
1809 trailing_comments: Vec::new(),
1810 use_bracket_syntax: false,
1811 no_parens: f.no_parens,
1812 quoted: false,
1813 span: None,
1814 inferred_type: None,
1815 }))),
1816
1817 "CURRENT_TIMESTAMP" if f.args.is_empty() => {
1821 Ok(Expression::Function(Box::new(Function {
1822 name: "CURRENT_TIMESTAMP".to_string(),
1823 args: Vec::new(),
1824 distinct: false,
1825 trailing_comments: Vec::new(),
1826 use_bracket_syntax: false,
1827 no_parens: false, quoted: false,
1829 span: None,
1830 inferred_type: None,
1831 })))
1832 }
1833
1834 "TO_DATE" => {
1838 if f.args.len() == 1 {
1839 if let Expression::Literal(lit) = &f.args[0] {
1840 if let crate::expressions::Literal::String(s) = lit.as_ref() {
1841 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
1843 return Ok(Expression::Cast(Box::new(Cast {
1844 this: f.args.into_iter().next().unwrap(),
1845 to: crate::expressions::DataType::Date,
1846 double_colon_syntax: false,
1847 trailing_comments: Vec::new(),
1848 format: None,
1849 default: None,
1850 inferred_type: None,
1851 })));
1852 }
1853 }
1854 }
1855 }
1856 let mut args = f.args;
1858 if args.len() >= 2 {
1859 args[1] = Self::normalize_format_arg(args[1].clone());
1860 }
1861 Ok(Expression::Function(Box::new(Function::new(
1862 "TO_DATE".to_string(),
1863 args,
1864 ))))
1865 }
1866
1867 "TO_TIME" => {
1869 if f.args.len() == 1 {
1870 if let Expression::Literal(lit) = &f.args[0] {
1871 if let crate::expressions::Literal::String(_) = lit.as_ref() {
1872 return Ok(Expression::Cast(Box::new(Cast {
1873 this: f.args.into_iter().next().unwrap(),
1874 to: crate::expressions::DataType::Time {
1875 precision: None,
1876 timezone: false,
1877 },
1878 double_colon_syntax: false,
1879 trailing_comments: Vec::new(),
1880 format: None,
1881 default: None,
1882 inferred_type: None,
1883 })));
1884 }
1885 }
1886 }
1887 let mut args = f.args;
1889 if args.len() >= 2 {
1890 args[1] = Self::normalize_format_arg(args[1].clone());
1891 }
1892 Ok(Expression::Function(Box::new(Function::new(
1893 "TO_TIME".to_string(),
1894 args,
1895 ))))
1896 }
1897
1898 "TO_TIMESTAMP" => {
1905 let args = f.args;
1906 if args.len() == 1 {
1907 let arg = &args[0];
1908 match arg {
1909 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_datetime(s)) =>
1910 {
1911 let Literal::String(_) = lit.as_ref() else {
1912 unreachable!()
1913 };
1914 return Ok(Expression::Cast(Box::new(Cast {
1916 this: args.into_iter().next().unwrap(),
1917 to: DataType::Timestamp {
1918 precision: None,
1919 timezone: false,
1920 },
1921 double_colon_syntax: false,
1922 trailing_comments: vec![],
1923 format: None,
1924 default: None,
1925 inferred_type: None,
1926 })));
1927 }
1928 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_epoch(s)) =>
1929 {
1930 let Literal::String(_) = lit.as_ref() else {
1931 unreachable!()
1932 };
1933 return Ok(Expression::UnixToTime(Box::new(
1935 crate::expressions::UnixToTime {
1936 this: Box::new(args.into_iter().next().unwrap()),
1937 scale: None,
1938 zone: None,
1939 hours: None,
1940 minutes: None,
1941 format: None,
1942 target_type: None,
1943 },
1944 )));
1945 }
1946 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1947 return Ok(Expression::UnixToTime(Box::new(
1949 crate::expressions::UnixToTime {
1950 this: Box::new(args.into_iter().next().unwrap()),
1951 scale: None,
1952 zone: None,
1953 hours: None,
1954 minutes: None,
1955 format: None,
1956 target_type: None,
1957 },
1958 )));
1959 }
1960 Expression::Neg(_) => {
1961 return Ok(Expression::UnixToTime(Box::new(
1963 crate::expressions::UnixToTime {
1964 this: Box::new(args.into_iter().next().unwrap()),
1965 scale: None,
1966 zone: None,
1967 hours: None,
1968 minutes: None,
1969 format: None,
1970 target_type: None,
1971 },
1972 )));
1973 }
1974 _ => {
1975 return Ok(Expression::Function(Box::new(Function::new(
1977 "TO_TIMESTAMP".to_string(),
1978 args,
1979 ))));
1980 }
1981 }
1982 } else if args.len() == 2 {
1983 let second_arg = &args[1];
1984 let is_int_scale = match second_arg {
1986 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1987 let Literal::Number(n) = lit.as_ref() else {
1988 unreachable!()
1989 };
1990 n.parse::<i64>().is_ok()
1991 }
1992 _ => false,
1993 };
1994
1995 if is_int_scale {
1996 let mut args_iter = args.into_iter();
1998 let value = args_iter.next().unwrap();
1999 let scale_expr = args_iter.next().unwrap();
2000 let scale = if let Expression::Literal(lit) = &scale_expr {
2001 if let Literal::Number(n) = lit.as_ref() {
2002 n.parse::<i64>().ok()
2003 } else {
2004 None
2005 }
2006 } else {
2007 None
2008 };
2009 return Ok(Expression::UnixToTime(Box::new(
2010 crate::expressions::UnixToTime {
2011 this: Box::new(value),
2012 scale,
2013 zone: None,
2014 hours: None,
2015 minutes: None,
2016 format: None,
2017 target_type: None,
2018 },
2019 )));
2020 } else {
2021 let mut args_iter = args.into_iter();
2023 let value = args_iter.next().unwrap();
2024 let format_expr = args_iter.next().unwrap();
2025 let format_str = match &format_expr {
2026 Expression::Literal(lit)
2027 if matches!(lit.as_ref(), Literal::String(_)) =>
2028 {
2029 let Literal::String(s) = lit.as_ref() else {
2030 unreachable!()
2031 };
2032 s.clone()
2033 }
2034 _ => {
2035 return Ok(Expression::Function(Box::new(Function::new(
2037 "TO_TIMESTAMP".to_string(),
2038 vec![value, format_expr],
2039 ))));
2040 }
2041 };
2042 let normalized_format = Self::normalize_snowflake_format(&format_str);
2044 return Ok(Expression::StrToTime(Box::new(
2045 crate::expressions::StrToTime {
2046 this: Box::new(value),
2047 format: normalized_format,
2048 zone: None,
2049 safe: None,
2050 target_type: None,
2051 },
2052 )));
2053 }
2054 }
2055 Ok(Expression::Function(Box::new(Function::new(
2057 "TO_TIMESTAMP".to_string(),
2058 args,
2059 ))))
2060 }
2061
2062 "TO_CHAR"
2065 if f.args.len() == 2
2066 && Self::is_temporal_expr(&f.args[0])
2067 && matches!(&f.args[1], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_))) =>
2068 {
2069 let mut args = f.args;
2070 let this = args.remove(0);
2071 let Literal::String(format) = (match args.remove(0) {
2072 Expression::Literal(lit) => *lit,
2073 _ => unreachable!(),
2074 }) else {
2075 unreachable!()
2076 };
2077
2078 Ok(Expression::TimeToStr(Box::new(
2079 crate::expressions::TimeToStr {
2080 this: Box::new(this),
2081 format: Self::normalize_snowflake_format(&format),
2082 culture: None,
2083 zone: None,
2084 },
2085 )))
2086 }
2087
2088 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
2090
2091 "ROUND"
2094 if f.args
2095 .iter()
2096 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
2097 {
2098 let mut expr_val = None;
2099 let mut scale_val = None;
2100 let mut rounding_mode_val = None;
2101 for arg in &f.args {
2102 if let Expression::NamedArgument(na) = arg {
2103 match na.name.name.to_uppercase().as_str() {
2104 "EXPR" => expr_val = Some(na.value.clone()),
2105 "SCALE" => scale_val = Some(na.value.clone()),
2106 "ROUNDING_MODE" => rounding_mode_val = Some(na.value.clone()),
2107 _ => {}
2108 }
2109 }
2110 }
2111 if let Some(expr) = expr_val {
2112 let mut args = vec![expr];
2113 if let Some(scale) = scale_val {
2114 args.push(scale);
2115 }
2116 if let Some(mode) = rounding_mode_val {
2117 args.push(mode);
2118 }
2119 Ok(Expression::Function(Box::new(Function::new(
2120 "ROUND".to_string(),
2121 args,
2122 ))))
2123 } else {
2124 Ok(Expression::Function(Box::new(f)))
2125 }
2126 }
2127
2128 "DATE_FORMAT" => {
2131 let mut args = f.args;
2132 if !args.is_empty() {
2134 if matches!(&args[0], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)))
2135 {
2136 args[0] = Expression::Cast(Box::new(crate::expressions::Cast {
2137 this: args[0].clone(),
2138 to: DataType::Timestamp {
2139 precision: None,
2140 timezone: false,
2141 },
2142 trailing_comments: Vec::new(),
2143 double_colon_syntax: false,
2144 format: None,
2145 default: None,
2146 inferred_type: None,
2147 }));
2148 }
2149 }
2150 if args.len() >= 2 {
2152 if let Expression::Literal(ref lit) = args[1] {
2153 if let Literal::String(ref fmt) = lit.as_ref() {
2154 let sf_fmt = strftime_to_snowflake_format(fmt);
2155 args[1] = Expression::Literal(Box::new(Literal::String(sf_fmt)));
2156 }
2157 }
2158 }
2159 Ok(Expression::Function(Box::new(Function::new(
2160 "TO_CHAR".to_string(),
2161 args,
2162 ))))
2163 }
2164
2165 "ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2167 "ARRAY_CONSTRUCT".to_string(),
2168 f.args,
2169 )))),
2170
2171 "STRUCT" => {
2174 let mut oc_args = Vec::new();
2175 for arg in f.args {
2176 match arg {
2177 Expression::Alias(a) => {
2178 oc_args.push(Expression::Literal(Box::new(
2180 crate::expressions::Literal::String(a.alias.name.clone()),
2181 )));
2182 oc_args.push(a.this);
2183 }
2184 other => {
2185 oc_args.push(other);
2187 }
2188 }
2189 }
2190 Ok(Expression::Function(Box::new(Function::new(
2191 "OBJECT_CONSTRUCT".to_string(),
2192 oc_args,
2193 ))))
2194 }
2195
2196 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2198 "GET_PATH".to_string(),
2199 f.args,
2200 )))),
2201
2202 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2204 "JSON_EXTRACT_PATH_TEXT".to_string(),
2205 f.args,
2206 )))),
2207
2208 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2210 f.args.into_iter().next().unwrap(),
2211 )))),
2212
2213 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2215 this: f.args.into_iter().next().unwrap(),
2216 decimals: None,
2217 to: None,
2218 }))),
2219
2220 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2222
2223 "SPLIT" => Ok(Expression::Function(Box::new(f))),
2225
2226 "ARRAY_AGG" => Ok(Expression::Function(Box::new(f))),
2228
2229 "JSON_PARSE" | "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2231 "PARSE_JSON".to_string(),
2232 f.args,
2233 )))),
2234
2235 "RAND" => {
2237 let seed = f.args.first().cloned().map(Box::new);
2238 Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2239 seed,
2240 lower: None,
2241 upper: None,
2242 })))
2243 }
2244
2245 "SHA" => Ok(Expression::Function(Box::new(Function::new(
2247 "SHA1".to_string(),
2248 f.args,
2249 )))),
2250
2251 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
2253 "APPROX_COUNT_DISTINCT".to_string(),
2254 f.args,
2255 )))),
2256
2257 "GEN_RANDOM_UUID" | "UUID" => {
2259 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2260 this: None,
2261 name: None,
2262 is_string: None,
2263 })))
2264 }
2265
2266 "NEWID" => Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2268 this: None,
2269 name: None,
2270 is_string: None,
2271 }))),
2272
2273 "UUID_STRING" => {
2275 if f.args.is_empty() {
2276 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2277 this: None,
2278 name: None,
2279 is_string: None,
2280 })))
2281 } else {
2282 Ok(Expression::Function(Box::new(Function::new(
2283 "UUID_STRING".to_string(),
2284 f.args,
2285 ))))
2286 }
2287 }
2288
2289 "IF" if f.args.len() >= 2 => {
2291 let mut args = f.args;
2292 let condition = args.remove(0);
2293 let true_val = args.remove(0);
2294 let false_val = if !args.is_empty() {
2295 Some(args.remove(0))
2296 } else {
2297 None
2298 };
2299 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2300 condition,
2301 true_value: true_val,
2302 false_value: Some(
2303 false_val.unwrap_or(Expression::Null(crate::expressions::Null)),
2304 ),
2305 original_name: Some("IFF".to_string()),
2306 inferred_type: None,
2307 })))
2308 }
2309
2310 "SQUARE" if f.args.len() == 1 => {
2312 let x = f.args.into_iter().next().unwrap();
2313 Ok(Expression::Power(Box::new(
2314 crate::expressions::BinaryFunc {
2315 original_name: None,
2316 this: x,
2317 expression: Expression::number(2),
2318 inferred_type: None,
2319 },
2320 )))
2321 }
2322
2323 "POW" if f.args.len() == 2 => {
2325 let mut args = f.args.into_iter();
2326 let x = args.next().unwrap();
2327 let y = args.next().unwrap();
2328 Ok(Expression::Power(Box::new(
2329 crate::expressions::BinaryFunc {
2330 original_name: None,
2331 this: x,
2332 expression: y,
2333 inferred_type: None,
2334 },
2335 )))
2336 }
2337
2338 "MOD" if f.args.len() == 2 => {
2340 let mut args = f.args.into_iter();
2341 let x = args.next().unwrap();
2342 let y = args.next().unwrap();
2343 Ok(Expression::Mod(Box::new(crate::expressions::BinaryOp {
2344 left: x,
2345 right: y,
2346 left_comments: Vec::new(),
2347 operator_comments: Vec::new(),
2348 trailing_comments: Vec::new(),
2349 inferred_type: None,
2350 })))
2351 }
2352
2353 "APPROXIMATE_JACCARD_INDEX" => Ok(Expression::Function(Box::new(Function::new(
2355 "APPROXIMATE_SIMILARITY".to_string(),
2356 f.args,
2357 )))),
2358
2359 "ARRAY_CONSTRUCT" => Ok(Expression::ArrayFunc(Box::new(
2361 crate::expressions::ArrayConstructor {
2362 expressions: f.args,
2363 bracket_notation: true,
2364 use_list_keyword: false,
2365 inferred_type: None,
2366 },
2367 ))),
2368
2369 "APPROX_TOP_K" if f.args.len() == 1 => {
2371 let mut args = f.args;
2372 args.push(Expression::number(1));
2373 Ok(Expression::Function(Box::new(Function::new(
2374 "APPROX_TOP_K".to_string(),
2375 args,
2376 ))))
2377 }
2378
2379 "TO_DECIMAL" | "TO_NUMERIC" => Ok(Expression::Function(Box::new(Function::new(
2381 "TO_NUMBER".to_string(),
2382 f.args,
2383 )))),
2384
2385 "TRY_TO_DECIMAL" | "TRY_TO_NUMERIC" => Ok(Expression::Function(Box::new(
2387 Function::new("TRY_TO_NUMBER".to_string(), f.args),
2388 ))),
2389
2390 "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2392 "STDDEV".to_string(),
2393 f.args,
2394 )))),
2395
2396 "STRTOK" if f.args.len() >= 1 => {
2398 let mut args = f.args;
2399 if args.len() == 1 {
2401 args.push(Expression::string(" ".to_string()));
2402 }
2403 if args.len() == 2 {
2405 args.push(Expression::number(1));
2406 }
2407 Ok(Expression::Function(Box::new(Function::new(
2408 "STRTOK".to_string(),
2409 args,
2410 ))))
2411 }
2412
2413 "STRTOK_TO_ARRAY" if f.args.len() == 1 => {
2414 let mut args = f.args;
2415 args.push(Expression::string(" ".to_string()));
2416 Ok(Expression::Function(Box::new(Function::new(
2417 "STRTOK_TO_ARRAY".to_string(),
2418 args,
2419 ))))
2420 }
2421
2422 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2424 "WEEK".to_string(),
2425 f.args,
2426 )))),
2427
2428 "LIKE" if f.args.len() >= 2 => {
2430 let mut args = f.args.into_iter();
2431 let left = args.next().unwrap();
2432 let right = args.next().unwrap();
2433 let escape = args.next();
2434 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2435 left,
2436 right,
2437 escape,
2438 quantifier: None,
2439 inferred_type: None,
2440 })))
2441 }
2442
2443 "ILIKE" if f.args.len() >= 2 => {
2445 let mut args = f.args.into_iter();
2446 let left = args.next().unwrap();
2447 let right = args.next().unwrap();
2448 let escape = args.next();
2449 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2450 left,
2451 right,
2452 escape,
2453 quantifier: None,
2454 inferred_type: None,
2455 })))
2456 }
2457
2458 "RLIKE" if f.args.len() >= 2 => {
2460 let mut args = f.args.into_iter();
2461 let left = args.next().unwrap();
2462 let pattern = args.next().unwrap();
2463 let flags = args.next();
2464 Ok(Expression::RegexpLike(Box::new(
2465 crate::expressions::RegexpFunc {
2466 this: left,
2467 pattern,
2468 flags,
2469 },
2470 )))
2471 }
2472
2473 "IFF" if f.args.len() >= 2 => {
2475 let mut args = f.args;
2476 let condition = args.remove(0);
2477 let true_value = args.remove(0);
2478 let false_value = if !args.is_empty() {
2479 Some(args.remove(0))
2480 } else {
2481 None
2482 };
2483 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2484 condition,
2485 true_value,
2486 false_value,
2487 original_name: Some("IFF".to_string()),
2488 inferred_type: None,
2489 })))
2490 }
2491
2492 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2494 Ok(Expression::Function(Box::new(Function::new(
2495 "TIMESTAMP_FROM_PARTS".to_string(),
2496 f.args,
2497 ))))
2498 }
2499
2500 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2502 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2503 f.args,
2504 )))),
2505
2506 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2508 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2509 f.args,
2510 )))),
2511
2512 "DATEADD" if f.args.len() >= 1 => {
2514 let mut args = f.args;
2515 args[0] = self.transform_date_part_arg(args[0].clone());
2516 Ok(Expression::Function(Box::new(Function::new(
2517 "DATEADD".to_string(),
2518 args,
2519 ))))
2520 }
2521
2522 "DATEDIFF" if f.args.len() >= 1 => {
2525 let mut args = f.args;
2526 args[0] = self.transform_date_part_arg(args[0].clone());
2527 for i in 1..args.len() {
2530 if let Expression::Function(ref func) = args[i] {
2531 if func.name == "_POLYGLOT_TO_DATE" {
2532 let inner_args = func.args.clone();
2533 args[i] = Expression::Function(Box::new(Function::new(
2534 "TO_DATE".to_string(),
2535 inner_args,
2536 )));
2537 }
2538 }
2539 }
2540 Ok(Expression::Function(Box::new(Function::new(
2541 "DATEDIFF".to_string(),
2542 args,
2543 ))))
2544 }
2545
2546 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2548 "DATEDIFF".to_string(),
2549 f.args,
2550 )))),
2551
2552 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2554 "DATEDIFF".to_string(),
2555 f.args,
2556 )))),
2557
2558 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2560 "DATEADD".to_string(),
2561 f.args,
2562 )))),
2563
2564 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2566
2567 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2569 "DATE_FROM_PARTS".to_string(),
2570 f.args,
2571 )))),
2572
2573 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2575 "TIME_FROM_PARTS".to_string(),
2576 f.args,
2577 )))),
2578
2579 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2581
2582 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2584
2585 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2587
2588 "MONTHNAME" if f.args.len() == 1 => {
2591 let arg = f.args.into_iter().next().unwrap();
2592 Ok(Expression::Monthname(Box::new(
2593 crate::expressions::Monthname {
2594 this: Box::new(arg),
2595 abbreviated: Some(Box::new(Expression::Literal(Box::new(
2596 Literal::String("true".to_string()),
2597 )))),
2598 },
2599 )))
2600 }
2601
2602 "DAYNAME" if f.args.len() == 1 => {
2605 let arg = f.args.into_iter().next().unwrap();
2606 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2607 this: Box::new(arg),
2608 abbreviated: Some(Box::new(Expression::Literal(Box::new(Literal::String(
2609 "true".to_string(),
2610 ))))),
2611 })))
2612 }
2613
2614 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2616 let arg = f.args.into_iter().next().unwrap();
2617 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2618 this: arg,
2619 distinct: false,
2620 filter: None,
2621 order_by: Vec::new(),
2622 name: Some("BOOLAND_AGG".to_string()),
2623 ignore_nulls: None,
2624 having_max: None,
2625 limit: None,
2626 inferred_type: None,
2627 })))
2628 }
2629
2630 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2632 let arg = f.args.into_iter().next().unwrap();
2633 Ok(Expression::LogicalOr(Box::new(AggFunc {
2634 this: arg,
2635 distinct: false,
2636 filter: None,
2637 order_by: Vec::new(),
2638 name: Some("BOOLOR_AGG".to_string()),
2639 ignore_nulls: None,
2640 having_max: None,
2641 limit: None,
2642 inferred_type: None,
2643 })))
2644 }
2645
2646 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2648 let arg = f.args.into_iter().next().unwrap();
2649 Ok(Expression::Skewness(Box::new(AggFunc {
2650 this: arg,
2651 distinct: false,
2652 filter: None,
2653 order_by: Vec::new(),
2654 name: Some("SKEW".to_string()),
2655 ignore_nulls: None,
2656 having_max: None,
2657 limit: None,
2658 inferred_type: None,
2659 })))
2660 }
2661
2662 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2664 "VARIANCE".to_string(),
2665 f.args,
2666 )))),
2667
2668 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2670 "VARIANCE_POP".to_string(),
2671 f.args,
2672 )))),
2673
2674 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2676 "TO_DATE".to_string(),
2677 f.args,
2678 )))),
2679 "DATE" if f.args.len() >= 2 => {
2683 let mut args = f.args;
2684 args[1] = Self::normalize_format_arg(args[1].clone());
2685 Ok(Expression::Function(Box::new(Function::new(
2686 "TO_DATE".to_string(),
2687 args,
2688 ))))
2689 }
2690 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2693 let mut args = f.args;
2694 args[1] = Self::normalize_format_arg(args[1].clone());
2695 Ok(Expression::Function(Box::new(Function::new(
2696 "DATE".to_string(),
2697 args,
2698 ))))
2699 }
2700
2701 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2703
2704 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2706 "MD5".to_string(),
2707 f.args,
2708 )))),
2709
2710 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2712 "SHA1".to_string(),
2713 f.args,
2714 )))),
2715
2716 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2718 "SHA2".to_string(),
2719 f.args,
2720 )))),
2721
2722 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2724 "EDITDISTANCE".to_string(),
2725 f.args,
2726 )))),
2727
2728 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2730 "BITNOT".to_string(),
2731 f.args,
2732 )))),
2733
2734 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2736 "BITAND".to_string(),
2737 f.args,
2738 )))),
2739
2740 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2742 "BITOR".to_string(),
2743 f.args,
2744 )))),
2745
2746 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2748 "BITXOR".to_string(),
2749 f.args,
2750 )))),
2751
2752 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2754 Function::new("BITSHIFTLEFT".to_string(), f.args),
2755 ))),
2756
2757 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2759 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2760 ))),
2761
2762 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2764 name: "CURRENT_TIMESTAMP".to_string(),
2765 args: f.args,
2766 distinct: false,
2767 trailing_comments: Vec::new(),
2768 use_bracket_syntax: false,
2769 no_parens: f.no_parens,
2770 quoted: false,
2771 span: None,
2772 inferred_type: None,
2773 }))),
2774
2775 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2777 name: "CURRENT_TIMESTAMP".to_string(),
2778 args: f.args,
2779 distinct: false,
2780 trailing_comments: Vec::new(),
2781 use_bracket_syntax: false,
2782 no_parens: f.no_parens,
2783 quoted: false,
2784 span: None,
2785 inferred_type: None,
2786 }))),
2787
2788 "SPACE" if f.args.len() == 1 => {
2790 let arg = f.args.into_iter().next().unwrap();
2791 Ok(Expression::Function(Box::new(Function::new(
2792 "REPEAT".to_string(),
2793 vec![
2794 Expression::Literal(Box::new(Literal::String(" ".to_string()))),
2795 arg,
2796 ],
2797 ))))
2798 }
2799
2800 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2802 "CEIL".to_string(),
2803 f.args,
2804 )))),
2805
2806 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2808 "LN".to_string(),
2809 f.args,
2810 )))),
2811
2812 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(f))),
2814
2815 "GET_PATH" if f.args.len() >= 2 => {
2819 let mut args = f.args;
2820 if let Expression::Literal(lit) = &args[1] {
2822 if let crate::expressions::Literal::String(path) = lit.as_ref() {
2823 let transformed = Self::transform_json_path(path);
2824 args[1] = Expression::Literal(Box::new(
2825 crate::expressions::Literal::String(transformed),
2826 ));
2827 }
2828 }
2829 Ok(Expression::Function(Box::new(Function::new(
2830 "GET_PATH".to_string(),
2831 args,
2832 ))))
2833 }
2834 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2835
2836 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2838
2839 "DATE_TRUNC" if f.args.len() >= 1 => {
2842 let mut args = f.args;
2843 let unit_name = match &args[0] {
2845 Expression::Identifier(id) => Some(id.name.as_str()),
2846 Expression::Var(v) => Some(v.this.as_str()),
2847 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2848 _ => None,
2849 };
2850 if let Some(name) = unit_name {
2851 let canonical = Self::map_date_part(name).unwrap_or(name);
2852 args[0] = Expression::Literal(Box::new(crate::expressions::Literal::String(
2853 canonical.to_uppercase(),
2854 )));
2855 }
2856 Ok(Expression::Function(Box::new(Function::new(
2857 "DATE_TRUNC".to_string(),
2858 args,
2859 ))))
2860 }
2861
2862 "DATE_PART" if f.args.len() >= 1 => {
2868 let mut args = f.args;
2869 let from_typed_literal = args.len() >= 2
2870 && matches!(
2871 &args[1],
2872 Expression::Literal(lit) if matches!(lit.as_ref(),
2873 crate::expressions::Literal::Timestamp(_)
2874 | crate::expressions::Literal::Date(_)
2875 | crate::expressions::Literal::Time(_)
2876 | crate::expressions::Literal::Datetime(_)
2877 )
2878 );
2879 if from_typed_literal {
2880 args[0] = self.transform_date_part_arg(args[0].clone());
2881 } else {
2882 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2885 }
2886 Ok(Expression::Function(Box::new(Function::new(
2887 "DATE_PART".to_string(),
2888 args,
2889 ))))
2890 }
2891
2892 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2894
2895 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2897
2898 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2900 "DESCRIBE".to_string(),
2901 f.args,
2902 )))),
2903
2904 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2906 "REGEXP_LIKE".to_string(),
2907 f.args,
2908 )))),
2909
2910 "TRANSFORM" => {
2915 let transformed_args: Vec<Expression> = f
2916 .args
2917 .into_iter()
2918 .map(|arg| {
2919 if let Expression::Lambda(lambda) = arg {
2920 self.transform_typed_lambda(*lambda)
2921 } else {
2922 arg
2923 }
2924 })
2925 .collect();
2926 Ok(Expression::Function(Box::new(Function::new(
2927 "TRANSFORM".to_string(),
2928 transformed_args,
2929 ))))
2930 }
2931
2932 "SEARCH" if f.args.len() >= 2 => {
2934 let mut args = f.args.into_iter();
2935 let this = Box::new(args.next().unwrap());
2936 let expression = Box::new(args.next().unwrap());
2937
2938 let mut analyzer: Option<Box<Expression>> = None;
2939 let mut search_mode: Option<Box<Expression>> = None;
2940
2941 for arg in args {
2943 if let Expression::NamedArgument(na) = &arg {
2944 let name_upper = na.name.name.to_uppercase();
2945 match name_upper.as_str() {
2946 "ANALYZER" => analyzer = Some(Box::new(arg)),
2947 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2948 _ => {}
2949 }
2950 }
2951 }
2952
2953 Ok(Expression::Search(Box::new(crate::expressions::Search {
2954 this,
2955 expression,
2956 json_scope: None,
2957 analyzer,
2958 analyzer_options: None,
2959 search_mode,
2960 })))
2961 }
2962
2963 "CONVERT" if f.args.len() == 2 => {
2966 let value = f.args.get(0).cloned().unwrap();
2967 let type_arg = f.args.get(1).cloned().unwrap();
2968
2969 if let Expression::Column(col) = &type_arg {
2971 let type_name = col.name.name.to_uppercase();
2972 let data_type = match type_name.as_str() {
2973 "SQL_DOUBLE" => Some(DataType::Double {
2974 precision: None,
2975 scale: None,
2976 }),
2977 "SQL_VARCHAR" => Some(DataType::VarChar {
2978 length: None,
2979 parenthesized_length: false,
2980 }),
2981 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2982 length: None,
2983 integer_spelling: false,
2984 }),
2985 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2986 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2987 "SQL_FLOAT" => Some(DataType::Float {
2988 precision: None,
2989 scale: None,
2990 real_spelling: false,
2991 }),
2992 "SQL_REAL" => Some(DataType::Float {
2993 precision: None,
2994 scale: None,
2995 real_spelling: true,
2996 }),
2997 "SQL_DECIMAL" => Some(DataType::Decimal {
2998 precision: None,
2999 scale: None,
3000 }),
3001 "SQL_DATE" => Some(DataType::Date),
3002 "SQL_TIME" => Some(DataType::Time {
3003 precision: None,
3004 timezone: false,
3005 }),
3006 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
3007 precision: None,
3008 timezone: false,
3009 }),
3010 _ => None,
3011 };
3012
3013 if let Some(dt) = data_type {
3014 return Ok(Expression::Cast(Box::new(Cast {
3015 this: value,
3016 to: dt,
3017 double_colon_syntax: false,
3018 trailing_comments: vec![],
3019 format: None,
3020 default: None,
3021 inferred_type: None,
3022 })));
3023 }
3024 }
3025 Ok(Expression::Function(Box::new(f)))
3027 }
3028
3029 "TO_TIMESTAMP_TZ" => {
3032 if f.args.len() == 1 {
3033 if let Expression::Literal(lit) = &f.args[0] {
3034 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3035 return Ok(Expression::Cast(Box::new(Cast {
3036 this: f.args.into_iter().next().unwrap(),
3037 to: DataType::Custom {
3038 name: "TIMESTAMPTZ".to_string(),
3039 },
3040 double_colon_syntax: false,
3041 trailing_comments: vec![],
3042 format: None,
3043 default: None,
3044 inferred_type: None,
3045 })));
3046 }
3047 }
3048 }
3049 Ok(Expression::Function(Box::new(f)))
3050 }
3051
3052 "TO_TIMESTAMP_NTZ" => {
3054 if f.args.len() == 1 {
3055 if let Expression::Literal(lit) = &f.args[0] {
3056 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3057 return Ok(Expression::Cast(Box::new(Cast {
3058 this: f.args.into_iter().next().unwrap(),
3059 to: DataType::Custom {
3060 name: "TIMESTAMPNTZ".to_string(),
3061 },
3062 double_colon_syntax: false,
3063 trailing_comments: vec![],
3064 format: None,
3065 default: None,
3066 inferred_type: None,
3067 })));
3068 }
3069 }
3070 }
3071 Ok(Expression::Function(Box::new(f)))
3072 }
3073
3074 "TO_TIMESTAMP_LTZ" => {
3076 if f.args.len() == 1 {
3077 if let Expression::Literal(lit) = &f.args[0] {
3078 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3079 return Ok(Expression::Cast(Box::new(Cast {
3080 this: f.args.into_iter().next().unwrap(),
3081 to: DataType::Custom {
3082 name: "TIMESTAMPLTZ".to_string(),
3083 },
3084 double_colon_syntax: false,
3085 trailing_comments: vec![],
3086 format: None,
3087 default: None,
3088 inferred_type: None,
3089 })));
3090 }
3091 }
3092 }
3093 Ok(Expression::Function(Box::new(f)))
3094 }
3095
3096 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
3098
3099 "REPLACE" if f.args.len() == 2 => {
3101 let mut args = f.args;
3102 args.push(Expression::Literal(Box::new(
3103 crate::expressions::Literal::String(String::new()),
3104 )));
3105 Ok(Expression::Function(Box::new(Function::new(
3106 "REPLACE".to_string(),
3107 args,
3108 ))))
3109 }
3110
3111 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
3113 "ANY_VALUE".to_string(),
3114 f.args,
3115 )))),
3116
3117 "SAFE_DIVIDE" if f.args.len() == 2 => {
3119 let mut args = f.args;
3120 let x = args.remove(0);
3121 let y = args.remove(0);
3122 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3123 condition: Expression::Neq(Box::new(BinaryOp {
3124 left: y.clone(),
3125 right: Expression::number(0),
3126 left_comments: Vec::new(),
3127 operator_comments: Vec::new(),
3128 trailing_comments: Vec::new(),
3129 inferred_type: None,
3130 })),
3131 true_value: Expression::Div(Box::new(BinaryOp {
3132 left: x,
3133 right: y,
3134 left_comments: Vec::new(),
3135 operator_comments: Vec::new(),
3136 trailing_comments: Vec::new(),
3137 inferred_type: None,
3138 })),
3139 false_value: Some(Expression::Null(crate::expressions::Null)),
3140 original_name: Some("IFF".to_string()),
3141 inferred_type: None,
3142 })))
3143 }
3144
3145 "TIMESTAMP" if f.args.len() == 1 => {
3147 let arg = f.args.into_iter().next().unwrap();
3148 Ok(Expression::Cast(Box::new(Cast {
3149 this: arg,
3150 to: DataType::Custom {
3151 name: "TIMESTAMPTZ".to_string(),
3152 },
3153 trailing_comments: Vec::new(),
3154 double_colon_syntax: false,
3155 format: None,
3156 default: None,
3157 inferred_type: None,
3158 })))
3159 }
3160
3161 "TIMESTAMP" if f.args.len() == 2 => {
3163 let mut args = f.args;
3164 let value = args.remove(0);
3165 let tz = args.remove(0);
3166 Ok(Expression::Function(Box::new(Function::new(
3167 "CONVERT_TIMEZONE".to_string(),
3168 vec![
3169 tz,
3170 Expression::Cast(Box::new(Cast {
3171 this: value,
3172 to: DataType::Timestamp {
3173 precision: None,
3174 timezone: false,
3175 },
3176 trailing_comments: Vec::new(),
3177 double_colon_syntax: false,
3178 format: None,
3179 default: None,
3180 inferred_type: None,
3181 })),
3182 ],
3183 ))))
3184 }
3185
3186 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3188 "TIME_FROM_PARTS".to_string(),
3189 f.args,
3190 )))),
3191
3192 "DIV0" if f.args.len() == 2 => {
3194 let mut args = f.args;
3195 let x = args.remove(0);
3196 let y = args.remove(0);
3197 let x_expr = Self::maybe_paren(x.clone());
3199 let y_expr = Self::maybe_paren(y.clone());
3200 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3201 condition: Expression::And(Box::new(BinaryOp::new(
3202 Expression::Eq(Box::new(BinaryOp::new(
3203 y_expr.clone(),
3204 Expression::number(0),
3205 ))),
3206 Expression::Not(Box::new(crate::expressions::UnaryOp {
3207 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3208 this: x_expr.clone(),
3209 not: false,
3210 postfix_form: false,
3211 })),
3212 inferred_type: None,
3213 })),
3214 ))),
3215 true_value: Expression::number(0),
3216 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3217 original_name: Some("IFF".to_string()),
3218 inferred_type: None,
3219 })))
3220 }
3221
3222 "DIV0NULL" if f.args.len() == 2 => {
3224 let mut args = f.args;
3225 let x = args.remove(0);
3226 let y = args.remove(0);
3227 let x_expr = Self::maybe_paren(x.clone());
3228 let y_expr = Self::maybe_paren(y.clone());
3229 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3230 condition: Expression::Or(Box::new(BinaryOp::new(
3231 Expression::Eq(Box::new(BinaryOp::new(
3232 y_expr.clone(),
3233 Expression::number(0),
3234 ))),
3235 Expression::IsNull(Box::new(crate::expressions::IsNull {
3236 this: y_expr.clone(),
3237 not: false,
3238 postfix_form: false,
3239 })),
3240 ))),
3241 true_value: Expression::number(0),
3242 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3243 original_name: Some("IFF".to_string()),
3244 inferred_type: None,
3245 })))
3246 }
3247
3248 "ZEROIFNULL" if f.args.len() == 1 => {
3250 let x = f.args.into_iter().next().unwrap();
3251 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3252 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3253 this: x.clone(),
3254 not: false,
3255 postfix_form: false,
3256 })),
3257 true_value: Expression::number(0),
3258 false_value: Some(x),
3259 original_name: Some("IFF".to_string()),
3260 inferred_type: None,
3261 })))
3262 }
3263
3264 "NULLIFZERO" if f.args.len() == 1 => {
3266 let x = f.args.into_iter().next().unwrap();
3267 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3268 condition: Expression::Eq(Box::new(BinaryOp::new(
3269 x.clone(),
3270 Expression::number(0),
3271 ))),
3272 true_value: Expression::Null(crate::expressions::Null),
3273 false_value: Some(x),
3274 original_name: Some("IFF".to_string()),
3275 inferred_type: None,
3276 })))
3277 }
3278
3279 "TRY_TO_TIME" => {
3281 if f.args.len() == 1 {
3282 if let Expression::Literal(lit) = &f.args[0] {
3283 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3284 return Ok(Expression::TryCast(Box::new(Cast {
3285 this: f.args.into_iter().next().unwrap(),
3286 to: crate::expressions::DataType::Time {
3287 precision: None,
3288 timezone: false,
3289 },
3290 double_colon_syntax: false,
3291 trailing_comments: Vec::new(),
3292 format: None,
3293 default: None,
3294 inferred_type: None,
3295 })));
3296 }
3297 }
3298 }
3299 let mut args = f.args;
3301 if args.len() >= 2 {
3302 args[1] = Self::normalize_format_arg(args[1].clone());
3303 }
3304 Ok(Expression::Function(Box::new(Function::new(
3305 "TRY_TO_TIME".to_string(),
3306 args,
3307 ))))
3308 }
3309
3310 "TRY_TO_TIMESTAMP" => {
3313 if f.args.len() == 1 {
3314 if let Expression::Literal(lit) = &f.args[0] {
3315 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3316 if !Self::looks_like_epoch(s) {
3317 return Ok(Expression::TryCast(Box::new(Cast {
3318 this: f.args.into_iter().next().unwrap(),
3319 to: DataType::Timestamp {
3320 precision: None,
3321 timezone: false,
3322 },
3323 double_colon_syntax: false,
3324 trailing_comments: Vec::new(),
3325 format: None,
3326 default: None,
3327 inferred_type: None,
3328 })));
3329 }
3330 }
3331 }
3332 }
3333 let mut args = f.args;
3335 if args.len() >= 2 {
3336 args[1] = Self::normalize_format_arg(args[1].clone());
3337 }
3338 Ok(Expression::Function(Box::new(Function::new(
3339 "TRY_TO_TIMESTAMP".to_string(),
3340 args,
3341 ))))
3342 }
3343
3344 "TRY_TO_DATE" => {
3346 if f.args.len() == 1 {
3347 if let Expression::Literal(lit) = &f.args[0] {
3348 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3349 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3351 return Ok(Expression::TryCast(Box::new(Cast {
3352 this: f.args.into_iter().next().unwrap(),
3353 to: crate::expressions::DataType::Date,
3354 double_colon_syntax: false,
3355 trailing_comments: Vec::new(),
3356 format: None,
3357 default: None,
3358 inferred_type: None,
3359 })));
3360 }
3361 }
3362 }
3363 }
3364 let mut args = f.args;
3366 if args.len() >= 2 {
3367 args[1] = Self::normalize_format_arg(args[1].clone());
3368 }
3369 Ok(Expression::Function(Box::new(Function::new(
3370 "TRY_TO_DATE".to_string(),
3371 args,
3372 ))))
3373 }
3374
3375 "TRY_TO_DOUBLE" if f.args.len() == 1 => {
3378 let this = f.args.into_iter().next().unwrap();
3379 Ok(Expression::ToDouble(Box::new(
3380 crate::expressions::ToDouble {
3381 this: Box::new(this),
3382 format: None,
3383 safe: Some(Box::new(Expression::Boolean(
3384 crate::expressions::BooleanLiteral { value: true },
3385 ))),
3386 },
3387 )))
3388 }
3389 "TRY_TO_DOUBLE"
3390 if f.args.len() == 2
3391 && matches!(&f.args[1], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_))) =>
3392 {
3393 let mut args = f.args;
3394 let this = args.remove(0);
3395 let Literal::String(format) = (match args.remove(0) {
3396 Expression::Literal(lit) => *lit,
3397 _ => unreachable!(),
3398 }) else {
3399 unreachable!()
3400 };
3401 Ok(Expression::ToDouble(Box::new(
3402 crate::expressions::ToDouble {
3403 this: Box::new(this),
3404 format: Some(format),
3405 safe: Some(Box::new(Expression::Boolean(
3406 crate::expressions::BooleanLiteral { value: true },
3407 ))),
3408 },
3409 )))
3410 }
3411 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3412
3413 "REGEXP_REPLACE" if f.args.len() == 2 => {
3415 let mut args = f.args;
3416 args.push(Expression::Literal(Box::new(
3417 crate::expressions::Literal::String(String::new()),
3418 )));
3419 Ok(Expression::Function(Box::new(Function::new(
3420 "REGEXP_REPLACE".to_string(),
3421 args,
3422 ))))
3423 }
3424
3425 "LAST_DAY" if f.args.len() == 2 => {
3427 let mut args = f.args;
3428 let date = args.remove(0);
3429 let unit = args.remove(0);
3430 let unit_str = match &unit {
3431 Expression::Column(c) => c.name.name.to_uppercase(),
3432 Expression::Identifier(i) => i.name.to_uppercase(),
3433 _ => String::new(),
3434 };
3435 if unit_str == "MONTH" {
3436 Ok(Expression::Function(Box::new(Function::new(
3437 "LAST_DAY".to_string(),
3438 vec![date],
3439 ))))
3440 } else {
3441 Ok(Expression::Function(Box::new(Function::new(
3442 "LAST_DAY".to_string(),
3443 vec![date, unit],
3444 ))))
3445 }
3446 }
3447
3448 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3450 "DATE_PART".to_string(),
3451 f.args,
3452 )))),
3453
3454 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3456 let mut args = f.args;
3457 let this = args.remove(0);
3458 let expr = args.remove(0);
3459 Ok(Expression::EndsWith(Box::new(
3460 crate::expressions::BinaryFunc {
3461 original_name: None,
3462 this,
3463 expression: expr,
3464 inferred_type: None,
3465 },
3466 )))
3467 }
3468
3469 _ => Ok(Expression::Function(Box::new(f))),
3471 }
3472 }
3473
3474 fn looks_like_datetime(s: &str) -> bool {
3476 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3479 }
3480
3481 fn looks_like_epoch(s: &str) -> bool {
3483 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3484 }
3485
3486 fn maybe_paren(expr: Expression) -> Expression {
3488 match &expr {
3489 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3490 Expression::Paren(Box::new(crate::expressions::Paren {
3491 this: expr,
3492 trailing_comments: Vec::new(),
3493 }))
3494 }
3495 _ => expr,
3496 }
3497 }
3498
3499 fn normalize_snowflake_format(format: &str) -> String {
3503 let mut result = String::new();
3504 let mut cursor = crate::format_tokens::FormatTokenCursor::new(format);
3505 while let Some(ch) = cursor.peek() {
3506 if cursor.consume_prefix("\"", false) {
3508 while let Some(literal) = cursor.next_char() {
3509 if literal == '"' {
3510 break;
3511 }
3512 result.push(literal);
3513 }
3514 continue;
3515 }
3516
3517 if cursor.consume_prefix("YYYY", true) {
3519 result.push_str("yyyy");
3520 } else if cursor.consume_prefix("YY", true) {
3521 result.push_str("yy");
3522 } else if cursor.consume_prefix("MMMM", true) {
3523 result.push_str("mmmm");
3524 } else if cursor.consume_prefix("MON", true) {
3525 result.push_str("mon");
3526 } else if cursor.consume_prefix("MM", true) {
3527 result.push_str("mm");
3528 } else if cursor.consume_prefix("DD", true) {
3529 result.push_str("DD");
3530 } else if cursor.consume_prefix("DY", true) {
3531 result.push_str("dy");
3532 } else if cursor.consume_prefix("HH24", true) {
3533 result.push_str("hh24");
3534 } else if cursor.consume_prefix("HH12", true) {
3535 result.push_str("hh12");
3536 } else if cursor.consume_prefix("HH", true) {
3537 result.push_str("hh");
3538 } else if cursor.consume_prefix("MISS", true) {
3539 result.push_str("miss");
3541 } else if cursor.consume_prefix("MI", true) {
3542 result.push_str("mi");
3543 } else if cursor.consume_prefix("SS", true) {
3544 result.push_str("ss");
3545 } else if cursor.consume_prefix("FF", true) {
3546 if let Some(digit) = cursor.peek().filter(|c| c.is_ascii_digit()) {
3547 result.push_str("ff");
3548 result.push(digit);
3549 cursor.next_char();
3550 } else {
3551 result.push_str("ff9");
3553 }
3554 } else if cursor.consume_prefix("AM", true) || cursor.consume_prefix("PM", true) {
3555 result.push_str("pm");
3556 } else if cursor.consume_prefix("TZH", true) {
3557 result.push_str("tzh");
3558 } else if cursor.consume_prefix("TZM", true) {
3559 result.push_str("tzm");
3560 } else {
3561 result.push(ch);
3563 cursor.next_char();
3564 }
3565 }
3566 result
3567 }
3568
3569 fn is_temporal_expr(expr: &Expression) -> bool {
3570 match expr {
3571 Expression::CurrentDate(_)
3572 | Expression::CurrentTime(_)
3573 | Expression::CurrentTimestamp(_)
3574 | Expression::CurrentTimestampLTZ(_)
3575 | Expression::CurrentDatetime(_)
3576 | Expression::Localtime(_)
3577 | Expression::Localtimestamp(_)
3578 | Expression::Systimestamp(_)
3579 | Expression::UtcTime(_)
3580 | Expression::UtcTimestamp(_)
3581 | Expression::Date(_)
3582 | Expression::Time(_)
3583 | Expression::ToDate(_)
3584 | Expression::ToTimestamp(_)
3585 | Expression::DateStrToDate(_)
3586 | Expression::TimeStrToTime(_)
3587 | Expression::StrToTime(_) => true,
3588 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
3589 matches!(
3590 cast.to,
3591 DataType::Date | DataType::Time { .. } | DataType::Timestamp { .. }
3592 )
3593 }
3594 Expression::Paren(paren) => Self::is_temporal_expr(&paren.this),
3595 other => matches!(
3596 other.inferred_type(),
3597 Some(DataType::Date | DataType::Time { .. } | DataType::Timestamp { .. })
3598 ),
3599 }
3600 }
3601
3602 fn normalize_format_arg(expr: Expression) -> Expression {
3604 if let Expression::Literal(lit) = &expr {
3605 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3606 let normalized = Self::normalize_snowflake_format(s);
3607 Expression::Literal(Box::new(crate::expressions::Literal::String(normalized)))
3608 } else {
3609 expr.clone()
3610 }
3611 } else {
3612 expr
3613 }
3614 }
3615
3616 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3619 use crate::expressions::{DataType, LambdaExpr};
3620 use std::collections::HashMap;
3621
3622 let mut param_types: HashMap<String, DataType> = HashMap::new();
3624 for (i, param) in lambda.parameters.iter().enumerate() {
3625 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3626 param_types.insert(param.name.to_uppercase(), dt.clone());
3627 }
3628 }
3629
3630 if param_types.is_empty() {
3632 return Expression::Lambda(Box::new(lambda));
3633 }
3634
3635 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3637
3638 Expression::Lambda(Box::new(LambdaExpr {
3640 parameters: lambda.parameters,
3641 body: transformed_body,
3642 colon: lambda.colon,
3643 parameter_types: Vec::new(), }))
3645 }
3646
3647 fn replace_lambda_params_with_cast(
3649 &self,
3650 expr: Expression,
3651 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3652 ) -> Expression {
3653 use crate::expressions::{BinaryOp, Cast, Paren};
3654
3655 match expr {
3656 Expression::Column(col) if col.table.is_none() => {
3658 let name_upper = col.name.name.to_uppercase();
3659 if let Some(dt) = param_types.get(&name_upper) {
3660 Expression::Cast(Box::new(Cast {
3662 this: Expression::Column(col),
3663 to: dt.clone(),
3664 double_colon_syntax: false,
3665 trailing_comments: Vec::new(),
3666 format: None,
3667 default: None,
3668 inferred_type: None,
3669 }))
3670 } else {
3671 Expression::Column(col)
3672 }
3673 }
3674
3675 Expression::Identifier(id) => {
3677 let name_upper = id.name.to_uppercase();
3678 if let Some(dt) = param_types.get(&name_upper) {
3679 Expression::Cast(Box::new(Cast {
3681 this: Expression::Identifier(id),
3682 to: dt.clone(),
3683 double_colon_syntax: false,
3684 trailing_comments: Vec::new(),
3685 format: None,
3686 default: None,
3687 inferred_type: None,
3688 }))
3689 } else {
3690 Expression::Identifier(id)
3691 }
3692 }
3693
3694 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3696 self.replace_lambda_params_with_cast(op.left, param_types),
3697 self.replace_lambda_params_with_cast(op.right, param_types),
3698 ))),
3699 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3700 self.replace_lambda_params_with_cast(op.left, param_types),
3701 self.replace_lambda_params_with_cast(op.right, param_types),
3702 ))),
3703 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3704 self.replace_lambda_params_with_cast(op.left, param_types),
3705 self.replace_lambda_params_with_cast(op.right, param_types),
3706 ))),
3707 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3708 self.replace_lambda_params_with_cast(op.left, param_types),
3709 self.replace_lambda_params_with_cast(op.right, param_types),
3710 ))),
3711 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3712 self.replace_lambda_params_with_cast(op.left, param_types),
3713 self.replace_lambda_params_with_cast(op.right, param_types),
3714 ))),
3715
3716 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3718 this: self.replace_lambda_params_with_cast(p.this, param_types),
3719 trailing_comments: p.trailing_comments,
3720 })),
3721
3722 Expression::Function(mut f) => {
3724 f.args = f
3725 .args
3726 .into_iter()
3727 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3728 .collect();
3729 Expression::Function(f)
3730 }
3731
3732 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3734 self.replace_lambda_params_with_cast(op.left, param_types),
3735 self.replace_lambda_params_with_cast(op.right, param_types),
3736 ))),
3737 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3738 self.replace_lambda_params_with_cast(op.left, param_types),
3739 self.replace_lambda_params_with_cast(op.right, param_types),
3740 ))),
3741 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3742 self.replace_lambda_params_with_cast(op.left, param_types),
3743 self.replace_lambda_params_with_cast(op.right, param_types),
3744 ))),
3745 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3746 self.replace_lambda_params_with_cast(op.left, param_types),
3747 self.replace_lambda_params_with_cast(op.right, param_types),
3748 ))),
3749 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3750 self.replace_lambda_params_with_cast(op.left, param_types),
3751 self.replace_lambda_params_with_cast(op.right, param_types),
3752 ))),
3753 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3754 self.replace_lambda_params_with_cast(op.left, param_types),
3755 self.replace_lambda_params_with_cast(op.right, param_types),
3756 ))),
3757
3758 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3760 self.replace_lambda_params_with_cast(op.left, param_types),
3761 self.replace_lambda_params_with_cast(op.right, param_types),
3762 ))),
3763 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3764 self.replace_lambda_params_with_cast(op.left, param_types),
3765 self.replace_lambda_params_with_cast(op.right, param_types),
3766 ))),
3767
3768 other => other,
3770 }
3771 }
3772
3773 fn transform_aggregate_function(
3774 &self,
3775 f: Box<crate::expressions::AggregateFunction>,
3776 ) -> Result<Expression> {
3777 let name_upper = f.name.to_uppercase();
3778 match name_upper.as_str() {
3779 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3781 Function::new("LISTAGG".to_string(), f.args),
3782 ))),
3783
3784 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3786 Function::new("LISTAGG".to_string(), f.args),
3787 ))),
3788
3789 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3791 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3792 ))),
3793
3794 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3796 "BITAND_AGG".to_string(),
3797 f.args,
3798 )))),
3799
3800 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3802 "BITOR_AGG".to_string(),
3803 f.args,
3804 )))),
3805
3806 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3808 "BITXOR_AGG".to_string(),
3809 f.args,
3810 )))),
3811
3812 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3814 let arg = f.args.into_iter().next().unwrap();
3815 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3816 this: arg,
3817 distinct: f.distinct,
3818 filter: f.filter,
3819 order_by: Vec::new(),
3820 name: Some("BOOLAND_AGG".to_string()),
3821 ignore_nulls: None,
3822 having_max: None,
3823 limit: None,
3824 inferred_type: None,
3825 })))
3826 }
3827
3828 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3830 let arg = f.args.into_iter().next().unwrap();
3831 Ok(Expression::LogicalOr(Box::new(AggFunc {
3832 this: arg,
3833 distinct: f.distinct,
3834 filter: f.filter,
3835 order_by: Vec::new(),
3836 name: Some("BOOLOR_AGG".to_string()),
3837 ignore_nulls: None,
3838 having_max: None,
3839 limit: None,
3840 inferred_type: None,
3841 })))
3842 }
3843
3844 "APPROX_TOP_K" if f.args.len() == 1 => {
3846 let mut args = f.args;
3847 args.push(Expression::number(1));
3848 Ok(Expression::AggregateFunction(Box::new(
3849 crate::expressions::AggregateFunction {
3850 name: "APPROX_TOP_K".to_string(),
3851 args,
3852 distinct: f.distinct,
3853 filter: f.filter,
3854 order_by: Vec::new(),
3855 limit: None,
3856 ignore_nulls: None,
3857 inferred_type: None,
3858 },
3859 )))
3860 }
3861
3862 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3864 let arg = f.args.into_iter().next().unwrap();
3865 Ok(Expression::Skewness(Box::new(AggFunc {
3866 this: arg,
3867 distinct: f.distinct,
3868 filter: f.filter,
3869 order_by: Vec::new(),
3870 name: Some("SKEW".to_string()),
3871 ignore_nulls: None,
3872 having_max: None,
3873 limit: None,
3874 inferred_type: None,
3875 })))
3876 }
3877
3878 _ => Ok(Expression::AggregateFunction(f)),
3880 }
3881 }
3882}
3883
3884#[cfg(feature = "transpile")]
3886fn strftime_to_snowflake_format(fmt: &str) -> String {
3887 let mut result = String::new();
3888 let chars: Vec<char> = fmt.chars().collect();
3889 let mut i = 0;
3890 while i < chars.len() {
3891 if chars[i] == '%' && i + 1 < chars.len() {
3892 match chars[i + 1] {
3893 'Y' => {
3894 result.push_str("yyyy");
3895 i += 2;
3896 }
3897 'y' => {
3898 result.push_str("yy");
3899 i += 2;
3900 }
3901 'm' => {
3902 result.push_str("mm");
3903 i += 2;
3904 }
3905 'd' => {
3906 result.push_str("DD");
3907 i += 2;
3908 }
3909 'H' => {
3910 result.push_str("hh24");
3911 i += 2;
3912 }
3913 'M' => {
3914 result.push_str("mmmm");
3915 i += 2;
3916 } 'i' => {
3918 result.push_str("mi");
3919 i += 2;
3920 }
3921 'S' | 's' => {
3922 result.push_str("ss");
3923 i += 2;
3924 }
3925 'f' => {
3926 result.push_str("ff");
3927 i += 2;
3928 }
3929 'w' => {
3930 result.push_str("dy");
3931 i += 2;
3932 } 'a' => {
3934 result.push_str("DY");
3935 i += 2;
3936 } 'b' => {
3938 result.push_str("mon");
3939 i += 2;
3940 } 'T' => {
3942 result.push_str("hh24:mi:ss");
3943 i += 2;
3944 } _ => {
3946 result.push(chars[i]);
3947 result.push(chars[i + 1]);
3948 i += 2;
3949 }
3950 }
3951 } else {
3952 result.push(chars[i]);
3953 i += 1;
3954 }
3955 }
3956 result
3957}
3958
3959#[cfg(test)]
3960mod tests {
3961 use super::*;
3962 use crate::dialects::Dialect;
3963
3964 #[test]
3965 fn test_date_time_format_normalization_preserves_unicode() {
3966 for literal in ["é", "年", "🦀", "e\u{301}", "ß", "ſ"] {
3967 assert_eq!(
3968 SnowflakeDialect::normalize_snowflake_format(literal),
3969 literal
3970 );
3971 assert_eq!(
3972 SnowflakeDialect::normalize_snowflake_format(&format!(
3973 "{literal}YYYY{literal}mM{literal}"
3974 )),
3975 format!("{literal}yyyy{literal}mm{literal}")
3976 );
3977 }
3978 for (input, expected) in [
3979 ("", ""),
3980 (
3981 "YYYY YY MMMM MON MM DD DY HH24 HH12 HH MISS MI SS AM PM TZH TZM",
3982 "yyyy yy mmmm mon mm DD dy hh24 hh12 hh miss mi ss pm pm tzh tzm",
3983 ),
3984 (
3985 "FF FF0 FF1 FF6 FF7 FF9 FF69",
3986 "ff9 ff0 ff1 ff6 ff7 ff9 ff69",
3987 ),
3988 ("éFF9年YYYY", "éff9年yyyy"),
3989 ("\"éYYYY🦀\"YYYY", "éYYYY🦀yyyy"),
3990 ("YYYY\"年", "yyyy年"),
3991 ("\"\"YYYY\"T\"HH24", "yyyyThh24"),
3992 ("q %-q %", "q %-q %"),
3993 ] {
3994 assert_eq!(
3995 SnowflakeDialect::normalize_snowflake_format(input),
3996 expected,
3997 "{input}"
3998 );
3999 }
4000 }
4001
4002 fn transpile_to_snowflake(sql: &str) -> String {
4003 let dialect = Dialect::get(DialectType::Generic);
4004 let result = dialect
4005 .transpile(sql, DialectType::Snowflake)
4006 .expect("Transpile failed");
4007 result[0].clone()
4008 }
4009
4010 #[test]
4011 fn test_ifnull_to_coalesce() {
4012 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
4013 assert!(
4014 result.contains("COALESCE"),
4015 "Expected COALESCE, got: {}",
4016 result
4017 );
4018 }
4019
4020 #[test]
4021 fn test_basic_select() {
4022 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
4023 assert!(result.contains("SELECT"));
4024 assert!(result.contains("FROM users"));
4025 }
4026
4027 #[test]
4028 fn test_extract_string_comma_syntax_remains_date_part() {
4029 assert_eq!(
4030 transpile_to_snowflake("SELECT EXTRACT('month', a)"),
4031 "SELECT DATE_PART('month', a)"
4032 );
4033 }
4034
4035 #[test]
4036 fn test_snowflake_scripting_cursor_declare_block_roundtrip() {
4037 let sql = "DECLARE
4038 emp CURSOR FOR SELECT salary FROM employees;
4039BEGIN
4040 RETURN 1;
4041END";
4042
4043 let dialect = Dialect::get(DialectType::Snowflake);
4044 let ast = dialect.parse(sql).expect("Parse failed");
4045 let output = dialect.generate(&ast[0]).expect("Generate failed");
4046
4047 assert_eq!(output, sql);
4048 }
4049
4050 #[test]
4051 fn test_snowflake_scripting_cursor_return_table_roundtrip() {
4052 let sql = "DECLARE
4053 c1 CURSOR FOR SELECT * FROM invoices;
4054BEGIN
4055 OPEN c1;
4056 RETURN TABLE(RESULTSET_FROM_CURSOR(c1));
4057END";
4058
4059 let dialect = Dialect::get(DialectType::Snowflake);
4060 let ast = dialect.parse(sql).expect("Parse failed");
4061 let output = dialect.generate(&ast[0]).expect("Generate failed");
4062
4063 assert_eq!(output, sql);
4064 }
4065
4066 #[test]
4067 fn test_group_concat_to_listagg() {
4068 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
4069 assert!(
4070 result.contains("LISTAGG"),
4071 "Expected LISTAGG, got: {}",
4072 result
4073 );
4074 }
4075
4076 #[test]
4077 fn test_string_agg_to_listagg() {
4078 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
4079 assert!(
4080 result.contains("LISTAGG"),
4081 "Expected LISTAGG, got: {}",
4082 result
4083 );
4084 }
4085
4086 #[test]
4087 fn test_array_to_array_construct() {
4088 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
4089 assert!(
4091 result.contains("[1, 2, 3]"),
4092 "Expected [1, 2, 3], got: {}",
4093 result
4094 );
4095 }
4096
4097 #[test]
4098 fn test_double_quote_identifiers() {
4099 let dialect = SnowflakeDialect;
4101 let config = dialect.generator_config();
4102 assert_eq!(config.identifier_quote, '"');
4103 }
4104}