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