1use super::{DialectImpl, DialectType};
13use crate::error::Result;
14use crate::expressions::{
15 AggFunc, Alias, BinaryOp, Case, Cast, CeilFunc, Column, DataType, Expression, Function,
16 Identifier, Interval, IntervalUnit, IntervalUnitSpec, IsNull, JSONPath, JSONPathKey,
17 JSONPathRoot, JSONPathSubscript, JsonExtractFunc, Literal, Null, Paren, Struct, Subquery,
18 SubstringFunc, UnaryFunc, UnaryOp, Unhex, VarArgFunc, WindowFunction,
19};
20#[cfg(feature = "generate")]
21use crate::generator::GeneratorConfig;
22use crate::tokens::TokenizerConfig;
23
24fn normalize_json_path(path: Expression) -> Expression {
28 match &path {
29 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
31 let Literal::String(s) = lit.as_ref() else {
32 unreachable!()
33 };
34 if s.starts_with('$') || s.starts_with('/') || s.contains("[#") {
37 return path;
38 }
39 Expression::JSONPath(Box::new(JSONPath {
41 expressions: vec![
42 Expression::JSONPathRoot(JSONPathRoot),
43 Expression::JSONPathKey(Box::new(JSONPathKey {
44 this: Box::new(Expression::Literal(Box::new(Literal::String(s.clone())))),
45 })),
46 ],
47 escape: None,
48 }))
49 }
50 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
52 let Literal::Number(n) = lit.as_ref() else {
53 unreachable!()
54 };
55 Expression::JSONPath(Box::new(JSONPath {
57 expressions: vec![
58 Expression::JSONPathRoot(JSONPathRoot),
59 Expression::JSONPathSubscript(Box::new(JSONPathSubscript {
60 this: Box::new(Expression::Literal(Box::new(Literal::Number(n.clone())))),
61 })),
62 ],
63 escape: None,
64 }))
65 }
66 _ => path,
68 }
69}
70
71fn wrap_if_json_arrow(expr: Expression) -> Expression {
75 match &expr {
76 Expression::JsonExtract(f) if f.arrow_syntax => Expression::Paren(Box::new(Paren {
77 this: expr,
78 trailing_comments: Vec::new(),
79 })),
80 Expression::JsonExtractScalar(f) if f.arrow_syntax => Expression::Paren(Box::new(Paren {
81 this: expr,
82 trailing_comments: Vec::new(),
83 })),
84 _ => expr,
85 }
86}
87
88pub struct DuckDBDialect;
90
91impl DialectImpl for DuckDBDialect {
92 fn dialect_type(&self) -> DialectType {
93 DialectType::DuckDB
94 }
95
96 fn tokenizer_config(&self) -> TokenizerConfig {
97 let mut config = TokenizerConfig::default();
98 config.identifiers.insert('"', '"');
100 config.quotes.remove("\"\"\"");
102 config.nested_comments = true;
104 config.numbers_can_be_underscore_separated = true;
106 config.double_slash_int_div = true;
108 config
109 }
110
111 #[cfg(feature = "generate")]
112
113 fn generator_config(&self) -> GeneratorConfig {
114 use crate::generator::IdentifierQuoteStyle;
115 GeneratorConfig {
116 identifier_quote: '"',
117 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
118 dialect: Some(DialectType::DuckDB),
119 parameter_token: "$",
121 named_placeholder_token: "$",
122 join_hints: false,
123 table_hints: false,
124 query_hints: false,
125 limit_fetch_style: crate::generator::LimitFetchStyle::Limit,
126 struct_delimiter: ("(", ")"),
127 rename_table_with_db: false,
128 nvl2_supported: false,
129 semi_anti_join_with_side: false,
130 tablesample_keywords: "TABLESAMPLE",
131 tablesample_seed_keyword: "REPEATABLE",
132 last_day_supports_date_part: false,
133 json_key_value_pair_sep: ",",
134 ignore_nulls_in_func: true,
135 json_path_bracketed_key_supported: false,
136 supports_create_table_like: false,
137 multi_arg_distinct: false,
138 quantified_no_paren_space: false,
139 can_implement_array_any: true,
140 supports_to_number: false,
141 supports_window_exclude: true,
142 copy_has_into_keyword: false,
143 star_except: "EXCLUDE",
144 pad_fill_pattern_is_required: true,
145 array_concat_is_var_len: false,
146 array_size_dim_required: None,
147 normalize_extract_date_parts: true,
148 supports_like_quantifiers: false,
149 try_supported: true,
151 struct_curly_brace_notation: true,
153 array_bracket_only: true,
155 ..Default::default()
156 }
157 }
158
159 #[cfg(feature = "transpile")]
160
161 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
162 match expr {
163 Expression::DataType(dt) => self.transform_data_type(dt),
165
166 Expression::BitwiseXor(op) => Ok(Expression::Function(Box::new(
169 crate::expressions::Function::new("XOR", vec![op.left, op.right]),
170 ))),
171
172 Expression::ArrayFunc(mut f) => {
175 f.bracket_notation = true;
176 Ok(Expression::ArrayFunc(f))
177 }
178
179 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
181 original_name: None,
182 expressions: vec![f.this, f.expression],
183 inferred_type: None,
184 }))),
185
186 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
188 original_name: None,
189 expressions: vec![f.this, f.expression],
190 inferred_type: None,
191 }))),
192
193 Expression::Coalesce(mut f) => {
195 f.original_name = None;
196 Ok(Expression::Coalesce(f))
197 }
198
199 Expression::GroupConcat(f) => Ok(Expression::ListAgg(Box::new(
201 crate::expressions::ListAggFunc {
202 source_dialect: None,
203 this: f.this,
204 separator: f.separator,
205 on_overflow: None,
206 max_length: None,
207 order_by: f.order_by,
208 distinct: f.distinct,
209 filter: f.filter,
210 inferred_type: None,
211 },
212 ))),
213
214 Expression::ListAgg(f) => Ok(Expression::ListAgg(f)),
216
217 Expression::StringAgg(f) => Ok(Expression::ListAgg(Box::new(
219 crate::expressions::ListAggFunc {
220 source_dialect: None,
221 this: f.this,
222 separator: f.separator,
223 on_overflow: None,
224 max_length: None,
225 order_by: f.order_by,
226 distinct: f.distinct,
227 filter: f.filter,
228 inferred_type: None,
229 },
230 ))),
231
232 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
234
235 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
237
238 Expression::ILike(op) => Ok(Expression::ILike(op)),
240
241 Expression::Explode(f) => Ok(Expression::Unnest(Box::new(
243 crate::expressions::UnnestFunc {
244 this: f.this,
245 expressions: Vec::new(),
246 with_ordinality: false,
247 alias: None,
248 offset_alias: None,
249 inferred_type: None,
250 },
251 ))),
252
253 Expression::Unnest(f) => Ok(Expression::Unnest(f)),
255
256 Expression::DateAdd(f) => {
258 let interval_expr = if matches!(&f.interval, Expression::Interval(_)) {
260 f.interval
261 } else {
262 Expression::Interval(Box::new(Interval {
263 this: Some(f.interval),
264 unit: Some(IntervalUnitSpec::Simple {
265 unit: f.unit,
266 use_plural: false,
267 }),
268 }))
269 };
270 Ok(Expression::Add(Box::new(BinaryOp {
271 left: f.this,
272 right: interval_expr,
273 left_comments: Vec::new(),
274 operator_comments: Vec::new(),
275 trailing_comments: Vec::new(),
276 inferred_type: None,
277 })))
278 }
279
280 Expression::DateSub(f) => {
282 let interval_expr = if matches!(&f.interval, Expression::Interval(_)) {
284 f.interval
285 } else {
286 Expression::Interval(Box::new(Interval {
287 this: Some(f.interval),
288 unit: Some(IntervalUnitSpec::Simple {
289 unit: f.unit,
290 use_plural: false,
291 }),
292 }))
293 };
294 Ok(Expression::Sub(Box::new(BinaryOp {
295 left: f.this,
296 right: interval_expr,
297 left_comments: Vec::new(),
298 operator_comments: Vec::new(),
299 trailing_comments: Vec::new(),
300 inferred_type: None,
301 })))
302 }
303
304 Expression::GenerateSeries(mut f) => {
306 if f.start.is_none() && f.end.is_some() {
308 f.start = Some(Box::new(Expression::number(0)));
309 }
310 Ok(Expression::GenerateSeries(f))
311 }
312
313 Expression::ArrayAppend(f) => Ok(Expression::Function(Box::new(Function::new(
316 "LIST_APPEND".to_string(),
317 vec![f.this, f.expression],
318 )))),
319
320 Expression::ArrayPrepend(f) => Ok(Expression::Function(Box::new(Function::new(
322 "LIST_PREPEND".to_string(),
323 vec![f.expression, f.this],
324 )))),
325
326 Expression::ArrayUniqueAgg(f) => {
328 let col = f.this;
329 let filter_expr = Expression::Not(Box::new(UnaryOp {
331 this: Expression::IsNull(Box::new(IsNull {
332 this: col.clone(),
333 not: false,
334 postfix_form: false,
335 })),
336 inferred_type: None,
337 }));
338 Ok(Expression::ArrayAgg(Box::new(AggFunc {
339 this: col,
340 distinct: true,
341 filter: Some(filter_expr),
342 order_by: Vec::new(),
343 name: Some("LIST".to_string()),
344 ignore_nulls: None,
345 having_max: None,
346 limit: None,
347 inferred_type: None,
348 })))
349 }
350
351 Expression::Split(f) => Ok(Expression::Function(Box::new(Function::new(
353 "STR_SPLIT".to_string(),
354 vec![f.this, f.delimiter],
355 )))),
356
357 Expression::Random(_) => Ok(Expression::Random(crate::expressions::Random)),
359
360 Expression::Rand(r) => {
363 if r.seed.is_some() {
364 Ok(Expression::Rand(r))
365 } else {
366 Ok(Expression::Random(crate::expressions::Random))
367 }
368 }
369
370 Expression::LogicalAnd(f) => Ok(Expression::Function(Box::new(Function::new(
373 "BOOL_AND".to_string(),
374 vec![Expression::Cast(Box::new(crate::expressions::Cast {
375 this: f.this,
376 to: crate::expressions::DataType::Boolean,
377 trailing_comments: Vec::new(),
378 double_colon_syntax: false,
379 format: None,
380 default: None,
381 inferred_type: None,
382 }))],
383 )))),
384
385 Expression::LogicalOr(f) => Ok(Expression::Function(Box::new(Function::new(
387 "BOOL_OR".to_string(),
388 vec![Expression::Cast(Box::new(crate::expressions::Cast {
389 this: f.this,
390 to: crate::expressions::DataType::Boolean,
391 trailing_comments: Vec::new(),
392 double_colon_syntax: false,
393 format: None,
394 default: None,
395 inferred_type: None,
396 }))],
397 )))),
398
399 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
402 "APPROX_COUNT_DISTINCT".to_string(),
403 vec![f.this],
404 )))),
405
406 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
409 "VAR_POP".to_string(),
410 vec![f.this],
411 )))),
412
413 Expression::DayOfMonth(f) => Ok(Expression::Function(Box::new(Function::new(
416 "DAYOFMONTH".to_string(),
417 vec![f.this],
418 )))),
419
420 Expression::DayOfWeek(f) => Ok(Expression::Function(Box::new(Function::new(
422 "DAYOFWEEK".to_string(),
423 vec![f.this],
424 )))),
425
426 Expression::DayOfWeekIso(f) => Ok(Expression::Function(Box::new(Function::new(
428 "ISODOW".to_string(),
429 vec![f.this],
430 )))),
431
432 Expression::DayOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
434 "DAYOFYEAR".to_string(),
435 vec![f.this],
436 )))),
437
438 Expression::WeekOfYear(f) => Ok(Expression::Function(Box::new(Function::new(
440 "WEEKOFYEAR".to_string(),
441 vec![f.this],
442 )))),
443
444 Expression::TimeStrToUnix(f) => Ok(Expression::Function(Box::new(Function::new(
447 "EPOCH".to_string(),
448 vec![f.this],
449 )))),
450
451 Expression::TimeToUnix(f) => Ok(Expression::Function(Box::new(Function::new(
453 "EPOCH".to_string(),
454 vec![f.this],
455 )))),
456
457 Expression::UnixMicros(f) => Ok(Expression::Function(Box::new(Function::new(
459 "EPOCH_US".to_string(),
460 vec![f.this],
461 )))),
462
463 Expression::UnixMillis(f) => Ok(Expression::Function(Box::new(Function::new(
465 "EPOCH_MS".to_string(),
466 vec![f.this],
467 )))),
468
469 Expression::TimestampDiff(f) => Ok(Expression::Function(Box::new(Function::new(
471 "DATE_DIFF".to_string(),
472 vec![*f.this, *f.expression],
473 )))),
474
475 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
478 "SHA1".to_string(),
479 vec![f.this],
480 )))),
481
482 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
484 "UNHEX".to_string(),
485 vec![*f.this],
486 )))),
487
488 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
490 "UNHEX".to_string(),
491 vec![f.this],
492 )))),
493
494 Expression::SHA2Digest(f) => Ok(Expression::Function(Box::new(Function::new(
496 "UNHEX".to_string(),
497 vec![*f.this],
498 )))),
499
500 Expression::CosineDistance(f) => Ok(Expression::Function(Box::new(Function::new(
503 "LIST_COSINE_DISTANCE".to_string(),
504 vec![*f.this, *f.expression],
505 )))),
506
507 Expression::EuclideanDistance(f) => Ok(Expression::Function(Box::new(Function::new(
509 "LIST_DISTANCE".to_string(),
510 vec![*f.this, *f.expression],
511 )))),
512
513 Expression::IsInf(f) => Ok(Expression::Function(Box::new(Function::new(
516 "ISINF".to_string(),
517 vec![f.this],
518 )))),
519
520 Expression::IsNan(f) => Ok(Expression::Function(Box::new(Function::new(
522 "ISNAN".to_string(),
523 vec![f.this],
524 )))),
525
526 Expression::RegexpLike(f) => Ok(Expression::Function(Box::new(Function::new(
529 "REGEXP_FULL_MATCH".to_string(),
530 vec![f.this, f.pattern],
531 )))),
532
533 Expression::CurrentTime(_) => Ok(Expression::Function(Box::new(Function {
536 on_error: None,
537 qualified_name: Vec::new(),
538 source_dialect: None,
539
540 name: "CURRENT_TIME".to_string(),
541 args: vec![],
542 distinct: false,
543 trailing_comments: vec![],
544 use_bracket_syntax: false,
545 no_parens: true,
546 quoted: false,
547 span: None,
548 inferred_type: None,
549 }))),
550
551 Expression::ReturnStmt(e) => Ok(*e),
554
555 Expression::CommentColumnConstraint(_) => Ok(Expression::Literal(Box::new(
558 crate::expressions::Literal::String(String::new()),
559 ))),
560
561 Expression::JsonExtract(mut f) => {
563 f.arrow_syntax = true;
564 f.path = normalize_json_path(f.path);
565 Ok(Expression::JsonExtract(f))
566 }
567
568 Expression::JsonExtractScalar(mut f) => {
570 f.arrow_syntax = true;
571 f.path = normalize_json_path(f.path);
572 Ok(Expression::JsonExtractScalar(f))
573 }
574
575 Expression::AddMonths(f) => {
581 let func = Function::new("ADD_MONTHS".to_string(), vec![f.this, f.expression]);
582 self.transform_function(func)
583 }
584
585 Expression::NextDay(f) => {
587 let func = Function::new("NEXT_DAY".to_string(), vec![f.this, f.expression]);
588 self.transform_function(func)
589 }
590
591 Expression::LastDay(f) => {
593 if let Some(unit) = f.unit {
594 let unit_str = match unit {
595 crate::expressions::DateTimeField::Year => "YEAR",
596 crate::expressions::DateTimeField::Month => "MONTH",
597 crate::expressions::DateTimeField::Quarter => "QUARTER",
598 crate::expressions::DateTimeField::Week => "WEEK",
599 crate::expressions::DateTimeField::Day => "DAY",
600 _ => "MONTH",
601 };
602 let func = Function::new(
603 "LAST_DAY".to_string(),
604 vec![
605 f.this,
606 Expression::Identifier(Identifier {
607 name: unit_str.to_string(),
608 quoted: false,
609 trailing_comments: Vec::new(),
610 span: None,
611 }),
612 ],
613 );
614 self.transform_function(func)
615 } else {
616 Ok(Expression::Function(Box::new(Function::new(
618 "LAST_DAY".to_string(),
619 vec![f.this],
620 ))))
621 }
622 }
623
624 Expression::Dayname(d) => Ok(Expression::Function(Box::new(Function::new(
626 "STRFTIME".to_string(),
627 vec![
628 *d.this,
629 Expression::Literal(Box::new(Literal::String("%a".to_string()))),
630 ],
631 )))),
632
633 Expression::Monthname(d) => Ok(Expression::Function(Box::new(Function::new(
635 "STRFTIME".to_string(),
636 vec![
637 *d.this,
638 Expression::Literal(Box::new(Literal::String("%b".to_string()))),
639 ],
640 )))),
641
642 Expression::Floor(f) if f.scale.is_some() => {
644 let x = f.this;
645 let scale = f.scale.unwrap();
646 let needs_cast = match &scale {
647 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
648 let Literal::Number(n) = lit.as_ref() else {
649 unreachable!()
650 };
651 n.contains('.')
652 }
653 _ => false,
654 };
655 let int_scale = if needs_cast {
656 Expression::Cast(Box::new(Cast {
657 this: scale.clone(),
658 to: DataType::Int {
659 length: None,
660 integer_spelling: false,
661 },
662 trailing_comments: Vec::new(),
663 double_colon_syntax: false,
664 format: None,
665 default: None,
666 inferred_type: None,
667 }))
668 } else {
669 scale.clone()
670 };
671 let power_10 = Expression::Function(Box::new(Function::new(
672 "POWER".to_string(),
673 vec![Expression::number(10), int_scale.clone()],
674 )));
675 let x_paren = match &x {
676 Expression::Add(_)
677 | Expression::Sub(_)
678 | Expression::Mul(_)
679 | Expression::Div(_) => Expression::Paren(Box::new(Paren {
680 this: x,
681 trailing_comments: Vec::new(),
682 })),
683 _ => x,
684 };
685 let multiplied = Expression::Mul(Box::new(BinaryOp {
686 left: x_paren,
687 right: power_10.clone(),
688 left_comments: Vec::new(),
689 operator_comments: Vec::new(),
690 trailing_comments: Vec::new(),
691 inferred_type: None,
692 }));
693 let floored = Expression::Function(Box::new(Function::new(
694 "FLOOR".to_string(),
695 vec![multiplied],
696 )));
697 let divided = Expression::Div(Box::new(BinaryOp {
698 left: floored,
699 right: power_10,
700 left_comments: Vec::new(),
701 operator_comments: Vec::new(),
702 trailing_comments: Vec::new(),
703 inferred_type: None,
704 }));
705 Ok(Expression::Function(Box::new(Function::new(
706 "ROUND".to_string(),
707 vec![divided, int_scale],
708 ))))
709 }
710
711 Expression::Ceil(f) if f.decimals.is_some() => {
713 let x = f.this;
714 let scale = f.decimals.unwrap();
715 let needs_cast = match &scale {
716 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
717 let Literal::Number(n) = lit.as_ref() else {
718 unreachable!()
719 };
720 n.contains('.')
721 }
722 _ => false,
723 };
724 let int_scale = if needs_cast {
725 Expression::Cast(Box::new(Cast {
726 this: scale.clone(),
727 to: DataType::Int {
728 length: None,
729 integer_spelling: false,
730 },
731 trailing_comments: Vec::new(),
732 double_colon_syntax: false,
733 format: None,
734 default: None,
735 inferred_type: None,
736 }))
737 } else {
738 scale.clone()
739 };
740 let power_10 = Expression::Function(Box::new(Function::new(
741 "POWER".to_string(),
742 vec![Expression::number(10), int_scale.clone()],
743 )));
744 let x_paren = match &x {
745 Expression::Add(_)
746 | Expression::Sub(_)
747 | Expression::Mul(_)
748 | Expression::Div(_) => Expression::Paren(Box::new(Paren {
749 this: x,
750 trailing_comments: Vec::new(),
751 })),
752 _ => x,
753 };
754 let multiplied = Expression::Mul(Box::new(BinaryOp {
755 left: x_paren,
756 right: power_10.clone(),
757 left_comments: Vec::new(),
758 operator_comments: Vec::new(),
759 trailing_comments: Vec::new(),
760 inferred_type: None,
761 }));
762 let ceiled = Expression::Function(Box::new(Function::new(
763 "CEIL".to_string(),
764 vec![multiplied],
765 )));
766 let divided = Expression::Div(Box::new(BinaryOp {
767 left: ceiled,
768 right: power_10,
769 left_comments: Vec::new(),
770 operator_comments: Vec::new(),
771 trailing_comments: Vec::new(),
772 inferred_type: None,
773 }));
774 Ok(Expression::Function(Box::new(Function::new(
775 "ROUND".to_string(),
776 vec![divided, int_scale],
777 ))))
778 }
779
780 Expression::TableArgument(ta) if ta.prefix.to_uppercase() == "TABLE" => {
785 match ta.this {
787 Expression::Function(ref f) if f.name.to_uppercase() == "RANGE" => {
788 Ok(ta.this)
790 }
791 Expression::Function(ref f) if f.name.to_uppercase() == "GENERATOR" => {
792 let mut rowcount = None;
794 for arg in &f.args {
795 if let Expression::NamedArgument(na) = arg {
796 if na.name.name.to_uppercase() == "ROWCOUNT" {
797 rowcount = Some(na.value.clone());
798 }
799 }
800 }
801 if let Some(n) = rowcount {
802 Ok(Expression::Function(Box::new(Function::new(
803 "RANGE".to_string(),
804 vec![n],
805 ))))
806 } else {
807 Ok(Expression::TableArgument(ta))
808 }
809 }
810 _ => Ok(Expression::TableArgument(ta)),
811 }
812 }
813
814 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
816 let path = match *e.expression {
817 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
818 let Literal::String(s) = lit.as_ref() else {
819 unreachable!()
820 };
821 let s = Self::convert_bracket_to_quoted_path(&s);
823 let normalized = if s.starts_with('$') {
824 s
825 } else if s.starts_with('[') {
826 format!("${}", s)
827 } else {
828 format!("$.{}", s)
829 };
830 Expression::Literal(Box::new(Literal::String(normalized)))
831 }
832 other => other,
833 };
834 Ok(Expression::JsonExtract(Box::new(JsonExtractFunc {
835 options: None,
836 source_dialect: None,
837
838 this: *e.this,
839 path,
840 returning: None,
841 arrow_syntax: true,
842 hash_arrow_syntax: false,
843 wrapper_option: None,
844 quotes_option: None,
845 on_scalar_string: false,
846 on_error: None,
847 })))
848 }
849
850 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::HexString(_)) => {
852 let Literal::HexString(s) = lit.as_ref() else {
853 unreachable!()
854 };
855 Ok(Expression::Function(Box::new(Function::new(
856 "UNHEX".to_string(),
857 vec![Expression::Literal(Box::new(Literal::String(s.clone())))],
858 ))))
859 }
860
861 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::ByteString(_)) => {
863 let Literal::ByteString(s) = lit.as_ref() else {
864 unreachable!()
865 };
866 Ok(Expression::Cast(Box::new(Cast {
867 this: Expression::Literal(Box::new(Literal::EscapeString(s.clone()))),
868 to: DataType::VarBinary { length: None },
869 trailing_comments: Vec::new(),
870 double_colon_syntax: false,
871 format: None,
872 default: None,
873 inferred_type: None,
874 })))
875 }
876
877 Expression::Cast(mut c) => {
880 let transformed_this = self.transform_expr(c.this)?;
881 c.this = transformed_this;
882 Ok(Expression::Cast(c))
883 }
884
885 Expression::Function(f) => self.transform_function(*f),
887
888 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
890
891 Expression::WindowFunction(wf) => {
895 if let Expression::Case(case_box) = wf.this {
896 let case = *case_box;
897 if case.whens.len() == 1
899 && matches!(&case.else_, Some(Expression::AggregateFunction(ref af)) if af.name.to_uppercase() == "CORR")
900 {
901 let over = wf.over;
903 let new_else = case.else_.map(|e| {
904 Expression::WindowFunction(Box::new(WindowFunction {
905 this: e,
906 over: over.clone(),
907 keep: None,
908 inferred_type: None,
909 }))
910 });
911 let new_whens = case
912 .whens
913 .into_iter()
914 .map(|(when_cond, when_result)| {
915 let new_cond = if let Expression::Function(func) = when_cond {
917 if func.name.to_uppercase() == "ISNAN" && func.args.len() == 1 {
918 let inner = func.args.into_iter().next().unwrap();
919 let windowed =
920 Expression::WindowFunction(Box::new(WindowFunction {
921 this: inner,
922 over: over.clone(),
923 keep: None,
924 inferred_type: None,
925 }));
926 Expression::Function(Box::new(Function::new(
927 "ISNAN".to_string(),
928 vec![windowed],
929 )))
930 } else {
931 Expression::Function(func)
932 }
933 } else {
934 when_cond
935 };
936 (new_cond, when_result)
937 })
938 .collect();
939 Ok(Expression::Case(Box::new(Case {
940 operand: None,
941 whens: new_whens,
942 else_: new_else,
943 comments: Vec::new(),
944 inferred_type: None,
945 })))
946 } else {
947 Ok(Expression::WindowFunction(Box::new(WindowFunction {
948 this: Expression::Case(Box::new(case)),
949 over: wf.over,
950 keep: wf.keep,
951 inferred_type: None,
952 })))
953 }
954 } else {
955 Ok(Expression::WindowFunction(wf))
956 }
957 }
958
959 Expression::Eq(op) => Ok(Expression::Eq(Box::new(BinaryOp {
966 left: wrap_if_json_arrow(op.left),
967 right: wrap_if_json_arrow(op.right),
968 ..*op
969 }))),
970 Expression::Neq(op) => Ok(Expression::Neq(Box::new(BinaryOp {
971 left: wrap_if_json_arrow(op.left),
972 right: wrap_if_json_arrow(op.right),
973 ..*op
974 }))),
975 Expression::Lt(op) => Ok(Expression::Lt(Box::new(BinaryOp {
976 left: wrap_if_json_arrow(op.left),
977 right: wrap_if_json_arrow(op.right),
978 ..*op
979 }))),
980 Expression::Lte(op) => Ok(Expression::Lte(Box::new(BinaryOp {
981 left: wrap_if_json_arrow(op.left),
982 right: wrap_if_json_arrow(op.right),
983 ..*op
984 }))),
985 Expression::Gt(op) => Ok(Expression::Gt(Box::new(BinaryOp {
986 left: wrap_if_json_arrow(op.left),
987 right: wrap_if_json_arrow(op.right),
988 ..*op
989 }))),
990 Expression::Gte(op) => Ok(Expression::Gte(Box::new(BinaryOp {
991 left: wrap_if_json_arrow(op.left),
992 right: wrap_if_json_arrow(op.right),
993 ..*op
994 }))),
995 Expression::And(op) => Ok(Expression::And(Box::new(BinaryOp {
996 left: wrap_if_json_arrow(op.left),
997 right: wrap_if_json_arrow(op.right),
998 ..*op
999 }))),
1000 Expression::Or(op) => Ok(Expression::Or(Box::new(BinaryOp {
1001 left: wrap_if_json_arrow(op.left),
1002 right: wrap_if_json_arrow(op.right),
1003 ..*op
1004 }))),
1005 Expression::Add(op) => Ok(Expression::Add(Box::new(BinaryOp {
1006 left: wrap_if_json_arrow(op.left),
1007 right: wrap_if_json_arrow(op.right),
1008 ..*op
1009 }))),
1010 Expression::Sub(op) => Ok(Expression::Sub(Box::new(BinaryOp {
1011 left: wrap_if_json_arrow(op.left),
1012 right: wrap_if_json_arrow(op.right),
1013 ..*op
1014 }))),
1015 Expression::Mul(op) => Ok(Expression::Mul(Box::new(BinaryOp {
1016 left: wrap_if_json_arrow(op.left),
1017 right: wrap_if_json_arrow(op.right),
1018 ..*op
1019 }))),
1020 Expression::Div(op) => Ok(Expression::Div(Box::new(BinaryOp {
1021 left: wrap_if_json_arrow(op.left),
1022 right: wrap_if_json_arrow(op.right),
1023 ..*op
1024 }))),
1025 Expression::Mod(op) => Ok(Expression::Mod(Box::new(BinaryOp {
1026 left: wrap_if_json_arrow(op.left),
1027 right: wrap_if_json_arrow(op.right),
1028 ..*op
1029 }))),
1030 Expression::Concat(op) => Ok(Expression::Concat(Box::new(BinaryOp {
1031 left: wrap_if_json_arrow(op.left),
1032 right: wrap_if_json_arrow(op.right),
1033 ..*op
1034 }))),
1035
1036 Expression::In(mut i) => {
1039 i.this = wrap_if_json_arrow(i.this);
1040 if i.not {
1041 i.not = false;
1043 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
1044 this: Expression::In(i),
1045 inferred_type: None,
1046 })))
1047 } else {
1048 Ok(Expression::In(i))
1049 }
1050 }
1051
1052 Expression::Not(mut n) => {
1054 n.this = wrap_if_json_arrow(n.this);
1055 Ok(Expression::Not(n))
1056 }
1057
1058 Expression::WithinGroup(wg) => {
1060 match &wg.this {
1061 Expression::ListAgg(listagg) => {
1062 let mut listagg = listagg.clone();
1063 listagg.order_by = Some(wg.order_by.clone());
1064 Ok(Expression::ListAgg(listagg))
1065 }
1066 Expression::PercentileCont(p) => {
1067 let column = wg
1068 .order_by
1069 .first()
1070 .map(|o| o.this.clone())
1071 .unwrap_or_else(|| p.this.clone());
1072 let percentile = p.percentile.clone();
1073 let filter = p.filter.clone();
1074 Ok(Expression::AggregateFunction(Box::new(
1075 crate::expressions::AggregateFunction {
1076 source_dialect: None,
1077
1078 name: "QUANTILE_CONT".to_string(),
1079 args: vec![column, percentile],
1080 distinct: false,
1081 filter,
1082 order_by: wg.order_by,
1083 limit: None,
1084 ignore_nulls: None,
1085 inferred_type: None,
1086 },
1087 )))
1088 }
1089 Expression::PercentileDisc(p) => {
1090 let column = wg
1091 .order_by
1092 .first()
1093 .map(|o| o.this.clone())
1094 .unwrap_or_else(|| p.this.clone());
1095 let percentile = p.percentile.clone();
1096 let filter = p.filter.clone();
1097 Ok(Expression::AggregateFunction(Box::new(
1098 crate::expressions::AggregateFunction {
1099 source_dialect: None,
1100
1101 name: "QUANTILE_DISC".to_string(),
1102 args: vec![column, percentile],
1103 distinct: false,
1104 filter,
1105 order_by: wg.order_by,
1106 limit: None,
1107 ignore_nulls: None,
1108 inferred_type: None,
1109 },
1110 )))
1111 }
1112 Expression::AggregateFunction(af)
1114 if af.name == "PERCENTILE_CONT" || af.name == "PERCENTILE_DISC" =>
1115 {
1116 let new_name = if af.name == "PERCENTILE_CONT" {
1117 "QUANTILE_CONT"
1118 } else {
1119 "QUANTILE_DISC"
1120 };
1121 let column = wg.order_by.first().map(|o| o.this.clone());
1122 let quantile = af.args.first().cloned();
1123 match (column, quantile) {
1124 (Some(col), Some(q)) => Ok(Expression::AggregateFunction(Box::new(
1125 crate::expressions::AggregateFunction {
1126 source_dialect: None,
1127
1128 name: new_name.to_string(),
1129 args: vec![col, q],
1130 distinct: false,
1131 filter: af.filter.clone(),
1132 order_by: wg.order_by,
1133 limit: None,
1134 ignore_nulls: None,
1135 inferred_type: None,
1136 },
1137 ))),
1138 _ => Ok(Expression::WithinGroup(wg)),
1139 }
1140 }
1141 _ => Ok(Expression::WithinGroup(wg)),
1142 }
1143 }
1144
1145 Expression::Column(ref c) if c.name.name.starts_with('@') && c.table.is_none() => {
1149 let col_name = &c.name.name[1..]; Ok(Expression::Abs(Box::new(UnaryFunc {
1151 this: Expression::boxed_column(Column {
1152 name: Identifier::new(col_name),
1153 table: None,
1154 join_mark: false,
1155 trailing_comments: Vec::new(),
1156 span: None,
1157 inferred_type: None,
1158 }),
1159 original_name: None,
1160 inferred_type: None,
1161 })))
1162 }
1163
1164 Expression::Select(mut select) => {
1169 select.expressions = select
1170 .expressions
1171 .into_iter()
1172 .map(|e| {
1173 match e {
1174 Expression::JSONExtract(ref je) if je.variant_extract.is_some() => {
1175 let alias_ident = match je.this.as_ref() {
1177 Expression::Identifier(ident) => Some(ident.clone()),
1178 Expression::Column(col) if col.table.is_none() => {
1179 Some(col.name.clone())
1180 }
1181 _ => None,
1182 };
1183 let value_expr = match je.expression.as_ref() {
1184 Expression::Literal(lit)
1185 if matches!(lit.as_ref(), Literal::String(_)) =>
1186 {
1187 let Literal::String(s) = lit.as_ref() else {
1188 unreachable!()
1189 };
1190 if s.contains('.') {
1192 let parts: Vec<&str> = s.splitn(2, '.').collect();
1194 Some(Expression::boxed_column(Column {
1195 name: Identifier::new(parts[1]),
1196 table: Some(Identifier::new(parts[0])),
1197 join_mark: false,
1198 trailing_comments: Vec::new(),
1199 span: None,
1200 inferred_type: None,
1201 }))
1202 } else {
1203 Some(Expression::boxed_column(Column {
1204 name: Identifier::new(s.as_str()),
1205 table: None,
1206 join_mark: false,
1207 trailing_comments: Vec::new(),
1208 span: None,
1209 inferred_type: None,
1210 }))
1211 }
1212 }
1213 _ => None,
1214 };
1215
1216 if let (Some(alias), Some(value)) = (alias_ident, value_expr) {
1217 Expression::Alias(Box::new(Alias {
1218 this: value,
1219 alias,
1220 column_aliases: Vec::new(),
1221 alias_explicit_as: false,
1222 alias_keyword: None,
1223 pre_alias_comments: Vec::new(),
1224 trailing_comments: Vec::new(),
1225 inferred_type: None,
1226 }))
1227 } else {
1228 e
1229 }
1230 }
1231 _ => e,
1232 }
1233 })
1234 .collect();
1235
1236 if let Some(ref mut from) = select.from {
1239 if from.expressions.len() > 1 {
1240 let mut new_from_exprs = Vec::new();
1242 let mut new_joins = Vec::new();
1243
1244 for (idx, expr) in from.expressions.drain(..).enumerate() {
1245 if idx == 0 {
1246 new_from_exprs.push(expr);
1248 } else {
1249 let is_unnest = match &expr {
1251 Expression::Unnest(_) => true,
1252 Expression::Alias(a) => matches!(a.this, Expression::Unnest(_)),
1253 _ => false,
1254 };
1255
1256 if is_unnest {
1257 new_joins.push(crate::expressions::Join {
1259 this: expr,
1260 on: Some(Expression::Boolean(
1261 crate::expressions::BooleanLiteral { value: true },
1262 )),
1263 using: Vec::new(),
1264 kind: crate::expressions::JoinKind::Inner,
1265 use_inner_keyword: false,
1266 use_outer_keyword: false,
1267 deferred_condition: false,
1268 join_hint: None,
1269 match_condition: None,
1270 pivots: Vec::new(),
1271 comments: Vec::new(),
1272 nesting_group: 0,
1273 directed: false,
1274 });
1275 } else {
1276 new_from_exprs.push(expr);
1278 }
1279 }
1280 }
1281
1282 from.expressions = new_from_exprs;
1283
1284 new_joins.append(&mut select.joins);
1286 select.joins = new_joins;
1287 }
1288 }
1289
1290 Ok(Expression::Select(select))
1291 }
1292
1293 Expression::Interval(interval) => self.transform_interval(*interval),
1298
1299 Expression::CreateFunction(mut cf) => {
1301 cf.parameters = cf
1303 .parameters
1304 .into_iter()
1305 .map(|mut p| {
1306 if let Ok(Expression::DataType(new_dt)) =
1307 self.transform_data_type(p.data_type.clone())
1308 {
1309 p.data_type = new_dt;
1310 }
1311 p
1312 })
1313 .collect();
1314
1315 if cf.returns_table_body.is_some()
1319 && !matches!(&cf.return_type, Some(DataType::Custom { ref name }) if name == "TABLE")
1320 {
1321 cf.return_type = Some(DataType::Custom {
1322 name: "TABLE".to_string(),
1323 });
1324 cf.returns_table_body = None;
1325 }
1326
1327 Ok(Expression::CreateFunction(cf))
1328 }
1329
1330 Expression::IfFunc(f) => Ok(Expression::Case(Box::new(Case {
1334 operand: None,
1335 whens: vec![(f.condition, f.true_value)],
1336 else_: f.false_value,
1337 comments: Vec::new(),
1338 inferred_type: None,
1339 }))),
1340
1341 Expression::VarSamp(f) => Ok(Expression::Function(Box::new(Function::new(
1343 "VARIANCE".to_string(),
1344 vec![f.this],
1345 )))),
1346
1347 Expression::Nvl2(f) => {
1349 let condition = Expression::IsNull(Box::new(crate::expressions::IsNull {
1350 this: f.this,
1351 not: true,
1352 postfix_form: false,
1353 }));
1354 Ok(Expression::Case(Box::new(Case {
1355 operand: None,
1356 whens: vec![(condition, f.true_value)],
1357 else_: Some(f.false_value),
1358 comments: Vec::new(),
1359 inferred_type: None,
1360 })))
1361 }
1362
1363 _ => Ok(expr),
1365 }
1366 }
1367}
1368
1369#[cfg(feature = "transpile")]
1370impl DuckDBDialect {
1371 fn extract_number_value(expr: &Expression) -> Option<f64> {
1373 match expr {
1374 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
1375 let Literal::Number(n) = lit.as_ref() else {
1376 unreachable!()
1377 };
1378 n.parse::<f64>().ok()
1379 }
1380 _ => None,
1381 }
1382 }
1383
1384 fn expr_to_sql(expr: &Expression) -> String {
1386 crate::generator::Generator::sql(expr).unwrap_or_default()
1387 }
1388
1389 fn extract_seed_info(gen: &Expression) -> (String, bool) {
1395 match gen {
1396 Expression::Function(func) if func.name.to_uppercase() == "RANDOM" => {
1397 if func.args.is_empty() {
1398 ("RANDOM()".to_string(), true)
1399 } else {
1400 (Self::expr_to_sql(&func.args[0]), false)
1402 }
1403 }
1404 Expression::Rand(r) => {
1405 if let Some(ref seed) = r.seed {
1406 (Self::expr_to_sql(seed), false)
1408 } else {
1409 ("RANDOM()".to_string(), true)
1410 }
1411 }
1412 Expression::Random(_) => ("RANDOM()".to_string(), true),
1413 _ => (Self::expr_to_sql(gen), false),
1414 }
1415 }
1416
1417 fn parse_as_subquery(sql: &str) -> Result<Expression> {
1420 let sql_owned = sql.to_string();
1421 let handle = std::thread::Builder::new()
1422 .stack_size(16 * 1024 * 1024) .spawn(move || match crate::parser::Parser::parse_sql(&sql_owned) {
1424 Ok(stmts) => {
1425 if let Some(stmt) = stmts.into_iter().next() {
1426 Ok(Expression::Subquery(Box::new(Subquery {
1427 this: stmt,
1428 alias: None,
1429 column_aliases: Vec::new(),
1430 alias_explicit_as: false,
1431 alias_keyword: None,
1432 order_by: None,
1433 limit: None,
1434 offset: None,
1435 distribute_by: None,
1436 sort_by: None,
1437 cluster_by: None,
1438 lateral: false,
1439 modifiers_inside: false,
1440 trailing_comments: Vec::new(),
1441 inferred_type: None,
1442 })))
1443 } else {
1444 Err(crate::error::Error::Generate(
1445 "Failed to parse template SQL".to_string(),
1446 ))
1447 }
1448 }
1449 Err(e) => Err(e),
1450 })
1451 .map_err(|e| {
1452 crate::error::Error::Internal(format!("Failed to spawn parser thread: {}", e))
1453 })?;
1454
1455 handle
1456 .join()
1457 .map_err(|_| crate::error::Error::Internal("Parser thread panicked".to_string()))?
1458 }
1459
1460 fn normalize_empty_map_expr(expr: Expression) -> Expression {
1462 match expr {
1463 Expression::Cast(mut c) if matches!(&c.to, DataType::Map { .. }) => {
1464 if matches!(&c.this, Expression::Struct(s) if s.fields.is_empty()) {
1465 c.this =
1466 Expression::Function(Box::new(Function::new("MAP".to_string(), vec![])));
1467 }
1468 Expression::Cast(c)
1469 }
1470 other => other,
1471 }
1472 }
1473
1474 fn convert_bracket_to_quoted_path(path: &str) -> String {
1478 let mut result = String::new();
1479 let mut chars = path.chars().peekable();
1480 while let Some(c) = chars.next() {
1481 if c == '[' && chars.peek() == Some(&'"') {
1482 chars.next(); let mut key = String::new();
1485 while let Some(kc) = chars.next() {
1486 if kc == '"' && chars.peek() == Some(&']') {
1487 chars.next(); break;
1489 }
1490 key.push(kc);
1491 }
1492 if !result.is_empty() && !result.ends_with('.') {
1494 result.push('.');
1495 }
1496 result.push('"');
1497 result.push_str(&key);
1498 result.push('"');
1499 } else {
1500 result.push(c);
1501 }
1502 }
1503 result
1504 }
1505
1506 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
1508 use crate::expressions::DataType;
1509 let transformed = match dt {
1510 DataType::Binary { length } => DataType::VarBinary { length },
1512 DataType::Blob => DataType::VarBinary { length: None },
1515 DataType::Char { .. } | DataType::VarChar { .. } => dt,
1517 DataType::Float {
1519 precision, scale, ..
1520 } => DataType::Float {
1521 precision,
1522 scale,
1523 real_spelling: true,
1524 },
1525 DataType::JsonB => DataType::Json,
1527 DataType::Custom { ref name } => {
1529 let upper = name.to_uppercase();
1530 match upper.as_str() {
1531 name if DataType::from_unsigned_name(name).is_some() => {
1532 DataType::from_unsigned_name(name).unwrap()
1533 }
1534 "INT64" | "INT8" => DataType::BigInt { length: None },
1536 "INT32" | "INT4" | "SIGNED" => DataType::Int {
1538 length: None,
1539 integer_spelling: false,
1540 },
1541 "INT16" => DataType::SmallInt { length: None },
1543 "INT1" => DataType::TinyInt { length: None },
1545 "HUGEINT" | "INT128" => DataType::Int128,
1547 "BPCHAR" => DataType::Text,
1549 "CHARACTER VARYING" | "CHAR VARYING" => DataType::Text,
1551 "FLOAT4" => DataType::Custom {
1553 name: "REAL".to_string(),
1554 },
1555 "LOGICAL" => DataType::Boolean,
1557 "TIMESTAMPNTZ" | "TIMESTAMP_NTZ" => DataType::Timestamp {
1559 precision: None,
1560 timezone: false,
1561 },
1562 "TIMESTAMP_US" => DataType::Timestamp {
1564 precision: None,
1565 timezone: false,
1566 },
1567 "TIMESTAMPLTZ" | "TIMESTAMP_LTZ" | "TIMESTAMPTZ" | "TIMESTAMP_TZ" => {
1569 DataType::Timestamp {
1570 precision: None,
1571 timezone: true,
1572 }
1573 }
1574 "DECFLOAT" => DataType::Decimal {
1576 precision: Some(38),
1577 scale: Some(5),
1578 },
1579 _ => dt,
1581 }
1582 }
1583 other => other,
1585 };
1586 Ok(Expression::DataType(transformed))
1587 }
1588
1589 fn transform_interval(&self, interval: Interval) -> Result<Expression> {
1592 if interval.unit.is_some() {
1596 return Ok(Expression::Interval(Box::new(interval)));
1598 }
1599
1600 if let Some(Expression::Literal(ref lit)) = interval.this {
1601 if let Literal::String(ref s) = lit.as_ref() {
1602 if let Some((value, unit)) = Self::parse_interval_string(s) {
1604 return Ok(Expression::Interval(Box::new(Interval {
1606 this: Some(Expression::Literal(Box::new(Literal::String(
1607 value.to_string(),
1608 )))),
1609 unit: Some(IntervalUnitSpec::Simple {
1610 unit,
1611 use_plural: false, }),
1613 })));
1614 }
1615 }
1616 }
1617
1618 Ok(Expression::Interval(Box::new(interval)))
1620 }
1621
1622 fn parse_interval_string(s: &str) -> Option<(&str, IntervalUnit)> {
1625 let s = s.trim();
1626
1627 let mut num_end = 0;
1630 let mut chars = s.chars().peekable();
1631
1632 if chars.peek() == Some(&'-') {
1634 chars.next();
1635 num_end += 1;
1636 }
1637
1638 while let Some(&c) = chars.peek() {
1640 if c.is_ascii_digit() {
1641 chars.next();
1642 num_end += 1;
1643 } else {
1644 break;
1645 }
1646 }
1647
1648 if chars.peek() == Some(&'.') {
1650 chars.next();
1651 num_end += 1;
1652 while let Some(&c) = chars.peek() {
1653 if c.is_ascii_digit() {
1654 chars.next();
1655 num_end += 1;
1656 } else {
1657 break;
1658 }
1659 }
1660 }
1661
1662 if num_end == 0 || (num_end == 1 && s.starts_with('-')) {
1663 return None; }
1665
1666 let value = &s[..num_end];
1667 let rest = s[num_end..].trim();
1668
1669 if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_alphabetic()) {
1671 return None;
1672 }
1673
1674 let unit = match rest.to_uppercase().as_str() {
1676 "YEAR" | "YEARS" | "Y" => IntervalUnit::Year,
1677 "MONTH" | "MONTHS" | "MON" | "MONS" => IntervalUnit::Month,
1678 "DAY" | "DAYS" | "D" => IntervalUnit::Day,
1679 "HOUR" | "HOURS" | "H" | "HR" | "HRS" => IntervalUnit::Hour,
1680 "MINUTE" | "MINUTES" | "MIN" | "MINS" | "M" => IntervalUnit::Minute,
1681 "SECOND" | "SECONDS" | "SEC" | "SECS" | "S" => IntervalUnit::Second,
1682 "MILLISECOND" | "MILLISECONDS" | "MS" => IntervalUnit::Millisecond,
1683 "MICROSECOND" | "MICROSECONDS" | "US" => IntervalUnit::Microsecond,
1684 "QUARTER" | "QUARTERS" | "Q" => IntervalUnit::Quarter,
1685 "WEEK" | "WEEKS" | "W" => IntervalUnit::Week,
1686 _ => return None, };
1688
1689 Some((value, unit))
1690 }
1691
1692 fn transform_function(&self, f: Function) -> Result<Expression> {
1693 let name_upper = f.name.to_uppercase();
1694 match name_upper.as_str() {
1695 "FROM_HEX" if f.args.len() == 1 => {
1696 let mut args = f.args;
1697 Ok(Expression::Unhex(Box::new(Unhex {
1698 this: Box::new(args.remove(0)),
1699 expression: None,
1700 })))
1701 }
1702
1703 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1705 original_name: None,
1706 expressions: f.args,
1707 inferred_type: None,
1708 }))),
1709
1710 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1712 original_name: None,
1713 expressions: f.args,
1714 inferred_type: None,
1715 }))),
1716
1717 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1719 original_name: None,
1720 expressions: f.args,
1721 inferred_type: None,
1722 }))),
1723
1724 "ARRAY_COMPACT" if f.args.len() == 1 => {
1726 let arr = f.args.into_iter().next().unwrap();
1727 let lambda = Expression::Lambda(Box::new(crate::expressions::LambdaExpr {
1728 parameters: vec![Identifier::new("_u".to_string())],
1729 body: Expression::Not(Box::new(crate::expressions::UnaryOp {
1730 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
1731 this: Expression::boxed_column(Column {
1732 table: None,
1733 name: Identifier::new("_u".to_string()),
1734 join_mark: false,
1735 trailing_comments: Vec::new(),
1736 span: None,
1737 inferred_type: None,
1738 }),
1739 not: false,
1740 postfix_form: false,
1741 })),
1742 inferred_type: None,
1743 })),
1744 colon: false,
1745 parameter_types: Vec::new(),
1746 }));
1747 Ok(Expression::Function(Box::new(Function::new(
1748 "LIST_FILTER".to_string(),
1749 vec![arr, lambda],
1750 ))))
1751 }
1752
1753 "ARRAY_CONSTRUCT_COMPACT" => Ok(Expression::Function(Box::new(f))),
1755
1756 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1758 Function::new("LISTAGG".to_string(), f.args),
1759 ))),
1760
1761 "LISTAGG" => Ok(Expression::Function(Box::new(f))),
1763
1764 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1766 Function::new("LISTAGG".to_string(), f.args),
1767 ))),
1768
1769 "ARRAY_UNIQUE_AGG" if f.args.len() == 1 => {
1771 let col = f.args.into_iter().next().unwrap();
1772 let filter_expr = Expression::Not(Box::new(UnaryOp {
1774 this: Expression::IsNull(Box::new(IsNull {
1775 this: col.clone(),
1776 not: false,
1777 postfix_form: false,
1778 })),
1779 inferred_type: None,
1780 }));
1781 Ok(Expression::ArrayAgg(Box::new(AggFunc {
1782 this: col,
1783 distinct: true,
1784 filter: Some(filter_expr),
1785 order_by: Vec::new(),
1786 name: Some("LIST".to_string()),
1787 ignore_nulls: None,
1788 having_max: None,
1789 limit: None,
1790 inferred_type: None,
1791 })))
1792 }
1793
1794 "CHECK_JSON" if f.args.len() == 1 => {
1796 let x = f.args.into_iter().next().unwrap();
1797 let is_null = Expression::IsNull(Box::new(IsNull {
1799 this: x.clone(),
1800 not: false,
1801 postfix_form: false,
1802 }));
1803 let eq_empty = Expression::Eq(Box::new(BinaryOp::new(
1805 x.clone(),
1806 Expression::Literal(Box::new(Literal::String(String::new()))),
1807 )));
1808 let json_valid = Expression::Function(Box::new(Function::new(
1810 "JSON_VALID".to_string(),
1811 vec![x],
1812 )));
1813 let or1 = Expression::Or(Box::new(BinaryOp::new(is_null, eq_empty)));
1815 let condition = Expression::Or(Box::new(BinaryOp::new(or1, json_valid)));
1817 Ok(Expression::Case(Box::new(Case {
1818 operand: None,
1819 whens: vec![(condition, Expression::Null(Null))],
1820 else_: Some(Expression::Literal(Box::new(Literal::String(
1821 "Invalid JSON".to_string(),
1822 )))),
1823 comments: Vec::new(),
1824 inferred_type: None,
1825 })))
1826 }
1827
1828 "SUBSTR" => Ok(Expression::Function(Box::new(f))),
1830
1831 "FLATTEN" => Ok(Expression::Function(Box::new(Function::new(
1833 "UNNEST".to_string(),
1834 f.args,
1835 )))),
1836
1837 "ARRAY_FLATTEN" => Ok(Expression::Function(Box::new(Function::new(
1839 "FLATTEN".to_string(),
1840 f.args,
1841 )))),
1842
1843 "RPAD" if f.args.len() == 2 => {
1845 let mut args = f.args;
1846 args.push(Expression::Literal(Box::new(Literal::String(
1847 " ".to_string(),
1848 ))));
1849 Ok(Expression::Function(Box::new(Function::new(
1850 "RPAD".to_string(),
1851 args,
1852 ))))
1853 }
1854
1855 "BASE64_DECODE_STRING" => {
1858 let mut args = f.args;
1859 let input = args.remove(0);
1860 let has_alphabet = !args.is_empty();
1861 let decoded_input = if has_alphabet {
1862 let r1 = Expression::Function(Box::new(Function::new(
1864 "REPLACE".to_string(),
1865 vec![
1866 input,
1867 Expression::Literal(Box::new(Literal::String("-".to_string()))),
1868 Expression::Literal(Box::new(Literal::String("+".to_string()))),
1869 ],
1870 )));
1871 let r2 = Expression::Function(Box::new(Function::new(
1872 "REPLACE".to_string(),
1873 vec![
1874 r1,
1875 Expression::Literal(Box::new(Literal::String("_".to_string()))),
1876 Expression::Literal(Box::new(Literal::String("/".to_string()))),
1877 ],
1878 )));
1879 Expression::Function(Box::new(Function::new(
1880 "REPLACE".to_string(),
1881 vec![
1882 r2,
1883 Expression::Literal(Box::new(Literal::String("+".to_string()))),
1884 Expression::Literal(Box::new(Literal::String("=".to_string()))),
1885 ],
1886 )))
1887 } else {
1888 input
1889 };
1890 let from_base64 = Expression::Function(Box::new(Function::new(
1891 "FROM_BASE64".to_string(),
1892 vec![decoded_input],
1893 )));
1894 Ok(Expression::Function(Box::new(Function::new(
1895 "DECODE".to_string(),
1896 vec![from_base64],
1897 ))))
1898 }
1899
1900 "BASE64_DECODE_BINARY" => {
1903 let mut args = f.args;
1904 let input = args.remove(0);
1905 let has_alphabet = !args.is_empty();
1906 let decoded_input = if has_alphabet {
1907 let r1 = Expression::Function(Box::new(Function::new(
1908 "REPLACE".to_string(),
1909 vec![
1910 input,
1911 Expression::Literal(Box::new(Literal::String("-".to_string()))),
1912 Expression::Literal(Box::new(Literal::String("+".to_string()))),
1913 ],
1914 )));
1915 let r2 = Expression::Function(Box::new(Function::new(
1916 "REPLACE".to_string(),
1917 vec![
1918 r1,
1919 Expression::Literal(Box::new(Literal::String("_".to_string()))),
1920 Expression::Literal(Box::new(Literal::String("/".to_string()))),
1921 ],
1922 )));
1923 Expression::Function(Box::new(Function::new(
1924 "REPLACE".to_string(),
1925 vec![
1926 r2,
1927 Expression::Literal(Box::new(Literal::String("+".to_string()))),
1928 Expression::Literal(Box::new(Literal::String("=".to_string()))),
1929 ],
1930 )))
1931 } else {
1932 input
1933 };
1934 Ok(Expression::Function(Box::new(Function::new(
1935 "FROM_BASE64".to_string(),
1936 vec![decoded_input],
1937 ))))
1938 }
1939
1940 "SPACE" if f.args.len() == 1 => {
1942 let arg = f.args.into_iter().next().unwrap();
1943 let cast_arg = Expression::Cast(Box::new(Cast {
1944 this: arg,
1945 to: DataType::BigInt { length: None },
1946 trailing_comments: Vec::new(),
1947 double_colon_syntax: false,
1948 format: None,
1949 default: None,
1950 inferred_type: None,
1951 }));
1952 Ok(Expression::Function(Box::new(Function::new(
1953 "REPEAT".to_string(),
1954 vec![
1955 Expression::Literal(Box::new(Literal::String(" ".to_string()))),
1956 cast_arg,
1957 ],
1958 ))))
1959 }
1960
1961 "IS_ARRAY" if f.args.len() == 1 => {
1963 let arg = f.args.into_iter().next().unwrap();
1964 let json_type = Expression::Function(Box::new(Function::new(
1965 "JSON_TYPE".to_string(),
1966 vec![arg],
1967 )));
1968 Ok(Expression::Eq(Box::new(BinaryOp {
1969 left: json_type,
1970 right: Expression::Literal(Box::new(Literal::String("ARRAY".to_string()))),
1971 left_comments: Vec::new(),
1972 operator_comments: Vec::new(),
1973 trailing_comments: Vec::new(),
1974 inferred_type: None,
1975 })))
1976 }
1977
1978 "EXPLODE" => Ok(Expression::Function(Box::new(Function::new(
1980 "UNNEST".to_string(),
1981 f.args,
1982 )))),
1983
1984 "GETDATE" => Ok(Expression::CurrentTimestamp(
1986 crate::expressions::CurrentTimestamp {
1987 precision: None,
1988 sysdate: false,
1989 },
1990 )),
1991
1992 "TODAY" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1994
1995 "CURDATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
1997
1998 "GET_CURRENT_TIME" => Ok(Expression::CurrentTime(crate::expressions::CurrentTime {
2000 precision: None,
2001 })),
2002
2003 "CURRENT_LOCALTIMESTAMP" => Ok(Expression::Localtimestamp(Box::new(
2005 crate::expressions::Localtimestamp { this: None },
2006 ))),
2007
2008 "REGEXP_EXTRACT_ALL" if f.args.len() == 3 => {
2010 if matches!(&f.args[2], Expression::Literal(lit) if matches!(lit.as_ref(), crate::expressions::Literal::Number(n) if n == "0"))
2012 {
2013 Ok(Expression::Function(Box::new(Function::new(
2014 "REGEXP_EXTRACT_ALL".to_string(),
2015 vec![f.args[0].clone(), f.args[1].clone()],
2016 ))))
2017 } else {
2018 Ok(Expression::Function(Box::new(Function::new(
2019 "REGEXP_EXTRACT_ALL".to_string(),
2020 f.args,
2021 ))))
2022 }
2023 }
2024
2025 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
2027
2028 "TO_DATE" if f.args.len() == 1 => {
2030 let arg = f.args.into_iter().next().unwrap();
2031 Ok(Expression::Cast(Box::new(Cast {
2032 this: arg,
2033 to: DataType::Date,
2034 trailing_comments: Vec::new(),
2035 double_colon_syntax: false,
2036 format: None,
2037 default: None,
2038 inferred_type: None,
2039 })))
2040 }
2041
2042 "DATE_FORMAT" if f.args.len() >= 2 => {
2046 let mut args = f.args;
2047 args[1] = Self::convert_format_to_duckdb(&args[1]);
2048 Ok(Expression::Function(Box::new(Function::new(
2049 "STRFTIME".to_string(),
2050 args,
2051 ))))
2052 }
2053
2054 "DATE_PARSE" if f.args.len() >= 2 => {
2056 let mut args = f.args;
2057 args[1] = Self::convert_format_to_duckdb(&args[1]);
2058 Ok(Expression::Function(Box::new(Function::new(
2059 "STRPTIME".to_string(),
2060 args,
2061 ))))
2062 }
2063
2064 "FORMAT_DATE" if f.args.len() >= 2 => {
2066 let mut args = f.args;
2067 args[1] = Self::convert_format_to_duckdb(&args[1]);
2068 Ok(Expression::Function(Box::new(Function::new(
2069 "STRFTIME".to_string(),
2070 args,
2071 ))))
2072 }
2073
2074 "TO_CHAR" if f.args.len() >= 2 => {
2076 let mut args = f.args;
2077 args[1] = Self::convert_format_to_duckdb(&args[1]);
2078 Ok(Expression::Function(Box::new(Function::new(
2079 "STRFTIME".to_string(),
2080 args,
2081 ))))
2082 }
2083
2084 "EPOCH_MS" => Ok(Expression::Function(Box::new(f))),
2086
2087 "EPOCH" => Ok(Expression::Function(Box::new(f))),
2089
2090 "FROM_UNIXTIME" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
2092 Function::new("TO_TIMESTAMP".to_string(), f.args),
2093 ))),
2094
2095 "UNIX_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
2097 "EPOCH".to_string(),
2098 f.args,
2099 )))),
2100
2101 "JSON_EXTRACT" if f.args.len() == 2 => {
2103 let mut args = f.args;
2104 let path = args.pop().unwrap();
2105 let this = args.pop().unwrap();
2106 Ok(Expression::JsonExtract(Box::new(JsonExtractFunc {
2107 options: None,
2108 source_dialect: None,
2109
2110 this,
2111 path,
2112 returning: None,
2113 arrow_syntax: true,
2114 hash_arrow_syntax: false,
2115 wrapper_option: None,
2116 quotes_option: None,
2117 on_scalar_string: false,
2118 on_error: None,
2119 })))
2120 }
2121
2122 "JSON_EXTRACT_STRING" if f.args.len() == 2 => {
2124 let mut args = f.args;
2125 let path = args.pop().unwrap();
2126 let this = args.pop().unwrap();
2127 Ok(Expression::JsonExtractScalar(Box::new(JsonExtractFunc {
2128 options: None,
2129 source_dialect: None,
2130
2131 this,
2132 path,
2133 returning: None,
2134 arrow_syntax: true,
2135 hash_arrow_syntax: false,
2136 wrapper_option: None,
2137 quotes_option: None,
2138 on_scalar_string: false,
2139 on_error: None,
2140 })))
2141 }
2142
2143 "ARRAY_CONSTRUCT" => Ok(Expression::Function(Box::new(Function::new(
2145 "list_value".to_string(),
2146 f.args,
2147 )))),
2148
2149 "ARRAY" => {
2152 let has_query = f
2154 .args
2155 .iter()
2156 .any(|a| matches!(a, Expression::Subquery(_) | Expression::Select(_)));
2157 if has_query {
2158 Ok(Expression::Function(Box::new(Function::new(
2160 "ARRAY".to_string(),
2161 f.args,
2162 ))))
2163 } else {
2164 Ok(Expression::Function(Box::new(Function::new(
2165 "list_value".to_string(),
2166 f.args,
2167 ))))
2168 }
2169 }
2170
2171 "LIST_VALUE" => Ok(Expression::Array(Box::new(crate::expressions::Array {
2173 expressions: f.args,
2174 inferred_type: None,
2175 }))),
2176
2177 "ARRAY_AGG" => Ok(Expression::Function(Box::new(Function::new(
2179 "list".to_string(),
2180 f.args,
2181 )))),
2182
2183 "LIST_CONTAINS" | "ARRAY_CONTAINS" => Ok(Expression::Function(Box::new(
2185 Function::new("ARRAY_CONTAINS".to_string(), f.args),
2186 ))),
2187
2188 "ARRAY_SIZE" | "CARDINALITY" => Ok(Expression::Function(Box::new(Function::new(
2190 "ARRAY_LENGTH".to_string(),
2191 f.args,
2192 )))),
2193
2194 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
2196 f.args.into_iter().next().unwrap(),
2197 )))),
2198
2199 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
2201 this: f.args.into_iter().next().unwrap(),
2202 decimals: None,
2203 to: None,
2204 }))),
2205
2206 "LOGICAL_OR" if f.args.len() == 1 => {
2208 let arg = f.args.into_iter().next().unwrap();
2209 Ok(Expression::Function(Box::new(Function::new(
2210 "BOOL_OR".to_string(),
2211 vec![Expression::Cast(Box::new(crate::expressions::Cast {
2212 this: arg,
2213 to: crate::expressions::DataType::Boolean,
2214 trailing_comments: Vec::new(),
2215 double_colon_syntax: false,
2216 format: None,
2217 default: None,
2218 inferred_type: None,
2219 }))],
2220 ))))
2221 }
2222
2223 "LOGICAL_AND" if f.args.len() == 1 => {
2225 let arg = f.args.into_iter().next().unwrap();
2226 Ok(Expression::Function(Box::new(Function::new(
2227 "BOOL_AND".to_string(),
2228 vec![Expression::Cast(Box::new(crate::expressions::Cast {
2229 this: arg,
2230 to: crate::expressions::DataType::Boolean,
2231 trailing_comments: Vec::new(),
2232 double_colon_syntax: false,
2233 format: None,
2234 default: None,
2235 inferred_type: None,
2236 }))],
2237 ))))
2238 }
2239
2240 "REGEXP_LIKE" => Ok(Expression::Function(Box::new(Function::new(
2242 "REGEXP_MATCHES".to_string(),
2243 f.args,
2244 )))),
2245
2246 "POSITION" => Ok(Expression::Function(Box::new(f))),
2248
2249 "CHARINDEX" if f.args.len() == 2 => {
2251 let mut args = f.args;
2252 let substr = args.remove(0);
2253 let str_expr = args.remove(0);
2254 Ok(Expression::Function(Box::new(Function::new(
2255 "STRPOS".to_string(),
2256 vec![str_expr, substr],
2257 ))))
2258 }
2259
2260 "CHARINDEX" if f.args.len() == 3 => {
2266 let mut args = f.args;
2267 let substr = args.remove(0);
2268 let str_expr = args.remove(0);
2269 let pos = args.remove(0);
2270
2271 let zero = Expression::Literal(Box::new(Literal::Number("0".to_string())));
2272 let one = Expression::Literal(Box::new(Literal::Number("1".to_string())));
2273
2274 let pos_case = Expression::Case(Box::new(Case {
2276 operand: None,
2277 whens: vec![(
2278 Expression::Lte(Box::new(BinaryOp::new(pos.clone(), zero.clone()))),
2279 one.clone(),
2280 )],
2281 else_: Some(pos.clone()),
2282 comments: Vec::new(),
2283 inferred_type: None,
2284 }));
2285
2286 let substring_expr = Expression::Substring(Box::new(SubstringFunc {
2288 this: str_expr,
2289 start: pos_case.clone(),
2290 length: None,
2291 from_for_syntax: false,
2292 }));
2293
2294 let strpos = Expression::Function(Box::new(Function::new(
2296 "STRPOS".to_string(),
2297 vec![substring_expr, substr],
2298 )));
2299
2300 let eq_zero = Expression::Eq(Box::new(BinaryOp::new(strpos.clone(), zero.clone())));
2302
2303 let add_pos = Expression::Add(Box::new(BinaryOp::new(strpos, pos_case)));
2305 let sub_one = Expression::Sub(Box::new(BinaryOp::new(add_pos, one)));
2306
2307 Ok(Expression::Case(Box::new(Case {
2308 operand: None,
2309 whens: vec![(eq_zero, zero)],
2310 else_: Some(sub_one),
2311 comments: Vec::new(),
2312 inferred_type: None,
2313 })))
2314 }
2315
2316 "SPLIT" => Ok(Expression::Function(Box::new(Function::new(
2318 "STR_SPLIT".to_string(),
2319 f.args,
2320 )))),
2321
2322 "STRING_SPLIT" => Ok(Expression::Function(Box::new(Function::new(
2324 "STR_SPLIT".to_string(),
2325 f.args,
2326 )))),
2327
2328 "STRTOK_TO_ARRAY" => Ok(Expression::Function(Box::new(Function::new(
2330 "STR_SPLIT".to_string(),
2331 f.args,
2332 )))),
2333
2334 "REGEXP_SPLIT" => Ok(Expression::Function(Box::new(Function::new(
2336 "STR_SPLIT_REGEX".to_string(),
2337 f.args,
2338 )))),
2339
2340 "EDITDIST3" => Ok(Expression::Function(Box::new(Function::new(
2342 "LEVENSHTEIN".to_string(),
2343 f.args,
2344 )))),
2345
2346 "JSON_EXTRACT_PATH" if f.args.len() >= 2 => {
2348 let mut args = f.args;
2349 let this = args.remove(0);
2350 let path = args.remove(0);
2351 Ok(Expression::JsonExtract(Box::new(JsonExtractFunc {
2352 options: None,
2353 source_dialect: None,
2354
2355 this,
2356 path,
2357 returning: None,
2358 arrow_syntax: true,
2359 hash_arrow_syntax: false,
2360 wrapper_option: None,
2361 quotes_option: None,
2362 on_scalar_string: false,
2363 on_error: None,
2364 })))
2365 }
2366
2367 "JSON_EXTRACT_PATH_TEXT" if f.args.len() >= 2 => {
2369 let mut args = f.args;
2370 let this = args.remove(0);
2371 let path = args.remove(0);
2372 Ok(Expression::JsonExtractScalar(Box::new(JsonExtractFunc {
2373 options: None,
2374 source_dialect: None,
2375
2376 this,
2377 path,
2378 returning: None,
2379 arrow_syntax: true,
2380 hash_arrow_syntax: false,
2381 wrapper_option: None,
2382 quotes_option: None,
2383 on_scalar_string: false,
2384 on_error: None,
2385 })))
2386 }
2387
2388 "DATE_ADD" if f.args.len() == 2 => {
2390 let mut args = f.args;
2391 let date = args.remove(0);
2392 let interval = args.remove(0);
2393 Ok(Expression::Add(Box::new(BinaryOp {
2394 left: date,
2395 right: interval,
2396 left_comments: Vec::new(),
2397 operator_comments: Vec::new(),
2398 trailing_comments: Vec::new(),
2399 inferred_type: None,
2400 })))
2401 }
2402
2403 "DATE_SUB" if f.args.len() == 2 => {
2405 let mut args = f.args;
2406 let date = args.remove(0);
2407 let interval = args.remove(0);
2408 Ok(Expression::Sub(Box::new(BinaryOp {
2409 left: date,
2410 right: interval,
2411 left_comments: Vec::new(),
2412 operator_comments: Vec::new(),
2413 trailing_comments: Vec::new(),
2414 inferred_type: None,
2415 })))
2416 }
2417
2418 "RANGE" if f.args.len() == 1 => {
2420 let mut new_args = vec![Expression::number(0)];
2421 new_args.extend(f.args);
2422 Ok(Expression::Function(Box::new(Function::new(
2423 "RANGE".to_string(),
2424 new_args,
2425 ))))
2426 }
2427
2428 "GENERATE_SERIES" if f.args.len() == 1 => {
2430 let mut new_args = vec![Expression::number(0)];
2431 new_args.extend(f.args);
2432 Ok(Expression::Function(Box::new(Function::new(
2433 "GENERATE_SERIES".to_string(),
2434 new_args,
2435 ))))
2436 }
2437
2438 "REGEXP_EXTRACT" if f.args.len() == 3 => {
2441 let drop_group = match &f.args[2] {
2443 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
2444 let Literal::Number(n) = lit.as_ref() else {
2445 unreachable!()
2446 };
2447 n == "0"
2448 }
2449 _ => false,
2450 };
2451 if drop_group {
2452 Ok(Expression::Function(Box::new(Function::new(
2453 "REGEXP_EXTRACT".to_string(),
2454 vec![f.args[0].clone(), f.args[1].clone()],
2455 ))))
2456 } else {
2457 Ok(Expression::Function(Box::new(f)))
2458 }
2459 }
2460
2461 "STRUCT_PACK" => {
2463 let mut fields = Vec::new();
2464 for arg in f.args {
2465 match arg {
2466 Expression::NamedArgument(na) => {
2467 fields.push((Some(na.name.name.clone()), na.value));
2468 }
2469 other => {
2471 fields.push((None, other));
2472 }
2473 }
2474 }
2475 Ok(Expression::Struct(Box::new(Struct { fields })))
2476 }
2477
2478 "REPLACE" if f.args.len() == 2 => {
2480 let mut args = f.args;
2481 args.push(Expression::Literal(Box::new(
2482 Literal::String(String::new()),
2483 )));
2484 Ok(Expression::Function(Box::new(Function::new(
2485 "REPLACE".to_string(),
2486 args,
2487 ))))
2488 }
2489
2490 "TO_UNIXTIME" => Ok(Expression::Function(Box::new(Function::new(
2492 "EPOCH".to_string(),
2493 f.args,
2494 )))),
2495
2496 "FROM_ISO8601_TIMESTAMP" if f.args.len() == 1 => {
2498 use crate::expressions::{Cast, DataType};
2499 Ok(Expression::Cast(Box::new(Cast {
2500 this: f.args.into_iter().next().unwrap(),
2501 to: DataType::Timestamp {
2502 precision: None,
2503 timezone: true,
2504 },
2505 trailing_comments: Vec::new(),
2506 double_colon_syntax: false,
2507 format: None,
2508 default: None,
2509 inferred_type: None,
2510 })))
2511 }
2512
2513 "APPROX_DISTINCT" => {
2515 let args = if f.args.len() > 1 {
2517 vec![f.args.into_iter().next().unwrap()]
2518 } else {
2519 f.args
2520 };
2521 Ok(Expression::Function(Box::new(Function::new(
2522 "APPROX_COUNT_DISTINCT".to_string(),
2523 args,
2524 ))))
2525 }
2526
2527 "ARRAY_SORT" => {
2529 let args = vec![f.args.into_iter().next().unwrap()];
2530 Ok(Expression::Function(Box::new(Function::new(
2531 "ARRAY_SORT".to_string(),
2532 args,
2533 ))))
2534 }
2535
2536 "TO_UTF8" => Ok(Expression::Function(Box::new(Function::new(
2538 "ENCODE".to_string(),
2539 f.args,
2540 )))),
2541
2542 "FROM_UTF8" => Ok(Expression::Function(Box::new(Function::new(
2544 "DECODE".to_string(),
2545 f.args,
2546 )))),
2547
2548 "ARBITRARY" => Ok(Expression::Function(Box::new(Function::new(
2550 "ANY_VALUE".to_string(),
2551 f.args,
2552 )))),
2553
2554 "MAX_BY" => Ok(Expression::Function(Box::new(Function::new(
2556 "ARG_MAX".to_string(),
2557 f.args,
2558 )))),
2559
2560 "MIN_BY" => Ok(Expression::Function(Box::new(Function::new(
2562 "ARG_MIN".to_string(),
2563 f.args,
2564 )))),
2565
2566 "IFF" if f.args.len() == 3 => {
2568 let mut args = f.args;
2569 let cond = args.remove(0);
2570 let true_val = args.remove(0);
2571 let false_val = args.remove(0);
2572 Ok(Expression::Case(Box::new(Case {
2573 operand: None,
2574 whens: vec![(cond, true_val)],
2575 else_: Some(false_val),
2576 comments: Vec::new(),
2577 inferred_type: None,
2578 })))
2579 }
2580 "SKEW" => Ok(Expression::Function(Box::new(Function::new(
2581 "SKEWNESS".to_string(),
2582 f.args,
2583 )))),
2584 "VAR_SAMP" => Ok(Expression::Function(Box::new(Function::new(
2585 "VARIANCE".to_string(),
2586 f.args,
2587 )))),
2588 "VARIANCE_POP" => Ok(Expression::Function(Box::new(Function::new(
2589 "VAR_POP".to_string(),
2590 f.args,
2591 )))),
2592 "REGR_VALX" if f.args.len() == 2 => {
2593 let mut args = f.args;
2594 let y = args.remove(0);
2595 let x = args.remove(0);
2596 Ok(Expression::Case(Box::new(Case {
2597 operand: None,
2598 whens: vec![(
2599 Expression::IsNull(Box::new(crate::expressions::IsNull {
2600 this: y,
2601 not: false,
2602 postfix_form: false,
2603 })),
2604 Expression::Cast(Box::new(Cast {
2605 this: Expression::Null(crate::expressions::Null),
2606 to: DataType::Double {
2607 precision: None,
2608 scale: None,
2609 },
2610 trailing_comments: Vec::new(),
2611 double_colon_syntax: false,
2612 format: None,
2613 default: None,
2614 inferred_type: None,
2615 })),
2616 )],
2617 else_: Some(x),
2618 comments: Vec::new(),
2619 inferred_type: None,
2620 })))
2621 }
2622 "REGR_VALY" if f.args.len() == 2 => {
2623 let mut args = f.args;
2624 let y = args.remove(0);
2625 let x = args.remove(0);
2626 Ok(Expression::Case(Box::new(Case {
2627 operand: None,
2628 whens: vec![(
2629 Expression::IsNull(Box::new(crate::expressions::IsNull {
2630 this: x,
2631 not: false,
2632 postfix_form: false,
2633 })),
2634 Expression::Cast(Box::new(Cast {
2635 this: Expression::Null(crate::expressions::Null),
2636 to: DataType::Double {
2637 precision: None,
2638 scale: None,
2639 },
2640 trailing_comments: Vec::new(),
2641 double_colon_syntax: false,
2642 format: None,
2643 default: None,
2644 inferred_type: None,
2645 })),
2646 )],
2647 else_: Some(y),
2648 comments: Vec::new(),
2649 inferred_type: None,
2650 })))
2651 }
2652 "BOOLNOT" if f.args.len() == 1 => {
2653 let arg = f.args.into_iter().next().unwrap();
2654 let rounded = Expression::Function(Box::new(Function::new(
2656 "ROUND".to_string(),
2657 vec![arg, Expression::number(0)],
2658 )));
2659 Ok(Expression::Not(Box::new(crate::expressions::UnaryOp {
2660 this: Expression::Paren(Box::new(Paren {
2661 this: rounded,
2662 trailing_comments: Vec::new(),
2663 })),
2664 inferred_type: None,
2665 })))
2666 }
2667 "BITMAP_BIT_POSITION" if f.args.len() == 1 => {
2668 let n = f.args.into_iter().next().unwrap();
2669 let case_expr = Expression::Case(Box::new(Case {
2670 operand: None,
2671 whens: vec![(
2672 Expression::Gt(Box::new(BinaryOp {
2673 left: n.clone(),
2674 right: Expression::number(0),
2675 left_comments: Vec::new(),
2676 operator_comments: Vec::new(),
2677 trailing_comments: Vec::new(),
2678 inferred_type: None,
2679 })),
2680 Expression::Sub(Box::new(BinaryOp {
2681 left: n.clone(),
2682 right: Expression::number(1),
2683 left_comments: Vec::new(),
2684 operator_comments: Vec::new(),
2685 trailing_comments: Vec::new(),
2686 inferred_type: None,
2687 })),
2688 )],
2689 else_: Some(Expression::Abs(Box::new(UnaryFunc {
2690 this: n,
2691 original_name: None,
2692 inferred_type: None,
2693 }))),
2694 comments: Vec::new(),
2695 inferred_type: None,
2696 }));
2697 Ok(Expression::Mod(Box::new(BinaryOp {
2698 left: Expression::Paren(Box::new(Paren {
2699 this: case_expr,
2700 trailing_comments: Vec::new(),
2701 })),
2702 right: Expression::number(32768),
2703 left_comments: Vec::new(),
2704 operator_comments: Vec::new(),
2705 trailing_comments: Vec::new(),
2706 inferred_type: None,
2707 })))
2708 }
2709 "GREATEST" | "LEAST" => Ok(Expression::Function(Box::new(f))),
2711 "GREATEST_IGNORE_NULLS" => Ok(Expression::Greatest(Box::new(VarArgFunc {
2712 expressions: f.args,
2713 original_name: None,
2714 inferred_type: None,
2715 }))),
2716 "LEAST_IGNORE_NULLS" => Ok(Expression::Least(Box::new(VarArgFunc {
2717 expressions: f.args,
2718 original_name: None,
2719 inferred_type: None,
2720 }))),
2721 "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
2722 "JSON".to_string(),
2723 f.args,
2724 )))),
2725 "TRY_PARSE_JSON" if f.args.len() == 1 => {
2727 let x = f.args.into_iter().next().unwrap();
2728 let json_valid = Expression::Function(Box::new(Function::new(
2729 "JSON_VALID".to_string(),
2730 vec![x.clone()],
2731 )));
2732 let cast_json = Expression::Cast(Box::new(crate::expressions::Cast {
2733 this: x,
2734 to: DataType::Json,
2735 double_colon_syntax: false,
2736 trailing_comments: Vec::new(),
2737 format: None,
2738 default: None,
2739 inferred_type: None,
2740 }));
2741 Ok(Expression::Case(Box::new(crate::expressions::Case {
2742 operand: None,
2743 whens: vec![(json_valid, cast_json)],
2744 else_: Some(Expression::Null(crate::expressions::Null)),
2745 comments: Vec::new(),
2746 inferred_type: None,
2747 })))
2748 }
2749 "OBJECT_CONSTRUCT_KEEP_NULL" => {
2750 Ok(Expression::Function(Box::new(Function::new(
2752 "JSON_OBJECT".to_string(),
2753 f.args,
2754 ))))
2755 }
2756 "OBJECT_CONSTRUCT" => {
2757 let args = f.args;
2759 if args.is_empty() {
2760 Ok(Expression::Function(Box::new(Function::new(
2762 "STRUCT_PACK".to_string(),
2763 vec![],
2764 ))))
2765 } else {
2766 let mut fields = Vec::new();
2768 let mut i = 0;
2769 while i + 1 < args.len() {
2770 let key = &args[i];
2771 let value = args[i + 1].clone();
2772 let key_name = match key {
2773 Expression::Literal(lit)
2774 if matches!(lit.as_ref(), Literal::String(_)) =>
2775 {
2776 let Literal::String(s) = lit.as_ref() else {
2777 unreachable!()
2778 };
2779 Some(s.clone())
2780 }
2781 _ => None,
2782 };
2783 fields.push((key_name, value));
2784 i += 2;
2785 }
2786 Ok(Expression::Struct(Box::new(Struct { fields })))
2787 }
2788 }
2789 "IS_NULL_VALUE" if f.args.len() == 1 => {
2790 let arg = f.args.into_iter().next().unwrap();
2791 Ok(Expression::Eq(Box::new(BinaryOp {
2792 left: Expression::Function(Box::new(Function::new(
2793 "JSON_TYPE".to_string(),
2794 vec![arg],
2795 ))),
2796 right: Expression::Literal(Box::new(Literal::String("NULL".to_string()))),
2797 left_comments: Vec::new(),
2798 operator_comments: Vec::new(),
2799 trailing_comments: Vec::new(),
2800 inferred_type: None,
2801 })))
2802 }
2803 "TRY_TO_DOUBLE" | "TRY_TO_NUMBER" | "TRY_TO_NUMERIC" | "TRY_TO_DECIMAL"
2804 if f.args.len() == 1 =>
2805 {
2806 let arg = f.args.into_iter().next().unwrap();
2807 Ok(Expression::TryCast(Box::new(Cast {
2808 this: arg,
2809 to: DataType::Double {
2810 precision: None,
2811 scale: None,
2812 },
2813 trailing_comments: Vec::new(),
2814 double_colon_syntax: false,
2815 format: None,
2816 default: None,
2817 inferred_type: None,
2818 })))
2819 }
2820 "TRY_TO_TIME" if f.args.len() == 1 => {
2821 let arg = f.args.into_iter().next().unwrap();
2822 Ok(Expression::TryCast(Box::new(Cast {
2823 this: arg,
2824 to: DataType::Time {
2825 precision: None,
2826 timezone: false,
2827 },
2828 trailing_comments: Vec::new(),
2829 double_colon_syntax: false,
2830 format: None,
2831 default: None,
2832 inferred_type: None,
2833 })))
2834 }
2835 "TRY_TO_TIME" if f.args.len() == 2 => {
2836 let mut args = f.args;
2837 let value = args.remove(0);
2838 let fmt = self.convert_snowflake_time_format(args.remove(0));
2839 Ok(Expression::TryCast(Box::new(Cast {
2840 this: Expression::Function(Box::new(Function::new(
2841 "TRY_STRPTIME".to_string(),
2842 vec![value, fmt],
2843 ))),
2844 to: DataType::Time {
2845 precision: None,
2846 timezone: false,
2847 },
2848 trailing_comments: Vec::new(),
2849 double_colon_syntax: false,
2850 format: None,
2851 default: None,
2852 inferred_type: None,
2853 })))
2854 }
2855 "TRY_TO_TIMESTAMP" if f.args.len() == 1 => {
2856 let arg = f.args.into_iter().next().unwrap();
2857 Ok(Expression::TryCast(Box::new(Cast {
2858 this: arg,
2859 to: DataType::Timestamp {
2860 precision: None,
2861 timezone: false,
2862 },
2863 trailing_comments: Vec::new(),
2864 double_colon_syntax: false,
2865 format: None,
2866 default: None,
2867 inferred_type: None,
2868 })))
2869 }
2870 "TRY_TO_TIMESTAMP" if f.args.len() == 2 => {
2871 let mut args = f.args;
2872 let value = args.remove(0);
2873 let fmt = self.convert_snowflake_time_format(args.remove(0));
2874 Ok(Expression::Cast(Box::new(Cast {
2875 this: Expression::Function(Box::new(Function::new(
2876 "TRY_STRPTIME".to_string(),
2877 vec![value, fmt],
2878 ))),
2879 to: DataType::Timestamp {
2880 precision: None,
2881 timezone: false,
2882 },
2883 trailing_comments: Vec::new(),
2884 double_colon_syntax: false,
2885 format: None,
2886 default: None,
2887 inferred_type: None,
2888 })))
2889 }
2890 "TRY_TO_DATE" if f.args.len() == 1 => {
2891 let arg = f.args.into_iter().next().unwrap();
2892 Ok(Expression::TryCast(Box::new(Cast {
2893 this: arg,
2894 to: DataType::Date,
2895 trailing_comments: Vec::new(),
2896 double_colon_syntax: false,
2897 format: None,
2898 default: None,
2899 inferred_type: None,
2900 })))
2901 }
2902 "DAYOFWEEKISO" | "DAYOFWEEK_ISO" => Ok(Expression::Function(Box::new(Function::new(
2903 "ISODOW".to_string(),
2904 f.args,
2905 )))),
2906 "YEAROFWEEK" | "YEAROFWEEKISO" if f.args.len() == 1 => {
2907 let arg = f.args.into_iter().next().unwrap();
2908 Ok(Expression::Extract(Box::new(
2909 crate::expressions::ExtractFunc {
2910 this: arg,
2911 field: crate::expressions::DateTimeField::Custom("ISOYEAR".to_string()),
2912 },
2913 )))
2914 }
2915 "WEEKISO" => Ok(Expression::Function(Box::new(Function::new(
2916 "WEEKOFYEAR".to_string(),
2917 f.args,
2918 )))),
2919 "TIME_FROM_PARTS" | "TIMEFROMPARTS" if f.args.len() == 3 => {
2920 let args_ref = &f.args;
2921 let all_in_range = if let (Some(h_val), Some(m_val), Some(s_val)) = (
2923 Self::extract_number_value(&args_ref[0]),
2924 Self::extract_number_value(&args_ref[1]),
2925 Self::extract_number_value(&args_ref[2]),
2926 ) {
2927 h_val >= 0.0
2928 && h_val < 24.0
2929 && m_val >= 0.0
2930 && m_val < 60.0
2931 && s_val >= 0.0
2932 && s_val < 60.0
2933 } else {
2934 false
2935 };
2936 if all_in_range {
2937 Ok(Expression::Function(Box::new(Function::new(
2939 "MAKE_TIME".to_string(),
2940 f.args,
2941 ))))
2942 } else {
2943 let mut args = f.args;
2946 let h = args.remove(0);
2947 let m = args.remove(0);
2948 let s = args.remove(0);
2949 let seconds_expr = Expression::Add(Box::new(BinaryOp {
2950 left: Expression::Add(Box::new(BinaryOp {
2951 left: Expression::Paren(Box::new(Paren {
2952 this: Expression::Mul(Box::new(BinaryOp {
2953 left: h,
2954 right: Expression::number(3600),
2955 left_comments: Vec::new(),
2956 operator_comments: Vec::new(),
2957 trailing_comments: Vec::new(),
2958 inferred_type: None,
2959 })),
2960 trailing_comments: Vec::new(),
2961 })),
2962 right: Expression::Paren(Box::new(Paren {
2963 this: Expression::Mul(Box::new(BinaryOp {
2964 left: m,
2965 right: Expression::number(60),
2966 left_comments: Vec::new(),
2967 operator_comments: Vec::new(),
2968 trailing_comments: Vec::new(),
2969 inferred_type: None,
2970 })),
2971 trailing_comments: Vec::new(),
2972 })),
2973 left_comments: Vec::new(),
2974 operator_comments: Vec::new(),
2975 trailing_comments: Vec::new(),
2976 inferred_type: None,
2977 })),
2978 right: s,
2979 left_comments: Vec::new(),
2980 operator_comments: Vec::new(),
2981 trailing_comments: Vec::new(),
2982 inferred_type: None,
2983 }));
2984 let base_time = Expression::Cast(Box::new(Cast {
2985 this: Expression::Literal(Box::new(Literal::String(
2986 "00:00:00".to_string(),
2987 ))),
2988 to: DataType::Time {
2989 precision: None,
2990 timezone: false,
2991 },
2992 trailing_comments: Vec::new(),
2993 double_colon_syntax: false,
2994 format: None,
2995 default: None,
2996 inferred_type: None,
2997 }));
2998 Ok(Expression::Add(Box::new(BinaryOp {
2999 left: base_time,
3000 right: Expression::Interval(Box::new(Interval {
3001 this: Some(Expression::Paren(Box::new(crate::expressions::Paren {
3002 this: seconds_expr,
3003 trailing_comments: Vec::new(),
3004 }))),
3005 unit: Some(IntervalUnitSpec::Simple {
3006 unit: IntervalUnit::Second,
3007 use_plural: false,
3008 }),
3009 })),
3010 left_comments: Vec::new(),
3011 operator_comments: Vec::new(),
3012 trailing_comments: Vec::new(),
3013 inferred_type: None,
3014 })))
3015 }
3016 }
3017 "TIME_FROM_PARTS" | "TIMEFROMPARTS" if f.args.len() == 4 => {
3018 let mut args = f.args;
3019 let h = args.remove(0);
3020 let m = args.remove(0);
3021 let s = args.remove(0);
3022 let ns = args.remove(0);
3023 let seconds_expr = Expression::Add(Box::new(BinaryOp {
3024 left: Expression::Add(Box::new(BinaryOp {
3025 left: Expression::Add(Box::new(BinaryOp {
3026 left: Expression::Paren(Box::new(Paren {
3027 this: Expression::Mul(Box::new(BinaryOp {
3028 left: h,
3029 right: Expression::number(3600),
3030 left_comments: Vec::new(),
3031 operator_comments: Vec::new(),
3032 trailing_comments: Vec::new(),
3033 inferred_type: None,
3034 })),
3035 trailing_comments: Vec::new(),
3036 })),
3037 right: Expression::Paren(Box::new(Paren {
3038 this: Expression::Mul(Box::new(BinaryOp {
3039 left: m,
3040 right: Expression::number(60),
3041 left_comments: Vec::new(),
3042 operator_comments: Vec::new(),
3043 trailing_comments: Vec::new(),
3044 inferred_type: None,
3045 })),
3046 trailing_comments: Vec::new(),
3047 })),
3048 left_comments: Vec::new(),
3049 operator_comments: Vec::new(),
3050 trailing_comments: Vec::new(),
3051 inferred_type: None,
3052 })),
3053 right: s,
3054 left_comments: Vec::new(),
3055 operator_comments: Vec::new(),
3056 trailing_comments: Vec::new(),
3057 inferred_type: None,
3058 })),
3059 right: Expression::Paren(Box::new(Paren {
3060 this: Expression::Div(Box::new(BinaryOp {
3061 left: ns,
3062 right: Expression::Literal(Box::new(Literal::Number(
3063 "1000000000.0".to_string(),
3064 ))),
3065 left_comments: Vec::new(),
3066 operator_comments: Vec::new(),
3067 trailing_comments: Vec::new(),
3068 inferred_type: None,
3069 })),
3070 trailing_comments: Vec::new(),
3071 })),
3072 left_comments: Vec::new(),
3073 operator_comments: Vec::new(),
3074 trailing_comments: Vec::new(),
3075 inferred_type: None,
3076 }));
3077 let base_time = Expression::Cast(Box::new(Cast {
3078 this: Expression::Literal(Box::new(Literal::String("00:00:00".to_string()))),
3079 to: DataType::Time {
3080 precision: None,
3081 timezone: false,
3082 },
3083 trailing_comments: Vec::new(),
3084 double_colon_syntax: false,
3085 format: None,
3086 default: None,
3087 inferred_type: None,
3088 }));
3089 Ok(Expression::Add(Box::new(BinaryOp {
3090 left: base_time,
3091 right: Expression::Interval(Box::new(Interval {
3092 this: Some(Expression::Paren(Box::new(crate::expressions::Paren {
3093 this: seconds_expr,
3094 trailing_comments: Vec::new(),
3095 }))),
3096 unit: Some(IntervalUnitSpec::Simple {
3097 unit: IntervalUnit::Second,
3098 use_plural: false,
3099 }),
3100 })),
3101 left_comments: Vec::new(),
3102 operator_comments: Vec::new(),
3103 trailing_comments: Vec::new(),
3104 inferred_type: None,
3105 })))
3106 }
3107 "TIMESTAMP_FROM_PARTS" | "TIMESTAMPFROMPARTS" if f.args.len() == 6 => {
3108 Ok(Expression::Function(Box::new(Function::new(
3109 "MAKE_TIMESTAMP".to_string(),
3110 f.args,
3111 ))))
3112 }
3113 "TIMESTAMP_FROM_PARTS" | "TIMESTAMPFROMPARTS" | "TIMESTAMP_NTZ_FROM_PARTS"
3114 if f.args.len() == 2 =>
3115 {
3116 let mut args = f.args;
3117 let d = args.remove(0);
3118 let t = args.remove(0);
3119 Ok(Expression::Add(Box::new(BinaryOp {
3120 left: d,
3121 right: t,
3122 left_comments: Vec::new(),
3123 operator_comments: Vec::new(),
3124 trailing_comments: Vec::new(),
3125 inferred_type: None,
3126 })))
3127 }
3128 "TIMESTAMP_LTZ_FROM_PARTS" if f.args.len() == 6 => {
3129 Ok(Expression::Cast(Box::new(Cast {
3130 this: Expression::Function(Box::new(Function::new(
3131 "MAKE_TIMESTAMP".to_string(),
3132 f.args,
3133 ))),
3134 to: DataType::Timestamp {
3135 precision: None,
3136 timezone: true,
3137 },
3138 trailing_comments: Vec::new(),
3139 double_colon_syntax: false,
3140 format: None,
3141 default: None,
3142 inferred_type: None,
3143 })))
3144 }
3145 "TIMESTAMP_TZ_FROM_PARTS" if f.args.len() == 8 => {
3146 let mut args = f.args;
3147 let ts_args = vec![
3148 args.remove(0),
3149 args.remove(0),
3150 args.remove(0),
3151 args.remove(0),
3152 args.remove(0),
3153 args.remove(0),
3154 ];
3155 let _nano = args.remove(0);
3156 let tz = args.remove(0);
3157 Ok(Expression::AtTimeZone(Box::new(
3158 crate::expressions::AtTimeZone {
3159 this: Expression::Function(Box::new(Function::new(
3160 "MAKE_TIMESTAMP".to_string(),
3161 ts_args,
3162 ))),
3163 zone: tz,
3164 },
3165 )))
3166 }
3167 "BOOLAND_AGG" if f.args.len() == 1 => {
3168 let arg = f.args.into_iter().next().unwrap();
3169 Ok(Expression::Function(Box::new(Function::new(
3170 "BOOL_AND".to_string(),
3171 vec![Expression::Cast(Box::new(Cast {
3172 this: arg,
3173 to: DataType::Boolean,
3174 trailing_comments: Vec::new(),
3175 double_colon_syntax: false,
3176 format: None,
3177 default: None,
3178 inferred_type: None,
3179 }))],
3180 ))))
3181 }
3182 "BOOLOR_AGG" if f.args.len() == 1 => {
3183 let arg = f.args.into_iter().next().unwrap();
3184 Ok(Expression::Function(Box::new(Function::new(
3185 "BOOL_OR".to_string(),
3186 vec![Expression::Cast(Box::new(Cast {
3187 this: arg,
3188 to: DataType::Boolean,
3189 trailing_comments: Vec::new(),
3190 double_colon_syntax: false,
3191 format: None,
3192 default: None,
3193 inferred_type: None,
3194 }))],
3195 ))))
3196 }
3197 "NVL2" if f.args.len() == 3 => {
3198 let mut args = f.args;
3199 let a = args.remove(0);
3200 let b = args.remove(0);
3201 let c = args.remove(0);
3202 Ok(Expression::Case(Box::new(Case {
3203 operand: None,
3204 whens: vec![(
3205 Expression::Not(Box::new(crate::expressions::UnaryOp {
3206 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3207 this: a,
3208 not: false,
3209 postfix_form: false,
3210 })),
3211 inferred_type: None,
3212 })),
3213 b,
3214 )],
3215 else_: Some(c),
3216 comments: Vec::new(),
3217 inferred_type: None,
3218 })))
3219 }
3220 "EQUAL_NULL" if f.args.len() == 2 => {
3221 let mut args = f.args;
3222 let a = args.remove(0);
3223 let b = args.remove(0);
3224 Ok(Expression::NullSafeEq(Box::new(BinaryOp {
3225 left: a,
3226 right: b,
3227 left_comments: Vec::new(),
3228 operator_comments: Vec::new(),
3229 trailing_comments: Vec::new(),
3230 inferred_type: None,
3231 })))
3232 }
3233 "EDITDISTANCE" if f.args.len() == 3 => {
3234 let mut args = f.args;
3236 let a = args.remove(0);
3237 let b = args.remove(0);
3238 let max_dist = args.remove(0);
3239 let lev = Expression::Function(Box::new(Function::new(
3240 "LEVENSHTEIN".to_string(),
3241 vec![a, b],
3242 )));
3243 let lev_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
3244 this: lev.clone(),
3245 not: false,
3246 postfix_form: false,
3247 }));
3248 let max_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
3249 this: max_dist.clone(),
3250 not: false,
3251 postfix_form: false,
3252 }));
3253 let null_check = Expression::Or(Box::new(BinaryOp {
3254 left: lev_is_null,
3255 right: max_is_null,
3256 left_comments: Vec::new(),
3257 operator_comments: Vec::new(),
3258 trailing_comments: Vec::new(),
3259 inferred_type: None,
3260 }));
3261 let least = Expression::Least(Box::new(VarArgFunc {
3262 expressions: vec![lev, max_dist],
3263 original_name: None,
3264 inferred_type: None,
3265 }));
3266 Ok(Expression::Case(Box::new(Case {
3267 operand: None,
3268 whens: vec![(null_check, Expression::Null(crate::expressions::Null))],
3269 else_: Some(least),
3270 comments: Vec::new(),
3271 inferred_type: None,
3272 })))
3273 }
3274 "EDITDISTANCE" => Ok(Expression::Function(Box::new(Function::new(
3275 "LEVENSHTEIN".to_string(),
3276 f.args,
3277 )))),
3278 "BITAND" if f.args.len() == 2 => {
3279 let mut args = f.args;
3280 let left = args.remove(0);
3281 let right = args.remove(0);
3282 let wrap = |e: Expression| -> Expression {
3284 match &e {
3285 Expression::BitwiseLeftShift(_) | Expression::BitwiseRightShift(_) => {
3286 Expression::Paren(Box::new(Paren {
3287 this: e,
3288 trailing_comments: Vec::new(),
3289 }))
3290 }
3291 _ => e,
3292 }
3293 };
3294 Ok(Expression::BitwiseAnd(Box::new(BinaryOp {
3295 left: wrap(left),
3296 right: wrap(right),
3297 left_comments: Vec::new(),
3298 operator_comments: Vec::new(),
3299 trailing_comments: Vec::new(),
3300 inferred_type: None,
3301 })))
3302 }
3303 "BITOR" if f.args.len() == 2 => {
3304 let mut args = f.args;
3305 let left = args.remove(0);
3306 let right = args.remove(0);
3307 let wrap = |e: Expression| -> Expression {
3309 match &e {
3310 Expression::BitwiseLeftShift(_) | Expression::BitwiseRightShift(_) => {
3311 Expression::Paren(Box::new(Paren {
3312 this: e,
3313 trailing_comments: Vec::new(),
3314 }))
3315 }
3316 _ => e,
3317 }
3318 };
3319 Ok(Expression::BitwiseOr(Box::new(BinaryOp {
3320 left: wrap(left),
3321 right: wrap(right),
3322 left_comments: Vec::new(),
3323 operator_comments: Vec::new(),
3324 trailing_comments: Vec::new(),
3325 inferred_type: None,
3326 })))
3327 }
3328 "BITXOR" if f.args.len() == 2 => {
3329 let mut args = f.args;
3330 Ok(Expression::BitwiseXor(Box::new(BinaryOp {
3331 left: args.remove(0),
3332 right: args.remove(0),
3333 left_comments: Vec::new(),
3334 operator_comments: Vec::new(),
3335 trailing_comments: Vec::new(),
3336 inferred_type: None,
3337 })))
3338 }
3339 "BITNOT" if f.args.len() == 1 => {
3340 let arg = f.args.into_iter().next().unwrap();
3341 Ok(Expression::BitwiseNot(Box::new(
3342 crate::expressions::UnaryOp {
3343 this: Expression::Paren(Box::new(Paren {
3344 this: arg,
3345 trailing_comments: Vec::new(),
3346 })),
3347 inferred_type: None,
3348 },
3349 )))
3350 }
3351 "BITSHIFTLEFT" if f.args.len() == 2 => {
3352 let mut args = f.args;
3353 let a = args.remove(0);
3354 let b = args.remove(0);
3355 let is_binary = if let Expression::Cast(ref c) = a {
3357 matches!(
3358 &c.to,
3359 DataType::Binary { .. } | DataType::VarBinary { .. } | DataType::Blob
3360 ) || matches!(&c.to, DataType::Custom { name } if name == "BLOB")
3361 } else {
3362 false
3363 };
3364 if is_binary {
3365 let cast_to_bit = Expression::Cast(Box::new(Cast {
3367 this: a,
3368 to: DataType::Custom {
3369 name: "BIT".to_string(),
3370 },
3371 trailing_comments: Vec::new(),
3372 double_colon_syntax: false,
3373 format: None,
3374 default: None,
3375 inferred_type: None,
3376 }));
3377 let shift = Expression::BitwiseLeftShift(Box::new(BinaryOp {
3378 left: cast_to_bit,
3379 right: b,
3380 left_comments: Vec::new(),
3381 operator_comments: Vec::new(),
3382 trailing_comments: Vec::new(),
3383 inferred_type: None,
3384 }));
3385 Ok(Expression::Cast(Box::new(Cast {
3386 this: shift,
3387 to: DataType::Custom {
3388 name: "BLOB".to_string(),
3389 },
3390 trailing_comments: Vec::new(),
3391 double_colon_syntax: false,
3392 format: None,
3393 default: None,
3394 inferred_type: None,
3395 })))
3396 } else {
3397 Ok(Expression::BitwiseLeftShift(Box::new(BinaryOp {
3398 left: Expression::Cast(Box::new(Cast {
3399 this: a,
3400 to: DataType::Int128,
3401 trailing_comments: Vec::new(),
3402 double_colon_syntax: false,
3403 format: None,
3404 default: None,
3405 inferred_type: None,
3406 })),
3407 right: b,
3408 left_comments: Vec::new(),
3409 operator_comments: Vec::new(),
3410 trailing_comments: Vec::new(),
3411 inferred_type: None,
3412 })))
3413 }
3414 }
3415 "BITSHIFTRIGHT" if f.args.len() == 2 => {
3416 let mut args = f.args;
3417 let a = args.remove(0);
3418 let b = args.remove(0);
3419 let is_binary = if let Expression::Cast(ref c) = a {
3421 matches!(
3422 &c.to,
3423 DataType::Binary { .. } | DataType::VarBinary { .. } | DataType::Blob
3424 ) || matches!(&c.to, DataType::Custom { name } if name == "BLOB")
3425 } else {
3426 false
3427 };
3428 if is_binary {
3429 let cast_to_bit = Expression::Cast(Box::new(Cast {
3431 this: a,
3432 to: DataType::Custom {
3433 name: "BIT".to_string(),
3434 },
3435 trailing_comments: Vec::new(),
3436 double_colon_syntax: false,
3437 format: None,
3438 default: None,
3439 inferred_type: None,
3440 }));
3441 let shift = Expression::BitwiseRightShift(Box::new(BinaryOp {
3442 left: cast_to_bit,
3443 right: b,
3444 left_comments: Vec::new(),
3445 operator_comments: Vec::new(),
3446 trailing_comments: Vec::new(),
3447 inferred_type: None,
3448 }));
3449 Ok(Expression::Cast(Box::new(Cast {
3450 this: shift,
3451 to: DataType::Custom {
3452 name: "BLOB".to_string(),
3453 },
3454 trailing_comments: Vec::new(),
3455 double_colon_syntax: false,
3456 format: None,
3457 default: None,
3458 inferred_type: None,
3459 })))
3460 } else {
3461 Ok(Expression::BitwiseRightShift(Box::new(BinaryOp {
3462 left: Expression::Cast(Box::new(Cast {
3463 this: a,
3464 to: DataType::Int128,
3465 trailing_comments: Vec::new(),
3466 double_colon_syntax: false,
3467 format: None,
3468 default: None,
3469 inferred_type: None,
3470 })),
3471 right: b,
3472 left_comments: Vec::new(),
3473 operator_comments: Vec::new(),
3474 trailing_comments: Vec::new(),
3475 inferred_type: None,
3476 })))
3477 }
3478 }
3479 "SQUARE" if f.args.len() == 1 => {
3480 let arg = f.args.into_iter().next().unwrap();
3481 Ok(Expression::Function(Box::new(Function::new(
3482 "POWER".to_string(),
3483 vec![arg, Expression::number(2)],
3484 ))))
3485 }
3486 "LIST"
3487 if f.args.len() == 1 && !matches!(f.args.first(), Some(Expression::Select(_))) =>
3488 {
3489 Ok(Expression::Function(Box::new(Function::new(
3490 "ARRAY_AGG".to_string(),
3491 f.args,
3492 ))))
3493 }
3494 "UUID_STRING" => {
3495 if f.args.is_empty() {
3496 Ok(Expression::Function(Box::new(Function::new(
3497 "UUID".to_string(),
3498 vec![],
3499 ))))
3500 } else {
3501 Ok(Expression::Function(Box::new(Function::new(
3502 "UUID_STRING".to_string(),
3503 f.args,
3504 ))))
3505 }
3506 }
3507 "ENDSWITH" => Ok(Expression::Function(Box::new(Function::new(
3508 "ENDS_WITH".to_string(),
3509 f.args,
3510 )))),
3511 "REGEXP_REPLACE" if f.args.len() == 2 => {
3515 let mut args = f.args;
3517 args.push(Expression::Literal(Box::new(
3518 Literal::String(String::new()),
3519 )));
3520 Ok(Expression::Function(Box::new(Function::new(
3521 "REGEXP_REPLACE".to_string(),
3522 args,
3523 ))))
3524 }
3525 "DIV0" if f.args.len() == 2 => {
3526 let mut args = f.args;
3527 let a = args.remove(0);
3528 let b = args.remove(0);
3529 Ok(Expression::Case(Box::new(Case {
3530 operand: None,
3531 whens: vec![(
3532 Expression::And(Box::new(BinaryOp {
3533 left: Expression::Eq(Box::new(BinaryOp {
3534 left: b.clone(),
3535 right: Expression::number(0),
3536 left_comments: Vec::new(),
3537 operator_comments: Vec::new(),
3538 trailing_comments: Vec::new(),
3539 inferred_type: None,
3540 })),
3541 right: Expression::Not(Box::new(crate::expressions::UnaryOp {
3542 this: Expression::IsNull(Box::new(crate::expressions::IsNull {
3543 this: a.clone(),
3544 not: false,
3545 postfix_form: false,
3546 })),
3547 inferred_type: None,
3548 })),
3549 left_comments: Vec::new(),
3550 operator_comments: Vec::new(),
3551 trailing_comments: Vec::new(),
3552 inferred_type: None,
3553 })),
3554 Expression::number(0),
3555 )],
3556 else_: Some(Expression::Div(Box::new(BinaryOp {
3557 left: a,
3558 right: b,
3559 left_comments: Vec::new(),
3560 operator_comments: Vec::new(),
3561 trailing_comments: Vec::new(),
3562 inferred_type: None,
3563 }))),
3564 comments: Vec::new(),
3565 inferred_type: None,
3566 })))
3567 }
3568 "DIV0NULL" if f.args.len() == 2 => {
3569 let mut args = f.args;
3570 let a = args.remove(0);
3571 let b = args.remove(0);
3572 Ok(Expression::Case(Box::new(Case {
3573 operand: None,
3574 whens: vec![(
3575 Expression::Or(Box::new(BinaryOp {
3576 left: Expression::Eq(Box::new(BinaryOp {
3577 left: b.clone(),
3578 right: Expression::number(0),
3579 left_comments: Vec::new(),
3580 operator_comments: Vec::new(),
3581 trailing_comments: Vec::new(),
3582 inferred_type: None,
3583 })),
3584 right: Expression::IsNull(Box::new(crate::expressions::IsNull {
3585 this: b.clone(),
3586 not: false,
3587 postfix_form: false,
3588 })),
3589 left_comments: Vec::new(),
3590 operator_comments: Vec::new(),
3591 trailing_comments: Vec::new(),
3592 inferred_type: None,
3593 })),
3594 Expression::number(0),
3595 )],
3596 else_: Some(Expression::Div(Box::new(BinaryOp {
3597 left: a,
3598 right: b,
3599 left_comments: Vec::new(),
3600 operator_comments: Vec::new(),
3601 trailing_comments: Vec::new(),
3602 inferred_type: None,
3603 }))),
3604 comments: Vec::new(),
3605 inferred_type: None,
3606 })))
3607 }
3608 "ZEROIFNULL" if f.args.len() == 1 => {
3609 let x = f.args.into_iter().next().unwrap();
3610 Ok(Expression::Case(Box::new(Case {
3611 operand: None,
3612 whens: vec![(
3613 Expression::IsNull(Box::new(crate::expressions::IsNull {
3614 this: x.clone(),
3615 not: false,
3616 postfix_form: false,
3617 })),
3618 Expression::number(0),
3619 )],
3620 else_: Some(x),
3621 comments: Vec::new(),
3622 inferred_type: None,
3623 })))
3624 }
3625 "NULLIFZERO" if f.args.len() == 1 => {
3626 let x = f.args.into_iter().next().unwrap();
3627 Ok(Expression::Case(Box::new(Case {
3628 operand: None,
3629 whens: vec![(
3630 Expression::Eq(Box::new(BinaryOp {
3631 left: x.clone(),
3632 right: Expression::number(0),
3633 left_comments: Vec::new(),
3634 operator_comments: Vec::new(),
3635 trailing_comments: Vec::new(),
3636 inferred_type: None,
3637 })),
3638 Expression::Null(crate::expressions::Null),
3639 )],
3640 else_: Some(x),
3641 comments: Vec::new(),
3642 inferred_type: None,
3643 })))
3644 }
3645 "TO_DOUBLE" if f.args.len() == 1 => {
3646 let arg = f.args.into_iter().next().unwrap();
3647 Ok(Expression::Cast(Box::new(Cast {
3648 this: arg,
3649 to: DataType::Double {
3650 precision: None,
3651 scale: None,
3652 },
3653 trailing_comments: Vec::new(),
3654 double_colon_syntax: false,
3655 format: None,
3656 default: None,
3657 inferred_type: None,
3658 })))
3659 }
3660 "DATE" if f.args.len() == 1 => {
3661 let arg = f.args.into_iter().next().unwrap();
3662 Ok(Expression::Cast(Box::new(Cast {
3663 this: arg,
3664 to: DataType::Date,
3665 trailing_comments: Vec::new(),
3666 double_colon_syntax: false,
3667 format: None,
3668 default: None,
3669 inferred_type: None,
3670 })))
3671 }
3672 "DATE" if f.args.len() == 2 => {
3673 let mut args = f.args;
3674 let value = args.remove(0);
3675 let fmt = self.convert_snowflake_date_format(args.remove(0));
3676 Ok(Expression::Cast(Box::new(Cast {
3677 this: Expression::Function(Box::new(Function::new(
3678 "STRPTIME".to_string(),
3679 vec![value, fmt],
3680 ))),
3681 to: DataType::Date,
3682 trailing_comments: Vec::new(),
3683 double_colon_syntax: false,
3684 format: None,
3685 default: None,
3686 inferred_type: None,
3687 })))
3688 }
3689 "SYSDATE" => Ok(Expression::AtTimeZone(Box::new(
3690 crate::expressions::AtTimeZone {
3691 this: Expression::CurrentTimestamp(crate::expressions::CurrentTimestamp {
3692 precision: None,
3693 sysdate: false,
3694 }),
3695 zone: Expression::Literal(Box::new(Literal::String("UTC".to_string()))),
3696 },
3697 ))),
3698 "HEX_DECODE_BINARY" => Ok(Expression::Function(Box::new(Function::new(
3699 "UNHEX".to_string(),
3700 f.args,
3701 )))),
3702 "CONVERT_TIMEZONE" if f.args.len() == 3 => {
3703 let mut args = f.args;
3704 let src_tz = args.remove(0);
3705 let tgt_tz = args.remove(0);
3706 let ts = args.remove(0);
3707 let cast_ts = Expression::Cast(Box::new(Cast {
3708 this: ts,
3709 to: DataType::Timestamp {
3710 precision: None,
3711 timezone: false,
3712 },
3713 trailing_comments: Vec::new(),
3714 double_colon_syntax: false,
3715 format: None,
3716 default: None,
3717 inferred_type: None,
3718 }));
3719 Ok(Expression::AtTimeZone(Box::new(
3720 crate::expressions::AtTimeZone {
3721 this: Expression::AtTimeZone(Box::new(crate::expressions::AtTimeZone {
3722 this: cast_ts,
3723 zone: src_tz,
3724 })),
3725 zone: tgt_tz,
3726 },
3727 )))
3728 }
3729 "CONVERT_TIMEZONE" if f.args.len() == 2 => {
3730 let mut args = f.args;
3731 let tgt_tz = args.remove(0);
3732 let ts = args.remove(0);
3733 let cast_ts = Expression::Cast(Box::new(Cast {
3734 this: ts,
3735 to: DataType::Timestamp {
3736 precision: None,
3737 timezone: false,
3738 },
3739 trailing_comments: Vec::new(),
3740 double_colon_syntax: false,
3741 format: None,
3742 default: None,
3743 inferred_type: None,
3744 }));
3745 Ok(Expression::AtTimeZone(Box::new(
3746 crate::expressions::AtTimeZone {
3747 this: cast_ts,
3748 zone: tgt_tz,
3749 },
3750 )))
3751 }
3752 "DATE_PART" | "DATEPART" if f.args.len() == 2 => self.transform_date_part(f.args),
3753 "DATEADD" | "TIMEADD" if f.args.len() == 3 => self.transform_dateadd(f.args),
3754 "TIMESTAMPADD" if f.args.len() == 3 => self.transform_dateadd(f.args),
3755 "DATEDIFF" | "TIMEDIFF" if f.args.len() == 3 => self.transform_datediff(f.args),
3756 "TIMESTAMPDIFF" if f.args.len() == 3 => self.transform_datediff(f.args),
3757 "CORR" if f.args.len() == 2 => {
3758 Ok(Expression::Function(Box::new(f)))
3760 }
3761 "TO_TIMESTAMP" | "TO_TIMESTAMP_NTZ" if f.args.len() == 2 => {
3762 let mut args = f.args;
3763 let value = args.remove(0);
3764 let second_arg = args.remove(0);
3765 match &second_arg {
3766 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => Ok(
3767 Expression::AtTimeZone(Box::new(crate::expressions::AtTimeZone {
3768 this: Expression::Function(Box::new(Function::new(
3769 "TO_TIMESTAMP".to_string(),
3770 vec![Expression::Div(Box::new(BinaryOp {
3771 left: value,
3772 right: Expression::Function(Box::new(Function::new(
3773 "POWER".to_string(),
3774 vec![Expression::number(10), second_arg],
3775 ))),
3776 left_comments: Vec::new(),
3777 operator_comments: Vec::new(),
3778 trailing_comments: Vec::new(),
3779 inferred_type: None,
3780 }))],
3781 ))),
3782 zone: Expression::Literal(Box::new(Literal::String("UTC".to_string()))),
3783 })),
3784 ),
3785 _ => {
3786 let fmt = self.convert_snowflake_time_format(second_arg);
3787 Ok(Expression::Function(Box::new(Function::new(
3788 "STRPTIME".to_string(),
3789 vec![value, fmt],
3790 ))))
3791 }
3792 }
3793 }
3794 "TO_TIME" if f.args.len() == 1 => {
3795 let arg = f.args.into_iter().next().unwrap();
3796 Ok(Expression::Cast(Box::new(Cast {
3797 this: arg,
3798 to: DataType::Time {
3799 precision: None,
3800 timezone: false,
3801 },
3802 trailing_comments: Vec::new(),
3803 double_colon_syntax: false,
3804 format: None,
3805 default: None,
3806 inferred_type: None,
3807 })))
3808 }
3809 "TO_TIME" if f.args.len() == 2 => {
3810 let mut args = f.args;
3811 let value = args.remove(0);
3812 let fmt = self.convert_snowflake_time_format(args.remove(0));
3813 Ok(Expression::Cast(Box::new(Cast {
3814 this: Expression::Function(Box::new(Function::new(
3815 "STRPTIME".to_string(),
3816 vec![value, fmt],
3817 ))),
3818 to: DataType::Time {
3819 precision: None,
3820 timezone: false,
3821 },
3822 trailing_comments: Vec::new(),
3823 double_colon_syntax: false,
3824 format: None,
3825 default: None,
3826 inferred_type: None,
3827 })))
3828 }
3829 "TO_DATE" if f.args.len() == 2 => {
3830 let mut args = f.args;
3831 let value = args.remove(0);
3832 let fmt = self.convert_snowflake_date_format(args.remove(0));
3833 Ok(Expression::Cast(Box::new(Cast {
3834 this: Expression::Function(Box::new(Function::new(
3835 "STRPTIME".to_string(),
3836 vec![value, fmt],
3837 ))),
3838 to: DataType::Date,
3839 trailing_comments: Vec::new(),
3840 double_colon_syntax: false,
3841 format: None,
3842 default: None,
3843 inferred_type: None,
3844 })))
3845 }
3846 "SAFE_DIVIDE" if f.args.len() == 2 => {
3850 let mut args = f.args;
3851 let x = args.remove(0);
3852 let y = args.remove(0);
3853 Ok(Expression::Case(Box::new(Case {
3854 operand: None,
3855 whens: vec![(
3856 Expression::Neq(Box::new(BinaryOp {
3857 left: y.clone(),
3858 right: Expression::number(0),
3859 left_comments: Vec::new(),
3860 operator_comments: Vec::new(),
3861 trailing_comments: Vec::new(),
3862 inferred_type: None,
3863 })),
3864 Expression::Div(Box::new(BinaryOp {
3865 left: x,
3866 right: y,
3867 left_comments: Vec::new(),
3868 operator_comments: Vec::new(),
3869 trailing_comments: Vec::new(),
3870 inferred_type: None,
3871 })),
3872 )],
3873 else_: Some(Expression::Null(crate::expressions::Null)),
3874 comments: Vec::new(),
3875 inferred_type: None,
3876 })))
3877 }
3878
3879 "TO_HEX" if f.args.len() == 1 => {
3881 let arg = f.args.into_iter().next().unwrap();
3882 Ok(Expression::Lower(Box::new(UnaryFunc::new(
3883 Expression::Function(Box::new(Function::new("HEX".to_string(), vec![arg]))),
3884 ))))
3885 }
3886
3887 "EDIT_DISTANCE" if f.args.len() >= 2 => {
3889 let mut args = f.args;
3891 let a = args.remove(0);
3892 let b = args.remove(0);
3893 Ok(Expression::Function(Box::new(Function::new(
3894 "LEVENSHTEIN".to_string(),
3895 vec![a, b],
3896 ))))
3897 }
3898
3899 "UNIX_DATE" if f.args.len() == 1 => {
3901 let arg = f.args.into_iter().next().unwrap();
3902 Ok(Expression::Function(Box::new(Function::new(
3903 "DATE_DIFF".to_string(),
3904 vec![
3905 Expression::Literal(Box::new(Literal::String("DAY".to_string()))),
3906 Expression::Cast(Box::new(Cast {
3907 this: Expression::Literal(Box::new(Literal::String(
3908 "1970-01-01".to_string(),
3909 ))),
3910 to: DataType::Date,
3911 trailing_comments: Vec::new(),
3912 double_colon_syntax: false,
3913 format: None,
3914 default: None,
3915 inferred_type: None,
3916 })),
3917 arg,
3918 ],
3919 ))))
3920 }
3921
3922 "TIMESTAMP" if f.args.len() == 1 => {
3924 let arg = f.args.into_iter().next().unwrap();
3925 Ok(Expression::Cast(Box::new(Cast {
3926 this: arg,
3927 to: DataType::Custom {
3928 name: "TIMESTAMPTZ".to_string(),
3929 },
3930 trailing_comments: Vec::new(),
3931 double_colon_syntax: false,
3932 format: None,
3933 default: None,
3934 inferred_type: None,
3935 })))
3936 }
3937
3938 "TIME" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3940 "MAKE_TIME".to_string(),
3941 f.args,
3942 )))),
3943
3944 "DATE" if f.args.len() == 3 => Ok(Expression::Function(Box::new(Function::new(
3946 "MAKE_DATE".to_string(),
3947 f.args,
3948 )))),
3949
3950 "DATETIME" if f.args.len() == 6 => Ok(Expression::Function(Box::new(Function::new(
3952 "MAKE_TIMESTAMP".to_string(),
3953 f.args,
3954 )))),
3955
3956 "PARSE_TIMESTAMP" if f.args.len() >= 2 => {
3958 let mut args = f.args;
3959 let fmt = args.remove(0);
3960 let value = args.remove(0);
3961 let duckdb_fmt = self.convert_bq_to_strptime_format(fmt);
3963 Ok(Expression::Function(Box::new(Function::new(
3964 "STRPTIME".to_string(),
3965 vec![value, duckdb_fmt],
3966 ))))
3967 }
3968
3969 "BOOLAND" if f.args.len() == 2 => {
3971 let mut args = f.args;
3972 let a = args.remove(0);
3973 let b = args.remove(0);
3974 let ra = Expression::Function(Box::new(Function::new(
3975 "ROUND".to_string(),
3976 vec![a, Expression::number(0)],
3977 )));
3978 let rb = Expression::Function(Box::new(Function::new(
3979 "ROUND".to_string(),
3980 vec![b, Expression::number(0)],
3981 )));
3982 Ok(Expression::Paren(Box::new(Paren {
3983 this: Expression::And(Box::new(BinaryOp {
3984 left: Expression::Paren(Box::new(Paren {
3985 this: ra,
3986 trailing_comments: Vec::new(),
3987 })),
3988 right: Expression::Paren(Box::new(Paren {
3989 this: rb,
3990 trailing_comments: Vec::new(),
3991 })),
3992 left_comments: Vec::new(),
3993 operator_comments: Vec::new(),
3994 trailing_comments: Vec::new(),
3995 inferred_type: None,
3996 })),
3997 trailing_comments: Vec::new(),
3998 })))
3999 }
4000
4001 "BOOLOR" if f.args.len() == 2 => {
4003 let mut args = f.args;
4004 let a = args.remove(0);
4005 let b = args.remove(0);
4006 let ra = Expression::Function(Box::new(Function::new(
4007 "ROUND".to_string(),
4008 vec![a, Expression::number(0)],
4009 )));
4010 let rb = Expression::Function(Box::new(Function::new(
4011 "ROUND".to_string(),
4012 vec![b, Expression::number(0)],
4013 )));
4014 Ok(Expression::Paren(Box::new(Paren {
4015 this: Expression::Or(Box::new(BinaryOp {
4016 left: Expression::Paren(Box::new(Paren {
4017 this: ra,
4018 trailing_comments: Vec::new(),
4019 })),
4020 right: Expression::Paren(Box::new(Paren {
4021 this: rb,
4022 trailing_comments: Vec::new(),
4023 })),
4024 left_comments: Vec::new(),
4025 operator_comments: Vec::new(),
4026 trailing_comments: Vec::new(),
4027 inferred_type: None,
4028 })),
4029 trailing_comments: Vec::new(),
4030 })))
4031 }
4032
4033 "BOOLXOR" if f.args.len() == 2 => {
4035 let mut args = f.args;
4036 let a = args.remove(0);
4037 let b = args.remove(0);
4038 let ra = Expression::Function(Box::new(Function::new(
4039 "ROUND".to_string(),
4040 vec![a, Expression::number(0)],
4041 )));
4042 let rb = Expression::Function(Box::new(Function::new(
4043 "ROUND".to_string(),
4044 vec![b, Expression::number(0)],
4045 )));
4046 let not_rb = Expression::Not(Box::new(crate::expressions::UnaryOp {
4048 this: rb.clone(),
4049 inferred_type: None,
4050 }));
4051 let not_ra = Expression::Not(Box::new(crate::expressions::UnaryOp {
4052 this: ra.clone(),
4053 inferred_type: None,
4054 }));
4055 let left_and = Expression::And(Box::new(BinaryOp {
4056 left: ra,
4057 right: Expression::Paren(Box::new(Paren {
4058 this: not_rb,
4059 trailing_comments: Vec::new(),
4060 })),
4061 left_comments: Vec::new(),
4062 operator_comments: Vec::new(),
4063 trailing_comments: Vec::new(),
4064 inferred_type: None,
4065 }));
4066 let right_and = Expression::And(Box::new(BinaryOp {
4067 left: Expression::Paren(Box::new(Paren {
4068 this: not_ra,
4069 trailing_comments: Vec::new(),
4070 })),
4071 right: rb,
4072 left_comments: Vec::new(),
4073 operator_comments: Vec::new(),
4074 trailing_comments: Vec::new(),
4075 inferred_type: None,
4076 }));
4077 Ok(Expression::Or(Box::new(BinaryOp {
4078 left: Expression::Paren(Box::new(Paren {
4079 this: left_and,
4080 trailing_comments: Vec::new(),
4081 })),
4082 right: Expression::Paren(Box::new(Paren {
4083 this: right_and,
4084 trailing_comments: Vec::new(),
4085 })),
4086 left_comments: Vec::new(),
4087 operator_comments: Vec::new(),
4088 trailing_comments: Vec::new(),
4089 inferred_type: None,
4090 })))
4091 }
4092
4093 "DECODE" if f.args.len() >= 3 => {
4096 let mut args = f.args;
4097 let expr = args.remove(0);
4098 let mut whens = Vec::new();
4099 let mut else_expr = None;
4100 while args.len() >= 2 {
4101 let search = args.remove(0);
4102 let result = args.remove(0);
4103 let condition = if matches!(&search, Expression::Null(_)) {
4105 Expression::IsNull(Box::new(crate::expressions::IsNull {
4106 this: expr.clone(),
4107 not: false,
4108 postfix_form: false,
4109 }))
4110 } else {
4111 Expression::Eq(Box::new(BinaryOp {
4112 left: expr.clone(),
4113 right: search,
4114 left_comments: Vec::new(),
4115 operator_comments: Vec::new(),
4116 trailing_comments: Vec::new(),
4117 inferred_type: None,
4118 }))
4119 };
4120 whens.push((condition, result));
4121 }
4122 if !args.is_empty() {
4123 else_expr = Some(args.remove(0));
4124 }
4125 Ok(Expression::Case(Box::new(Case {
4126 operand: None,
4127 whens,
4128 else_: else_expr,
4129 comments: Vec::new(),
4130 inferred_type: None,
4131 })))
4132 }
4133
4134 "TRY_TO_BOOLEAN" if f.args.len() == 1 => {
4136 let arg = f.args.into_iter().next().unwrap();
4137 let cast_text = Expression::Cast(Box::new(Cast {
4138 this: arg.clone(),
4139 to: DataType::Text,
4140 trailing_comments: Vec::new(),
4141 double_colon_syntax: false,
4142 format: None,
4143 default: None,
4144 inferred_type: None,
4145 }));
4146 let upper_text = Expression::Upper(Box::new(UnaryFunc::new(cast_text)));
4147 Ok(Expression::Case(Box::new(Case {
4148 operand: None,
4149 whens: vec![
4150 (
4151 Expression::Eq(Box::new(BinaryOp {
4152 left: upper_text.clone(),
4153 right: Expression::Literal(Box::new(Literal::String(
4154 "ON".to_string(),
4155 ))),
4156 left_comments: Vec::new(),
4157 operator_comments: Vec::new(),
4158 trailing_comments: Vec::new(),
4159 inferred_type: None,
4160 })),
4161 Expression::Boolean(crate::expressions::BooleanLiteral { value: true }),
4162 ),
4163 (
4164 Expression::Eq(Box::new(BinaryOp {
4165 left: upper_text,
4166 right: Expression::Literal(Box::new(Literal::String(
4167 "OFF".to_string(),
4168 ))),
4169 left_comments: Vec::new(),
4170 operator_comments: Vec::new(),
4171 trailing_comments: Vec::new(),
4172 inferred_type: None,
4173 })),
4174 Expression::Boolean(crate::expressions::BooleanLiteral {
4175 value: false,
4176 }),
4177 ),
4178 ],
4179 else_: Some(Expression::TryCast(Box::new(Cast {
4180 this: arg,
4181 to: DataType::Boolean,
4182 trailing_comments: Vec::new(),
4183 double_colon_syntax: false,
4184 format: None,
4185 default: None,
4186 inferred_type: None,
4187 }))),
4188 comments: Vec::new(),
4189 inferred_type: None,
4190 })))
4191 }
4192
4193 "TO_BOOLEAN" if f.args.len() == 1 => {
4195 let arg = f.args.into_iter().next().unwrap();
4196 let cast_text = Expression::Cast(Box::new(Cast {
4197 this: arg.clone(),
4198 to: DataType::Text,
4199 trailing_comments: Vec::new(),
4200 double_colon_syntax: false,
4201 format: None,
4202 default: None,
4203 inferred_type: None,
4204 }));
4205 let upper_text = Expression::Upper(Box::new(UnaryFunc::new(cast_text)));
4206 Ok(Expression::Case(Box::new(Case {
4207 operand: None,
4208 whens: vec![
4209 (
4210 Expression::Eq(Box::new(BinaryOp {
4211 left: upper_text.clone(),
4212 right: Expression::Literal(Box::new(Literal::String(
4213 "ON".to_string(),
4214 ))),
4215 left_comments: Vec::new(),
4216 operator_comments: Vec::new(),
4217 trailing_comments: Vec::new(),
4218 inferred_type: None,
4219 })),
4220 Expression::Boolean(crate::expressions::BooleanLiteral { value: true }),
4221 ),
4222 (
4223 Expression::Eq(Box::new(BinaryOp {
4224 left: upper_text,
4225 right: Expression::Literal(Box::new(Literal::String(
4226 "OFF".to_string(),
4227 ))),
4228 left_comments: Vec::new(),
4229 operator_comments: Vec::new(),
4230 trailing_comments: Vec::new(),
4231 inferred_type: None,
4232 })),
4233 Expression::Boolean(crate::expressions::BooleanLiteral {
4234 value: false,
4235 }),
4236 ),
4237 (
4238 Expression::Or(Box::new(BinaryOp {
4239 left: Expression::Function(Box::new(Function::new(
4240 "ISNAN".to_string(),
4241 vec![Expression::TryCast(Box::new(Cast {
4242 this: arg.clone(),
4243 to: DataType::Custom {
4244 name: "REAL".to_string(),
4245 },
4246 trailing_comments: Vec::new(),
4247 double_colon_syntax: false,
4248 format: None,
4249 default: None,
4250 inferred_type: None,
4251 }))],
4252 ))),
4253 right: Expression::Function(Box::new(Function::new(
4254 "ISINF".to_string(),
4255 vec![Expression::TryCast(Box::new(Cast {
4256 this: arg.clone(),
4257 to: DataType::Custom {
4258 name: "REAL".to_string(),
4259 },
4260 trailing_comments: Vec::new(),
4261 double_colon_syntax: false,
4262 format: None,
4263 default: None,
4264 inferred_type: None,
4265 }))],
4266 ))),
4267 left_comments: Vec::new(),
4268 operator_comments: Vec::new(),
4269 trailing_comments: Vec::new(),
4270 inferred_type: None,
4271 })),
4272 Expression::Function(Box::new(Function::new(
4273 "ERROR".to_string(),
4274 vec![Expression::Literal(Box::new(Literal::String(
4275 "TO_BOOLEAN: Non-numeric values NaN and INF are not supported"
4276 .to_string(),
4277 )))],
4278 ))),
4279 ),
4280 ],
4281 else_: Some(Expression::Cast(Box::new(Cast {
4282 this: arg,
4283 to: DataType::Boolean,
4284 trailing_comments: Vec::new(),
4285 double_colon_syntax: false,
4286 format: None,
4287 default: None,
4288 inferred_type: None,
4289 }))),
4290 comments: Vec::new(),
4291 inferred_type: None,
4292 })))
4293 }
4294
4295 "OBJECT_INSERT" if f.args.len() == 3 => {
4298 let mut args = f.args;
4299 let obj = args.remove(0);
4300 let key = args.remove(0);
4301 let value = args.remove(0);
4302 let key_name = match &key {
4304 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
4305 let Literal::String(s) = lit.as_ref() else {
4306 unreachable!()
4307 };
4308 s.clone()
4309 }
4310 _ => "key".to_string(),
4311 };
4312 let named_arg =
4313 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
4314 name: Identifier::new(&key_name),
4315 value,
4316 separator: crate::expressions::NamedArgSeparator::ColonEq,
4317 }));
4318 let is_empty_struct = match &obj {
4320 Expression::Struct(s) if s.fields.is_empty() => true,
4321 Expression::Function(f) => {
4322 let n = f.name.to_uppercase();
4323 (n == "STRUCT_PACK" || n == "OBJECT_CONSTRUCT") && f.args.is_empty()
4324 }
4325 _ => false,
4326 };
4327 if is_empty_struct {
4328 Ok(Expression::Function(Box::new(Function::new(
4330 "STRUCT_PACK".to_string(),
4331 vec![named_arg],
4332 ))))
4333 } else {
4334 Ok(Expression::Function(Box::new(Function::new(
4335 "STRUCT_INSERT".to_string(),
4336 vec![obj, named_arg],
4337 ))))
4338 }
4339 }
4340
4341 "GET" if f.args.len() == 2 => {
4343 let mut args = f.args;
4344 let this = args.remove(0);
4345 let key = args.remove(0);
4346 match &key {
4347 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
4349 let Literal::String(s) = lit.as_ref() else {
4350 unreachable!()
4351 };
4352 let json_path = format!("$.{}", s);
4353 Ok(Expression::JsonExtract(Box::new(JsonExtractFunc {
4354 options: None,
4355 source_dialect: None,
4356
4357 this,
4358 path: Expression::Literal(Box::new(Literal::String(json_path))),
4359 returning: None,
4360 arrow_syntax: true,
4361 hash_arrow_syntax: false,
4362 wrapper_option: None,
4363 quotes_option: None,
4364 on_scalar_string: false,
4365 on_error: None,
4366 })))
4367 }
4368 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
4372 let Literal::Number(n) = lit.as_ref() else {
4373 unreachable!()
4374 };
4375 let idx: i64 = n.parse().unwrap_or(0);
4376 let is_map = matches!(&this, Expression::Cast(c) if matches!(c.to, DataType::Map { .. }));
4377 let index_val = if is_map { idx } else { idx + 1 };
4378 Ok(Expression::Subscript(Box::new(
4379 crate::expressions::Subscript {
4380 this,
4381 index: Expression::number(index_val),
4382 },
4383 )))
4384 }
4385 _ => {
4386 Ok(Expression::JsonExtract(Box::new(JsonExtractFunc {
4388 options: None,
4389 source_dialect: None,
4390
4391 this,
4392 path: Expression::JSONPath(Box::new(JSONPath {
4393 expressions: vec![
4394 Expression::JSONPathRoot(JSONPathRoot),
4395 Expression::JSONPathKey(Box::new(JSONPathKey {
4396 this: Box::new(key),
4397 })),
4398 ],
4399 escape: None,
4400 })),
4401 returning: None,
4402 arrow_syntax: true,
4403 hash_arrow_syntax: false,
4404 wrapper_option: None,
4405 quotes_option: None,
4406 on_scalar_string: false,
4407 on_error: None,
4408 })))
4409 }
4410 }
4411 }
4412
4413 "GET_PATH" if f.args.len() == 2 => {
4415 let mut args = f.args;
4416 let this = args.remove(0);
4417 let path = args.remove(0);
4418 let json_path = match &path {
4420 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
4421 let Literal::String(s) = lit.as_ref() else {
4422 unreachable!()
4423 };
4424 let s = Self::convert_bracket_to_quoted_path(s);
4426 let normalized = if s.starts_with('$') {
4428 s
4429 } else if s.starts_with('[') {
4430 format!("${}", s)
4431 } else {
4432 format!("$.{}", s)
4433 };
4434 Expression::Literal(Box::new(Literal::String(normalized)))
4435 }
4436 _ => path,
4437 };
4438 Ok(Expression::JsonExtract(Box::new(JsonExtractFunc {
4439 options: None,
4440 source_dialect: None,
4441
4442 this,
4443 path: json_path,
4444 returning: None,
4445 arrow_syntax: true,
4446 hash_arrow_syntax: false,
4447 wrapper_option: None,
4448 quotes_option: None,
4449 on_scalar_string: false,
4450 on_error: None,
4451 })))
4452 }
4453
4454 "BASE64_ENCODE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
4456 Function::new("TO_BASE64".to_string(), f.args),
4457 ))),
4458
4459 "BASE64_ENCODE" if f.args.len() >= 2 => {
4461 let mut args = f.args;
4462 let x = args.remove(0);
4463 let line_len = args.remove(0);
4464 let line_len_str = match &line_len {
4465 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
4466 let Literal::Number(n) = lit.as_ref() else {
4467 unreachable!()
4468 };
4469 n.clone()
4470 }
4471 _ => "76".to_string(),
4472 };
4473 let to_base64 =
4474 Expression::Function(Box::new(Function::new("TO_BASE64".to_string(), vec![x])));
4475 let pattern = format!("(.{{{}}})", line_len_str);
4476 let chr_10 = Expression::Function(Box::new(Function::new(
4477 "CHR".to_string(),
4478 vec![Expression::number(10)],
4479 )));
4480 let replacement = Expression::Concat(Box::new(BinaryOp {
4481 left: Expression::Literal(Box::new(Literal::String("\\1".to_string()))),
4482 right: chr_10.clone(),
4483 left_comments: Vec::new(),
4484 operator_comments: Vec::new(),
4485 trailing_comments: Vec::new(),
4486 inferred_type: None,
4487 }));
4488 let regexp_replace = Expression::Function(Box::new(Function::new(
4489 "REGEXP_REPLACE".to_string(),
4490 vec![
4491 to_base64,
4492 Expression::Literal(Box::new(Literal::String(pattern))),
4493 replacement,
4494 Expression::Literal(Box::new(Literal::String("g".to_string()))),
4495 ],
4496 )));
4497 Ok(Expression::Function(Box::new(Function::new(
4498 "RTRIM".to_string(),
4499 vec![regexp_replace, chr_10],
4500 ))))
4501 }
4502
4503 "TRY_TO_DATE" if f.args.len() == 2 => {
4505 let mut args = f.args;
4506 let value = args.remove(0);
4507 let fmt = self.convert_snowflake_date_format(args.remove(0));
4508 Ok(Expression::Cast(Box::new(Cast {
4509 this: Expression::Cast(Box::new(Cast {
4510 this: Expression::Function(Box::new(Function::new(
4511 "TRY_STRPTIME".to_string(),
4512 vec![value, fmt],
4513 ))),
4514 to: DataType::Timestamp {
4515 precision: None,
4516 timezone: false,
4517 },
4518 trailing_comments: Vec::new(),
4519 double_colon_syntax: false,
4520 format: None,
4521 default: None,
4522 inferred_type: None,
4523 })),
4524 to: DataType::Date,
4525 trailing_comments: Vec::new(),
4526 double_colon_syntax: false,
4527 format: None,
4528 default: None,
4529 inferred_type: None,
4530 })))
4531 }
4532
4533 "REGEXP_REPLACE" if f.args.len() == 4 => {
4536 let is_snowflake_position = matches!(&f.args[3], Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)));
4537 if is_snowflake_position {
4538 let mut args = f.args;
4540 let subject = args.remove(0);
4541 let pattern = args.remove(0);
4542 let replacement = args.remove(0);
4543 Ok(Expression::Function(Box::new(Function::new(
4544 "REGEXP_REPLACE".to_string(),
4545 vec![
4546 subject,
4547 pattern,
4548 replacement,
4549 Expression::Literal(Box::new(Literal::String("g".to_string()))),
4550 ],
4551 ))))
4552 } else {
4553 Ok(Expression::Function(Box::new(f)))
4555 }
4556 }
4557
4558 "REGEXP_REPLACE" if f.args.len() >= 5 => {
4560 let mut args = f.args;
4561 let subject = args.remove(0);
4562 let pattern = args.remove(0);
4563 let replacement = args.remove(0);
4564 let _position = args.remove(0);
4565 let occurrence = if !args.is_empty() {
4566 Some(args.remove(0))
4567 } else {
4568 None
4569 };
4570 let params = if !args.is_empty() {
4571 Some(args.remove(0))
4572 } else {
4573 None
4574 };
4575
4576 let mut flags = String::new();
4577 if let Some(Expression::Literal(lit)) = ¶ms {
4578 if let Literal::String(p) = lit.as_ref() {
4579 flags = p.clone();
4580 }
4581 }
4582 let is_global = match &occurrence {
4583 Some(Expression::Literal(lit))
4584 if matches!(lit.as_ref(), Literal::Number(_)) =>
4585 {
4586 let Literal::Number(n) = lit.as_ref() else {
4587 unreachable!()
4588 };
4589 n == "0"
4590 }
4591 None => true,
4592 _ => false,
4593 };
4594 if is_global && !flags.contains('g') {
4595 flags.push('g');
4596 }
4597
4598 Ok(Expression::Function(Box::new(Function::new(
4599 "REGEXP_REPLACE".to_string(),
4600 vec![
4601 subject,
4602 pattern,
4603 replacement,
4604 Expression::Literal(Box::new(Literal::String(flags))),
4605 ],
4606 ))))
4607 }
4608
4609 "ROUND"
4611 if f.args
4612 .iter()
4613 .any(|a| matches!(a, Expression::NamedArgument(_))) =>
4614 {
4615 let mut expr_val = None;
4616 let mut scale_val = None;
4617 let mut rounding_mode = None;
4618 for arg in &f.args {
4619 if let Expression::NamedArgument(na) = arg {
4620 match na.name.name.to_uppercase().as_str() {
4621 "EXPR" => expr_val = Some(na.value.clone()),
4622 "SCALE" => scale_val = Some(na.value.clone()),
4623 "ROUNDING_MODE" => rounding_mode = Some(na.value.clone()),
4624 _ => {}
4625 }
4626 }
4627 }
4628 if let Some(expr) = expr_val {
4629 let scale = scale_val.unwrap_or(Expression::number(0));
4630 let is_half_to_even = match &rounding_mode {
4631 Some(Expression::Literal(lit))
4632 if matches!(lit.as_ref(), Literal::String(_)) =>
4633 {
4634 let Literal::String(s) = lit.as_ref() else {
4635 unreachable!()
4636 };
4637 s == "HALF_TO_EVEN"
4638 }
4639 _ => false,
4640 };
4641 if is_half_to_even {
4642 Ok(Expression::Function(Box::new(Function::new(
4643 "ROUND_EVEN".to_string(),
4644 vec![expr, scale],
4645 ))))
4646 } else {
4647 Ok(Expression::Function(Box::new(Function::new(
4648 "ROUND".to_string(),
4649 vec![expr, scale],
4650 ))))
4651 }
4652 } else {
4653 Ok(Expression::Function(Box::new(f)))
4654 }
4655 }
4656
4657 "ROUND" if f.args.len() == 3 => {
4660 let mut args = f.args;
4661 let x = args.remove(0);
4662 let scale = args.remove(0);
4663 let mode = args.remove(0);
4664 let is_half_to_even = match &mode {
4665 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
4666 let Literal::String(s) = lit.as_ref() else {
4667 unreachable!()
4668 };
4669 s == "HALF_TO_EVEN"
4670 }
4671 _ => false,
4672 };
4673 if is_half_to_even {
4674 Ok(Expression::Function(Box::new(Function::new(
4675 "ROUND_EVEN".to_string(),
4676 vec![x, scale],
4677 ))))
4678 } else {
4679 Ok(Expression::Function(Box::new(Function::new(
4681 "ROUND".to_string(),
4682 vec![x, scale],
4683 ))))
4684 }
4685 }
4686
4687 "ROUND" if f.args.len() == 2 => {
4689 let mut args = f.args;
4690 let x = args.remove(0);
4691 let scale = args.remove(0);
4692 let needs_cast = match &scale {
4693 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
4694 let Literal::Number(n) = lit.as_ref() else {
4695 unreachable!()
4696 };
4697 n.contains('.')
4698 }
4699 Expression::Cast(_) => {
4700 true
4702 }
4703 _ => false,
4704 };
4705 if needs_cast {
4706 Ok(Expression::Function(Box::new(Function::new(
4707 "ROUND".to_string(),
4708 vec![
4709 x,
4710 Expression::Cast(Box::new(Cast {
4711 this: scale,
4712 to: DataType::Int {
4713 length: None,
4714 integer_spelling: false,
4715 },
4716 trailing_comments: Vec::new(),
4717 double_colon_syntax: false,
4718 format: None,
4719 default: None,
4720 inferred_type: None,
4721 })),
4722 ],
4723 ))))
4724 } else {
4725 Ok(Expression::Function(Box::new(Function::new(
4726 "ROUND".to_string(),
4727 vec![x, scale],
4728 ))))
4729 }
4730 }
4731
4732 "FLOOR" if f.args.len() == 2 => {
4734 let mut args = f.args;
4735 let x = args.remove(0);
4736 let scale = args.remove(0);
4737 let needs_cast = match &scale {
4739 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
4740 let Literal::Number(n) = lit.as_ref() else {
4741 unreachable!()
4742 };
4743 n.contains('.')
4744 }
4745 _ => false,
4746 };
4747 let int_scale = if needs_cast {
4748 Expression::Cast(Box::new(Cast {
4749 this: scale.clone(),
4750 to: DataType::Int {
4751 length: None,
4752 integer_spelling: false,
4753 },
4754 trailing_comments: Vec::new(),
4755 double_colon_syntax: false,
4756 format: None,
4757 default: None,
4758 inferred_type: None,
4759 }))
4760 } else {
4761 scale.clone()
4762 };
4763 let power_10 = Expression::Function(Box::new(Function::new(
4764 "POWER".to_string(),
4765 vec![Expression::number(10), int_scale.clone()],
4766 )));
4767 let x_paren = match &x {
4768 Expression::Add(_)
4769 | Expression::Sub(_)
4770 | Expression::Mul(_)
4771 | Expression::Div(_) => Expression::Paren(Box::new(Paren {
4772 this: x,
4773 trailing_comments: Vec::new(),
4774 })),
4775 _ => x,
4776 };
4777 let multiplied = Expression::Mul(Box::new(BinaryOp {
4778 left: x_paren,
4779 right: power_10.clone(),
4780 left_comments: Vec::new(),
4781 operator_comments: Vec::new(),
4782 trailing_comments: Vec::new(),
4783 inferred_type: None,
4784 }));
4785 let floored = Expression::Function(Box::new(Function::new(
4786 "FLOOR".to_string(),
4787 vec![multiplied],
4788 )));
4789 let divided = Expression::Div(Box::new(BinaryOp {
4790 left: floored,
4791 right: power_10,
4792 left_comments: Vec::new(),
4793 operator_comments: Vec::new(),
4794 trailing_comments: Vec::new(),
4795 inferred_type: None,
4796 }));
4797 Ok(Expression::Function(Box::new(Function::new(
4798 "ROUND".to_string(),
4799 vec![divided, int_scale],
4800 ))))
4801 }
4802
4803 "CEIL" | "CEILING" if f.args.len() == 2 => {
4805 let mut args = f.args;
4806 let x = args.remove(0);
4807 let scale = args.remove(0);
4808 let needs_cast = match &scale {
4809 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
4810 let Literal::Number(n) = lit.as_ref() else {
4811 unreachable!()
4812 };
4813 n.contains('.')
4814 }
4815 _ => false,
4816 };
4817 let int_scale = if needs_cast {
4818 Expression::Cast(Box::new(Cast {
4819 this: scale.clone(),
4820 to: DataType::Int {
4821 length: None,
4822 integer_spelling: false,
4823 },
4824 trailing_comments: Vec::new(),
4825 double_colon_syntax: false,
4826 format: None,
4827 default: None,
4828 inferred_type: None,
4829 }))
4830 } else {
4831 scale.clone()
4832 };
4833 let power_10 = Expression::Function(Box::new(Function::new(
4834 "POWER".to_string(),
4835 vec![Expression::number(10), int_scale.clone()],
4836 )));
4837 let x_paren = match &x {
4838 Expression::Add(_)
4839 | Expression::Sub(_)
4840 | Expression::Mul(_)
4841 | Expression::Div(_) => Expression::Paren(Box::new(Paren {
4842 this: x,
4843 trailing_comments: Vec::new(),
4844 })),
4845 _ => x,
4846 };
4847 let multiplied = Expression::Mul(Box::new(BinaryOp {
4848 left: x_paren,
4849 right: power_10.clone(),
4850 left_comments: Vec::new(),
4851 operator_comments: Vec::new(),
4852 trailing_comments: Vec::new(),
4853 inferred_type: None,
4854 }));
4855 let ceiled = Expression::Function(Box::new(Function::new(
4856 "CEIL".to_string(),
4857 vec![multiplied],
4858 )));
4859 let divided = Expression::Div(Box::new(BinaryOp {
4860 left: ceiled,
4861 right: power_10,
4862 left_comments: Vec::new(),
4863 operator_comments: Vec::new(),
4864 trailing_comments: Vec::new(),
4865 inferred_type: None,
4866 }));
4867 Ok(Expression::Function(Box::new(Function::new(
4868 "ROUND".to_string(),
4869 vec![divided, int_scale],
4870 ))))
4871 }
4872
4873 "ADD_MONTHS" if f.args.len() == 2 => {
4875 let mut args = f.args;
4876 let date_expr_raw = args.remove(0);
4877 let months_expr = args.remove(0);
4878
4879 let was_string_literal = matches!(&date_expr_raw, Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)));
4881
4882 let date_expr = match &date_expr_raw {
4884 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
4885 Expression::Cast(Box::new(Cast {
4886 this: date_expr_raw,
4887 to: DataType::Timestamp {
4888 precision: None,
4889 timezone: false,
4890 },
4891 trailing_comments: Vec::new(),
4892 double_colon_syntax: false,
4893 format: None,
4894 default: None,
4895 inferred_type: None,
4896 }))
4897 }
4898 _ => date_expr_raw,
4899 };
4900
4901 let date_type = if was_string_literal {
4904 None
4905 } else {
4906 match &date_expr {
4907 Expression::Cast(c) => Some(c.to.clone()),
4908 _ => None,
4909 }
4910 };
4911
4912 let is_non_integer_months = match &months_expr {
4914 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
4915 let Literal::Number(n) = lit.as_ref() else {
4916 unreachable!()
4917 };
4918 n.contains('.')
4919 }
4920 Expression::Neg(_) => {
4921 if let Expression::Neg(um) = &months_expr {
4922 matches!(&um.this, Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(n) if n.contains('.')))
4923 } else {
4924 false
4925 }
4926 }
4927 Expression::Cast(c) => matches!(&c.to, DataType::Decimal { .. }),
4929 _ => false,
4930 };
4931
4932 let is_negative = match &months_expr {
4933 Expression::Neg(_) => true,
4934 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
4935 let Literal::Number(n) = lit.as_ref() else {
4936 unreachable!()
4937 };
4938 n.starts_with('-')
4939 }
4940 _ => false,
4941 };
4942 let is_null = matches!(&months_expr, Expression::Null(_));
4943
4944 let interval_expr = if is_non_integer_months {
4945 Expression::Function(Box::new(Function::new(
4947 "TO_MONTHS".to_string(),
4948 vec![Expression::Cast(Box::new(Cast {
4949 this: Expression::Function(Box::new(Function::new(
4950 "ROUND".to_string(),
4951 vec![months_expr.clone()],
4952 ))),
4953 to: DataType::Int {
4954 length: None,
4955 integer_spelling: false,
4956 },
4957 trailing_comments: Vec::new(),
4958 double_colon_syntax: false,
4959 format: None,
4960 default: None,
4961 inferred_type: None,
4962 }))],
4963 )))
4964 } else if is_negative || is_null {
4965 Expression::Interval(Box::new(Interval {
4967 this: Some(Expression::Paren(Box::new(Paren {
4968 this: months_expr.clone(),
4969 trailing_comments: Vec::new(),
4970 }))),
4971 unit: Some(IntervalUnitSpec::Simple {
4972 unit: IntervalUnit::Month,
4973 use_plural: false,
4974 }),
4975 }))
4976 } else {
4977 Expression::Interval(Box::new(Interval {
4979 this: Some(months_expr.clone()),
4980 unit: Some(IntervalUnitSpec::Simple {
4981 unit: IntervalUnit::Month,
4982 use_plural: false,
4983 }),
4984 }))
4985 };
4986
4987 let date_plus_interval = Expression::Add(Box::new(BinaryOp {
4988 left: date_expr.clone(),
4989 right: interval_expr.clone(),
4990 left_comments: Vec::new(),
4991 operator_comments: Vec::new(),
4992 trailing_comments: Vec::new(),
4993 inferred_type: None,
4994 }));
4995
4996 let case_expr = Expression::Case(Box::new(Case {
4997 operand: None,
4998 whens: vec![(
4999 Expression::Eq(Box::new(BinaryOp {
5000 left: Expression::Function(Box::new(Function::new(
5001 "LAST_DAY".to_string(),
5002 vec![date_expr.clone()],
5003 ))),
5004 right: date_expr.clone(),
5005 left_comments: Vec::new(),
5006 operator_comments: Vec::new(),
5007 trailing_comments: Vec::new(),
5008 inferred_type: None,
5009 })),
5010 Expression::Function(Box::new(Function::new(
5011 "LAST_DAY".to_string(),
5012 vec![date_plus_interval.clone()],
5013 ))),
5014 )],
5015 else_: Some(date_plus_interval),
5016 comments: Vec::new(),
5017 inferred_type: None,
5018 }));
5019
5020 if let Some(dt) = date_type {
5022 Ok(Expression::Cast(Box::new(Cast {
5023 this: case_expr,
5024 to: dt,
5025 trailing_comments: Vec::new(),
5026 double_colon_syntax: false,
5027 format: None,
5028 default: None,
5029 inferred_type: None,
5030 })))
5031 } else {
5032 Ok(case_expr)
5033 }
5034 }
5035
5036 "TIME_SLICE" if f.args.len() >= 3 => {
5039 let mut args = f.args;
5040 let date_expr = args.remove(0);
5041 let n = args.remove(0);
5042 let unit_str = args.remove(0);
5043 let alignment = if !args.is_empty() {
5044 Some(args.remove(0))
5045 } else {
5046 None
5047 };
5048
5049 let unit = match &unit_str {
5051 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
5052 let Literal::String(s) = lit.as_ref() else {
5053 unreachable!()
5054 };
5055 s.to_uppercase()
5056 }
5057 Expression::Column(c) => c.name.name.to_uppercase(),
5058 Expression::Identifier(i) => i.name.to_uppercase(),
5059 _ => "DAY".to_string(),
5060 };
5061
5062 let interval_unit = match unit.as_str() {
5063 "YEAR" => IntervalUnit::Year,
5064 "QUARTER" => IntervalUnit::Quarter,
5065 "MONTH" => IntervalUnit::Month,
5066 "WEEK" => IntervalUnit::Week,
5067 "DAY" => IntervalUnit::Day,
5068 "HOUR" => IntervalUnit::Hour,
5069 "MINUTE" => IntervalUnit::Minute,
5070 "SECOND" => IntervalUnit::Second,
5071 _ => IntervalUnit::Day,
5072 };
5073
5074 let interval = Expression::Interval(Box::new(Interval {
5075 this: Some(n.clone()),
5076 unit: Some(IntervalUnitSpec::Simple {
5077 unit: interval_unit.clone(),
5078 use_plural: false,
5079 }),
5080 }));
5081
5082 let time_bucket = Expression::Function(Box::new(Function::new(
5083 "TIME_BUCKET".to_string(),
5084 vec![interval.clone(), date_expr.clone()],
5085 )));
5086
5087 let is_end = match &alignment {
5088 Some(Expression::Literal(lit))
5089 if matches!(lit.as_ref(), Literal::String(_)) =>
5090 {
5091 let Literal::String(s) = lit.as_ref() else {
5092 unreachable!()
5093 };
5094 s.to_uppercase() == "END"
5095 }
5096 _ => false,
5097 };
5098
5099 let is_date_type = match &date_expr {
5101 Expression::Cast(c) => matches!(&c.to, DataType::Date),
5102 _ => false,
5103 };
5104
5105 if is_end {
5106 let bucket_plus = Expression::Add(Box::new(BinaryOp {
5107 left: time_bucket,
5108 right: Expression::Interval(Box::new(Interval {
5109 this: Some(n),
5110 unit: Some(IntervalUnitSpec::Simple {
5111 unit: interval_unit,
5112 use_plural: false,
5113 }),
5114 })),
5115 left_comments: Vec::new(),
5116 operator_comments: Vec::new(),
5117 trailing_comments: Vec::new(),
5118 inferred_type: None,
5119 }));
5120 if is_date_type {
5121 Ok(Expression::Cast(Box::new(Cast {
5122 this: bucket_plus,
5123 to: DataType::Date,
5124 trailing_comments: Vec::new(),
5125 double_colon_syntax: false,
5126 format: None,
5127 default: None,
5128 inferred_type: None,
5129 })))
5130 } else {
5131 Ok(bucket_plus)
5132 }
5133 } else {
5134 Ok(time_bucket)
5135 }
5136 }
5137
5138 "DATE_FROM_PARTS" | "DATEFROMPARTS" if f.args.len() == 3 => {
5140 let mut args = f.args;
5141 let year = args.remove(0);
5142 let month = args.remove(0);
5143 let day = args.remove(0);
5144
5145 let make_date = Expression::Function(Box::new(Function::new(
5146 "MAKE_DATE".to_string(),
5147 vec![year, Expression::number(1), Expression::number(1)],
5148 )));
5149
5150 let month_wrapped = match &month {
5152 Expression::Add(_)
5153 | Expression::Sub(_)
5154 | Expression::Mul(_)
5155 | Expression::Div(_) => Expression::Paren(Box::new(Paren {
5156 this: month,
5157 trailing_comments: Vec::new(),
5158 })),
5159 _ => month,
5160 };
5161 let day_wrapped = match &day {
5162 Expression::Add(_)
5163 | Expression::Sub(_)
5164 | Expression::Mul(_)
5165 | Expression::Div(_) => Expression::Paren(Box::new(Paren {
5166 this: day,
5167 trailing_comments: Vec::new(),
5168 })),
5169 _ => day,
5170 };
5171 let month_minus_1 = Expression::Sub(Box::new(BinaryOp {
5172 left: month_wrapped,
5173 right: Expression::number(1),
5174 left_comments: Vec::new(),
5175 operator_comments: Vec::new(),
5176 trailing_comments: Vec::new(),
5177 inferred_type: None,
5178 }));
5179 let month_interval = Expression::Interval(Box::new(Interval {
5180 this: Some(Expression::Paren(Box::new(Paren {
5181 this: month_minus_1,
5182 trailing_comments: Vec::new(),
5183 }))),
5184 unit: Some(IntervalUnitSpec::Simple {
5185 unit: IntervalUnit::Month,
5186 use_plural: false,
5187 }),
5188 }));
5189
5190 let day_minus_1 = Expression::Sub(Box::new(BinaryOp {
5191 left: day_wrapped,
5192 right: Expression::number(1),
5193 left_comments: Vec::new(),
5194 operator_comments: Vec::new(),
5195 trailing_comments: Vec::new(),
5196 inferred_type: None,
5197 }));
5198 let day_interval = Expression::Interval(Box::new(Interval {
5199 this: Some(Expression::Paren(Box::new(Paren {
5200 this: day_minus_1,
5201 trailing_comments: Vec::new(),
5202 }))),
5203 unit: Some(IntervalUnitSpec::Simple {
5204 unit: IntervalUnit::Day,
5205 use_plural: false,
5206 }),
5207 }));
5208
5209 let result = Expression::Add(Box::new(BinaryOp {
5210 left: Expression::Add(Box::new(BinaryOp {
5211 left: make_date,
5212 right: month_interval,
5213 left_comments: Vec::new(),
5214 operator_comments: Vec::new(),
5215 trailing_comments: Vec::new(),
5216 inferred_type: None,
5217 })),
5218 right: day_interval,
5219 left_comments: Vec::new(),
5220 operator_comments: Vec::new(),
5221 trailing_comments: Vec::new(),
5222 inferred_type: None,
5223 }));
5224
5225 Ok(Expression::Cast(Box::new(Cast {
5226 this: result,
5227 to: DataType::Date,
5228 trailing_comments: Vec::new(),
5229 double_colon_syntax: false,
5230 format: None,
5231 default: None,
5232 inferred_type: None,
5233 })))
5234 }
5235
5236 "NEXT_DAY" if f.args.len() == 2 => {
5238 let mut args = f.args;
5239 let date = args.remove(0);
5240 let day_name = args.remove(0);
5241
5242 let day_num = match &day_name {
5244 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
5245 let Literal::String(s) = lit.as_ref() else {
5246 unreachable!()
5247 };
5248 let upper = s.to_uppercase();
5249 if upper.starts_with("MO") {
5250 Some(1)
5251 } else if upper.starts_with("TU") {
5252 Some(2)
5253 } else if upper.starts_with("WE") {
5254 Some(3)
5255 } else if upper.starts_with("TH") {
5256 Some(4)
5257 } else if upper.starts_with("FR") {
5258 Some(5)
5259 } else if upper.starts_with("SA") {
5260 Some(6)
5261 } else if upper.starts_with("SU") {
5262 Some(7)
5263 } else {
5264 None
5265 }
5266 }
5267 _ => None,
5268 };
5269
5270 let target_day_expr = if let Some(n) = day_num {
5271 Expression::number(n)
5272 } else {
5273 Expression::Case(Box::new(Case {
5275 operand: None,
5276 whens: vec![
5277 (
5278 Expression::Function(Box::new(Function::new(
5279 "STARTS_WITH".to_string(),
5280 vec![
5281 Expression::Upper(Box::new(UnaryFunc::new(
5282 day_name.clone(),
5283 ))),
5284 Expression::Literal(Box::new(Literal::String(
5285 "MO".to_string(),
5286 ))),
5287 ],
5288 ))),
5289 Expression::number(1),
5290 ),
5291 (
5292 Expression::Function(Box::new(Function::new(
5293 "STARTS_WITH".to_string(),
5294 vec![
5295 Expression::Upper(Box::new(UnaryFunc::new(
5296 day_name.clone(),
5297 ))),
5298 Expression::Literal(Box::new(Literal::String(
5299 "TU".to_string(),
5300 ))),
5301 ],
5302 ))),
5303 Expression::number(2),
5304 ),
5305 (
5306 Expression::Function(Box::new(Function::new(
5307 "STARTS_WITH".to_string(),
5308 vec![
5309 Expression::Upper(Box::new(UnaryFunc::new(
5310 day_name.clone(),
5311 ))),
5312 Expression::Literal(Box::new(Literal::String(
5313 "WE".to_string(),
5314 ))),
5315 ],
5316 ))),
5317 Expression::number(3),
5318 ),
5319 (
5320 Expression::Function(Box::new(Function::new(
5321 "STARTS_WITH".to_string(),
5322 vec![
5323 Expression::Upper(Box::new(UnaryFunc::new(
5324 day_name.clone(),
5325 ))),
5326 Expression::Literal(Box::new(Literal::String(
5327 "TH".to_string(),
5328 ))),
5329 ],
5330 ))),
5331 Expression::number(4),
5332 ),
5333 (
5334 Expression::Function(Box::new(Function::new(
5335 "STARTS_WITH".to_string(),
5336 vec![
5337 Expression::Upper(Box::new(UnaryFunc::new(
5338 day_name.clone(),
5339 ))),
5340 Expression::Literal(Box::new(Literal::String(
5341 "FR".to_string(),
5342 ))),
5343 ],
5344 ))),
5345 Expression::number(5),
5346 ),
5347 (
5348 Expression::Function(Box::new(Function::new(
5349 "STARTS_WITH".to_string(),
5350 vec![
5351 Expression::Upper(Box::new(UnaryFunc::new(
5352 day_name.clone(),
5353 ))),
5354 Expression::Literal(Box::new(Literal::String(
5355 "SA".to_string(),
5356 ))),
5357 ],
5358 ))),
5359 Expression::number(6),
5360 ),
5361 (
5362 Expression::Function(Box::new(Function::new(
5363 "STARTS_WITH".to_string(),
5364 vec![
5365 Expression::Upper(Box::new(UnaryFunc::new(day_name))),
5366 Expression::Literal(Box::new(Literal::String(
5367 "SU".to_string(),
5368 ))),
5369 ],
5370 ))),
5371 Expression::number(7),
5372 ),
5373 ],
5374 else_: None,
5375 comments: Vec::new(),
5376 inferred_type: None,
5377 }))
5378 };
5379
5380 let isodow = Expression::Function(Box::new(Function::new(
5381 "ISODOW".to_string(),
5382 vec![date.clone()],
5383 )));
5384 let diff = Expression::Add(Box::new(BinaryOp {
5386 left: Expression::Paren(Box::new(Paren {
5387 this: Expression::Mod(Box::new(BinaryOp {
5388 left: Expression::Paren(Box::new(Paren {
5389 this: Expression::Add(Box::new(BinaryOp {
5390 left: Expression::Paren(Box::new(Paren {
5391 this: Expression::Sub(Box::new(BinaryOp {
5392 left: target_day_expr,
5393 right: isodow,
5394 left_comments: Vec::new(),
5395 operator_comments: Vec::new(),
5396 trailing_comments: Vec::new(),
5397 inferred_type: None,
5398 })),
5399 trailing_comments: Vec::new(),
5400 })),
5401 right: Expression::number(6),
5402 left_comments: Vec::new(),
5403 operator_comments: Vec::new(),
5404 trailing_comments: Vec::new(),
5405 inferred_type: None,
5406 })),
5407 trailing_comments: Vec::new(),
5408 })),
5409 right: Expression::number(7),
5410 left_comments: Vec::new(),
5411 operator_comments: Vec::new(),
5412 trailing_comments: Vec::new(),
5413 inferred_type: None,
5414 })),
5415 trailing_comments: Vec::new(),
5416 })),
5417 right: Expression::number(1),
5418 left_comments: Vec::new(),
5419 operator_comments: Vec::new(),
5420 trailing_comments: Vec::new(),
5421 inferred_type: None,
5422 }));
5423
5424 let result = Expression::Add(Box::new(BinaryOp {
5425 left: date,
5426 right: Expression::Interval(Box::new(Interval {
5427 this: Some(Expression::Paren(Box::new(Paren {
5428 this: diff,
5429 trailing_comments: Vec::new(),
5430 }))),
5431 unit: Some(IntervalUnitSpec::Simple {
5432 unit: IntervalUnit::Day,
5433 use_plural: false,
5434 }),
5435 })),
5436 left_comments: Vec::new(),
5437 operator_comments: Vec::new(),
5438 trailing_comments: Vec::new(),
5439 inferred_type: None,
5440 }));
5441
5442 Ok(Expression::Cast(Box::new(Cast {
5443 this: result,
5444 to: DataType::Date,
5445 trailing_comments: Vec::new(),
5446 double_colon_syntax: false,
5447 format: None,
5448 default: None,
5449 inferred_type: None,
5450 })))
5451 }
5452
5453 "PREVIOUS_DAY" if f.args.len() == 2 => {
5455 let mut args = f.args;
5456 let date = args.remove(0);
5457 let day_name = args.remove(0);
5458
5459 let day_num = match &day_name {
5460 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
5461 let Literal::String(s) = lit.as_ref() else {
5462 unreachable!()
5463 };
5464 let upper = s.to_uppercase();
5465 if upper.starts_with("MO") {
5466 Some(1)
5467 } else if upper.starts_with("TU") {
5468 Some(2)
5469 } else if upper.starts_with("WE") {
5470 Some(3)
5471 } else if upper.starts_with("TH") {
5472 Some(4)
5473 } else if upper.starts_with("FR") {
5474 Some(5)
5475 } else if upper.starts_with("SA") {
5476 Some(6)
5477 } else if upper.starts_with("SU") {
5478 Some(7)
5479 } else {
5480 None
5481 }
5482 }
5483 _ => None,
5484 };
5485
5486 let target_day_expr = if let Some(n) = day_num {
5487 Expression::number(n)
5488 } else {
5489 Expression::Case(Box::new(Case {
5490 operand: None,
5491 whens: vec![
5492 (
5493 Expression::Function(Box::new(Function::new(
5494 "STARTS_WITH".to_string(),
5495 vec![
5496 Expression::Upper(Box::new(UnaryFunc::new(
5497 day_name.clone(),
5498 ))),
5499 Expression::Literal(Box::new(Literal::String(
5500 "MO".to_string(),
5501 ))),
5502 ],
5503 ))),
5504 Expression::number(1),
5505 ),
5506 (
5507 Expression::Function(Box::new(Function::new(
5508 "STARTS_WITH".to_string(),
5509 vec![
5510 Expression::Upper(Box::new(UnaryFunc::new(
5511 day_name.clone(),
5512 ))),
5513 Expression::Literal(Box::new(Literal::String(
5514 "TU".to_string(),
5515 ))),
5516 ],
5517 ))),
5518 Expression::number(2),
5519 ),
5520 (
5521 Expression::Function(Box::new(Function::new(
5522 "STARTS_WITH".to_string(),
5523 vec![
5524 Expression::Upper(Box::new(UnaryFunc::new(
5525 day_name.clone(),
5526 ))),
5527 Expression::Literal(Box::new(Literal::String(
5528 "WE".to_string(),
5529 ))),
5530 ],
5531 ))),
5532 Expression::number(3),
5533 ),
5534 (
5535 Expression::Function(Box::new(Function::new(
5536 "STARTS_WITH".to_string(),
5537 vec![
5538 Expression::Upper(Box::new(UnaryFunc::new(
5539 day_name.clone(),
5540 ))),
5541 Expression::Literal(Box::new(Literal::String(
5542 "TH".to_string(),
5543 ))),
5544 ],
5545 ))),
5546 Expression::number(4),
5547 ),
5548 (
5549 Expression::Function(Box::new(Function::new(
5550 "STARTS_WITH".to_string(),
5551 vec![
5552 Expression::Upper(Box::new(UnaryFunc::new(
5553 day_name.clone(),
5554 ))),
5555 Expression::Literal(Box::new(Literal::String(
5556 "FR".to_string(),
5557 ))),
5558 ],
5559 ))),
5560 Expression::number(5),
5561 ),
5562 (
5563 Expression::Function(Box::new(Function::new(
5564 "STARTS_WITH".to_string(),
5565 vec![
5566 Expression::Upper(Box::new(UnaryFunc::new(
5567 day_name.clone(),
5568 ))),
5569 Expression::Literal(Box::new(Literal::String(
5570 "SA".to_string(),
5571 ))),
5572 ],
5573 ))),
5574 Expression::number(6),
5575 ),
5576 (
5577 Expression::Function(Box::new(Function::new(
5578 "STARTS_WITH".to_string(),
5579 vec![
5580 Expression::Upper(Box::new(UnaryFunc::new(day_name))),
5581 Expression::Literal(Box::new(Literal::String(
5582 "SU".to_string(),
5583 ))),
5584 ],
5585 ))),
5586 Expression::number(7),
5587 ),
5588 ],
5589 else_: None,
5590 comments: Vec::new(),
5591 inferred_type: None,
5592 }))
5593 };
5594
5595 let isodow = Expression::Function(Box::new(Function::new(
5596 "ISODOW".to_string(),
5597 vec![date.clone()],
5598 )));
5599 let diff = Expression::Add(Box::new(BinaryOp {
5601 left: Expression::Paren(Box::new(Paren {
5602 this: Expression::Mod(Box::new(BinaryOp {
5603 left: Expression::Paren(Box::new(Paren {
5604 this: Expression::Add(Box::new(BinaryOp {
5605 left: Expression::Paren(Box::new(Paren {
5606 this: Expression::Sub(Box::new(BinaryOp {
5607 left: isodow,
5608 right: target_day_expr,
5609 left_comments: Vec::new(),
5610 operator_comments: Vec::new(),
5611 trailing_comments: Vec::new(),
5612 inferred_type: None,
5613 })),
5614 trailing_comments: Vec::new(),
5615 })),
5616 right: Expression::number(6),
5617 left_comments: Vec::new(),
5618 operator_comments: Vec::new(),
5619 trailing_comments: Vec::new(),
5620 inferred_type: None,
5621 })),
5622 trailing_comments: Vec::new(),
5623 })),
5624 right: Expression::number(7),
5625 left_comments: Vec::new(),
5626 operator_comments: Vec::new(),
5627 trailing_comments: Vec::new(),
5628 inferred_type: None,
5629 })),
5630 trailing_comments: Vec::new(),
5631 })),
5632 right: Expression::number(1),
5633 left_comments: Vec::new(),
5634 operator_comments: Vec::new(),
5635 trailing_comments: Vec::new(),
5636 inferred_type: None,
5637 }));
5638
5639 let result = Expression::Sub(Box::new(BinaryOp {
5640 left: date,
5641 right: Expression::Interval(Box::new(Interval {
5642 this: Some(Expression::Paren(Box::new(Paren {
5643 this: diff,
5644 trailing_comments: Vec::new(),
5645 }))),
5646 unit: Some(IntervalUnitSpec::Simple {
5647 unit: IntervalUnit::Day,
5648 use_plural: false,
5649 }),
5650 })),
5651 left_comments: Vec::new(),
5652 operator_comments: Vec::new(),
5653 trailing_comments: Vec::new(),
5654 inferred_type: None,
5655 }));
5656
5657 Ok(Expression::Cast(Box::new(Cast {
5658 this: result,
5659 to: DataType::Date,
5660 trailing_comments: Vec::new(),
5661 double_colon_syntax: false,
5662 format: None,
5663 default: None,
5664 inferred_type: None,
5665 })))
5666 }
5667
5668 "LAST_DAY" if f.args.len() == 2 => {
5672 let mut args = f.args;
5673 let date = args.remove(0);
5674 let unit = args.remove(0);
5675 let unit_str = match &unit {
5676 Expression::Column(c) => c.name.name.to_uppercase(),
5677 Expression::Identifier(i) => i.name.to_uppercase(),
5678 _ => String::new(),
5679 };
5680
5681 match unit_str.as_str() {
5682 "MONTH" => Ok(Expression::Function(Box::new(Function::new(
5683 "LAST_DAY".to_string(),
5684 vec![date],
5685 )))),
5686 "YEAR" => Ok(Expression::Function(Box::new(Function::new(
5687 "MAKE_DATE".to_string(),
5688 vec![
5689 Expression::Extract(Box::new(crate::expressions::ExtractFunc {
5690 this: date,
5691 field: crate::expressions::DateTimeField::Year,
5692 })),
5693 Expression::number(12),
5694 Expression::number(31),
5695 ],
5696 )))),
5697 "QUARTER" => {
5698 let year = Expression::Extract(Box::new(crate::expressions::ExtractFunc {
5699 this: date.clone(),
5700 field: crate::expressions::DateTimeField::Year,
5701 }));
5702 let quarter_month = Expression::Mul(Box::new(BinaryOp {
5703 left: Expression::Extract(Box::new(crate::expressions::ExtractFunc {
5704 this: date,
5705 field: crate::expressions::DateTimeField::Custom(
5706 "QUARTER".to_string(),
5707 ),
5708 })),
5709 right: Expression::number(3),
5710 left_comments: Vec::new(),
5711 operator_comments: Vec::new(),
5712 trailing_comments: Vec::new(),
5713 inferred_type: None,
5714 }));
5715 let make_date = Expression::Function(Box::new(Function::new(
5716 "MAKE_DATE".to_string(),
5717 vec![year, quarter_month, Expression::number(1)],
5718 )));
5719 Ok(Expression::Function(Box::new(Function::new(
5720 "LAST_DAY".to_string(),
5721 vec![make_date],
5722 ))))
5723 }
5724 "WEEK" => {
5725 let dow = Expression::Extract(Box::new(crate::expressions::ExtractFunc {
5726 this: date.clone(),
5727 field: crate::expressions::DateTimeField::Custom(
5728 "DAYOFWEEK".to_string(),
5729 ),
5730 }));
5731 let diff = Expression::Mod(Box::new(BinaryOp {
5732 left: Expression::Paren(Box::new(Paren {
5733 this: Expression::Sub(Box::new(BinaryOp {
5734 left: Expression::number(7),
5735 right: dow,
5736 left_comments: Vec::new(),
5737 operator_comments: Vec::new(),
5738 trailing_comments: Vec::new(),
5739 inferred_type: None,
5740 })),
5741 trailing_comments: Vec::new(),
5742 })),
5743 right: Expression::number(7),
5744 left_comments: Vec::new(),
5745 operator_comments: Vec::new(),
5746 trailing_comments: Vec::new(),
5747 inferred_type: None,
5748 }));
5749 let result = Expression::Add(Box::new(BinaryOp {
5750 left: date,
5751 right: Expression::Interval(Box::new(Interval {
5752 this: Some(Expression::Paren(Box::new(Paren {
5753 this: diff,
5754 trailing_comments: Vec::new(),
5755 }))),
5756 unit: Some(IntervalUnitSpec::Simple {
5757 unit: IntervalUnit::Day,
5758 use_plural: false,
5759 }),
5760 })),
5761 left_comments: Vec::new(),
5762 operator_comments: Vec::new(),
5763 trailing_comments: Vec::new(),
5764 inferred_type: None,
5765 }));
5766 Ok(Expression::Cast(Box::new(Cast {
5767 this: result,
5768 to: DataType::Date,
5769 trailing_comments: Vec::new(),
5770 double_colon_syntax: false,
5771 format: None,
5772 default: None,
5773 inferred_type: None,
5774 })))
5775 }
5776 _ => Ok(Expression::Function(Box::new(Function::new(
5777 "LAST_DAY".to_string(),
5778 vec![date, unit],
5779 )))),
5780 }
5781 }
5782
5783 "SEQ1" | "SEQ2" | "SEQ4" | "SEQ8" => {
5786 let (range, half): (u128, u128) = match name_upper.as_str() {
5787 "SEQ1" => (256, 128),
5788 "SEQ2" => (65536, 32768),
5789 "SEQ4" => (4294967296, 2147483648),
5790 "SEQ8" => (18446744073709551616, 9223372036854775808),
5791 _ => unreachable!("sequence type already matched in caller"),
5792 };
5793
5794 let is_signed = match f.args.first() {
5795 Some(Expression::Literal(lit))
5796 if matches!(lit.as_ref(), Literal::Number(_)) =>
5797 {
5798 let Literal::Number(n) = lit.as_ref() else {
5799 unreachable!()
5800 };
5801 n == "1"
5802 }
5803 _ => false,
5804 };
5805
5806 let row_num = Expression::Sub(Box::new(BinaryOp {
5807 left: Expression::WindowFunction(Box::new(
5808 crate::expressions::WindowFunction {
5809 this: Expression::Function(Box::new(Function::new(
5810 "ROW_NUMBER".to_string(),
5811 vec![],
5812 ))),
5813 over: crate::expressions::Over {
5814 window_name: None,
5815 partition_by: vec![],
5816 order_by: vec![crate::expressions::Ordered {
5817 nulls_auto: false,
5818 this: Expression::number(1),
5819 desc: false,
5820 nulls_first: Some(true),
5821 explicit_asc: false,
5822 with_fill: None,
5823 }],
5824 frame: None,
5825 alias: None,
5826 },
5827 keep: None,
5828 inferred_type: None,
5829 },
5830 )),
5831 right: Expression::number(1),
5832 left_comments: Vec::new(),
5833 operator_comments: Vec::new(),
5834 trailing_comments: Vec::new(),
5835 inferred_type: None,
5836 }));
5837
5838 let modded = Expression::Mod(Box::new(BinaryOp {
5839 left: Expression::Paren(Box::new(Paren {
5840 this: row_num,
5841 trailing_comments: Vec::new(),
5842 })),
5843 right: Expression::Literal(Box::new(Literal::Number(range.to_string()))),
5844 left_comments: Vec::new(),
5845 operator_comments: Vec::new(),
5846 trailing_comments: Vec::new(),
5847 inferred_type: None,
5848 }));
5849
5850 if is_signed {
5851 let cond = Expression::Gte(Box::new(BinaryOp {
5853 left: modded.clone(),
5854 right: Expression::Literal(Box::new(Literal::Number(half.to_string()))),
5855 left_comments: Vec::new(),
5856 operator_comments: Vec::new(),
5857 trailing_comments: Vec::new(),
5858 inferred_type: None,
5859 }));
5860 let signed_val = Expression::Sub(Box::new(BinaryOp {
5861 left: modded.clone(),
5862 right: Expression::Literal(Box::new(Literal::Number(range.to_string()))),
5863 left_comments: Vec::new(),
5864 operator_comments: Vec::new(),
5865 trailing_comments: Vec::new(),
5866 inferred_type: None,
5867 }));
5868 Ok(Expression::Paren(Box::new(Paren {
5869 this: Expression::Case(Box::new(Case {
5870 operand: None,
5871 whens: vec![(cond, signed_val)],
5872 else_: Some(modded),
5873 comments: Vec::new(),
5874 inferred_type: None,
5875 })),
5876 trailing_comments: Vec::new(),
5877 })))
5878 } else {
5879 Ok(modded)
5880 }
5881 }
5882
5883 "TABLE" if f.args.len() == 1 => {
5886 let inner = f.args.into_iter().next().unwrap();
5887 if let Expression::Function(ref gen_f) = inner {
5889 if gen_f.name.to_uppercase() == "GENERATOR" {
5890 let mut rowcount = None;
5891 for arg in &gen_f.args {
5892 if let Expression::NamedArgument(na) = arg {
5893 if na.name.name.to_uppercase() == "ROWCOUNT" {
5894 rowcount = Some(na.value.clone());
5895 }
5896 }
5897 }
5898 if let Some(n) = rowcount {
5899 return Ok(Expression::Function(Box::new(Function::new(
5900 "RANGE".to_string(),
5901 vec![n],
5902 ))));
5903 }
5904 }
5905 }
5906 Ok(inner)
5907 }
5908
5909 "GENERATOR" => {
5911 let mut rowcount = None;
5912 for arg in &f.args {
5913 if let Expression::NamedArgument(na) = arg {
5914 if na.name.name.to_uppercase() == "ROWCOUNT" {
5915 rowcount = Some(na.value.clone());
5916 }
5917 }
5918 }
5919 if let Some(n) = rowcount {
5920 Ok(Expression::Function(Box::new(Function::new(
5921 "RANGE".to_string(),
5922 vec![n],
5923 ))))
5924 } else {
5925 Ok(Expression::Function(Box::new(f)))
5926 }
5927 }
5928
5929 "UNIFORM" if f.args.len() == 3 => {
5932 let mut args = f.args;
5933 let low = args.remove(0);
5934 let high = args.remove(0);
5935 let gen = args.remove(0);
5936
5937 let range = Expression::Add(Box::new(BinaryOp {
5938 left: Expression::Sub(Box::new(BinaryOp {
5939 left: high,
5940 right: low.clone(),
5941 left_comments: Vec::new(),
5942 operator_comments: Vec::new(),
5943 trailing_comments: Vec::new(),
5944 inferred_type: None,
5945 })),
5946 right: Expression::number(1),
5947 left_comments: Vec::new(),
5948 operator_comments: Vec::new(),
5949 trailing_comments: Vec::new(),
5950 inferred_type: None,
5951 }));
5952
5953 let random_val = match &gen {
5955 Expression::Rand(_) | Expression::Random(_) => {
5956 Expression::Function(Box::new(Function::new("RANDOM".to_string(), vec![])))
5958 }
5959 Expression::Function(func) if func.name.to_uppercase() == "RANDOM" => {
5960 Expression::Function(Box::new(Function::new("RANDOM".to_string(), vec![])))
5962 }
5963 _ => {
5964 let hash = Expression::Function(Box::new(Function::new(
5966 "HASH".to_string(),
5967 vec![gen],
5968 )));
5969 let abs_hash = Expression::Abs(Box::new(UnaryFunc::new(hash)));
5970 let modded = Expression::Mod(Box::new(BinaryOp {
5971 left: abs_hash,
5972 right: Expression::number(1000000),
5973 left_comments: Vec::new(),
5974 operator_comments: Vec::new(),
5975 trailing_comments: Vec::new(),
5976 inferred_type: None,
5977 }));
5978 let paren_modded = Expression::Paren(Box::new(Paren {
5979 this: modded,
5980 trailing_comments: Vec::new(),
5981 }));
5982 Expression::Div(Box::new(BinaryOp {
5983 left: paren_modded,
5984 right: Expression::Literal(Box::new(Literal::Number(
5985 "1000000.0".to_string(),
5986 ))),
5987 left_comments: Vec::new(),
5988 operator_comments: Vec::new(),
5989 trailing_comments: Vec::new(),
5990 inferred_type: None,
5991 }))
5992 }
5993 };
5994
5995 let inner = Expression::Function(Box::new(Function::new(
5996 "FLOOR".to_string(),
5997 vec![Expression::Add(Box::new(BinaryOp {
5998 left: low,
5999 right: Expression::Mul(Box::new(BinaryOp {
6000 left: random_val,
6001 right: Expression::Paren(Box::new(Paren {
6002 this: range,
6003 trailing_comments: Vec::new(),
6004 })),
6005 left_comments: Vec::new(),
6006 operator_comments: Vec::new(),
6007 trailing_comments: Vec::new(),
6008 inferred_type: None,
6009 })),
6010 left_comments: Vec::new(),
6011 operator_comments: Vec::new(),
6012 trailing_comments: Vec::new(),
6013 inferred_type: None,
6014 }))],
6015 )));
6016
6017 Ok(Expression::Cast(Box::new(Cast {
6018 this: inner,
6019 to: DataType::BigInt { length: None },
6020 trailing_comments: Vec::new(),
6021 double_colon_syntax: false,
6022 format: None,
6023 default: None,
6024 inferred_type: None,
6025 })))
6026 }
6027
6028 "NORMAL" if f.args.len() == 3 => {
6032 let mut args = f.args;
6033 let mean = args.remove(0);
6034 let stddev = args.remove(0);
6035 let gen = args.remove(0);
6036
6037 let make_seed_random = |seed: Expression| -> Expression {
6039 let hash = Expression::Function(Box::new(Function::new(
6040 "HASH".to_string(),
6041 vec![seed],
6042 )));
6043 let abs_hash = Expression::Abs(Box::new(UnaryFunc::new(hash)));
6044 let modded = Expression::Mod(Box::new(BinaryOp {
6045 left: abs_hash,
6046 right: Expression::number(1000000),
6047 left_comments: Vec::new(),
6048 operator_comments: Vec::new(),
6049 trailing_comments: Vec::new(),
6050 inferred_type: None,
6051 }));
6052 let paren_modded = Expression::Paren(Box::new(Paren {
6053 this: modded,
6054 trailing_comments: Vec::new(),
6055 }));
6056 Expression::Div(Box::new(BinaryOp {
6057 left: paren_modded,
6058 right: Expression::Literal(Box::new(Literal::Number(
6059 "1000000.0".to_string(),
6060 ))),
6061 left_comments: Vec::new(),
6062 operator_comments: Vec::new(),
6063 trailing_comments: Vec::new(),
6064 inferred_type: None,
6065 }))
6066 };
6067
6068 let is_random_no_seed = match &gen {
6070 Expression::Random(_) => true,
6071 Expression::Rand(r) => r.seed.is_none(),
6072 _ => false,
6073 };
6074 let (u1, u2) = if is_random_no_seed {
6075 let u1 =
6077 Expression::Function(Box::new(Function::new("RANDOM".to_string(), vec![])));
6078 let u2 =
6079 Expression::Function(Box::new(Function::new("RANDOM".to_string(), vec![])));
6080 (u1, u2)
6081 } else {
6082 let seed = match gen {
6084 Expression::Rand(r) => r.seed.map(|s| *s).unwrap_or(Expression::number(0)),
6085 Expression::Function(func) if func.name.to_uppercase() == "RANDOM" => {
6086 if func.args.len() == 1 {
6087 func.args.into_iter().next().unwrap()
6088 } else {
6089 Expression::number(0)
6090 }
6091 }
6092 other => other,
6093 };
6094 let u1 = make_seed_random(seed.clone());
6095 let seed_plus_1 = Expression::Add(Box::new(BinaryOp {
6096 left: seed,
6097 right: Expression::number(1),
6098 left_comments: Vec::new(),
6099 operator_comments: Vec::new(),
6100 trailing_comments: Vec::new(),
6101 inferred_type: None,
6102 }));
6103 let u2 = make_seed_random(seed_plus_1);
6104 (u1, u2)
6105 };
6106
6107 let greatest = Expression::Greatest(Box::new(VarArgFunc {
6109 expressions: vec![
6110 u1,
6111 Expression::Literal(Box::new(Literal::Number("1e-10".to_string()))),
6112 ],
6113 original_name: None,
6114 inferred_type: None,
6115 }));
6116
6117 let neg2 = Expression::Neg(Box::new(crate::expressions::UnaryOp {
6119 this: Expression::number(2),
6120 inferred_type: None,
6121 }));
6122 let ln_greatest =
6123 Expression::Function(Box::new(Function::new("LN".to_string(), vec![greatest])));
6124 let neg2_times_ln = Expression::Mul(Box::new(BinaryOp {
6125 left: neg2,
6126 right: ln_greatest,
6127 left_comments: Vec::new(),
6128 operator_comments: Vec::new(),
6129 trailing_comments: Vec::new(),
6130 inferred_type: None,
6131 }));
6132 let sqrt_part = Expression::Function(Box::new(Function::new(
6133 "SQRT".to_string(),
6134 vec![neg2_times_ln],
6135 )));
6136
6137 let pi = Expression::Function(Box::new(Function::new("PI".to_string(), vec![])));
6139 let two_pi = Expression::Mul(Box::new(BinaryOp {
6140 left: Expression::number(2),
6141 right: pi,
6142 left_comments: Vec::new(),
6143 operator_comments: Vec::new(),
6144 trailing_comments: Vec::new(),
6145 inferred_type: None,
6146 }));
6147 let two_pi_u2 = if let Expression::Div(div) = u2 {
6148 let numerator = Expression::Mul(Box::new(BinaryOp::new(two_pi, div.left)));
6149 Expression::Div(Box::new(BinaryOp::new(numerator, div.right)))
6150 } else {
6151 Expression::Mul(Box::new(BinaryOp::new(two_pi, u2)))
6152 };
6153 let cos_part = Expression::Function(Box::new(Function::new(
6154 "COS".to_string(),
6155 vec![two_pi_u2],
6156 )));
6157
6158 let stddev_times_sqrt = Expression::Mul(Box::new(BinaryOp {
6160 left: stddev,
6161 right: sqrt_part,
6162 left_comments: Vec::new(),
6163 operator_comments: Vec::new(),
6164 trailing_comments: Vec::new(),
6165 inferred_type: None,
6166 }));
6167 let inner = Expression::Mul(Box::new(BinaryOp {
6168 left: stddev_times_sqrt,
6169 right: cos_part,
6170 left_comments: Vec::new(),
6171 operator_comments: Vec::new(),
6172 trailing_comments: Vec::new(),
6173 inferred_type: None,
6174 }));
6175 let paren_inner = Expression::Paren(Box::new(Paren {
6176 this: inner,
6177 trailing_comments: Vec::new(),
6178 }));
6179
6180 Ok(Expression::Add(Box::new(BinaryOp {
6182 left: mean,
6183 right: paren_inner,
6184 left_comments: Vec::new(),
6185 operator_comments: Vec::new(),
6186 trailing_comments: Vec::new(),
6187 inferred_type: None,
6188 })))
6189 }
6190
6191 "ZIPF" if f.args.len() == 3 => {
6201 let mut args = f.args;
6202 let s_expr = args.remove(0);
6203 let n_expr = args.remove(0);
6204 let gen_expr = args.remove(0);
6205
6206 let s_sql = Self::expr_to_sql(&s_expr);
6207 let n_sql = Self::expr_to_sql(&n_expr);
6208 let (seed_sql, is_random) = Self::extract_seed_info(&gen_expr);
6209
6210 let rand_sql = if is_random {
6211 format!("SELECT {} AS r", seed_sql)
6212 } else {
6213 format!(
6214 "SELECT (ABS(HASH({})) % 1000000) / 1000000.0 AS r",
6215 seed_sql
6216 )
6217 };
6218
6219 let template = format!(
6220 "WITH rand AS ({}), weights AS (SELECT i, 1.0 / POWER(i, {}) AS w FROM RANGE(1, {} + 1) AS t(i)), cdf AS (SELECT i, SUM(w) OVER (ORDER BY i NULLS FIRST) / SUM(w) OVER () AS p FROM weights) SELECT MIN(i) FROM cdf WHERE p >= (SELECT r FROM rand)",
6221 rand_sql, s_sql, n_sql
6222 );
6223
6224 Self::parse_as_subquery(&template)
6225 }
6226
6227 "RANDSTR" if f.args.len() == 2 => {
6229 let mut args = f.args;
6230 let len_expr = args.remove(0);
6231 let gen_expr = args.remove(0);
6232
6233 let len_sql = Self::expr_to_sql(&len_expr);
6234 let (seed_sql, is_random) = Self::extract_seed_info(&gen_expr);
6235
6236 let random_value_sql = if is_random {
6237 format!("(ABS(HASH(i + {})) % 1000) / 1000.0", seed_sql)
6238 } else {
6239 format!("(ABS(HASH(i + {})) % 1000) / 1000.0", seed_sql)
6240 };
6241
6242 let template = format!(
6243 "SELECT LISTAGG(SUBSTRING('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 1 + CAST(FLOOR(random_value * 62) AS INT), 1), '') FROM (SELECT {} AS random_value FROM RANGE({}) AS t(i))",
6244 random_value_sql, len_sql
6245 );
6246
6247 Self::parse_as_subquery(&template)
6248 }
6249
6250 "MAP_CAT" if f.args.len() == 2 => {
6252 let mut args = f.args;
6253 let left = Self::normalize_empty_map_expr(args.remove(0));
6254 let right = Self::normalize_empty_map_expr(args.remove(0));
6255 let left_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
6256 this: left.clone(),
6257 not: false,
6258 postfix_form: false,
6259 }));
6260 let right_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
6261 this: right.clone(),
6262 not: false,
6263 postfix_form: false,
6264 }));
6265 let null_cond = Expression::Or(Box::new(BinaryOp {
6266 left: left_is_null,
6267 right: right_is_null,
6268 left_comments: Vec::new(),
6269 operator_comments: Vec::new(),
6270 trailing_comments: Vec::new(),
6271 inferred_type: None,
6272 }));
6273
6274 let list_concat = Expression::Function(Box::new(Function::new(
6275 "LIST_CONCAT".to_string(),
6276 vec![
6277 Expression::Function(Box::new(Function::new(
6278 "MAP_KEYS".to_string(),
6279 vec![left.clone()],
6280 ))),
6281 Expression::Function(Box::new(Function::new(
6282 "MAP_KEYS".to_string(),
6283 vec![right.clone()],
6284 ))),
6285 ],
6286 )));
6287 let list_distinct = Expression::Function(Box::new(Function::new(
6288 "LIST_DISTINCT".to_string(),
6289 vec![list_concat],
6290 )));
6291
6292 let k_ident = Identifier::new("__k");
6293 let k_ref = Expression::boxed_column(Column {
6294 table: None,
6295 name: k_ident.clone(),
6296 join_mark: false,
6297 trailing_comments: Vec::new(),
6298 span: None,
6299 inferred_type: None,
6300 });
6301 let right_key = Expression::Subscript(Box::new(crate::expressions::Subscript {
6302 this: right.clone(),
6303 index: k_ref.clone(),
6304 }));
6305 let left_key = Expression::Subscript(Box::new(crate::expressions::Subscript {
6306 this: left.clone(),
6307 index: k_ref.clone(),
6308 }));
6309 let key_value = Expression::Coalesce(Box::new(VarArgFunc {
6310 expressions: vec![right_key, left_key],
6311 original_name: None,
6312 inferred_type: None,
6313 }));
6314 let struct_pack = Expression::Function(Box::new(Function::new(
6315 "STRUCT_PACK".to_string(),
6316 vec![
6317 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
6318 name: Identifier::new("key"),
6319 value: k_ref.clone(),
6320 separator: crate::expressions::NamedArgSeparator::ColonEq,
6321 })),
6322 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
6323 name: Identifier::new("value"),
6324 value: key_value,
6325 separator: crate::expressions::NamedArgSeparator::ColonEq,
6326 })),
6327 ],
6328 )));
6329 let lambda_k = Expression::Lambda(Box::new(crate::expressions::LambdaExpr {
6330 parameters: vec![k_ident],
6331 body: struct_pack,
6332 colon: false,
6333 parameter_types: Vec::new(),
6334 }));
6335
6336 let list_transform = Expression::Function(Box::new(Function::new(
6337 "LIST_TRANSFORM".to_string(),
6338 vec![list_distinct, lambda_k],
6339 )));
6340
6341 let x_ident = Identifier::new("__x");
6342 let x_ref = Expression::boxed_column(Column {
6343 table: None,
6344 name: x_ident.clone(),
6345 join_mark: false,
6346 trailing_comments: Vec::new(),
6347 span: None,
6348 inferred_type: None,
6349 });
6350 let x_value = Expression::Dot(Box::new(crate::expressions::DotAccess {
6351 this: x_ref,
6352 field: Identifier::new("value"),
6353 inferred_type: None,
6354 }));
6355 let x_value_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
6356 this: x_value,
6357 not: false,
6358 postfix_form: false,
6359 }));
6360 let lambda_x = Expression::Lambda(Box::new(crate::expressions::LambdaExpr {
6361 parameters: vec![x_ident],
6362 body: Expression::Not(Box::new(crate::expressions::UnaryOp {
6363 this: x_value_is_null,
6364 inferred_type: None,
6365 })),
6366 colon: false,
6367 parameter_types: Vec::new(),
6368 }));
6369
6370 let list_filter = Expression::Function(Box::new(Function::new(
6371 "LIST_FILTER".to_string(),
6372 vec![list_transform, lambda_x],
6373 )));
6374 let merged_map = Expression::Function(Box::new(Function::new(
6375 "MAP_FROM_ENTRIES".to_string(),
6376 vec![list_filter],
6377 )));
6378
6379 Ok(Expression::Case(Box::new(Case {
6380 operand: None,
6381 whens: vec![(null_cond, Expression::Null(crate::expressions::Null))],
6382 else_: Some(merged_map),
6383 comments: Vec::new(),
6384 inferred_type: None,
6385 })))
6386 }
6387
6388 "MINHASH" if f.args.len() == 2 => {
6390 let mut args = f.args;
6391 let num_perm = args.remove(0);
6392 let value = args.remove(0);
6393
6394 let num_perm_sql = Self::expr_to_sql(&num_perm);
6395 let value_sql = Self::expr_to_sql(&value);
6396
6397 let template = format!(
6398 "SELECT JSON_OBJECT('state', LIST(min_h ORDER BY seed NULLS FIRST), 'type', 'minhash', 'version', 1) FROM (SELECT seed, LIST_MIN(LIST_TRANSFORM(vals, __v -> HASH(CAST(__v AS TEXT) || CAST(seed AS TEXT)))) AS min_h FROM (SELECT LIST({value}) AS vals), RANGE(0, {num_perm}) AS t(seed))",
6399 value = value_sql,
6400 num_perm = num_perm_sql
6401 );
6402
6403 Self::parse_as_subquery(&template)
6404 }
6405
6406 "MINHASH_COMBINE" if f.args.len() == 1 => {
6408 let sig_sql = Self::expr_to_sql(&f.args[0]);
6409 let template = format!(
6410 "SELECT JSON_OBJECT('state', LIST(min_h ORDER BY idx NULLS FIRST), 'type', 'minhash', 'version', 1) FROM (SELECT pos AS idx, MIN(val) AS min_h FROM UNNEST(LIST({sig})) AS _(sig) JOIN UNNEST(CAST(sig -> '$.state' AS UBIGINT[])) WITH ORDINALITY AS t(val, pos) ON TRUE GROUP BY pos)",
6411 sig = sig_sql
6412 );
6413 Self::parse_as_subquery(&template)
6414 }
6415
6416 "APPROXIMATE_SIMILARITY" if f.args.len() == 1 => {
6418 let sig_sql = Self::expr_to_sql(&f.args[0]);
6419 let template = format!(
6420 "SELECT CAST(SUM(CASE WHEN num_distinct = 1 THEN 1 ELSE 0 END) AS DOUBLE) / COUNT(*) FROM (SELECT pos, COUNT(DISTINCT h) AS num_distinct FROM (SELECT h, pos FROM UNNEST(LIST({sig})) AS _(sig) JOIN UNNEST(CAST(sig -> '$.state' AS UBIGINT[])) WITH ORDINALITY AS s(h, pos) ON TRUE) GROUP BY pos)",
6421 sig = sig_sql
6422 );
6423 Self::parse_as_subquery(&template)
6424 }
6425
6426 "ARRAYS_ZIP" if !f.args.is_empty() => {
6428 let args = f.args;
6429 let n = args.len();
6430 let is_null = |expr: Expression| {
6431 Expression::IsNull(Box::new(crate::expressions::IsNull {
6432 this: expr,
6433 not: false,
6434 postfix_form: false,
6435 }))
6436 };
6437 let length_of = |expr: Expression| {
6438 Expression::Function(Box::new(Function::new("LENGTH".to_string(), vec![expr])))
6439 };
6440 let eq_zero = |expr: Expression| {
6441 Expression::Eq(Box::new(BinaryOp {
6442 left: expr,
6443 right: Expression::number(0),
6444 left_comments: Vec::new(),
6445 operator_comments: Vec::new(),
6446 trailing_comments: Vec::new(),
6447 inferred_type: None,
6448 }))
6449 };
6450 let and_expr = |left: Expression, right: Expression| {
6451 Expression::And(Box::new(BinaryOp {
6452 left,
6453 right,
6454 left_comments: Vec::new(),
6455 operator_comments: Vec::new(),
6456 trailing_comments: Vec::new(),
6457 inferred_type: None,
6458 }))
6459 };
6460 let or_expr = |left: Expression, right: Expression| {
6461 Expression::Or(Box::new(BinaryOp {
6462 left,
6463 right,
6464 left_comments: Vec::new(),
6465 operator_comments: Vec::new(),
6466 trailing_comments: Vec::new(),
6467 inferred_type: None,
6468 }))
6469 };
6470
6471 let null_cond = args.iter().cloned().map(is_null).reduce(or_expr).unwrap();
6472 let empty_cond = args
6473 .iter()
6474 .cloned()
6475 .map(|a| eq_zero(length_of(a)))
6476 .reduce(and_expr)
6477 .unwrap();
6478
6479 let null_struct = Expression::Struct(Box::new(Struct {
6480 fields: (1..=n)
6481 .map(|i| {
6482 (
6483 Some(format!("${}", i)),
6484 Expression::Null(crate::expressions::Null),
6485 )
6486 })
6487 .collect(),
6488 }));
6489 let empty_result = Expression::Array(Box::new(crate::expressions::Array {
6490 expressions: vec![null_struct],
6491 inferred_type: None,
6492 }));
6493
6494 let range_upper = if n == 1 {
6495 length_of(args[0].clone())
6496 } else {
6497 let length_null_cond = args
6498 .iter()
6499 .cloned()
6500 .map(|a| is_null(length_of(a)))
6501 .reduce(or_expr)
6502 .unwrap();
6503 let greatest_len = Expression::Greatest(Box::new(VarArgFunc {
6504 expressions: args.iter().cloned().map(length_of).collect(),
6505 original_name: None,
6506 inferred_type: None,
6507 }));
6508 Expression::Case(Box::new(Case {
6509 operand: None,
6510 whens: vec![(length_null_cond, Expression::Null(crate::expressions::Null))],
6511 else_: Some(greatest_len),
6512 comments: Vec::new(),
6513 inferred_type: None,
6514 }))
6515 };
6516
6517 let range_expr = Expression::Function(Box::new(Function::new(
6518 "RANGE".to_string(),
6519 vec![Expression::number(0), range_upper],
6520 )));
6521
6522 let i_ident = Identifier::new("__i");
6523 let i_ref = Expression::boxed_column(Column {
6524 table: None,
6525 name: i_ident.clone(),
6526 join_mark: false,
6527 trailing_comments: Vec::new(),
6528 span: None,
6529 inferred_type: None,
6530 });
6531 let i_plus_one = Expression::Add(Box::new(BinaryOp {
6532 left: i_ref,
6533 right: Expression::number(1),
6534 left_comments: Vec::new(),
6535 operator_comments: Vec::new(),
6536 trailing_comments: Vec::new(),
6537 inferred_type: None,
6538 }));
6539 let empty_array = Expression::Array(Box::new(crate::expressions::Array {
6540 expressions: vec![],
6541 inferred_type: None,
6542 }));
6543 let zipped_struct = Expression::Struct(Box::new(Struct {
6544 fields: args
6545 .iter()
6546 .enumerate()
6547 .map(|(i, a)| {
6548 let coalesced = Expression::Coalesce(Box::new(VarArgFunc {
6549 expressions: vec![a.clone(), empty_array.clone()],
6550 original_name: None,
6551 inferred_type: None,
6552 }));
6553 let item =
6554 Expression::Subscript(Box::new(crate::expressions::Subscript {
6555 this: coalesced,
6556 index: i_plus_one.clone(),
6557 }));
6558 (Some(format!("${}", i + 1)), item)
6559 })
6560 .collect(),
6561 }));
6562 let lambda_i = Expression::Lambda(Box::new(crate::expressions::LambdaExpr {
6563 parameters: vec![i_ident],
6564 body: zipped_struct,
6565 colon: false,
6566 parameter_types: Vec::new(),
6567 }));
6568 let zipped_result = Expression::Function(Box::new(Function::new(
6569 "LIST_TRANSFORM".to_string(),
6570 vec![range_expr, lambda_i],
6571 )));
6572
6573 Ok(Expression::Case(Box::new(Case {
6574 operand: None,
6575 whens: vec![
6576 (null_cond, Expression::Null(crate::expressions::Null)),
6577 (empty_cond, empty_result),
6578 ],
6579 else_: Some(zipped_result),
6580 comments: Vec::new(),
6581 inferred_type: None,
6582 })))
6583 }
6584
6585 "STRTOK" if f.args.len() == 3 => {
6589 let mut args = f.args.into_iter();
6590 let str_arg = args.next().unwrap();
6591 let delim_arg = args.next().unwrap();
6592 let pos_arg = args.next().unwrap();
6593
6594 let empty_str = || Expression::string("".to_string());
6596 let null_expr = || Expression::Null(crate::expressions::Null);
6598
6599 let when1_cond = Expression::And(Box::new(BinaryOp::new(
6601 Expression::Eq(Box::new(BinaryOp::new(delim_arg.clone(), empty_str()))),
6602 Expression::Eq(Box::new(BinaryOp::new(str_arg.clone(), empty_str()))),
6603 )));
6604
6605 let when2_cond = Expression::And(Box::new(BinaryOp::new(
6607 Expression::Eq(Box::new(BinaryOp::new(delim_arg.clone(), empty_str()))),
6608 Expression::Eq(Box::new(BinaryOp::new(
6609 pos_arg.clone(),
6610 Expression::number(1),
6611 ))),
6612 )));
6613
6614 let when3_cond =
6616 Expression::Eq(Box::new(BinaryOp::new(delim_arg.clone(), empty_str())));
6617
6618 let when4_cond = Expression::Lt(Box::new(BinaryOp::new(
6620 pos_arg.clone(),
6621 Expression::number(0),
6622 )));
6623
6624 let str_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
6626 this: str_arg.clone(),
6627 not: false,
6628 postfix_form: false,
6629 }));
6630 let delim_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
6631 this: delim_arg.clone(),
6632 not: false,
6633 postfix_form: false,
6634 }));
6635 let pos_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
6636 this: pos_arg.clone(),
6637 not: false,
6638 postfix_form: false,
6639 }));
6640 let when5_cond = Expression::Or(Box::new(BinaryOp::new(
6641 Expression::Or(Box::new(BinaryOp::new(str_is_null, delim_is_null))),
6642 pos_is_null,
6643 )));
6644
6645 let regex_replace = Expression::Function(Box::new(Function::new(
6650 "REGEXP_REPLACE".to_string(),
6651 vec![
6652 delim_arg.clone(),
6653 Expression::string(r"([\[\]^.\-*+?(){}|$\\])".to_string()),
6654 Expression::string(r"\\\1".to_string()),
6655 Expression::string("g".to_string()),
6656 ],
6657 )));
6658
6659 let concat_regex = Expression::DPipe(Box::new(crate::expressions::DPipe {
6661 this: Box::new(Expression::DPipe(Box::new(crate::expressions::DPipe {
6662 this: Box::new(Expression::string("[".to_string())),
6663 expression: Box::new(regex_replace),
6664 safe: None,
6665 }))),
6666 expression: Box::new(Expression::string("]".to_string())),
6667 safe: None,
6668 }));
6669
6670 let inner_case = Expression::Case(Box::new(Case {
6671 operand: None,
6672 whens: vec![(
6673 Expression::Eq(Box::new(BinaryOp::new(delim_arg.clone(), empty_str()))),
6674 empty_str(),
6675 )],
6676 else_: Some(concat_regex),
6677 comments: Vec::new(),
6678 inferred_type: None,
6679 }));
6680
6681 let regexp_split = Expression::Function(Box::new(Function::new(
6683 "REGEXP_SPLIT_TO_ARRAY".to_string(),
6684 vec![str_arg.clone(), inner_case],
6685 )));
6686
6687 let lambda = Expression::Lambda(Box::new(crate::expressions::LambdaExpr {
6689 parameters: vec![Identifier::new("x".to_string())],
6690 body: Expression::Not(Box::new(crate::expressions::UnaryOp {
6691 this: Expression::Eq(Box::new(BinaryOp::new(
6692 Expression::boxed_column(Column {
6693 table: None,
6694 name: Identifier::new("x".to_string()),
6695 join_mark: false,
6696 trailing_comments: Vec::new(),
6697 span: None,
6698 inferred_type: None,
6699 }),
6700 empty_str(),
6701 ))),
6702 inferred_type: None,
6703 })),
6704 colon: false,
6705 parameter_types: Vec::new(),
6706 }));
6707
6708 let list_filter = Expression::Function(Box::new(Function::new(
6710 "LIST_FILTER".to_string(),
6711 vec![regexp_split, lambda],
6712 )));
6713
6714 let subscripted = Expression::Subscript(Box::new(crate::expressions::Subscript {
6716 this: list_filter,
6717 index: pos_arg.clone(),
6718 }));
6719
6720 Ok(Expression::Case(Box::new(Case {
6721 operand: None,
6722 whens: vec![
6723 (when1_cond, null_expr()),
6724 (when2_cond, str_arg.clone()),
6725 (when3_cond, null_expr()),
6726 (when4_cond, null_expr()),
6727 (when5_cond, null_expr()),
6728 ],
6729 else_: Some(subscripted),
6730 comments: Vec::new(),
6731 inferred_type: None,
6732 })))
6733 }
6734
6735 _ => Ok(Expression::Function(Box::new(f))),
6737 }
6738 }
6739
6740 fn convert_snowflake_date_format(&self, fmt: Expression) -> Expression {
6742 match fmt {
6743 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
6744 let Literal::String(s) = lit.as_ref() else {
6745 unreachable!()
6746 };
6747 let converted = Self::snowflake_to_strptime(&s);
6748 Expression::Literal(Box::new(Literal::String(converted)))
6749 }
6750 _ => fmt,
6751 }
6752 }
6753
6754 fn convert_snowflake_time_format(&self, fmt: Expression) -> Expression {
6756 match fmt {
6757 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
6758 let Literal::String(s) = lit.as_ref() else {
6759 unreachable!()
6760 };
6761 let converted = Self::snowflake_to_strptime(&s);
6762 Expression::Literal(Box::new(Literal::String(converted)))
6763 }
6764 _ => fmt,
6765 }
6766 }
6767
6768 fn snowflake_to_strptime(s: &str) -> String {
6771 let mut result = String::new();
6772 let mut cursor = crate::format_tokens::FormatTokenCursor::new(s);
6773 while let Some(ch) = cursor.peek() {
6774 if cursor.consume_prefix("HH24MISS", true) {
6776 result.push_str("%H%M%S");
6777 } else if cursor.consume_prefix("MMMM", true) {
6778 result.push_str("%B");
6779 } else if cursor.consume_prefix("YYYY", true) {
6780 result.push_str("%Y");
6781 } else if cursor.consume_prefix("YY", true) {
6782 result.push_str("%y");
6783 } else if cursor.consume_prefix("MON", true) {
6784 result.push_str("%b");
6785 } else if cursor.consume_prefix("HH24", true) {
6786 result.push_str("%H");
6787 } else if cursor.consume_prefix("HH12", true) {
6788 result.push_str("%I");
6789 } else if cursor.consume_prefix("HH", true) {
6790 result.push_str("%I");
6791 } else if cursor.consume_prefix("MISS", true) {
6792 result.push_str("%M%S");
6793 } else if cursor.consume_prefix("MI", true) {
6794 result.push_str("%M");
6795 } else if cursor.consume_prefix("MM", true) {
6796 result.push_str("%m");
6797 } else if cursor.consume_prefix("DD", true) {
6798 result.push_str("%d");
6799 } else if cursor.consume_prefix("DY", true) {
6800 result.push_str("%a");
6801 } else if cursor.consume_prefix("SS", true) {
6802 result.push_str("%S");
6803 } else if cursor.consume_prefix("FF", true) {
6804 if let Some(digit) = cursor.peek().filter(|c| c.is_ascii_digit()) {
6807 result.push_str(if digit >= '7' { "%n" } else { "%f" });
6808 cursor.next_char();
6809 } else {
6810 result.push_str("%f");
6811 }
6812 } else if cursor.consume_prefix("PM", true) || cursor.consume_prefix("AM", true) {
6813 result.push_str("%p");
6814 } else if cursor.consume_prefix("TZH", true) {
6815 result.push_str("%z");
6816 } else if cursor.consume_prefix("TZM", true) {
6817 } else {
6819 result.push(ch);
6820 cursor.next_char();
6821 }
6822 }
6823 result
6824 }
6825
6826 fn convert_bq_to_strptime_format(&self, fmt: Expression) -> Expression {
6829 match fmt {
6830 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
6831 let Literal::String(s) = lit.as_ref() else {
6832 unreachable!()
6833 };
6834 let converted = s.replace("%E6S", "%S.%f").replace("%E*S", "%S.%f");
6835 Expression::Literal(Box::new(Literal::String(converted)))
6836 }
6837 _ => fmt,
6838 }
6839 }
6840
6841 fn transform_date_part(&self, args: Vec<Expression>) -> Result<Expression> {
6843 let mut args = args;
6844 let unit_expr = args.remove(0);
6845 let date_expr = args.remove(0);
6846 let unit_name = match &unit_expr {
6847 Expression::Column(c) => c.name.name.to_uppercase(),
6848 Expression::Identifier(i) => i.name.to_uppercase(),
6849 Expression::Var(v) => v.this.to_uppercase(),
6850 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
6851 let Literal::String(s) = lit.as_ref() else {
6852 unreachable!()
6853 };
6854 s.to_uppercase()
6855 }
6856 _ => {
6857 return Ok(Expression::Function(Box::new(Function::new(
6858 "DATE_PART".to_string(),
6859 vec![unit_expr, date_expr],
6860 ))))
6861 }
6862 };
6863 match unit_name.as_str() {
6864 "EPOCH_SECOND" | "EPOCH" => Ok(Expression::Cast(Box::new(Cast {
6865 this: Expression::Function(Box::new(Function::new(
6866 "EPOCH".to_string(),
6867 vec![date_expr],
6868 ))),
6869 to: DataType::BigInt { length: None },
6870 trailing_comments: Vec::new(),
6871 double_colon_syntax: false,
6872 format: None,
6873 default: None,
6874 inferred_type: None,
6875 }))),
6876 "EPOCH_MILLISECOND" | "EPOCH_MILLISECONDS" => Ok(Expression::Function(Box::new(
6877 Function::new("EPOCH_MS".to_string(), vec![date_expr]),
6878 ))),
6879 "EPOCH_MICROSECOND" | "EPOCH_MICROSECONDS" => Ok(Expression::Function(Box::new(
6880 Function::new("EPOCH_US".to_string(), vec![date_expr]),
6881 ))),
6882 "EPOCH_NANOSECOND" | "EPOCH_NANOSECONDS" => Ok(Expression::Function(Box::new(
6883 Function::new("EPOCH_NS".to_string(), vec![date_expr]),
6884 ))),
6885 "DAYOFWEEKISO" | "DAYOFWEEK_ISO" => Ok(Expression::Extract(Box::new(
6886 crate::expressions::ExtractFunc {
6887 this: date_expr,
6888 field: crate::expressions::DateTimeField::Custom("ISODOW".to_string()),
6889 },
6890 ))),
6891 "YEAROFWEEK" | "YEAROFWEEKISO" => Ok(Expression::Cast(Box::new(Cast {
6892 this: Expression::Function(Box::new(Function::new(
6893 "STRFTIME".to_string(),
6894 vec![
6895 date_expr,
6896 Expression::Literal(Box::new(Literal::String("%G".to_string()))),
6897 ],
6898 ))),
6899 to: DataType::Int {
6900 length: None,
6901 integer_spelling: false,
6902 },
6903 trailing_comments: Vec::new(),
6904 double_colon_syntax: false,
6905 format: None,
6906 default: None,
6907 inferred_type: None,
6908 }))),
6909 "WEEKISO" => Ok(Expression::Cast(Box::new(Cast {
6910 this: Expression::Function(Box::new(Function::new(
6911 "STRFTIME".to_string(),
6912 vec![
6913 date_expr,
6914 Expression::Literal(Box::new(Literal::String("%V".to_string()))),
6915 ],
6916 ))),
6917 to: DataType::Int {
6918 length: None,
6919 integer_spelling: false,
6920 },
6921 trailing_comments: Vec::new(),
6922 double_colon_syntax: false,
6923 format: None,
6924 default: None,
6925 inferred_type: None,
6926 }))),
6927 "NANOSECOND" | "NANOSECONDS" | "NS" => Ok(Expression::Cast(Box::new(Cast {
6928 this: Expression::Function(Box::new(Function::new(
6929 "STRFTIME".to_string(),
6930 vec![
6931 Expression::Cast(Box::new(Cast {
6932 this: date_expr,
6933 to: DataType::Custom {
6934 name: "TIMESTAMP_NS".to_string(),
6935 },
6936 trailing_comments: Vec::new(),
6937 double_colon_syntax: false,
6938 format: None,
6939 default: None,
6940 inferred_type: None,
6941 })),
6942 Expression::Literal(Box::new(Literal::String("%n".to_string()))),
6943 ],
6944 ))),
6945 to: DataType::BigInt { length: None },
6946 trailing_comments: Vec::new(),
6947 double_colon_syntax: false,
6948 format: None,
6949 default: None,
6950 inferred_type: None,
6951 }))),
6952 "DAYOFMONTH" => Ok(Expression::Extract(Box::new(
6953 crate::expressions::ExtractFunc {
6954 this: date_expr,
6955 field: crate::expressions::DateTimeField::Day,
6956 },
6957 ))),
6958 _ => {
6959 let field = match unit_name.as_str() {
6960 "YEAR" | "YY" | "YYYY" => crate::expressions::DateTimeField::Year,
6961 "MONTH" | "MON" | "MM" => crate::expressions::DateTimeField::Month,
6962 "DAY" | "DD" | "D" => crate::expressions::DateTimeField::Day,
6963 "HOUR" | "HH" => crate::expressions::DateTimeField::Hour,
6964 "MINUTE" | "MI" | "MIN" => crate::expressions::DateTimeField::Minute,
6965 "SECOND" | "SEC" | "SS" => crate::expressions::DateTimeField::Second,
6966 "MILLISECOND" | "MS" => crate::expressions::DateTimeField::Millisecond,
6967 "MICROSECOND" | "US" => crate::expressions::DateTimeField::Microsecond,
6968 "QUARTER" | "QTR" => crate::expressions::DateTimeField::Quarter,
6969 "WEEK" | "WK" => crate::expressions::DateTimeField::Week,
6970 "DAYOFWEEK" | "DOW" => crate::expressions::DateTimeField::DayOfWeek,
6971 "DAYOFYEAR" | "DOY" => crate::expressions::DateTimeField::DayOfYear,
6972 "TIMEZONE_HOUR" => crate::expressions::DateTimeField::TimezoneHour,
6973 "TIMEZONE_MINUTE" => crate::expressions::DateTimeField::TimezoneMinute,
6974 _ => crate::expressions::DateTimeField::Custom(unit_name),
6975 };
6976 Ok(Expression::Extract(Box::new(
6977 crate::expressions::ExtractFunc {
6978 this: date_expr,
6979 field,
6980 },
6981 )))
6982 }
6983 }
6984 }
6985
6986 fn transform_dateadd(&self, args: Vec<Expression>) -> Result<Expression> {
6988 let mut args = args;
6989 let unit_expr = args.remove(0);
6990 let amount = args.remove(0);
6991 let date = args.remove(0);
6992 let unit_name = match &unit_expr {
6993 Expression::Column(c) => c.name.name.to_uppercase(),
6994 Expression::Identifier(i) => i.name.to_uppercase(),
6995 Expression::Var(v) => v.this.to_uppercase(),
6996 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
6997 let Literal::String(s) = lit.as_ref() else {
6998 unreachable!()
6999 };
7000 s.to_uppercase()
7001 }
7002 _ => String::new(),
7003 };
7004 if unit_name == "NANOSECOND" || unit_name == "NS" {
7005 let epoch_ns = Expression::Function(Box::new(Function::new(
7006 "EPOCH_NS".to_string(),
7007 vec![Expression::Cast(Box::new(Cast {
7008 this: date,
7009 to: DataType::Custom {
7010 name: "TIMESTAMP_NS".to_string(),
7011 },
7012 trailing_comments: Vec::new(),
7013 double_colon_syntax: false,
7014 format: None,
7015 default: None,
7016 inferred_type: None,
7017 }))],
7018 )));
7019 return Ok(Expression::Function(Box::new(Function::new(
7020 "MAKE_TIMESTAMP_NS".to_string(),
7021 vec![Expression::Add(Box::new(BinaryOp {
7022 left: epoch_ns,
7023 right: amount,
7024 left_comments: Vec::new(),
7025 operator_comments: Vec::new(),
7026 trailing_comments: Vec::new(),
7027 inferred_type: None,
7028 }))],
7029 ))));
7030 }
7031 let (interval_unit, multiplied_amount) = match unit_name.as_str() {
7032 "YEAR" | "YY" | "YYYY" => (IntervalUnit::Year, amount),
7033 "MONTH" | "MON" | "MM" => (IntervalUnit::Month, amount),
7034 "DAY" | "DD" | "D" => (IntervalUnit::Day, amount),
7035 "HOUR" | "HH" => (IntervalUnit::Hour, amount),
7036 "MINUTE" | "MI" | "MIN" => (IntervalUnit::Minute, amount),
7037 "SECOND" | "SEC" | "SS" => (IntervalUnit::Second, amount),
7038 "MILLISECOND" | "MS" => (IntervalUnit::Millisecond, amount),
7039 "MICROSECOND" | "US" => (IntervalUnit::Microsecond, amount),
7040 "WEEK" | "WK" => (
7041 IntervalUnit::Day,
7042 Expression::Mul(Box::new(BinaryOp {
7043 left: amount,
7044 right: Expression::number(7),
7045 left_comments: Vec::new(),
7046 operator_comments: Vec::new(),
7047 trailing_comments: Vec::new(),
7048 inferred_type: None,
7049 })),
7050 ),
7051 "QUARTER" | "QTR" => (
7052 IntervalUnit::Month,
7053 Expression::Mul(Box::new(BinaryOp {
7054 left: amount,
7055 right: Expression::number(3),
7056 left_comments: Vec::new(),
7057 operator_comments: Vec::new(),
7058 trailing_comments: Vec::new(),
7059 inferred_type: None,
7060 })),
7061 ),
7062 _ => (IntervalUnit::Day, amount),
7063 };
7064 Ok(Expression::Add(Box::new(BinaryOp {
7065 left: date,
7066 right: Expression::Interval(Box::new(Interval {
7067 this: Some(multiplied_amount),
7068 unit: Some(IntervalUnitSpec::Simple {
7069 unit: interval_unit,
7070 use_plural: false,
7071 }),
7072 })),
7073 left_comments: Vec::new(),
7074 operator_comments: Vec::new(),
7075 trailing_comments: Vec::new(),
7076 inferred_type: None,
7077 })))
7078 }
7079
7080 fn transform_datediff(&self, args: Vec<Expression>) -> Result<Expression> {
7082 let mut args = args;
7083 let unit_expr = args.remove(0);
7084 let start = args.remove(0);
7085 let end = args.remove(0);
7086 let unit_name = match &unit_expr {
7087 Expression::Column(c) => c.name.name.to_uppercase(),
7088 Expression::Identifier(i) => i.name.to_uppercase(),
7089 Expression::Var(v) => v.this.to_uppercase(),
7090 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
7091 let Literal::String(s) = lit.as_ref() else {
7092 unreachable!()
7093 };
7094 s.to_uppercase()
7095 }
7096 _ => String::new(),
7097 };
7098 if unit_name == "NANOSECOND" || unit_name == "NS" {
7099 let epoch_end = Expression::Function(Box::new(Function::new(
7100 "EPOCH_NS".to_string(),
7101 vec![Expression::Cast(Box::new(Cast {
7102 this: end,
7103 to: DataType::Custom {
7104 name: "TIMESTAMP_NS".to_string(),
7105 },
7106 trailing_comments: Vec::new(),
7107 double_colon_syntax: false,
7108 format: None,
7109 default: None,
7110 inferred_type: None,
7111 }))],
7112 )));
7113 let epoch_start = Expression::Function(Box::new(Function::new(
7114 "EPOCH_NS".to_string(),
7115 vec![Expression::Cast(Box::new(Cast {
7116 this: start,
7117 to: DataType::Custom {
7118 name: "TIMESTAMP_NS".to_string(),
7119 },
7120 trailing_comments: Vec::new(),
7121 double_colon_syntax: false,
7122 format: None,
7123 default: None,
7124 inferred_type: None,
7125 }))],
7126 )));
7127 return Ok(Expression::Sub(Box::new(BinaryOp {
7128 left: epoch_end,
7129 right: epoch_start,
7130 left_comments: Vec::new(),
7131 operator_comments: Vec::new(),
7132 trailing_comments: Vec::new(),
7133 inferred_type: None,
7134 })));
7135 }
7136 if unit_name == "WEEK" || unit_name == "WK" {
7137 let trunc_start = Expression::Function(Box::new(Function::new(
7138 "DATE_TRUNC".to_string(),
7139 vec![
7140 Expression::Literal(Box::new(Literal::String("WEEK".to_string()))),
7141 Expression::Cast(Box::new(Cast {
7142 this: start,
7143 to: DataType::Date,
7144 trailing_comments: Vec::new(),
7145 double_colon_syntax: false,
7146 format: None,
7147 default: None,
7148 inferred_type: None,
7149 })),
7150 ],
7151 )));
7152 let trunc_end = Expression::Function(Box::new(Function::new(
7153 "DATE_TRUNC".to_string(),
7154 vec![
7155 Expression::Literal(Box::new(Literal::String("WEEK".to_string()))),
7156 Expression::Cast(Box::new(Cast {
7157 this: end,
7158 to: DataType::Date,
7159 trailing_comments: Vec::new(),
7160 double_colon_syntax: false,
7161 format: None,
7162 default: None,
7163 inferred_type: None,
7164 })),
7165 ],
7166 )));
7167 return Ok(Expression::Function(Box::new(Function::new(
7168 "DATE_DIFF".to_string(),
7169 vec![
7170 Expression::Literal(Box::new(Literal::String("WEEK".to_string()))),
7171 trunc_start,
7172 trunc_end,
7173 ],
7174 ))));
7175 }
7176 let cast_if_string = |e: Expression| -> Expression {
7177 match &e {
7178 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
7179 Expression::Cast(Box::new(Cast {
7180 this: e,
7181 to: DataType::Date,
7182 trailing_comments: Vec::new(),
7183 double_colon_syntax: false,
7184 format: None,
7185 default: None,
7186 inferred_type: None,
7187 }))
7188 }
7189 _ => e,
7190 }
7191 };
7192 let start = cast_if_string(start);
7193 let end = cast_if_string(end);
7194 Ok(Expression::Function(Box::new(Function::new(
7195 "DATE_DIFF".to_string(),
7196 vec![
7197 Expression::Literal(Box::new(Literal::String(unit_name))),
7198 start,
7199 end,
7200 ],
7201 ))))
7202 }
7203
7204 fn transform_aggregate_function(
7205 &self,
7206 f: Box<crate::expressions::AggregateFunction>,
7207 ) -> Result<Expression> {
7208 let name_upper = f.name.to_uppercase();
7209 match name_upper.as_str() {
7210 "LIST"
7215 if f.args.len() == 1
7216 && !f.distinct
7217 && f.filter.is_none()
7218 && f.order_by.is_empty()
7219 && f.limit.is_none()
7220 && f.ignore_nulls.is_none() =>
7221 {
7222 Ok(Expression::Function(Box::new(Function::new(
7223 "ARRAY_AGG".to_string(),
7224 f.args,
7225 ))))
7226 }
7227
7228 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
7230 Function::new("LISTAGG".to_string(), f.args),
7231 ))),
7232
7233 "LISTAGG" => Ok(Expression::AggregateFunction(f)),
7235
7236 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
7238 Function::new("LISTAGG".to_string(), f.args),
7239 ))),
7240
7241 "ARRAY_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
7243 "list".to_string(),
7244 f.args,
7245 )))),
7246
7247 "LOGICAL_OR" if !f.args.is_empty() => {
7249 let arg = f.args.into_iter().next().unwrap();
7250 Ok(Expression::Function(Box::new(Function::new(
7251 "BOOL_OR".to_string(),
7252 vec![Expression::Cast(Box::new(crate::expressions::Cast {
7253 this: arg,
7254 to: crate::expressions::DataType::Boolean,
7255 trailing_comments: Vec::new(),
7256 double_colon_syntax: false,
7257 format: None,
7258 default: None,
7259 inferred_type: None,
7260 }))],
7261 ))))
7262 }
7263
7264 "LOGICAL_AND" if !f.args.is_empty() => {
7266 let arg = f.args.into_iter().next().unwrap();
7267 Ok(Expression::Function(Box::new(Function::new(
7268 "BOOL_AND".to_string(),
7269 vec![Expression::Cast(Box::new(crate::expressions::Cast {
7270 this: arg,
7271 to: crate::expressions::DataType::Boolean,
7272 trailing_comments: Vec::new(),
7273 double_colon_syntax: false,
7274 format: None,
7275 default: None,
7276 inferred_type: None,
7277 }))],
7278 ))))
7279 }
7280
7281 "SKEW" => Ok(Expression::Function(Box::new(Function::new(
7283 "SKEWNESS".to_string(),
7284 f.args,
7285 )))),
7286
7287 "REGR_VALX" if f.args.len() == 2 => {
7289 let mut args = f.args;
7290 let y = args.remove(0);
7291 let x = args.remove(0);
7292 Ok(Expression::Case(Box::new(Case {
7293 operand: None,
7294 whens: vec![(
7295 Expression::IsNull(Box::new(crate::expressions::IsNull {
7296 this: y,
7297 not: false,
7298 postfix_form: false,
7299 })),
7300 Expression::Cast(Box::new(Cast {
7301 this: Expression::Null(crate::expressions::Null),
7302 to: DataType::Double {
7303 precision: None,
7304 scale: None,
7305 },
7306 trailing_comments: Vec::new(),
7307 double_colon_syntax: false,
7308 format: None,
7309 default: None,
7310 inferred_type: None,
7311 })),
7312 )],
7313 else_: Some(x),
7314 comments: Vec::new(),
7315 inferred_type: None,
7316 })))
7317 }
7318
7319 "REGR_VALY" if f.args.len() == 2 => {
7321 let mut args = f.args;
7322 let y = args.remove(0);
7323 let x = args.remove(0);
7324 Ok(Expression::Case(Box::new(Case {
7325 operand: None,
7326 whens: vec![(
7327 Expression::IsNull(Box::new(crate::expressions::IsNull {
7328 this: x,
7329 not: false,
7330 postfix_form: false,
7331 })),
7332 Expression::Cast(Box::new(Cast {
7333 this: Expression::Null(crate::expressions::Null),
7334 to: DataType::Double {
7335 precision: None,
7336 scale: None,
7337 },
7338 trailing_comments: Vec::new(),
7339 double_colon_syntax: false,
7340 format: None,
7341 default: None,
7342 inferred_type: None,
7343 })),
7344 )],
7345 else_: Some(y),
7346 comments: Vec::new(),
7347 inferred_type: None,
7348 })))
7349 }
7350
7351 "BOOLAND_AGG" if !f.args.is_empty() => {
7353 let arg = f.args.into_iter().next().unwrap();
7354 Ok(Expression::Function(Box::new(Function::new(
7355 "BOOL_AND".to_string(),
7356 vec![Expression::Cast(Box::new(Cast {
7357 this: arg,
7358 to: DataType::Boolean,
7359 trailing_comments: Vec::new(),
7360 double_colon_syntax: false,
7361 format: None,
7362 default: None,
7363 inferred_type: None,
7364 }))],
7365 ))))
7366 }
7367
7368 "BOOLOR_AGG" if !f.args.is_empty() => {
7370 let arg = f.args.into_iter().next().unwrap();
7371 Ok(Expression::Function(Box::new(Function::new(
7372 "BOOL_OR".to_string(),
7373 vec![Expression::Cast(Box::new(Cast {
7374 this: arg,
7375 to: DataType::Boolean,
7376 trailing_comments: Vec::new(),
7377 double_colon_syntax: false,
7378 format: None,
7379 default: None,
7380 inferred_type: None,
7381 }))],
7382 ))))
7383 }
7384
7385 "BOOLXOR_AGG" if !f.args.is_empty() => {
7387 let arg = f.args.into_iter().next().unwrap();
7388 Ok(Expression::Eq(Box::new(BinaryOp {
7389 left: Expression::Function(Box::new(Function::new(
7390 "COUNT_IF".to_string(),
7391 vec![Expression::Cast(Box::new(Cast {
7392 this: arg,
7393 to: DataType::Boolean,
7394 trailing_comments: Vec::new(),
7395 double_colon_syntax: false,
7396 format: None,
7397 default: None,
7398 inferred_type: None,
7399 }))],
7400 ))),
7401 right: Expression::number(1),
7402 left_comments: Vec::new(),
7403 operator_comments: Vec::new(),
7404 trailing_comments: Vec::new(),
7405 inferred_type: None,
7406 })))
7407 }
7408
7409 "MAX_BY" if f.args.len() == 2 => Ok(Expression::AggregateFunction(Box::new(
7411 crate::expressions::AggregateFunction {
7412 name: "ARG_MAX".to_string(),
7413 ..(*f)
7414 },
7415 ))),
7416
7417 "MIN_BY" if f.args.len() == 2 => Ok(Expression::AggregateFunction(Box::new(
7419 crate::expressions::AggregateFunction {
7420 name: "ARG_MIN".to_string(),
7421 ..(*f)
7422 },
7423 ))),
7424
7425 "CORR" if f.args.len() == 2 => Ok(Expression::AggregateFunction(f)),
7427
7428 "BITMAP_CONSTRUCT_AGG" if f.args.len() == 1 => {
7430 let v_sql = Self::expr_to_sql(&f.args[0]);
7431
7432 let template = format!(
7433 "SELECT CASE WHEN l IS NULL OR LENGTH(l) = 0 THEN NULL WHEN LENGTH(l) <> LENGTH(LIST_FILTER(l, __v -> __v BETWEEN 0 AND 32767)) THEN NULL WHEN LENGTH(l) < 5 THEN UNHEX(PRINTF('%04X', LENGTH(l)) || h || REPEAT('00', GREATEST(0, 4 - LENGTH(l)) * 2)) ELSE UNHEX('08000000000000000000' || h) END FROM (SELECT l, COALESCE(LIST_REDUCE(LIST_TRANSFORM(l, __x -> PRINTF('%02X%02X', CAST(__x AS INT) & 255, (CAST(__x AS INT) >> 8) & 255)), (__a, __b) -> __a || __b, ''), '') AS h FROM (SELECT LIST_SORT(LIST_DISTINCT(LIST({v}) FILTER(WHERE NOT {v} IS NULL))) AS l))",
7434 v = v_sql
7435 );
7436
7437 Self::parse_as_subquery(&template)
7438 }
7439
7440 _ => Ok(Expression::AggregateFunction(f)),
7442 }
7443 }
7444
7445 fn convert_format_to_duckdb(expr: &Expression) -> Expression {
7449 if let Expression::Literal(lit) = expr {
7450 if let Literal::String(s) = lit.as_ref() {
7451 let duckdb_fmt = Self::presto_to_duckdb_format(s);
7452 Expression::Literal(Box::new(Literal::String(duckdb_fmt)))
7453 } else {
7454 expr.clone()
7455 }
7456 } else {
7457 expr.clone()
7458 }
7459 }
7460
7461 fn presto_to_duckdb_format(fmt: &str) -> String {
7463 let mut result = String::new();
7464 let chars: Vec<char> = fmt.chars().collect();
7465 let mut i = 0;
7466 while i < chars.len() {
7467 if chars[i] == '%' && i + 1 < chars.len() {
7468 match chars[i + 1] {
7469 'i' => {
7470 result.push_str("%M");
7472 i += 2;
7473 }
7474 'T' => {
7475 result.push_str("%H:%M:%S");
7477 i += 2;
7478 }
7479 'F' => {
7480 result.push_str("%Y-%m-%d");
7482 i += 2;
7483 }
7484 _ => {
7485 result.push('%');
7486 result.push(chars[i + 1]);
7487 i += 2;
7488 }
7489 }
7490 } else {
7491 result.push(chars[i]);
7492 i += 1;
7493 }
7494 }
7495 result
7496 }
7497}
7498
7499#[cfg(test)]
7500mod tests {
7501 use super::*;
7502 use crate::dialects::Dialect;
7503 use crate::expressions::JoinKind;
7504
7505 #[test]
7506 fn test_date_time_format_conversion_preserves_unicode() {
7507 for literal in ["é", "年", "🦀", "e\u{301}", "ß", "ſ"] {
7508 assert_eq!(DuckDBDialect::snowflake_to_strptime(literal), literal);
7509 assert_eq!(
7510 DuckDBDialect::snowflake_to_strptime(&format!("{literal}YYYY{literal}mM{literal}")),
7511 format!("{literal}%Y{literal}%m{literal}")
7512 );
7513 }
7514 for (input, expected) in [
7515 ("", ""),
7516 (
7517 "HH24MISS MMMM YYYY YY MON HH24 HH12 HH MISS MI MM DD DY SS PM AM TZH TZM",
7518 "%H%M%S %B %Y %y %b %H %I %I %M%S %M %m %d %a %S %p %p %z ",
7519 ),
7520 ("FF FF0 FF1 FF6 FF7 FF9 FF69", "%f %f %f %f %n %n %f9"),
7521 ("éFF7年YYYY", "é%n年%Y"),
7522 ("\"å¹´\"YYYY %q", "\"å¹´\"%Y %q"),
7523 ] {
7524 assert_eq!(
7525 DuckDBDialect::snowflake_to_strptime(input),
7526 expected,
7527 "{input}"
7528 );
7529 }
7530 }
7531
7532 fn transpile_to_duckdb(sql: &str) -> String {
7533 transpile_to_duckdb_from(sql, DialectType::Generic)
7534 }
7535
7536 fn transpile_to_duckdb_from(sql: &str, read: DialectType) -> String {
7537 let dialect = Dialect::get(read);
7538 let result = dialect
7539 .transpile(sql, DialectType::DuckDB)
7540 .expect("Transpile failed");
7541 result[0].clone()
7542 }
7543
7544 #[test]
7545 fn test_athena_max_by_preserves_filter() {
7546 let sql = "SELECT max_by(value,seq) FILTER (WHERE keep) AS answer FROM (VALUES ('kept',1,true),('ignored',2,false)) t(value,seq,keep)";
7547 assert_eq!(
7548 transpile_to_duckdb_from(sql, DialectType::Athena),
7549 "SELECT ARG_MAX_NULL(value, seq) FILTER(WHERE keep) AS answer FROM (VALUES ('kept', 1, TRUE), ('ignored', 2, FALSE)) AS t(value, seq, keep)"
7550 );
7551
7552 for read in [DialectType::Athena, DialectType::Presto, DialectType::Trino] {
7553 for (source, target) in [("MAX_BY", "ARG_MAX"), ("MIN_BY", "ARG_MIN")] {
7554 for args in ["value, seq", "value, seq, 2"] {
7555 let target = if args == "value, seq" {
7556 format!("{target}_NULL")
7557 } else {
7558 target.to_string()
7559 };
7560 for suffix in ["", " OVER (PARTITION BY category)"] {
7561 let sql =
7562 format!("SELECT {source}({args}) FILTER (WHERE keep){suffix} FROM t");
7563 assert_eq!(
7564 transpile_to_duckdb_from(&sql, read),
7565 format!("SELECT {target}({args}) FILTER(WHERE keep){suffix} FROM t"),
7566 "{read:?}: {sql}"
7567 );
7568 }
7569 }
7570 }
7571 }
7572 }
7573
7574 #[test]
7575 fn test_athena_max_by_preserves_null_winner() {
7576 for read in [DialectType::Athena, DialectType::Presto, DialectType::Trino] {
7577 for (source, target) in [("MAX_BY", "ARG_MAX_NULL"), ("MIN_BY", "ARG_MIN_NULL")] {
7578 let sql = format!(
7579 "SELECT {source}(value, seq) AS answer FROM (VALUES ('older', 1), (CAST(NULL AS VARCHAR), 2)) t(value, seq)"
7580 );
7581 assert_eq!(
7582 transpile_to_duckdb_from(&sql, read),
7583 format!("SELECT {target}(value, seq) AS answer FROM (VALUES ('older', 1), (CAST(NULL AS TEXT), 2)) AS t(value, seq)"),
7584 "{read:?}: {sql}"
7585 );
7586 assert_eq!(
7587 transpile_to_duckdb_from(
7588 &format!("SELECT {source}(DISTINCT value, seq) FILTER (WHERE keep) FROM t"),
7589 read,
7590 ),
7591 format!("SELECT {target}(DISTINCT value, seq) FILTER(WHERE keep) FROM t")
7592 );
7593 }
7594 }
7595
7596 for (source, target) in [("MAX_BY", "ARG_MAX"), ("MIN_BY", "ARG_MIN")] {
7598 assert_eq!(
7599 transpile_to_duckdb_from(
7600 &format!("SELECT {source}(value, seq) FROM t"),
7601 DialectType::DuckDB,
7602 ),
7603 format!("SELECT {target}(value, seq) FROM t")
7604 );
7605 }
7606 }
7607
7608 #[test]
7609 fn test_athena_regexp_extract_preserves_null_and_empty_matches() {
7610 for read in [DialectType::Athena, DialectType::Presto, DialectType::Trino] {
7611 for args in [
7612 "'no-match', '([0-9]+)', 1",
7613 "'abc', '(z*)a', 1",
7614 "'abc', '(z)?a', 1",
7615 "'abc', '(a)(b)(c)'",
7616 "'abc', '(a)(b)(c)', 2",
7617 "'12 34', '[0-9]+'",
7618 "'', '()'",
7619 "NULL, '([0-9]+)', 1",
7620 "'abc', NULL, 1",
7621 "value, pattern, group_index",
7622 ] {
7623 assert_eq!(
7624 transpile_to_duckdb_from(
7625 &format!("SELECT REGEXP_EXTRACT({args}) AS answer"),
7626 read,
7627 ),
7628 format!("SELECT ARRAY_EXTRACT(REGEXP_EXTRACT_ALL({args}), 1) AS answer"),
7629 "{read:?}: {args}"
7630 );
7631 }
7632 }
7633
7634 assert_eq!(
7635 transpile_to_duckdb_from(
7636 "SELECT REGEXP_EXTRACT('no-match', '([0-9]+)', 1)",
7637 DialectType::DuckDB,
7638 ),
7639 "SELECT REGEXP_EXTRACT('no-match', '([0-9]+)', 1)"
7640 );
7641 }
7642
7643 #[test]
7644 fn test_athena_regexp_replace_capture_references() {
7645 for read in [DialectType::Athena, DialectType::Presto, DialectType::Trino] {
7646 for (sql, expected) in [
7647 (
7648 "SELECT regexp_replace('2026.09 2027.10', '([0-9]+)[.]([0-9]+)', '$1-$2') AS answer",
7649 r"SELECT REGEXP_REPLACE('2026.09 2027.10', '([0-9]+)[.]([0-9]+)', '\1-\2', 'g') AS answer",
7650 ),
7651 (
7652 "SELECT regexp_replace(value, pattern, '$0/$1/$2') FROM t",
7653 r"SELECT REGEXP_REPLACE(value, pattern, '\0/\1/\2', 'g') FROM t",
7654 ),
7655 (
7656 r"SELECT regexp_replace('aa', '(a)', '\$1')",
7657 "SELECT REGEXP_REPLACE('aa', '(a)', '$1', 'g')",
7658 ),
7659 (
7660 "SELECT regexp_replace('a1b2', '[0-9]')",
7661 "SELECT REGEXP_REPLACE('a1b2', '[0-9]', '', 'g')",
7662 ),
7663 (
7664 "SELECT regexp_replace('aa', 'a', 'x')",
7665 "SELECT REGEXP_REPLACE('aa', 'a', 'x', 'g')",
7666 ),
7667 ] {
7668 assert_eq!(transpile_to_duckdb_from(sql, read), expected, "{read:?}: {sql}");
7669 }
7670 }
7671
7672 assert_eq!(
7673 transpile_to_duckdb_from(
7674 "SELECT REGEXP_REPLACE('aa', '(a)', '$1')",
7675 DialectType::DuckDB,
7676 ),
7677 "SELECT REGEXP_REPLACE('aa', '(a)', '$1')"
7678 );
7679 }
7680
7681 fn assert_duckdb_value(sql: &str, expected: &str) {
7684 let Ok(engine) = std::env::var("POLYGLOT_DUCKDB") else {
7685 return;
7686 };
7687 for timezone in ["UTC", "America/New_York"] {
7688 let query = format!("SET TimeZone = '{timezone}'; {sql}");
7689 let output = std::process::Command::new(&engine)
7690 .args([
7691 "-init",
7692 "/dev/null",
7693 "-noheader",
7694 "-list",
7695 "-nullvalue",
7696 "NULL",
7697 ":memory:",
7698 &query,
7699 ])
7700 .output()
7701 .expect("run POLYGLOT_DUCKDB");
7702 assert!(
7703 output.status.success(),
7704 "{query}: {}",
7705 String::from_utf8_lossy(&output.stderr)
7706 );
7707 assert_eq!(
7708 String::from_utf8(output.stdout).unwrap().trim_end(),
7709 expected,
7710 "{query}"
7711 );
7712 }
7713 }
7714
7715 #[test]
7716 fn test_bigquery_numeric_precision_to_duckdb_479() {
7717 for (sql, expected_sql, expected_value) in [
7718 (
7719 "SELECT CAST(1.005 AS NUMERIC(10, 2)) AS a",
7720 "SELECT CAST(1.005 AS DECIMAL(10, 2)) AS a",
7721 "1.01",
7722 ),
7723 (
7724 "SELECT CAST(0.1249 AS NUMERIC)",
7725 "SELECT CAST(0.1249 AS DECIMAL(38, 9))",
7726 "0.124900000",
7727 ),
7728 (
7729 "SELECT ROUND(CAST(0.1249 AS NUMERIC), 2)",
7730 "SELECT ROUND(CAST(0.1249 AS DECIMAL(38, 9)), 2)",
7731 "0.12",
7732 ),
7733 (
7734 "SELECT SAFE_CAST('0.1249' AS NUMERIC)",
7735 "SELECT TRY_CAST('0.1249' AS DECIMAL(38, 9))",
7736 "0.124900000",
7737 ),
7738 (
7739 "SELECT NUMERIC '0.000000001'",
7740 "SELECT CAST('0.000000001' AS DECIMAL(38, 9))",
7741 "0.000000001",
7742 ),
7743 ] {
7744 let output = transpile_to_duckdb_from(sql, DialectType::BigQuery);
7745 assert_eq!(output, expected_sql, "{sql}");
7746 assert_duckdb_value(&output, expected_value);
7747 }
7748 for (sql, expected) in [
7749 ("SELECT CAST(-1.005 AS DECIMAL(10, 2))", "-1.01"),
7750 ("SELECT CAST(1.6 AS NUMERIC(10))", "2"),
7751 ("SELECT ROUND(CAST(-0.1249 AS NUMERIC), 2)", "-0.12"),
7752 ("SELECT SAFE_CAST('invalid' AS NUMERIC)", "NULL"),
7753 (
7754 "SELECT CAST('12345678901234567890123456789.123456789' AS NUMERIC)",
7755 "12345678901234567890123456789.123456789",
7756 ),
7757 (
7758 "SELECT COALESCE(CAST(NULL AS NUMERIC), DECIMAL '0.1249')",
7759 "0.124900000",
7760 ),
7761 (
7762 "SELECT CAST(['0.1249'] AS ARRAY<NUMERIC>)[OFFSET(0)]",
7763 "0.124900000",
7764 ),
7765 ("SELECT ABS(CAST(-0.1249 AS NUMERIC))", "0.124900000"),
7766 (
7767 "SELECT ROUND(NUMERIC '2.25', 1, 'ROUND_HALF_AWAY_FROM_ZERO')",
7768 "2.3",
7769 ),
7770 ("SELECT ROUND(NUMERIC '2.25', 1, 'ROUND_HALF_EVEN')", "2.2"),
7771 (
7772 "SELECT ROUND(NUMERIC '0.1249', 2, 'ROUND_HALF_AWAY_FROM_ZERO')",
7773 "0.12",
7774 ),
7775 (
7776 "SELECT ROUND(NUMERIC '0.1349', 2, 'ROUND_HALF_EVEN')",
7777 "0.13",
7778 ),
7779 ] {
7780 let output = transpile_to_duckdb_from(sql, DialectType::BigQuery);
7781 assert_duckdb_value(&output, expected);
7782 }
7783 let ddl = transpile_to_duckdb_from(
7784 "CREATE TABLE t (a NUMERIC, b NUMERIC(10, 2), c ARRAY<NUMERIC>, d STRUCT<n NUMERIC>)",
7785 DialectType::BigQuery,
7786 );
7787 assert_duckdb_value(
7788 &format!("{ddl}; INSERT INTO t VALUES ('0.1249', 1.005, ['0.1249'], {{'n': '0.1249'}}); SELECT a, b, c[1], d.n FROM t"),
7789 "0.124900000|1.01|0.124900000|0.124900000",
7790 );
7791 assert_eq!(
7792 transpile_to_duckdb_from("SELECT CAST(0.1249 AS NUMERIC)", DialectType::DuckDB),
7793 "SELECT CAST(0.1249 AS DECIMAL(18, 3))"
7794 );
7795 }
7796
7797 #[test]
7798 fn test_bigquery_named_parameters_to_duckdb_478() {
7799 let unnest = transpile_to_duckdb_from(
7800 "SELECT * FROM UNNEST(@sites) AS site",
7801 DialectType::BigQuery,
7802 );
7803 assert_eq!(unnest, "SELECT * FROM UNNEST($sites) AS _t0(site)");
7804 assert_duckdb_value(
7805 &format!("PREPARE q AS {unnest}; EXECUTE q(sites := ['alpha', 'beta'])"),
7806 "alpha\nbeta",
7807 );
7808 let membership = transpile_to_duckdb_from(
7809 "SELECT x FROM t WHERE id IN UNNEST(@ids)",
7810 DialectType::BigQuery,
7811 );
7812 assert!(!membership.contains("ABS("), "{membership}");
7813 assert!(
7814 membership.contains("ARRAY_CONTAINS($ids, id)"),
7815 "{membership}"
7816 );
7817 for (ids, expected) in [
7818 ("[2]", "b"),
7819 ("[]", ""),
7820 ("NULL::INTEGER[]", ""),
7821 ("[NULL, 1]", "a"),
7822 ] {
7823 assert_duckdb_value(
7824 &format!("CREATE TABLE t AS SELECT 1 AS id, 'a' AS x UNION ALL SELECT 2, 'b'; PREPARE q AS {membership}; EXECUTE q(ids := {ids})"), expected,
7825 );
7826 }
7827 for (sql, expected_sql, binding, value) in [
7828 ("SELECT @name + 1", "SELECT $name + 1", "name := 6", "7"),
7829 ("SELECT @select", "SELECT $select", "\"select\" := 7", "7"),
7830 ("SELECT @`a b`", "SELECT $\"a b\"", "\"a b\" := 7", "7"),
7831 (
7832 "SELECT @`a\"b`",
7833 "SELECT $\"a\"\"b\"",
7834 "\"a\"\"b\" := 7",
7835 "7",
7836 ),
7837 (
7838 "SELECT @param.dataField",
7839 "SELECT $param.dataField",
7840 "param := {'dataField': 7}",
7841 "7",
7842 ),
7843 (
7844 "SELECT @ids[OFFSET(0)]",
7845 "SELECT $ids[1]",
7846 "ids := [7, 8]",
7847 "7",
7848 ),
7849 ] {
7850 let output = transpile_to_duckdb_from(sql, DialectType::BigQuery);
7851 assert_eq!(output, expected_sql, "{sql}");
7852 assert_eq!(
7853 transpile_to_duckdb_from(&output, DialectType::DuckDB),
7854 output
7855 );
7856 assert_duckdb_value(
7857 &format!("PREPARE q AS {output}; EXECUTE q({binding})"),
7858 value,
7859 );
7860 }
7861 for dialect in [
7862 DialectType::PostgreSQL,
7863 DialectType::DuckDB,
7864 DialectType::Vertica,
7865 ] {
7866 assert_eq!(
7867 transpile_to_duckdb_from("SELECT @(-7)", dialect),
7868 "SELECT ABS((-7))"
7869 );
7870 let output = transpile_to_duckdb_from("SELECT @n FROM (SELECT -7 AS n) AS t", dialect);
7871 assert!(output.contains("ABS(n)"), "{dialect:?}: {output}");
7872 assert_duckdb_value(&output, "7");
7873 }
7874 let reverse = Dialect::get(DialectType::DuckDB)
7875 .transpile("SELECT $\"a b\"", DialectType::BigQuery)
7876 .unwrap();
7877 assert_eq!(reverse[0], "SELECT @`a b`");
7878 }
7879
7880 #[test]
7881 fn test_bigquery_variable_interval_to_duckdb_477() {
7882 for (sql, expected_sql, value) in [
7883 (
7884 "SELECT DATE_ADD(DATE '2026-01-01', INTERVAL n MONTH) AS d FROM (SELECT 2 AS n)",
7885 "SELECT CAST('2026-01-01' AS DATE) + INTERVAL (n) MONTH AS d FROM (SELECT 2 AS n)",
7886 "2026-03-01 00:00:00",
7887 ),
7888 (
7889 "SELECT DATE_ADD(DATE '2026-01-01', INTERVAL DATE_DIFF(DATE '2026-03-15', DATE '2026-01-01', MONTH) MONTH) AS d",
7890 "SELECT CAST('2026-01-01' AS DATE) + INTERVAL (DATE_DIFF('MONTH', CAST('2026-01-01' AS DATE), CAST('2026-03-15' AS DATE))) MONTH AS d",
7891 "2026-03-01 00:00:00",
7892 ),
7893 ] {
7894 let output = transpile_to_duckdb_from(sql, DialectType::BigQuery);
7895 assert_eq!(output, expected_sql);
7896 assert_duckdb_value(&output, value);
7897 }
7898 for (amount, expected) in [
7899 ("(n)", "2026-03-01 00:00:00"),
7900 ("(n + 1)", "2026-04-01 00:00:00"),
7901 ("ABS(-n)", "2026-03-01 00:00:00"),
7902 ("CASE WHEN n > 0 THEN n ELSE 1 END", "2026-03-01 00:00:00"),
7903 ("-n", "2025-11-01 00:00:00"),
7904 ("NULL", "NULL"),
7905 ] {
7906 let sql = format!(
7907 "SELECT DATE_ADD(DATE '2026-01-01', INTERVAL {amount} MONTH) FROM (SELECT 2 AS n)"
7908 );
7909 let output = transpile_to_duckdb_from(&sql, DialectType::BigQuery);
7910 assert_duckdb_value(&output, expected);
7911 }
7912 for (sql, expected) in [
7913 ("SELECT INTERVAL (n) MONTH FROM (SELECT 2 AS n)", "2 months"),
7914 (
7915 "SELECT INTERVAL (ABS(n)) MONTH FROM (SELECT -2 AS n)",
7916 "2 months",
7917 ),
7918 (
7919 "SELECT INTERVAL (s) FROM (SELECT '1 month' AS s)",
7920 "1 month",
7921 ),
7922 ("SELECT INTERVAL '2' MONTH", "2 months"),
7923 ] {
7924 let output = transpile_to_duckdb_from(sql, DialectType::DuckDB);
7925 assert!(!output.contains("INTERVAL (("), "{output}");
7926 assert_duckdb_value(&output, expected);
7927 }
7928 let output = transpile_to_duckdb_from(
7929 "SELECT DATE_SUB(DATE '2026-01-01', INTERVAL DATE_DIFF(DATE '2026-03-15', DATE '2026-01-01', MONTH) MONTH)",
7930 DialectType::BigQuery,
7931 );
7932 assert_duckdb_value(&output, "2025-11-01 00:00:00");
7933 }
7934
7935 #[test]
7936 fn test_bigquery_date_timezone_to_duckdb_476() {
7937 let source = Dialect::get(DialectType::BigQuery);
7938 for (argument, zone, expected) in [
7939 (
7940 "TIMESTAMP '2026-01-31 23:30:00+00'",
7941 "'Europe/Berlin'",
7942 "2026-02-01",
7943 ),
7944 (
7945 "TIMESTAMP '2016-12-25 05:30:00+07'",
7946 "'America/Los_Angeles'",
7947 "2016-12-24",
7948 ),
7949 (
7950 "TIMESTAMP '2026-07-31 22:30:00+00'",
7951 "'Europe/Berlin'",
7952 "2026-08-01",
7953 ),
7954 (
7955 "TIMESTAMP '2026-01-31 23:30:00-05:00'",
7956 "'UTC'",
7957 "2026-02-01",
7958 ),
7959 (
7960 "TIMESTAMP '2026-01-31T23:30:00Z'",
7961 "'Europe/Berlin'",
7962 "2026-02-01",
7963 ),
7964 (
7965 "TIMESTAMP '2026-01-31 23:30:00 America/New_York'",
7966 "'UTC'",
7967 "2026-02-01",
7968 ),
7969 (
7970 "TIMESTAMP '2016-12-25'",
7971 "'America/Los_Angeles'",
7972 "2016-12-24",
7973 ),
7974 (
7975 "TIMESTAMP '2026-01-31 23:30:00'",
7976 "'Europe/Berlin'",
7977 "2026-02-01",
7978 ),
7979 ("'2026-01-31 23:30:00'", "'Europe/Berlin'", "2026-02-01"),
7980 (
7981 "TIMESTAMP('2026-01-31 23:30:00')",
7982 "'Europe/Berlin'",
7983 "2026-02-01",
7984 ),
7985 (
7986 "CAST('2026-01-31 23:30:00' AS TIMESTAMP)",
7987 "'Europe/Berlin'",
7988 "2026-02-01",
7989 ),
7990 (
7991 "COALESCE(NULL, TIMESTAMP '2026-01-31 23:30:00')",
7992 "'Europe/Berlin'",
7993 "2026-02-01",
7994 ),
7995 (
7996 "TIMESTAMP_MILLIS(1769902200000)",
7997 "'Europe/Berlin'",
7998 "2026-02-01",
7999 ),
8000 (
8001 "TIMESTAMP_MICROS(1769902200000000)",
8002 "'Europe/Berlin'",
8003 "2026-02-01",
8004 ),
8005 (
8006 "TIMESTAMP_SECONDS(1769902200)",
8007 "'Europe/Berlin'",
8008 "2026-02-01",
8009 ),
8010 (
8011 "TIMESTAMP '2026-01-31 20:00:00+00'",
8012 "'+05:30'",
8013 "2026-02-01",
8014 ),
8015 ("TIMESTAMP '2026-02-01 01:00:00+00'", "'-08'", "2026-01-31"),
8016 ("NULL", "'Europe/Berlin'", "NULL"),
8017 ("TIMESTAMP '2026-01-31 23:30:00+00'", "NULL", "NULL"),
8018 ] {
8019 let input = format!("SELECT DATE({argument}, {zone}) AS d");
8020 let output = source
8021 .transpile(&input, DialectType::DuckDB)
8022 .unwrap()
8023 .remove(0);
8024 assert!(!output.contains("STRPTIME"), "{input}: {output}");
8025 assert!(output.contains("AT TIME ZONE"), "{input}: {output}");
8026 assert_duckdb_value(&output, expected);
8027 }
8028 let input = "SELECT DATE(TIMESTAMP '2026-01-31 23:30:00+00', 'Europe/Berlin') AS d";
8029 assert_eq!(source.transpile(input, DialectType::DuckDB).unwrap()[0],
8030 "SELECT CAST(CAST('2026-01-31 23:30:00+00' AS TIMESTAMPTZ) AT TIME ZONE 'Europe/Berlin' AS DATE) AS d");
8031
8032 let input = "SELECT DATE(ts, zone) AS d FROM (SELECT TIMESTAMP '2026-01-31 23:30:00+00' AS ts, 'Europe/Berlin' AS zone) AS t";
8033 let output = source
8034 .transpile(input, DialectType::DuckDB)
8035 .unwrap()
8036 .remove(0);
8037 assert!(
8038 output.contains("CAST(ts AS TIMESTAMPTZ) AT TIME ZONE zone"),
8039 "{output}"
8040 );
8041 assert_duckdb_value(&output, "2026-02-01");
8042
8043 for (sql, read, expected) in [
8045 (
8046 "SELECT DATE(2026, 2, 1)",
8047 DialectType::BigQuery,
8048 "2026-02-01",
8049 ),
8050 (
8051 "SELECT DATE(DATETIME '2026-02-01 12:00:00')",
8052 DialectType::BigQuery,
8053 "2026-02-01",
8054 ),
8055 (
8056 "SELECT DATE('2026-02-01', 'YYYY-MM-DD')",
8057 DialectType::Snowflake,
8058 "2026-02-01",
8059 ),
8060 ] {
8061 let output = transpile_to_duckdb_from(sql, read);
8062 assert_duckdb_value(&output, expected);
8063 }
8064 let identity = source
8065 .transpile(
8066 "SELECT DATE(ts, 'Europe/Berlin') FROM t",
8067 DialectType::BigQuery,
8068 )
8069 .unwrap();
8070 assert_eq!(identity[0], "SELECT DATE(ts, 'Europe/Berlin') FROM t");
8071 }
8072
8073 #[test]
8074 fn test_athena_to_iso8601_exact_translation() {
8075 use crate::dialects::TranspileOptions;
8076 use crate::generator::UnsupportedLevel;
8077
8078 for read in [DialectType::Athena, DialectType::Trino] {
8079 for (argument, target_argument, format, expected_value) in [
8080 (
8081 "DATE '2026-05-26'",
8082 "CAST('2026-05-26' AS DATE)",
8083 "%Y-%m-%d",
8084 "2026-05-26",
8085 ),
8086 (
8087 "TIMESTAMP '2026-05-26 02:08:02'",
8088 "CAST('2026-05-26 02:08:02' AS TIMESTAMP(0))",
8089 "%Y-%m-%dT%H:%M:%S",
8090 "2026-05-26T02:08:02",
8091 ),
8092 (
8093 "TIMESTAMP '2026-05-26 02:08:02.930'",
8094 "CAST('2026-05-26 02:08:02.930' AS TIMESTAMP(3))",
8095 "%Y-%m-%dT%H:%M:%S.%g",
8096 "2026-05-26T02:08:02.930",
8097 ),
8098 (
8099 "TIMESTAMP '2026-05-26 02:08:02.123456'",
8100 "CAST('2026-05-26 02:08:02.123456' AS TIMESTAMP(6))",
8101 "%Y-%m-%dT%H:%M:%S.%f",
8102 "2026-05-26T02:08:02.123456",
8103 ),
8104 (
8105 "TIMESTAMP '2026-05-26 02:08:02.123456789'",
8106 "CAST('2026-05-26 02:08:02.123456789' AS TIMESTAMP(9))",
8107 "%Y-%m-%dT%H:%M:%S.%n",
8108 "2026-05-26T02:08:02.123456789",
8109 ),
8110 (
8111 "TIMESTAMP '1969-12-31 23:59:59.123456789'",
8112 "CAST('1969-12-31 23:59:59.123456789' AS TIMESTAMP(9))",
8113 "%Y-%m-%dT%H:%M:%S.%n",
8114 "1969-12-31T23:59:59.123456789",
8115 ),
8116 (
8117 "CAST('2026-05-26 02:08:02.930' AS TIMESTAMP)",
8118 "CAST('2026-05-26 02:08:02.930' AS TIMESTAMP(3))",
8119 "%Y-%m-%dT%H:%M:%S.%g",
8120 "2026-05-26T02:08:02.930",
8121 ),
8122 (
8123 "CAST(TIMESTAMP '2026-05-26 02:08:02.930' AS TIMESTAMP(6))",
8124 "CAST(CAST('2026-05-26 02:08:02.930' AS TIMESTAMP(3)) AS TIMESTAMP(6))",
8125 "%Y-%m-%dT%H:%M:%S.%f",
8126 "2026-05-26T02:08:02.930000",
8127 ),
8128 (
8129 "CAST(CASE WHEN TRUE THEN TIMESTAMP '2026-05-26 02:08:02.123456789' ELSE NULL END AS TIMESTAMP(9))",
8130 "CAST(CASE WHEN TRUE THEN CAST('2026-05-26 02:08:02.123456789' AS TIMESTAMP(9)) ELSE NULL END AS TIMESTAMP(9))",
8131 "%Y-%m-%dT%H:%M:%S.%n",
8132 "2026-05-26T02:08:02.123456789",
8133 ),
8134 (
8135 "(TIMESTAMP '2026-05-26 02:08:02.930')",
8136 "(CAST('2026-05-26 02:08:02.930' AS TIMESTAMP(3)))",
8137 "%Y-%m-%dT%H:%M:%S.%g",
8138 "2026-05-26T02:08:02.930",
8139 ),
8140 (
8141 "CAST(NULL AS DATE)",
8142 "CAST(NULL AS DATE)",
8143 "%Y-%m-%d",
8144 "NULL",
8145 ),
8146 (
8147 "CAST(NULL AS TIMESTAMP(3))",
8148 "CAST(NULL AS TIMESTAMP(3))",
8149 "%Y-%m-%dT%H:%M:%S.%g",
8150 "NULL",
8151 ),
8152 (
8153 "TRY_CAST('invalid' AS TIMESTAMP(3))",
8154 "TRY_CAST('invalid' AS TIMESTAMP(3))",
8155 "%Y-%m-%dT%H:%M:%S.%g",
8156 "NULL",
8157 ),
8158 ] {
8159 let sql = format!("SELECT TO_ISO8601({argument}) AS answer");
8160 for level in [
8161 UnsupportedLevel::Ignore,
8162 UnsupportedLevel::Warn,
8163 UnsupportedLevel::Raise,
8164 UnsupportedLevel::Immediate,
8165 ] {
8166 let output = Dialect::get(read)
8167 .transpile_with(
8168 &sql,
8169 DialectType::DuckDB,
8170 TranspileOptions {
8171 unsupported_level: level,
8172 ..Default::default()
8173 },
8174 )
8175 .unwrap();
8176 assert_eq!(
8177 output[0],
8178 format!("SELECT STRFTIME({target_argument}, '{format}') AS answer"),
8179 "{read:?}/{level:?}: {sql}"
8180 );
8181 if level == UnsupportedLevel::Ignore {
8182 assert_duckdb_value(&output[0], expected_value);
8183 }
8184 }
8185 }
8186 }
8187 let output = Dialect::get(DialectType::Presto)
8189 .transpile_with(
8190 "SELECT TO_ISO8601(DATE '2026-05-26')",
8191 DialectType::DuckDB,
8192 TranspileOptions::strict(),
8193 )
8194 .unwrap();
8195 assert_duckdb_value(&output[0], "2026-05-26");
8196 assert_eq!(
8197 output[0],
8198 "SELECT STRFTIME(CAST('2026-05-26' AS DATE), '%Y-%m-%d')"
8199 );
8200 }
8201
8202 #[test]
8203 fn test_athena_to_iso8601_permissive_translation() {
8204 use crate::dialects::TranspileOptions;
8205 use crate::generator::UnsupportedLevel;
8206
8207 for read in [DialectType::Athena, DialectType::Presto, DialectType::Trino] {
8208 let mut cases = vec![
8209 ("TIMESTAMP '2026-05-26 02:08:02.93'", "CAST('2026-05-26 02:08:02.93' AS TIMESTAMP(3))", false, "2026-05-26T02:08:02.930000000"),
8210 ("TIMESTAMP '2026-05-26 02:08:02.930 +02:00'", "CAST(CAST('2026-05-26 02:08:02.930+02:00' AS TIMESTAMPTZ) AT TIME ZONE 'UTC' AS TIMESTAMP(3))", true, "2026-05-26T00:08:02.930000000Z"),
8211 ("TIMESTAMP '2026-05-26 02:08:02.930 Z'", "CAST(CAST('2026-05-26 02:08:02.930Z' AS TIMESTAMPTZ) AT TIME ZONE 'UTC' AS TIMESTAMP(3))", true, "2026-05-26T02:08:02.930000000Z"),
8212 ("TIMESTAMP '2026-05-26 02:08:02.930 America/New_York'", "CAST(CAST('2026-05-26 02:08:02.930 America/New_York' AS TIMESTAMPTZ) AT TIME ZONE 'UTC' AS TIMESTAMP(3))", true, "2026-05-26T06:08:02.930000000Z"),
8213 ("CAST(NULL AS TIMESTAMP WITH TIME ZONE)", "CAST(CAST(NULL AS TIMESTAMPTZ) AT TIME ZONE 'UTC' AS TIMESTAMP(3))", true, "NULL"),
8214 ("TRY_CAST('invalid' AS TIMESTAMP WITH TIME ZONE)", "CAST(TRY_CAST('invalid' AS TIMESTAMPTZ) AT TIME ZONE 'UTC' AS TIMESTAMP(3))", true, "NULL"),
8215 ];
8216 if read == DialectType::Presto {
8217 cases.push((
8218 "TIMESTAMP '2026-05-26 02:08:02.930'",
8219 "CAST('2026-05-26 02:08:02.930' AS TIMESTAMP(3))",
8220 false,
8221 "2026-05-26T02:08:02.930000000",
8222 ));
8223 } else {
8224 cases.extend([
8225 ("TIMESTAMP '2026-05-26 02:08:02.1234567'", "CAST('2026-05-26 02:08:02.1234567' AS TIMESTAMP(9))", false, "2026-05-26T02:08:02.123456700"),
8226 ("TIMESTAMP '1969-12-31 23:59:59.123456 -02:00'", "CAST(CAST('1969-12-31 23:59:59.123456-02:00' AS TIMESTAMPTZ) AT TIME ZONE 'UTC' AS TIMESTAMP(6))", true, "1970-01-01T01:59:59.123456000Z"),
8227 ]);
8228 }
8229 for (argument, target_argument, timezone, expected_value) in cases {
8230 let sql = format!("SELECT TO_ISO8601({argument}) AS answer");
8231 for level in [
8232 UnsupportedLevel::Ignore,
8233 UnsupportedLevel::Warn,
8234 UnsupportedLevel::Raise,
8235 UnsupportedLevel::Immediate,
8236 ] {
8237 let result = Dialect::get(read).transpile_with(
8238 &sql,
8239 DialectType::DuckDB,
8240 TranspileOptions {
8241 unsupported_level: level,
8242 ..Default::default()
8243 },
8244 );
8245 if matches!(level, UnsupportedLevel::Raise | UnsupportedLevel::Immediate) {
8246 assert!(
8247 matches!(result, Err(crate::error::Error::Unsupported { .. })),
8248 "{read:?}/{level:?}: {sql}: {result:?}"
8249 );
8250 } else {
8251 let output = result.unwrap();
8252 let suffix = if timezone { " || 'Z'" } else { "" };
8253 assert_eq!(output[0], format!("SELECT STRFTIME({target_argument}, '%Y-%m-%dT%H:%M:%S.%n'){suffix} AS answer"), "{read:?}/{level:?}: {sql}");
8254 if level == UnsupportedLevel::Ignore {
8255 assert_duckdb_value(&output[0], expected_value);
8256 }
8257 }
8258 }
8259 }
8260 }
8261 }
8262
8263 #[test]
8264 fn test_athena_to_iso8601_rejects_unverified_conversions() {
8265 use crate::dialects::TranspileOptions;
8266 use crate::generator::UnsupportedLevel;
8267
8268 for read in [DialectType::Athena, DialectType::Presto, DialectType::Trino] {
8269 let dialect = Dialect::get(read);
8270 for argument in [
8271 "value",
8272 "NULL",
8273 "'2026-05-26'",
8274 "42",
8275 "CAST(value AS VARCHAR)",
8276 "TIMESTAMP '2026-05-26 02:08:02.123456789123'",
8277 "TIMESTAMP '2026-05-26 02:08:02.123456789 +02:00'",
8278 "CAST(value AS TIMESTAMP(2))",
8279 "CAST(value AS TIMESTAMP(12))",
8280 "CAST(TIMESTAMP '2026-05-26 02:08:02.123456789' AS TIMESTAMP(6))",
8281 "CAST('2026-05-26 02:08:02.930999' AS TIMESTAMP(3))",
8282 "CAST(TIMESTAMP '2026-05-26 00:08:02.930 +02:00' AS DATE)",
8283 "CAST(TIMESTAMP '2026-05-26 00:08:02.930 +02:00' AS TIMESTAMP(3))",
8284 "DISTINCT DATE '2026-05-26'",
8285 "DATE '2026-05-26', DATE '2026-05-27'",
8286 "",
8287 ] {
8288 let sql = format!("SELECT TO_ISO8601({argument}) AS answer FROM t");
8289 for level in [
8290 UnsupportedLevel::Ignore,
8291 UnsupportedLevel::Warn,
8292 UnsupportedLevel::Raise,
8293 UnsupportedLevel::Immediate,
8294 ] {
8295 let error = dialect
8296 .transpile_with(
8297 &sql,
8298 DialectType::DuckDB,
8299 TranspileOptions {
8300 unsupported_level: level,
8301 ..Default::default()
8302 },
8303 )
8304 .expect_err("unsupported TO_ISO8601 must not emit invalid DuckDB SQL");
8305 assert!(
8306 matches!(error, crate::error::Error::Unsupported { .. }),
8307 "{read:?}/{level:?}: {sql}: {error}"
8308 );
8309 assert!(error.to_string().contains("TO_ISO8601"));
8310 }
8311 }
8312
8313 assert_eq!(
8314 dialect
8315 .transpile("SELECT TO_ISO8601(value) FROM t", read)
8316 .unwrap()[0],
8317 "SELECT TO_ISO8601(value) FROM t"
8318 );
8319 assert_eq!(
8320 dialect
8321 .transpile_with(
8322 "SELECT custom.TO_ISO8601(value) FROM t",
8323 DialectType::DuckDB,
8324 TranspileOptions::strict()
8325 )
8326 .unwrap()[0],
8327 "SELECT custom.TO_ISO8601(value) FROM t"
8328 );
8329 }
8330 }
8331
8332 #[test]
8333 fn test_athena_to_iso8601_annotated_argument() {
8334 for (data_type, format) in [
8335 (DataType::Date, "%Y-%m-%d"),
8336 (
8337 DataType::Timestamp {
8338 precision: Some(6),
8339 timezone: false,
8340 },
8341 "%Y-%m-%dT%H:%M:%S.%f",
8342 ),
8343 ] {
8344 let mut argument = Expression::column("value");
8345 argument.set_inferred_type(data_type);
8346 let expression = Expression::Function(Box::new(Function::new(
8347 "TO_ISO8601".to_string(),
8348 vec![argument],
8349 )));
8350 let normalized = crate::dialects::normalization::normalize(
8351 expression,
8352 DialectType::Trino,
8353 DialectType::DuckDB,
8354 true,
8355 )
8356 .unwrap();
8357 assert_eq!(
8358 Dialect::get(DialectType::DuckDB)
8359 .generate(&normalized)
8360 .unwrap(),
8361 format!("STRFTIME(value, '{format}')")
8362 );
8363 }
8364 let mut argument = Expression::column("value");
8365 argument.set_inferred_type(DataType::Timestamp {
8366 precision: None,
8367 timezone: false,
8368 });
8369 for strict in [false, true] {
8370 let expression = Expression::Function(Box::new(Function::new(
8371 "TO_ISO8601".to_string(),
8372 vec![argument.clone()],
8373 )));
8374 assert!(crate::dialects::normalization::normalize(
8375 expression,
8376 DialectType::Trino,
8377 DialectType::DuckDB,
8378 strict
8379 )
8380 .is_err());
8381 }
8382 }
8383
8384 #[test]
8385 fn test_athena_to_iso8601_evaluates_argument_once() {
8386 let output = Dialect::get(DialectType::Athena).transpile_with(
8387 "SELECT TO_ISO8601(CAST(CASE WHEN NEXTVAL('calls') = 1 THEN '2026-05-26 02:08:02.930' ELSE '2000-01-01 00:00:00.000' END AS TIMESTAMP(3)))",
8388 DialectType::DuckDB,
8389 crate::dialects::TranspileOptions::strict(),
8390 ).unwrap();
8391 assert_eq!(output[0].matches("NEXTVAL").count(), 1);
8392 assert_duckdb_value(
8393 &format!(
8394 "CREATE SEQUENCE calls; {}; SELECT CURRVAL('calls');",
8395 output[0]
8396 ),
8397 "2026-05-26T02:08:02.930\n1",
8398 );
8399 }
8400
8401 #[test]
8402 fn test_ifnull_to_coalesce() {
8403 let result = transpile_to_duckdb("SELECT IFNULL(a, b)");
8404 assert!(
8405 result.contains("COALESCE"),
8406 "Expected COALESCE, got: {}",
8407 result
8408 );
8409 }
8410
8411 #[test]
8412 fn test_nvl_to_coalesce() {
8413 let result = transpile_to_duckdb("SELECT NVL(a, b)");
8414 assert!(
8415 result.contains("COALESCE"),
8416 "Expected COALESCE, got: {}",
8417 result
8418 );
8419 }
8420
8421 #[test]
8422 fn test_basic_select() {
8423 let result = transpile_to_duckdb("SELECT a, b FROM users WHERE id = 1");
8424 assert!(result.contains("SELECT"));
8425 assert!(result.contains("FROM users"));
8426 }
8427
8428 #[test]
8429 fn test_duckdb_keyword_relation_aliases() {
8430 let dialect = Dialect::get(DialectType::DuckDB);
8431 for alias in [
8432 "top",
8433 "TOP",
8434 "ToP",
8435 "first",
8436 "last",
8437 "begin",
8438 "type",
8439 "\"top\"",
8440 "\"where\"",
8441 ] {
8442 for template in [
8443 "SELECT {alias}.item_id FROM ranked_items {as}{alias}",
8444 "WITH ranked_items AS (SELECT 1 AS item_id) SELECT {alias}.item_id FROM ranked_items {as}{alias}",
8445 "WITH ranked_items AS (SELECT 1 AS item_id), selected_items AS (SELECT 1 AS item_id) SELECT {alias}.item_id FROM selected_items JOIN ranked_items {as}{alias} ON {alias}.item_id = selected_items.item_id",
8446 "SELECT {alias}.item_id FROM (SELECT 1 AS item_id) {as}{alias}",
8447 "SELECT {alias}.item_id FROM range(1) {as}{alias}(item_id)",
8448 "SELECT {alias}.item_id FROM (VALUES (1)) {as}{alias}(item_id)",
8449 ] {
8450 let template = template.replace("{alias}", alias);
8451 let explicit_sql = template.replace("{as}", "AS ");
8452 let expected = transpile_to_duckdb_from(&explicit_sql, DialectType::DuckDB);
8453 for as_keyword in ["", "AS "] {
8454 let sql = template.replace("{as}", as_keyword);
8455 let statements = dialect
8456 .parse(&sql)
8457 .unwrap_or_else(|error| panic!("Failed to parse {sql:?}: {error}"));
8458 assert_eq!(statements.len(), 1, "{sql}");
8459 let Expression::Select(select) = &statements[0] else {
8460 panic!("Expected SELECT for {sql}");
8461 };
8462 let relation = select.joins.last().map_or_else(
8463 || &select.from.as_ref().unwrap().expressions[0],
8464 |join| &join.this,
8465 );
8466 let (identifier, columns) = match relation {
8467 Expression::Table(table) => (table.alias.as_ref().unwrap(), &table.column_aliases),
8468 Expression::Subquery(subquery) => (subquery.alias.as_ref().unwrap(), &subquery.column_aliases),
8469 Expression::Alias(alias) => (&alias.alias, &alias.column_aliases),
8470 _ => panic!("Expected aliased relation for {sql}"),
8471 };
8472 assert_eq!(identifier.name, alias.trim_matches('"'), "{sql}");
8473 assert_eq!(identifier.quoted, alias.starts_with('"'), "{sql}");
8474 if template.contains("(item_id)") {
8475 assert_eq!(columns.len(), 1, "{sql}");
8476 assert_eq!(columns[0].name, "item_id", "{sql}");
8477 }
8478 assert_eq!(
8479 transpile_to_duckdb_from(&sql, DialectType::DuckDB),
8480 expected,
8481 "{sql}"
8482 );
8483 }
8484 }
8485 }
8486 }
8487
8488 #[test]
8489 fn test_duckdb_keyword_relation_aliases_preserve_clause_boundaries() {
8490 let dialect = Dialect::get(DialectType::DuckDB);
8491 for alias in ["", " top"] {
8492 let sql = format!(
8493 "SELECT item_id, ROW_NUMBER() OVER w AS rn FROM ranked_items{alias} \
8494 WHERE item_id > 0 GROUP BY item_id HAVING COUNT(*) > 0 \
8495 WINDOW w AS (ORDER BY item_id) QUALIFY rn = 1 \
8496 ORDER BY item_id NULLS FIRST, rn NULLS LAST LIMIT 5 OFFSET 1"
8497 );
8498 let statements = dialect.parse(&sql).unwrap();
8499 let Expression::Select(select) = &statements[0] else {
8500 panic!("Expected SELECT for {sql}");
8501 };
8502 assert!(select.where_clause.is_some());
8503 assert!(select.group_by.is_some());
8504 assert!(select.having.is_some());
8505 assert!(select.windows.is_some());
8506 assert!(select.qualify.is_some());
8507 let ordering = &select.order_by.as_ref().unwrap().expressions;
8508 assert_eq!(ordering.len(), 2);
8509 assert_eq!(ordering[0].nulls_first, Some(true));
8510 assert_eq!(ordering[1].nulls_first, Some(false));
8511 assert!(select.limit.is_some());
8512 assert!(select.offset.is_some());
8513 let Expression::Table(table) = &select.from.as_ref().unwrap().expressions[0] else {
8514 panic!("Expected table source for {sql}");
8515 };
8516 assert_eq!(
8517 table.alias.as_ref().map(|a| a.name.as_str()),
8518 if alias.is_empty() { None } else { Some("top") }
8519 );
8520
8521 for (join, kind) in [
8522 ("LEFT JOIN selected_items ON TRUE", JoinKind::Left),
8523 ("POSITIONAL JOIN selected_items", JoinKind::Positional),
8524 ] {
8525 let sql = format!("SELECT * FROM ranked_items{alias} {join}");
8526 let statements = dialect.parse(&sql).unwrap();
8527 let Expression::Select(select) = &statements[0] else {
8528 panic!("Expected SELECT for {sql}");
8529 };
8530 assert_eq!(select.joins.len(), 1, "{sql}");
8531 assert_eq!(select.joins[0].kind, kind, "{sql}");
8532 let Expression::Table(table) = &select.from.as_ref().unwrap().expressions[0] else {
8533 panic!("Expected table source for {sql}");
8534 };
8535 assert_eq!(
8536 table.alias.as_ref().map(|a| a.name.as_str()),
8537 if alias.is_empty() { None } else { Some("top") }
8538 );
8539 }
8540 }
8541
8542 for alias in ["end", "where", "qualify", "select", "join", "limit"] {
8544 let sql = format!("SELECT * FROM ranked_items {alias}");
8545 assert!(dialect.parse(&sql).is_err(), "Unexpectedly accepted {sql}");
8546 }
8547 }
8548
8549 #[test]
8550 fn test_extract_quoted_date_parts() {
8551 for (quoted, canonical) in [("year", "YEAR"), ("month", "MONTH"), ("day", "DAY")] {
8552 let sql = format!("SELECT EXTRACT('{quoted}' FROM created_at) FROM events");
8553 assert_eq!(
8554 transpile_to_duckdb_from(&sql, DialectType::DuckDB),
8555 format!("SELECT EXTRACT({canonical} FROM created_at) FROM events")
8556 );
8557 }
8558
8559 let unquoted = "SELECT EXTRACT(YEAR FROM created_at) FROM events";
8560 assert_eq!(
8561 transpile_to_duckdb_from(unquoted, DialectType::DuckDB),
8562 unquoted
8563 );
8564 }
8565
8566 #[test]
8567 fn test_group_concat_to_listagg() {
8568 let result = transpile_to_duckdb("SELECT GROUP_CONCAT(name)");
8569 assert!(
8570 result.contains("LISTAGG"),
8571 "Expected LISTAGG, got: {}",
8572 result
8573 );
8574 }
8575
8576 #[test]
8577 fn test_listagg_preserved() {
8578 let result = transpile_to_duckdb("SELECT LISTAGG(name)");
8579 assert!(
8580 result.contains("LISTAGG"),
8581 "Expected LISTAGG, got: {}",
8582 result
8583 );
8584 }
8585
8586 #[test]
8587 fn test_ordered_string_agg_uses_duckdb_listagg_order_syntax() {
8588 let result = transpile_to_duckdb_from(
8589 "SELECT string_agg(nm, ',' ORDER BY id) AS v FROM t",
8590 DialectType::PostgreSQL,
8591 );
8592 assert_eq!(result, "SELECT LISTAGG(nm, ',' ORDER BY id) AS v FROM t");
8593 }
8594
8595 #[test]
8596 fn test_ordered_listagg_uses_duckdb_order_syntax() {
8597 let result = transpile_to_duckdb_from(
8598 "SELECT LISTAGG(col, '|SEPARATOR|') WITHIN GROUP (ORDER BY col2) FROM t",
8599 DialectType::Snowflake,
8600 );
8601 assert_eq!(
8602 result,
8603 "SELECT LISTAGG(col, '|SEPARATOR|' ORDER BY col2) FROM t"
8604 );
8605 }
8606
8607 #[test]
8608 fn test_ordered_group_concat_uses_duckdb_listagg_order_syntax() {
8609 let result = transpile_to_duckdb_from(
8610 "SELECT GROUP_CONCAT(nm ORDER BY id SEPARATOR ',') AS v FROM t",
8611 DialectType::MySQL,
8612 );
8613 assert_eq!(result, "SELECT LISTAGG(nm, ',' ORDER BY id) AS v FROM t");
8614 }
8615
8616 #[test]
8617 fn test_date_format_to_strftime() {
8618 let result = transpile_to_duckdb("SELECT DATE_FORMAT(d, '%Y-%m-%d')");
8619 assert!(
8621 result.to_uppercase().contains("STRFTIME"),
8622 "Expected STRFTIME, got: {}",
8623 result
8624 );
8625 }
8626
8627 #[test]
8628 fn test_regexp_like_to_regexp_matches() {
8629 let result = transpile_to_duckdb("SELECT REGEXP_LIKE(name, 'pattern')");
8630 assert!(
8632 result.to_uppercase().contains("REGEXP_MATCHES"),
8633 "Expected REGEXP_MATCHES, got: {}",
8634 result
8635 );
8636 }
8637
8638 #[test]
8639 fn test_double_quote_identifiers() {
8640 let dialect = Dialect::get(DialectType::DuckDB);
8642 let config = dialect.generator_config();
8643 assert_eq!(config.identifier_quote, '"');
8644 }
8645
8646 fn duckdb_identity(sql: &str) -> String {
8648 let dialect = Dialect::get(DialectType::DuckDB);
8649 let ast = dialect.parse(sql).expect("Parse failed");
8650 let transformed = dialect.transform(ast[0].clone()).expect("Transform failed");
8651 dialect.generate(&transformed).expect("Generate failed")
8652 }
8653
8654 #[test]
8655 fn test_interval_quoting() {
8656 let result = duckdb_identity("SELECT DATE_ADD(CAST('2020-01-01' AS DATE), INTERVAL 1 DAY)");
8658 assert_eq!(
8659 result, "SELECT CAST('2020-01-01' AS DATE) + INTERVAL '1' DAY",
8660 "Interval value should be quoted as string"
8661 );
8662 }
8663
8664 #[test]
8665 fn test_struct_pack_to_curly_brace() {
8666 let result = duckdb_identity("CAST([STRUCT_PACK(a := 1)] AS STRUCT(a BIGINT)[])");
8668 assert_eq!(
8669 result, "CAST([{'a': 1}] AS STRUCT(a BIGINT)[])",
8670 "STRUCT_PACK should be transformed to curly brace notation"
8671 );
8672 }
8673
8674 #[test]
8675 fn test_struct_pack_nested() {
8676 let result = duckdb_identity("CAST([[STRUCT_PACK(a := 1)]] AS STRUCT(a BIGINT)[][])");
8678 assert_eq!(
8679 result, "CAST([[{'a': 1}]] AS STRUCT(a BIGINT)[][])",
8680 "Nested STRUCT_PACK should be transformed"
8681 );
8682 }
8683
8684 #[test]
8685 fn test_struct_pack_cast() {
8686 let result = duckdb_identity("STRUCT_PACK(a := 'b')::json");
8688 assert_eq!(
8689 result, "CAST({'a': 'b'} AS JSON)",
8690 "STRUCT_PACK with cast should be transformed"
8691 );
8692 }
8693
8694 #[test]
8695 fn test_list_value_to_bracket() {
8696 let result = duckdb_identity("SELECT LIST_VALUE(1)[i]");
8698 assert_eq!(
8699 result, "SELECT [1][i]",
8700 "LIST_VALUE should be transformed to bracket notation"
8701 );
8702 }
8703
8704 #[test]
8705 fn test_list_value_in_struct_literal() {
8706 let result = duckdb_identity("{'x': LIST_VALUE(1)[i]}");
8708 assert_eq!(
8709 result, "{'x': [1][i]}",
8710 "LIST_VALUE inside struct literal should be transformed"
8711 );
8712 }
8713
8714 #[test]
8715 fn test_struct_pack_simple() {
8716 let result = duckdb_identity("SELECT STRUCT_PACK(a := 1)");
8718 eprintln!("STRUCT_PACK result: {}", result);
8719 assert!(
8720 result.contains("{"),
8721 "Expected curly brace, got: {}",
8722 result
8723 );
8724 }
8725
8726 #[test]
8727 fn test_not_in_position() {
8728 let result = duckdb_identity(
8731 "SELECT col FROM t WHERE JSON_EXTRACT_STRING(col, '$.id') NOT IN ('b')",
8732 );
8733 assert_eq!(
8734 result, "SELECT col FROM t WHERE NOT (col ->> '$.id') IN ('b')",
8735 "NOT IN should have NOT moved outside and JSON expression wrapped"
8736 );
8737 }
8738
8739 #[test]
8740 fn test_unnest_comma_join_to_join_on_true() {
8741 let result = duckdb_identity(
8743 "WITH _data AS (SELECT [{'a': 1, 'b': 2}, {'a': 2, 'b': 3}] AS col) SELECT t.col['b'] FROM _data, UNNEST(_data.col) AS t(col) WHERE t.col['a'] = 1",
8744 );
8745 assert_eq!(
8746 result,
8747 "WITH _data AS (SELECT [{'a': 1, 'b': 2}, {'a': 2, 'b': 3}] AS col) SELECT t.col['b'] FROM _data JOIN UNNEST(_data.col) AS t(col) ON TRUE WHERE t.col['a'] = 1",
8748 "Comma-join with UNNEST should become JOIN ON TRUE"
8749 );
8750 }
8751}