1use super::{DialectImpl, DialectType};
13use crate::error::Result;
14use crate::expressions::{
15 AggFunc, BinaryOp, Cast, CeilFunc, DataType, Expression, Function, IntervalUnit, ListAggFunc,
16 Literal, UnaryFunc, VarArgFunc,
17};
18#[cfg(feature = "generate")]
19use crate::generator::GeneratorConfig;
20use crate::tokens::TokenizerConfig;
21
22fn interval_unit_to_str(unit: &IntervalUnit) -> String {
24 match unit {
25 IntervalUnit::Year => "YEAR".to_string(),
26 IntervalUnit::Quarter => "QUARTER".to_string(),
27 IntervalUnit::Month => "MONTH".to_string(),
28 IntervalUnit::Week => "WEEK".to_string(),
29 IntervalUnit::Day => "DAY".to_string(),
30 IntervalUnit::Hour => "HOUR".to_string(),
31 IntervalUnit::Minute => "MINUTE".to_string(),
32 IntervalUnit::Second => "SECOND".to_string(),
33 IntervalUnit::Millisecond => "MILLISECOND".to_string(),
34 IntervalUnit::Microsecond => "MICROSECOND".to_string(),
35 IntervalUnit::Nanosecond => "NANOSECOND".to_string(),
36 }
37}
38
39pub struct SnowflakeDialect;
41
42impl DialectImpl for SnowflakeDialect {
43 fn dialect_type(&self) -> DialectType {
44 DialectType::Snowflake
45 }
46
47 fn tokenizer_config(&self) -> TokenizerConfig {
48 let mut config = TokenizerConfig::default();
49 config.identifiers.insert('"', '"');
51 config.quotes.insert("$$".to_string(), "$$".to_string());
53 config.nested_comments = false;
55 config.comments.insert("//".to_string(), None);
57 config
58 }
59
60 #[cfg(feature = "generate")]
61
62 fn generator_config(&self) -> GeneratorConfig {
63 use crate::generator::IdentifierQuoteStyle;
64 GeneratorConfig {
65 identifier_quote: '"',
66 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
67 dialect: Some(DialectType::Snowflake),
68 parameter_token: "$",
70 matched_by_source: false,
71 single_string_interval: true,
72 join_hints: false,
73 table_hints: false,
74 query_hints: false,
75 aggregate_filter_supported: false,
76 supports_table_copy: false,
77 collate_is_func: true,
78 limit_only_literals: true,
79 json_key_value_pair_sep: ",",
80 insert_overwrite: " OVERWRITE INTO",
81 struct_delimiter: ("(", ")"),
82 copy_params_are_wrapped: false,
83 copy_params_eq_required: true,
84 star_except: "EXCLUDE",
85 supports_exploding_projections: false,
86 array_concat_is_var_len: false,
87 supports_convert_timezone: true,
88 except_intersect_support_all_clause: false,
89 supports_median: true,
90 array_size_name: "ARRAY_SIZE",
91 supports_decode_case: true,
92 is_bool_allowed: false,
93 try_supported: true,
95 nvl2_supported: true,
97 unnest_with_ordinality: false,
99 quantified_no_paren_space: false,
101 array_bracket_only: true,
103 ..Default::default()
104 }
105 }
106
107 #[cfg(feature = "transpile")]
108
109 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
110 match expr {
111 Expression::DataType(dt) => self.transform_data_type(dt),
113
114 Expression::In(in_expr) if in_expr.not && in_expr.query.is_some() => {
118 let inner = in_expr.query.unwrap();
120 let subquery = Expression::Subquery(Box::new(crate::expressions::Subquery {
122 this: inner,
123 alias: None,
124 column_aliases: Vec::new(),
125 alias_explicit_as: false,
126 alias_keyword: None,
127 order_by: None,
128 limit: None,
129 offset: None,
130 distribute_by: None,
131 sort_by: None,
132 cluster_by: None,
133 lateral: false,
134 modifiers_inside: false,
135 trailing_comments: Vec::new(),
136 inferred_type: None,
137 }));
138 Ok(Expression::All(Box::new(
139 crate::expressions::QuantifiedExpr {
140 this: in_expr.this,
141 subquery,
142 op: Some(crate::expressions::QuantifiedOp::Neq),
143 },
144 )))
145 }
146
147 Expression::In(in_expr) if in_expr.not => {
149 let in_without_not = crate::expressions::In {
151 this: in_expr.this,
152 expressions: in_expr.expressions,
153 query: in_expr.query,
154 not: false,
155 global: in_expr.global,
156 unnest: in_expr.unnest,
157 is_field: in_expr.is_field,
158 };
159 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
160 this: Expression::In(Box::new(in_without_not)),
161 inferred_type: None,
162 })))
163 }
164
165 Expression::Interval(interval) => self.transform_interval(*interval),
168
169 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
172 original_name: None,
173 expressions: vec![f.this, f.expression],
174 inferred_type: None,
175 }))),
176
177 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
179 original_name: None,
180 expressions: vec![f.this, f.expression],
181 inferred_type: None,
182 }))),
183
184 Expression::Coalesce(mut f) => {
186 f.original_name = None;
187 Ok(Expression::Coalesce(f))
188 }
189
190 Expression::GroupConcat(f) => Ok(Expression::ListAgg(Box::new(ListAggFunc {
192 this: f.this,
193 separator: f.separator,
194 on_overflow: None,
195 order_by: f.order_by,
196 distinct: f.distinct,
197 filter: f.filter,
198 inferred_type: None,
199 }))),
200
201 Expression::Cast(c) => {
205 use crate::expressions::DataType;
206 let transformed_this = self.transform_expr(c.this)?;
208 match &c.to {
209 DataType::Geography { .. } => Ok(Expression::Function(Box::new(
210 Function::new("TO_GEOGRAPHY".to_string(), vec![transformed_this]),
211 ))),
212 DataType::Geometry { .. } => Ok(Expression::Function(Box::new(Function::new(
213 "TO_GEOMETRY".to_string(),
214 vec![transformed_this],
215 )))),
216 _ => {
217 let transformed_dt = match self.transform_data_type(c.to.clone())? {
219 Expression::DataType(dt) => dt,
220 _ => c.to.clone(),
221 };
222 Ok(Expression::Cast(Box::new(Cast {
223 this: transformed_this,
224 to: transformed_dt,
225 double_colon_syntax: false, trailing_comments: c.trailing_comments,
227 format: c.format,
228 default: c.default,
229 inferred_type: None,
230 })))
231 }
232 }
233 }
234
235 Expression::TryCast(c) => {
238 let transformed_this = self.transform_expr(c.this)?;
239 Ok(Expression::TryCast(Box::new(Cast {
240 this: transformed_this,
241 to: c.to,
242 double_colon_syntax: false, trailing_comments: c.trailing_comments,
244 format: c.format,
245 default: c.default,
246 inferred_type: None,
247 })))
248 }
249
250 Expression::SafeCast(c) => {
253 let to = match c.to {
254 DataType::Timestamp { .. } => DataType::Custom {
255 name: "TIMESTAMPTZ".to_string(),
256 },
257 DataType::Custom { name } if name.eq_ignore_ascii_case("TIMESTAMP") => {
258 DataType::Custom {
259 name: "TIMESTAMPTZ".to_string(),
260 }
261 }
262 other => other,
263 };
264 let transformed_this = self.transform_expr(c.this)?;
265 Ok(Expression::Cast(Box::new(Cast {
266 this: transformed_this,
267 to,
268 double_colon_syntax: c.double_colon_syntax,
269 trailing_comments: c.trailing_comments,
270 format: c.format,
271 default: c.default,
272 inferred_type: None,
273 })))
274 }
275
276 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Timestamp(_)) => {
279 let Literal::Timestamp(s) = lit.as_ref() else {
280 unreachable!()
281 };
282 Ok(Expression::Cast(Box::new(Cast {
283 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
284 to: DataType::Timestamp {
285 precision: None,
286 timezone: false,
287 },
288 double_colon_syntax: false,
289 trailing_comments: Vec::new(),
290 format: None,
291 default: None,
292 inferred_type: None,
293 })))
294 }
295
296 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Date(_)) => {
298 let Literal::Date(s) = lit.as_ref() else {
299 unreachable!()
300 };
301 Ok(Expression::Cast(Box::new(Cast {
302 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
303 to: DataType::Date,
304 double_colon_syntax: false,
305 trailing_comments: Vec::new(),
306 format: None,
307 default: None,
308 inferred_type: None,
309 })))
310 }
311
312 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Time(_)) => {
314 let Literal::Time(s) = lit.as_ref() else {
315 unreachable!()
316 };
317 Ok(Expression::Cast(Box::new(Cast {
318 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
319 to: DataType::Time {
320 precision: None,
321 timezone: false,
322 },
323 double_colon_syntax: false,
324 trailing_comments: Vec::new(),
325 format: None,
326 default: None,
327 inferred_type: None,
328 })))
329 }
330
331 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Datetime(_)) => {
333 let Literal::Datetime(s) = lit.as_ref() else {
334 unreachable!()
335 };
336 Ok(Expression::Cast(Box::new(Cast {
337 this: Expression::Literal(Box::new(Literal::String(s.clone()))),
338 to: DataType::Custom {
339 name: "DATETIME".to_string(),
340 },
341 double_colon_syntax: false,
342 trailing_comments: Vec::new(),
343 format: None,
344 default: None,
345 inferred_type: None,
346 })))
347 }
348
349 Expression::ILike(op) => Ok(Expression::ILike(op)),
352
353 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
356 "FLATTEN".to_string(),
357 vec![f.this],
358 )))),
359
360 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
362 "FLATTEN".to_string(),
363 vec![f.this],
364 )))),
365
366 Expression::Unnest(f) => {
368 let input_arg =
370 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
371 name: crate::expressions::Identifier::new("INPUT"),
372 value: f.this,
373 separator: crate::expressions::NamedArgSeparator::DArrow,
374 }));
375
376 let flatten = Expression::Function(Box::new(Function::new(
378 "FLATTEN".to_string(),
379 vec![input_arg],
380 )));
381
382 let table_func =
384 Expression::TableFromRows(Box::new(crate::expressions::TableFromRows {
385 this: Box::new(flatten),
386 alias: None,
387 joins: vec![],
388 pivots: None,
389 sample: None,
390 }));
391
392 Ok(Expression::Alias(Box::new(crate::expressions::Alias {
394 this: table_func,
395 alias: crate::expressions::Identifier::new("_t0"),
396 column_aliases: vec![
397 crate::expressions::Identifier::new("seq"),
398 crate::expressions::Identifier::new("key"),
399 crate::expressions::Identifier::new("path"),
400 crate::expressions::Identifier::new("index"),
401 crate::expressions::Identifier::new("value"),
402 crate::expressions::Identifier::new("this"),
403 ],
404 alias_explicit_as: false,
405 alias_keyword: None,
406 pre_alias_comments: vec![],
407 trailing_comments: vec![],
408 inferred_type: None,
409 })))
410 }
411
412 Expression::ArrayFunc(arr) => {
416 if arr.bracket_notation {
417 Ok(Expression::ArrayFunc(arr))
419 } else {
420 Ok(Expression::Function(Box::new(Function::new(
422 "ARRAY_CONSTRUCT".to_string(),
423 arr.expressions,
424 ))))
425 }
426 }
427
428 Expression::ArrayConcat(f) => Ok(Expression::Function(Box::new(Function::new(
430 "ARRAY_CAT".to_string(),
431 f.expressions,
432 )))),
433
434 Expression::ArrayConcatAgg(f) => Ok(Expression::Function(Box::new(Function::new(
436 "ARRAY_FLATTEN".to_string(),
437 vec![f.this],
438 )))),
439
440 Expression::ArrayContains(f) => Ok(Expression::Function(Box::new(Function::new(
442 "ARRAY_CONTAINS".to_string(),
443 vec![f.this, f.expression],
444 )))),
445
446 Expression::ArrayIntersect(f) => Ok(Expression::Function(Box::new(Function::new(
448 "ARRAY_INTERSECTION".to_string(),
449 f.expressions,
450 )))),
451
452 Expression::ArraySort(f) => Ok(Expression::Function(Box::new(Function::new(
454 "ARRAY_SORT".to_string(),
455 vec![f.this],
456 )))),
457
458 Expression::StringToArray(f) => {
460 let mut args = vec![*f.this];
461 if let Some(expr) = f.expression {
462 args.push(*expr);
463 }
464 Ok(Expression::Function(Box::new(Function::new(
465 "STRTOK_TO_ARRAY".to_string(),
466 args,
467 ))))
468 }
469
470 Expression::BitwiseOr(f) => Ok(Expression::Function(Box::new(Function::new(
473 "BITOR".to_string(),
474 vec![f.left, f.right],
475 )))),
476
477 Expression::BitwiseXor(f) => Ok(Expression::Function(Box::new(Function::new(
479 "BITXOR".to_string(),
480 vec![f.left, f.right],
481 )))),
482
483 Expression::BitwiseAnd(f) => Ok(Expression::Function(Box::new(Function::new(
485 "BITAND".to_string(),
486 vec![f.left, f.right],
487 )))),
488
489 Expression::BitwiseNot(f) => Ok(Expression::Function(Box::new(Function::new(
491 "BITNOT".to_string(),
492 vec![f.this],
493 )))),
494
495 Expression::BitwiseLeftShift(f) => Ok(Expression::Function(Box::new(Function::new(
497 "BITSHIFTLEFT".to_string(),
498 vec![f.left, f.right],
499 )))),
500
501 Expression::BitwiseRightShift(f) => Ok(Expression::Function(Box::new(Function::new(
503 "BITSHIFTRIGHT".to_string(),
504 vec![f.left, f.right],
505 )))),
506
507 Expression::BitwiseAndAgg(f) => Ok(Expression::Function(Box::new(Function::new(
509 "BITAND_AGG".to_string(),
510 vec![f.this],
511 )))),
512
513 Expression::BitwiseOrAgg(f) => Ok(Expression::Function(Box::new(Function::new(
515 "BITOR_AGG".to_string(),
516 vec![f.this],
517 )))),
518
519 Expression::BitwiseXorAgg(f) => Ok(Expression::Function(Box::new(Function::new(
521 "BITXOR_AGG".to_string(),
522 vec![f.this],
523 )))),
524
525 Expression::LogicalAnd(f) => Ok(Expression::Function(Box::new(Function::new(
528 "BOOLAND_AGG".to_string(),
529 vec![f.this],
530 )))),
531
532 Expression::LogicalOr(f) => Ok(Expression::Function(Box::new(Function::new(
534 "BOOLOR_AGG".to_string(),
535 vec![f.this],
536 )))),
537
538 Expression::Booland(f) => Ok(Expression::Function(Box::new(Function::new(
540 "BOOLAND".to_string(),
541 vec![*f.this, *f.expression],
542 )))),
543
544 Expression::Boolor(f) => Ok(Expression::Function(Box::new(Function::new(
546 "BOOLOR".to_string(),
547 vec![*f.this, *f.expression],
548 )))),
549
550 Expression::Xor(f) => {
552 let mut args = Vec::new();
553 if let Some(this) = f.this {
554 args.push(*this);
555 }
556 if let Some(expr) = f.expression {
557 args.push(*expr);
558 }
559 Ok(Expression::Function(Box::new(Function::new(
560 "BOOLXOR".to_string(),
561 args,
562 ))))
563 }
564
565 Expression::DayOfMonth(f) => Ok(Expression::Function(Box::new(Function::new(
568 "DAYOFMONTH".to_string(),
569 vec![f.this],
570 )))),
571
572 Expression::DayOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
574 "DAYOFWEEK".to_string(),
575 vec![f.this],
576 )))),
577
578 Expression::DayOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
580 "DAYOFWEEKISO".to_string(),
581 vec![f.this],
582 )))),
583
584 Expression::DayOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
586 "DAYOFYEAR".to_string(),
587 vec![f.this],
588 )))),
589
590 Expression::WeekOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
592 "WEEK".to_string(),
593 vec![f.this],
594 )))),
595
596 Expression::YearOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
598 "YEAROFWEEK".to_string(),
599 vec![f.this],
600 )))),
601
602 Expression::YearOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
604 "YEAROFWEEKISO".to_string(),
605 vec![f.this],
606 )))),
607
608 Expression::ByteLength(f) => Ok(Expression::Function(Box::new(Function::new(
610 "OCTET_LENGTH".to_string(),
611 vec![f.this],
612 )))),
613
614 Expression::TimestampDiff(f) => {
616 let mut args = vec![];
617 if let Some(ref unit_str) = f.unit {
619 args.push(Expression::Identifier(crate::expressions::Identifier::new(
620 unit_str.clone(),
621 )));
622 args.push(*f.this);
623 args.push(*f.expression);
624 } else {
625 args.push(*f.this);
626 args.push(*f.expression);
627 }
628 Ok(Expression::Function(Box::new(Function::new(
629 "TIMESTAMPDIFF".to_string(),
630 args,
631 ))))
632 }
633
634 Expression::TimestampAdd(f) => {
636 let mut args = vec![];
637 if let Some(ref unit_str) = f.unit {
638 args.push(Expression::Identifier(crate::expressions::Identifier::new(
639 unit_str.clone(),
640 )));
641 args.push(*f.this);
642 args.push(*f.expression);
643 } else {
644 args.push(*f.this);
645 args.push(*f.expression);
646 }
647 Ok(Expression::Function(Box::new(Function::new(
648 "TIMESTAMPADD".to_string(),
649 args,
650 ))))
651 }
652
653 Expression::ToArray(f) => Ok(Expression::Function(Box::new(Function::new(
655 "TO_ARRAY".to_string(),
656 vec![f.this],
657 )))),
658
659 Expression::DateAdd(f) => {
661 let unit_str = interval_unit_to_str(&f.unit);
662 let unit = Expression::Identifier(crate::expressions::Identifier {
663 name: unit_str,
664 quoted: false,
665 trailing_comments: Vec::new(),
666 span: None,
667 });
668 Ok(Expression::Function(Box::new(Function::new(
669 "DATEADD".to_string(),
670 vec![unit, f.interval, f.this],
671 ))))
672 }
673
674 Expression::DateSub(f) => {
676 let unit_str = interval_unit_to_str(&f.unit);
677 let unit = Expression::Identifier(crate::expressions::Identifier {
678 name: unit_str,
679 quoted: false,
680 trailing_comments: Vec::new(),
681 span: None,
682 });
683 let neg_expr = Expression::Mul(Box::new(crate::expressions::BinaryOp::new(
685 f.interval,
686 Expression::Neg(Box::new(crate::expressions::UnaryOp {
687 this: Expression::number(1),
688 inferred_type: None,
689 })),
690 )));
691 Ok(Expression::Function(Box::new(Function::new(
692 "DATEADD".to_string(),
693 vec![unit, neg_expr, f.this],
694 ))))
695 }
696
697 Expression::DateDiff(f) => {
699 let unit_str =
700 interval_unit_to_str(&f.unit.unwrap_or(crate::expressions::IntervalUnit::Day));
701 let unit = Expression::Identifier(crate::expressions::Identifier {
702 name: unit_str,
703 quoted: false,
704 trailing_comments: Vec::new(),
705 span: None,
706 });
707 Ok(Expression::Function(Box::new(Function::new(
708 "DATEDIFF".to_string(),
709 vec![unit, f.expression, f.this],
710 ))))
711 }
712
713 Expression::StringAgg(f) => {
716 let mut args = vec![f.this.clone()];
717 if let Some(separator) = &f.separator {
718 args.push(separator.clone());
719 }
720 Ok(Expression::Function(Box::new(Function::new(
721 "LISTAGG".to_string(),
722 args,
723 ))))
724 }
725
726 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
728 "STARTSWITH".to_string(),
729 vec![f.this, f.expression],
730 )))),
731
732 Expression::EndsWith(f) => Ok(Expression::EndsWith(f)),
734
735 Expression::Stuff(f) => {
737 let mut args = vec![*f.this];
738 if let Some(start) = f.start {
739 args.push(*start);
740 }
741 if let Some(length) = f.length {
742 args.push(Expression::number(length));
743 }
744 args.push(*f.expression);
745 Ok(Expression::Function(Box::new(Function::new(
746 "INSERT".to_string(),
747 args,
748 ))))
749 }
750
751 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
754 "SHA1".to_string(),
755 vec![f.this],
756 )))),
757
758 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
760 "SHA1_BINARY".to_string(),
761 vec![f.this],
762 )))),
763
764 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
766 "SHA2_BINARY".to_string(),
767 vec![*f.this],
768 )))),
769
770 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
772 "MD5_BINARY".to_string(),
773 vec![*f.this],
774 )))),
775
776 Expression::MD5NumberLower64(f) => Ok(Expression::Function(Box::new(Function::new(
778 "MD5_NUMBER_LOWER64".to_string(),
779 vec![f.this],
780 )))),
781
782 Expression::MD5NumberUpper64(f) => Ok(Expression::Function(Box::new(Function::new(
784 "MD5_NUMBER_UPPER64".to_string(),
785 vec![f.this],
786 )))),
787
788 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
791 "VECTOR_COSINE_SIMILARITY".to_string(),
792 vec![*f.this, *f.expression],
793 )))),
794
795 Expression::DotProduct(f) => Ok(Expression::Function(Box::new(Function::new(
797 "VECTOR_INNER_PRODUCT".to_string(),
798 vec![*f.this, *f.expression],
799 )))),
800
801 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
803 "VECTOR_L2_DISTANCE".to_string(),
804 vec![*f.this, *f.expression],
805 )))),
806
807 Expression::ManhattanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
809 "VECTOR_L1_DISTANCE".to_string(),
810 vec![*f.this, *f.expression],
811 )))),
812
813 Expression::JSONFormat(f) => {
816 let mut args = Vec::new();
817 if let Some(this) = f.this {
818 args.push(*this);
819 }
820 Ok(Expression::Function(Box::new(Function::new(
821 "TO_JSON".to_string(),
822 args,
823 ))))
824 }
825
826 Expression::JSONKeys(f) => Ok(Expression::Function(Box::new(Function::new(
828 "OBJECT_KEYS".to_string(),
829 vec![*f.this],
830 )))),
831
832 Expression::GetExtract(f) => Ok(Expression::Function(Box::new(Function::new(
834 "GET".to_string(),
835 vec![*f.this, *f.expression],
836 )))),
837
838 Expression::StarMap(f) => Ok(Expression::Function(Box::new(Function::new(
840 "OBJECT_CONSTRUCT".to_string(),
841 vec![f.this, f.expression],
842 )))),
843
844 Expression::LowerHex(f) => Ok(Expression::Function(Box::new(Function::new(
846 "TO_CHAR".to_string(),
847 vec![f.this],
848 )))),
849
850 Expression::Skewness(f) => Ok(Expression::Function(Box::new(Function::new(
852 "SKEW".to_string(),
853 vec![f.this],
854 )))),
855
856 Expression::StPoint(f) => Ok(Expression::Function(Box::new(Function::new(
858 "ST_MAKEPOINT".to_string(),
859 vec![*f.this, *f.expression],
860 )))),
861
862 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
864 "CONVERT_TIMEZONE".to_string(),
865 vec![*f.this],
866 )))),
867
868 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
871 "HEX_DECODE_BINARY".to_string(),
872 vec![*f.this],
873 )))),
874
875 Expression::UnixToTime(f) => {
877 let mut args = vec![*f.this];
878 if let Some(scale) = f.scale {
879 args.push(Expression::number(scale));
880 }
881 Ok(Expression::Function(Box::new(Function::new(
882 "TO_TIMESTAMP".to_string(),
883 args,
884 ))))
885 }
886
887 Expression::IfFunc(f) => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
890 condition: f.condition,
891 true_value: f.true_value,
892 false_value: Some(
893 f.false_value
894 .unwrap_or(Expression::Null(crate::expressions::Null)),
895 ),
896 original_name: Some("IFF".to_string()),
897 inferred_type: None,
898 }))),
899
900 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
903 "APPROX_COUNT_DISTINCT".to_string(),
904 vec![f.this],
905 )))),
906
907 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
909 "MAX_BY".to_string(),
910 vec![*f.this, *f.expression],
911 )))),
912
913 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
915 "MIN_BY".to_string(),
916 vec![*f.this, *f.expression],
917 )))),
918
919 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
922
923 Expression::Rand(r) => Ok(Expression::Rand(r)),
925
926 Expression::Uuid(u) => Ok(Expression::Uuid(u)),
929
930 Expression::Map(f) => Ok(Expression::Function(Box::new(Function::new(
933 "OBJECT_CONSTRUCT".to_string(),
934 f.keys
935 .into_iter()
936 .zip(f.values.into_iter())
937 .flat_map(|(k, v)| vec![k, v])
938 .collect(),
939 )))),
940
941 Expression::MapFunc(f) => Ok(Expression::Function(Box::new(Function::new(
943 "OBJECT_CONSTRUCT".to_string(),
944 f.keys
945 .into_iter()
946 .zip(f.values.into_iter())
947 .flat_map(|(k, v)| vec![k, v])
948 .collect(),
949 )))),
950
951 Expression::VarMap(f) => Ok(Expression::Function(Box::new(Function::new(
953 "OBJECT_CONSTRUCT".to_string(),
954 f.keys
955 .into_iter()
956 .zip(f.values.into_iter())
957 .flat_map(|(k, v)| vec![k, v])
958 .collect(),
959 )))),
960
961 Expression::JsonObject(f) => Ok(Expression::Function(Box::new(Function::new(
964 "OBJECT_CONSTRUCT_KEEP_NULL".to_string(),
965 f.pairs.into_iter().flat_map(|(k, v)| vec![k, v]).collect(),
966 )))),
967
968 Expression::JsonExtractScalar(f) => Ok(Expression::Function(Box::new(Function::new(
970 "JSON_EXTRACT_PATH_TEXT".to_string(),
971 vec![f.this, f.path],
972 )))),
973
974 Expression::Struct(f) => Ok(Expression::Function(Box::new(Function::new(
977 "OBJECT_CONSTRUCT".to_string(),
978 f.fields
979 .into_iter()
980 .flat_map(|(name, expr)| {
981 let key = match name {
982 Some(n) => Expression::string(n),
983 None => Expression::Null(crate::expressions::Null),
984 };
985 vec![key, expr]
986 })
987 .collect(),
988 )))),
989
990 Expression::JSONPathRoot(_) => Ok(Expression::Literal(Box::new(
993 crate::expressions::Literal::String(String::new()),
994 ))),
995
996 Expression::VarSamp(agg) => Ok(Expression::Variance(agg)),
999
1000 Expression::VarPop(agg) => Ok(Expression::VarPop(agg)),
1003
1004 Expression::Extract(f) => {
1007 use crate::expressions::DateTimeField;
1008 let transformed_this = self.transform_expr(f.this)?;
1010 let field_name = match &f.field {
1011 DateTimeField::Year => "YEAR",
1012 DateTimeField::Month => "MONTH",
1013 DateTimeField::Day => "DAY",
1014 DateTimeField::Hour => "HOUR",
1015 DateTimeField::Minute => "MINUTE",
1016 DateTimeField::Second => "SECOND",
1017 DateTimeField::Millisecond => "MILLISECOND",
1018 DateTimeField::Microsecond => "MICROSECOND",
1019 DateTimeField::Week => "WEEK",
1020 DateTimeField::WeekWithModifier(m) => {
1021 return Ok(Expression::Function(Box::new(Function::new(
1022 "DATE_PART".to_string(),
1023 vec![
1024 Expression::Identifier(crate::expressions::Identifier {
1025 name: format!("WEEK({})", m),
1026 quoted: false,
1027 trailing_comments: Vec::new(),
1028 span: None,
1029 }),
1030 transformed_this,
1031 ],
1032 ))))
1033 }
1034 DateTimeField::DayOfWeek => "DAYOFWEEK",
1035 DateTimeField::DayOfYear => "DAYOFYEAR",
1036 DateTimeField::Quarter => "QUARTER",
1037 DateTimeField::Epoch => "EPOCH",
1038 DateTimeField::Timezone => "TIMEZONE",
1039 DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
1040 DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
1041 DateTimeField::Date => "DATE",
1042 DateTimeField::Time => "TIME",
1043 DateTimeField::Custom(s) => {
1044 match s.to_uppercase().as_str() {
1046 "DAYOFMONTH" => "DAY",
1047 "DOW" => "DAYOFWEEK",
1048 "DOY" => "DAYOFYEAR",
1049 "ISODOW" => "DAYOFWEEKISO",
1050 "EPOCH_SECOND" | "EPOCH_SECONDS" => "EPOCH_SECOND",
1051 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => "EPOCH_MILLISECOND",
1052 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => "EPOCH_MICROSECOND",
1053 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => "EPOCH_NANOSECOND",
1054 _ => {
1055 return {
1056 let field_ident =
1057 Expression::Identifier(crate::expressions::Identifier {
1058 name: s.to_string(),
1059 quoted: false,
1060 trailing_comments: Vec::new(),
1061 span: None,
1062 });
1063 Ok(Expression::Function(Box::new(Function::new(
1064 "DATE_PART".to_string(),
1065 vec![field_ident, transformed_this],
1066 ))))
1067 }
1068 }
1069 }
1070 }
1071 };
1072 let field_ident = Expression::Identifier(crate::expressions::Identifier {
1073 name: field_name.to_string(),
1074 quoted: false,
1075 trailing_comments: Vec::new(),
1076 span: None,
1077 });
1078 Ok(Expression::Function(Box::new(Function::new(
1079 "DATE_PART".to_string(),
1080 vec![field_ident, transformed_this],
1081 ))))
1082 }
1083
1084 Expression::Function(f) => self.transform_function(*f),
1086
1087 Expression::Sum(mut agg) => {
1089 agg.this = self.transform_expr(agg.this)?;
1090 Ok(Expression::Sum(agg))
1091 }
1092
1093 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
1095
1096 Expression::NamedArgument(na) => {
1098 let transformed_value = self.transform_expr(na.value)?;
1099 Ok(Expression::NamedArgument(Box::new(
1100 crate::expressions::NamedArgument {
1101 name: na.name,
1102 value: transformed_value,
1103 separator: na.separator,
1104 },
1105 )))
1106 }
1107
1108 Expression::CreateTable(mut ct) => {
1110 for col in &mut ct.columns {
1111 if let Expression::DataType(new_dt) =
1112 self.transform_data_type(col.data_type.clone())?
1113 {
1114 col.data_type = new_dt;
1115 }
1116 if let Some(default_expr) = col.default.take() {
1118 col.default = Some(self.transform_expr(default_expr)?);
1119 }
1120 for constraint in &mut col.constraints {
1122 if let crate::expressions::ColumnConstraint::ComputedColumn(cc) = constraint
1123 {
1124 let transformed = self.transform_expr(*cc.expression.clone())?;
1125 cc.expression = Box::new(transformed);
1126 }
1127 }
1128 }
1129
1130 if ct.table_modifier.as_deref() == Some("EXTERNAL")
1133 && !ct.with_properties.is_empty()
1134 {
1135 for (key, value) in ct.with_properties.drain(..) {
1136 let formatted = Self::format_external_table_property(&key, &value);
1137 ct.properties
1138 .push(Expression::Raw(crate::expressions::Raw { sql: formatted }));
1139 }
1140 }
1141
1142 Ok(Expression::CreateTable(ct))
1143 }
1144
1145 Expression::AlterTable(mut at) => {
1147 for action in &mut at.actions {
1148 if let crate::expressions::AlterTableAction::AddColumn { column, .. } = action {
1149 if let Expression::DataType(new_dt) =
1150 self.transform_data_type(column.data_type.clone())?
1151 {
1152 column.data_type = new_dt;
1153 }
1154 }
1155 }
1156 Ok(Expression::AlterTable(at))
1157 }
1158
1159 Expression::Table(mut t) => {
1161 if let Some(when) = t.when.take() {
1162 let transformed_expr = self.transform_expr(*when.expression)?;
1164 t.when = Some(Box::new(crate::expressions::HistoricalData {
1165 this: when.this,
1166 kind: when.kind,
1167 expression: Box::new(transformed_expr),
1168 }));
1169 }
1170 Ok(Expression::Table(t))
1171 }
1172
1173 Expression::Subscript(s) => {
1175 let transformed_this = self.transform_expr(s.this)?;
1176 let transformed_index = self.transform_expr(s.index)?;
1177 Ok(Expression::Subscript(Box::new(
1178 crate::expressions::Subscript {
1179 this: transformed_this,
1180 index: transformed_index,
1181 },
1182 )))
1183 }
1184
1185 Expression::Paren(p) => {
1187 let transformed = self.transform_expr(p.this)?;
1188 Ok(Expression::Paren(Box::new(crate::expressions::Paren {
1189 this: transformed,
1190 trailing_comments: p.trailing_comments,
1191 })))
1192 }
1193
1194 Expression::Select(mut select) => {
1198 if let Some(ref mut order) = select.order_by {
1199 for ord in &mut order.expressions {
1200 if ord.nulls_first.is_none() {
1201 ord.nulls_first = Some(ord.desc);
1202 }
1203 }
1204 }
1205 Ok(Expression::Select(select))
1206 }
1207
1208 Expression::WindowFunction(mut wf) => {
1210 for ord in &mut wf.over.order_by {
1211 if ord.nulls_first.is_none() {
1212 ord.nulls_first = Some(ord.desc);
1213 }
1214 }
1215 Ok(Expression::WindowFunction(wf))
1216 }
1217
1218 Expression::Window(mut w) => {
1220 for ord in &mut w.order_by {
1221 if ord.nulls_first.is_none() {
1222 ord.nulls_first = Some(ord.desc);
1223 }
1224 }
1225 Ok(Expression::Window(w))
1226 }
1227
1228 Expression::Lateral(mut lat) => {
1230 let is_flatten = match lat.this.as_ref() {
1232 Expression::Function(f) => f.name.to_uppercase() == "FLATTEN",
1233 _ => false,
1234 };
1235 if is_flatten && lat.column_aliases.is_empty() {
1236 lat.column_aliases = vec![
1238 "SEQ".to_string(),
1239 "KEY".to_string(),
1240 "PATH".to_string(),
1241 "INDEX".to_string(),
1242 "VALUE".to_string(),
1243 "THIS".to_string(),
1244 ];
1245 if lat.alias.is_none() {
1247 lat.alias = Some("_flattened".to_string());
1248 }
1249 }
1250 Ok(Expression::Lateral(lat))
1251 }
1252
1253 _ => Ok(expr),
1255 }
1256 }
1257}
1258
1259#[cfg(feature = "transpile")]
1260impl SnowflakeDialect {
1261 fn format_external_table_property(key: &str, value: &str) -> String {
1264 let lower_key = key.to_lowercase();
1265 match lower_key.as_str() {
1266 "location" => format!("LOCATION={}", value),
1267 "file_format" => {
1268 let formatted_value = Self::format_file_format_value(value);
1270 format!("FILE_FORMAT={}", formatted_value)
1271 }
1272 _ => format!("{}={}", key, value),
1273 }
1274 }
1275
1276 fn format_file_format_value(value: &str) -> String {
1280 if !value.starts_with('(') {
1281 return value.to_string();
1282 }
1283 let inner = value[1..value.len() - 1].trim();
1285 let mut result = String::from("(");
1287 let mut parts: Vec<String> = Vec::new();
1288 let tokens: Vec<&str> = inner.split_whitespace().collect();
1290 let mut i = 0;
1291 while i < tokens.len() {
1292 let token = tokens[i];
1293 if i + 2 < tokens.len() && tokens[i + 1] == "=" {
1294 let val = Self::format_property_value(tokens[i + 2]);
1296 parts.push(format!("{}={}", token, val));
1297 i += 3;
1298 } else if token.contains('=') {
1299 let eq_pos = token.find('=').unwrap();
1301 let k = &token[..eq_pos];
1302 let v = Self::format_property_value(&token[eq_pos + 1..]);
1303 parts.push(format!("{}={}", k, v));
1304 i += 1;
1305 } else {
1306 parts.push(token.to_string());
1307 i += 1;
1308 }
1309 }
1310 result.push_str(&parts.join(" "));
1311 result.push(')');
1312 result
1313 }
1314
1315 fn format_property_value(value: &str) -> String {
1317 match value.to_lowercase().as_str() {
1318 "true" => "TRUE".to_string(),
1319 "false" => "FALSE".to_string(),
1320 _ => value.to_string(),
1321 }
1322 }
1323
1324 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1326 use crate::expressions::DataType;
1327 let transformed = match dt {
1328 DataType::Text => DataType::VarChar {
1330 length: None,
1331 parenthesized_length: false,
1332 },
1333 DataType::Struct { fields, .. } => {
1335 let _ = fields; DataType::Custom {
1338 name: "OBJECT".to_string(),
1339 }
1340 }
1341 DataType::Custom { name } => {
1343 let upper_name = name.to_uppercase();
1344 match upper_name.as_str() {
1345 "NVARCHAR" | "NCHAR" | "NATIONAL CHARACTER VARYING" | "NATIONAL CHAR" => {
1347 DataType::VarChar {
1348 length: None,
1349 parenthesized_length: false,
1350 }
1351 }
1352 "STRING" => DataType::VarChar {
1354 length: None,
1355 parenthesized_length: false,
1356 },
1357 "BIGDECIMAL" => DataType::Double {
1359 precision: None,
1360 scale: None,
1361 },
1362 "NESTED" => DataType::Custom {
1364 name: "OBJECT".to_string(),
1365 },
1366 "BYTEINT" => DataType::Int {
1368 length: None,
1369 integer_spelling: false,
1370 },
1371 "CHAR VARYING" | "CHARACTER VARYING" => DataType::VarChar {
1373 length: None,
1374 parenthesized_length: false,
1375 },
1376 "SQL_DOUBLE" => DataType::Double {
1378 precision: None,
1379 scale: None,
1380 },
1381 "SQL_VARCHAR" => DataType::VarChar {
1383 length: None,
1384 parenthesized_length: false,
1385 },
1386 "TIMESTAMP_NTZ" => DataType::Custom {
1388 name: "TIMESTAMPNTZ".to_string(),
1389 },
1390 "TIMESTAMP_LTZ" => DataType::Custom {
1392 name: "TIMESTAMPLTZ".to_string(),
1393 },
1394 "TIMESTAMP_TZ" => DataType::Custom {
1396 name: "TIMESTAMPTZ".to_string(),
1397 },
1398 "NCHAR VARYING" => DataType::VarChar {
1400 length: None,
1401 parenthesized_length: false,
1402 },
1403 "NUMBER" => DataType::Decimal {
1405 precision: Some(38),
1406 scale: Some(0),
1407 },
1408 _ if name.starts_with("NUMBER(") => {
1409 let inner = &name[7..name.len() - 1]; let parts: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1413 let precision = parts.first().and_then(|p| p.parse::<u32>().ok());
1414 let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
1415 DataType::Decimal { precision, scale }
1416 }
1417 _ => DataType::Custom { name },
1418 }
1419 }
1420 DataType::Decimal {
1422 precision: None,
1423 scale: None,
1424 } => DataType::Decimal {
1425 precision: Some(38),
1426 scale: Some(0),
1427 },
1428 DataType::Float { .. } => DataType::Double {
1430 precision: None,
1431 scale: None,
1432 },
1433 other => other,
1435 };
1436 Ok(Expression::DataType(transformed))
1437 }
1438
1439 fn map_date_part(abbr: &str) -> Option<&'static str> {
1441 match abbr.to_uppercase().as_str() {
1442 "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some("YEAR"),
1444 "MM" | "MON" | "MONS" | "MONTHS" => Some("MONTH"),
1446 "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some("DAY"),
1448 "DAY OF WEEK" | "WEEKDAY" | "DOW" | "DW" => Some("DAYOFWEEK"),
1450 "WEEKDAY_ISO" | "DOW_ISO" | "DW_ISO" | "DAYOFWEEK_ISO" => Some("DAYOFWEEKISO"),
1451 "DAY OF YEAR" | "DOY" | "DY" => Some("DAYOFYEAR"),
1453 "W" | "WK" | "WEEKOFYEAR" | "WOY" | "WY" => Some("WEEK"),
1455 "WEEK_ISO" | "WEEKOFYEARISO" | "WEEKOFYEAR_ISO" => Some("WEEKISO"),
1456 "Q" | "QTR" | "QTRS" | "QUARTERS" => Some("QUARTER"),
1458 "H" | "HH" | "HR" | "HOURS" | "HRS" => Some("HOUR"),
1460 "MI" | "MIN" | "MINUTES" | "MINS" => Some("MINUTE"),
1462 "S" | "SEC" | "SECONDS" | "SECS" => Some("SECOND"),
1464 "MS" | "MSEC" | "MSECS" | "MSECOND" | "MSECONDS" | "MILLISEC" | "MILLISECS"
1466 | "MILLISECON" | "MILLISECONDS" => Some("MILLISECOND"),
1467 "US" | "USEC" | "USECS" | "MICROSEC" | "MICROSECS" | "USECOND" | "USECONDS"
1469 | "MICROSECONDS" => Some("MICROSECOND"),
1470 "NS" | "NSEC" | "NANOSEC" | "NSECOND" | "NSECONDS" | "NANOSECS" => Some("NANOSECOND"),
1472 "EPOCH_SECOND" | "EPOCH_SECONDS" => Some("EPOCH_SECOND"),
1474 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Some("EPOCH_MILLISECOND"),
1475 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Some("EPOCH_MICROSECOND"),
1476 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Some("EPOCH_NANOSECOND"),
1477 "TZH" => Some("TIMEZONE_HOUR"),
1479 "TZM" => Some("TIMEZONE_MINUTE"),
1480 "DEC" | "DECS" | "DECADES" => Some("DECADE"),
1482 "MIL" | "MILS" | "MILLENIA" => Some("MILLENNIUM"),
1484 "C" | "CENT" | "CENTS" | "CENTURIES" => Some("CENTURY"),
1486 _ => None,
1488 }
1489 }
1490
1491 fn transform_date_part_arg(&self, expr: Expression) -> Expression {
1493 match &expr {
1494 Expression::Literal(lit)
1496 if matches!(lit.as_ref(), crate::expressions::Literal::String(_)) =>
1497 {
1498 let crate::expressions::Literal::String(s) = lit.as_ref() else {
1499 unreachable!()
1500 };
1501 Expression::Identifier(crate::expressions::Identifier {
1502 name: s.clone(),
1503 quoted: false,
1504 trailing_comments: Vec::new(),
1505 span: None,
1506 })
1507 }
1508 Expression::Identifier(id) => {
1510 if let Some(canonical) = Self::map_date_part(&id.name) {
1511 Expression::Identifier(crate::expressions::Identifier {
1512 name: canonical.to_string(),
1513 quoted: false,
1514 trailing_comments: Vec::new(),
1515 span: None,
1516 })
1517 } else {
1518 expr
1520 }
1521 }
1522 Expression::Var(v) => {
1523 if let Some(canonical) = Self::map_date_part(&v.this) {
1524 Expression::Identifier(crate::expressions::Identifier {
1525 name: canonical.to_string(),
1526 quoted: false,
1527 trailing_comments: Vec::new(),
1528 span: None,
1529 })
1530 } else {
1531 expr
1532 }
1533 }
1534 Expression::Column(col) if col.table.is_none() => {
1536 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1537 Expression::Identifier(crate::expressions::Identifier {
1538 name: canonical.to_string(),
1539 quoted: false,
1540 trailing_comments: Vec::new(),
1541 span: None,
1542 })
1543 } else {
1544 expr
1546 }
1547 }
1548 _ => expr,
1549 }
1550 }
1551
1552 fn transform_date_part_arg_identifiers_only(&self, expr: Expression) -> Expression {
1555 match &expr {
1556 Expression::Identifier(id) => {
1557 if let Some(canonical) = Self::map_date_part(&id.name) {
1558 Expression::Identifier(crate::expressions::Identifier {
1559 name: canonical.to_string(),
1560 quoted: false,
1561 trailing_comments: Vec::new(),
1562 span: None,
1563 })
1564 } else {
1565 expr
1566 }
1567 }
1568 Expression::Var(v) => {
1569 if let Some(canonical) = Self::map_date_part(&v.this) {
1570 Expression::Identifier(crate::expressions::Identifier {
1571 name: canonical.to_string(),
1572 quoted: false,
1573 trailing_comments: Vec::new(),
1574 span: None,
1575 })
1576 } else {
1577 expr
1578 }
1579 }
1580 Expression::Column(col) if col.table.is_none() => {
1581 if let Some(canonical) = Self::map_date_part(&col.name.name) {
1582 Expression::Identifier(crate::expressions::Identifier {
1583 name: canonical.to_string(),
1584 quoted: false,
1585 trailing_comments: Vec::new(),
1586 span: None,
1587 })
1588 } else {
1589 expr
1590 }
1591 }
1592 _ => expr,
1593 }
1594 }
1595
1596 fn transform_json_path(path: &str) -> String {
1600 fn is_safe_identifier(s: &str) -> bool {
1603 if s.is_empty() {
1604 return false;
1605 }
1606 let mut chars = s.chars();
1607 match chars.next() {
1608 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
1609 _ => return false,
1610 }
1611 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
1612 }
1613
1614 if !path.contains('.') && !path.contains('[') && !path.contains(':') {
1617 if is_safe_identifier(path) {
1618 return path.to_string();
1619 } else {
1620 return format!("[\"{}\"]", path);
1622 }
1623 }
1624
1625 let result = path.replace(':', ".");
1628 result
1629 }
1630
1631 fn transform_interval(&self, interval: crate::expressions::Interval) -> Result<Expression> {
1633 use crate::expressions::{Interval, Literal};
1634
1635 fn expand_unit(abbr: &str) -> &'static str {
1637 match abbr.to_uppercase().as_str() {
1638 "D" => "DAY",
1639 "H" => "HOUR",
1640 "M" => "MINUTE",
1641 "MS" => "MILLISECOND",
1642 "NS" => "NANOSECOND",
1643 "Q" => "QUARTER",
1644 "S" => "SECOND",
1645 "US" => "MICROSECOND",
1646 "W" => "WEEK",
1647 "Y" => "YEAR",
1648 "WEEK" | "WEEKS" => "WEEK",
1650 "DAY" | "DAYS" => "DAY",
1651 "HOUR" | "HOURS" => "HOUR",
1652 "MINUTE" | "MINUTES" => "MINUTE",
1653 "SECOND" | "SECONDS" => "SECOND",
1654 "MONTH" | "MONTHS" => "MONTH",
1655 "YEAR" | "YEARS" => "YEAR",
1656 "QUARTER" | "QUARTERS" => "QUARTER",
1657 "MILLISECOND" | "MILLISECONDS" => "MILLISECOND",
1658 "MICROSECOND" | "MICROSECONDS" => "MICROSECOND",
1659 "NANOSECOND" | "NANOSECONDS" => "NANOSECOND",
1660 _ => "", }
1662 }
1663
1664 fn parse_interval_string(s: &str) -> Option<(&str, &str)> {
1666 let s = s.trim();
1667
1668 let mut num_end = 0;
1671 let mut chars = s.chars().peekable();
1672
1673 if chars.peek() == Some(&'-') {
1675 chars.next();
1676 num_end += 1;
1677 }
1678
1679 while let Some(&c) = chars.peek() {
1681 if c.is_ascii_digit() {
1682 chars.next();
1683 num_end += 1;
1684 } else {
1685 break;
1686 }
1687 }
1688
1689 if chars.peek() == Some(&'.') {
1691 chars.next();
1692 num_end += 1;
1693 while let Some(&c) = chars.peek() {
1694 if c.is_ascii_digit() {
1695 chars.next();
1696 num_end += 1;
1697 } else {
1698 break;
1699 }
1700 }
1701 }
1702
1703 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1704 return None; }
1706
1707 let value = &s[..num_end];
1708 let rest = s[num_end..].trim();
1709
1710 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1712 return None;
1713 }
1714
1715 Some((value, rest))
1716 }
1717
1718 if let Some(Expression::Literal(ref lit)) = interval.this {
1720 if let Literal::String(ref s) = lit.as_ref() {
1721 if let Some((value, unit)) = parse_interval_string(s) {
1722 let expanded = expand_unit(unit);
1723 if !expanded.is_empty() {
1724 let new_value = format!("{} {}", value, expanded);
1726
1727 return Ok(Expression::Interval(Box::new(Interval {
1728 this: Some(Expression::Literal(Box::new(Literal::String(new_value)))),
1729 unit: None, })));
1731 }
1732 }
1733 }
1734 }
1735
1736 Ok(Expression::Interval(Box::new(interval)))
1738 }
1739
1740 fn transform_function(&self, f: Function) -> Result<Expression> {
1741 let transformed_args: Vec<Expression> = f
1743 .args
1744 .into_iter()
1745 .map(|arg| self.transform_expr(arg))
1746 .collect::<Result<Vec<_>>>()?;
1747
1748 let f = Function {
1749 name: f.name,
1750 args: transformed_args,
1751 distinct: f.distinct,
1752 trailing_comments: f.trailing_comments,
1753 use_bracket_syntax: f.use_bracket_syntax,
1754 no_parens: f.no_parens,
1755 quoted: f.quoted,
1756 span: None,
1757 inferred_type: None,
1758 };
1759
1760 let name_upper = f.name.to_uppercase();
1761 match name_upper.as_str() {
1762 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1764 original_name: None,
1765 expressions: f.args,
1766 inferred_type: None,
1767 }))),
1768
1769 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1771 original_name: None,
1772 expressions: f.args,
1773 inferred_type: None,
1774 }))),
1775
1776 "NVL2" => Ok(Expression::Function(Box::new(f))),
1778
1779 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1781 Function::new("LISTAGG".to_string(), f.args),
1782 ))),
1783
1784 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1786 Function::new("LISTAGG".to_string(), f.args),
1787 ))),
1788
1789 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1791 "SUBSTRING".to_string(),
1792 f.args,
1793 )))),
1794
1795 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
1797 "FLATTEN".to_string(),
1798 f.args,
1799 )))),
1800
1801 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1803 "FLATTEN".to_string(),
1804 f.args,
1805 )))),
1806
1807 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1809
1810 "NOW" => Ok(Expression::Function(Box::new(Function {
1812 name: "CURRENT_TIMESTAMP".to_string(),
1813 args: f.args,
1814 distinct: false,
1815 trailing_comments: Vec::new(),
1816 use_bracket_syntax: false,
1817 no_parens: f.no_parens,
1818 quoted: false,
1819 span: None,
1820 inferred_type: None,
1821 }))),
1822
1823 "GETDATE" => Ok(Expression::Function(Box::new(Function {
1825 name: "CURRENT_TIMESTAMP".to_string(),
1826 args: f.args,
1827 distinct: false,
1828 trailing_comments: Vec::new(),
1829 use_bracket_syntax: false,
1830 no_parens: f.no_parens,
1831 quoted: false,
1832 span: None,
1833 inferred_type: None,
1834 }))),
1835
1836 "CURRENT_TIMESTAMP" if f.args.is_empty() => {
1840 Ok(Expression::Function(Box::new(Function {
1841 name: "CURRENT_TIMESTAMP".to_string(),
1842 args: Vec::new(),
1843 distinct: false,
1844 trailing_comments: Vec::new(),
1845 use_bracket_syntax: false,
1846 no_parens: false, quoted: false,
1848 span: None,
1849 inferred_type: None,
1850 })))
1851 }
1852
1853 "TO_DATE" => {
1857 if f.args.len() == 1 {
1858 if let Expression::Literal(lit) = &f.args[0] {
1859 if let crate::expressions::Literal::String(s) = lit.as_ref() {
1860 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
1862 return Ok(Expression::Cast(Box::new(Cast {
1863 this: f.args.into_iter().next().unwrap(),
1864 to: crate::expressions::DataType::Date,
1865 double_colon_syntax: false,
1866 trailing_comments: Vec::new(),
1867 format: None,
1868 default: None,
1869 inferred_type: None,
1870 })));
1871 }
1872 }
1873 }
1874 }
1875 let mut args = f.args;
1877 if args.len() >= 2 {
1878 args[1] = Self::normalize_format_arg(args[1].clone());
1879 }
1880 Ok(Expression::Function(Box::new(Function::new(
1881 "TO_DATE".to_string(),
1882 args,
1883 ))))
1884 }
1885
1886 "TO_TIME" => {
1888 if f.args.len() == 1 {
1889 if let Expression::Literal(lit) = &f.args[0] {
1890 if let crate::expressions::Literal::String(_) = lit.as_ref() {
1891 return Ok(Expression::Cast(Box::new(Cast {
1892 this: f.args.into_iter().next().unwrap(),
1893 to: crate::expressions::DataType::Time {
1894 precision: None,
1895 timezone: false,
1896 },
1897 double_colon_syntax: false,
1898 trailing_comments: Vec::new(),
1899 format: None,
1900 default: None,
1901 inferred_type: None,
1902 })));
1903 }
1904 }
1905 }
1906 let mut args = f.args;
1908 if args.len() >= 2 {
1909 args[1] = Self::normalize_format_arg(args[1].clone());
1910 }
1911 Ok(Expression::Function(Box::new(Function::new(
1912 "TO_TIME".to_string(),
1913 args,
1914 ))))
1915 }
1916
1917 "TO_TIMESTAMP" => {
1924 let args = f.args;
1925 if args.len() == 1 {
1926 let arg = &args[0];
1927 match arg {
1928 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_datetime(s)) =>
1929 {
1930 let Literal::String(_) = lit.as_ref() else {
1931 unreachable!()
1932 };
1933 return Ok(Expression::Cast(Box::new(Cast {
1935 this: args.into_iter().next().unwrap(),
1936 to: DataType::Timestamp {
1937 precision: None,
1938 timezone: false,
1939 },
1940 double_colon_syntax: false,
1941 trailing_comments: vec![],
1942 format: None,
1943 default: None,
1944 inferred_type: None,
1945 })));
1946 }
1947 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if Self::looks_like_epoch(s)) =>
1948 {
1949 let Literal::String(_) = lit.as_ref() else {
1950 unreachable!()
1951 };
1952 return Ok(Expression::UnixToTime(Box::new(
1954 crate::expressions::UnixToTime {
1955 this: Box::new(args.into_iter().next().unwrap()),
1956 scale: None,
1957 zone: None,
1958 hours: None,
1959 minutes: None,
1960 format: None,
1961 target_type: None,
1962 },
1963 )));
1964 }
1965 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1966 return Ok(Expression::UnixToTime(Box::new(
1968 crate::expressions::UnixToTime {
1969 this: Box::new(args.into_iter().next().unwrap()),
1970 scale: None,
1971 zone: None,
1972 hours: None,
1973 minutes: None,
1974 format: None,
1975 target_type: None,
1976 },
1977 )));
1978 }
1979 Expression::Neg(_) => {
1980 return Ok(Expression::UnixToTime(Box::new(
1982 crate::expressions::UnixToTime {
1983 this: Box::new(args.into_iter().next().unwrap()),
1984 scale: None,
1985 zone: None,
1986 hours: None,
1987 minutes: None,
1988 format: None,
1989 target_type: None,
1990 },
1991 )));
1992 }
1993 _ => {
1994 return Ok(Expression::Function(Box::new(Function::new(
1996 "TO_TIMESTAMP".to_string(),
1997 args,
1998 ))));
1999 }
2000 }
2001 } else if args.len() == 2 {
2002 let second_arg = &args[1];
2003 let is_int_scale = match second_arg {
2005 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
2006 let Literal::Number(n) = lit.as_ref() else {
2007 unreachable!()
2008 };
2009 n.parse::<i64>().is_ok()
2010 }
2011 _ => false,
2012 };
2013
2014 if is_int_scale {
2015 let mut args_iter = args.into_iter();
2017 let value = args_iter.next().unwrap();
2018 let scale_expr = args_iter.next().unwrap();
2019 let scale = if let Expression::Literal(lit) = &scale_expr {
2020 if let Literal::Number(n) = lit.as_ref() {
2021 n.parse::<i64>().ok()
2022 } else {
2023 None
2024 }
2025 } else {
2026 None
2027 };
2028 return Ok(Expression::UnixToTime(Box::new(
2029 crate::expressions::UnixToTime {
2030 this: Box::new(value),
2031 scale,
2032 zone: None,
2033 hours: None,
2034 minutes: None,
2035 format: None,
2036 target_type: None,
2037 },
2038 )));
2039 } else {
2040 let mut args_iter = args.into_iter();
2042 let value = args_iter.next().unwrap();
2043 let format_expr = args_iter.next().unwrap();
2044 let format_str = match &format_expr {
2045 Expression::Literal(lit)
2046 if matches!(lit.as_ref(), Literal::String(_)) =>
2047 {
2048 let Literal::String(s) = lit.as_ref() else {
2049 unreachable!()
2050 };
2051 s.clone()
2052 }
2053 _ => {
2054 return Ok(Expression::Function(Box::new(Function::new(
2056 "TO_TIMESTAMP".to_string(),
2057 vec![value, format_expr],
2058 ))));
2059 }
2060 };
2061 let normalized_format = Self::normalize_snowflake_format(&format_str);
2063 return Ok(Expression::StrToTime(Box::new(
2064 crate::expressions::StrToTime {
2065 this: Box::new(value),
2066 format: normalized_format,
2067 zone: None,
2068 safe: None,
2069 target_type: None,
2070 },
2071 )));
2072 }
2073 }
2074 Ok(Expression::Function(Box::new(Function::new(
2076 "TO_TIMESTAMP".to_string(),
2077 args,
2078 ))))
2079 }
2080
2081 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
2083
2084 "ROUND"
2087 if f.args
2088 .iter()
2089 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
2090 {
2091 let mut expr_val = None;
2092 let mut scale_val = None;
2093 let mut rounding_mode_val = None;
2094 for arg in &f.args {
2095 if let Expression::NamedArgument(na) = arg {
2096 match na.name.name.to_uppercase().as_str() {
2097 "EXPR" => expr_val = Some(na.value.clone()),
2098 "SCALE" => scale_val = Some(na.value.clone()),
2099 "ROUNDING_MODE" => rounding_mode_val = Some(na.value.clone()),
2100 _ => {}
2101 }
2102 }
2103 }
2104 if let Some(expr) = expr_val {
2105 let mut args = vec![expr];
2106 if let Some(scale) = scale_val {
2107 args.push(scale);
2108 }
2109 if let Some(mode) = rounding_mode_val {
2110 args.push(mode);
2111 }
2112 Ok(Expression::Function(Box::new(Function::new(
2113 "ROUND".to_string(),
2114 args,
2115 ))))
2116 } else {
2117 Ok(Expression::Function(Box::new(f)))
2118 }
2119 }
2120
2121 "DATE_FORMAT" => {
2124 let mut args = f.args;
2125 if !args.is_empty() {
2127 if matches!(&args[0], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)))
2128 {
2129 args[0] = Expression::Cast(Box::new(crate::expressions::Cast {
2130 this: args[0].clone(),
2131 to: DataType::Timestamp {
2132 precision: None,
2133 timezone: false,
2134 },
2135 trailing_comments: Vec::new(),
2136 double_colon_syntax: false,
2137 format: None,
2138 default: None,
2139 inferred_type: None,
2140 }));
2141 }
2142 }
2143 if args.len() >= 2 {
2145 if let Expression::Literal(ref lit) = args[1] {
2146 if let Literal::String(ref fmt) = lit.as_ref() {
2147 let sf_fmt = strftime_to_snowflake_format(fmt);
2148 args[1] = Expression::Literal(Box::new(Literal::String(sf_fmt)));
2149 }
2150 }
2151 }
2152 Ok(Expression::Function(Box::new(Function::new(
2153 "TO_CHAR".to_string(),
2154 args,
2155 ))))
2156 }
2157
2158 "ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2160 "ARRAY_CONSTRUCT".to_string(),
2161 f.args,
2162 )))),
2163
2164 "STRUCT" => {
2167 let mut oc_args = Vec::new();
2168 for arg in f.args {
2169 match arg {
2170 Expression::Alias(a) => {
2171 oc_args.push(Expression::Literal(Box::new(
2173 crate::expressions::Literal::String(a.alias.name.clone()),
2174 )));
2175 oc_args.push(a.this);
2176 }
2177 other => {
2178 oc_args.push(other);
2180 }
2181 }
2182 }
2183 Ok(Expression::Function(Box::new(Function::new(
2184 "OBJECT_CONSTRUCT".to_string(),
2185 oc_args,
2186 ))))
2187 }
2188
2189 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
2191 "GET_PATH".to_string(),
2192 f.args,
2193 )))),
2194
2195 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
2197 "JSON_EXTRACT_PATH_TEXT".to_string(),
2198 f.args,
2199 )))),
2200
2201 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2203 f.args.into_iter().next().unwrap(),
2204 )))),
2205
2206 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2208 this: f.args.into_iter().next().unwrap(),
2209 decimals: None,
2210 to: None,
2211 }))),
2212
2213 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
2215
2216 "SPLIT" => Ok(Expression::Function(Box::new(f))),
2218
2219 "ARRAY_AGG" => Ok(Expression::Function(Box::new(f))),
2221
2222 "JSON_PARSE" | "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2224 "PARSE_JSON".to_string(),
2225 f.args,
2226 )))),
2227
2228 "RAND" => {
2230 let seed = f.args.first().cloned().map(Box::new);
2231 Ok(Expression::Rand(Box::new(crate::expressions::Rand {
2232 seed,
2233 lower: None,
2234 upper: None,
2235 })))
2236 }
2237
2238 "SHA" => Ok(Expression::Function(Box::new(Function::new(
2240 "SHA1".to_string(),
2241 f.args,
2242 )))),
2243
2244 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
2246 "APPROX_COUNT_DISTINCT".to_string(),
2247 f.args,
2248 )))),
2249
2250 "GEN_RANDOM_UUID" | "UUID" => {
2252 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2253 this: None,
2254 name: None,
2255 is_string: None,
2256 })))
2257 }
2258
2259 "NEWID" => Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2261 this: None,
2262 name: None,
2263 is_string: None,
2264 }))),
2265
2266 "UUID_STRING" => {
2268 if f.args.is_empty() {
2269 Ok(Expression::Uuid(Box::new(crate::expressions::Uuid {
2270 this: None,
2271 name: None,
2272 is_string: None,
2273 })))
2274 } else {
2275 Ok(Expression::Function(Box::new(Function::new(
2276 "UUID_STRING".to_string(),
2277 f.args,
2278 ))))
2279 }
2280 }
2281
2282 "IF" if f.args.len() >= 2 => {
2284 let mut args = f.args;
2285 let condition = args.remove(0);
2286 let true_val = args.remove(0);
2287 let false_val = if !args.is_empty() {
2288 Some(args.remove(0))
2289 } else {
2290 None
2291 };
2292 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2293 condition,
2294 true_value: true_val,
2295 false_value: Some(
2296 false_val.unwrap_or(Expression::Null(crate::expressions::Null)),
2297 ),
2298 original_name: Some("IFF".to_string()),
2299 inferred_type: None,
2300 })))
2301 }
2302
2303 "SQUARE" if f.args.len() == 1 => {
2305 let x = f.args.into_iter().next().unwrap();
2306 Ok(Expression::Power(Box::new(
2307 crate::expressions::BinaryFunc {
2308 original_name: None,
2309 this: x,
2310 expression: Expression::number(2),
2311 inferred_type: None,
2312 },
2313 )))
2314 }
2315
2316 "POW" if f.args.len() == 2 => {
2318 let mut args = f.args.into_iter();
2319 let x = args.next().unwrap();
2320 let y = args.next().unwrap();
2321 Ok(Expression::Power(Box::new(
2322 crate::expressions::BinaryFunc {
2323 original_name: None,
2324 this: x,
2325 expression: y,
2326 inferred_type: None,
2327 },
2328 )))
2329 }
2330
2331 "MOD" if f.args.len() == 2 => {
2333 let mut args = f.args.into_iter();
2334 let x = args.next().unwrap();
2335 let y = args.next().unwrap();
2336 Ok(Expression::Mod(Box::new(crate::expressions::BinaryOp {
2337 left: x,
2338 right: y,
2339 left_comments: Vec::new(),
2340 operator_comments: Vec::new(),
2341 trailing_comments: Vec::new(),
2342 inferred_type: None,
2343 })))
2344 }
2345
2346 "APPROXIMATE_JACCARD_INDEX" => Ok(Expression::Function(Box::new(Function::new(
2348 "APPROXIMATE_SIMILARITY".to_string(),
2349 f.args,
2350 )))),
2351
2352 "ARRAY_CONSTRUCT" => Ok(Expression::ArrayFunc(Box::new(
2354 crate::expressions::ArrayConstructor {
2355 expressions: f.args,
2356 bracket_notation: true,
2357 use_list_keyword: false,
2358 },
2359 ))),
2360
2361 "APPROX_TOP_K" if f.args.len() == 1 => {
2363 let mut args = f.args;
2364 args.push(Expression::number(1));
2365 Ok(Expression::Function(Box::new(Function::new(
2366 "APPROX_TOP_K".to_string(),
2367 args,
2368 ))))
2369 }
2370
2371 "TO_DECIMAL" | "TO_NUMERIC" => Ok(Expression::Function(Box::new(Function::new(
2373 "TO_NUMBER".to_string(),
2374 f.args,
2375 )))),
2376
2377 "TRY_TO_DECIMAL" | "TRY_TO_NUMERIC" => Ok(Expression::Function(Box::new(
2379 Function::new("TRY_TO_NUMBER".to_string(), f.args),
2380 ))),
2381
2382 "STDDEV_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2384 "STDDEV".to_string(),
2385 f.args,
2386 )))),
2387
2388 "STRTOK" if f.args.len() >= 1 => {
2390 let mut args = f.args;
2391 if args.len() == 1 {
2393 args.push(Expression::string(" ".to_string()));
2394 }
2395 if args.len() == 2 {
2397 args.push(Expression::number(1));
2398 }
2399 Ok(Expression::Function(Box::new(Function::new(
2400 "STRTOK".to_string(),
2401 args,
2402 ))))
2403 }
2404
2405 "STRTOK_TO_ARRAY" if f.args.len() == 1 => {
2406 let mut args = f.args;
2407 args.push(Expression::string(" ".to_string()));
2408 Ok(Expression::Function(Box::new(Function::new(
2409 "STRTOK_TO_ARRAY".to_string(),
2410 args,
2411 ))))
2412 }
2413
2414 "WEEKOFYEAR" => Ok(Expression::Function(Box::new(Function::new(
2416 "WEEK".to_string(),
2417 f.args,
2418 )))),
2419
2420 "LIKE" if f.args.len() >= 2 => {
2422 let mut args = f.args.into_iter();
2423 let left = args.next().unwrap();
2424 let right = args.next().unwrap();
2425 let escape = args.next();
2426 Ok(Expression::Like(Box::new(crate::expressions::LikeOp {
2427 left,
2428 right,
2429 escape,
2430 quantifier: None,
2431 inferred_type: None,
2432 })))
2433 }
2434
2435 "ILIKE" if f.args.len() >= 2 => {
2437 let mut args = f.args.into_iter();
2438 let left = args.next().unwrap();
2439 let right = args.next().unwrap();
2440 let escape = args.next();
2441 Ok(Expression::ILike(Box::new(crate::expressions::LikeOp {
2442 left,
2443 right,
2444 escape,
2445 quantifier: None,
2446 inferred_type: None,
2447 })))
2448 }
2449
2450 "RLIKE" if f.args.len() >= 2 => {
2452 let mut args = f.args.into_iter();
2453 let left = args.next().unwrap();
2454 let pattern = args.next().unwrap();
2455 let flags = args.next();
2456 Ok(Expression::RegexpLike(Box::new(
2457 crate::expressions::RegexpFunc {
2458 this: left,
2459 pattern,
2460 flags,
2461 },
2462 )))
2463 }
2464
2465 "IFF" if f.args.len() >= 2 => {
2467 let mut args = f.args;
2468 let condition = args.remove(0);
2469 let true_value = args.remove(0);
2470 let false_value = if !args.is_empty() {
2471 Some(args.remove(0))
2472 } else {
2473 None
2474 };
2475 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
2476 condition,
2477 true_value,
2478 false_value,
2479 original_name: Some("IFF".to_string()),
2480 inferred_type: None,
2481 })))
2482 }
2483
2484 "TIMESTAMP_NTZ_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMPNTZFROMPARTS" => {
2486 Ok(Expression::Function(Box::new(Function::new(
2487 "TIMESTAMP_FROM_PARTS".to_string(),
2488 f.args,
2489 ))))
2490 }
2491
2492 "TIMESTAMPLTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2494 "TIMESTAMP_LTZ_FROM_PARTS".to_string(),
2495 f.args,
2496 )))),
2497
2498 "TIMESTAMPTZFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2500 "TIMESTAMP_TZ_FROM_PARTS".to_string(),
2501 f.args,
2502 )))),
2503
2504 "DATEADD" if f.args.len() >= 1 => {
2506 let mut args = f.args;
2507 args[0] = self.transform_date_part_arg(args[0].clone());
2508 Ok(Expression::Function(Box::new(Function::new(
2509 "DATEADD".to_string(),
2510 args,
2511 ))))
2512 }
2513
2514 "DATEDIFF" if f.args.len() >= 1 => {
2517 let mut args = f.args;
2518 args[0] = self.transform_date_part_arg(args[0].clone());
2519 for i in 1..args.len() {
2522 if let Expression::Function(ref func) = args[i] {
2523 if func.name == "_POLYGLOT_TO_DATE" {
2524 let inner_args = func.args.clone();
2525 args[i] = Expression::Function(Box::new(Function::new(
2526 "TO_DATE".to_string(),
2527 inner_args,
2528 )));
2529 }
2530 }
2531 }
2532 Ok(Expression::Function(Box::new(Function::new(
2533 "DATEDIFF".to_string(),
2534 args,
2535 ))))
2536 }
2537
2538 "TIMEDIFF" => Ok(Expression::Function(Box::new(Function::new(
2540 "DATEDIFF".to_string(),
2541 f.args,
2542 )))),
2543
2544 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
2546 "DATEDIFF".to_string(),
2547 f.args,
2548 )))),
2549
2550 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(Function::new(
2552 "DATEADD".to_string(),
2553 f.args,
2554 )))),
2555
2556 "TIMEADD" => Ok(Expression::Function(Box::new(f))),
2558
2559 "DATEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2561 "DATE_FROM_PARTS".to_string(),
2562 f.args,
2563 )))),
2564
2565 "TIMEFROMPARTS" => Ok(Expression::Function(Box::new(Function::new(
2567 "TIME_FROM_PARTS".to_string(),
2568 f.args,
2569 )))),
2570
2571 "DAYOFWEEK" => Ok(Expression::Function(Box::new(f))),
2573
2574 "DAYOFMONTH" => Ok(Expression::Function(Box::new(f))),
2576
2577 "DAYOFYEAR" => Ok(Expression::Function(Box::new(f))),
2579
2580 "MONTHNAME" if f.args.len() == 1 => {
2583 let arg = f.args.into_iter().next().unwrap();
2584 Ok(Expression::Monthname(Box::new(
2585 crate::expressions::Monthname {
2586 this: Box::new(arg),
2587 abbreviated: Some(Box::new(Expression::Literal(Box::new(
2588 Literal::String("true".to_string()),
2589 )))),
2590 },
2591 )))
2592 }
2593
2594 "DAYNAME" if f.args.len() == 1 => {
2597 let arg = f.args.into_iter().next().unwrap();
2598 Ok(Expression::Dayname(Box::new(crate::expressions::Dayname {
2599 this: Box::new(arg),
2600 abbreviated: Some(Box::new(Expression::Literal(Box::new(Literal::String(
2601 "true".to_string(),
2602 ))))),
2603 })))
2604 }
2605
2606 "BOOLAND_AGG" | "BOOL_AND" | "LOGICAL_AND" if !f.args.is_empty() => {
2608 let arg = f.args.into_iter().next().unwrap();
2609 Ok(Expression::LogicalAnd(Box::new(AggFunc {
2610 this: arg,
2611 distinct: false,
2612 filter: None,
2613 order_by: Vec::new(),
2614 name: Some("BOOLAND_AGG".to_string()),
2615 ignore_nulls: None,
2616 having_max: None,
2617 limit: None,
2618 inferred_type: None,
2619 })))
2620 }
2621
2622 "BOOLOR_AGG" | "BOOL_OR" | "LOGICAL_OR" if !f.args.is_empty() => {
2624 let arg = f.args.into_iter().next().unwrap();
2625 Ok(Expression::LogicalOr(Box::new(AggFunc {
2626 this: arg,
2627 distinct: false,
2628 filter: None,
2629 order_by: Vec::new(),
2630 name: Some("BOOLOR_AGG".to_string()),
2631 ignore_nulls: None,
2632 having_max: None,
2633 limit: None,
2634 inferred_type: None,
2635 })))
2636 }
2637
2638 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
2640 let arg = f.args.into_iter().next().unwrap();
2641 Ok(Expression::Skewness(Box::new(AggFunc {
2642 this: arg,
2643 distinct: false,
2644 filter: None,
2645 order_by: Vec::new(),
2646 name: Some("SKEW".to_string()),
2647 ignore_nulls: None,
2648 having_max: None,
2649 limit: None,
2650 inferred_type: None,
2651 })))
2652 }
2653
2654 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2656 "VARIANCE".to_string(),
2657 f.args,
2658 )))),
2659
2660 "VAR_POP" => Ok(Expression::Function(Box::new(Function::new(
2662 "VARIANCE_POP".to_string(),
2663 f.args,
2664 )))),
2665
2666 "DATE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2668 "TO_DATE".to_string(),
2669 f.args,
2670 )))),
2671 "DATE" if f.args.len() >= 2 => {
2675 let mut args = f.args;
2676 args[1] = Self::normalize_format_arg(args[1].clone());
2677 Ok(Expression::Function(Box::new(Function::new(
2678 "TO_DATE".to_string(),
2679 args,
2680 ))))
2681 }
2682 "_POLYGLOT_DATE" if f.args.len() >= 2 => {
2685 let mut args = f.args;
2686 args[1] = Self::normalize_format_arg(args[1].clone());
2687 Ok(Expression::Function(Box::new(Function::new(
2688 "DATE".to_string(),
2689 args,
2690 ))))
2691 }
2692
2693 "DESCRIBE" => Ok(Expression::Function(Box::new(f))),
2695
2696 "MD5_HEX" => Ok(Expression::Function(Box::new(Function::new(
2698 "MD5".to_string(),
2699 f.args,
2700 )))),
2701
2702 "SHA1_HEX" => Ok(Expression::Function(Box::new(Function::new(
2704 "SHA1".to_string(),
2705 f.args,
2706 )))),
2707
2708 "SHA2_HEX" => Ok(Expression::Function(Box::new(Function::new(
2710 "SHA2".to_string(),
2711 f.args,
2712 )))),
2713
2714 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
2716 "EDITDISTANCE".to_string(),
2717 f.args,
2718 )))),
2719
2720 "BIT_NOT" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2722 "BITNOT".to_string(),
2723 f.args,
2724 )))),
2725
2726 "BIT_AND" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2728 "BITAND".to_string(),
2729 f.args,
2730 )))),
2731
2732 "BIT_OR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2734 "BITOR".to_string(),
2735 f.args,
2736 )))),
2737
2738 "BIT_XOR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2740 "BITXOR".to_string(),
2741 f.args,
2742 )))),
2743
2744 "BIT_SHIFTLEFT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2746 Function::new("BITSHIFTLEFT".to_string(), f.args),
2747 ))),
2748
2749 "BIT_SHIFTRIGHT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
2751 Function::new("BITSHIFTRIGHT".to_string(), f.args),
2752 ))),
2753
2754 "SYSTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2756 name: "CURRENT_TIMESTAMP".to_string(),
2757 args: f.args,
2758 distinct: false,
2759 trailing_comments: Vec::new(),
2760 use_bracket_syntax: false,
2761 no_parens: f.no_parens,
2762 quoted: false,
2763 span: None,
2764 inferred_type: None,
2765 }))),
2766
2767 "LOCALTIMESTAMP" => Ok(Expression::Function(Box::new(Function {
2769 name: "CURRENT_TIMESTAMP".to_string(),
2770 args: f.args,
2771 distinct: false,
2772 trailing_comments: Vec::new(),
2773 use_bracket_syntax: false,
2774 no_parens: f.no_parens,
2775 quoted: false,
2776 span: None,
2777 inferred_type: None,
2778 }))),
2779
2780 "SPACE" if f.args.len() == 1 => {
2782 let arg = f.args.into_iter().next().unwrap();
2783 Ok(Expression::Function(Box::new(Function::new(
2784 "REPEAT".to_string(),
2785 vec![
2786 Expression::Literal(Box::new(Literal::String(" ".to_string()))),
2787 arg,
2788 ],
2789 ))))
2790 }
2791
2792 "CEILING" => Ok(Expression::Function(Box::new(Function::new(
2794 "CEIL".to_string(),
2795 f.args,
2796 )))),
2797
2798 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
2800 "LN".to_string(),
2801 f.args,
2802 )))),
2803
2804 "REGEXP_SUBSTR_ALL" => Ok(Expression::Function(Box::new(f))),
2806
2807 "GET_PATH" if f.args.len() >= 2 => {
2811 let mut args = f.args;
2812 if let Expression::Literal(lit) = &args[1] {
2814 if let crate::expressions::Literal::String(path) = lit.as_ref() {
2815 let transformed = Self::transform_json_path(path);
2816 args[1] = Expression::Literal(Box::new(
2817 crate::expressions::Literal::String(transformed),
2818 ));
2819 }
2820 }
2821 Ok(Expression::Function(Box::new(Function::new(
2822 "GET_PATH".to_string(),
2823 args,
2824 ))))
2825 }
2826 "GET_PATH" => Ok(Expression::Function(Box::new(f))),
2827
2828 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
2830
2831 "DATE_TRUNC" if f.args.len() >= 1 => {
2834 let mut args = f.args;
2835 let unit_name = match &args[0] {
2837 Expression::Identifier(id) => Some(id.name.as_str()),
2838 Expression::Var(v) => Some(v.this.as_str()),
2839 Expression::Column(col) if col.table.is_none() => Some(col.name.name.as_str()),
2840 _ => None,
2841 };
2842 if let Some(name) = unit_name {
2843 let canonical = Self::map_date_part(name).unwrap_or(name);
2844 args[0] = Expression::Literal(Box::new(crate::expressions::Literal::String(
2845 canonical.to_uppercase(),
2846 )));
2847 }
2848 Ok(Expression::Function(Box::new(Function::new(
2849 "DATE_TRUNC".to_string(),
2850 args,
2851 ))))
2852 }
2853
2854 "DATE_PART" if f.args.len() >= 1 => {
2860 let mut args = f.args;
2861 let from_typed_literal = args.len() >= 2
2862 && matches!(
2863 &args[1],
2864 Expression::Literal(lit) if matches!(lit.as_ref(),
2865 crate::expressions::Literal::Timestamp(_)
2866 | crate::expressions::Literal::Date(_)
2867 | crate::expressions::Literal::Time(_)
2868 | crate::expressions::Literal::Datetime(_)
2869 )
2870 );
2871 if from_typed_literal {
2872 args[0] = self.transform_date_part_arg(args[0].clone());
2873 } else {
2874 args[0] = self.transform_date_part_arg_identifiers_only(args[0].clone());
2877 }
2878 Ok(Expression::Function(Box::new(Function::new(
2879 "DATE_PART".to_string(),
2880 args,
2881 ))))
2882 }
2883
2884 "OBJECT_CONSTRUCT" => Ok(Expression::Function(Box::new(f))),
2886
2887 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(f))),
2889
2890 "DESC" => Ok(Expression::Function(Box::new(Function::new(
2892 "DESCRIBE".to_string(),
2893 f.args,
2894 )))),
2895
2896 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
2898 "REGEXP_LIKE".to_string(),
2899 f.args,
2900 )))),
2901
2902 "TRANSFORM" => {
2907 let transformed_args: Vec<Expression> = f
2908 .args
2909 .into_iter()
2910 .map(|arg| {
2911 if let Expression::Lambda(lambda) = arg {
2912 self.transform_typed_lambda(*lambda)
2913 } else {
2914 arg
2915 }
2916 })
2917 .collect();
2918 Ok(Expression::Function(Box::new(Function::new(
2919 "TRANSFORM".to_string(),
2920 transformed_args,
2921 ))))
2922 }
2923
2924 "SEARCH" if f.args.len() >= 2 => {
2926 let mut args = f.args.into_iter();
2927 let this = Box::new(args.next().unwrap());
2928 let expression = Box::new(args.next().unwrap());
2929
2930 let mut analyzer: Option<Box<Expression>> = None;
2931 let mut search_mode: Option<Box<Expression>> = None;
2932
2933 for arg in args {
2935 if let Expression::NamedArgument(na) = &arg {
2936 let name_upper = na.name.name.to_uppercase();
2937 match name_upper.as_str() {
2938 "ANALYZER" => analyzer = Some(Box::new(arg)),
2939 "SEARCH_MODE" => search_mode = Some(Box::new(arg)),
2940 _ => {}
2941 }
2942 }
2943 }
2944
2945 Ok(Expression::Search(Box::new(crate::expressions::Search {
2946 this,
2947 expression,
2948 json_scope: None,
2949 analyzer,
2950 analyzer_options: None,
2951 search_mode,
2952 })))
2953 }
2954
2955 "CONVERT" if f.args.len() == 2 => {
2958 let value = f.args.get(0).cloned().unwrap();
2959 let type_arg = f.args.get(1).cloned().unwrap();
2960
2961 if let Expression::Column(col) = &type_arg {
2963 let type_name = col.name.name.to_uppercase();
2964 let data_type = match type_name.as_str() {
2965 "SQL_DOUBLE" => Some(DataType::Double {
2966 precision: None,
2967 scale: None,
2968 }),
2969 "SQL_VARCHAR" => Some(DataType::VarChar {
2970 length: None,
2971 parenthesized_length: false,
2972 }),
2973 "SQL_INTEGER" | "SQL_INT" => Some(DataType::Int {
2974 length: None,
2975 integer_spelling: false,
2976 }),
2977 "SQL_BIGINT" => Some(DataType::BigInt { length: None }),
2978 "SQL_SMALLINT" => Some(DataType::SmallInt { length: None }),
2979 "SQL_FLOAT" => Some(DataType::Float {
2980 precision: None,
2981 scale: None,
2982 real_spelling: false,
2983 }),
2984 "SQL_REAL" => Some(DataType::Float {
2985 precision: None,
2986 scale: None,
2987 real_spelling: true,
2988 }),
2989 "SQL_DECIMAL" => Some(DataType::Decimal {
2990 precision: None,
2991 scale: None,
2992 }),
2993 "SQL_DATE" => Some(DataType::Date),
2994 "SQL_TIME" => Some(DataType::Time {
2995 precision: None,
2996 timezone: false,
2997 }),
2998 "SQL_TIMESTAMP" => Some(DataType::Timestamp {
2999 precision: None,
3000 timezone: false,
3001 }),
3002 _ => None,
3003 };
3004
3005 if let Some(dt) = data_type {
3006 return Ok(Expression::Cast(Box::new(Cast {
3007 this: value,
3008 to: dt,
3009 double_colon_syntax: false,
3010 trailing_comments: vec![],
3011 format: None,
3012 default: None,
3013 inferred_type: None,
3014 })));
3015 }
3016 }
3017 Ok(Expression::Function(Box::new(f)))
3019 }
3020
3021 "TO_TIMESTAMP_TZ" => {
3024 if f.args.len() == 1 {
3025 if let Expression::Literal(lit) = &f.args[0] {
3026 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3027 return Ok(Expression::Cast(Box::new(Cast {
3028 this: f.args.into_iter().next().unwrap(),
3029 to: DataType::Custom {
3030 name: "TIMESTAMPTZ".to_string(),
3031 },
3032 double_colon_syntax: false,
3033 trailing_comments: vec![],
3034 format: None,
3035 default: None,
3036 inferred_type: None,
3037 })));
3038 }
3039 }
3040 }
3041 Ok(Expression::Function(Box::new(f)))
3042 }
3043
3044 "TO_TIMESTAMP_NTZ" => {
3046 if f.args.len() == 1 {
3047 if let Expression::Literal(lit) = &f.args[0] {
3048 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3049 return Ok(Expression::Cast(Box::new(Cast {
3050 this: f.args.into_iter().next().unwrap(),
3051 to: DataType::Custom {
3052 name: "TIMESTAMPNTZ".to_string(),
3053 },
3054 double_colon_syntax: false,
3055 trailing_comments: vec![],
3056 format: None,
3057 default: None,
3058 inferred_type: None,
3059 })));
3060 }
3061 }
3062 }
3063 Ok(Expression::Function(Box::new(f)))
3064 }
3065
3066 "TO_TIMESTAMP_LTZ" => {
3068 if f.args.len() == 1 {
3069 if let Expression::Literal(lit) = &f.args[0] {
3070 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3071 return Ok(Expression::Cast(Box::new(Cast {
3072 this: f.args.into_iter().next().unwrap(),
3073 to: DataType::Custom {
3074 name: "TIMESTAMPLTZ".to_string(),
3075 },
3076 double_colon_syntax: false,
3077 trailing_comments: vec![],
3078 format: None,
3079 default: None,
3080 inferred_type: None,
3081 })));
3082 }
3083 }
3084 }
3085 Ok(Expression::Function(Box::new(f)))
3086 }
3087
3088 "UNIFORM" => Ok(Expression::Function(Box::new(f))),
3090
3091 "REPLACE" if f.args.len() == 2 => {
3093 let mut args = f.args;
3094 args.push(Expression::Literal(Box::new(
3095 crate::expressions::Literal::String(String::new()),
3096 )));
3097 Ok(Expression::Function(Box::new(Function::new(
3098 "REPLACE".to_string(),
3099 args,
3100 ))))
3101 }
3102
3103 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
3105 "ANY_VALUE".to_string(),
3106 f.args,
3107 )))),
3108
3109 "SAFE_DIVIDE" if f.args.len() == 2 => {
3111 let mut args = f.args;
3112 let x = args.remove(0);
3113 let y = args.remove(0);
3114 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3115 condition: Expression::Neq(Box::new(BinaryOp {
3116 left: y.clone(),
3117 right: Expression::number(0),
3118 left_comments: Vec::new(),
3119 operator_comments: Vec::new(),
3120 trailing_comments: Vec::new(),
3121 inferred_type: None,
3122 })),
3123 true_value: Expression::Div(Box::new(BinaryOp {
3124 left: x,
3125 right: y,
3126 left_comments: Vec::new(),
3127 operator_comments: Vec::new(),
3128 trailing_comments: Vec::new(),
3129 inferred_type: None,
3130 })),
3131 false_value: Some(Expression::Null(crate::expressions::Null)),
3132 original_name: Some("IFF".to_string()),
3133 inferred_type: None,
3134 })))
3135 }
3136
3137 "TIMESTAMP" if f.args.len() == 1 => {
3139 let arg = f.args.into_iter().next().unwrap();
3140 Ok(Expression::Cast(Box::new(Cast {
3141 this: arg,
3142 to: DataType::Custom {
3143 name: "TIMESTAMPTZ".to_string(),
3144 },
3145 trailing_comments: Vec::new(),
3146 double_colon_syntax: false,
3147 format: None,
3148 default: None,
3149 inferred_type: None,
3150 })))
3151 }
3152
3153 "TIMESTAMP" if f.args.len() == 2 => {
3155 let mut args = f.args;
3156 let value = args.remove(0);
3157 let tz = args.remove(0);
3158 Ok(Expression::Function(Box::new(Function::new(
3159 "CONVERT_TIMEZONE".to_string(),
3160 vec![
3161 tz,
3162 Expression::Cast(Box::new(Cast {
3163 this: value,
3164 to: DataType::Timestamp {
3165 precision: None,
3166 timezone: false,
3167 },
3168 trailing_comments: Vec::new(),
3169 double_colon_syntax: false,
3170 format: None,
3171 default: None,
3172 inferred_type: None,
3173 })),
3174 ],
3175 ))))
3176 }
3177
3178 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3180 "TIME_FROM_PARTS".to_string(),
3181 f.args,
3182 )))),
3183
3184 "DIV0" if f.args.len() == 2 => {
3186 let mut args = f.args;
3187 let x = args.remove(0);
3188 let y = args.remove(0);
3189 let x_expr = Self::maybe_paren(x.clone());
3191 let y_expr = Self::maybe_paren(y.clone());
3192 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3193 condition: Expression::And(Box::new(BinaryOp::new(
3194 Expression::Eq(Box::new(BinaryOp::new(
3195 y_expr.clone(),
3196 Expression::number(0),
3197 ))),
3198 Expression::Not(Box::new(crate::expressions::UnaryOp {
3199 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3200 this: x_expr.clone(),
3201 not: false,
3202 postfix_form: false,
3203 })),
3204 inferred_type: None,
3205 })),
3206 ))),
3207 true_value: Expression::number(0),
3208 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3209 original_name: Some("IFF".to_string()),
3210 inferred_type: None,
3211 })))
3212 }
3213
3214 "DIV0NULL" if f.args.len() == 2 => {
3216 let mut args = f.args;
3217 let x = args.remove(0);
3218 let y = args.remove(0);
3219 let x_expr = Self::maybe_paren(x.clone());
3220 let y_expr = Self::maybe_paren(y.clone());
3221 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3222 condition: Expression::Or(Box::new(BinaryOp::new(
3223 Expression::Eq(Box::new(BinaryOp::new(
3224 y_expr.clone(),
3225 Expression::number(0),
3226 ))),
3227 Expression::IsNull(Box::new(crate::expressions::IsNull {
3228 this: y_expr.clone(),
3229 not: false,
3230 postfix_form: false,
3231 })),
3232 ))),
3233 true_value: Expression::number(0),
3234 false_value: Some(Expression::Div(Box::new(BinaryOp::new(x_expr, y_expr)))),
3235 original_name: Some("IFF".to_string()),
3236 inferred_type: None,
3237 })))
3238 }
3239
3240 "ZEROIFNULL" if f.args.len() == 1 => {
3242 let x = f.args.into_iter().next().unwrap();
3243 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3244 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
3245 this: x.clone(),
3246 not: false,
3247 postfix_form: false,
3248 })),
3249 true_value: Expression::number(0),
3250 false_value: Some(x),
3251 original_name: Some("IFF".to_string()),
3252 inferred_type: None,
3253 })))
3254 }
3255
3256 "NULLIFZERO" if f.args.len() == 1 => {
3258 let x = f.args.into_iter().next().unwrap();
3259 Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
3260 condition: Expression::Eq(Box::new(BinaryOp::new(
3261 x.clone(),
3262 Expression::number(0),
3263 ))),
3264 true_value: Expression::Null(crate::expressions::Null),
3265 false_value: Some(x),
3266 original_name: Some("IFF".to_string()),
3267 inferred_type: None,
3268 })))
3269 }
3270
3271 "TRY_TO_TIME" => {
3273 if f.args.len() == 1 {
3274 if let Expression::Literal(lit) = &f.args[0] {
3275 if let crate::expressions::Literal::String(_) = lit.as_ref() {
3276 return Ok(Expression::TryCast(Box::new(Cast {
3277 this: f.args.into_iter().next().unwrap(),
3278 to: crate::expressions::DataType::Time {
3279 precision: None,
3280 timezone: false,
3281 },
3282 double_colon_syntax: false,
3283 trailing_comments: Vec::new(),
3284 format: None,
3285 default: None,
3286 inferred_type: None,
3287 })));
3288 }
3289 }
3290 }
3291 let mut args = f.args;
3293 if args.len() >= 2 {
3294 args[1] = Self::normalize_format_arg(args[1].clone());
3295 }
3296 Ok(Expression::Function(Box::new(Function::new(
3297 "TRY_TO_TIME".to_string(),
3298 args,
3299 ))))
3300 }
3301
3302 "TRY_TO_TIMESTAMP" => {
3305 if f.args.len() == 1 {
3306 if let Expression::Literal(lit) = &f.args[0] {
3307 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3308 if !Self::looks_like_epoch(s) {
3309 return Ok(Expression::TryCast(Box::new(Cast {
3310 this: f.args.into_iter().next().unwrap(),
3311 to: DataType::Timestamp {
3312 precision: None,
3313 timezone: false,
3314 },
3315 double_colon_syntax: false,
3316 trailing_comments: Vec::new(),
3317 format: None,
3318 default: None,
3319 inferred_type: None,
3320 })));
3321 }
3322 }
3323 }
3324 }
3325 let mut args = f.args;
3327 if args.len() >= 2 {
3328 args[1] = Self::normalize_format_arg(args[1].clone());
3329 }
3330 Ok(Expression::Function(Box::new(Function::new(
3331 "TRY_TO_TIMESTAMP".to_string(),
3332 args,
3333 ))))
3334 }
3335
3336 "TRY_TO_DATE" => {
3338 if f.args.len() == 1 {
3339 if let Expression::Literal(lit) = &f.args[0] {
3340 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3341 if s.contains('-') && s.len() >= 8 && s.len() <= 12 {
3343 return Ok(Expression::TryCast(Box::new(Cast {
3344 this: f.args.into_iter().next().unwrap(),
3345 to: crate::expressions::DataType::Date,
3346 double_colon_syntax: false,
3347 trailing_comments: Vec::new(),
3348 format: None,
3349 default: None,
3350 inferred_type: None,
3351 })));
3352 }
3353 }
3354 }
3355 }
3356 let mut args = f.args;
3358 if args.len() >= 2 {
3359 args[1] = Self::normalize_format_arg(args[1].clone());
3360 }
3361 Ok(Expression::Function(Box::new(Function::new(
3362 "TRY_TO_DATE".to_string(),
3363 args,
3364 ))))
3365 }
3366
3367 "TRY_TO_DOUBLE" => Ok(Expression::Function(Box::new(f))),
3369
3370 "REGEXP_REPLACE" if f.args.len() == 2 => {
3372 let mut args = f.args;
3373 args.push(Expression::Literal(Box::new(
3374 crate::expressions::Literal::String(String::new()),
3375 )));
3376 Ok(Expression::Function(Box::new(Function::new(
3377 "REGEXP_REPLACE".to_string(),
3378 args,
3379 ))))
3380 }
3381
3382 "LAST_DAY" if f.args.len() == 2 => {
3384 let mut args = f.args;
3385 let date = args.remove(0);
3386 let unit = args.remove(0);
3387 let unit_str = match &unit {
3388 Expression::Column(c) => c.name.name.to_uppercase(),
3389 Expression::Identifier(i) => i.name.to_uppercase(),
3390 _ => String::new(),
3391 };
3392 if unit_str == "MONTH" {
3393 Ok(Expression::Function(Box::new(Function::new(
3394 "LAST_DAY".to_string(),
3395 vec![date],
3396 ))))
3397 } else {
3398 Ok(Expression::Function(Box::new(Function::new(
3399 "LAST_DAY".to_string(),
3400 vec![date, unit],
3401 ))))
3402 }
3403 }
3404
3405 "EXTRACT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
3407 "DATE_PART".to_string(),
3408 f.args,
3409 )))),
3410
3411 "ENDS_WITH" | "ENDSWITH" if f.args.len() == 2 => {
3413 let mut args = f.args;
3414 let this = args.remove(0);
3415 let expr = args.remove(0);
3416 Ok(Expression::EndsWith(Box::new(
3417 crate::expressions::BinaryFunc {
3418 original_name: None,
3419 this,
3420 expression: expr,
3421 inferred_type: None,
3422 },
3423 )))
3424 }
3425
3426 _ => Ok(Expression::Function(Box::new(f))),
3428 }
3429 }
3430
3431 fn looks_like_datetime(s: &str) -> bool {
3433 s.contains('-') || s.contains(':') || s.contains(' ') || s.contains('/')
3436 }
3437
3438 fn looks_like_epoch(s: &str) -> bool {
3440 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit() || c == '.')
3441 }
3442
3443 fn maybe_paren(expr: Expression) -> Expression {
3445 match &expr {
3446 Expression::Sub(_) | Expression::Add(_) | Expression::Mul(_) | Expression::Div(_) => {
3447 Expression::Paren(Box::new(crate::expressions::Paren {
3448 this: expr,
3449 trailing_comments: Vec::new(),
3450 }))
3451 }
3452 _ => expr,
3453 }
3454 }
3455
3456 fn normalize_snowflake_format(format: &str) -> String {
3460 let mut result = String::new();
3461 let chars: Vec<char> = format.chars().collect();
3462 let mut i = 0;
3463 while i < chars.len() {
3464 if chars[i] == '"' {
3466 i += 1;
3467 while i < chars.len() && chars[i] != '"' {
3468 result.push(chars[i]);
3469 i += 1;
3470 }
3471 if i < chars.len() {
3472 i += 1; }
3474 continue;
3475 }
3476
3477 let remaining = &format[i..];
3478 let remaining_upper = remaining.to_uppercase();
3479
3480 if remaining_upper.starts_with("YYYY") {
3482 result.push_str("yyyy");
3483 i += 4;
3484 } else if remaining_upper.starts_with("YY") {
3485 result.push_str("yy");
3486 i += 2;
3487 } else if remaining_upper.starts_with("MMMM") {
3488 result.push_str("mmmm");
3489 i += 4;
3490 } else if remaining_upper.starts_with("MON") {
3491 result.push_str("mon");
3492 i += 3;
3493 } else if remaining_upper.starts_with("MM") {
3494 result.push_str("mm");
3495 i += 2;
3496 } else if remaining_upper.starts_with("DD") {
3497 result.push_str("DD");
3498 i += 2;
3499 } else if remaining_upper.starts_with("DY") {
3500 result.push_str("dy");
3501 i += 2;
3502 } else if remaining_upper.starts_with("HH24") {
3503 result.push_str("hh24");
3504 i += 4;
3505 } else if remaining_upper.starts_with("HH12") {
3506 result.push_str("hh12");
3507 i += 4;
3508 } else if remaining_upper.starts_with("HH") {
3509 result.push_str("hh");
3510 i += 2;
3511 } else if remaining_upper.starts_with("MISS") {
3512 result.push_str("miss");
3514 i += 4;
3515 } else if remaining_upper.starts_with("MI") {
3516 result.push_str("mi");
3517 i += 2;
3518 } else if remaining_upper.starts_with("SS") {
3519 result.push_str("ss");
3520 i += 2;
3521 } else if remaining_upper.starts_with("FF") {
3522 let ff_len = 2;
3524 let digit = if i + ff_len < chars.len() && chars[i + ff_len].is_ascii_digit() {
3525 let d = chars[i + ff_len];
3526 Some(d)
3527 } else {
3528 None
3529 };
3530 if let Some(d) = digit {
3531 result.push_str("ff");
3532 result.push(d);
3533 i += 3;
3534 } else {
3535 result.push_str("ff9");
3537 i += 2;
3538 }
3539 } else if remaining_upper.starts_with("AM") || remaining_upper.starts_with("PM") {
3540 result.push_str("pm");
3541 i += 2;
3542 } else if remaining_upper.starts_with("TZH") {
3543 result.push_str("tzh");
3544 i += 3;
3545 } else if remaining_upper.starts_with("TZM") {
3546 result.push_str("tzm");
3547 i += 3;
3548 } else {
3549 result.push(chars[i]);
3551 i += 1;
3552 }
3553 }
3554 result
3555 }
3556
3557 fn normalize_format_arg(expr: Expression) -> Expression {
3559 if let Expression::Literal(lit) = &expr {
3560 if let crate::expressions::Literal::String(s) = lit.as_ref() {
3561 let normalized = Self::normalize_snowflake_format(s);
3562 Expression::Literal(Box::new(crate::expressions::Literal::String(normalized)))
3563 } else {
3564 expr.clone()
3565 }
3566 } else {
3567 expr
3568 }
3569 }
3570
3571 fn transform_typed_lambda(&self, lambda: crate::expressions::LambdaExpr) -> Expression {
3574 use crate::expressions::{DataType, LambdaExpr};
3575 use std::collections::HashMap;
3576
3577 let mut param_types: HashMap<String, DataType> = HashMap::new();
3579 for (i, param) in lambda.parameters.iter().enumerate() {
3580 if let Some(Some(dt)) = lambda.parameter_types.get(i) {
3581 param_types.insert(param.name.to_uppercase(), dt.clone());
3582 }
3583 }
3584
3585 if param_types.is_empty() {
3587 return Expression::Lambda(Box::new(lambda));
3588 }
3589
3590 let transformed_body = self.replace_lambda_params_with_cast(lambda.body, ¶m_types);
3592
3593 Expression::Lambda(Box::new(LambdaExpr {
3595 parameters: lambda.parameters,
3596 body: transformed_body,
3597 colon: lambda.colon,
3598 parameter_types: Vec::new(), }))
3600 }
3601
3602 fn replace_lambda_params_with_cast(
3604 &self,
3605 expr: Expression,
3606 param_types: &std::collections::HashMap<String, crate::expressions::DataType>,
3607 ) -> Expression {
3608 use crate::expressions::{BinaryOp, Cast, Paren};
3609
3610 match expr {
3611 Expression::Column(col) if col.table.is_none() => {
3613 let name_upper = col.name.name.to_uppercase();
3614 if let Some(dt) = param_types.get(&name_upper) {
3615 Expression::Cast(Box::new(Cast {
3617 this: Expression::Column(col),
3618 to: dt.clone(),
3619 double_colon_syntax: false,
3620 trailing_comments: Vec::new(),
3621 format: None,
3622 default: None,
3623 inferred_type: None,
3624 }))
3625 } else {
3626 Expression::Column(col)
3627 }
3628 }
3629
3630 Expression::Identifier(id) => {
3632 let name_upper = id.name.to_uppercase();
3633 if let Some(dt) = param_types.get(&name_upper) {
3634 Expression::Cast(Box::new(Cast {
3636 this: Expression::Identifier(id),
3637 to: dt.clone(),
3638 double_colon_syntax: false,
3639 trailing_comments: Vec::new(),
3640 format: None,
3641 default: None,
3642 inferred_type: None,
3643 }))
3644 } else {
3645 Expression::Identifier(id)
3646 }
3647 }
3648
3649 Expression::Add(op) => Expression::Add(Box::new(BinaryOp::new(
3651 self.replace_lambda_params_with_cast(op.left, param_types),
3652 self.replace_lambda_params_with_cast(op.right, param_types),
3653 ))),
3654 Expression::Sub(op) => Expression::Sub(Box::new(BinaryOp::new(
3655 self.replace_lambda_params_with_cast(op.left, param_types),
3656 self.replace_lambda_params_with_cast(op.right, param_types),
3657 ))),
3658 Expression::Mul(op) => Expression::Mul(Box::new(BinaryOp::new(
3659 self.replace_lambda_params_with_cast(op.left, param_types),
3660 self.replace_lambda_params_with_cast(op.right, param_types),
3661 ))),
3662 Expression::Div(op) => Expression::Div(Box::new(BinaryOp::new(
3663 self.replace_lambda_params_with_cast(op.left, param_types),
3664 self.replace_lambda_params_with_cast(op.right, param_types),
3665 ))),
3666 Expression::Mod(op) => Expression::Mod(Box::new(BinaryOp::new(
3667 self.replace_lambda_params_with_cast(op.left, param_types),
3668 self.replace_lambda_params_with_cast(op.right, param_types),
3669 ))),
3670
3671 Expression::Paren(p) => Expression::Paren(Box::new(Paren {
3673 this: self.replace_lambda_params_with_cast(p.this, param_types),
3674 trailing_comments: p.trailing_comments,
3675 })),
3676
3677 Expression::Function(mut f) => {
3679 f.args = f
3680 .args
3681 .into_iter()
3682 .map(|arg| self.replace_lambda_params_with_cast(arg, param_types))
3683 .collect();
3684 Expression::Function(f)
3685 }
3686
3687 Expression::Eq(op) => Expression::Eq(Box::new(BinaryOp::new(
3689 self.replace_lambda_params_with_cast(op.left, param_types),
3690 self.replace_lambda_params_with_cast(op.right, param_types),
3691 ))),
3692 Expression::Neq(op) => Expression::Neq(Box::new(BinaryOp::new(
3693 self.replace_lambda_params_with_cast(op.left, param_types),
3694 self.replace_lambda_params_with_cast(op.right, param_types),
3695 ))),
3696 Expression::Lt(op) => Expression::Lt(Box::new(BinaryOp::new(
3697 self.replace_lambda_params_with_cast(op.left, param_types),
3698 self.replace_lambda_params_with_cast(op.right, param_types),
3699 ))),
3700 Expression::Lte(op) => Expression::Lte(Box::new(BinaryOp::new(
3701 self.replace_lambda_params_with_cast(op.left, param_types),
3702 self.replace_lambda_params_with_cast(op.right, param_types),
3703 ))),
3704 Expression::Gt(op) => Expression::Gt(Box::new(BinaryOp::new(
3705 self.replace_lambda_params_with_cast(op.left, param_types),
3706 self.replace_lambda_params_with_cast(op.right, param_types),
3707 ))),
3708 Expression::Gte(op) => Expression::Gte(Box::new(BinaryOp::new(
3709 self.replace_lambda_params_with_cast(op.left, param_types),
3710 self.replace_lambda_params_with_cast(op.right, param_types),
3711 ))),
3712
3713 Expression::And(op) => Expression::And(Box::new(BinaryOp::new(
3715 self.replace_lambda_params_with_cast(op.left, param_types),
3716 self.replace_lambda_params_with_cast(op.right, param_types),
3717 ))),
3718 Expression::Or(op) => Expression::Or(Box::new(BinaryOp::new(
3719 self.replace_lambda_params_with_cast(op.left, param_types),
3720 self.replace_lambda_params_with_cast(op.right, param_types),
3721 ))),
3722
3723 other => other,
3725 }
3726 }
3727
3728 fn transform_aggregate_function(
3729 &self,
3730 f: Box<crate::expressions::AggregateFunction>,
3731 ) -> Result<Expression> {
3732 let name_upper = f.name.to_uppercase();
3733 match name_upper.as_str() {
3734 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3736 Function::new("LISTAGG".to_string(), f.args),
3737 ))),
3738
3739 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3741 Function::new("LISTAGG".to_string(), f.args),
3742 ))),
3743
3744 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
3746 Function::new("APPROX_COUNT_DISTINCT".to_string(), f.args),
3747 ))),
3748
3749 "BIT_AND" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3751 "BITAND_AGG".to_string(),
3752 f.args,
3753 )))),
3754
3755 "BIT_OR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3757 "BITOR_AGG".to_string(),
3758 f.args,
3759 )))),
3760
3761 "BIT_XOR" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
3763 "BITXOR_AGG".to_string(),
3764 f.args,
3765 )))),
3766
3767 "BOOL_AND" | "LOGICAL_AND" | "BOOLAND_AGG" if !f.args.is_empty() => {
3769 let arg = f.args.into_iter().next().unwrap();
3770 Ok(Expression::LogicalAnd(Box::new(AggFunc {
3771 this: arg,
3772 distinct: f.distinct,
3773 filter: f.filter,
3774 order_by: Vec::new(),
3775 name: Some("BOOLAND_AGG".to_string()),
3776 ignore_nulls: None,
3777 having_max: None,
3778 limit: None,
3779 inferred_type: None,
3780 })))
3781 }
3782
3783 "BOOL_OR" | "LOGICAL_OR" | "BOOLOR_AGG" if !f.args.is_empty() => {
3785 let arg = f.args.into_iter().next().unwrap();
3786 Ok(Expression::LogicalOr(Box::new(AggFunc {
3787 this: arg,
3788 distinct: f.distinct,
3789 filter: f.filter,
3790 order_by: Vec::new(),
3791 name: Some("BOOLOR_AGG".to_string()),
3792 ignore_nulls: None,
3793 having_max: None,
3794 limit: None,
3795 inferred_type: None,
3796 })))
3797 }
3798
3799 "APPROX_TOP_K" if f.args.len() == 1 => {
3801 let mut args = f.args;
3802 args.push(Expression::number(1));
3803 Ok(Expression::AggregateFunction(Box::new(
3804 crate::expressions::AggregateFunction {
3805 name: "APPROX_TOP_K".to_string(),
3806 args,
3807 distinct: f.distinct,
3808 filter: f.filter,
3809 order_by: Vec::new(),
3810 limit: None,
3811 ignore_nulls: None,
3812 inferred_type: None,
3813 },
3814 )))
3815 }
3816
3817 "SKEW" | "SKEWNESS" if !f.args.is_empty() => {
3819 let arg = f.args.into_iter().next().unwrap();
3820 Ok(Expression::Skewness(Box::new(AggFunc {
3821 this: arg,
3822 distinct: f.distinct,
3823 filter: f.filter,
3824 order_by: Vec::new(),
3825 name: Some("SKEW".to_string()),
3826 ignore_nulls: None,
3827 having_max: None,
3828 limit: None,
3829 inferred_type: None,
3830 })))
3831 }
3832
3833 _ => Ok(Expression::AggregateFunction(f)),
3835 }
3836 }
3837}
3838
3839fn strftime_to_snowflake_format(fmt: &str) -> String {
3841 let mut result = String::new();
3842 let chars: Vec<char> = fmt.chars().collect();
3843 let mut i = 0;
3844 while i < chars.len() {
3845 if chars[i] == '%' && i + 1 < chars.len() {
3846 match chars[i + 1] {
3847 'Y' => {
3848 result.push_str("yyyy");
3849 i += 2;
3850 }
3851 'y' => {
3852 result.push_str("yy");
3853 i += 2;
3854 }
3855 'm' => {
3856 result.push_str("mm");
3857 i += 2;
3858 }
3859 'd' => {
3860 result.push_str("DD");
3861 i += 2;
3862 }
3863 'H' => {
3864 result.push_str("hh24");
3865 i += 2;
3866 }
3867 'M' => {
3868 result.push_str("mmmm");
3869 i += 2;
3870 } 'i' => {
3872 result.push_str("mi");
3873 i += 2;
3874 }
3875 'S' | 's' => {
3876 result.push_str("ss");
3877 i += 2;
3878 }
3879 'f' => {
3880 result.push_str("ff");
3881 i += 2;
3882 }
3883 'w' => {
3884 result.push_str("dy");
3885 i += 2;
3886 } 'a' => {
3888 result.push_str("DY");
3889 i += 2;
3890 } 'b' => {
3892 result.push_str("mon");
3893 i += 2;
3894 } 'T' => {
3896 result.push_str("hh24:mi:ss");
3897 i += 2;
3898 } _ => {
3900 result.push(chars[i]);
3901 result.push(chars[i + 1]);
3902 i += 2;
3903 }
3904 }
3905 } else {
3906 result.push(chars[i]);
3907 i += 1;
3908 }
3909 }
3910 result
3911}
3912
3913#[cfg(test)]
3914mod tests {
3915 use super::*;
3916 use crate::dialects::Dialect;
3917
3918 fn transpile_to_snowflake(sql: &str) -> String {
3919 let dialect = Dialect::get(DialectType::Generic);
3920 let result = dialect
3921 .transpile(sql, DialectType::Snowflake)
3922 .expect("Transpile failed");
3923 result[0].clone()
3924 }
3925
3926 #[test]
3927 fn test_ifnull_to_coalesce() {
3928 let result = transpile_to_snowflake("SELECT IFNULL(a, b)");
3929 assert!(
3930 result.contains("COALESCE"),
3931 "Expected COALESCE, got: {}",
3932 result
3933 );
3934 }
3935
3936 #[test]
3937 fn test_basic_select() {
3938 let result = transpile_to_snowflake("SELECT a, b FROM users WHERE id = 1");
3939 assert!(result.contains("SELECT"));
3940 assert!(result.contains("FROM users"));
3941 }
3942
3943 #[test]
3944 fn test_snowflake_scripting_cursor_declare_block_roundtrip() {
3945 let sql = "DECLARE
3946 emp CURSOR FOR SELECT salary FROM employees;
3947BEGIN
3948 RETURN 1;
3949END";
3950
3951 let dialect = Dialect::get(DialectType::Snowflake);
3952 let ast = dialect.parse(sql).expect("Parse failed");
3953 let output = dialect.generate(&ast[0]).expect("Generate failed");
3954
3955 assert_eq!(output, sql);
3956 }
3957
3958 #[test]
3959 fn test_snowflake_scripting_cursor_return_table_roundtrip() {
3960 let sql = "DECLARE
3961 c1 CURSOR FOR SELECT * FROM invoices;
3962BEGIN
3963 OPEN c1;
3964 RETURN TABLE(RESULTSET_FROM_CURSOR(c1));
3965END";
3966
3967 let dialect = Dialect::get(DialectType::Snowflake);
3968 let ast = dialect.parse(sql).expect("Parse failed");
3969 let output = dialect.generate(&ast[0]).expect("Generate failed");
3970
3971 assert_eq!(output, sql);
3972 }
3973
3974 #[test]
3975 fn test_group_concat_to_listagg() {
3976 let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
3977 assert!(
3978 result.contains("LISTAGG"),
3979 "Expected LISTAGG, got: {}",
3980 result
3981 );
3982 }
3983
3984 #[test]
3985 fn test_string_agg_to_listagg() {
3986 let result = transpile_to_snowflake("SELECT STRING_AGG(name)");
3987 assert!(
3988 result.contains("LISTAGG"),
3989 "Expected LISTAGG, got: {}",
3990 result
3991 );
3992 }
3993
3994 #[test]
3995 fn test_array_to_array_construct() {
3996 let result = transpile_to_snowflake("SELECT ARRAY(1, 2, 3)");
3997 assert!(
3999 result.contains("[1, 2, 3]"),
4000 "Expected [1, 2, 3], got: {}",
4001 result
4002 );
4003 }
4004
4005 #[test]
4006 fn test_double_quote_identifiers() {
4007 let dialect = SnowflakeDialect;
4009 let config = dialect.generator_config();
4010 assert_eq!(config.identifier_quote, '"');
4011 }
4012}