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