1use super::{DialectImpl, DialectType};
15use crate::error::Result;
16use crate::expressions::{
17 CeilFunc, CurrentTimestamp, DataType, DateTimeField, Expression, ExtractFunc, Function,
18 Literal, StructField, UnaryFunc, VarArgFunc,
19};
20use crate::generator::GeneratorConfig;
21use crate::tokens::TokenizerConfig;
22
23pub struct SparkDialect;
25
26impl DialectImpl for SparkDialect {
27 fn dialect_type(&self) -> DialectType {
28 DialectType::Spark
29 }
30
31 fn tokenizer_config(&self) -> TokenizerConfig {
32 let mut config = TokenizerConfig::default();
33 config.identifiers.clear();
35 config.identifiers.insert('`', '`');
36 config.quotes.insert("\"".to_string(), "\"".to_string());
38 config.string_escapes.push('\\');
40 config
42 .keywords
43 .insert("DIV".to_string(), crate::tokens::TokenType::Div);
44 config
46 .numeric_literals
47 .insert("L".to_string(), "BIGINT".to_string());
48 config
49 .numeric_literals
50 .insert("S".to_string(), "SMALLINT".to_string());
51 config
52 .numeric_literals
53 .insert("Y".to_string(), "TINYINT".to_string());
54 config
55 .numeric_literals
56 .insert("D".to_string(), "DOUBLE".to_string());
57 config
58 .numeric_literals
59 .insert("F".to_string(), "FLOAT".to_string());
60 config
61 .numeric_literals
62 .insert("BD".to_string(), "DECIMAL".to_string());
63 config.identifiers_can_start_with_digit = true;
65 config.string_escapes_allowed_in_raw_strings = false;
68 config
69 }
70
71 fn generator_config(&self) -> GeneratorConfig {
72 use crate::generator::IdentifierQuoteStyle;
73 GeneratorConfig {
74 identifier_quote: '`',
75 identifier_quote_style: IdentifierQuoteStyle::BACKTICK,
76 dialect: Some(DialectType::Spark),
77 struct_field_sep: ": ",
79 create_function_return_as: false,
81 alias_post_tablesample: true,
83 tablesample_seed_keyword: "REPEATABLE",
84 join_hints: false,
85 identifiers_can_start_with_digit: true,
86 schema_comment_with_eq: false,
88 ..Default::default()
89 }
90 }
91
92 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
93 match expr {
94 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
96 original_name: None,
97 expressions: vec![f.this, f.expression],
98 inferred_type: None,
99 }))),
100
101 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
103 original_name: None,
104 expressions: vec![f.this, f.expression],
105 inferred_type: None,
106 }))),
107
108 Expression::Cast(mut c) => {
110 c.to = Self::normalize_spark_type(c.to);
111 Ok(Expression::Cast(c))
112 }
113
114 Expression::TryCast(mut c) => {
116 c.to = Self::normalize_spark_type(c.to);
117 Ok(Expression::TryCast(c))
118 }
119
120 Expression::SafeCast(mut c) => {
122 c.to = Self::normalize_spark_type(c.to);
123 Ok(Expression::TryCast(c))
124 }
125
126 Expression::Trim(mut t) => {
129 if !t.sql_standard_syntax && t.characters.is_some() {
130 t.sql_standard_syntax = true;
133 }
134 Ok(Expression::Trim(t))
135 }
136
137 Expression::ILike(op) => Ok(Expression::ILike(op)),
139
140 Expression::Unnest(f) => Ok(Expression::Explode(Box::new(UnaryFunc::new(f.this)))),
142
143 Expression::Explode(f) => Ok(Expression::Explode(f)),
145
146 Expression::ExplodeOuter(f) => Ok(Expression::ExplodeOuter(f)),
148
149 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
151 seed: None,
152 lower: None,
153 upper: None,
154 }))),
155
156 Expression::Rand(r) => Ok(Expression::Rand(r)),
158
159 Expression::Concat(op) => Ok(Expression::Function(Box::new(Function::new(
161 "CONCAT".to_string(),
162 vec![op.left, op.right],
163 )))),
164
165 Expression::Function(f) => self.transform_function(*f),
169
170 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
172
173 Expression::Parameter(mut p)
175 if p.style == crate::expressions::ParameterStyle::Dollar =>
176 {
177 p.style = crate::expressions::ParameterStyle::DollarBrace;
178 if let Some(idx) = p.index {
180 p.name = Some(idx.to_string());
181 }
182 Ok(Expression::Parameter(p))
183 }
184
185 Expression::JSONExtract(je) if je.variant_extract.is_some() => {
187 let path = match *je.expression {
189 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
190 let Literal::String(s) = lit.as_ref() else { unreachable!() };
191 Expression::Literal(Box::new(Literal::String(format!("$.{}", s))))
192 }
193 other => other,
194 };
195 Ok(Expression::Function(Box::new(Function::new(
196 "GET_JSON_OBJECT".to_string(),
197 vec![*je.this, path],
198 ))))
199 }
200
201 _ => Ok(expr),
203 }
204 }
205}
206
207impl SparkDialect {
208 fn normalize_spark_type(dt: DataType) -> DataType {
213 match dt {
214 DataType::VarChar { length: None, .. }
215 | DataType::Char { length: None }
216 | DataType::Text => DataType::Custom {
217 name: "STRING".to_string(),
218 },
219 DataType::VarChar { .. } | DataType::Char { .. } => dt,
221 DataType::Struct { fields, nested } => {
223 let normalized_fields: Vec<StructField> = fields
224 .into_iter()
225 .map(|mut f| {
226 f.data_type = Self::normalize_spark_type(f.data_type);
227 f
228 })
229 .collect();
230 DataType::Struct {
231 fields: normalized_fields,
232 nested,
233 }
234 }
235 _ => dt,
236 }
237 }
238
239 fn transform_function(&self, f: Function) -> Result<Expression> {
240 let name_upper = f.name.to_uppercase();
241 match name_upper.as_str() {
242 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
244 original_name: None,
245 expressions: f.args,
246 inferred_type: None,
247 }))),
248
249 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
251 original_name: None,
252 expressions: f.args,
253 inferred_type: None,
254 }))),
255
256 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
258 original_name: None,
259 expressions: f.args,
260 inferred_type: None,
261 }))),
262
263 "GROUP_CONCAT" if !f.args.is_empty() => {
266 Ok(Expression::Function(Box::new(Function::new(
268 "COLLECT_LIST".to_string(),
269 f.args,
270 ))))
271 }
272
273 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
276 Function::new("COLLECT_LIST".to_string(), f.args),
277 ))),
278
279 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
281 "COLLECT_LIST".to_string(),
282 f.args,
283 )))),
284
285 "SUBSTRING" | "SUBSTR" => Ok(Expression::Function(Box::new(f))),
287
288 "LENGTH" => Ok(Expression::Function(Box::new(f))),
290
291 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
293 f.args.into_iter().next().unwrap(),
294 )))),
295
296 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
298 seed: None,
299 lower: None,
300 upper: None,
301 }))),
302
303 "RAND" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
305 seed: None,
306 lower: None,
307 upper: None,
308 }))),
309
310 "NOW" => Ok(Expression::CurrentTimestamp(
312 crate::expressions::CurrentTimestamp {
313 precision: None,
314 sysdate: false,
315 },
316 )),
317
318 "GETDATE" => Ok(Expression::CurrentTimestamp(
320 crate::expressions::CurrentTimestamp {
321 precision: None,
322 sysdate: false,
323 },
324 )),
325
326 "CURRENT_TIMESTAMP" => Ok(Expression::CurrentTimestamp(
328 crate::expressions::CurrentTimestamp {
329 precision: None,
330 sysdate: false,
331 },
332 )),
333
334 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
336
337 "TO_DATE" if f.args.len() == 2 => {
339 let is_default_format = matches!(&f.args[1], Expression::Literal(lit) if matches!(lit.as_ref(), crate::expressions::Literal::String(s) if s == "yyyy-MM-dd"));
340 if is_default_format {
341 Ok(Expression::Function(Box::new(Function::new(
342 "TO_DATE".to_string(),
343 vec![f.args.into_iter().next().unwrap()],
344 ))))
345 } else {
346 Ok(Expression::Function(Box::new(f)))
347 }
348 }
349 "TO_DATE" => Ok(Expression::Function(Box::new(f))),
350
351 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(f))),
353
354 "DATE_FORMAT" => Ok(Expression::Function(Box::new(f))),
356
357 "STRFTIME" => Ok(Expression::Function(Box::new(Function::new(
359 "DATE_FORMAT".to_string(),
360 f.args,
361 )))),
362
363 "TO_CHAR" => Ok(Expression::Function(Box::new(Function::new(
365 "DATE_FORMAT".to_string(),
366 f.args,
367 )))),
368
369 "DATE_TRUNC" => Ok(Expression::Function(Box::new(f))),
371
372 "TRUNC" => Ok(Expression::Function(Box::new(f))),
374
375 "EXTRACT" => Ok(Expression::Function(Box::new(f))),
377
378 "DATEPART" => Ok(Expression::Function(Box::new(Function::new(
380 "EXTRACT".to_string(),
381 f.args,
382 )))),
383
384 "UNIX_TIMESTAMP" => {
387 if f.args.is_empty() {
388 Ok(Expression::Function(Box::new(Function::new(
389 "UNIX_TIMESTAMP".to_string(),
390 vec![Expression::CurrentTimestamp(CurrentTimestamp {
391 precision: None,
392 sysdate: false,
393 })],
394 ))))
395 } else {
396 Ok(Expression::Function(Box::new(f)))
397 }
398 }
399
400 "FROM_UNIXTIME" => Ok(Expression::Function(Box::new(f))),
402
403 "STR_TO_MAP" => {
406 if f.args.len() == 1 {
407 let mut args = f.args;
408 args.push(Expression::Literal(Box::new(crate::expressions::Literal::String(
409 ",".to_string(),
410 ))));
411 args.push(Expression::Literal(Box::new(crate::expressions::Literal::String(
412 ":".to_string(),
413 ))));
414 Ok(Expression::Function(Box::new(Function::new(
415 "STR_TO_MAP".to_string(),
416 args,
417 ))))
418 } else {
419 Ok(Expression::Function(Box::new(f)))
420 }
421 }
422
423 "POSITION" => Ok(Expression::Function(Box::new(f))),
425
426 "LOCATE" => Ok(Expression::Function(Box::new(f))),
428
429 "STRPOS" if f.args.len() == 2 => {
431 let mut args = f.args;
432 let first = args.remove(0);
433 let second = args.remove(0);
434 Ok(Expression::Function(Box::new(Function::new(
436 "LOCATE".to_string(),
437 vec![second, first],
438 ))))
439 }
440
441 "CHARINDEX" if f.args.len() >= 2 => {
443 let mut args = f.args;
444 let substring = args.remove(0);
445 let string = args.remove(0);
446 let mut locate_args = vec![substring, string];
447 if !args.is_empty() {
448 locate_args.push(args.remove(0));
449 }
450 Ok(Expression::Function(Box::new(Function::new(
451 "LOCATE".to_string(),
452 locate_args,
453 ))))
454 }
455
456 "INSTR" => Ok(Expression::Function(Box::new(f))),
458
459 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
461 this: f.args.into_iter().next().unwrap(),
462 decimals: None,
463 to: None,
464 }))),
465
466 "CEIL" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
468 this: f.args.into_iter().next().unwrap(),
469 decimals: None,
470 to: None,
471 }))),
472
473 "UNNEST" => Ok(Expression::Function(Box::new(Function::new(
475 "EXPLODE".to_string(),
476 f.args,
477 )))),
478
479 "FLATTEN" => Ok(Expression::Function(Box::new(f))),
481
482 "ARRAY_AGG" => Ok(Expression::Function(Box::new(Function::new(
484 "COLLECT_LIST".to_string(),
485 f.args,
486 )))),
487
488 "COLLECT_LIST" => Ok(Expression::Function(Box::new(f))),
490
491 "COLLECT_SET" => Ok(Expression::Function(Box::new(f))),
493
494 "ARRAY_LENGTH" | "CARDINALITY" => Ok(Expression::Function(Box::new(Function::new(
496 "SIZE".to_string(),
497 f.args,
498 )))),
499
500 "SIZE" => Ok(Expression::Function(Box::new(f))),
502
503 "SPLIT" => Ok(Expression::Function(Box::new(f))),
505
506 "REGEXP_REPLACE" if f.args.len() > 4 => {
509 let mut args = f.args;
510 args.truncate(4);
511 Ok(Expression::Function(Box::new(Function::new(
512 "REGEXP_REPLACE".to_string(),
513 args,
514 ))))
515 }
516 "REGEXP_REPLACE" => Ok(Expression::Function(Box::new(f))),
517
518 "REGEXP_EXTRACT" => Ok(Expression::Function(Box::new(f))),
520
521 "REGEXP_EXTRACT_ALL" => Ok(Expression::Function(Box::new(f))),
523
524 "RLIKE" | "REGEXP_LIKE" => Ok(Expression::Function(Box::new(Function::new(
526 "RLIKE".to_string(),
527 f.args,
528 )))),
529
530 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
532 "GET_JSON_OBJECT".to_string(),
533 f.args,
534 )))),
535
536 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
538 "GET_JSON_OBJECT".to_string(),
539 f.args,
540 )))),
541
542 "GET_JSON_OBJECT" => Ok(Expression::Function(Box::new(f))),
544
545 "FROM_JSON" => Ok(Expression::Function(Box::new(f))),
547
548 "TO_JSON" => Ok(Expression::Function(Box::new(f))),
550
551 "PARSE_JSON" if f.args.len() == 1 => Ok(f.args.into_iter().next().unwrap()),
553 "PARSE_JSON" => Ok(Expression::Function(Box::new(Function::new(
554 "FROM_JSON".to_string(),
555 f.args,
556 )))),
557
558 "DATEDIFF" | "DATE_DIFF" => Ok(Expression::Function(Box::new(Function::new(
560 "DATEDIFF".to_string(),
561 f.args,
562 )))),
563
564 "DATE_ADD" | "DATEADD" => Ok(Expression::Function(Box::new(Function::new(
566 "DATE_ADD".to_string(),
567 f.args,
568 )))),
569
570 "DATE_SUB" => Ok(Expression::Function(Box::new(f))),
572
573 "TIMESTAMPADD" => Ok(Expression::Function(Box::new(f))),
575
576 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(f))),
578
579 "ADD_MONTHS" => Ok(Expression::Function(Box::new(f))),
581
582 "MONTHS_BETWEEN" => Ok(Expression::Function(Box::new(f))),
584
585 "NVL" => Ok(Expression::Function(Box::new(f))),
587
588 "NVL2" => Ok(Expression::Function(Box::new(f))),
590
591 "MAP" => Ok(Expression::Function(Box::new(f))),
593
594 "ARRAY" => Ok(Expression::Function(Box::new(f))),
596
597 "ROW" => Ok(Expression::Function(Box::new(Function::new(
599 "STRUCT".to_string(),
600 f.args,
601 )))),
602
603 "STRUCT" => {
605 let mut col_idx = 1usize;
606 let named_args: Vec<Expression> = f
607 .args
608 .into_iter()
609 .map(|arg| {
610 let current_idx = col_idx;
611 col_idx += 1;
612 match &arg {
614 Expression::Alias(_) => arg, Expression::Star(_) => arg, Expression::Column(c) if c.table.is_none() => {
617 let name = c.name.name.clone();
619 Expression::Alias(Box::new(crate::expressions::Alias {
620 this: arg,
621 alias: crate::expressions::Identifier::new(&name),
622 column_aliases: Vec::new(),
623 pre_alias_comments: Vec::new(),
624 trailing_comments: Vec::new(),
625 inferred_type: None,
626 }))
627 }
628 _ => {
629 let name = format!("col{}", current_idx);
631 Expression::Alias(Box::new(crate::expressions::Alias {
632 this: arg,
633 alias: crate::expressions::Identifier::new(&name),
634 column_aliases: Vec::new(),
635 pre_alias_comments: Vec::new(),
636 trailing_comments: Vec::new(),
637 inferred_type: None,
638 }))
639 }
640 }
641 })
642 .collect();
643 Ok(Expression::Function(Box::new(Function {
644 name: "STRUCT".to_string(),
645 args: named_args,
646 distinct: false,
647 trailing_comments: Vec::new(),
648 use_bracket_syntax: false,
649 no_parens: false,
650 quoted: false,
651 span: None,
652 inferred_type: None,
653 })))
654 }
655
656 "NAMED_STRUCT" => Ok(Expression::Function(Box::new(f))),
658
659 "MAP_FROM_ARRAYS" => Ok(Expression::Function(Box::new(f))),
661
662 "ARRAY_SORT" => Ok(Expression::Function(Box::new(f))),
664
665 "ARRAY_DISTINCT" => Ok(Expression::Function(Box::new(f))),
667
668 "ARRAY_UNION" => Ok(Expression::Function(Box::new(f))),
670
671 "ARRAY_INTERSECT" => Ok(Expression::Function(Box::new(f))),
673
674 "ARRAY_EXCEPT" => Ok(Expression::Function(Box::new(f))),
676
677 "ARRAY_CONTAINS" => Ok(Expression::Function(Box::new(f))),
679
680 "ELEMENT_AT" => Ok(Expression::Function(Box::new(f))),
682
683 "TRY_ELEMENT_AT" => Ok(Expression::Function(Box::new(f))),
685
686 "TRANSFORM" => Ok(Expression::Function(Box::new(f))),
688
689 "FILTER" => Ok(Expression::Function(Box::new(f))),
691
692 "AGGREGATE" => Ok(Expression::Function(Box::new(f))),
694
695 "SEQUENCE" => Ok(Expression::Function(Box::new(f))),
697
698 "GENERATE_SERIES" => Ok(Expression::Function(Box::new(Function::new(
700 "SEQUENCE".to_string(),
701 f.args,
702 )))),
703
704 "STARTSWITH" | "STARTS_WITH" => Ok(Expression::Function(Box::new(Function::new(
706 "STARTSWITH".to_string(),
707 f.args,
708 )))),
709
710 "ENDSWITH" | "ENDS_WITH" => Ok(Expression::Function(Box::new(Function::new(
712 "ENDSWITH".to_string(),
713 f.args,
714 )))),
715
716 "ARRAY_CONSTRUCT_COMPACT" => {
718 let inner =
719 Expression::Function(Box::new(Function::new("ARRAY".to_string(), f.args)));
720 Ok(Expression::Function(Box::new(Function::new(
721 "ARRAY_COMPACT".to_string(),
722 vec![inner],
723 ))))
724 }
725
726 "ARRAY_TO_STRING" => Ok(Expression::Function(Box::new(Function::new(
728 "ARRAY_JOIN".to_string(),
729 f.args,
730 )))),
731
732 "TO_ARRAY" if f.args.len() == 1 => {
734 let x = f.args[0].clone();
735 match &x {
738 Expression::ArrayFunc(arr) => {
739 Ok(Expression::Function(Box::new(Function::new(
741 "ARRAY".to_string(),
742 arr.expressions.clone(),
743 ))))
744 }
745 _ => Ok(Expression::IfFunc(Box::new(crate::expressions::IfFunc {
746 condition: Expression::IsNull(Box::new(crate::expressions::IsNull {
747 this: x.clone(),
748 not: false,
749 postfix_form: false,
750 })),
751 true_value: Expression::Null(crate::expressions::Null),
752 false_value: Some(Expression::Function(Box::new(Function::new(
753 "ARRAY".to_string(),
754 vec![x],
755 )))),
756 original_name: Some("IF".to_string()),
757 inferred_type: None,
758 }))),
759 }
760 }
761
762 "REGEXP_SUBSTR" if f.args.len() >= 2 => {
764 let subject = f.args[0].clone();
765 let pattern = f.args[1].clone();
766 let group = if f.args.len() >= 6 {
769 let g = &f.args[5];
770 if matches!(g, Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(n) if n == "1")) {
772 None
773 } else {
774 Some(g.clone())
775 }
776 } else {
777 None
778 };
779 let mut args = vec![subject, pattern];
780 if let Some(g) = group {
781 args.push(g);
782 }
783 Ok(Expression::Function(Box::new(Function::new(
784 "REGEXP_EXTRACT".to_string(),
785 args,
786 ))))
787 }
788
789 "UUID_STRING" => Ok(Expression::Function(Box::new(Function::new(
791 "UUID".to_string(),
792 vec![],
793 )))),
794
795 "OBJECT_CONSTRUCT" if f.args.len() >= 2 && f.args.len() % 2 == 0 => {
797 let mut struct_args = Vec::new();
801 for pair in f.args.chunks(2) {
802 if let Expression::Literal(lit) = &pair[0] {
803 if let Literal::String(key) = lit.as_ref() {
804 struct_args.push(Expression::Alias(Box::new(crate::expressions::Alias {
805 this: pair[1].clone(),
806 alias: crate::expressions::Identifier::new(key.clone()),
807 column_aliases: vec![],
808 pre_alias_comments: vec![],
809 trailing_comments: vec![],
810 inferred_type: None,
811 })));
812 }
813 } else {
814 struct_args.push(pair[1].clone());
815 }
816 }
817 Ok(Expression::Function(Box::new(Function::new(
818 "STRUCT".to_string(),
819 struct_args,
820 ))))
821 }
822
823 "DATE_PART" if f.args.len() == 2 => {
825 let mut args = f.args;
826 let part = args.remove(0);
827 let expr = args.remove(0);
828 if let Some(field) = expr_to_datetime_field(&part) {
829 Ok(Expression::Extract(Box::new(ExtractFunc {
830 this: expr,
831 field,
832 })))
833 } else {
834 Ok(Expression::Function(Box::new(Function::new(
836 "DATE_PART".to_string(),
837 vec![part, expr],
838 ))))
839 }
840 }
841
842 "GET_PATH" if f.args.len() == 2 => {
844 let mut args = f.args;
845 let this = args.remove(0);
846 let path = args.remove(0);
847 let json_path = match &path {
848 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
849 let Literal::String(s) = lit.as_ref() else { unreachable!() };
850 let normalized = if s.starts_with('$') {
851 s.clone()
852 } else if s.starts_with('[') {
853 format!("${}", s)
854 } else {
855 format!("$.{}", s)
856 };
857 Expression::Literal(Box::new(Literal::String(normalized)))
858 }
859 _ => path,
860 };
861 Ok(Expression::Function(Box::new(Function::new(
862 "GET_JSON_OBJECT".to_string(),
863 vec![this, json_path],
864 ))))
865 }
866
867 "BITWISE_LEFT_SHIFT" => Ok(Expression::Function(Box::new(Function::new(
869 "SHIFTLEFT".to_string(),
870 f.args,
871 )))),
872
873 "BITWISE_RIGHT_SHIFT" => Ok(Expression::Function(Box::new(Function::new(
875 "SHIFTRIGHT".to_string(),
876 f.args,
877 )))),
878
879 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
881 "APPROX_COUNT_DISTINCT".to_string(),
882 f.args,
883 )))),
884
885 "ARRAY_SLICE" => Ok(Expression::Function(Box::new(Function::new(
887 "SLICE".to_string(),
888 f.args,
889 )))),
890
891 "DATE_FROM_PARTS" => Ok(Expression::Function(Box::new(Function::new(
893 "MAKE_DATE".to_string(),
894 f.args,
895 )))),
896
897 "DAYOFWEEK_ISO" => Ok(Expression::Function(Box::new(Function::new(
899 "DAYOFWEEK".to_string(),
900 f.args,
901 )))),
902
903 "FORMAT" => Ok(Expression::Function(Box::new(Function::new(
905 "FORMAT_STRING".to_string(),
906 f.args,
907 )))),
908
909 "LOGICAL_AND" => Ok(Expression::Function(Box::new(Function::new(
911 "BOOL_AND".to_string(),
912 f.args,
913 )))),
914
915 "VARIANCE_POP" => Ok(Expression::Function(Box::new(Function::new(
917 "VAR_POP".to_string(),
918 f.args,
919 )))),
920
921 "WEEK_OF_YEAR" => Ok(Expression::Function(Box::new(Function::new(
923 "WEEKOFYEAR".to_string(),
924 f.args,
925 )))),
926
927 "BIT_GET" => Ok(Expression::Function(Box::new(Function::new(
929 "GETBIT".to_string(),
930 f.args,
931 )))),
932
933 "CURDATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
935
936 _ => Ok(Expression::Function(Box::new(f))),
938 }
939 }
940
941 fn transform_aggregate_function(
942 &self,
943 f: Box<crate::expressions::AggregateFunction>,
944 ) -> Result<Expression> {
945 let name_upper = f.name.to_uppercase();
946 match name_upper.as_str() {
947 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
949 Function::new("COLLECT_LIST".to_string(), f.args),
950 ))),
951
952 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
954 Function::new("COLLECT_LIST".to_string(), f.args),
955 ))),
956
957 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
959 "COLLECT_LIST".to_string(),
960 f.args,
961 )))),
962
963 "ARRAY_AGG" if !f.args.is_empty() => {
965 let mut af = f;
966 af.name = "COLLECT_LIST".to_string();
967 Ok(Expression::AggregateFunction(af))
968 }
969
970 "LOGICAL_OR" if !f.args.is_empty() => {
972 let mut af = f;
973 af.name = "BOOL_OR".to_string();
974 Ok(Expression::AggregateFunction(af))
975 }
976
977 _ => Ok(Expression::AggregateFunction(f)),
979 }
980 }
981}
982
983fn expr_to_datetime_field(expr: &Expression) -> Option<DateTimeField> {
985 let name = match expr {
986 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => { let Literal::String(s) = lit.as_ref() else { unreachable!() }; s.to_uppercase() },
987 Expression::Identifier(id) => id.name.to_uppercase(),
988 Expression::Column(col) if col.table.is_none() => col.name.name.to_uppercase(),
989 _ => return None,
990 };
991 match name.as_str() {
992 "YEAR" | "Y" | "YY" | "YYY" | "YYYY" | "YR" | "YEARS" | "YRS" => Some(DateTimeField::Year),
993 "MONTH" | "MM" | "MON" | "MONS" | "MONTHS" => Some(DateTimeField::Month),
994 "DAY" | "D" | "DD" | "DAYS" | "DAYOFMONTH" => Some(DateTimeField::Day),
995 "HOUR" | "H" | "HH" | "HR" | "HOURS" | "HRS" => Some(DateTimeField::Hour),
996 "MINUTE" | "MI" | "MIN" | "MINUTES" | "MINS" => Some(DateTimeField::Minute),
997 "SECOND" | "S" | "SEC" | "SECONDS" | "SECS" => Some(DateTimeField::Second),
998 "MILLISECOND" | "MS" | "MSEC" | "MILLISECONDS" => Some(DateTimeField::Millisecond),
999 "MICROSECOND" | "US" | "USEC" | "MICROSECONDS" => Some(DateTimeField::Microsecond),
1000 "DOW" | "DAYOFWEEK" | "DAYOFWEEK_ISO" | "DW" => Some(DateTimeField::DayOfWeek),
1001 "DOY" | "DAYOFYEAR" => Some(DateTimeField::DayOfYear),
1002 "WEEK" | "W" | "WK" | "WEEKOFYEAR" | "WOY" => Some(DateTimeField::Week),
1003 "QUARTER" | "Q" | "QTR" | "QTRS" | "QUARTERS" => Some(DateTimeField::Quarter),
1004 "EPOCH" | "EPOCH_SECOND" | "EPOCH_SECONDS" => Some(DateTimeField::Epoch),
1005 "TIMEZONE" | "TIMEZONE_HOUR" | "TZH" => Some(DateTimeField::TimezoneHour),
1006 "TIMEZONE_MINUTE" | "TZM" => Some(DateTimeField::TimezoneMinute),
1007 _ => Some(DateTimeField::Custom(name)),
1008 }
1009}