1use super::{DialectImpl, DialectType};
13use crate::error::Result;
14use crate::expressions::{
15 AggFunc, BinaryOp, Cast, CeilFunc, DataType, Expression, Function, IntervalUnit, ListAggFunc,
16 Literal, UnaryFunc, VarArgFunc,
17};
18use crate::generator::GeneratorConfig;
19use crate::tokens::TokenizerConfig;
20
21fn interval_unit_to_str(unit: &IntervalUnit) -> String {
23 match unit {
24 IntervalUnit::Year => "YEAR".to_string(),
25 IntervalUnit::Quarter => "QUARTER".to_string(),
26 IntervalUnit::Month => "MONTH".to_string(),
27 IntervalUnit::Week => "WEEK".to_string(),
28 IntervalUnit::Day => "DAY".to_string(),
29 IntervalUnit::Hour => "HOUR".to_string(),
30 IntervalUnit::Minute => "MINUTE".to_string(),
31 IntervalUnit::Second => "SECOND".to_string(),
32 IntervalUnit::Millisecond => "MILLISECOND".to_string(),
33 IntervalUnit::Microsecond => "MICROSECOND".to_string(),
34 IntervalUnit::Nanosecond => "NANOSECOND".to_string(),
35 }
36}
37
38pub struct SnowflakeDialect;
40
41impl DialectImpl for SnowflakeDialect {
42 fn dialect_type(&self) -> DialectType {
43 DialectType::Snowflake
44 }
45
46 fn tokenizer_config(&self) -> TokenizerConfig {
47 let mut config = TokenizerConfig::default();
48 config.identifiers.insert('"', '"');
50 config.quotes.insert("$$".to_string(), "$$".to_string());
52 config.nested_comments = false;
54 config.comments.insert("//".to_string(), None);
56 config
57 }
58
59 fn generator_config(&self) -> GeneratorConfig {
60 use crate::generator::IdentifierQuoteStyle;
61 GeneratorConfig {
62 identifier_quote: '"',
63 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
64 dialect: Some(DialectType::Snowflake),
65 parameter_token: "$",
67 matched_by_source: false,
68 single_string_interval: true,
69 join_hints: false,
70 table_hints: false,
71 query_hints: false,
72 aggregate_filter_supported: false,
73 supports_table_copy: false,
74 collate_is_func: true,
75 limit_only_literals: true,
76 json_key_value_pair_sep: ",",
77 insert_overwrite: " OVERWRITE INTO",
78 struct_delimiter: ("(", ")"),
79 copy_params_are_wrapped: false,
80 copy_params_eq_required: true,
81 star_except: "EXCLUDE",
82 supports_exploding_projections: false,
83 array_concat_is_var_len: false,
84 supports_convert_timezone: true,
85 except_intersect_support_all_clause: false,
86 supports_median: true,
87 array_size_name: "ARRAY_SIZE",
88 supports_decode_case: true,
89 is_bool_allowed: false,
90 try_supported: true,
92 nvl2_supported: true,
94 unnest_with_ordinality: false,
96 quantified_no_paren_space: false,
98 ..Default::default()
99 }
100 }
101
102 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
103 match expr {
104 Expression::DataType(dt) => self.transform_data_type(dt),
106
107 Expression::In(in_expr) if in_expr.not && in_expr.query.is_some() => {
111 let inner = in_expr.query.unwrap();
113 let subquery = Expression::Subquery(Box::new(crate::expressions::Subquery {
115 this: inner,
116 alias: None,
117 column_aliases: Vec::new(),
118 order_by: None,
119 limit: None,
120 offset: None,
121 distribute_by: None,
122 sort_by: None,
123 cluster_by: None,
124 lateral: false,
125 modifiers_inside: false,
126 trailing_comments: Vec::new(),
127 }));
128 Ok(Expression::All(Box::new(
129 crate::expressions::QuantifiedExpr {
130 this: in_expr.this,
131 subquery,
132 op: Some(crate::expressions::QuantifiedOp::Neq),
133 },
134 )))
135 }
136
137 Expression::In(in_expr) if in_expr.not => {
139 let in_without_not = crate::expressions::In {
141 this: in_expr.this,
142 expressions: in_expr.expressions,
143 query: in_expr.query,
144 not: false,
145 global: in_expr.global,
146 unnest: in_expr.unnest,
147 is_field: in_expr.is_field,
148 };
149 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
150 this: Expression::In(Box::new(in_without_not)),
151 })))
152 }
153
154 Expression::Interval(interval) => self.transform_interval(*interval),
157
158 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
161 original_name: None,
162 expressions: vec![f.this, f.expression],
163 }))),
164
165 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
167 original_name: None,
168 expressions: vec![f.this, f.expression],
169 }))),
170
171 Expression::Coalesce(mut f) => {
173 f.original_name = None;
174 Ok(Expression::Coalesce(f))
175 }
176
177 Expression::GroupConcat(f) => Ok(Expression::ListAgg(Box::new(ListAggFunc {
179 this: f.this,
180 separator: f.separator,
181 on_overflow: None,
182 order_by: f.order_by,
183 distinct: f.distinct,
184 filter: f.filter,
185 }))),
186
187 Expression::Cast(c) => {
191 use crate::expressions::DataType;
192 let transformed_this = self.transform_expr(c.this)?;
194 match &c.to {
195 DataType::Geography { .. } => Ok(Expression::Function(Box::new(
196 Function::new("TO_GEOGRAPHY".to_string(), vec![transformed_this]),
197 ))),
198 DataType::Geometry { .. } => Ok(Expression::Function(Box::new(Function::new(
199 "TO_GEOMETRY".to_string(),
200 vec![transformed_this],
201 )))),
202 _ => {
203 let transformed_dt = match self.transform_data_type(c.to.clone())? {
205 Expression::DataType(dt) => dt,
206 _ => c.to.clone(),
207 };
208 Ok(Expression::Cast(Box::new(Cast {
209 this: transformed_this,
210 to: transformed_dt,
211 double_colon_syntax: false, trailing_comments: c.trailing_comments,
213 format: c.format,
214 default: c.default,
215 })))
216 }
217 }
218 }
219
220 Expression::TryCast(c) => {
223 let transformed_this = self.transform_expr(c.this)?;
224 Ok(Expression::TryCast(Box::new(Cast {
225 this: transformed_this,
226 to: c.to,
227 double_colon_syntax: false, trailing_comments: c.trailing_comments,
229 format: c.format,
230 default: c.default,
231 })))
232 }
233
234 Expression::SafeCast(c) => {
237 let to = match c.to {
238 DataType::Timestamp { .. } => DataType::Custom {
239 name: "TIMESTAMPTZ".to_string(),
240 },
241 DataType::Custom { name } if name.eq_ignore_ascii_case("TIMESTAMP") => {
242 DataType::Custom {
243 name: "TIMESTAMPTZ".to_string(),
244 }
245 }
246 other => other,
247 };
248 let transformed_this = self.transform_expr(c.this)?;
249 Ok(Expression::Cast(Box::new(Cast {
250 this: transformed_this,
251 to,
252 double_colon_syntax: c.double_colon_syntax,
253 trailing_comments: c.trailing_comments,
254 format: c.format,
255 default: c.default,
256 })))
257 }
258
259 Expression::Literal(Literal::Timestamp(s)) => Ok(Expression::Cast(Box::new(Cast {
262 this: Expression::Literal(Literal::String(s)),
263 to: DataType::Timestamp {
264 precision: None,
265 timezone: false,
266 },
267 double_colon_syntax: false,
268 trailing_comments: Vec::new(),
269 format: None,
270 default: None,
271 }))),
272
273 Expression::Literal(Literal::Date(s)) => Ok(Expression::Cast(Box::new(Cast {
275 this: Expression::Literal(Literal::String(s)),
276 to: DataType::Date,
277 double_colon_syntax: false,
278 trailing_comments: Vec::new(),
279 format: None,
280 default: None,
281 }))),
282
283 Expression::Literal(Literal::Time(s)) => Ok(Expression::Cast(Box::new(Cast {
285 this: Expression::Literal(Literal::String(s)),
286 to: DataType::Time {
287 precision: None,
288 timezone: false,
289 },
290 double_colon_syntax: false,
291 trailing_comments: Vec::new(),
292 format: None,
293 default: None,
294 }))),
295
296 Expression::Literal(Literal::Datetime(s)) => Ok(Expression::Cast(Box::new(Cast {
298 this: Expression::Literal(Literal::String(s)),
299 to: DataType::Custom {
300 name: "DATETIME".to_string(),
301 },
302 double_colon_syntax: false,
303 trailing_comments: Vec::new(),
304 format: None,
305 default: None,
306 }))),
307
308 Expression::ILike(op) => Ok(Expression::ILike(op)),
311
312 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
315 "FLATTEN".to_string(),
316 vec![f.this],
317 )))),
318
319 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
321 "FLATTEN".to_string(),
322 vec![f.this],
323 )))),
324
325 Expression::Unnest(f) => {
327 let input_arg =
329 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
330 name: crate::expressions::Identifier::new("INPUT"),
331 value: f.this,
332 separator: crate::expressions::NamedArgSeparator::DArrow,
333 }));
334
335 let flatten = Expression::Function(Box::new(Function::new(
337 "FLATTEN".to_string(),
338 vec![input_arg],
339 )));
340
341 let table_func =
343 Expression::TableFromRows(Box::new(crate::expressions::TableFromRows {
344 this: Box::new(flatten),
345 alias: None,
346 joins: vec![],
347 pivots: None,
348 sample: None,
349 }));
350
351 Ok(Expression::Alias(Box::new(crate::expressions::Alias {
353 this: table_func,
354 alias: crate::expressions::Identifier::new("_t0"),
355 column_aliases: vec![
356 crate::expressions::Identifier::new("seq"),
357 crate::expressions::Identifier::new("key"),
358 crate::expressions::Identifier::new("path"),
359 crate::expressions::Identifier::new("index"),
360 crate::expressions::Identifier::new("value"),
361 crate::expressions::Identifier::new("this"),
362 ],
363 pre_alias_comments: vec![],
364 trailing_comments: vec![],
365 })))
366 }
367
368 Expression::ArrayFunc(arr) => {
372 if arr.bracket_notation {
373 Ok(Expression::ArrayFunc(arr))
375 } else {
376 Ok(Expression::Function(Box::new(Function::new(
378 "ARRAY_CONSTRUCT".to_string(),
379 arr.expressions,
380 ))))
381 }
382 }
383
384 Expression::ArrayConcat(f) => Ok(Expression::Function(Box::new(Function::new(
386 "ARRAY_CAT".to_string(),
387 f.expressions,
388 )))),
389
390 Expression::ArrayConcatAgg(f) => Ok(Expression::Function(Box::new(Function::new(
392 "ARRAY_FLATTEN".to_string(),
393 vec![f.this],
394 )))),
395
396 Expression::ArrayContains(f) => Ok(Expression::Function(Box::new(Function::new(
398 "ARRAY_CONTAINS".to_string(),
399 vec![f.this, f.expression],
400 )))),
401
402 Expression::ArrayIntersect(f) => Ok(Expression::Function(Box::new(Function::new(
404 "ARRAY_INTERSECTION".to_string(),
405 f.expressions,
406 )))),
407
408 Expression::ArraySort(f) => Ok(Expression::Function(Box::new(Function::new(
410 "ARRAY_SORT".to_string(),
411 vec![f.this],
412 )))),
413
414 Expression::StringToArray(f) => {
416 let mut args = vec![*f.this];
417 if let Some(expr) = f.expression {
418 args.push(*expr);
419 }
420 Ok(Expression::Function(Box::new(Function::new(
421 "STRTOK_TO_ARRAY".to_string(),
422 args,
423 ))))
424 }
425
426 Expression::BitwiseOr(f) => Ok(Expression::Function(Box::new(Function::new(
429 "BITOR".to_string(),
430 vec![f.left, f.right],
431 )))),
432
433 Expression::BitwiseXor(f) => Ok(Expression::Function(Box::new(Function::new(
435 "BITXOR".to_string(),
436 vec![f.left, f.right],
437 )))),
438
439 Expression::BitwiseAnd(f) => Ok(Expression::Function(Box::new(Function::new(
441 "BITAND".to_string(),
442 vec![f.left, f.right],
443 )))),
444
445 Expression::BitwiseNot(f) => Ok(Expression::Function(Box::new(Function::new(
447 "BITNOT".to_string(),
448 vec![f.this],
449 )))),
450
451 Expression::BitwiseLeftShift(f) => Ok(Expression::Function(Box::new(Function::new(
453 "BITSHIFTLEFT".to_string(),
454 vec![f.left, f.right],
455 )))),
456
457 Expression::BitwiseRightShift(f) => Ok(Expression::Function(Box::new(Function::new(
459 "BITSHIFTRIGHT".to_string(),
460 vec![f.left, f.right],
461 )))),
462
463 Expression::BitwiseAndAgg(f) => Ok(Expression::Function(Box::new(Function::new(
465 "BITAND_AGG".to_string(),
466 vec![f.this],
467 )))),
468
469 Expression::BitwiseOrAgg(f) => Ok(Expression::Function(Box::new(Function::new(
471 "BITOR_AGG".to_string(),
472 vec![f.this],
473 )))),
474
475 Expression::BitwiseXorAgg(f) => Ok(Expression::Function(Box::new(Function::new(
477 "BITXOR_AGG".to_string(),
478 vec![f.this],
479 )))),
480
481 Expression::LogicalAnd(f) => Ok(Expression::Function(Box::new(Function::new(
484 "BOOLAND_AGG".to_string(),
485 vec![f.this],
486 )))),
487
488 Expression::LogicalOr(f) => Ok(Expression::Function(Box::new(Function::new(
490 "BOOLOR_AGG".to_string(),
491 vec![f.this],
492 )))),
493
494 Expression::Booland(f) => Ok(Expression::Function(Box::new(Function::new(
496 "BOOLAND".to_string(),
497 vec![*f.this, *f.expression],
498 )))),
499
500 Expression::Boolor(f) => Ok(Expression::Function(Box::new(Function::new(
502 "BOOLOR".to_string(),
503 vec![*f.this, *f.expression],
504 )))),
505
506 Expression::Xor(f) => {
508 let mut args = Vec::new();
509 if let Some(this) = f.this {
510 args.push(*this);
511 }
512 if let Some(expr) = f.expression {
513 args.push(*expr);
514 }
515 Ok(Expression::Function(Box::new(Function::new(
516 "BOOLXOR".to_string(),
517 args,
518 ))))
519 }
520
521 Expression::DayOfMonth(f) => Ok(Expression::Function(Box::new(Function::new(
524 "DAYOFMONTH".to_string(),
525 vec![f.this],
526 )))),
527
528 Expression::DayOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
530 "DAYOFWEEK".to_string(),
531 vec![f.this],
532 )))),
533
534 Expression::DayOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
536 "DAYOFWEEKISO".to_string(),
537 vec![f.this],
538 )))),
539
540 Expression::DayOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
542 "DAYOFYEAR".to_string(),
543 vec![f.this],
544 )))),
545
546 Expression::WeekOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
548 "WEEK".to_string(),
549 vec![f.this],
550 )))),
551
552 Expression::YearOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
554 "YEAROFWEEK".to_string(),
555 vec![f.this],
556 )))),
557
558 Expression::YearOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
560 "YEAROFWEEKISO".to_string(),
561 vec![f.this],
562 )))),
563
564 Expression::ByteLength(f) => Ok(Expression::Function(Box::new(Function::new(
566 "OCTET_LENGTH".to_string(),
567 vec![f.this],
568 )))),
569
570 Expression::TimestampDiff(f) => {
572 let mut args = vec![];
573 if let Some(ref unit_str) = f.unit {
575 args.push(Expression::Identifier(crate::expressions::Identifier::new(
576 unit_str.clone(),
577 )));
578 args.push(*f.this);
579 args.push(*f.expression);
580 } else {
581 args.push(*f.this);
582 args.push(*f.expression);
583 }
584 Ok(Expression::Function(Box::new(Function::new(
585 "TIMESTAMPDIFF".to_string(),
586 args,
587 ))))
588 }
589
590 Expression::TimestampAdd(f) => {
592 let mut args = vec![];
593 if let Some(ref unit_str) = f.unit {
594 args.push(Expression::Identifier(crate::expressions::Identifier::new(
595 unit_str.clone(),
596 )));
597 args.push(*f.this);
598 args.push(*f.expression);
599 } else {
600 args.push(*f.this);
601 args.push(*f.expression);
602 }
603 Ok(Expression::Function(Box::new(Function::new(
604 "TIMESTAMPADD".to_string(),
605 args,
606 ))))
607 }
608
609 Expression::ToArray(f) => Ok(Expression::Function(Box::new(Function::new(
611 "TO_ARRAY".to_string(),
612 vec![f.this],
613 )))),
614
615 Expression::DateAdd(f) => {
617 let unit_str = interval_unit_to_str(&f.unit);
618 let unit = Expression::Identifier(crate::expressions::Identifier {
619 name: unit_str,
620 quoted: false,
621 trailing_comments: Vec::new(),
622 span: None,
623 });
624 Ok(Expression::Function(Box::new(Function::new(
625 "DATEADD".to_string(),
626 vec![unit, f.interval, f.this],
627 ))))
628 }
629
630 Expression::DateSub(f) => {
632 let unit_str = interval_unit_to_str(&f.unit);
633 let unit = Expression::Identifier(crate::expressions::Identifier {
634 name: unit_str,
635 quoted: false,
636 trailing_comments: Vec::new(),
637 span: None,
638 });
639 let neg_expr = Expression::Mul(Box::new(crate::expressions::BinaryOp::new(
641 f.interval,
642 Expression::Neg(Box::new(crate::expressions::UnaryOp {
643 this: Expression::number(1),
644 })),
645 )));
646 Ok(Expression::Function(Box::new(Function::new(
647 "DATEADD".to_string(),
648 vec![unit, neg_expr, f.this],
649 ))))
650 }
651
652 Expression::DateDiff(f) => {
654 let unit_str =
655 interval_unit_to_str(&f.unit.unwrap_or(crate::expressions::IntervalUnit::Day));
656 let unit = Expression::Identifier(crate::expressions::Identifier {
657 name: unit_str,
658 quoted: false,
659 trailing_comments: Vec::new(),
660 span: None,
661 });
662 Ok(Expression::Function(Box::new(Function::new(
663 "DATEDIFF".to_string(),
664 vec![unit, f.expression, f.this],
665 ))))
666 }
667
668 Expression::StringAgg(f) => {
671 let mut args = vec![f.this.clone()];
672 if let Some(separator) = &f.separator {
673 args.push(separator.clone());
674 }
675 Ok(Expression::Function(Box::new(Function::new(
676 "LISTAGG".to_string(),
677 args,
678 ))))
679 }
680
681 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
683 "STARTSWITH".to_string(),
684 vec![f.this, f.expression],
685 )))),
686
687 Expression::EndsWith(f) => Ok(Expression::EndsWith(f)),
689
690 Expression::Stuff(f) => {
692 let mut args = vec![*f.this];
693 if let Some(start) = f.start {
694 args.push(*start);
695 }
696 if let Some(length) = f.length {
697 args.push(Expression::number(length));
698 }
699 args.push(*f.expression);
700 Ok(Expression::Function(Box::new(Function::new(
701 "INSERT".to_string(),
702 args,
703 ))))
704 }
705
706 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
709 "SHA1".to_string(),
710 vec![f.this],
711 )))),
712
713 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
715 "SHA1_BINARY".to_string(),
716 vec![f.this],
717 )))),
718
719 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
721 "SHA2_BINARY".to_string(),
722 vec![*f.this],
723 )))),
724
725 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
727 "MD5_BINARY".to_string(),
728 vec![*f.this],
729 )))),
730
731 Expression::MD5NumberLower64(f) => Ok(Expression::Function(Box::new(Function::new(
733 "MD5_NUMBER_LOWER64".to_string(),
734 vec![f.this],
735 )))),
736
737 Expression::MD5NumberUpper64(f) => Ok(Expression::Function(Box::new(Function::new(
739 "MD5_NUMBER_UPPER64".to_string(),
740 vec![f.this],
741 )))),
742
743 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
746 "VECTOR_COSINE_SIMILARITY".to_string(),
747 vec![*f.this, *f.expression],
748 )))),
749
750 Expression::DotProduct(f) => Ok(Expression::Function(Box::new(Function::new(
752 "VECTOR_INNER_PRODUCT".to_string(),
753 vec![*f.this, *f.expression],
754 )))),
755
756 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
758 "VECTOR_L2_DISTANCE".to_string(),
759 vec![*f.this, *f.expression],
760 )))),
761
762 Expression::ManhattanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
764 "VECTOR_L1_DISTANCE".to_string(),
765 vec![*f.this, *f.expression],
766 )))),
767
768 Expression::JSONFormat(f) => {
771 let mut args = Vec::new();
772 if let Some(this) = f.this {
773 args.push(*this);
774 }
775 Ok(Expression::Function(Box::new(Function::new(
776 "TO_JSON".to_string(),
777 args,
778 ))))
779 }
780
781 Expression::JSONKeys(f) => Ok(Expression::Function(Box::new(Function::new(
783 "OBJECT_KEYS".to_string(),
784 vec![*f.this],
785 )))),
786
787 Expression::GetExtract(f) => Ok(Expression::Function(Box::new(Function::new(
789 "GET".to_string(),
790 vec![*f.this, *f.expression],
791 )))),
792
793 Expression::StarMap(f) => Ok(Expression::Function(Box::new(Function::new(
795 "OBJECT_CONSTRUCT".to_string(),
796 vec![f.this, f.expression],
797 )))),
798
799 Expression::LowerHex(f) => Ok(Expression::Function(Box::new(Function::new(
801 "TO_CHAR".to_string(),
802 vec![f.this],
803 )))),
804
805 Expression::Skewness(f) => Ok(Expression::Function(Box::new(Function::new(
807 "SKEW".to_string(),
808 vec![f.this],
809 )))),
810
811 Expression::StPoint(f) => Ok(Expression::Function(Box::new(Function::new(
813 "ST_MAKEPOINT".to_string(),
814 vec![*f.this, *f.expression],
815 )))),
816
817 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
819 "CONVERT_TIMEZONE".to_string(),
820 vec![*f.this],
821 )))),
822
823 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
826 "HEX_DECODE_BINARY".to_string(),
827 vec![*f.this],
828 )))),
829
830 Expression::UnixToTime(f) => {
832 let mut args = vec![*f.this];
833 if let Some(scale) = f.scale {
834 args.push(Expression::number(scale));
835 }
836 Ok(Expression::Function(Box::new(Function::new(
837 "TO_TIMESTAMP".to_string(),
838 args,
839 ))))
840 }
841
842 Expression::IfFunc(f) => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
845 condition: f.condition,
846 true_value: f.true_value,
847 false_value: Some(
848 f.false_value
849 .unwrap_or(Expression::Null(crate::expressions::Null)),
850 ),
851 original_name: Some("IFF".to_string()),
852 }))),
853
854 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
857 "APPROX_COUNT_DISTINCT".to_string(),
858 vec![f.this],
859 )))),
860
861 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
863 "MAX_BY".to_string(),
864 vec![*f.this, *f.expression],
865 )))),
866
867 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
869 "MIN_BY".to_string(),
870 vec![*f.this, *f.expression],
871 )))),
872
873 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
876
877 Expression::Rand(r) => Ok(Expression::Rand(r)),
879
880 Expression::Uuid(u) => Ok(Expression::Uuid(u)),
883
884 Expression::Map(f) => Ok(Expression::Function(Box::new(Function::new(
887 "OBJECT_CONSTRUCT".to_string(),
888 f.keys
889 .into_iter()
890 .zip(f.values.into_iter())
891 .flat_map(|(k, v)| vec![k, v])
892 .collect(),
893 )))),
894
895 Expression::MapFunc(f) => Ok(Expression::Function(Box::new(Function::new(
897 "OBJECT_CONSTRUCT".to_string(),
898 f.keys
899 .into_iter()
900 .zip(f.values.into_iter())
901 .flat_map(|(k, v)| vec![k, v])
902 .collect(),
903 )))),
904
905 Expression::VarMap(f) => Ok(Expression::Function(Box::new(Function::new(
907 "OBJECT_CONSTRUCT".to_string(),
908 f.keys
909 .into_iter()
910 .zip(f.values.into_iter())
911 .flat_map(|(k, v)| vec![k, v])
912 .collect(),
913 )))),
914
915 Expression::JsonObject(f) => Ok(Expression::Function(Box::new(Function::new(
918 "OBJECT_CONSTRUCT_KEEP_NULL".to_string(),
919 f.pairs.into_iter().flat_map(|(k, v)| vec![k, v]).collect(),
920 )))),
921
922 Expression::JsonExtractScalar(f) => Ok(Expression::Function(Box::new(Function::new(
924 "JSON_EXTRACT_PATH_TEXT".to_string(),
925 vec![f.this, f.path],
926 )))),
927
928 Expression::Struct(f) => Ok(Expression::Function(Box::new(Function::new(
931 "OBJECT_CONSTRUCT".to_string(),
932 f.fields
933 .into_iter()
934 .flat_map(|(name, expr)| {
935 let key = match name {
936 Some(n) => Expression::string(n),
937 None => Expression::Null(crate::expressions::Null),
938 };
939 vec![key, expr]
940 })
941 .collect(),
942 )))),
943
944 Expression::JSONPathRoot(_) => Ok(Expression::Literal(
947 crate::expressions::Literal::String(String::new()),
948 )),
949
950 Expression::VarSamp(agg) => Ok(Expression::Variance(agg)),
953
954 Expression::VarPop(agg) => Ok(Expression::VarPop(agg)),
957
958 Expression::Extract(f) => {
961 use crate::expressions::DateTimeField;
962 let transformed_this = self.transform_expr(f.this)?;
964 let field_name = match &f.field {
965 DateTimeField::Year => "YEAR",
966 DateTimeField::Month => "MONTH",
967 DateTimeField::Day => "DAY",
968 DateTimeField::Hour => "HOUR",
969 DateTimeField::Minute => "MINUTE",
970 DateTimeField::Second => "SECOND",
971 DateTimeField::Millisecond => "MILLISECOND",
972 DateTimeField::Microsecond => "MICROSECOND",
973 DateTimeField::Week => "WEEK",
974 DateTimeField::WeekWithModifier(m) => {
975 return Ok(Expression::Function(Box::new(Function::new(
976 "DATE_PART".to_string(),
977 vec![
978 Expression::Identifier(crate::expressions::Identifier {
979 name: format!("WEEK({})", m),
980 quoted: false,
981 trailing_comments: Vec::new(),
982 span: None,
983 }),
984 transformed_this,
985 ],
986 ))))
987 }
988 DateTimeField::DayOfWeek => "DAYOFWEEK",
989 DateTimeField::DayOfYear => "DAYOFYEAR",
990 DateTimeField::Quarter => "QUARTER",
991 DateTimeField::Epoch => "EPOCH",
992 DateTimeField::Timezone => "TIMEZONE",
993 DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
994 DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
995 DateTimeField::Date => "DATE",
996 DateTimeField::Time => "TIME",
997 DateTimeField::Custom(s) => {
998 match s.to_uppercase().as_str() {
1000 "DAYOFMONTH" => "DAY",
1001 "DOW" => "DAYOFWEEK",
1002 "DOY" => "DAYOFYEAR",
1003 "ISODOW" => "DAYOFWEEKISO",
1004 "EPOCH_SECOND" | "EPOCH_SECONDS" => "EPOCH_SECOND",
1005 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => "EPOCH_MILLISECOND",
1006 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => "EPOCH_MICROSECOND",
1007 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => "EPOCH_NANOSECOND",
1008 _ => {
1009 return {
1010 let field_ident =
1011 Expression::Identifier(crate::expressions::Identifier {
1012 name: s.to_string(),
1013 quoted: false,
1014 trailing_comments: Vec::new(),
1015 span: None,
1016 });
1017 Ok(Expression::Function(Box::new(Function::new(
1018 "DATE_PART".to_string(),
1019 vec![field_ident, transformed_this],
1020 ))))
1021 }
1022 }
1023 }
1024 }
1025 };
1026 let field_ident = Expression::Identifier(crate::expressions::Identifier {
1027 name: field_name.to_string(),
1028 quoted: false,
1029 trailing_comments: Vec::new(),
1030 span: None,
1031 });
1032 Ok(Expression::Function(Box::new(Function::new(
1033 "DATE_PART".to_string(),
1034 vec![field_ident, transformed_this],
1035 ))))
1036 }
1037
1038 Expression::Function(f) => self.transform_function(*f),
1040
1041 Expression::Sum(mut agg) => {
1043 agg.this = self.transform_expr(agg.this)?;
1044 Ok(Expression::Sum(agg))
1045 }
1046
1047 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
1049
1050 Expression::NamedArgument(na) => {
1052 let transformed_value = self.transform_expr(na.value)?;
1053 Ok(Expression::NamedArgument(Box::new(
1054 crate::expressions::NamedArgument {
1055 name: na.name,
1056 value: transformed_value,
1057 separator: na.separator,
1058 },
1059 )))
1060 }
1061
1062 Expression::CreateTable(mut ct) => {
1064 for col in &mut ct.columns {
1065 if let Expression::DataType(new_dt) =
1066 self.transform_data_type(col.data_type.clone())?
1067 {
1068 col.data_type = new_dt;
1069 }
1070 if let Some(default_expr) = col.default.take() {
1072 col.default = Some(self.transform_expr(default_expr)?);
1073 }
1074 for constraint in &mut col.constraints {
1076 if let crate::expressions::ColumnConstraint::ComputedColumn(cc) = constraint
1077 {
1078 let transformed = self.transform_expr(*cc.expression.clone())?;
1079 cc.expression = Box::new(transformed);
1080 }
1081 }
1082 }
1083
1084 if ct.table_modifier.as_deref() == Some("EXTERNAL")
1087 && !ct.with_properties.is_empty()
1088 {
1089 for (key, value) in ct.with_properties.drain(..) {
1090 let formatted = Self::format_external_table_property(&key, &value);
1091 ct.properties
1092 .push(Expression::Raw(crate::expressions::Raw { sql: formatted }));
1093 }
1094 }
1095
1096 Ok(Expression::CreateTable(ct))
1097 }
1098
1099 Expression::AlterTable(mut at) => {
1101 for action in &mut at.actions {
1102 if let crate::expressions::AlterTableAction::AddColumn { column, .. } = action {
1103 if let Expression::DataType(new_dt) =
1104 self.transform_data_type(column.data_type.clone())?
1105 {
1106 column.data_type = new_dt;
1107 }
1108 }
1109 }
1110 Ok(Expression::AlterTable(at))
1111 }
1112
1113 Expression::Table(mut t) => {
1115 if let Some(when) = t.when.take() {
1116 let transformed_expr = self.transform_expr(*when.expression)?;
1118 t.when = Some(Box::new(crate::expressions::HistoricalData {
1119 this: when.this,
1120 kind: when.kind,
1121 expression: Box::new(transformed_expr),
1122 }));
1123 }
1124 Ok(Expression::Table(t))
1125 }
1126
1127 Expression::Subscript(s) => {
1129 let transformed_this = self.transform_expr(s.this)?;
1130 let transformed_index = self.transform_expr(s.index)?;
1131 Ok(Expression::Subscript(Box::new(
1132 crate::expressions::Subscript {
1133 this: transformed_this,
1134 index: transformed_index,
1135 },
1136 )))
1137 }
1138
1139 Expression::Paren(p) => {
1141 let transformed = self.transform_expr(p.this)?;
1142 Ok(Expression::Paren(Box::new(crate::expressions::Paren {
1143 this: transformed,
1144 trailing_comments: p.trailing_comments,
1145 })))
1146 }
1147
1148 Expression::Select(mut select) => {
1152 if let Some(ref mut order) = select.order_by {
1153 for ord in &mut order.expressions {
1154 if ord.nulls_first.is_none() {
1155 ord.nulls_first = Some(ord.desc);
1156 }
1157 }
1158 }
1159 Ok(Expression::Select(select))
1160 }
1161
1162 Expression::WindowFunction(mut wf) => {
1164 for ord in &mut wf.over.order_by {
1165 if ord.nulls_first.is_none() {
1166 ord.nulls_first = Some(ord.desc);
1167 }
1168 }
1169 Ok(Expression::WindowFunction(wf))
1170 }
1171
1172 Expression::Window(mut w) => {
1174 for ord in &mut w.order_by {
1175 if ord.nulls_first.is_none() {
1176 ord.nulls_first = Some(ord.desc);
1177 }
1178 }
1179 Ok(Expression::Window(w))
1180 }
1181
1182 Expression::Lateral(mut lat) => {
1184 let is_flatten = match lat.this.as_ref() {
1186 Expression::Function(f) => f.name.to_uppercase() == "FLATTEN",
1187 _ => false,
1188 };
1189 if is_flatten && lat.column_aliases.is_empty() {
1190 lat.column_aliases = vec![
1192 "SEQ".to_string(),
1193 "KEY".to_string(),
1194 "PATH".to_string(),
1195 "INDEX".to_string(),
1196 "VALUE".to_string(),
1197 "THIS".to_string(),
1198 ];
1199 if lat.alias.is_none() {
1201 lat.alias = Some("_flattened".to_string());
1202 }
1203 }
1204 Ok(Expression::Lateral(lat))
1205 }
1206
1207 _ => Ok(expr),
1209 }
1210 }
1211}
1212
1213impl SnowflakeDialect {
1214 fn format_external_table_property(key: &str, value: &str) -> String {
1217 let lower_key = key.to_lowercase();
1218 match lower_key.as_str() {
1219 "location" => format!("LOCATION={}", value),
1220 "file_format" => {
1221 let formatted_value = Self::format_file_format_value(value);
1223 format!("FILE_FORMAT={}", formatted_value)
1224 }
1225 _ => format!("{}={}", key, value),
1226 }
1227 }
1228
1229 fn format_file_format_value(value: &str) -> String {
1233 if !value.starts_with('(') {
1234 return value.to_string();
1235 }
1236 let inner = value[1..value.len() - 1].trim();
1238 let mut result = String::from("(");
1240 let mut parts: Vec<String> = Vec::new();
1241 let tokens: Vec<&str> = inner.split_whitespace().collect();
1243 let mut i = 0;
1244 while i < tokens.len() {
1245 let token = tokens[i];
1246 if i + 2 < tokens.len() && tokens[i + 1] == "=" {
1247 let val = Self::format_property_value(tokens[i + 2]);
1249 parts.push(format!("{}={}", token, val));
1250 i += 3;
1251 } else if token.contains('=') {
1252 let eq_pos = token.find('=').unwrap();
1254 let k = &token[..eq_pos];
1255 let v = Self::format_property_value(&token[eq_pos + 1..]);
1256 parts.push(format!("{}={}", k, v));
1257 i += 1;
1258 } else {
1259 parts.push(token.to_string());
1260 i += 1;
1261 }
1262 }
1263 result.push_str(&parts.join(" "));
1264 result.push(')');
1265 result
1266 }
1267
1268 fn format_property_value(value: &str) -> String {
1270 match value.to_lowercase().as_str() {
1271 "true" => "TRUE".to_string(),
1272 "false" => "FALSE".to_string(),
1273 _ => value.to_string(),
1274 }
1275 }
1276
1277 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1279 use crate::expressions::DataType;
1280 let transformed = match dt {
1281 DataType::Text => DataType::VarChar {
1283 length: None,
1284 parenthesized_length: false,
1285 },
1286 DataType::Struct { fields, .. } => {
1288 let _ = fields; DataType::Custom {
1291 name: "OBJECT".to_string(),
1292 }
1293 }
1294 DataType::Custom { name } => {
1296 let upper_name = name.to_uppercase();
1297 match upper_name.as_str() {
1298 "NVARCHAR" | "NCHAR" | "NATIONAL CHARACTER VARYING" | "NATIONAL CHAR" => {
1300 DataType::VarChar {
1301 length: None,
1302 parenthesized_length: false,
1303 }
1304 }
1305 "STRING" => DataType::VarChar {
1307 length: None,
1308 parenthesized_length: false,
1309 },
1310 "BIGDECIMAL" => DataType::Double {
1312 precision: None,
1313 scale: None,
1314 },
1315 "NESTED" => DataType::Custom {
1317 name: "OBJECT".to_string(),
1318 },
1319 "BYTEINT" => DataType::Int {
1321 length: None,
1322 integer_spelling: false,
1323 },
1324 "CHAR VARYING" | "CHARACTER VARYING" => DataType::VarChar {
1326 length: None,
1327 parenthesized_length: false,
1328 },
1329 "SQL_DOUBLE" => DataType::Double {
1331 precision: None,
1332 scale: None,
1333 },
1334 "SQL_VARCHAR" => DataType::VarChar {
1336 length: None,
1337 parenthesized_length: false,
1338 },
1339 "TIMESTAMP_NTZ" => DataType::Custom {
1341 name: "TIMESTAMPNTZ".to_string(),
1342 },
1343 "TIMESTAMP_LTZ" => DataType::Custom {
1345 name: "TIMESTAMPLTZ".to_string(),
1346 },
1347 "TIMESTAMP_TZ" => DataType::Custom {
1349 name: "TIMESTAMPTZ".to_string(),
1350 },
1351 "NCHAR VARYING" => DataType::VarChar {
1353 length: None,
1354 parenthesized_length: false,
1355 },
1356 "NUMBER" => DataType::Decimal {
1358 precision: Some(38),
1359 scale: Some(0),
1360 },
1361 _ if name.starts_with("NUMBER(") => {
1362 let inner = &name[7..name.len() - 1]; let parts: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1366 let precision = parts.first().and_then(|p| p.parse::<u32>().ok());
1367 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1368 DataType::Decimal { precision, scale }
1369 }
1370 _ => DataType::Custom { name },
1371 }
1372 }
1373 DataType::Decimal {
1375 precision: None,
1376 scale: None,
1377 } => DataType::Decimal {
1378 precision: Some(38),
1379 scale: Some(0),
1380 },
1381 DataType::Float { .. } => DataType::Double {
1383 precision: None,
1384 scale: None,
1385 },
1386 other => other,
1388 };
1389 Ok(Expression::DataType(transformed))
1390 }
1391
1392 fn map_date_part(abbr: &str) -> Option<&'static str> {
1394 match abbr.to_uppercase().as_str() {
1395 "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some("YEAR"),
1397 "MM" | "MON" | "MONS" | "MONTHS" => Some("MONTH"),
1399 "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some("DAY"),
1401 "DAY OF WEEK" | "WEEKDAY" | "DOW" | "DW" => Some("DAYOFWEEK"),
1403 "WEEKDAY_ISO" | "DOW_ISO" | "DW_ISO" | "DAYOFWEEK_ISO" => Some("DAYOFWEEKISO"),
1404 "DAY OF YEAR" | "DOY" | "DY" => Some("DAYOFYEAR"),
1406 "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY" => Some("WEEK"),
1408 "WEEK_ISO" | "WEEKOFYEARISO" | "WEEKOFYEAR_ISO" => Some("WEEKISO"),
1409 "Q" | "QTR" | "QTRS" | "QUARTERS" => Some("QUARTER"),
1411 "H" | "HH" | "HR" | "HOURS" | "HRS" => Some("HOUR"),
1413 "MI" | "MIN" | "MINUTES" | "MINS" => Some("MINUTE"),
1415 "S" | "SEC" | "SECONDS" | "SECS" => Some("SECOND"),
1417 "MS" | "MSEC" | "MSECS" | "MSECOND" | "MSECONDS" | "MILLISEC" | "MILLISECS"
1419 | "MILLISECON" | "MILLISECONDS" => Some("MILLISECOND"),
1420 "US" | "USEC" | "USECS" | "MICROSEC" | "MICROSECS" | "USECOND" | "USECONDS"
1422 | "MICROSECONDS" => Some("MICROSECOND"),
1423 "NS" | "NSEC" | "NANOSEC" | "NSECOND" | "NSECONDS" | "NANOSECS" => Some("NANOSECOND"),
1425 "EPOCH_SECOND" | "EPOCH_SECONDS" => Some("EPOCH_SECOND"),
1427 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Some("EPOCH_MILLISECOND"),
1428 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Some("EPOCH_MICROSECOND"),
1429 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Some("EPOCH_NANOSECOND"),
1430 "TZH" => Some("TIMEZONE_HOUR"),
1432 "TZM" => Some("TIMEZONE_MINUTE"),
1433 "DEC" | "DECS" | "DECADES" => Some("DECADE"),
1435 "MIL" | "MILS" | "MILLENIA" => Some("MILLENNIUM"),
1437 "C" | "CENT" | "CENTS" | "CENTURIES" => Some("CENTURY"),
1439 _ => None,
1441 }
1442 }
1443
1444 fn transform_date_part_arg(&self, expr: Expression) -> Expression {
1446 match &expr {
1447 Expression::Literal(crate::expressions::Literal::String(s)) => {
1449 Expression::Identifier(crate::expressions::Identifier {
1450 name: s.clone(),
1451 quoted: false,
1452 trailing_comments: Vec::new(),
1453 span: None,
1454 })
1455 }
1456 Expression::Identifier(id) => {
1458 if let Some(canonical) = Self::map_date_part(&id.name) {
1459 Expression::Identifier(crate::expressions::Identifier {
1460 name: canonical.to_string(),
1461 quoted: false,
1462 trailing_comments: Vec::new(),
1463 span: None,
1464 })
1465 } else {
1466 expr
1468 }
1469 }
1470 Expression::Column(col) if col.table.is_none() => {
1472 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1473 Expression::Identifier(crate::expressions::Identifier {
1474 name: canonical.to_string(),
1475 quoted: false,
1476 trailing_comments: Vec::new(),
1477 span: None,
1478 })
1479 } else {
1480 expr
1482 }
1483 }
1484 _ => expr,
1485 }
1486 }
1487
1488 fn transform_date_part_arg_identifiers_only(&self, expr: Expression) -> Expression {
1491 match &expr {
1492 Expression::Identifier(id) => {
1493 if let Some(canonical) = Self::map_date_part(&id.name) {
1494 Expression::Identifier(crate::expressions::Identifier {
1495 name: canonical.to_string(),
1496 quoted: false,
1497 trailing_comments: Vec::new(),
1498 span: None,
1499 })
1500 } else {
1501 expr
1502 }
1503 }
1504 Expression::Column(col) if col.table.is_none() => {
1505 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1506 Expression::Identifier(crate::expressions::Identifier {
1507 name: canonical.to_string(),
1508 quoted: false,
1509 trailing_comments: Vec::new(),
1510 span: None,
1511 })
1512 } else {
1513 expr
1514 }
1515 }
1516 _ => expr,
1517 }
1518 }
1519
1520 fn transform_json_path(path: &str) -> String {
1524 fn is_safe_identifier(s: &str) -> bool {
1527 if s.is_empty() {
1528 return false;
1529 }
1530 let mut chars = s.chars();
1531 match chars.next() {
1532 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
1533 _ => return false,
1534 }
1535 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
1536 }
1537
1538 if !path.contains('.') && !path.contains('[') && !path.contains(':') {
1541 if is_safe_identifier(path) {
1542 return path.to_string();
1543 } else {
1544 return format!("[\"{}\"]", path);
1546 }
1547 }
1548
1549 let result = path.replace(':', ".");
1552 result
1553 }
1554
1555 fn transform_interval(&self, interval: crate::expressions::Interval) -> Result<Expression> {
1557 use crate::expressions::{Interval, Literal};
1558
1559 fn expand_unit(abbr: &str) -> &'static str {
1561 match abbr.to_uppercase().as_str() {
1562 "D" => "DAY",
1563 "H" => "HOUR",
1564 "M" => "MINUTE",
1565 "MS" => "MILLISECOND",
1566 "NS" => "NANOSECOND",
1567 "Q" => "QUARTER",
1568 "S" => "SECOND",
1569 "US" => "MICROSECOND",
1570 "W" => "WEEK",
1571 "Y" => "YEAR",
1572 "WEEK" | "WEEKS" => "WEEK",
1574 "DAY" | "DAYS" => "DAY",
1575 "HOUR" | "HOURS" => "HOUR",
1576 "MINUTE" | "MINUTES" => "MINUTE",
1577 "SECOND" | "SECONDS" => "SECOND",
1578 "MONTH" | "MONTHS" => "MONTH",
1579 "YEAR" | "YEARS" => "YEAR",
1580 "QUARTER" | "QUARTERS" => "QUARTER",
1581 "MILLISECOND" | "MILLISECONDS" => "MILLISECOND",
1582 "MICROSECOND" | "MICROSECONDS" => "MICROSECOND",
1583 "NANOSECOND" | "NANOSECONDS" => "NANOSECOND",
1584 _ => "", }
1586 }
1587
1588 fn parse_interval_string(s: &str) -> Option<(&str, &str)> {
1590 let s = s.trim();
1591
1592 let mut num_end = 0;
1595 let mut chars = s.chars().peekable();
1596
1597 if chars.peek() == Some(&'-') {
1599 chars.next();
1600 num_end += 1;
1601 }
1602
1603 while let Some(&c) = chars.peek() {
1605 if c.is_ascii_digit() {
1606 chars.next();
1607 num_end += 1;
1608 } else {
1609 break;
1610 }
1611 }
1612
1613 if chars.peek() == Some(&'.') {
1615 chars.next();
1616 num_end += 1;
1617 while let Some(&c) = chars.peek() {
1618 if c.is_ascii_digit() {
1619 chars.next();
1620 num_end += 1;
1621 } else {
1622 break;
1623 }
1624 }
1625 }
1626
1627 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1628 return None; }
1630
1631 let value = &s[..num_end];
1632 let rest = s[num_end..].trim();
1633
1634 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1636 return None;
1637 }
1638
1639 Some((value, rest))
1640 }
1641
1642 if let Some(Expression::Literal(Literal::String(ref s))) = interval.this {
1644 if let Some((value, unit)) = parse_interval_string(s) {
1645 let expanded = expand_unit(unit);
1646 if !expanded.is_empty() {
1647 let new_value = format!("{} {}", value, expanded);
1649
1650 return Ok(Expression::Interval(Box::new(Interval {
1651 this: Some(Expression::Literal(Literal::String(new_value))),
1652 unit: None, })));
1654 }
1655 }
1656 }
1657
1658 Ok(Expression::Interval(Box::new(interval)))
1660 }
1661
1662 fn transform_function(&self, f: Function) -> Result<Expression> {
1663 let transformed_args: Vec<Expression> = f
1665 .args
1666 .into_iter()
1667 .map(|arg| self.transform_expr(arg))
1668 .collect::<Result<Vec<_>>>()?;
1669
1670 let f = Function {
1671 name: f.name,
1672 args: transformed_args,
1673 distinct: f.distinct,
1674 trailing_comments: f.trailing_comments,
1675 use_bracket_syntax: f.use_bracket_syntax,
1676 no_parens: f.no_parens,
1677 quoted: f.quoted,
1678 span: None,
1679 };
1680
1681 let name_upper = f.name.to_uppercase();
1682 match name_upper.as_str() {
1683 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1685 original_name: None,
1686 expressions: f.args,
1687 }))),
1688
1689 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1691 original_name: None,
1692 expressions: f.args,
1693 }))),
1694
1695 "NVL2" => Ok(Expression::Function(Box::new(f))),
1697
1698 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1700 Function::new("LISTAGG".to_string(), f.args),
1701 ))),
1702
1703 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1705 Function::new("LISTAGG".to_string(), f.args),
1706 ))),
1707
1708 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1710 "SUBSTRING".to_string(),
1711 f.args,
1712 )))),
1713
1714 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
1716 "FLATTEN".to_string(),
1717 f.args,
1718 )))),
1719
1720 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1722 "FLATTEN".to_string(),
1723 f.args,
1724 )))),
1725
1726 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1728
1729 "NOW" => Ok(Expression::Function(Box::new(Function {
1731 name: "CURRENT_TIMESTAMP".to_string(),
1732 args: f.args,
1733 distinct: false,
1734 trailing_comments: Vec::new(),
1735 use_bracket_syntax: false,
1736 no_parens: f.no_parens,
1737 quoted: false,
1738 span: None,
1739 }))),
1740
1741 "GETDATE" => Ok(Expression::Function(Box::new(Function {
1743 name: "CURRENT_TIMESTAMP".to_string(),
1744 args: f.args,
1745 distinct: false,
1746 trailing_comments: Vec::new(),
1747 use_bracket_syntax: false,
1748 no_parens: f.no_parens,
1749 quoted: false,
1750 span: None,
1751 }))),
1752
1753 "CURRENT_TIMESTAMP" if f.args.is_empty() => {
1757 Ok(Expression::Function(Box::new(Function {
1758 name: "CURRENT_TIMESTAMP".to_string(),
1759 args: Vec::new(),
1760 distinct: false,
1761 trailing_comments: Vec::new(),
1762 use_bracket_syntax: false,
1763 no_parens: false, quoted: false,
1765 span: None,
1766 })))
1767 }
1768
1769 "TO_DATE" => {
1773 if f.args.len() == 1 {
1774 if let Expression::Literal(crate::expressions::Literal::String(s)) = &f.args[0]
1775 {
1776 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
1778 return Ok(Expression::Cast(Box::new(Cast {
1779 this: f.args.into_iter().next().unwrap(),
1780 to: crate::expressions::DataType::Date,
1781 double_colon_syntax: false,
1782 trailing_comments: Vec::new(),
1783 format: None,
1784 default: None,
1785 })));
1786 }
1787 }
1788 }
1789 let mut args = f.args;
1791 if args.len() >= 2 {
1792 args[1] = Self::normalize_format_arg(args[1].clone());
1793 }
1794 Ok(Expression::Function(Box::new(Function::new(
1795 "TO_DATE".to_string(),
1796 args,
1797 ))))
1798 }
1799
1800 "TO_TIME" => {
1802 if f.args.len() == 1 {
1803 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
1804 {
1805 return Ok(Expression::Cast(Box::new(Cast {
1806 this: f.args.into_iter().next().unwrap(),
1807 to: crate::expressions::DataType::Time {
1808 precision: None,
1809 timezone: false,
1810 },
1811 double_colon_syntax: false,
1812 trailing_comments: Vec::new(),
1813 format: None,
1814 default: None,
1815 })));
1816 }
1817 }
1818 let mut args = f.args;
1820 if args.len() >= 2 {
1821 args[1] = Self::normalize_format_arg(args[1].clone());
1822 }
1823 Ok(Expression::Function(Box::new(Function::new(
1824 "TO_TIME".to_string(),
1825 args,
1826 ))))
1827 }
1828
1829 "TO_TIMESTAMP" => {
1836 let args = f.args;
1837 if args.len() == 1 {
1838 let arg = &args[0];
1839 match arg {
1840 Expression::Literal(Literal::String(s)) if Self::looks_like_datetime(s) => {
1841 return Ok(Expression::Cast(Box::new(Cast {
1843 this: args.into_iter().next().unwrap(),
1844 to: DataType::Timestamp {
1845 precision: None,
1846 timezone: false,
1847 },
1848 double_colon_syntax: false,
1849 trailing_comments: vec![],
1850 format: None,
1851 default: None,
1852 })));
1853 }
1854 Expression::Literal(Literal::String(s)) if Self::looks_like_epoch(s) => {
1855 return Ok(Expression::UnixToTime(Box::new(
1857 crate::expressions::UnixToTime {
1858 this: Box::new(args.into_iter().next().unwrap()),
1859 scale: None,
1860 zone: None,
1861 hours: None,
1862 minutes: None,
1863 format: None,
1864 target_type: None,
1865 },
1866 )));
1867 }
1868 Expression::Literal(Literal::Number(_)) | Expression::Neg(_) => {
1869 return Ok(Expression::UnixToTime(Box::new(
1871 crate::expressions::UnixToTime {
1872 this: Box::new(args.into_iter().next().unwrap()),
1873 scale: None,
1874 zone: None,
1875 hours: None,
1876 minutes: None,
1877 format: None,
1878 target_type: None,
1879 },
1880 )));
1881 }
1882 _ => {
1883 return Ok(Expression::Function(Box::new(Function::new(
1885 "TO_TIMESTAMP".to_string(),
1886 args,
1887 ))));
1888 }
1889 }
1890 } else if args.len() == 2 {
1891 let second_arg = &args[1];
1892 let is_int_scale = match second_arg {
1894 Expression::Literal(Literal::Number(n)) => n.parse::<i64>().is_ok(),
1895 _ => false,
1896 };
1897
1898 if is_int_scale {
1899 let mut args_iter = args.into_iter();
1901 let value = args_iter.next().unwrap();
1902 let scale_expr = args_iter.next().unwrap();
1903 let scale = if let Expression::Literal(Literal::Number(n)) = &scale_expr {
1904 n.parse::<i64>().ok()
1905 } else {
1906 None
1907 };
1908 return Ok(Expression::UnixToTime(Box::new(
1909 crate::expressions::UnixToTime {
1910 this: Box::new(value),
1911 scale,
1912 zone: None,
1913 hours: None,
1914 minutes: None,
1915 format: None,
1916 target_type: None,
1917 },
1918 )));
1919 } else {
1920 let mut args_iter = args.into_iter();
1922 let value = args_iter.next().unwrap();
1923 let format_expr = args_iter.next().unwrap();
1924 let format_str = match &format_expr {
1925 Expression::Literal(Literal::String(s)) => s.clone(),
1926 _ => {
1927 return Ok(Expression::Function(Box::new(Function::new(
1929 "TO_TIMESTAMP".to_string(),
1930 vec![value, format_expr],
1931 ))));
1932 }
1933 };
1934 let normalized_format = Self::normalize_snowflake_format(&format_str);
1936 return Ok(Expression::StrToTime(Box::new(
1937 crate::expressions::StrToTime {
1938 this: Box::new(value),
1939 format: normalized_format,
1940 zone: None,
1941 safe: None,
1942 target_type: None,
1943 },
1944 )));
1945 }
1946 }
1947 Ok(Expression::Function(Box::new(Function::new(
1949 "TO_TIMESTAMP".to_string(),
1950 args,
1951 ))))
1952 }
1953
1954 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
1956
1957 "ROUND"
1960 if f.args
1961 .iter()
1962 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
1963 {
1964 let mut expr_val = None;
1965 let mut scale_val = None;
1966 let mut rounding_mode_val = None;
1967 for arg in &f.args {
1968 if let Expression::NamedArgument(na) = arg {
1969 match na.name.name.to_uppercase().as_str() {
1970 "EXPR" => expr_val = Some(na.value.clone()),
1971 "SCALE" => scale_val = Some(na.value.clone()),
1972 "ROUNDING_MODE" => rounding_mode_val = Some(na.value.clone()),
1973 _ => {}
1974 }
1975 }
1976 }
1977 if let Some(expr) = expr_val {
1978 let mut args = vec![expr];
1979 if let Some(scale) = scale_val {
1980 args.push(scale);
1981 }
1982 if let Some(mode) = rounding_mode_val {
1983 args.push(mode);
1984 }
1985 Ok(Expression::Function(Box::new(Function::new(
1986 "ROUND".to_string(),
1987 args,
1988 ))))
1989 } else {
1990 Ok(Expression::Function(Box::new(f)))
1991 }
1992 }
1993
1994 "DATE_FORMAT" => {
1997 let mut args = f.args;
1998 if !args.is_empty() {
2000 if matches!(&args[0], Expression::Literal(Literal::String(_))) {
2001 args[0] = Expression::Cast(Box::new(crate::expressions::Cast {
2002 this: args[0].clone(),
2003 to: DataType::Timestamp {
2004 precision: None,
2005 timezone: false,
2006 },
2007 trailing_comments: Vec::new(),
2008 double_colon_syntax: false,
2009 format: None,
2010 default: None,
2011 }));
2012 }
2013 }
2014 if args.len() >= 2 {
2016 if let Expression::Literal(Literal::String(ref fmt)) = args[1] {
2017 let sf_fmt = strftime_to_snowflake_format(fmt);
2018 args[1] = Expression::Literal(Literal::String(sf_fmt));
2019 }
2020 }
2021 Ok(Expression::Function(Box::new(Function::new(
2022 "TO_CHAR".to_string(),
2023 args,
2024 ))))
2025 }
2026
2027 "ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2029 "ARRAY_CONSTRUCT".to_string(),
2030 f.args,
2031 )))),
2032
2033 "STRUCT" => {
2036 let mut oc_args = Vec::new();
2037 for arg in f.args {
2038 match arg {
2039 Expression::Alias(a) => {
2040 oc_args.push(Expression::Literal(crate::expressions::Literal::String(
2042 a.alias.name.clone(),
2043 )));
2044 oc_args.push(a.this);
2045 }
2046 other => {
2047 oc_args.push(other);
2049 }
2050 }
2051 }
2052 Ok(Expression::Function(Box::new(Function::new(
2053 "OBJECT_CONSTRUCT".to_string(),
2054 oc_args,
2055 ))))
2056 }
2057
2058 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2060 "GET_PATH".to_string(),
2061 f.args,
2062 )))),
2063
2064 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2066 "JSON_EXTRACT_PATH_TEXT".to_string(),
2067 f.args,
2068 )))),
2069
2070 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2072 f.args.into_iter().next().unwrap(),
2073 )))),
2074
2075 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2077 this: f.args.into_iter().next().unwrap(),
2078 decimals: None,
2079 to: None,
2080 }))),
2081
2082 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2084
2085 "SPLIT" => Ok(Expression::Function(Box::new(f))),
2087
2088 "ARRAY_AGG" => Ok(Expression::Function(Box::new(f))),
2090
2091 "JSON_PARSE" | "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2093 "PARSE_JSON".to_string(),
2094 f.args,
2095 )))),
2096
2097 "RAND" => {
2099 let seed = f.args.first().cloned().map(Box::new);
2100 Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2101 seed,
2102 lower: None,
2103 upper: None,
2104 })))
2105 }
2106
2107 "SHA" => Ok(Expression::Function(Box::new(Function::new(
2109 "SHA1".to_string(),
2110 f.args,
2111 )))),
2112
2113 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
2115 "APPROX_COUNT_DISTINCT".to_string(),
2116 f.args,
2117 )))),
2118
2119 "GEN_RANDOM_UUID" | "UUID" => {
2121 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2122 this: None,
2123 name: None,
2124 is_string: None,
2125 })))
2126 }
2127
2128 "NEWID" => Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2130 this: None,
2131 name: None,
2132 is_string: None,
2133 }))),
2134
2135 "UUID_STRING" => {
2137 if f.args.is_empty() {
2138 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2139 this: None,
2140 name: None,
2141 is_string: None,
2142 })))
2143 } else {
2144 Ok(Expression::Function(Box::new(Function::new(
2145 "UUID_STRING".to_string(),
2146 f.args,
2147 ))))
2148 }
2149 }
2150
2151 "IF" if f.args.len() >= 2 => {
2153 let mut args = f.args;
2154 let condition = args.remove(0);
2155 let true_val = args.remove(0);
2156 let false_val = if !args.is_empty() {
2157 Some(args.remove(0))
2158 } else {
2159 None
2160 };
2161 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2162 condition,
2163 true_value: true_val,
2164 false_value: Some(
2165 false_val.unwrap_or(Expression::Null(crate::expressions::Null)),
2166 ),
2167 original_name: Some("IFF".to_string()),
2168 })))
2169 }
2170
2171 "SQUARE" if f.args.len() == 1 => {
2173 let x = f.args.into_iter().next().unwrap();
2174 Ok(Expression::Power(Box::new(
2175 crate::expressions::BinaryFunc {
2176 original_name: None,
2177 this: x,
2178 expression: Expression::number(2),
2179 },
2180 )))
2181 }
2182
2183 "POW" if f.args.len() == 2 => {
2185 let mut args = f.args.into_iter();
2186 let x = args.next().unwrap();
2187 let y = args.next().unwrap();
2188 Ok(Expression::Power(Box::new(
2189 crate::expressions::BinaryFunc {
2190 original_name: None,
2191 this: x,
2192 expression: y,
2193 },
2194 )))
2195 }
2196
2197 "MOD" if f.args.len() == 2 => {
2199 let mut args = f.args.into_iter();
2200 let x = args.next().unwrap();
2201 let y = args.next().unwrap();
2202 Ok(Expression::Mod(Box::new(crate::expressions::BinaryOp {
2203 left: x,
2204 right: y,
2205 left_comments: Vec::new(),
2206 operator_comments: Vec::new(),
2207 trailing_comments: Vec::new(),
2208 })))
2209 }
2210
2211 "APPROXIMATE_JACCARD_INDEX" => Ok(Expression::Function(Box::new(Function::new(
2213 "APPROXIMATE_SIMILARITY".to_string(),
2214 f.args,
2215 )))),
2216
2217 "ARRAY_CONSTRUCT" => Ok(Expression::ArrayFunc(Box::new(
2219 crate::expressions::ArrayConstructor {
2220 expressions: f.args,
2221 bracket_notation: true,
2222 use_list_keyword: false,
2223 },
2224 ))),
2225
2226 "APPROX_TOP_K" if f.args.len() == 1 => {
2228 let mut args = f.args;
2229 args.push(Expression::number(1));
2230 Ok(Expression::Function(Box::new(Function::new(
2231 "APPROX_TOP_K".to_string(),
2232 args,
2233 ))))
2234 }
2235
2236 "TO_DECIMAL" | "TO_NUMERIC" => Ok(Expression::Function(Box::new(Function::new(
2238 "TO_NUMBER".to_string(),
2239 f.args,
2240 )))),
2241
2242 "TRY_TO_DECIMAL" | "TRY_TO_NUMERIC" => Ok(Expression::Function(Box::new(
2244 Function::new("TRY_TO_NUMBER".to_string(), f.args),
2245 ))),
2246
2247 "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2249 "STDDEV".to_string(),
2250 f.args,
2251 )))),
2252
2253 "STRTOK" if f.args.len() >= 1 => {
2255 let mut args = f.args;
2256 if args.len() == 1 {
2258 args.push(Expression::string(" ".to_string()));
2259 }
2260 if args.len() == 2 {
2262 args.push(Expression::number(1));
2263 }
2264 Ok(Expression::Function(Box::new(Function::new(
2265 "SPLIT_PART".to_string(),
2266 args,
2267 ))))
2268 }
2269
2270 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2272 "WEEK".to_string(),
2273 f.args,
2274 )))),
2275
2276 "LIKE" if f.args.len() >= 2 => {
2278 let mut args = f.args.into_iter();
2279 let left = args.next().unwrap();
2280 let right = args.next().unwrap();
2281 let escape = args.next();
2282 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2283 left,
2284 right,
2285 escape,
2286 quantifier: None,
2287 })))
2288 }
2289
2290 "ILIKE" if f.args.len() >= 2 => {
2292 let mut args = f.args.into_iter();
2293 let left = args.next().unwrap();
2294 let right = args.next().unwrap();
2295 let escape = args.next();
2296 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2297 left,
2298 right,
2299 escape,
2300 quantifier: None,
2301 })))
2302 }
2303
2304 "RLIKE" if f.args.len() >= 2 => {
2306 let mut args = f.args.into_iter();
2307 let left = args.next().unwrap();
2308 let pattern = args.next().unwrap();
2309 let flags = args.next();
2310 Ok(Expression::RegexpLike(Box::new(
2311 crate::expressions::RegexpFunc {
2312 this: left,
2313 pattern,
2314 flags,
2315 },
2316 )))
2317 }
2318
2319 "IFF" if f.args.len() >= 2 => {
2321 let mut args = f.args;
2322 let condition = args.remove(0);
2323 let true_value = args.remove(0);
2324 let false_value = if !args.is_empty() {
2325 Some(args.remove(0))
2326 } else {
2327 None
2328 };
2329 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2330 condition,
2331 true_value,
2332 false_value,
2333 original_name: Some("IFF".to_string()),
2334 })))
2335 }
2336
2337 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2339 Ok(Expression::Function(Box::new(Function::new(
2340 "TIMESTAMP_FROM_PARTS".to_string(),
2341 f.args,
2342 ))))
2343 }
2344
2345 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2347 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2348 f.args,
2349 )))),
2350
2351 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2353 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2354 f.args,
2355 )))),
2356
2357 "DATEADD" if f.args.len() >= 1 => {
2359 let mut args = f.args;
2360 args[0] = self.transform_date_part_arg(args[0].clone());
2361 Ok(Expression::Function(Box::new(Function::new(
2362 "DATEADD".to_string(),
2363 args,
2364 ))))
2365 }
2366
2367 "DATEDIFF" if f.args.len() >= 1 => {
2370 let mut args = f.args;
2371 args[0] = self.transform_date_part_arg(args[0].clone());
2372 for i in 1..args.len() {
2375 if let Expression::Function(ref func) = args[i] {
2376 if func.name == "_POLYGLOT_TO_DATE" {
2377 let inner_args = func.args.clone();
2378 args[i] = Expression::Function(Box::new(Function::new(
2379 "TO_DATE".to_string(),
2380 inner_args,
2381 )));
2382 }
2383 }
2384 }
2385 Ok(Expression::Function(Box::new(Function::new(
2386 "DATEDIFF".to_string(),
2387 args,
2388 ))))
2389 }
2390
2391 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2393 "DATEDIFF".to_string(),
2394 f.args,
2395 )))),
2396
2397 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2399 "DATEDIFF".to_string(),
2400 f.args,
2401 )))),
2402
2403 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2405 "DATEADD".to_string(),
2406 f.args,
2407 )))),
2408
2409 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2411
2412 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2414 "DATE_FROM_PARTS".to_string(),
2415 f.args,
2416 )))),
2417
2418 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2420 "TIME_FROM_PARTS".to_string(),
2421 f.args,
2422 )))),
2423
2424 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2426
2427 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2429
2430 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2432
2433 "MONTHNAME" if f.args.len() == 1 => {
2436 let arg = f.args.into_iter().next().unwrap();
2437 Ok(Expression::Monthname(Box::new(
2438 crate::expressions::Monthname {
2439 this: Box::new(arg),
2440 abbreviated: Some(Box::new(Expression::Literal(Literal::String(
2441 "true".to_string(),
2442 )))),
2443 },
2444 )))
2445 }
2446
2447 "DAYNAME" if f.args.len() == 1 => {
2450 let arg = f.args.into_iter().next().unwrap();
2451 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2452 this: Box::new(arg),
2453 abbreviated: Some(Box::new(Expression::Literal(Literal::String(
2454 "true".to_string(),
2455 )))),
2456 })))
2457 }
2458
2459 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2461 let arg = f.args.into_iter().next().unwrap();
2462 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2463 this: arg,
2464 distinct: false,
2465 filter: None,
2466 order_by: Vec::new(),
2467 name: Some("BOOLAND_AGG".to_string()),
2468 ignore_nulls: None,
2469 having_max: None,
2470 limit: None,
2471 })))
2472 }
2473
2474 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2476 let arg = f.args.into_iter().next().unwrap();
2477 Ok(Expression::LogicalOr(Box::new(AggFunc {
2478 this: arg,
2479 distinct: false,
2480 filter: None,
2481 order_by: Vec::new(),
2482 name: Some("BOOLOR_AGG".to_string()),
2483 ignore_nulls: None,
2484 having_max: None,
2485 limit: None,
2486 })))
2487 }
2488
2489 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2491 let arg = f.args.into_iter().next().unwrap();
2492 Ok(Expression::Skewness(Box::new(AggFunc {
2493 this: arg,
2494 distinct: false,
2495 filter: None,
2496 order_by: Vec::new(),
2497 name: Some("SKEW".to_string()),
2498 ignore_nulls: None,
2499 having_max: None,
2500 limit: None,
2501 })))
2502 }
2503
2504 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2506 "VARIANCE".to_string(),
2507 f.args,
2508 )))),
2509
2510 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2512 "VARIANCE_POP".to_string(),
2513 f.args,
2514 )))),
2515
2516 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2518 "TO_DATE".to_string(),
2519 f.args,
2520 )))),
2521 "DATE" if f.args.len() >= 2 => {
2525 let mut args = f.args;
2526 args[1] = Self::normalize_format_arg(args[1].clone());
2527 Ok(Expression::Function(Box::new(Function::new(
2528 "TO_DATE".to_string(),
2529 args,
2530 ))))
2531 }
2532 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2535 let mut args = f.args;
2536 args[1] = Self::normalize_format_arg(args[1].clone());
2537 Ok(Expression::Function(Box::new(Function::new(
2538 "DATE".to_string(),
2539 args,
2540 ))))
2541 }
2542
2543 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2545
2546 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2548 "MD5".to_string(),
2549 f.args,
2550 )))),
2551
2552 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2554 "SHA1".to_string(),
2555 f.args,
2556 )))),
2557
2558 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2560 "SHA2".to_string(),
2561 f.args,
2562 )))),
2563
2564 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2566 "EDITDISTANCE".to_string(),
2567 f.args,
2568 )))),
2569
2570 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2572 "BITNOT".to_string(),
2573 f.args,
2574 )))),
2575
2576 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2578 "BITAND".to_string(),
2579 f.args,
2580 )))),
2581
2582 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2584 "BITOR".to_string(),
2585 f.args,
2586 )))),
2587
2588 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2590 "BITXOR".to_string(),
2591 f.args,
2592 )))),
2593
2594 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2596 Function::new("BITSHIFTLEFT".to_string(), f.args),
2597 ))),
2598
2599 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2601 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2602 ))),
2603
2604 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2606 name: "CURRENT_TIMESTAMP".to_string(),
2607 args: f.args,
2608 distinct: false,
2609 trailing_comments: Vec::new(),
2610 use_bracket_syntax: false,
2611 no_parens: f.no_parens,
2612 quoted: false,
2613 span: None,
2614 }))),
2615
2616 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2618 name: "CURRENT_TIMESTAMP".to_string(),
2619 args: f.args,
2620 distinct: false,
2621 trailing_comments: Vec::new(),
2622 use_bracket_syntax: false,
2623 no_parens: f.no_parens,
2624 quoted: false,
2625 span: None,
2626 }))),
2627
2628 "SPACE" if f.args.len() == 1 => {
2630 let arg = f.args.into_iter().next().unwrap();
2631 Ok(Expression::Function(Box::new(Function::new(
2632 "REPEAT".to_string(),
2633 vec![Expression::Literal(Literal::String(" ".to_string())), arg],
2634 ))))
2635 }
2636
2637 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2639 "CEIL".to_string(),
2640 f.args,
2641 )))),
2642
2643 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2645 "LN".to_string(),
2646 f.args,
2647 )))),
2648
2649 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(Function::new(
2651 "REGEXP_EXTRACT_ALL".to_string(),
2652 f.args,
2653 )))),
2654
2655 "GET_PATH" if f.args.len() >= 2 => {
2659 let mut args = f.args;
2660 if let Expression::Literal(crate::expressions::Literal::String(path)) = &args[1] {
2662 let transformed = Self::transform_json_path(path);
2663 args[1] = Expression::Literal(crate::expressions::Literal::String(transformed));
2664 }
2665 Ok(Expression::Function(Box::new(Function::new(
2666 "GET_PATH".to_string(),
2667 args,
2668 ))))
2669 }
2670 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2671
2672 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2674
2675 "DATE_TRUNC" if f.args.len() >= 1 => {
2678 let mut args = f.args;
2679 let unit_name = match &args[0] {
2681 Expression::Identifier(id) => Some(id.name.as_str()),
2682 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2683 _ => None,
2684 };
2685 if let Some(name) = unit_name {
2686 let canonical = Self::map_date_part(name).unwrap_or(name);
2687 args[0] = Expression::Literal(crate::expressions::Literal::String(
2688 canonical.to_uppercase(),
2689 ));
2690 }
2691 Ok(Expression::Function(Box::new(Function::new(
2692 "DATE_TRUNC".to_string(),
2693 args,
2694 ))))
2695 }
2696
2697 "DATE_PART" if f.args.len() >= 1 => {
2703 let mut args = f.args;
2704 let from_typed_literal = args.len() >= 2
2705 && matches!(
2706 &args[1],
2707 Expression::Literal(crate::expressions::Literal::Timestamp(_))
2708 | Expression::Literal(crate::expressions::Literal::Date(_))
2709 | Expression::Literal(crate::expressions::Literal::Time(_))
2710 | Expression::Literal(crate::expressions::Literal::Datetime(_))
2711 );
2712 if from_typed_literal {
2713 args[0] = self.transform_date_part_arg(args[0].clone());
2714 } else {
2715 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2718 }
2719 Ok(Expression::Function(Box::new(Function::new(
2720 "DATE_PART".to_string(),
2721 args,
2722 ))))
2723 }
2724
2725 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2727
2728 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2730
2731 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2733 "DESCRIBE".to_string(),
2734 f.args,
2735 )))),
2736
2737 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2739 "REGEXP_LIKE".to_string(),
2740 f.args,
2741 )))),
2742
2743 "TRANSFORM" => {
2748 let transformed_args: Vec<Expression> = f
2749 .args
2750 .into_iter()
2751 .map(|arg| {
2752 if let Expression::Lambda(lambda) = arg {
2753 self.transform_typed_lambda(*lambda)
2754 } else {
2755 arg
2756 }
2757 })
2758 .collect();
2759 Ok(Expression::Function(Box::new(Function::new(
2760 "TRANSFORM".to_string(),
2761 transformed_args,
2762 ))))
2763 }
2764
2765 "SEARCH" if f.args.len() >= 2 => {
2767 let mut args = f.args.into_iter();
2768 let this = Box::new(args.next().unwrap());
2769 let expression = Box::new(args.next().unwrap());
2770
2771 let mut analyzer: Option<Box<Expression>> = None;
2772 let mut search_mode: Option<Box<Expression>> = None;
2773
2774 for arg in args {
2776 if let Expression::NamedArgument(na) = &arg {
2777 let name_upper = na.name.name.to_uppercase();
2778 match name_upper.as_str() {
2779 "ANALYZER" => analyzer = Some(Box::new(arg)),
2780 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2781 _ => {}
2782 }
2783 }
2784 }
2785
2786 Ok(Expression::Search(Box::new(crate::expressions::Search {
2787 this,
2788 expression,
2789 json_scope: None,
2790 analyzer,
2791 analyzer_options: None,
2792 search_mode,
2793 })))
2794 }
2795
2796 "CONVERT" if f.args.len() == 2 => {
2799 let value = f.args.get(0).cloned().unwrap();
2800 let type_arg = f.args.get(1).cloned().unwrap();
2801
2802 if let Expression::Column(col) = &type_arg {
2804 let type_name = col.name.name.to_uppercase();
2805 let data_type = match type_name.as_str() {
2806 "SQL_DOUBLE" => Some(DataType::Double {
2807 precision: None,
2808 scale: None,
2809 }),
2810 "SQL_VARCHAR" => Some(DataType::VarChar {
2811 length: None,
2812 parenthesized_length: false,
2813 }),
2814 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2815 length: None,
2816 integer_spelling: false,
2817 }),
2818 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2819 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2820 "SQL_FLOAT" => Some(DataType::Float {
2821 precision: None,
2822 scale: None,
2823 real_spelling: false,
2824 }),
2825 "SQL_REAL" => Some(DataType::Float {
2826 precision: None,
2827 scale: None,
2828 real_spelling: true,
2829 }),
2830 "SQL_DECIMAL" => Some(DataType::Decimal {
2831 precision: None,
2832 scale: None,
2833 }),
2834 "SQL_DATE" => Some(DataType::Date),
2835 "SQL_TIME" => Some(DataType::Time {
2836 precision: None,
2837 timezone: false,
2838 }),
2839 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
2840 precision: None,
2841 timezone: false,
2842 }),
2843 _ => None,
2844 };
2845
2846 if let Some(dt) = data_type {
2847 return Ok(Expression::Cast(Box::new(Cast {
2848 this: value,
2849 to: dt,
2850 double_colon_syntax: false,
2851 trailing_comments: vec![],
2852 format: None,
2853 default: None,
2854 })));
2855 }
2856 }
2857 Ok(Expression::Function(Box::new(f)))
2859 }
2860
2861 "TO_TIMESTAMP_TZ" => {
2864 if f.args.len() == 1 {
2865 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
2866 {
2867 return Ok(Expression::Cast(Box::new(Cast {
2868 this: f.args.into_iter().next().unwrap(),
2869 to: DataType::Custom {
2870 name: "TIMESTAMPTZ".to_string(),
2871 },
2872 double_colon_syntax: false,
2873 trailing_comments: vec![],
2874 format: None,
2875 default: None,
2876 })));
2877 }
2878 }
2879 Ok(Expression::Function(Box::new(f)))
2880 }
2881
2882 "TO_TIMESTAMP_NTZ" => {
2884 if f.args.len() == 1 {
2885 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
2886 {
2887 return Ok(Expression::Cast(Box::new(Cast {
2888 this: f.args.into_iter().next().unwrap(),
2889 to: DataType::Custom {
2890 name: "TIMESTAMPNTZ".to_string(),
2891 },
2892 double_colon_syntax: false,
2893 trailing_comments: vec![],
2894 format: None,
2895 default: None,
2896 })));
2897 }
2898 }
2899 Ok(Expression::Function(Box::new(f)))
2900 }
2901
2902 "TO_TIMESTAMP_LTZ" => {
2904 if f.args.len() == 1 {
2905 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
2906 {
2907 return Ok(Expression::Cast(Box::new(Cast {
2908 this: f.args.into_iter().next().unwrap(),
2909 to: DataType::Custom {
2910 name: "TIMESTAMPLTZ".to_string(),
2911 },
2912 double_colon_syntax: false,
2913 trailing_comments: vec![],
2914 format: None,
2915 default: None,
2916 })));
2917 }
2918 }
2919 Ok(Expression::Function(Box::new(f)))
2920 }
2921
2922 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
2924
2925 "REPLACE" if f.args.len() == 2 => {
2927 let mut args = f.args;
2928 args.push(Expression::Literal(crate::expressions::Literal::String(
2929 String::new(),
2930 )));
2931 Ok(Expression::Function(Box::new(Function::new(
2932 "REPLACE".to_string(),
2933 args,
2934 ))))
2935 }
2936
2937 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
2939 "ANY_VALUE".to_string(),
2940 f.args,
2941 )))),
2942
2943 "SAFE_DIVIDE" if f.args.len() == 2 => {
2945 let mut args = f.args;
2946 let x = args.remove(0);
2947 let y = args.remove(0);
2948 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2949 condition: Expression::Neq(Box::new(BinaryOp {
2950 left: y.clone(),
2951 right: Expression::number(0),
2952 left_comments: Vec::new(),
2953 operator_comments: Vec::new(),
2954 trailing_comments: Vec::new(),
2955 })),
2956 true_value: Expression::Div(Box::new(BinaryOp {
2957 left: x,
2958 right: y,
2959 left_comments: Vec::new(),
2960 operator_comments: Vec::new(),
2961 trailing_comments: Vec::new(),
2962 })),
2963 false_value: Some(Expression::Null(crate::expressions::Null)),
2964 original_name: Some("IFF".to_string()),
2965 })))
2966 }
2967
2968 "TIMESTAMP" if f.args.len() == 1 => {
2970 let arg = f.args.into_iter().next().unwrap();
2971 Ok(Expression::Cast(Box::new(Cast {
2972 this: arg,
2973 to: DataType::Custom {
2974 name: "TIMESTAMPTZ".to_string(),
2975 },
2976 trailing_comments: Vec::new(),
2977 double_colon_syntax: false,
2978 format: None,
2979 default: None,
2980 })))
2981 }
2982
2983 "TIMESTAMP" if f.args.len() == 2 => {
2985 let mut args = f.args;
2986 let value = args.remove(0);
2987 let tz = args.remove(0);
2988 Ok(Expression::Function(Box::new(Function::new(
2989 "CONVERT_TIMEZONE".to_string(),
2990 vec![
2991 tz,
2992 Expression::Cast(Box::new(Cast {
2993 this: value,
2994 to: DataType::Timestamp {
2995 precision: None,
2996 timezone: false,
2997 },
2998 trailing_comments: Vec::new(),
2999 double_colon_syntax: false,
3000 format: None,
3001 default: None,
3002 })),
3003 ],
3004 ))))
3005 }
3006
3007 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3009 "TIME_FROM_PARTS".to_string(),
3010 f.args,
3011 )))),
3012
3013 "DIV0" if f.args.len() == 2 => {
3015 let mut args = f.args;
3016 let x = args.remove(0);
3017 let y = args.remove(0);
3018 let x_expr = Self::maybe_paren(x.clone());
3020 let y_expr = Self::maybe_paren(y.clone());
3021 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3022 condition: Expression::And(Box::new(BinaryOp::new(
3023 Expression::Eq(Box::new(BinaryOp::new(
3024 y_expr.clone(),
3025 Expression::number(0),
3026 ))),
3027 Expression::Not(Box::new(crate::expressions::UnaryOp {
3028 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3029 this: x_expr.clone(),
3030 not: false,
3031 postfix_form: false,
3032 })),
3033 })),
3034 ))),
3035 true_value: Expression::number(0),
3036 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3037 original_name: Some("IFF".to_string()),
3038 })))
3039 }
3040
3041 "DIV0NULL" if f.args.len() == 2 => {
3043 let mut args = f.args;
3044 let x = args.remove(0);
3045 let y = args.remove(0);
3046 let x_expr = Self::maybe_paren(x.clone());
3047 let y_expr = Self::maybe_paren(y.clone());
3048 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3049 condition: Expression::Or(Box::new(BinaryOp::new(
3050 Expression::Eq(Box::new(BinaryOp::new(
3051 y_expr.clone(),
3052 Expression::number(0),
3053 ))),
3054 Expression::IsNull(Box::new(crate::expressions::IsNull {
3055 this: y_expr.clone(),
3056 not: false,
3057 postfix_form: false,
3058 })),
3059 ))),
3060 true_value: Expression::number(0),
3061 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3062 original_name: Some("IFF".to_string()),
3063 })))
3064 }
3065
3066 "ZEROIFNULL" if f.args.len() == 1 => {
3068 let x = f.args.into_iter().next().unwrap();
3069 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3070 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3071 this: x.clone(),
3072 not: false,
3073 postfix_form: false,
3074 })),
3075 true_value: Expression::number(0),
3076 false_value: Some(x),
3077 original_name: Some("IFF".to_string()),
3078 })))
3079 }
3080
3081 "NULLIFZERO" if f.args.len() == 1 => {
3083 let x = f.args.into_iter().next().unwrap();
3084 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3085 condition: Expression::Eq(Box::new(BinaryOp::new(
3086 x.clone(),
3087 Expression::number(0),
3088 ))),
3089 true_value: Expression::Null(crate::expressions::Null),
3090 false_value: Some(x),
3091 original_name: Some("IFF".to_string()),
3092 })))
3093 }
3094
3095 "TRY_TO_TIME" => {
3097 if f.args.len() == 1 {
3098 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
3099 {
3100 return Ok(Expression::TryCast(Box::new(Cast {
3101 this: f.args.into_iter().next().unwrap(),
3102 to: crate::expressions::DataType::Time {
3103 precision: None,
3104 timezone: false,
3105 },
3106 double_colon_syntax: false,
3107 trailing_comments: Vec::new(),
3108 format: None,
3109 default: None,
3110 })));
3111 }
3112 }
3113 let mut args = f.args;
3115 if args.len() >= 2 {
3116 args[1] = Self::normalize_format_arg(args[1].clone());
3117 }
3118 Ok(Expression::Function(Box::new(Function::new(
3119 "TRY_TO_TIME".to_string(),
3120 args,
3121 ))))
3122 }
3123
3124 "TRY_TO_TIMESTAMP" => {
3127 if f.args.len() == 1 {
3128 if let Expression::Literal(crate::expressions::Literal::String(s)) = &f.args[0]
3129 {
3130 if !Self::looks_like_epoch(s) {
3131 return Ok(Expression::TryCast(Box::new(Cast {
3132 this: f.args.into_iter().next().unwrap(),
3133 to: DataType::Timestamp {
3134 precision: None,
3135 timezone: false,
3136 },
3137 double_colon_syntax: false,
3138 trailing_comments: Vec::new(),
3139 format: None,
3140 default: None,
3141 })));
3142 }
3143 }
3144 }
3145 let mut args = f.args;
3147 if args.len() >= 2 {
3148 args[1] = Self::normalize_format_arg(args[1].clone());
3149 }
3150 Ok(Expression::Function(Box::new(Function::new(
3151 "TRY_TO_TIMESTAMP".to_string(),
3152 args,
3153 ))))
3154 }
3155
3156 "TRY_TO_DATE" => {
3158 if f.args.len() == 1 {
3159 if let Expression::Literal(crate::expressions::Literal::String(s)) = &f.args[0]
3160 {
3161 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3163 return Ok(Expression::TryCast(Box::new(Cast {
3164 this: f.args.into_iter().next().unwrap(),
3165 to: crate::expressions::DataType::Date,
3166 double_colon_syntax: false,
3167 trailing_comments: Vec::new(),
3168 format: None,
3169 default: None,
3170 })));
3171 }
3172 }
3173 }
3174 let mut args = f.args;
3176 if args.len() >= 2 {
3177 args[1] = Self::normalize_format_arg(args[1].clone());
3178 }
3179 Ok(Expression::Function(Box::new(Function::new(
3180 "TRY_TO_DATE".to_string(),
3181 args,
3182 ))))
3183 }
3184
3185 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3187
3188 "REGEXP_REPLACE" if f.args.len() == 2 => {
3190 let mut args = f.args;
3191 args.push(Expression::Literal(crate::expressions::Literal::String(
3192 String::new(),
3193 )));
3194 Ok(Expression::Function(Box::new(Function::new(
3195 "REGEXP_REPLACE".to_string(),
3196 args,
3197 ))))
3198 }
3199
3200 "LAST_DAY" if f.args.len() == 2 => {
3202 let mut args = f.args;
3203 let date = args.remove(0);
3204 let unit = args.remove(0);
3205 let unit_str = match &unit {
3206 Expression::Column(c) => c.name.name.to_uppercase(),
3207 Expression::Identifier(i) => i.name.to_uppercase(),
3208 _ => String::new(),
3209 };
3210 if unit_str == "MONTH" {
3211 Ok(Expression::Function(Box::new(Function::new(
3212 "LAST_DAY".to_string(),
3213 vec![date],
3214 ))))
3215 } else {
3216 Ok(Expression::Function(Box::new(Function::new(
3217 "LAST_DAY".to_string(),
3218 vec![date, unit],
3219 ))))
3220 }
3221 }
3222
3223 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3225 "DATE_PART".to_string(),
3226 f.args,
3227 )))),
3228
3229 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3231 let mut args = f.args;
3232 let this = args.remove(0);
3233 let expr = args.remove(0);
3234 Ok(Expression::EndsWith(Box::new(
3235 crate::expressions::BinaryFunc {
3236 original_name: None,
3237 this,
3238 expression: expr,
3239 },
3240 )))
3241 }
3242
3243 _ => Ok(Expression::Function(Box::new(f))),
3245 }
3246 }
3247
3248 fn looks_like_datetime(s: &str) -> bool {
3250 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3253 }
3254
3255 fn looks_like_epoch(s: &str) -> bool {
3257 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3258 }
3259
3260 fn maybe_paren(expr: Expression) -> Expression {
3262 match &expr {
3263 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3264 Expression::Paren(Box::new(crate::expressions::Paren {
3265 this: expr,
3266 trailing_comments: Vec::new(),
3267 }))
3268 }
3269 _ => expr,
3270 }
3271 }
3272
3273 fn normalize_snowflake_format(format: &str) -> String {
3277 let mut result = String::new();
3278 let chars: Vec<char> = format.chars().collect();
3279 let mut i = 0;
3280 while i < chars.len() {
3281 if chars[i] == '"' {
3283 i += 1;
3284 while i < chars.len() && chars[i] != '"' {
3285 result.push(chars[i]);
3286 i += 1;
3287 }
3288 if i < chars.len() {
3289 i += 1; }
3291 continue;
3292 }
3293
3294 let remaining = &format[i..];
3295 let remaining_upper = remaining.to_uppercase();
3296
3297 if remaining_upper.starts_with("YYYY") {
3299 result.push_str("yyyy");
3300 i += 4;
3301 } else if remaining_upper.starts_with("YY") {
3302 result.push_str("yy");
3303 i += 2;
3304 } else if remaining_upper.starts_with("MMMM") {
3305 result.push_str("mmmm");
3306 i += 4;
3307 } else if remaining_upper.starts_with("MON") {
3308 result.push_str("mon");
3309 i += 3;
3310 } else if remaining_upper.starts_with("MM") {
3311 result.push_str("mm");
3312 i += 2;
3313 } else if remaining_upper.starts_with("DD") {
3314 result.push_str("DD");
3315 i += 2;
3316 } else if remaining_upper.starts_with("DY") {
3317 result.push_str("dy");
3318 i += 2;
3319 } else if remaining_upper.starts_with("HH24") {
3320 result.push_str("hh24");
3321 i += 4;
3322 } else if remaining_upper.starts_with("HH12") {
3323 result.push_str("hh12");
3324 i += 4;
3325 } else if remaining_upper.starts_with("HH") {
3326 result.push_str("hh");
3327 i += 2;
3328 } else if remaining_upper.starts_with("MISS") {
3329 result.push_str("miss");
3331 i += 4;
3332 } else if remaining_upper.starts_with("MI") {
3333 result.push_str("mi");
3334 i += 2;
3335 } else if remaining_upper.starts_with("SS") {
3336 result.push_str("ss");
3337 i += 2;
3338 } else if remaining_upper.starts_with("FF") {
3339 let ff_len = 2;
3341 let digit = if i + ff_len < chars.len() && chars[i + ff_len].is_ascii_digit() {
3342 let d = chars[i + ff_len];
3343 Some(d)
3344 } else {
3345 None
3346 };
3347 if let Some(d) = digit {
3348 result.push_str("ff");
3349 result.push(d);
3350 i += 3;
3351 } else {
3352 result.push_str("ff9");
3354 i += 2;
3355 }
3356 } else if remaining_upper.starts_with("AM") || remaining_upper.starts_with("PM") {
3357 result.push_str("pm");
3358 i += 2;
3359 } else if remaining_upper.starts_with("TZH") {
3360 result.push_str("tzh");
3361 i += 3;
3362 } else if remaining_upper.starts_with("TZM") {
3363 result.push_str("tzm");
3364 i += 3;
3365 } else {
3366 result.push(chars[i]);
3368 i += 1;
3369 }
3370 }
3371 result
3372 }
3373
3374 fn normalize_format_arg(expr: Expression) -> Expression {
3376 if let Expression::Literal(crate::expressions::Literal::String(s)) = &expr {
3377 let normalized = Self::normalize_snowflake_format(s);
3378 Expression::Literal(crate::expressions::Literal::String(normalized))
3379 } else {
3380 expr
3381 }
3382 }
3383
3384 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3387 use crate::expressions::{DataType, LambdaExpr};
3388 use std::collections::HashMap;
3389
3390 let mut param_types: HashMap<String, DataType> = HashMap::new();
3392 for (i, param) in lambda.parameters.iter().enumerate() {
3393 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3394 param_types.insert(param.name.to_uppercase(), dt.clone());
3395 }
3396 }
3397
3398 if param_types.is_empty() {
3400 return Expression::Lambda(Box::new(lambda));
3401 }
3402
3403 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3405
3406 Expression::Lambda(Box::new(LambdaExpr {
3408 parameters: lambda.parameters,
3409 body: transformed_body,
3410 colon: lambda.colon,
3411 parameter_types: Vec::new(), }))
3413 }
3414
3415 fn replace_lambda_params_with_cast(
3417 &self,
3418 expr: Expression,
3419 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3420 ) -> Expression {
3421 use crate::expressions::{BinaryOp, Cast, Paren};
3422
3423 match expr {
3424 Expression::Column(col) if col.table.is_none() => {
3426 let name_upper = col.name.name.to_uppercase();
3427 if let Some(dt) = param_types.get(&name_upper) {
3428 Expression::Cast(Box::new(Cast {
3430 this: Expression::Column(col),
3431 to: dt.clone(),
3432 double_colon_syntax: false,
3433 trailing_comments: Vec::new(),
3434 format: None,
3435 default: None,
3436 }))
3437 } else {
3438 Expression::Column(col)
3439 }
3440 }
3441
3442 Expression::Identifier(id) => {
3444 let name_upper = id.name.to_uppercase();
3445 if let Some(dt) = param_types.get(&name_upper) {
3446 Expression::Cast(Box::new(Cast {
3448 this: Expression::Identifier(id),
3449 to: dt.clone(),
3450 double_colon_syntax: false,
3451 trailing_comments: Vec::new(),
3452 format: None,
3453 default: None,
3454 }))
3455 } else {
3456 Expression::Identifier(id)
3457 }
3458 }
3459
3460 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3462 self.replace_lambda_params_with_cast(op.left, param_types),
3463 self.replace_lambda_params_with_cast(op.right, param_types),
3464 ))),
3465 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3466 self.replace_lambda_params_with_cast(op.left, param_types),
3467 self.replace_lambda_params_with_cast(op.right, param_types),
3468 ))),
3469 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3470 self.replace_lambda_params_with_cast(op.left, param_types),
3471 self.replace_lambda_params_with_cast(op.right, param_types),
3472 ))),
3473 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3474 self.replace_lambda_params_with_cast(op.left, param_types),
3475 self.replace_lambda_params_with_cast(op.right, param_types),
3476 ))),
3477 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3478 self.replace_lambda_params_with_cast(op.left, param_types),
3479 self.replace_lambda_params_with_cast(op.right, param_types),
3480 ))),
3481
3482 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3484 this: self.replace_lambda_params_with_cast(p.this, param_types),
3485 trailing_comments: p.trailing_comments,
3486 })),
3487
3488 Expression::Function(mut f) => {
3490 f.args = f
3491 .args
3492 .into_iter()
3493 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3494 .collect();
3495 Expression::Function(f)
3496 }
3497
3498 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3500 self.replace_lambda_params_with_cast(op.left, param_types),
3501 self.replace_lambda_params_with_cast(op.right, param_types),
3502 ))),
3503 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3504 self.replace_lambda_params_with_cast(op.left, param_types),
3505 self.replace_lambda_params_with_cast(op.right, param_types),
3506 ))),
3507 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3508 self.replace_lambda_params_with_cast(op.left, param_types),
3509 self.replace_lambda_params_with_cast(op.right, param_types),
3510 ))),
3511 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3512 self.replace_lambda_params_with_cast(op.left, param_types),
3513 self.replace_lambda_params_with_cast(op.right, param_types),
3514 ))),
3515 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3516 self.replace_lambda_params_with_cast(op.left, param_types),
3517 self.replace_lambda_params_with_cast(op.right, param_types),
3518 ))),
3519 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3520 self.replace_lambda_params_with_cast(op.left, param_types),
3521 self.replace_lambda_params_with_cast(op.right, param_types),
3522 ))),
3523
3524 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3526 self.replace_lambda_params_with_cast(op.left, param_types),
3527 self.replace_lambda_params_with_cast(op.right, param_types),
3528 ))),
3529 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3530 self.replace_lambda_params_with_cast(op.left, param_types),
3531 self.replace_lambda_params_with_cast(op.right, param_types),
3532 ))),
3533
3534 other => other,
3536 }
3537 }
3538
3539 fn transform_aggregate_function(
3540 &self,
3541 f: Box<crate::expressions::AggregateFunction>,
3542 ) -> Result<Expression> {
3543 let name_upper = f.name.to_uppercase();
3544 match name_upper.as_str() {
3545 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3547 Function::new("LISTAGG".to_string(), f.args),
3548 ))),
3549
3550 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3552 Function::new("LISTAGG".to_string(), f.args),
3553 ))),
3554
3555 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3557 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3558 ))),
3559
3560 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3562 "BITAND_AGG".to_string(),
3563 f.args,
3564 )))),
3565
3566 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3568 "BITOR_AGG".to_string(),
3569 f.args,
3570 )))),
3571
3572 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3574 "BITXOR_AGG".to_string(),
3575 f.args,
3576 )))),
3577
3578 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3580 let arg = f.args.into_iter().next().unwrap();
3581 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3582 this: arg,
3583 distinct: f.distinct,
3584 filter: f.filter,
3585 order_by: Vec::new(),
3586 name: Some("BOOLAND_AGG".to_string()),
3587 ignore_nulls: None,
3588 having_max: None,
3589 limit: None,
3590 })))
3591 }
3592
3593 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3595 let arg = f.args.into_iter().next().unwrap();
3596 Ok(Expression::LogicalOr(Box::new(AggFunc {
3597 this: arg,
3598 distinct: f.distinct,
3599 filter: f.filter,
3600 order_by: Vec::new(),
3601 name: Some("BOOLOR_AGG".to_string()),
3602 ignore_nulls: None,
3603 having_max: None,
3604 limit: None,
3605 })))
3606 }
3607
3608 "APPROX_TOP_K" if f.args.len() == 1 => {
3610 let mut args = f.args;
3611 args.push(Expression::number(1));
3612 Ok(Expression::AggregateFunction(Box::new(
3613 crate::expressions::AggregateFunction {
3614 name: "APPROX_TOP_K".to_string(),
3615 args,
3616 distinct: f.distinct,
3617 filter: f.filter,
3618 order_by: Vec::new(),
3619 limit: None,
3620 ignore_nulls: None,
3621 },
3622 )))
3623 }
3624
3625 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3627 let arg = f.args.into_iter().next().unwrap();
3628 Ok(Expression::Skewness(Box::new(AggFunc {
3629 this: arg,
3630 distinct: f.distinct,
3631 filter: f.filter,
3632 order_by: Vec::new(),
3633 name: Some("SKEW".to_string()),
3634 ignore_nulls: None,
3635 having_max: None,
3636 limit: None,
3637 })))
3638 }
3639
3640 _ => Ok(Expression::AggregateFunction(f)),
3642 }
3643 }
3644}
3645
3646fn strftime_to_snowflake_format(fmt: &str) -> String {
3648 let mut result = String::new();
3649 let chars: Vec<char> = fmt.chars().collect();
3650 let mut i = 0;
3651 while i < chars.len() {
3652 if chars[i] == '%' && i + 1 < chars.len() {
3653 match chars[i + 1] {
3654 'Y' => {
3655 result.push_str("yyyy");
3656 i += 2;
3657 }
3658 'y' => {
3659 result.push_str("yy");
3660 i += 2;
3661 }
3662 'm' => {
3663 result.push_str("mm");
3664 i += 2;
3665 }
3666 'd' => {
3667 result.push_str("DD");
3668 i += 2;
3669 }
3670 'H' => {
3671 result.push_str("hh24");
3672 i += 2;
3673 }
3674 'M' => {
3675 result.push_str("mmmm");
3676 i += 2;
3677 } 'i' => {
3679 result.push_str("mi");
3680 i += 2;
3681 }
3682 'S' | 's' => {
3683 result.push_str("ss");
3684 i += 2;
3685 }
3686 'f' => {
3687 result.push_str("ff");
3688 i += 2;
3689 }
3690 'w' => {
3691 result.push_str("dy");
3692 i += 2;
3693 } 'a' => {
3695 result.push_str("DY");
3696 i += 2;
3697 } 'b' => {
3699 result.push_str("mon");
3700 i += 2;
3701 } 'T' => {
3703 result.push_str("hh24:mi:ss");
3704 i += 2;
3705 } _ => {
3707 result.push(chars[i]);
3708 result.push(chars[i + 1]);
3709 i += 2;
3710 }
3711 }
3712 } else {
3713 result.push(chars[i]);
3714 i += 1;
3715 }
3716 }
3717 result
3718}
3719
3720#[cfg(test)]
3721mod tests {
3722 use super::*;
3723 use crate::dialects::Dialect;
3724
3725 fn transpile_to_snowflake(sql: &str) -> String {
3726 let dialect = Dialect::get(DialectType::Generic);
3727 let result = dialect
3728 .transpile_to(sql, DialectType::Snowflake)
3729 .expect("Transpile failed");
3730 result[0].clone()
3731 }
3732
3733 #[test]
3734 fn test_ifnull_to_coalesce() {
3735 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
3736 assert!(
3737 result.contains("COALESCE"),
3738 "Expected COALESCE, got: {}",
3739 result
3740 );
3741 }
3742
3743 #[test]
3744 fn test_basic_select() {
3745 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
3746 assert!(result.contains("SELECT"));
3747 assert!(result.contains("FROM users"));
3748 }
3749
3750 #[test]
3751 fn test_group_concat_to_listagg() {
3752 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
3753 assert!(
3754 result.contains("LISTAGG"),
3755 "Expected LISTAGG, got: {}",
3756 result
3757 );
3758 }
3759
3760 #[test]
3761 fn test_string_agg_to_listagg() {
3762 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
3763 assert!(
3764 result.contains("LISTAGG"),
3765 "Expected LISTAGG, got: {}",
3766 result
3767 );
3768 }
3769
3770 #[test]
3771 fn test_array_to_array_construct() {
3772 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
3773 assert!(
3774 result.contains("ARRAY_CONSTRUCT"),
3775 "Expected ARRAY_CONSTRUCT, got: {}",
3776 result
3777 );
3778 }
3779
3780 #[test]
3781 fn test_double_quote_identifiers() {
3782 let dialect = SnowflakeDialect;
3784 let config = dialect.generator_config();
3785 assert_eq!(config.identifier_quote, '"');
3786 }
3787}