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 });
623 Ok(Expression::Function(Box::new(Function::new(
624 "DATEADD".to_string(),
625 vec![unit, f.interval, f.this],
626 ))))
627 }
628
629 Expression::DateSub(f) => {
631 let unit_str = interval_unit_to_str(&f.unit);
632 let unit = Expression::Identifier(crate::expressions::Identifier {
633 name: unit_str,
634 quoted: false,
635 trailing_comments: Vec::new(),
636 });
637 let neg_expr = Expression::Mul(Box::new(crate::expressions::BinaryOp::new(
639 f.interval,
640 Expression::Neg(Box::new(crate::expressions::UnaryOp {
641 this: Expression::number(1),
642 })),
643 )));
644 Ok(Expression::Function(Box::new(Function::new(
645 "DATEADD".to_string(),
646 vec![unit, neg_expr, f.this],
647 ))))
648 }
649
650 Expression::DateDiff(f) => {
652 let unit_str =
653 interval_unit_to_str(&f.unit.unwrap_or(crate::expressions::IntervalUnit::Day));
654 let unit = Expression::Identifier(crate::expressions::Identifier {
655 name: unit_str,
656 quoted: false,
657 trailing_comments: Vec::new(),
658 });
659 Ok(Expression::Function(Box::new(Function::new(
660 "DATEDIFF".to_string(),
661 vec![unit, f.expression, f.this],
662 ))))
663 }
664
665 Expression::StringAgg(f) => {
668 let mut args = vec![f.this.clone()];
669 if let Some(separator) = &f.separator {
670 args.push(separator.clone());
671 }
672 Ok(Expression::Function(Box::new(Function::new(
673 "LISTAGG".to_string(),
674 args,
675 ))))
676 }
677
678 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
680 "STARTSWITH".to_string(),
681 vec![f.this, f.expression],
682 )))),
683
684 Expression::EndsWith(f) => Ok(Expression::EndsWith(f)),
686
687 Expression::Stuff(f) => {
689 let mut args = vec![*f.this];
690 if let Some(start) = f.start {
691 args.push(*start);
692 }
693 if let Some(length) = f.length {
694 args.push(Expression::number(length));
695 }
696 args.push(*f.expression);
697 Ok(Expression::Function(Box::new(Function::new(
698 "INSERT".to_string(),
699 args,
700 ))))
701 }
702
703 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
706 "SHA1".to_string(),
707 vec![f.this],
708 )))),
709
710 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
712 "SHA1_BINARY".to_string(),
713 vec![f.this],
714 )))),
715
716 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
718 "SHA2_BINARY".to_string(),
719 vec![*f.this],
720 )))),
721
722 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
724 "MD5_BINARY".to_string(),
725 vec![*f.this],
726 )))),
727
728 Expression::MD5NumberLower64(f) => Ok(Expression::Function(Box::new(Function::new(
730 "MD5_NUMBER_LOWER64".to_string(),
731 vec![f.this],
732 )))),
733
734 Expression::MD5NumberUpper64(f) => Ok(Expression::Function(Box::new(Function::new(
736 "MD5_NUMBER_UPPER64".to_string(),
737 vec![f.this],
738 )))),
739
740 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
743 "VECTOR_COSINE_SIMILARITY".to_string(),
744 vec![*f.this, *f.expression],
745 )))),
746
747 Expression::DotProduct(f) => Ok(Expression::Function(Box::new(Function::new(
749 "VECTOR_INNER_PRODUCT".to_string(),
750 vec![*f.this, *f.expression],
751 )))),
752
753 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
755 "VECTOR_L2_DISTANCE".to_string(),
756 vec![*f.this, *f.expression],
757 )))),
758
759 Expression::ManhattanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
761 "VECTOR_L1_DISTANCE".to_string(),
762 vec![*f.this, *f.expression],
763 )))),
764
765 Expression::JSONFormat(f) => {
768 let mut args = Vec::new();
769 if let Some(this) = f.this {
770 args.push(*this);
771 }
772 Ok(Expression::Function(Box::new(Function::new(
773 "TO_JSON".to_string(),
774 args,
775 ))))
776 }
777
778 Expression::JSONKeys(f) => Ok(Expression::Function(Box::new(Function::new(
780 "OBJECT_KEYS".to_string(),
781 vec![*f.this],
782 )))),
783
784 Expression::GetExtract(f) => Ok(Expression::Function(Box::new(Function::new(
786 "GET".to_string(),
787 vec![*f.this, *f.expression],
788 )))),
789
790 Expression::StarMap(f) => Ok(Expression::Function(Box::new(Function::new(
792 "OBJECT_CONSTRUCT".to_string(),
793 vec![f.this, f.expression],
794 )))),
795
796 Expression::LowerHex(f) => Ok(Expression::Function(Box::new(Function::new(
798 "TO_CHAR".to_string(),
799 vec![f.this],
800 )))),
801
802 Expression::Skewness(f) => Ok(Expression::Function(Box::new(Function::new(
804 "SKEW".to_string(),
805 vec![f.this],
806 )))),
807
808 Expression::StPoint(f) => Ok(Expression::Function(Box::new(Function::new(
810 "ST_MAKEPOINT".to_string(),
811 vec![*f.this, *f.expression],
812 )))),
813
814 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
816 "CONVERT_TIMEZONE".to_string(),
817 vec![*f.this],
818 )))),
819
820 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
823 "HEX_DECODE_BINARY".to_string(),
824 vec![*f.this],
825 )))),
826
827 Expression::UnixToTime(f) => {
829 let mut args = vec![*f.this];
830 if let Some(scale) = f.scale {
831 args.push(Expression::number(scale));
832 }
833 Ok(Expression::Function(Box::new(Function::new(
834 "TO_TIMESTAMP".to_string(),
835 args,
836 ))))
837 }
838
839 Expression::IfFunc(f) => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
842 condition: f.condition,
843 true_value: f.true_value,
844 false_value: Some(
845 f.false_value
846 .unwrap_or(Expression::Null(crate::expressions::Null)),
847 ),
848 original_name: Some("IFF".to_string()),
849 }))),
850
851 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
854 "APPROX_COUNT_DISTINCT".to_string(),
855 vec![f.this],
856 )))),
857
858 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
860 "MAX_BY".to_string(),
861 vec![*f.this, *f.expression],
862 )))),
863
864 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
866 "MIN_BY".to_string(),
867 vec![*f.this, *f.expression],
868 )))),
869
870 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
873
874 Expression::Rand(r) => Ok(Expression::Rand(r)),
876
877 Expression::Uuid(u) => Ok(Expression::Uuid(u)),
880
881 Expression::Map(f) => Ok(Expression::Function(Box::new(Function::new(
884 "OBJECT_CONSTRUCT".to_string(),
885 f.keys
886 .into_iter()
887 .zip(f.values.into_iter())
888 .flat_map(|(k, v)| vec![k, v])
889 .collect(),
890 )))),
891
892 Expression::MapFunc(f) => Ok(Expression::Function(Box::new(Function::new(
894 "OBJECT_CONSTRUCT".to_string(),
895 f.keys
896 .into_iter()
897 .zip(f.values.into_iter())
898 .flat_map(|(k, v)| vec![k, v])
899 .collect(),
900 )))),
901
902 Expression::VarMap(f) => Ok(Expression::Function(Box::new(Function::new(
904 "OBJECT_CONSTRUCT".to_string(),
905 f.keys
906 .into_iter()
907 .zip(f.values.into_iter())
908 .flat_map(|(k, v)| vec![k, v])
909 .collect(),
910 )))),
911
912 Expression::JsonObject(f) => Ok(Expression::Function(Box::new(Function::new(
915 "OBJECT_CONSTRUCT_KEEP_NULL".to_string(),
916 f.pairs.into_iter().flat_map(|(k, v)| vec![k, v]).collect(),
917 )))),
918
919 Expression::JsonExtractScalar(f) => Ok(Expression::Function(Box::new(Function::new(
921 "JSON_EXTRACT_PATH_TEXT".to_string(),
922 vec![f.this, f.path],
923 )))),
924
925 Expression::Struct(f) => Ok(Expression::Function(Box::new(Function::new(
928 "OBJECT_CONSTRUCT".to_string(),
929 f.fields
930 .into_iter()
931 .flat_map(|(name, expr)| {
932 let key = match name {
933 Some(n) => Expression::string(n),
934 None => Expression::Null(crate::expressions::Null),
935 };
936 vec![key, expr]
937 })
938 .collect(),
939 )))),
940
941 Expression::JSONPathRoot(_) => Ok(Expression::Literal(
944 crate::expressions::Literal::String(String::new()),
945 )),
946
947 Expression::VarSamp(agg) => Ok(Expression::Variance(agg)),
950
951 Expression::VarPop(agg) => Ok(Expression::VarPop(agg)),
954
955 Expression::Extract(f) => {
958 use crate::expressions::DateTimeField;
959 let transformed_this = self.transform_expr(f.this)?;
961 let field_name = match &f.field {
962 DateTimeField::Year => "YEAR",
963 DateTimeField::Month => "MONTH",
964 DateTimeField::Day => "DAY",
965 DateTimeField::Hour => "HOUR",
966 DateTimeField::Minute => "MINUTE",
967 DateTimeField::Second => "SECOND",
968 DateTimeField::Millisecond => "MILLISECOND",
969 DateTimeField::Microsecond => "MICROSECOND",
970 DateTimeField::Week => "WEEK",
971 DateTimeField::WeekWithModifier(m) => {
972 return Ok(Expression::Function(Box::new(Function::new(
973 "DATE_PART".to_string(),
974 vec![
975 Expression::Identifier(crate::expressions::Identifier {
976 name: format!("WEEK({})", m),
977 quoted: false,
978 trailing_comments: Vec::new(),
979 }),
980 transformed_this,
981 ],
982 ))))
983 }
984 DateTimeField::DayOfWeek => "DAYOFWEEK",
985 DateTimeField::DayOfYear => "DAYOFYEAR",
986 DateTimeField::Quarter => "QUARTER",
987 DateTimeField::Epoch => "EPOCH",
988 DateTimeField::Timezone => "TIMEZONE",
989 DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
990 DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
991 DateTimeField::Date => "DATE",
992 DateTimeField::Time => "TIME",
993 DateTimeField::Custom(s) => {
994 match s.to_uppercase().as_str() {
996 "DAYOFMONTH" => "DAY",
997 "DOW" => "DAYOFWEEK",
998 "DOY" => "DAYOFYEAR",
999 "ISODOW" => "DAYOFWEEKISO",
1000 "EPOCH_SECOND" | "EPOCH_SECONDS" => "EPOCH_SECOND",
1001 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => "EPOCH_MILLISECOND",
1002 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => "EPOCH_MICROSECOND",
1003 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => "EPOCH_NANOSECOND",
1004 _ => {
1005 return {
1006 let field_ident =
1007 Expression::Identifier(crate::expressions::Identifier {
1008 name: s.to_string(),
1009 quoted: false,
1010 trailing_comments: Vec::new(),
1011 });
1012 Ok(Expression::Function(Box::new(Function::new(
1013 "DATE_PART".to_string(),
1014 vec![field_ident, transformed_this],
1015 ))))
1016 }
1017 }
1018 }
1019 }
1020 };
1021 let field_ident = Expression::Identifier(crate::expressions::Identifier {
1022 name: field_name.to_string(),
1023 quoted: false,
1024 trailing_comments: Vec::new(),
1025 });
1026 Ok(Expression::Function(Box::new(Function::new(
1027 "DATE_PART".to_string(),
1028 vec![field_ident, transformed_this],
1029 ))))
1030 }
1031
1032 Expression::Function(f) => self.transform_function(*f),
1034
1035 Expression::Sum(mut agg) => {
1037 agg.this = self.transform_expr(agg.this)?;
1038 Ok(Expression::Sum(agg))
1039 }
1040
1041 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
1043
1044 Expression::NamedArgument(na) => {
1046 let transformed_value = self.transform_expr(na.value)?;
1047 Ok(Expression::NamedArgument(Box::new(
1048 crate::expressions::NamedArgument {
1049 name: na.name,
1050 value: transformed_value,
1051 separator: na.separator,
1052 },
1053 )))
1054 }
1055
1056 Expression::CreateTable(mut ct) => {
1058 for col in &mut ct.columns {
1059 if let Expression::DataType(new_dt) =
1060 self.transform_data_type(col.data_type.clone())?
1061 {
1062 col.data_type = new_dt;
1063 }
1064 if let Some(default_expr) = col.default.take() {
1066 col.default = Some(self.transform_expr(default_expr)?);
1067 }
1068 for constraint in &mut col.constraints {
1070 if let crate::expressions::ColumnConstraint::ComputedColumn(cc) = constraint
1071 {
1072 let transformed = self.transform_expr(*cc.expression.clone())?;
1073 cc.expression = Box::new(transformed);
1074 }
1075 }
1076 }
1077
1078 if ct.table_modifier.as_deref() == Some("EXTERNAL")
1081 && !ct.with_properties.is_empty()
1082 {
1083 for (key, value) in ct.with_properties.drain(..) {
1084 let formatted = Self::format_external_table_property(&key, &value);
1085 ct.properties
1086 .push(Expression::Raw(crate::expressions::Raw { sql: formatted }));
1087 }
1088 }
1089
1090 Ok(Expression::CreateTable(ct))
1091 }
1092
1093 Expression::AlterTable(mut at) => {
1095 for action in &mut at.actions {
1096 if let crate::expressions::AlterTableAction::AddColumn { column, .. } = action {
1097 if let Expression::DataType(new_dt) =
1098 self.transform_data_type(column.data_type.clone())?
1099 {
1100 column.data_type = new_dt;
1101 }
1102 }
1103 }
1104 Ok(Expression::AlterTable(at))
1105 }
1106
1107 Expression::Table(mut t) => {
1109 if let Some(when) = t.when.take() {
1110 let transformed_expr = self.transform_expr(*when.expression)?;
1112 t.when = Some(Box::new(crate::expressions::HistoricalData {
1113 this: when.this,
1114 kind: when.kind,
1115 expression: Box::new(transformed_expr),
1116 }));
1117 }
1118 Ok(Expression::Table(t))
1119 }
1120
1121 Expression::Subscript(s) => {
1123 let transformed_this = self.transform_expr(s.this)?;
1124 let transformed_index = self.transform_expr(s.index)?;
1125 Ok(Expression::Subscript(Box::new(
1126 crate::expressions::Subscript {
1127 this: transformed_this,
1128 index: transformed_index,
1129 },
1130 )))
1131 }
1132
1133 Expression::Paren(p) => {
1135 let transformed = self.transform_expr(p.this)?;
1136 Ok(Expression::Paren(Box::new(crate::expressions::Paren {
1137 this: transformed,
1138 trailing_comments: p.trailing_comments,
1139 })))
1140 }
1141
1142 Expression::Select(mut select) => {
1146 if let Some(ref mut order) = select.order_by {
1147 for ord in &mut order.expressions {
1148 if ord.nulls_first.is_none() {
1149 ord.nulls_first = Some(ord.desc);
1150 }
1151 }
1152 }
1153 Ok(Expression::Select(select))
1154 }
1155
1156 Expression::WindowFunction(mut wf) => {
1158 for ord in &mut wf.over.order_by {
1159 if ord.nulls_first.is_none() {
1160 ord.nulls_first = Some(ord.desc);
1161 }
1162 }
1163 Ok(Expression::WindowFunction(wf))
1164 }
1165
1166 Expression::Window(mut w) => {
1168 for ord in &mut w.order_by {
1169 if ord.nulls_first.is_none() {
1170 ord.nulls_first = Some(ord.desc);
1171 }
1172 }
1173 Ok(Expression::Window(w))
1174 }
1175
1176 Expression::Lateral(mut lat) => {
1178 let is_flatten = match lat.this.as_ref() {
1180 Expression::Function(f) => f.name.to_uppercase() == "FLATTEN",
1181 _ => false,
1182 };
1183 if is_flatten && lat.column_aliases.is_empty() {
1184 lat.column_aliases = vec![
1186 "SEQ".to_string(),
1187 "KEY".to_string(),
1188 "PATH".to_string(),
1189 "INDEX".to_string(),
1190 "VALUE".to_string(),
1191 "THIS".to_string(),
1192 ];
1193 if lat.alias.is_none() {
1195 lat.alias = Some("_flattened".to_string());
1196 }
1197 }
1198 Ok(Expression::Lateral(lat))
1199 }
1200
1201 _ => Ok(expr),
1203 }
1204 }
1205}
1206
1207impl SnowflakeDialect {
1208 fn format_external_table_property(key: &str, value: &str) -> String {
1211 let lower_key = key.to_lowercase();
1212 match lower_key.as_str() {
1213 "location" => format!("LOCATION={}", value),
1214 "file_format" => {
1215 let formatted_value = Self::format_file_format_value(value);
1217 format!("FILE_FORMAT={}", formatted_value)
1218 }
1219 _ => format!("{}={}", key, value),
1220 }
1221 }
1222
1223 fn format_file_format_value(value: &str) -> String {
1227 if !value.starts_with('(') {
1228 return value.to_string();
1229 }
1230 let inner = value[1..value.len() - 1].trim();
1232 let mut result = String::from("(");
1234 let mut parts: Vec<String> = Vec::new();
1235 let tokens: Vec<&str> = inner.split_whitespace().collect();
1237 let mut i = 0;
1238 while i < tokens.len() {
1239 let token = tokens[i];
1240 if i + 2 < tokens.len() && tokens[i + 1] == "=" {
1241 let val = Self::format_property_value(tokens[i + 2]);
1243 parts.push(format!("{}={}", token, val));
1244 i += 3;
1245 } else if token.contains('=') {
1246 let eq_pos = token.find('=').unwrap();
1248 let k = &token[..eq_pos];
1249 let v = Self::format_property_value(&token[eq_pos + 1..]);
1250 parts.push(format!("{}={}", k, v));
1251 i += 1;
1252 } else {
1253 parts.push(token.to_string());
1254 i += 1;
1255 }
1256 }
1257 result.push_str(&parts.join(" "));
1258 result.push(')');
1259 result
1260 }
1261
1262 fn format_property_value(value: &str) -> String {
1264 match value.to_lowercase().as_str() {
1265 "true" => "TRUE".to_string(),
1266 "false" => "FALSE".to_string(),
1267 _ => value.to_string(),
1268 }
1269 }
1270
1271 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1273 use crate::expressions::DataType;
1274 let transformed = match dt {
1275 DataType::Text => DataType::VarChar {
1277 length: None,
1278 parenthesized_length: false,
1279 },
1280 DataType::Struct { fields, .. } => {
1282 let _ = fields; DataType::Custom {
1285 name: "OBJECT".to_string(),
1286 }
1287 }
1288 DataType::Custom { name } => {
1290 let upper_name = name.to_uppercase();
1291 match upper_name.as_str() {
1292 "NVARCHAR" | "NCHAR" | "NATIONAL CHARACTER VARYING" | "NATIONAL CHAR" => {
1294 DataType::VarChar {
1295 length: None,
1296 parenthesized_length: false,
1297 }
1298 }
1299 "STRING" => DataType::VarChar {
1301 length: None,
1302 parenthesized_length: false,
1303 },
1304 "BIGDECIMAL" => DataType::Double {
1306 precision: None,
1307 scale: None,
1308 },
1309 "NESTED" => DataType::Custom {
1311 name: "OBJECT".to_string(),
1312 },
1313 "BYTEINT" => DataType::Int {
1315 length: None,
1316 integer_spelling: false,
1317 },
1318 "CHAR VARYING" | "CHARACTER VARYING" => DataType::VarChar {
1320 length: None,
1321 parenthesized_length: false,
1322 },
1323 "SQL_DOUBLE" => DataType::Double {
1325 precision: None,
1326 scale: None,
1327 },
1328 "SQL_VARCHAR" => DataType::VarChar {
1330 length: None,
1331 parenthesized_length: false,
1332 },
1333 "TIMESTAMP_NTZ" => DataType::Custom {
1335 name: "TIMESTAMPNTZ".to_string(),
1336 },
1337 "TIMESTAMP_LTZ" => DataType::Custom {
1339 name: "TIMESTAMPLTZ".to_string(),
1340 },
1341 "TIMESTAMP_TZ" => DataType::Custom {
1343 name: "TIMESTAMPTZ".to_string(),
1344 },
1345 "NCHAR VARYING" => DataType::VarChar {
1347 length: None,
1348 parenthesized_length: false,
1349 },
1350 "NUMBER" => DataType::Decimal {
1352 precision: Some(38),
1353 scale: Some(0),
1354 },
1355 _ if name.starts_with("NUMBER(") => {
1356 let inner = &name[7..name.len() - 1]; let parts: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1360 let precision = parts.first().and_then(|p| p.parse::<u32>().ok());
1361 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1362 DataType::Decimal { precision, scale }
1363 }
1364 _ => DataType::Custom { name },
1365 }
1366 }
1367 DataType::Decimal {
1369 precision: None,
1370 scale: None,
1371 } => DataType::Decimal {
1372 precision: Some(38),
1373 scale: Some(0),
1374 },
1375 DataType::Float { .. } => DataType::Double {
1377 precision: None,
1378 scale: None,
1379 },
1380 other => other,
1382 };
1383 Ok(Expression::DataType(transformed))
1384 }
1385
1386 fn map_date_part(abbr: &str) -> Option<&'static str> {
1388 match abbr.to_uppercase().as_str() {
1389 "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some("YEAR"),
1391 "MM" | "MON" | "MONS" | "MONTHS" => Some("MONTH"),
1393 "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some("DAY"),
1395 "DAY OF WEEK" | "WEEKDAY" | "DOW" | "DW" => Some("DAYOFWEEK"),
1397 "WEEKDAY_ISO" | "DOW_ISO" | "DW_ISO" | "DAYOFWEEK_ISO" => Some("DAYOFWEEKISO"),
1398 "DAY OF YEAR" | "DOY" | "DY" => Some("DAYOFYEAR"),
1400 "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY" => Some("WEEK"),
1402 "WEEK_ISO" | "WEEKOFYEARISO" | "WEEKOFYEAR_ISO" => Some("WEEKISO"),
1403 "Q" | "QTR" | "QTRS" | "QUARTERS" => Some("QUARTER"),
1405 "H" | "HH" | "HR" | "HOURS" | "HRS" => Some("HOUR"),
1407 "MI" | "MIN" | "MINUTES" | "MINS" => Some("MINUTE"),
1409 "S" | "SEC" | "SECONDS" | "SECS" => Some("SECOND"),
1411 "MS" | "MSEC" | "MSECS" | "MSECOND" | "MSECONDS" | "MILLISEC" | "MILLISECS"
1413 | "MILLISECON" | "MILLISECONDS" => Some("MILLISECOND"),
1414 "US" | "USEC" | "USECS" | "MICROSEC" | "MICROSECS" | "USECOND" | "USECONDS"
1416 | "MICROSECONDS" => Some("MICROSECOND"),
1417 "NS" | "NSEC" | "NANOSEC" | "NSECOND" | "NSECONDS" | "NANOSECS" => Some("NANOSECOND"),
1419 "EPOCH_SECOND" | "EPOCH_SECONDS" => Some("EPOCH_SECOND"),
1421 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Some("EPOCH_MILLISECOND"),
1422 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Some("EPOCH_MICROSECOND"),
1423 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Some("EPOCH_NANOSECOND"),
1424 "TZH" => Some("TIMEZONE_HOUR"),
1426 "TZM" => Some("TIMEZONE_MINUTE"),
1427 "DEC" | "DECS" | "DECADES" => Some("DECADE"),
1429 "MIL" | "MILS" | "MILLENIA" => Some("MILLENNIUM"),
1431 "C" | "CENT" | "CENTS" | "CENTURIES" => Some("CENTURY"),
1433 _ => None,
1435 }
1436 }
1437
1438 fn transform_date_part_arg(&self, expr: Expression) -> Expression {
1440 match &expr {
1441 Expression::Literal(crate::expressions::Literal::String(s)) => {
1443 Expression::Identifier(crate::expressions::Identifier {
1444 name: s.clone(),
1445 quoted: false,
1446 trailing_comments: Vec::new(),
1447 })
1448 }
1449 Expression::Identifier(id) => {
1451 if let Some(canonical) = Self::map_date_part(&id.name) {
1452 Expression::Identifier(crate::expressions::Identifier {
1453 name: canonical.to_string(),
1454 quoted: false,
1455 trailing_comments: Vec::new(),
1456 })
1457 } else {
1458 expr
1460 }
1461 }
1462 Expression::Column(col) if col.table.is_none() => {
1464 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1465 Expression::Identifier(crate::expressions::Identifier {
1466 name: canonical.to_string(),
1467 quoted: false,
1468 trailing_comments: Vec::new(),
1469 })
1470 } else {
1471 expr
1473 }
1474 }
1475 _ => expr,
1476 }
1477 }
1478
1479 fn transform_date_part_arg_identifiers_only(&self, expr: Expression) -> Expression {
1482 match &expr {
1483 Expression::Identifier(id) => {
1484 if let Some(canonical) = Self::map_date_part(&id.name) {
1485 Expression::Identifier(crate::expressions::Identifier {
1486 name: canonical.to_string(),
1487 quoted: false,
1488 trailing_comments: Vec::new(),
1489 })
1490 } else {
1491 expr
1492 }
1493 }
1494 Expression::Column(col) if col.table.is_none() => {
1495 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1496 Expression::Identifier(crate::expressions::Identifier {
1497 name: canonical.to_string(),
1498 quoted: false,
1499 trailing_comments: Vec::new(),
1500 })
1501 } else {
1502 expr
1503 }
1504 }
1505 _ => expr,
1506 }
1507 }
1508
1509 fn transform_json_path(path: &str) -> String {
1513 fn is_safe_identifier(s: &str) -> bool {
1516 if s.is_empty() {
1517 return false;
1518 }
1519 let mut chars = s.chars();
1520 match chars.next() {
1521 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
1522 _ => return false,
1523 }
1524 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
1525 }
1526
1527 if !path.contains('.') && !path.contains('[') && !path.contains(':') {
1530 if is_safe_identifier(path) {
1531 return path.to_string();
1532 } else {
1533 return format!("[\"{}\"]", path);
1535 }
1536 }
1537
1538 let result = path.replace(':', ".");
1541 result
1542 }
1543
1544 fn transform_interval(&self, interval: crate::expressions::Interval) -> Result<Expression> {
1546 use crate::expressions::{Interval, Literal};
1547
1548 fn expand_unit(abbr: &str) -> &'static str {
1550 match abbr.to_uppercase().as_str() {
1551 "D" => "DAY",
1552 "H" => "HOUR",
1553 "M" => "MINUTE",
1554 "MS" => "MILLISECOND",
1555 "NS" => "NANOSECOND",
1556 "Q" => "QUARTER",
1557 "S" => "SECOND",
1558 "US" => "MICROSECOND",
1559 "W" => "WEEK",
1560 "Y" => "YEAR",
1561 "WEEK" | "WEEKS" => "WEEK",
1563 "DAY" | "DAYS" => "DAY",
1564 "HOUR" | "HOURS" => "HOUR",
1565 "MINUTE" | "MINUTES" => "MINUTE",
1566 "SECOND" | "SECONDS" => "SECOND",
1567 "MONTH" | "MONTHS" => "MONTH",
1568 "YEAR" | "YEARS" => "YEAR",
1569 "QUARTER" | "QUARTERS" => "QUARTER",
1570 "MILLISECOND" | "MILLISECONDS" => "MILLISECOND",
1571 "MICROSECOND" | "MICROSECONDS" => "MICROSECOND",
1572 "NANOSECOND" | "NANOSECONDS" => "NANOSECOND",
1573 _ => "", }
1575 }
1576
1577 fn parse_interval_string(s: &str) -> Option<(&str, &str)> {
1579 let s = s.trim();
1580
1581 let mut num_end = 0;
1584 let mut chars = s.chars().peekable();
1585
1586 if chars.peek() == Some(&'-') {
1588 chars.next();
1589 num_end += 1;
1590 }
1591
1592 while let Some(&c) = chars.peek() {
1594 if c.is_ascii_digit() {
1595 chars.next();
1596 num_end += 1;
1597 } else {
1598 break;
1599 }
1600 }
1601
1602 if chars.peek() == Some(&'.') {
1604 chars.next();
1605 num_end += 1;
1606 while let Some(&c) = chars.peek() {
1607 if c.is_ascii_digit() {
1608 chars.next();
1609 num_end += 1;
1610 } else {
1611 break;
1612 }
1613 }
1614 }
1615
1616 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1617 return None; }
1619
1620 let value = &s[..num_end];
1621 let rest = s[num_end..].trim();
1622
1623 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1625 return None;
1626 }
1627
1628 Some((value, rest))
1629 }
1630
1631 if let Some(Expression::Literal(Literal::String(ref s))) = interval.this {
1633 if let Some((value, unit)) = parse_interval_string(s) {
1634 let expanded = expand_unit(unit);
1635 if !expanded.is_empty() {
1636 let new_value = format!("{} {}", value, expanded);
1638
1639 return Ok(Expression::Interval(Box::new(Interval {
1640 this: Some(Expression::Literal(Literal::String(new_value))),
1641 unit: None, })));
1643 }
1644 }
1645 }
1646
1647 Ok(Expression::Interval(Box::new(interval)))
1649 }
1650
1651 fn transform_function(&self, f: Function) -> Result<Expression> {
1652 let transformed_args: Vec<Expression> = f
1654 .args
1655 .into_iter()
1656 .map(|arg| self.transform_expr(arg))
1657 .collect::<Result<Vec<_>>>()?;
1658
1659 let f = Function {
1660 name: f.name,
1661 args: transformed_args,
1662 distinct: f.distinct,
1663 trailing_comments: f.trailing_comments,
1664 use_bracket_syntax: f.use_bracket_syntax,
1665 no_parens: f.no_parens,
1666 quoted: f.quoted,
1667 };
1668
1669 let name_upper = f.name.to_uppercase();
1670 match name_upper.as_str() {
1671 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1673 original_name: None,
1674 expressions: f.args,
1675 }))),
1676
1677 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1679 original_name: None,
1680 expressions: f.args,
1681 }))),
1682
1683 "NVL2" => Ok(Expression::Function(Box::new(f))),
1685
1686 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1688 Function::new("LISTAGG".to_string(), f.args),
1689 ))),
1690
1691 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1693 Function::new("LISTAGG".to_string(), f.args),
1694 ))),
1695
1696 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1698 "SUBSTRING".to_string(),
1699 f.args,
1700 )))),
1701
1702 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
1704 "FLATTEN".to_string(),
1705 f.args,
1706 )))),
1707
1708 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1710 "FLATTEN".to_string(),
1711 f.args,
1712 )))),
1713
1714 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1716
1717 "NOW" => Ok(Expression::Function(Box::new(Function {
1719 name: "CURRENT_TIMESTAMP".to_string(),
1720 args: f.args,
1721 distinct: false,
1722 trailing_comments: Vec::new(),
1723 use_bracket_syntax: false,
1724 no_parens: f.no_parens,
1725 quoted: false,
1726 }))),
1727
1728 "GETDATE" => Ok(Expression::Function(Box::new(Function {
1730 name: "CURRENT_TIMESTAMP".to_string(),
1731 args: f.args,
1732 distinct: false,
1733 trailing_comments: Vec::new(),
1734 use_bracket_syntax: false,
1735 no_parens: f.no_parens,
1736 quoted: false,
1737 }))),
1738
1739 "CURRENT_TIMESTAMP" if f.args.is_empty() => {
1743 Ok(Expression::Function(Box::new(Function {
1744 name: "CURRENT_TIMESTAMP".to_string(),
1745 args: Vec::new(),
1746 distinct: false,
1747 trailing_comments: Vec::new(),
1748 use_bracket_syntax: false,
1749 no_parens: false, quoted: false,
1751 })))
1752 }
1753
1754 "TO_DATE" => {
1758 if f.args.len() == 1 {
1759 if let Expression::Literal(crate::expressions::Literal::String(s)) = &f.args[0]
1760 {
1761 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
1763 return Ok(Expression::Cast(Box::new(Cast {
1764 this: f.args.into_iter().next().unwrap(),
1765 to: crate::expressions::DataType::Date,
1766 double_colon_syntax: false,
1767 trailing_comments: Vec::new(),
1768 format: None,
1769 default: None,
1770 })));
1771 }
1772 }
1773 }
1774 let mut args = f.args;
1776 if args.len() >= 2 {
1777 args[1] = Self::normalize_format_arg(args[1].clone());
1778 }
1779 Ok(Expression::Function(Box::new(Function::new(
1780 "TO_DATE".to_string(),
1781 args,
1782 ))))
1783 }
1784
1785 "TO_TIME" => {
1787 if f.args.len() == 1 {
1788 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
1789 {
1790 return Ok(Expression::Cast(Box::new(Cast {
1791 this: f.args.into_iter().next().unwrap(),
1792 to: crate::expressions::DataType::Time {
1793 precision: None,
1794 timezone: false,
1795 },
1796 double_colon_syntax: false,
1797 trailing_comments: Vec::new(),
1798 format: None,
1799 default: None,
1800 })));
1801 }
1802 }
1803 let mut args = f.args;
1805 if args.len() >= 2 {
1806 args[1] = Self::normalize_format_arg(args[1].clone());
1807 }
1808 Ok(Expression::Function(Box::new(Function::new(
1809 "TO_TIME".to_string(),
1810 args,
1811 ))))
1812 }
1813
1814 "TO_TIMESTAMP" => {
1821 let args = f.args;
1822 if args.len() == 1 {
1823 let arg = &args[0];
1824 match arg {
1825 Expression::Literal(Literal::String(s)) if Self::looks_like_datetime(s) => {
1826 return Ok(Expression::Cast(Box::new(Cast {
1828 this: args.into_iter().next().unwrap(),
1829 to: DataType::Timestamp {
1830 precision: None,
1831 timezone: false,
1832 },
1833 double_colon_syntax: false,
1834 trailing_comments: vec![],
1835 format: None,
1836 default: None,
1837 })));
1838 }
1839 Expression::Literal(Literal::String(s)) if Self::looks_like_epoch(s) => {
1840 return Ok(Expression::UnixToTime(Box::new(
1842 crate::expressions::UnixToTime {
1843 this: Box::new(args.into_iter().next().unwrap()),
1844 scale: None,
1845 zone: None,
1846 hours: None,
1847 minutes: None,
1848 format: None,
1849 target_type: None,
1850 },
1851 )));
1852 }
1853 Expression::Literal(Literal::Number(_)) | Expression::Neg(_) => {
1854 return Ok(Expression::UnixToTime(Box::new(
1856 crate::expressions::UnixToTime {
1857 this: Box::new(args.into_iter().next().unwrap()),
1858 scale: None,
1859 zone: None,
1860 hours: None,
1861 minutes: None,
1862 format: None,
1863 target_type: None,
1864 },
1865 )));
1866 }
1867 _ => {
1868 return Ok(Expression::Function(Box::new(Function::new(
1870 "TO_TIMESTAMP".to_string(),
1871 args,
1872 ))));
1873 }
1874 }
1875 } else if args.len() == 2 {
1876 let second_arg = &args[1];
1877 let is_int_scale = match second_arg {
1879 Expression::Literal(Literal::Number(n)) => n.parse::<i64>().is_ok(),
1880 _ => false,
1881 };
1882
1883 if is_int_scale {
1884 let mut args_iter = args.into_iter();
1886 let value = args_iter.next().unwrap();
1887 let scale_expr = args_iter.next().unwrap();
1888 let scale = if let Expression::Literal(Literal::Number(n)) = &scale_expr {
1889 n.parse::<i64>().ok()
1890 } else {
1891 None
1892 };
1893 return Ok(Expression::UnixToTime(Box::new(
1894 crate::expressions::UnixToTime {
1895 this: Box::new(value),
1896 scale,
1897 zone: None,
1898 hours: None,
1899 minutes: None,
1900 format: None,
1901 target_type: None,
1902 },
1903 )));
1904 } else {
1905 let mut args_iter = args.into_iter();
1907 let value = args_iter.next().unwrap();
1908 let format_expr = args_iter.next().unwrap();
1909 let format_str = match &format_expr {
1910 Expression::Literal(Literal::String(s)) => s.clone(),
1911 _ => {
1912 return Ok(Expression::Function(Box::new(Function::new(
1914 "TO_TIMESTAMP".to_string(),
1915 vec![value, format_expr],
1916 ))));
1917 }
1918 };
1919 let normalized_format = Self::normalize_snowflake_format(&format_str);
1921 return Ok(Expression::StrToTime(Box::new(
1922 crate::expressions::StrToTime {
1923 this: Box::new(value),
1924 format: normalized_format,
1925 zone: None,
1926 safe: None,
1927 target_type: None,
1928 },
1929 )));
1930 }
1931 }
1932 Ok(Expression::Function(Box::new(Function::new(
1934 "TO_TIMESTAMP".to_string(),
1935 args,
1936 ))))
1937 }
1938
1939 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
1941
1942 "ROUND"
1945 if f.args
1946 .iter()
1947 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
1948 {
1949 let mut expr_val = None;
1950 let mut scale_val = None;
1951 let mut rounding_mode_val = None;
1952 for arg in &f.args {
1953 if let Expression::NamedArgument(na) = arg {
1954 match na.name.name.to_uppercase().as_str() {
1955 "EXPR" => expr_val = Some(na.value.clone()),
1956 "SCALE" => scale_val = Some(na.value.clone()),
1957 "ROUNDING_MODE" => rounding_mode_val = Some(na.value.clone()),
1958 _ => {}
1959 }
1960 }
1961 }
1962 if let Some(expr) = expr_val {
1963 let mut args = vec![expr];
1964 if let Some(scale) = scale_val {
1965 args.push(scale);
1966 }
1967 if let Some(mode) = rounding_mode_val {
1968 args.push(mode);
1969 }
1970 Ok(Expression::Function(Box::new(Function::new(
1971 "ROUND".to_string(),
1972 args,
1973 ))))
1974 } else {
1975 Ok(Expression::Function(Box::new(f)))
1976 }
1977 }
1978
1979 "DATE_FORMAT" => {
1982 let mut args = f.args;
1983 if !args.is_empty() {
1985 if matches!(&args[0], Expression::Literal(Literal::String(_))) {
1986 args[0] = Expression::Cast(Box::new(crate::expressions::Cast {
1987 this: args[0].clone(),
1988 to: DataType::Timestamp {
1989 precision: None,
1990 timezone: false,
1991 },
1992 trailing_comments: Vec::new(),
1993 double_colon_syntax: false,
1994 format: None,
1995 default: None,
1996 }));
1997 }
1998 }
1999 if args.len() >= 2 {
2001 if let Expression::Literal(Literal::String(ref fmt)) = args[1] {
2002 let sf_fmt = strftime_to_snowflake_format(fmt);
2003 args[1] = Expression::Literal(Literal::String(sf_fmt));
2004 }
2005 }
2006 Ok(Expression::Function(Box::new(Function::new(
2007 "TO_CHAR".to_string(),
2008 args,
2009 ))))
2010 }
2011
2012 "ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2014 "ARRAY_CONSTRUCT".to_string(),
2015 f.args,
2016 )))),
2017
2018 "STRUCT" => {
2021 let mut oc_args = Vec::new();
2022 for arg in f.args {
2023 match arg {
2024 Expression::Alias(a) => {
2025 oc_args.push(Expression::Literal(crate::expressions::Literal::String(
2027 a.alias.name.clone(),
2028 )));
2029 oc_args.push(a.this);
2030 }
2031 other => {
2032 oc_args.push(other);
2034 }
2035 }
2036 }
2037 Ok(Expression::Function(Box::new(Function::new(
2038 "OBJECT_CONSTRUCT".to_string(),
2039 oc_args,
2040 ))))
2041 }
2042
2043 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2045 "GET_PATH".to_string(),
2046 f.args,
2047 )))),
2048
2049 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2051 "JSON_EXTRACT_PATH_TEXT".to_string(),
2052 f.args,
2053 )))),
2054
2055 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2057 f.args.into_iter().next().unwrap(),
2058 )))),
2059
2060 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2062 this: f.args.into_iter().next().unwrap(),
2063 decimals: None,
2064 to: None,
2065 }))),
2066
2067 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2069
2070 "SPLIT" => Ok(Expression::Function(Box::new(f))),
2072
2073 "ARRAY_AGG" => Ok(Expression::Function(Box::new(f))),
2075
2076 "JSON_PARSE" | "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2078 "PARSE_JSON".to_string(),
2079 f.args,
2080 )))),
2081
2082 "RAND" => {
2084 let seed = f.args.first().cloned().map(Box::new);
2085 Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2086 seed,
2087 lower: None,
2088 upper: None,
2089 })))
2090 }
2091
2092 "SHA" => Ok(Expression::Function(Box::new(Function::new(
2094 "SHA1".to_string(),
2095 f.args,
2096 )))),
2097
2098 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
2100 "APPROX_COUNT_DISTINCT".to_string(),
2101 f.args,
2102 )))),
2103
2104 "GEN_RANDOM_UUID" | "UUID" => {
2106 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2107 this: None,
2108 name: None,
2109 is_string: None,
2110 })))
2111 }
2112
2113 "NEWID" => Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2115 this: None,
2116 name: None,
2117 is_string: None,
2118 }))),
2119
2120 "UUID_STRING" => {
2122 if f.args.is_empty() {
2123 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2124 this: None,
2125 name: None,
2126 is_string: None,
2127 })))
2128 } else {
2129 Ok(Expression::Function(Box::new(Function::new(
2130 "UUID_STRING".to_string(),
2131 f.args,
2132 ))))
2133 }
2134 }
2135
2136 "IF" if f.args.len() >= 2 => {
2138 let mut args = f.args;
2139 let condition = args.remove(0);
2140 let true_val = args.remove(0);
2141 let false_val = if !args.is_empty() {
2142 Some(args.remove(0))
2143 } else {
2144 None
2145 };
2146 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2147 condition,
2148 true_value: true_val,
2149 false_value: Some(
2150 false_val.unwrap_or(Expression::Null(crate::expressions::Null)),
2151 ),
2152 original_name: Some("IFF".to_string()),
2153 })))
2154 }
2155
2156 "SQUARE" if f.args.len() == 1 => {
2158 let x = f.args.into_iter().next().unwrap();
2159 Ok(Expression::Power(Box::new(
2160 crate::expressions::BinaryFunc {
2161 original_name: None,
2162 this: x,
2163 expression: Expression::number(2),
2164 },
2165 )))
2166 }
2167
2168 "POW" if f.args.len() == 2 => {
2170 let mut args = f.args.into_iter();
2171 let x = args.next().unwrap();
2172 let y = args.next().unwrap();
2173 Ok(Expression::Power(Box::new(
2174 crate::expressions::BinaryFunc {
2175 original_name: None,
2176 this: x,
2177 expression: y,
2178 },
2179 )))
2180 }
2181
2182 "MOD" if f.args.len() == 2 => {
2184 let mut args = f.args.into_iter();
2185 let x = args.next().unwrap();
2186 let y = args.next().unwrap();
2187 Ok(Expression::Mod(Box::new(crate::expressions::BinaryOp {
2188 left: x,
2189 right: y,
2190 left_comments: Vec::new(),
2191 operator_comments: Vec::new(),
2192 trailing_comments: Vec::new(),
2193 })))
2194 }
2195
2196 "APPROXIMATE_JACCARD_INDEX" => Ok(Expression::Function(Box::new(Function::new(
2198 "APPROXIMATE_SIMILARITY".to_string(),
2199 f.args,
2200 )))),
2201
2202 "ARRAY_CONSTRUCT" => Ok(Expression::ArrayFunc(Box::new(
2204 crate::expressions::ArrayConstructor {
2205 expressions: f.args,
2206 bracket_notation: true,
2207 use_list_keyword: false,
2208 },
2209 ))),
2210
2211 "APPROX_TOP_K" if f.args.len() == 1 => {
2213 let mut args = f.args;
2214 args.push(Expression::number(1));
2215 Ok(Expression::Function(Box::new(Function::new(
2216 "APPROX_TOP_K".to_string(),
2217 args,
2218 ))))
2219 }
2220
2221 "TO_DECIMAL" | "TO_NUMERIC" => Ok(Expression::Function(Box::new(Function::new(
2223 "TO_NUMBER".to_string(),
2224 f.args,
2225 )))),
2226
2227 "TRY_TO_DECIMAL" | "TRY_TO_NUMERIC" => Ok(Expression::Function(Box::new(
2229 Function::new("TRY_TO_NUMBER".to_string(), f.args),
2230 ))),
2231
2232 "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2234 "STDDEV".to_string(),
2235 f.args,
2236 )))),
2237
2238 "STRTOK" if f.args.len() >= 1 => {
2240 let mut args = f.args;
2241 if args.len() == 1 {
2243 args.push(Expression::string(" ".to_string()));
2244 }
2245 if args.len() == 2 {
2247 args.push(Expression::number(1));
2248 }
2249 Ok(Expression::Function(Box::new(Function::new(
2250 "SPLIT_PART".to_string(),
2251 args,
2252 ))))
2253 }
2254
2255 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2257 "WEEK".to_string(),
2258 f.args,
2259 )))),
2260
2261 "LIKE" if f.args.len() >= 2 => {
2263 let mut args = f.args.into_iter();
2264 let left = args.next().unwrap();
2265 let right = args.next().unwrap();
2266 let escape = args.next();
2267 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2268 left,
2269 right,
2270 escape,
2271 quantifier: None,
2272 })))
2273 }
2274
2275 "ILIKE" if f.args.len() >= 2 => {
2277 let mut args = f.args.into_iter();
2278 let left = args.next().unwrap();
2279 let right = args.next().unwrap();
2280 let escape = args.next();
2281 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2282 left,
2283 right,
2284 escape,
2285 quantifier: None,
2286 })))
2287 }
2288
2289 "RLIKE" if f.args.len() >= 2 => {
2291 let mut args = f.args.into_iter();
2292 let left = args.next().unwrap();
2293 let pattern = args.next().unwrap();
2294 let flags = args.next();
2295 Ok(Expression::RegexpLike(Box::new(
2296 crate::expressions::RegexpFunc {
2297 this: left,
2298 pattern,
2299 flags,
2300 },
2301 )))
2302 }
2303
2304 "IFF" if f.args.len() >= 2 => {
2306 let mut args = f.args;
2307 let condition = args.remove(0);
2308 let true_value = args.remove(0);
2309 let false_value = if !args.is_empty() {
2310 Some(args.remove(0))
2311 } else {
2312 None
2313 };
2314 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2315 condition,
2316 true_value,
2317 false_value,
2318 original_name: Some("IFF".to_string()),
2319 })))
2320 }
2321
2322 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2324 Ok(Expression::Function(Box::new(Function::new(
2325 "TIMESTAMP_FROM_PARTS".to_string(),
2326 f.args,
2327 ))))
2328 }
2329
2330 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2332 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2333 f.args,
2334 )))),
2335
2336 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2338 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2339 f.args,
2340 )))),
2341
2342 "DATEADD" if f.args.len() >= 1 => {
2344 let mut args = f.args;
2345 args[0] = self.transform_date_part_arg(args[0].clone());
2346 Ok(Expression::Function(Box::new(Function::new(
2347 "DATEADD".to_string(),
2348 args,
2349 ))))
2350 }
2351
2352 "DATEDIFF" if f.args.len() >= 1 => {
2355 let mut args = f.args;
2356 args[0] = self.transform_date_part_arg(args[0].clone());
2357 for i in 1..args.len() {
2360 if let Expression::Function(ref func) = args[i] {
2361 if func.name == "_POLYGLOT_TO_DATE" {
2362 let inner_args = func.args.clone();
2363 args[i] = Expression::Function(Box::new(Function::new(
2364 "TO_DATE".to_string(),
2365 inner_args,
2366 )));
2367 }
2368 }
2369 }
2370 Ok(Expression::Function(Box::new(Function::new(
2371 "DATEDIFF".to_string(),
2372 args,
2373 ))))
2374 }
2375
2376 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2378 "DATEDIFF".to_string(),
2379 f.args,
2380 )))),
2381
2382 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2384 "DATEDIFF".to_string(),
2385 f.args,
2386 )))),
2387
2388 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2390 "DATEADD".to_string(),
2391 f.args,
2392 )))),
2393
2394 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2396
2397 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2399 "DATE_FROM_PARTS".to_string(),
2400 f.args,
2401 )))),
2402
2403 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2405 "TIME_FROM_PARTS".to_string(),
2406 f.args,
2407 )))),
2408
2409 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2411
2412 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2414
2415 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2417
2418 "MONTHNAME" if f.args.len() == 1 => {
2421 let arg = f.args.into_iter().next().unwrap();
2422 Ok(Expression::Monthname(Box::new(
2423 crate::expressions::Monthname {
2424 this: Box::new(arg),
2425 abbreviated: Some(Box::new(Expression::Literal(Literal::String(
2426 "true".to_string(),
2427 )))),
2428 },
2429 )))
2430 }
2431
2432 "DAYNAME" if f.args.len() == 1 => {
2435 let arg = f.args.into_iter().next().unwrap();
2436 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2437 this: Box::new(arg),
2438 abbreviated: Some(Box::new(Expression::Literal(Literal::String(
2439 "true".to_string(),
2440 )))),
2441 })))
2442 }
2443
2444 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2446 let arg = f.args.into_iter().next().unwrap();
2447 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2448 this: arg,
2449 distinct: false,
2450 filter: None,
2451 order_by: Vec::new(),
2452 name: Some("BOOLAND_AGG".to_string()),
2453 ignore_nulls: None,
2454 having_max: None,
2455 limit: None,
2456 })))
2457 }
2458
2459 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2461 let arg = f.args.into_iter().next().unwrap();
2462 Ok(Expression::LogicalOr(Box::new(AggFunc {
2463 this: arg,
2464 distinct: false,
2465 filter: None,
2466 order_by: Vec::new(),
2467 name: Some("BOOLOR_AGG".to_string()),
2468 ignore_nulls: None,
2469 having_max: None,
2470 limit: None,
2471 })))
2472 }
2473
2474 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2476 let arg = f.args.into_iter().next().unwrap();
2477 Ok(Expression::Skewness(Box::new(AggFunc {
2478 this: arg,
2479 distinct: false,
2480 filter: None,
2481 order_by: Vec::new(),
2482 name: Some("SKEW".to_string()),
2483 ignore_nulls: None,
2484 having_max: None,
2485 limit: None,
2486 })))
2487 }
2488
2489 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2491 "VARIANCE".to_string(),
2492 f.args,
2493 )))),
2494
2495 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2497 "VARIANCE_POP".to_string(),
2498 f.args,
2499 )))),
2500
2501 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2503 "TO_DATE".to_string(),
2504 f.args,
2505 )))),
2506 "DATE" if f.args.len() >= 2 => {
2510 let mut args = f.args;
2511 args[1] = Self::normalize_format_arg(args[1].clone());
2512 Ok(Expression::Function(Box::new(Function::new(
2513 "TO_DATE".to_string(),
2514 args,
2515 ))))
2516 }
2517 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2520 let mut args = f.args;
2521 args[1] = Self::normalize_format_arg(args[1].clone());
2522 Ok(Expression::Function(Box::new(Function::new(
2523 "DATE".to_string(),
2524 args,
2525 ))))
2526 }
2527
2528 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2530
2531 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2533 "MD5".to_string(),
2534 f.args,
2535 )))),
2536
2537 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2539 "SHA1".to_string(),
2540 f.args,
2541 )))),
2542
2543 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2545 "SHA2".to_string(),
2546 f.args,
2547 )))),
2548
2549 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2551 "EDITDISTANCE".to_string(),
2552 f.args,
2553 )))),
2554
2555 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2557 "BITNOT".to_string(),
2558 f.args,
2559 )))),
2560
2561 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2563 "BITAND".to_string(),
2564 f.args,
2565 )))),
2566
2567 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2569 "BITOR".to_string(),
2570 f.args,
2571 )))),
2572
2573 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2575 "BITXOR".to_string(),
2576 f.args,
2577 )))),
2578
2579 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2581 Function::new("BITSHIFTLEFT".to_string(), f.args),
2582 ))),
2583
2584 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2586 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2587 ))),
2588
2589 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2591 name: "CURRENT_TIMESTAMP".to_string(),
2592 args: f.args,
2593 distinct: false,
2594 trailing_comments: Vec::new(),
2595 use_bracket_syntax: false,
2596 no_parens: f.no_parens,
2597 quoted: false,
2598 }))),
2599
2600 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2602 name: "CURRENT_TIMESTAMP".to_string(),
2603 args: f.args,
2604 distinct: false,
2605 trailing_comments: Vec::new(),
2606 use_bracket_syntax: false,
2607 no_parens: f.no_parens,
2608 quoted: false,
2609 }))),
2610
2611 "SPACE" if f.args.len() == 1 => {
2613 let arg = f.args.into_iter().next().unwrap();
2614 Ok(Expression::Function(Box::new(Function::new(
2615 "REPEAT".to_string(),
2616 vec![Expression::Literal(Literal::String(" ".to_string())), arg],
2617 ))))
2618 }
2619
2620 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2622 "CEIL".to_string(),
2623 f.args,
2624 )))),
2625
2626 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2628 "LN".to_string(),
2629 f.args,
2630 )))),
2631
2632 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(Function::new(
2634 "REGEXP_EXTRACT_ALL".to_string(),
2635 f.args,
2636 )))),
2637
2638 "GET_PATH" if f.args.len() >= 2 => {
2642 let mut args = f.args;
2643 if let Expression::Literal(crate::expressions::Literal::String(path)) = &args[1] {
2645 let transformed = Self::transform_json_path(path);
2646 args[1] = Expression::Literal(crate::expressions::Literal::String(transformed));
2647 }
2648 Ok(Expression::Function(Box::new(Function::new(
2649 "GET_PATH".to_string(),
2650 args,
2651 ))))
2652 }
2653 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2654
2655 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2657
2658 "DATE_TRUNC" if f.args.len() >= 1 => {
2661 let mut args = f.args;
2662 let unit_name = match &args[0] {
2664 Expression::Identifier(id) => Some(id.name.as_str()),
2665 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2666 _ => None,
2667 };
2668 if let Some(name) = unit_name {
2669 let canonical = Self::map_date_part(name).unwrap_or(name);
2670 args[0] = Expression::Literal(crate::expressions::Literal::String(
2671 canonical.to_uppercase(),
2672 ));
2673 }
2674 Ok(Expression::Function(Box::new(Function::new(
2675 "DATE_TRUNC".to_string(),
2676 args,
2677 ))))
2678 }
2679
2680 "DATE_PART" if f.args.len() >= 1 => {
2686 let mut args = f.args;
2687 let from_typed_literal = args.len() >= 2
2688 && matches!(
2689 &args[1],
2690 Expression::Literal(crate::expressions::Literal::Timestamp(_))
2691 | Expression::Literal(crate::expressions::Literal::Date(_))
2692 | Expression::Literal(crate::expressions::Literal::Time(_))
2693 | Expression::Literal(crate::expressions::Literal::Datetime(_))
2694 );
2695 if from_typed_literal {
2696 args[0] = self.transform_date_part_arg(args[0].clone());
2697 } else {
2698 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2701 }
2702 Ok(Expression::Function(Box::new(Function::new(
2703 "DATE_PART".to_string(),
2704 args,
2705 ))))
2706 }
2707
2708 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2710
2711 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2713
2714 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2716 "DESCRIBE".to_string(),
2717 f.args,
2718 )))),
2719
2720 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2722 "REGEXP_LIKE".to_string(),
2723 f.args,
2724 )))),
2725
2726 "TRANSFORM" => {
2731 let transformed_args: Vec<Expression> = f
2732 .args
2733 .into_iter()
2734 .map(|arg| {
2735 if let Expression::Lambda(lambda) = arg {
2736 self.transform_typed_lambda(*lambda)
2737 } else {
2738 arg
2739 }
2740 })
2741 .collect();
2742 Ok(Expression::Function(Box::new(Function::new(
2743 "TRANSFORM".to_string(),
2744 transformed_args,
2745 ))))
2746 }
2747
2748 "SEARCH" if f.args.len() >= 2 => {
2750 let mut args = f.args.into_iter();
2751 let this = Box::new(args.next().unwrap());
2752 let expression = Box::new(args.next().unwrap());
2753
2754 let mut analyzer: Option<Box<Expression>> = None;
2755 let mut search_mode: Option<Box<Expression>> = None;
2756
2757 for arg in args {
2759 if let Expression::NamedArgument(na) = &arg {
2760 let name_upper = na.name.name.to_uppercase();
2761 match name_upper.as_str() {
2762 "ANALYZER" => analyzer = Some(Box::new(arg)),
2763 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2764 _ => {}
2765 }
2766 }
2767 }
2768
2769 Ok(Expression::Search(Box::new(crate::expressions::Search {
2770 this,
2771 expression,
2772 json_scope: None,
2773 analyzer,
2774 analyzer_options: None,
2775 search_mode,
2776 })))
2777 }
2778
2779 "CONVERT" if f.args.len() == 2 => {
2782 let value = f.args.get(0).cloned().unwrap();
2783 let type_arg = f.args.get(1).cloned().unwrap();
2784
2785 if let Expression::Column(col) = &type_arg {
2787 let type_name = col.name.name.to_uppercase();
2788 let data_type = match type_name.as_str() {
2789 "SQL_DOUBLE" => Some(DataType::Double {
2790 precision: None,
2791 scale: None,
2792 }),
2793 "SQL_VARCHAR" => Some(DataType::VarChar {
2794 length: None,
2795 parenthesized_length: false,
2796 }),
2797 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2798 length: None,
2799 integer_spelling: false,
2800 }),
2801 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2802 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2803 "SQL_FLOAT" => Some(DataType::Float {
2804 precision: None,
2805 scale: None,
2806 real_spelling: false,
2807 }),
2808 "SQL_REAL" => Some(DataType::Float {
2809 precision: None,
2810 scale: None,
2811 real_spelling: true,
2812 }),
2813 "SQL_DECIMAL" => Some(DataType::Decimal {
2814 precision: None,
2815 scale: None,
2816 }),
2817 "SQL_DATE" => Some(DataType::Date),
2818 "SQL_TIME" => Some(DataType::Time {
2819 precision: None,
2820 timezone: false,
2821 }),
2822 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
2823 precision: None,
2824 timezone: false,
2825 }),
2826 _ => None,
2827 };
2828
2829 if let Some(dt) = data_type {
2830 return Ok(Expression::Cast(Box::new(Cast {
2831 this: value,
2832 to: dt,
2833 double_colon_syntax: false,
2834 trailing_comments: vec![],
2835 format: None,
2836 default: None,
2837 })));
2838 }
2839 }
2840 Ok(Expression::Function(Box::new(f)))
2842 }
2843
2844 "TO_TIMESTAMP_TZ" => {
2847 if f.args.len() == 1 {
2848 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
2849 {
2850 return Ok(Expression::Cast(Box::new(Cast {
2851 this: f.args.into_iter().next().unwrap(),
2852 to: DataType::Custom {
2853 name: "TIMESTAMPTZ".to_string(),
2854 },
2855 double_colon_syntax: false,
2856 trailing_comments: vec![],
2857 format: None,
2858 default: None,
2859 })));
2860 }
2861 }
2862 Ok(Expression::Function(Box::new(f)))
2863 }
2864
2865 "TO_TIMESTAMP_NTZ" => {
2867 if f.args.len() == 1 {
2868 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
2869 {
2870 return Ok(Expression::Cast(Box::new(Cast {
2871 this: f.args.into_iter().next().unwrap(),
2872 to: DataType::Custom {
2873 name: "TIMESTAMPNTZ".to_string(),
2874 },
2875 double_colon_syntax: false,
2876 trailing_comments: vec![],
2877 format: None,
2878 default: None,
2879 })));
2880 }
2881 }
2882 Ok(Expression::Function(Box::new(f)))
2883 }
2884
2885 "TO_TIMESTAMP_LTZ" => {
2887 if f.args.len() == 1 {
2888 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
2889 {
2890 return Ok(Expression::Cast(Box::new(Cast {
2891 this: f.args.into_iter().next().unwrap(),
2892 to: DataType::Custom {
2893 name: "TIMESTAMPLTZ".to_string(),
2894 },
2895 double_colon_syntax: false,
2896 trailing_comments: vec![],
2897 format: None,
2898 default: None,
2899 })));
2900 }
2901 }
2902 Ok(Expression::Function(Box::new(f)))
2903 }
2904
2905 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
2907
2908 "REPLACE" if f.args.len() == 2 => {
2910 let mut args = f.args;
2911 args.push(Expression::Literal(crate::expressions::Literal::String(
2912 String::new(),
2913 )));
2914 Ok(Expression::Function(Box::new(Function::new(
2915 "REPLACE".to_string(),
2916 args,
2917 ))))
2918 }
2919
2920 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
2922 "ANY_VALUE".to_string(),
2923 f.args,
2924 )))),
2925
2926 "SAFE_DIVIDE" if f.args.len() == 2 => {
2928 let mut args = f.args;
2929 let x = args.remove(0);
2930 let y = args.remove(0);
2931 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2932 condition: Expression::Neq(Box::new(BinaryOp {
2933 left: y.clone(),
2934 right: Expression::number(0),
2935 left_comments: Vec::new(),
2936 operator_comments: Vec::new(),
2937 trailing_comments: Vec::new(),
2938 })),
2939 true_value: Expression::Div(Box::new(BinaryOp {
2940 left: x,
2941 right: y,
2942 left_comments: Vec::new(),
2943 operator_comments: Vec::new(),
2944 trailing_comments: Vec::new(),
2945 })),
2946 false_value: Some(Expression::Null(crate::expressions::Null)),
2947 original_name: Some("IFF".to_string()),
2948 })))
2949 }
2950
2951 "TIMESTAMP" if f.args.len() == 1 => {
2953 let arg = f.args.into_iter().next().unwrap();
2954 Ok(Expression::Cast(Box::new(Cast {
2955 this: arg,
2956 to: DataType::Custom {
2957 name: "TIMESTAMPTZ".to_string(),
2958 },
2959 trailing_comments: Vec::new(),
2960 double_colon_syntax: false,
2961 format: None,
2962 default: None,
2963 })))
2964 }
2965
2966 "TIMESTAMP" if f.args.len() == 2 => {
2968 let mut args = f.args;
2969 let value = args.remove(0);
2970 let tz = args.remove(0);
2971 Ok(Expression::Function(Box::new(Function::new(
2972 "CONVERT_TIMEZONE".to_string(),
2973 vec![
2974 tz,
2975 Expression::Cast(Box::new(Cast {
2976 this: value,
2977 to: DataType::Timestamp {
2978 precision: None,
2979 timezone: false,
2980 },
2981 trailing_comments: Vec::new(),
2982 double_colon_syntax: false,
2983 format: None,
2984 default: None,
2985 })),
2986 ],
2987 ))))
2988 }
2989
2990 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
2992 "TIME_FROM_PARTS".to_string(),
2993 f.args,
2994 )))),
2995
2996 "DIV0" if f.args.len() == 2 => {
2998 let mut args = f.args;
2999 let x = args.remove(0);
3000 let y = args.remove(0);
3001 let x_expr = Self::maybe_paren(x.clone());
3003 let y_expr = Self::maybe_paren(y.clone());
3004 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3005 condition: Expression::And(Box::new(BinaryOp::new(
3006 Expression::Eq(Box::new(BinaryOp::new(
3007 y_expr.clone(),
3008 Expression::number(0),
3009 ))),
3010 Expression::Not(Box::new(crate::expressions::UnaryOp {
3011 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3012 this: x_expr.clone(),
3013 not: false,
3014 postfix_form: false,
3015 })),
3016 })),
3017 ))),
3018 true_value: Expression::number(0),
3019 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3020 original_name: Some("IFF".to_string()),
3021 })))
3022 }
3023
3024 "DIV0NULL" if f.args.len() == 2 => {
3026 let mut args = f.args;
3027 let x = args.remove(0);
3028 let y = args.remove(0);
3029 let x_expr = Self::maybe_paren(x.clone());
3030 let y_expr = Self::maybe_paren(y.clone());
3031 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3032 condition: Expression::Or(Box::new(BinaryOp::new(
3033 Expression::Eq(Box::new(BinaryOp::new(
3034 y_expr.clone(),
3035 Expression::number(0),
3036 ))),
3037 Expression::IsNull(Box::new(crate::expressions::IsNull {
3038 this: y_expr.clone(),
3039 not: false,
3040 postfix_form: false,
3041 })),
3042 ))),
3043 true_value: Expression::number(0),
3044 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3045 original_name: Some("IFF".to_string()),
3046 })))
3047 }
3048
3049 "ZEROIFNULL" if f.args.len() == 1 => {
3051 let x = f.args.into_iter().next().unwrap();
3052 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3053 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3054 this: x.clone(),
3055 not: false,
3056 postfix_form: false,
3057 })),
3058 true_value: Expression::number(0),
3059 false_value: Some(x),
3060 original_name: Some("IFF".to_string()),
3061 })))
3062 }
3063
3064 "NULLIFZERO" if f.args.len() == 1 => {
3066 let x = f.args.into_iter().next().unwrap();
3067 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3068 condition: Expression::Eq(Box::new(BinaryOp::new(
3069 x.clone(),
3070 Expression::number(0),
3071 ))),
3072 true_value: Expression::Null(crate::expressions::Null),
3073 false_value: Some(x),
3074 original_name: Some("IFF".to_string()),
3075 })))
3076 }
3077
3078 "TRY_TO_TIME" => {
3080 if f.args.len() == 1 {
3081 if let Expression::Literal(crate::expressions::Literal::String(_)) = &f.args[0]
3082 {
3083 return Ok(Expression::TryCast(Box::new(Cast {
3084 this: f.args.into_iter().next().unwrap(),
3085 to: crate::expressions::DataType::Time {
3086 precision: None,
3087 timezone: false,
3088 },
3089 double_colon_syntax: false,
3090 trailing_comments: Vec::new(),
3091 format: None,
3092 default: None,
3093 })));
3094 }
3095 }
3096 let mut args = f.args;
3098 if args.len() >= 2 {
3099 args[1] = Self::normalize_format_arg(args[1].clone());
3100 }
3101 Ok(Expression::Function(Box::new(Function::new(
3102 "TRY_TO_TIME".to_string(),
3103 args,
3104 ))))
3105 }
3106
3107 "TRY_TO_TIMESTAMP" => {
3110 if f.args.len() == 1 {
3111 if let Expression::Literal(crate::expressions::Literal::String(s)) = &f.args[0]
3112 {
3113 if !Self::looks_like_epoch(s) {
3114 return Ok(Expression::TryCast(Box::new(Cast {
3115 this: f.args.into_iter().next().unwrap(),
3116 to: DataType::Timestamp {
3117 precision: None,
3118 timezone: false,
3119 },
3120 double_colon_syntax: false,
3121 trailing_comments: Vec::new(),
3122 format: None,
3123 default: None,
3124 })));
3125 }
3126 }
3127 }
3128 let mut args = f.args;
3130 if args.len() >= 2 {
3131 args[1] = Self::normalize_format_arg(args[1].clone());
3132 }
3133 Ok(Expression::Function(Box::new(Function::new(
3134 "TRY_TO_TIMESTAMP".to_string(),
3135 args,
3136 ))))
3137 }
3138
3139 "TRY_TO_DATE" => {
3141 if f.args.len() == 1 {
3142 if let Expression::Literal(crate::expressions::Literal::String(s)) = &f.args[0]
3143 {
3144 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3146 return Ok(Expression::TryCast(Box::new(Cast {
3147 this: f.args.into_iter().next().unwrap(),
3148 to: crate::expressions::DataType::Date,
3149 double_colon_syntax: false,
3150 trailing_comments: Vec::new(),
3151 format: None,
3152 default: None,
3153 })));
3154 }
3155 }
3156 }
3157 let mut args = f.args;
3159 if args.len() >= 2 {
3160 args[1] = Self::normalize_format_arg(args[1].clone());
3161 }
3162 Ok(Expression::Function(Box::new(Function::new(
3163 "TRY_TO_DATE".to_string(),
3164 args,
3165 ))))
3166 }
3167
3168 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3170
3171 "REGEXP_REPLACE" if f.args.len() == 2 => {
3173 let mut args = f.args;
3174 args.push(Expression::Literal(crate::expressions::Literal::String(
3175 String::new(),
3176 )));
3177 Ok(Expression::Function(Box::new(Function::new(
3178 "REGEXP_REPLACE".to_string(),
3179 args,
3180 ))))
3181 }
3182
3183 "LAST_DAY" if f.args.len() == 2 => {
3185 let mut args = f.args;
3186 let date = args.remove(0);
3187 let unit = args.remove(0);
3188 let unit_str = match &unit {
3189 Expression::Column(c) => c.name.name.to_uppercase(),
3190 Expression::Identifier(i) => i.name.to_uppercase(),
3191 _ => String::new(),
3192 };
3193 if unit_str == "MONTH" {
3194 Ok(Expression::Function(Box::new(Function::new(
3195 "LAST_DAY".to_string(),
3196 vec![date],
3197 ))))
3198 } else {
3199 Ok(Expression::Function(Box::new(Function::new(
3200 "LAST_DAY".to_string(),
3201 vec![date, unit],
3202 ))))
3203 }
3204 }
3205
3206 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3208 "DATE_PART".to_string(),
3209 f.args,
3210 )))),
3211
3212 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3214 let mut args = f.args;
3215 let this = args.remove(0);
3216 let expr = args.remove(0);
3217 Ok(Expression::EndsWith(Box::new(
3218 crate::expressions::BinaryFunc {
3219 original_name: None,
3220 this,
3221 expression: expr,
3222 },
3223 )))
3224 }
3225
3226 _ => Ok(Expression::Function(Box::new(f))),
3228 }
3229 }
3230
3231 fn looks_like_datetime(s: &str) -> bool {
3233 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3236 }
3237
3238 fn looks_like_epoch(s: &str) -> bool {
3240 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3241 }
3242
3243 fn maybe_paren(expr: Expression) -> Expression {
3245 match &expr {
3246 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3247 Expression::Paren(Box::new(crate::expressions::Paren {
3248 this: expr,
3249 trailing_comments: Vec::new(),
3250 }))
3251 }
3252 _ => expr,
3253 }
3254 }
3255
3256 fn normalize_snowflake_format(format: &str) -> String {
3260 let mut result = String::new();
3261 let chars: Vec<char> = format.chars().collect();
3262 let mut i = 0;
3263 while i < chars.len() {
3264 if chars[i] == '"' {
3266 i += 1;
3267 while i < chars.len() && chars[i] != '"' {
3268 result.push(chars[i]);
3269 i += 1;
3270 }
3271 if i < chars.len() {
3272 i += 1; }
3274 continue;
3275 }
3276
3277 let remaining = &format[i..];
3278 let remaining_upper = remaining.to_uppercase();
3279
3280 if remaining_upper.starts_with("YYYY") {
3282 result.push_str("yyyy");
3283 i += 4;
3284 } else if remaining_upper.starts_with("YY") {
3285 result.push_str("yy");
3286 i += 2;
3287 } else if remaining_upper.starts_with("MMMM") {
3288 result.push_str("mmmm");
3289 i += 4;
3290 } else if remaining_upper.starts_with("MON") {
3291 result.push_str("mon");
3292 i += 3;
3293 } else if remaining_upper.starts_with("MM") {
3294 result.push_str("mm");
3295 i += 2;
3296 } else if remaining_upper.starts_with("DD") {
3297 result.push_str("DD");
3298 i += 2;
3299 } else if remaining_upper.starts_with("DY") {
3300 result.push_str("dy");
3301 i += 2;
3302 } else if remaining_upper.starts_with("HH24") {
3303 result.push_str("hh24");
3304 i += 4;
3305 } else if remaining_upper.starts_with("HH12") {
3306 result.push_str("hh12");
3307 i += 4;
3308 } else if remaining_upper.starts_with("HH") {
3309 result.push_str("hh");
3310 i += 2;
3311 } else if remaining_upper.starts_with("MISS") {
3312 result.push_str("miss");
3314 i += 4;
3315 } else if remaining_upper.starts_with("MI") {
3316 result.push_str("mi");
3317 i += 2;
3318 } else if remaining_upper.starts_with("SS") {
3319 result.push_str("ss");
3320 i += 2;
3321 } else if remaining_upper.starts_with("FF") {
3322 let ff_len = 2;
3324 let digit = if i + ff_len < chars.len() && chars[i + ff_len].is_ascii_digit() {
3325 let d = chars[i + ff_len];
3326 Some(d)
3327 } else {
3328 None
3329 };
3330 if let Some(d) = digit {
3331 result.push_str("ff");
3332 result.push(d);
3333 i += 3;
3334 } else {
3335 result.push_str("ff9");
3337 i += 2;
3338 }
3339 } else if remaining_upper.starts_with("AM") || remaining_upper.starts_with("PM") {
3340 result.push_str("pm");
3341 i += 2;
3342 } else if remaining_upper.starts_with("TZH") {
3343 result.push_str("tzh");
3344 i += 3;
3345 } else if remaining_upper.starts_with("TZM") {
3346 result.push_str("tzm");
3347 i += 3;
3348 } else {
3349 result.push(chars[i]);
3351 i += 1;
3352 }
3353 }
3354 result
3355 }
3356
3357 fn normalize_format_arg(expr: Expression) -> Expression {
3359 if let Expression::Literal(crate::expressions::Literal::String(s)) = &expr {
3360 let normalized = Self::normalize_snowflake_format(s);
3361 Expression::Literal(crate::expressions::Literal::String(normalized))
3362 } else {
3363 expr
3364 }
3365 }
3366
3367 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3370 use crate::expressions::{DataType, LambdaExpr};
3371 use std::collections::HashMap;
3372
3373 let mut param_types: HashMap<String, DataType> = HashMap::new();
3375 for (i, param) in lambda.parameters.iter().enumerate() {
3376 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3377 param_types.insert(param.name.to_uppercase(), dt.clone());
3378 }
3379 }
3380
3381 if param_types.is_empty() {
3383 return Expression::Lambda(Box::new(lambda));
3384 }
3385
3386 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3388
3389 Expression::Lambda(Box::new(LambdaExpr {
3391 parameters: lambda.parameters,
3392 body: transformed_body,
3393 colon: lambda.colon,
3394 parameter_types: Vec::new(), }))
3396 }
3397
3398 fn replace_lambda_params_with_cast(
3400 &self,
3401 expr: Expression,
3402 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3403 ) -> Expression {
3404 use crate::expressions::{BinaryOp, Cast, Paren};
3405
3406 match expr {
3407 Expression::Column(col) if col.table.is_none() => {
3409 let name_upper = col.name.name.to_uppercase();
3410 if let Some(dt) = param_types.get(&name_upper) {
3411 Expression::Cast(Box::new(Cast {
3413 this: Expression::Column(col),
3414 to: dt.clone(),
3415 double_colon_syntax: false,
3416 trailing_comments: Vec::new(),
3417 format: None,
3418 default: None,
3419 }))
3420 } else {
3421 Expression::Column(col)
3422 }
3423 }
3424
3425 Expression::Identifier(id) => {
3427 let name_upper = id.name.to_uppercase();
3428 if let Some(dt) = param_types.get(&name_upper) {
3429 Expression::Cast(Box::new(Cast {
3431 this: Expression::Identifier(id),
3432 to: dt.clone(),
3433 double_colon_syntax: false,
3434 trailing_comments: Vec::new(),
3435 format: None,
3436 default: None,
3437 }))
3438 } else {
3439 Expression::Identifier(id)
3440 }
3441 }
3442
3443 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3445 self.replace_lambda_params_with_cast(op.left, param_types),
3446 self.replace_lambda_params_with_cast(op.right, param_types),
3447 ))),
3448 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3449 self.replace_lambda_params_with_cast(op.left, param_types),
3450 self.replace_lambda_params_with_cast(op.right, param_types),
3451 ))),
3452 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3453 self.replace_lambda_params_with_cast(op.left, param_types),
3454 self.replace_lambda_params_with_cast(op.right, param_types),
3455 ))),
3456 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3457 self.replace_lambda_params_with_cast(op.left, param_types),
3458 self.replace_lambda_params_with_cast(op.right, param_types),
3459 ))),
3460 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3461 self.replace_lambda_params_with_cast(op.left, param_types),
3462 self.replace_lambda_params_with_cast(op.right, param_types),
3463 ))),
3464
3465 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3467 this: self.replace_lambda_params_with_cast(p.this, param_types),
3468 trailing_comments: p.trailing_comments,
3469 })),
3470
3471 Expression::Function(mut f) => {
3473 f.args = f
3474 .args
3475 .into_iter()
3476 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3477 .collect();
3478 Expression::Function(f)
3479 }
3480
3481 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3483 self.replace_lambda_params_with_cast(op.left, param_types),
3484 self.replace_lambda_params_with_cast(op.right, param_types),
3485 ))),
3486 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3487 self.replace_lambda_params_with_cast(op.left, param_types),
3488 self.replace_lambda_params_with_cast(op.right, param_types),
3489 ))),
3490 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3491 self.replace_lambda_params_with_cast(op.left, param_types),
3492 self.replace_lambda_params_with_cast(op.right, param_types),
3493 ))),
3494 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3495 self.replace_lambda_params_with_cast(op.left, param_types),
3496 self.replace_lambda_params_with_cast(op.right, param_types),
3497 ))),
3498 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3499 self.replace_lambda_params_with_cast(op.left, param_types),
3500 self.replace_lambda_params_with_cast(op.right, param_types),
3501 ))),
3502 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3503 self.replace_lambda_params_with_cast(op.left, param_types),
3504 self.replace_lambda_params_with_cast(op.right, param_types),
3505 ))),
3506
3507 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3509 self.replace_lambda_params_with_cast(op.left, param_types),
3510 self.replace_lambda_params_with_cast(op.right, param_types),
3511 ))),
3512 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3513 self.replace_lambda_params_with_cast(op.left, param_types),
3514 self.replace_lambda_params_with_cast(op.right, param_types),
3515 ))),
3516
3517 other => other,
3519 }
3520 }
3521
3522 fn transform_aggregate_function(
3523 &self,
3524 f: Box<crate::expressions::AggregateFunction>,
3525 ) -> Result<Expression> {
3526 let name_upper = f.name.to_uppercase();
3527 match name_upper.as_str() {
3528 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3530 Function::new("LISTAGG".to_string(), f.args),
3531 ))),
3532
3533 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3535 Function::new("LISTAGG".to_string(), f.args),
3536 ))),
3537
3538 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3540 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3541 ))),
3542
3543 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3545 "BITAND_AGG".to_string(),
3546 f.args,
3547 )))),
3548
3549 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3551 "BITOR_AGG".to_string(),
3552 f.args,
3553 )))),
3554
3555 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3557 "BITXOR_AGG".to_string(),
3558 f.args,
3559 )))),
3560
3561 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3563 let arg = f.args.into_iter().next().unwrap();
3564 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3565 this: arg,
3566 distinct: f.distinct,
3567 filter: f.filter,
3568 order_by: Vec::new(),
3569 name: Some("BOOLAND_AGG".to_string()),
3570 ignore_nulls: None,
3571 having_max: None,
3572 limit: None,
3573 })))
3574 }
3575
3576 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3578 let arg = f.args.into_iter().next().unwrap();
3579 Ok(Expression::LogicalOr(Box::new(AggFunc {
3580 this: arg,
3581 distinct: f.distinct,
3582 filter: f.filter,
3583 order_by: Vec::new(),
3584 name: Some("BOOLOR_AGG".to_string()),
3585 ignore_nulls: None,
3586 having_max: None,
3587 limit: None,
3588 })))
3589 }
3590
3591 "APPROX_TOP_K" if f.args.len() == 1 => {
3593 let mut args = f.args;
3594 args.push(Expression::number(1));
3595 Ok(Expression::AggregateFunction(Box::new(
3596 crate::expressions::AggregateFunction {
3597 name: "APPROX_TOP_K".to_string(),
3598 args,
3599 distinct: f.distinct,
3600 filter: f.filter,
3601 order_by: Vec::new(),
3602 limit: None,
3603 ignore_nulls: None,
3604 },
3605 )))
3606 }
3607
3608 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3610 let arg = f.args.into_iter().next().unwrap();
3611 Ok(Expression::Skewness(Box::new(AggFunc {
3612 this: arg,
3613 distinct: f.distinct,
3614 filter: f.filter,
3615 order_by: Vec::new(),
3616 name: Some("SKEW".to_string()),
3617 ignore_nulls: None,
3618 having_max: None,
3619 limit: None,
3620 })))
3621 }
3622
3623 _ => Ok(Expression::AggregateFunction(f)),
3625 }
3626 }
3627}
3628
3629fn strftime_to_snowflake_format(fmt: &str) -> String {
3631 let mut result = String::new();
3632 let chars: Vec<char> = fmt.chars().collect();
3633 let mut i = 0;
3634 while i < chars.len() {
3635 if chars[i] == '%' && i + 1 < chars.len() {
3636 match chars[i + 1] {
3637 'Y' => {
3638 result.push_str("yyyy");
3639 i += 2;
3640 }
3641 'y' => {
3642 result.push_str("yy");
3643 i += 2;
3644 }
3645 'm' => {
3646 result.push_str("mm");
3647 i += 2;
3648 }
3649 'd' => {
3650 result.push_str("DD");
3651 i += 2;
3652 }
3653 'H' => {
3654 result.push_str("hh24");
3655 i += 2;
3656 }
3657 'M' => {
3658 result.push_str("mmmm");
3659 i += 2;
3660 } 'i' => {
3662 result.push_str("mi");
3663 i += 2;
3664 }
3665 'S' | 's' => {
3666 result.push_str("ss");
3667 i += 2;
3668 }
3669 'f' => {
3670 result.push_str("ff");
3671 i += 2;
3672 }
3673 'w' => {
3674 result.push_str("dy");
3675 i += 2;
3676 } 'a' => {
3678 result.push_str("DY");
3679 i += 2;
3680 } 'b' => {
3682 result.push_str("mon");
3683 i += 2;
3684 } 'T' => {
3686 result.push_str("hh24:mi:ss");
3687 i += 2;
3688 } _ => {
3690 result.push(chars[i]);
3691 result.push(chars[i + 1]);
3692 i += 2;
3693 }
3694 }
3695 } else {
3696 result.push(chars[i]);
3697 i += 1;
3698 }
3699 }
3700 result
3701}
3702
3703#[cfg(test)]
3704mod tests {
3705 use super::*;
3706 use crate::dialects::Dialect;
3707
3708 fn transpile_to_snowflake(sql: &str) -> String {
3709 let dialect = Dialect::get(DialectType::Generic);
3710 let result = dialect
3711 .transpile_to(sql, DialectType::Snowflake)
3712 .expect("Transpile failed");
3713 result[0].clone()
3714 }
3715
3716 #[test]
3717 fn test_ifnull_to_coalesce() {
3718 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
3719 assert!(
3720 result.contains("COALESCE"),
3721 "Expected COALESCE, got: {}",
3722 result
3723 );
3724 }
3725
3726 #[test]
3727 fn test_basic_select() {
3728 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
3729 assert!(result.contains("SELECT"));
3730 assert!(result.contains("FROM users"));
3731 }
3732
3733 #[test]
3734 fn test_group_concat_to_listagg() {
3735 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
3736 assert!(
3737 result.contains("LISTAGG"),
3738 "Expected LISTAGG, got: {}",
3739 result
3740 );
3741 }
3742
3743 #[test]
3744 fn test_string_agg_to_listagg() {
3745 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
3746 assert!(
3747 result.contains("LISTAGG"),
3748 "Expected LISTAGG, got: {}",
3749 result
3750 );
3751 }
3752
3753 #[test]
3754 fn test_array_to_array_construct() {
3755 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
3756 assert!(
3757 result.contains("ARRAY_CONSTRUCT"),
3758 "Expected ARRAY_CONSTRUCT, got: {}",
3759 result
3760 );
3761 }
3762
3763 #[test]
3764 fn test_double_quote_identifiers() {
3765 let dialect = SnowflakeDialect;
3767 let config = dialect.generator_config();
3768 assert_eq!(config.identifier_quote, '"');
3769 }
3770}