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